Skip to content

Commit

Permalink
Merge pull request #57 from emc-openstack/feature/GH-58-link-aggregation
Browse files Browse the repository at this point in the history
[GH 58] Link aggregation
  • Loading branch information
Tianqi-Tang committed Nov 21, 2016
2 parents 8e93e2f + 1f0a33b commit e797cbd
Show file tree
Hide file tree
Showing 20 changed files with 564 additions and 10 deletions.
5 changes: 5 additions & 0 deletions storops/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,11 @@ class UnityStorageResourceNameInUseError(UnityException):
error_code = 108007952


@rest_exception
class UnityEthernetPortAlreadyAggregatedError(UnityException):
error_code = 100665643


class NaviseccliNotAvailableError(VNXException):
message = ("naviseccli not found. please make sure it's installed"
" and available in path.")
Expand Down
20 changes: 20 additions & 0 deletions storops/unity/parser_configs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1430,3 +1430,23 @@ UnityDnsServer:
- label: addresses
- label: origin
converter: DNSServerOriginEnum


UnityLinkAggregation:
data_src: rest
name: linkAggregation
properties:
- label: id
- label: name
- label: shortName
- label: masterPort
converter: UnityEthernetPort
- label: ports
converter: UnityEthernetPortList
- label: mtuSize
key: mtu
- label: supportedMtus
- label: macAddress
- label: isLinkUp
- label: parentStorageProcessor
converter: UnityStorageProcessor
53 changes: 48 additions & 5 deletions storops/unity/resource/port.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,32 @@

import logging

from storops.lib.common import instance_cache
from storops.unity.resource import UnityResource, UnityResourceList, \
UnityAttributeResource
from storops.exception import UnityEthernetPortMtuSizeNotSupportError
from storops.exception import UnityEthernetPortSpeedNotSupportError
from storops.unity.enums import EPSpeedValuesEnum, IOLimitPolicyTypeEnum


__author__ = 'Jay Xu'

LOG = logging.getLogger(__name__)


class UnityIpPort(UnityResource):
pass
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)

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


class UnityIpPortList(UnityResourceList):
Expand Down Expand Up @@ -129,13 +142,14 @@ def get_resource_class(cls):
class UnityEthernetPort(UnityResource):
def modify(self, speed=None, mtu=None):
speed = EPSpeedValuesEnum.parse(speed)
peer = self.get_peer()
self._modify(self, speed, mtu)
self._modify(peer, speed, mtu)
peer = self.get_peer()
if peer.existed:
self._modify(peer, speed, mtu)

def get_peer(self):
_peer_id = self._get_peer_id(self.get_id())
return UnityEthernetPort(cli=self._cli, _id=_peer_id)
peer_id = self._get_peer_id(self.get_id())
return UnityEthernetPort(cli=self._cli, _id=peer_id)

def _modify(self, port, speed, mtu):
if speed is not None:
Expand Down Expand Up @@ -171,6 +185,35 @@ def get_resource_class(cls):
return UnityEthernetPort


class UnityLinkAggregation(UnityResource):
@classmethod
def create(cls, cli, ports, mtu=None):
resp = cli.post(cls().resource_class,
ports=ports,
mtuSize=mtu)
resp.raise_if_err()
return cls(_id=resp.resource_id, cli=cli)

def modify(self, mtu=None, add_ports=None, remove_ports=None):
if isinstance(add_ports, UnityEthernetPort):
add_ports = [add_ports]
if isinstance(remove_ports, UnityEthernetPort):
remove_ports = [remove_ports]

resp = self._cli.modify(self.resource_class,
self.get_id(),
mtuSize=mtu,
addPorts=add_ports,
removePorts=remove_ports)
resp.raise_if_err()


class UnityLinkAggregationList(UnityResourceList):
@classmethod
def get_resource_class(cls):
return UnityLinkAggregation


class UnityIscsiNode(UnityResource):
pass

Expand Down
7 changes: 6 additions & 1 deletion storops/unity/resource/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from storops.unity.resource.nfs_share import UnityNfsShareList
from storops.unity.resource.pool import UnityPoolList
from storops.unity.resource.port import UnityIpPortList, UnityIoLimitPolicy, \
UnityIoLimitPolicyList
UnityIoLimitPolicyList, UnityLinkAggregationList
from storops.unity.resource.snap import UnitySnapList
from storops.unity.resource.sp import UnityStorageProcessorList
from storops.unity.resource.port import UnityEthernetPortList, \
Expand Down Expand Up @@ -239,6 +239,11 @@ def clear_dns_server(self, use_dhcp=None):
def info(self):
return UnityBasicSystemInfo.get(cli=self._cli)

def get_link_aggregation(self, _id=None, name=None, **filters):
return self._get_unity_rsc(UnityLinkAggregationList, _id=_id,
name=name,
**filters)


