Skip to content

Commit

Permalink
Release 0.4.1
Browse files Browse the repository at this point in the history
- Remove cobertura and lxml dependency from UT.
- Support to delete tenant along with its hosts.
- Support to auto balance two SP when creating NAS servers.
  • Loading branch information
Murray-LIANG committed Dec 21, 2016
2 parents fb77f43 + ee47634 commit 93b0e11
Show file tree
Hide file tree
Showing 32 changed files with 1,286 additions and 41 deletions.
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ StorOps: The Python Library for VNX & Unity
.. image:: https://landscape.io/github/emc-openstack/storops/master/landscape.svg?style=flat
:target: https://landscape.io/github/emc-openstack/storops/

VERSION: 0.4.0
VERSION: 0.4.1

A minimalist Python library to manage VNX/Unity systems.
This document lies in the source code and go with the release.
Expand Down
10 changes: 10 additions & 0 deletions storops/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,16 @@ class UnityHostNotInSameTenantError(StoropsException):
error_code = 151036194


@rest_exception
class UnityTenantHasNasServerError(StoropsException):
error_code = 118939691


@rest_exception
class UnityTenantHasHostsError(StoropsException):
error_code = 118939704


class VNXStatsError(VNXException):
pass

Expand Down
16 changes: 15 additions & 1 deletion storops/lib/resource.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -197,11 +197,20 @@ def __init__(self):
super(ResourceList, self).__init__()
self._list = None

def shadow_copy(self):
def shadow_copy(self, *args, **kwargs):
ret = super(ResourceList, self).shadow_copy()
ret._list = self._list
ret.set_filter(*args, **kwargs)
return ret

def set_filter(self, *args, **kwargs):
self._set_filter(*args, **kwargs)
self._apply_filter()

def _set_filter(self, *args, **kwargs):
# implemented by child classes if needed
pass

@classmethod
def get_rsc_clz_list(cls, rsc_list_collection):
return [l.get_resource_class() for l in rsc_list_collection]
Expand Down Expand Up @@ -292,6 +301,11 @@ def get_member_attr_list(self, v):
def _is_updated(self):
return self._list is not None

def __add__(self, other):
if not isinstance(other, ResourceList):
raise TypeError
return self.list + other.list


class ResourceListCollection(object):
def __init__(self, init_list=None):
Expand Down
5 changes: 3 additions & 2 deletions storops/unity/resource/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,9 @@ def _is_updated(self):
len(self.get_preloaded_prop_keys()) > 1)
else:
# Return False when only id is parsed
ret = not (len(self._parsed_resource) == 1 and
len(self.property_names()) > 1)
ret = not (self.parsed_resource is None or
(len(self._parsed_resource) == 1 and
len(self.property_names()) > 1))
return ret

def _get_properties(self, dec=0):
Expand Down
19 changes: 19 additions & 0 deletions storops/unity/resource/nas_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,25 @@ def get_cifs_server(self):


class UnityNasServerList(UnityResourceList):
def __init__(self, cli=None, home_sp=None, current_sp=None, **filters):
super(UnityNasServerList, self).__init__(cli, **filters)
self._home_sp_id = None
self._current_sp_id = None
self._set_filter(home_sp, current_sp)

def _set_filter(self, home_sp=None, current_sp=None, **kwargs):
self._home_sp_id, self._current_sp_id = (
[sp.get_id() if isinstance(sp, UnityStorageProcessor)
else sp for sp in (home_sp, current_sp)])

def _filter(self, nas_server):
ret = True
if self._home_sp_id is not None:
ret &= nas_server.home_sp.get_id() == self._home_sp_id
if self._current_sp_id is not None:
ret &= nas_server.current_sp.get_id() == self._current_sp_id
return ret

@classmethod
def get_resource_class(cls):
return UnityNasServer
22 changes: 16 additions & 6 deletions storops/unity/resource/port.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,28 @@

class UnityIpPort(UnityResource):
def set_mtu(self, mtu):
if self.is_link_aggregation():
la = UnityLinkAggregation.get(self._cli, self.get_id())
la.modify(mtu=mtu)
else:
eth = UnityEthernetPort.get(self._cli, self.get_id())
eth.modify(mtu=mtu)
port = self.get_physical_port()
port.modify(mtu=mtu)

@instance_cache
def is_link_aggregation(self):
port = UnityLinkAggregation.get(self._cli, self.get_id())
return port.existed

def get_physical_port(self):
"""Returns the link aggregation object or the ethernet port object."""
obj = None
if self.is_link_aggregation():
obj = UnityLinkAggregation.get(self._cli, self.get_id())
else:
obj = UnityEthernetPort.get(self._cli, self.get_id())
return obj

@property
def mtu(self):
port = self.get_physical_port()
return port.mtu


class UnityIpPortList(UnityResourceList):
@classmethod
Expand Down
16 changes: 15 additions & 1 deletion storops/unity/resource/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,26 @@ def get_snap(self, _id=None, name=None, **filters):
def create_nas_server(self, name, sp=None, pool=None, is_repl_dst=None,
multi_proto=None, tenant=None):
if sp is None:
sp = self.get_sp().first_item
sp = self._auto_balance_sp()