class UnitySystemList(UnityResourceList):
@classmethod
Expand Down
64 changes: 62 additions & 2 deletions test/unity/resource/test_port.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@
raises, contains_string
from storops.exception import UnityEthernetPortSpeedNotSupportError, \
UnityEthernetPortMtuSizeNotSupportError, UnityResourceNotFoundError, \
UnityPolicyNameInUseError
UnityPolicyNameInUseError, UnityEthernetPortAlreadyAggregatedError
from storops.unity.enums import ConnectorTypeEnum, EPSpeedValuesEnum, \
FcSpeedEnum, IOLimitPolicyStateEnum
from storops.unity.resource.lun import UnityLun
from storops.unity.resource.port import UnityEthernetPort, UnityIpPort, \
UnityIpPortList, UnityIscsiPortal, UnityIscsiNode, UnityFcPort, \
UnityIoLimitRule, UnityIoLimitPolicy, UnityIoLimitPolicyList
UnityIoLimitRule, UnityIoLimitPolicy, UnityIoLimitPolicyList, \
UnityLinkAggregation
from storops.unity.resource.sp import UnityStorageProcessor
from test.unity.rest_mock import t_rest, patch_rest

Expand All @@ -50,6 +51,23 @@ def test_get_all(self):
ports = UnityIpPortList(cli=t_rest())
assert_that(len(ports), equal_to(8))

@patch_rest
def test_is_link_aggregation(self):
port = UnityIpPort('spa_eth3', cli=t_rest())
assert_that(port.is_link_aggregation(), equal_to(False))
port = UnityIpPort('spa_la_2', cli=t_rest())
assert_that(port.is_link_aggregation(), equal_to(True))

@patch_rest
def test_set_mtu_on_eth_port(self):
port = UnityIpPort('spa_eth3', cli=t_rest())
port.set_mtu(1500)

@patch_rest
def test_set_mtu_on_link_aggregation(self):
la = UnityIpPort('spa_la_2', cli=t_rest())
la.set_mtu(1500)


@ddt.ddt
class UnityEthernetPortTest(TestCase):
Expand Down Expand Up @@ -110,6 +128,11 @@ def do():

assert_that(do, raises(UnityEthernetPortSpeedNotSupportError))

@patch_rest
def test_modify_when_peer_not_exist(self):
port = UnityEthernetPort(cli=t_rest(), _id='spa_eth4')
port.modify(mtu=1500)

@ddt.data({'port_id': 'spa_eth2',
'peer_id': 'spb_eth2'},
{'port_id': 'spb_eth3',
Expand Down Expand Up @@ -243,3 +266,40 @@ def test_remove_from_storage(self):
lun2 = UnityLun('sv_2025', t_rest())
resp = policy.remove_from_storage(lun1, lun2)
assert_that(resp.is_ok(), equal_to(True))


class UnityLinkAggregationTest(TestCase):
@patch_rest
def test_get_properties(self):
la = UnityLinkAggregation('spa_la_2', cli=t_rest())
assert_that(la.is_link_up, equal_to(False))
assert_that(la.mac_address, equal_to('00:60:16:5C:08:E1'))
assert_that(la.master_port.get_id(), "spa_eth2")
assert_that(la.mtu, equal_to(9000))
assert_that(
la.parent_storage_processor,
equal_to(UnityStorageProcessor.get(t_rest(), 'spa')))
assert_that(len(la.ports), equal_to(2))
assert_that(la.supported_mtus, only_contains(1500, 9000))

@patch_rest
def test_create(self):
eth_2 = UnityEthernetPort.get(t_rest(), 'spa_eth2')
eth_3 = UnityEthernetPort.get(t_rest(), 'spa_eth3')
la = UnityLinkAggregation.create(t_rest(), [eth_2, eth_3], 9000)
assert_that(la.get_id(), equal_to('spa_la_2'))

@patch_rest
def test_create_already_exist(self):
def do():
eth_2 = UnityEthernetPort.get(t_rest(), 'spa_eth2')
eth_4 = UnityEthernetPort.get(t_rest(), 'spa_eth4')
UnityLinkAggregation.create(t_rest(), [eth_2, eth_4], 1500)
assert_that(do, raises(UnityEthernetPortAlreadyAggregatedError))

@patch_rest
def test_modify(self):
la = UnityLinkAggregation.get(t_rest(), 'spa_la_2')
la.modify(mtu=1500,
remove_ports=[UnityEthernetPort.get(t_rest(), "spa_eth2")],
add_ports=[UnityEthernetPort.get(t_rest(), "spa_eth4")])
15 changes: 15 additions & 0 deletions test/unity/resource/test_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,21 @@ def test_clear_dns_server(self):
ret = t_unity().clear_dns_server()
assert_that(ret, has_items('10.245.177.15', '10.245.177.16'))

@patch_rest
def test_get_link_aggregation_list(self):
la_list = t_unity().get_link_aggregation()
assert_that(len(la_list), equal_to(2))

@patch_rest
def test_get_link_aggregation_by_name(self):
cg = t_unity().get_link_aggregation(name='SP A Link Aggregation 2')
assert_that(cg.name, equal_to('SP A Link Aggregation 2'))

@patch_rest
def test_get_link_aggregation_by_id(self):
cg = t_unity().get_link_aggregation(_id='spa_la_2')
assert_that(cg.id, equal_to('spa_la_2'))


class UnityDpeTest(TestCase):
@patch_rest
Expand Down
8 changes: 8 additions & 0 deletions test/unity/rest_data/ethernetPort/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@
"speed": 100
},
"response": "success.json"
},
{
"url": "/api/instances/ethernetPort/spa_eth4?compact=True&fields=bond,cascadeNames,connectorType,health,id,instanceId,isLinkUp,isRDMACapable,isRSSCapable,linuxDeviceName,macAddress,mtu,name,needsReplacement,operationalStatus,parent,parentIOModule,parentStorageProcessor,portNumber,requestedMtu,requestedSpeed,sfpSupportedProtocols,sfpSupportedSpeeds,shortName,speed,storageProcessor,supportedMtus,supportedSpeeds",
"response": "spa_eth4.json"
},
{
"url": "/api/instances/ethernetPort/spb_eth4?compact=True&fields=bond,cascadeNames,connectorType,health,id,instanceId,isLinkUp,isRDMACapable,isRSSCapable,linuxDeviceName,macAddress,mtu,name,needsReplacement,operationalStatus,parent,parentIOModule,parentStorageProcessor,portNumber,requestedMtu,requestedSpeed,sfpSupportedProtocols,sfpSupportedSpeeds,shortName,speed,storageProcessor,supportedMtus,supportedSpeeds",
"response": "not_found.json"
}
]
}
12 changes: 12 additions & 0 deletions test/unity/rest_data/ethernetPort/not_found.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"error": {
"errorCode": 131149829,
"httpStatusCode": 404,
"messages": [
{
"en-US": "The requested resource does not exist. (Error Code:0x7d13005)"
}
],
"created": "2016-11-21T02:28:44.743Z"
}
}
59 changes: 59 additions & 0 deletions test/unity/rest_data/ethernetPort/spa_eth4.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"content": {
"macAddress": "00:60:16:5C:07:0A",
"isRDMACapable": false,
"parentStorageProcessor": {
"id": "spa"
},
"instanceId": "root/emc:EMC_UEM_EthernetPortLeaf%Tag=03:00:00:01",
"portNumber": 3,
"cascadeNames": [
"Ethernet Port 4",
"SP A"
],
"requestedMtu": 1500,
"mtu": 1500,
"connectorType": 1,
"id": "spa_eth4",
"supportedSpeeds": [
1000,
10000,
100,
0
],
"supportedMtus": [
1500,
9000
],
"storageProcessor": {
"id": "spa"
},
"health": {
"descriptionIds": [
"ALRT_PORT_LINK_DOWN_NOT_IN_USE"
],
"descriptions": [
"The port link is down, but not in use. No action is required."
],
"value": 5
},
"parent": {
"resource": "storageProcessor",
"id": "spa"
},
"needsReplacement": false,
"sfpSupportedSpeeds": [],
"sfpSupportedProtocols": [],
"operationalStatus": [
2,
32785
],
"shortName": "Ethernet Port 4",
"requestedSpeed": 0,
"isRSSCapable": false,
"name": "SP A Ethernet Port 4",
"linuxDeviceName": "eth3",
"isLinkUp": false,
"bond": false
}
}
4 changes: 4 additions & 0 deletions test/unity/rest_data/ipPort/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
{
"url": "/api/instances/ipPort/spa_eth2?compact=True&fields=cascadeNames,id,instanceId,isLinkUp,linuxDeviceName,macAddress,name,shortName,storageProcessor",
"response": "spa_eth2.json"
},
{
"url": "/api/instances/ipPort/spa_la_2?compact=True&fields=cascadeNames,id,instanceId,isLinkUp,linuxDeviceName,macAddress,name,shortName,storageProcessor",
"response": "spa_la_2.json"
}
]
}
14 changes: 14 additions & 0 deletions test/unity/rest_data/ipPort/spa_la_2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"content": {
"macAddress": "00:60:16:5C:08:E1",
"name": "SP A Link Aggregation 2",
"linuxDeviceName": "bond2",
"storageProcessor": {
"id": "spa"
},
"instanceId": "root/emc:EMC_UEM_LinkAggregationLeaf%Tag=03:00:00:00",
"isLinkUp": true,
"shortName": "Link Aggregation 2",
"id": "spa_la_2"
}
}

0 comments on commit e797cbd

Please sign in to comment.