return sp.create_nas_server(name, pool,
is_repl_dst=is_repl_dst,
multi_proto=multi_proto, tenant=tenant)

def _auto_balance_sp(self):
sp_list = self.get_sp()
if len(sp_list) < 2:
LOG.debug('spb not present. pick spa to host nas server.')
return sp_list.first_item

servers = self.get_nas_server()
spa, spb = sp_list
servers_on_spa = servers.shadow_copy(home_sp=spa)
sp = spb if len(servers_on_spa) * 2 > len(servers) else spa
LOG.debug('pick %s to balance of spa and spb to host nas servers.',
sp.get_id())
return sp

def get_ip_port(self, _id=None, name=None, **filters):
return self._get_unity_rsc(UnityIpPortList, _id=_id, name=name,
**filters)
Expand Down
12 changes: 12 additions & 0 deletions storops/unity/resource/tenant.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

from storops.unity.resource import UnityResource, UnityResourceList
from storops.lib.version import version
import storops.unity.resource.nas_server

__author__ = 'Tina Tang'

Expand Down Expand Up @@ -47,6 +48,17 @@ def modify(self, name=None, vlans=None):
resp.raise_if_err()
return resp

def delete(self, delete_hosts=False):
if delete_hosts and self.hosts:
for host in self.hosts:
host.delete()
return super(UnityTenant, self).delete()

@property
def nas_servers(self):
clz = storops.unity.resource.nas_server.UnityNasServerList
return clz(cli=self._cli, tenant=self)


@version('>=4.1')
class UnityTenantList(UnityResourceList):
Expand Down
10 changes: 1 addition & 9 deletions storops/vnx/resource/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,18 +169,10 @@ def __init__(self, cli=None):
self._poll = True

def shadow_copy(self, *args, **kwargs):
ret = super(VNXCliResourceList, self).shadow_copy()
ret = VNXCliResource.shadow_copy(self)
ret.set_filter(*args, **kwargs)
return ret

def set_filter(self, *args, **kwargs):
self._set_filter(*args, **kwargs)
self._apply_filter()

def _set_filter(self, *args, **kwargs):
# implemented by child classes if needed
pass

@classmethod
def _get_parser(cls):
return get_vnx_parser(cls.get_resource_class().__name__)
Expand Down
6 changes: 3 additions & 3 deletions storops/vnx/xmlapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,21 @@ def list_elements(self, name, elements):

_xb = XmlBuilder()
_default_task_timeout = 5 * 60
xml_ns = 'http://www.emc.com/schemas/celerra/xml_api'
XML_NS = 'http://www.emc.com/schemas/celerra/xml_api'


class NasXmlBuilder(object):

@staticmethod
def query_package(body):
return _xb.RequestPacket(_xb.Request(_xb.Query(body)),
xmlns=xml_ns)
xmlns=XML_NS)

@staticmethod
def task_package(body):
return _xb.RequestPacket(
_xb.Request(_xb.StartTask(body, timeout=_default_task_timeout)),
xmlns=xml_ns)
xmlns=XML_NS)

@classmethod
def get_filesystem(cls, name=None, fs_id=None):
Expand Down
3 changes: 1 addition & 2 deletions test-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ pytest-cov>=2.1.0
pytest-xdist>=1.13.1
pytest-capturelog>=0.7
xmltodict>=0.9.2
cobertura-clover-transform>=1.1.4
fasteners>=0.12.0
ddt>=1.0.1 # MIT
ddt>=1.0.1 # MIT
3 changes: 2 additions & 1 deletion test/lib/test_metric.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from hamcrest import assert_that, less_than, greater_than, none, equal_to, \
has_items, contains_string

from storops.lib.common import get_data_file
from storops.lib.metric import PerfManager, MetricCounterRecords, MetricsDumper
from storops.unity.resource.disk import UnityDiskList, UnityDisk
from storops.unity.resource.lun import UnityLun, UnityLunList
Expand Down Expand Up @@ -167,7 +168,7 @@ def _hdr_cb(rsc):
class MetricsDumperTest(unittest.TestCase):
dumper = MetricsDumper(SampleRscList(), ['time', 'name'],
SampleRscList._hdr_cb)
filename = 'temp_test_metric.csv'
filename = get_data_file('temp_test_metric.csv')

@classmethod
def tearDownClass(cls):
Expand Down
12 changes: 12 additions & 0 deletions test/lib/test_resource.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,15 @@ def test_update(self):
t0 = rlc.timestamp
rlc.update()
assert_that(t0, is_not(equal_to(rlc.timestamp)))


class ResourceListTest(unittest.TestCase):
@patch_rest
def test_add_resource_list(self):
ret = t_unity().get_ethernet_port() + t_unity().get_link_aggregation()
assert_that(len(ret), equal_to(10))

def test_add_resource_list_type_error(self):
def do():
return t_unity().get_ethernet_port() + None
assert_that(do, raises(TypeError))
15 changes: 15 additions & 0 deletions test/unity/resource/test_nas_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def test_properties(self):
assert_that(server.file_dns_server, instance_of(UnityFileDnsServer))
assert_that(server.file_interface, instance_of(UnityFileInterfaceList))
assert_that(server.virus_checker, instance_of(UnityVirusChecker))
assert_that(server.tenant, equal_to(None))

@patch_rest
def test_get_all(self):
Expand Down Expand Up @@ -192,3 +193,17 @@ def f():
local_password='Password123!')

assert_that(f, raises(UnitySmbNameInUseError, 'name already exists'))

@patch_rest
def test_shadow_copy_home_sp(self):
nas_servers = UnityNasServerList(cli=t_rest(), home_sp='spa')
assert_that(len(nas_servers), equal_to(2))
nas_servers = UnityNasServerList(cli=t_rest(), home_sp='spb')
assert_that(len(nas_servers), equal_to(1))

@patch_rest
def test_shadow_copy_current_sp(self):
nas_servers = UnityNasServerList(cli=t_rest(), current_sp='spa')
assert_that(len(nas_servers), equal_to(1))
nas_servers = UnityNasServerList(cli=t_rest(), current_sp='spb')
assert_that(len(nas_servers), equal_to(2))
10 changes: 10 additions & 0 deletions test/unity/resource/test_port.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ def test_set_mtu_on_link_aggregation(self):
la = UnityIpPort('spa_la_2', cli=t_rest())
la.set_mtu(1500)

@patch_rest
def test_mtu_of_link_aggregation(self):
la = UnityIpPort('spa_la_2', cli=t_rest())
assert_that(la.mtu, equal_to(9000))

@patch_rest
def test_mtu_of_eth_port(self):
port = UnityIpPort('spa_eth3', cli=t_rest())
assert_that(port.mtu, equal_to(1500))


@ddt.ddt
class UnityEthernetPortTest(TestCase):
Expand Down
31 changes: 31 additions & 0 deletions test/unity/resource/test_system.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ def test_get_ethernet_list(self):
unity = t_unity()
ports = unity.get_ethernet_port()
assert_that(ports, instance_of(UnityEthernetPortList))
assert_that(len(ports), equal_to(8))

@patch_rest
def test_get_host_list(self):
Expand Down Expand Up @@ -271,6 +272,36 @@ def test_create_nas_server(self):
nas_server = unity.create_nas_server('nas3', sp, pool)
assert_that(nas_server.existed, equal_to(True))

@patch_rest
def test_auto_balance_sp_one_sp(self):
unity = t_unity()

@patch_rest(output='auto_balance_sp_one_sp.json')
def inner():
sp = unity._auto_balance_sp()
assert_that(sp.get_id(), equal_to('spa'))

unity._auto_balance_sp()
inner()

@patch_rest
def test_auto_balance_sp_to_spb(self):
unity = t_unity()
sp = unity._auto_balance_sp()
assert_that(sp.get_id(), equal_to('spb'))

@patch_rest
def test_auto_balance_sp_to_spa(self):
unity = t_unity()

@patch_rest(output='auto_balance_sp_to_spa.json')
def inner():
sp = unity._auto_balance_sp()
assert_that(sp.get_id(), equal_to('spa'))

unity._auto_balance_sp()
inner()

@patch_rest
def test_get_ip_ports(self):
unity = t_unity()
Expand Down
13 changes: 13 additions & 0 deletions test/unity/resource/test_tenant.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from hamcrest import equal_to
from storops.unity.resource.tenant import UnityTenant, UnityTenantList
from storops.unity.resource.host import UnityHostList
from storops.unity.resource.nas_server import UnityNasServerList
from storops.exception import UnityTenantNameInUseError, SystemAPINotSupported
from test.unity.rest_mock import t_rest, patch_rest

Expand Down Expand Up @@ -71,6 +72,8 @@ def test_properties(self):
assert_that(tenant.vlans, only_contains(1, 3))
assert_that(len(tenant.hosts), equal_to(1))
assert_that(tenant.hosts, instance_of(UnityHostList))
assert_that(tenant.nas_servers, instance_of(UnityNasServerList))
assert_that(len(tenant.nas_servers), equal_to(1))

@patch_rest()
def test_get_all(self):
Expand All @@ -82,3 +85,13 @@ def test_query_tenant_with_vlans(self):
tenants = UnityTenantList(cli=t_rest('4.1.0'),
vlans=[1, 3])
assert_that(len(tenants), equal_to(1))

@patch_rest()
def test_delete_tenant(self):
tenant = UnityTenant('tenant_1', cli=t_rest())
tenant.delete()

@patch_rest()
def test_delete_tenant_with_hosts(self):
tenant = UnityTenant('tenant_2', cli=t_rest())
tenant.delete(delete_hosts=True)
Loading

0 comments on commit 93b0e11

Please sign in to comment.