Add acl rule field for rsd v2_1
Change-Id: I2e7bfaa0fdb8b5de4147900052438ac8a5a1b3ae
This commit is contained in:
parent
5db9a878e7
commit
c00a55915e
@ -13,8 +13,10 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from sushy import exceptions
|
||||
from sushy.resources import base
|
||||
|
||||
from rsd_lib.resources.v2_1.ethernet_switch import acl_rule
|
||||
from rsd_lib import utils as rsd_lib_utils
|
||||
|
||||
|
||||
@ -32,7 +34,7 @@ class ACL(base.ResourceBase):
|
||||
oem = base.Field('Oem')
|
||||
"""The acl oem info"""
|
||||
|
||||
rules = base.Field('Rules', adapter=rsd_lib_utils.get_resource_identity)
|
||||
_rules = None # ref to ACLRuleCollection instance
|
||||
"""The acl rules"""
|
||||
|
||||
links = base.Field('Links')
|
||||
@ -48,6 +50,31 @@ class ACL(base.ResourceBase):
|
||||
"""
|
||||
super(ACL, self).__init__(connector, identity, redfish_version)
|
||||
|
||||
def _get_acl_rule_collection_path(self):
|
||||
"""Helper function to find the RuleCollection path"""
|
||||
rule_col = self.json.get('Rules')
|
||||
if not rule_col:
|
||||
raise exceptions.MissingAttributeError(attribute='ACLRules',
|
||||
resource=self._path)
|
||||
return rsd_lib_utils.get_resource_identity(rule_col)
|
||||
|
||||
@property
|
||||
def rules(self):
|
||||
"""Property to provide reference to `RuleCollection` instance
|
||||
|
||||
It is calculated once when it is queried for the first time. On
|
||||
refresh, this property is reset.
|
||||
"""
|
||||
if self._rules is None:
|
||||
self._rules = acl_rule.ACLRuleCollection(
|
||||
self._conn, self._get_acl_rule_collection_path(),
|
||||
redfish_version=self.redfish_version)
|
||||
return self._rules
|
||||
|
||||
def refresh(self):
|
||||
super(ACL, self).refresh()
|
||||
self._rules = None
|
||||
|
||||
|
||||
class ACLCollection(base.ResourceCollectionBase):
|
||||
|
||||
|
119
rsd_lib/resources/v2_1/ethernet_switch/acl_rule.py
Normal file
119
rsd_lib/resources/v2_1/ethernet_switch/acl_rule.py
Normal file
@ -0,0 +1,119 @@
|
||||
# Copyright 2018 99cloud, Inc.
|
||||
# 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 sushy.resources import base
|
||||
from sushy import utils
|
||||
|
||||
from rsd_lib import utils as rsd_lib_utils
|
||||
|
||||
|
||||
class IPSourceField(base.CompositeField):
|
||||
ipv4_address = base.Field('IPv4Address')
|
||||
mask = base.Field('Mask')
|
||||
|
||||
|
||||
class MACSourceField(base.CompositeField):
|
||||
address = base.Field('Address')
|
||||
mask = base.Field('Mask', adapter=rsd_lib_utils.int_or_none)
|
||||
|
||||
|
||||
class VLANIdField(base.CompositeField):
|
||||
id = base.Field('Id', adapter=rsd_lib_utils.int_or_none)
|
||||
mask = base.Field('Mask', adapter=rsd_lib_utils.int_or_none)
|
||||
|
||||
|
||||
class L4SourcePortField(base.CompositeField):
|
||||
port = base.Field('Port', adapter=rsd_lib_utils.int_or_none)
|
||||
mask = base.Field('Mask', adapter=rsd_lib_utils.int_or_none)
|
||||
|
||||
|
||||
class ConditionField(base.CompositeField):
|
||||
ip_source = IPSourceField('IPSource')
|
||||
ip_destination = base.Field('IPDestination')
|
||||
mac_source = MACSourceField('MACSource')
|
||||
mac_destination = base.Field('MACDestination')
|
||||
vlan_id = VLANIdField('VLANId')
|
||||
l4_source_port = L4SourcePortField('L4SourcePort')
|
||||
l4_destination_port = base.Field('L4DestinationPort',
|
||||
adapter=rsd_lib_utils.int_or_none)
|
||||
l4_protocol = base.Field('L4Protocol')
|
||||
|
||||
|
||||
class ACLRule(base.ResourceBase):
|
||||
|
||||
identity = base.Field('Id')
|
||||
"""The acl rule identity string"""
|
||||
|
||||
name = base.Field('Name')
|
||||
"""The acl rule name"""
|
||||
|
||||
description = base.Field('Description')
|
||||
"""The acl rule description"""
|
||||
|
||||
rule_id = base.Field('RuleId', adapter=rsd_lib_utils.int_or_none)
|
||||
"""The acl rule id"""
|
||||
|
||||
action = base.Field('Action')
|
||||
"""The acl rule action"""
|
||||
|
||||
forward_mirror_interface = base.Field(
|
||||
'ForwardMirrorInterface',
|
||||
adapter=rsd_lib_utils.get_resource_identity)
|
||||
"""The acl rule forward mirror interface"""
|
||||
|
||||
mirror_port_region = base.Field('MirrorPortRegion',
|
||||
adapter=utils.get_members_identities)
|
||||
"""The acl rule mirror port region"""
|
||||
|
||||
mirror_type = base.Field('MirrorType')
|
||||
"""The acl rule mirror type"""
|
||||
|
||||
condition = ConditionField('Condition')
|
||||
"""The acl rule condition field"""
|
||||
|
||||
oem = base.Field('Oem')
|
||||
"""The ac rule oem field"""
|
||||
|
||||
links = base.Field('Links')
|
||||
"""The acl rule links field"""
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None):
|
||||
"""A class representing an ACL Rule
|
||||
|
||||
:param connector: A connector instance
|
||||
:param identity: The identity of the ACL Rule resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of the given version.
|
||||
"""
|
||||
super(ACLRule, self).__init__(connector, identity, redfish_version)
|
||||
|
||||
|
||||
class ACLRuleCollection(base.ResourceCollectionBase):
|
||||
|
||||
@property
|
||||
def _resource_type(self):
|
||||
return ACLRule
|
||||
|
||||
def __init__(self, connector, path, redfish_version=None):
|
||||
"""A class representing an ACL Rule Collection
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param path: The canonical path to the ACL Rule collection resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of the given version.
|
||||
"""
|
||||
super(ACLRuleCollection, self).__init__(connector,
|
||||
path,
|
||||
redfish_version)
|
46
rsd_lib/tests/unit/json_samples/v2_1/acl_rule.json
Normal file
46
rsd_lib/tests/unit/json_samples/v2_1/acl_rule.json
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#EthernetSwitches/Members/Switch1/ACLs/Members/Rules/Members/$entity",
|
||||
"@odata.id": "/redfish/v1/EthernetSwitches/Switch1/ACLs/ACL1/Rules/Rule1",
|
||||
"@odata.type": "#EthernetSwitchACLRule.v1_0_0.EthernetSwitchACLRule",
|
||||
"Id": "Rule1",
|
||||
"Name": "Example Rule",
|
||||
"Description": "User defined rule for ACL",
|
||||
"RuleId": 1,
|
||||
"Action": "Mirror",
|
||||
"ForwardMirrorInterface": {
|
||||
"@odata.id": "/redfish/v1/EthernetSwitches/Switch1/Ports/Port9"
|
||||
},
|
||||
"MirrorPortRegion": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/EthernetSwitches/Switch1/Ports/Port1"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/EthernetSwitches/Switch1/Ports/Port2"
|
||||
}
|
||||
],
|
||||
"MirrorType": "Bidirectional",
|
||||
"Condition": {
|
||||
"IPSource": {
|
||||
"IPv4Address": "192.168.1.0",
|
||||
"Mask": "0.0.0.255"
|
||||
},
|
||||
"IPDestination": null,
|
||||
"MACSource": {
|
||||
"Address": "00:11:22:33:44:55",
|
||||
"Mask": null
|
||||
},
|
||||
"MACDestination": null,
|
||||
"VLANId": {
|
||||
"Id": 1088,
|
||||
"Mask": 4095
|
||||
},
|
||||
"L4SourcePort": {
|
||||
"Port": 22,
|
||||
"Mask": 255
|
||||
},
|
||||
"L4DestinationPort": null,
|
||||
"L4Protocol": null
|
||||
},
|
||||
"Oem": {},
|
||||
"Links": {}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#EthernetSwitches/Members/Switch1/ACLs/Members/Rules",
|
||||
"@odata.id": "/redfish/v1/EthernetSwitches/Switch1/ACLs/ACL1/Rules",
|
||||
"@odata.type": "#EthernetSwitchACLRuleCollection.EthernetSwitchACLRuleCollection",
|
||||
"Name": "Ethernet Switch Access Control List Rules Collection",
|
||||
"Description": "Rules for switch Access Control List. Each Rule defines single action and at least one condition",
|
||||
"Members@odata.count": 1,
|
||||
"Members": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/EthernetSwitches/Switch1/ACLs/ACL1/Rules/Rule1"
|
||||
}
|
||||
]
|
||||
}
|
@ -18,7 +18,10 @@ import json
|
||||
import mock
|
||||
import testtools
|
||||
|
||||
from sushy import exceptions
|
||||
|
||||
from rsd_lib.resources.v2_1.ethernet_switch import acl
|
||||
from rsd_lib.resources.v2_1.ethernet_switch import acl_rule
|
||||
|
||||
|
||||
class ACLTestCase(testtools.TestCase):
|
||||
@ -36,7 +39,7 @@ class ACLTestCase(testtools.TestCase):
|
||||
redfish_version='1.0.2'
|
||||
)
|
||||
|
||||
def test__parst_attributes(self):
|
||||
def test__parse_attributes(self):
|
||||
self.acl_inst._parse_attributes()
|
||||
self.assertEqual('1.0.2', self.acl_inst.redfish_version)
|
||||
self.assertEqual('ACL1', self.acl_inst.identity)
|
||||
@ -44,8 +47,67 @@ class ACLTestCase(testtools.TestCase):
|
||||
self.acl_inst.name)
|
||||
self.assertEqual('Switch ACL', self.acl_inst.description)
|
||||
self.assertEqual({}, self.acl_inst.oem)
|
||||
self.assertEqual('/redfish/v1/EthernetSwitches/Switch1/ACLs/ACL1/'
|
||||
'Rules', self.acl_inst.rules)
|
||||
self.assertIsNone(self.acl_inst._rules)
|
||||
|
||||
def test__get_acl_rule_collection_path(self):
|
||||
self.assertEqual(
|
||||
'/redfish/v1/EthernetSwitches/Switch1/ACLs/ACL1/Rules',
|
||||
self.acl_inst._get_acl_rule_collection_path())
|
||||
|
||||
def test__get_acl_rule_collection_path_missing_attr(self):
|
||||
self.acl_inst._json.pop('Rules')
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError, 'attribute ACLRule',
|
||||
self.acl_inst._get_acl_rule_collection_path)
|
||||
|
||||
def test_acl_rule(self):
|
||||
# check for the underpath variable value
|
||||
self.assertIsNone(self.acl_inst._rules)
|
||||
# | GIVEN |
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_1/'
|
||||
'ethernet_switch_acl.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN |
|
||||
actual_acl_rules = self.acl_inst.rules
|
||||
# | THEN |
|
||||
self.assertIsInstance(actual_acl_rules,
|
||||
acl_rule.ACLRuleCollection)
|
||||
self.conn.get.return_value.json.assert_called_once_with()
|
||||
|
||||
# reset mock
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
# | WHEN & THEN |
|
||||
# tests for same object on invoking subsequently
|
||||
self.assertIs(actual_acl_rules,
|
||||
self.acl_inst.rules)
|
||||
self.conn.get.return_value.json.assert_not_called()
|
||||
|
||||
def test_acl_rule_on_refresh(self):
|
||||
# | GIVEN |
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_1/'
|
||||
'acl_rule_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN & THEN |
|
||||
self.assertIsInstance(self.acl_inst.rules,
|
||||
acl_rule.ACLRuleCollection)
|
||||
|
||||
# On refreshing the acl_rule instance...
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_1/'
|
||||
'ethernet_switch_acl.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
self.acl_inst.refresh()
|
||||
|
||||
# | WHEN & THEN |
|
||||
self.assertIsNone(self.acl_inst._rules)
|
||||
|
||||
# | GIVEN |
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_1/'
|
||||
'acl_rule_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN & THEN |
|
||||
self.assertIsInstance(self.acl_inst.rules,
|
||||
acl_rule.ACLRuleCollection)
|
||||
|
||||
|
||||
class ACLCollectionTestCase(testtools.TestCase):
|
||||
|
@ -0,0 +1,114 @@
|
||||
# Copyright 2018 99cloud, Inc.
|
||||
# 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.
|
||||
|
||||
import json
|
||||
|
||||
import mock
|
||||
import testtools
|
||||
|
||||
from rsd_lib.resources.v2_1.ethernet_switch import acl_rule
|
||||
|
||||
|
||||
class ACLRuleTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ACLRuleTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_1/acl_rule.json',
|
||||
'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
|
||||
self.acl_rule_inst = acl_rule.ACLRule(
|
||||
self.conn,
|
||||
'/redfish/v1/EthernetSwitches/Switch1/ACLs/ACL1/Rules/Rule1',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.acl_rule_inst._parse_attributes()
|
||||
self.assertEqual('1.0.2', self.acl_rule_inst.redfish_version)
|
||||
self.assertEqual('Rule1', self.acl_rule_inst.identity)
|
||||
self.assertEqual('Example Rule', self.acl_rule_inst.name)
|
||||
self.assertEqual('User defined rule for ACL',
|
||||
self.acl_rule_inst.description)
|
||||
self.assertEqual(1, self.acl_rule_inst.rule_id)
|
||||
self.assertEqual('Mirror', self.acl_rule_inst.action)
|
||||
self.assertEqual('/redfish/v1/EthernetSwitches/Switch1/Ports/Port9',
|
||||
self.acl_rule_inst.forward_mirror_interface)
|
||||
self.assertEqual(('/redfish/v1/EthernetSwitches/Switch1/Ports/Port1',
|
||||
'/redfish/v1/EthernetSwitches/Switch1/Ports/Port2',),
|
||||
self.acl_rule_inst.mirror_port_region)
|
||||
self.assertEqual('Bidirectional',
|
||||
self.acl_rule_inst.mirror_type)
|
||||
self.assertEqual('192.168.1.0',
|
||||
self.acl_rule_inst.condition.ip_source.ipv4_address)
|
||||
self.assertEqual('0.0.0.255',
|
||||
self.acl_rule_inst.condition.ip_source.mask)
|
||||
self.assertEqual(None, self.acl_rule_inst.condition.ip_destination)
|
||||
self.assertEqual('00:11:22:33:44:55',
|
||||
self.acl_rule_inst.condition.mac_source.address)
|
||||
self.assertEqual(None, self.acl_rule_inst.condition.mac_source.mask)
|
||||
self.assertEqual(1088, self.acl_rule_inst.condition.vlan_id.id)
|
||||
self.assertEqual(4095,
|
||||
self.acl_rule_inst.condition.vlan_id.mask)
|
||||
self.assertEqual(22,
|
||||
self.acl_rule_inst.condition.l4_source_port.port)
|
||||
self.assertEqual(255,
|
||||
self.acl_rule_inst.condition.l4_source_port.mask)
|
||||
self.assertEqual(None,
|
||||
self.acl_rule_inst.condition.l4_destination_port)
|
||||
|
||||
|
||||
class ACLRuleCollectionTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ACLRuleCollectionTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_1/'
|
||||
'acl_rule_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
|
||||
self.acl_rule_col = acl_rule.ACLRuleCollection(
|
||||
self.conn,
|
||||
'/redfish/v1/EthernetSwitches/Switch1/ACLs/ACL1/Rules',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.acl_rule_col._parse_attributes()
|
||||
self.assertEqual('1.0.2', self.acl_rule_col.redfish_version)
|
||||
self.assertEqual('Ethernet Switch Access Control '
|
||||
'List Rules Collection',
|
||||
self.acl_rule_col.name)
|
||||
self.assertEqual(('/redfish/v1/EthernetSwitches/Switch1/ACLs/ACL1/'
|
||||
'Rules/Rule1',),
|
||||
self.acl_rule_col.members_identities)
|
||||
|
||||
@mock.patch.object(acl_rule, 'ACLRule', autospec=True)
|
||||
def test_get_member(self, mock_acl_rule):
|
||||
self.acl_rule_col.get_member(
|
||||
'/redfish/v1/EthernetSwitches/Switch1/ACLs/ACL1/Rules/Rule1')
|
||||
|
||||
mock_acl_rule.assert_called_once_with(
|
||||
self.acl_rule_col._conn,
|
||||
'/redfish/v1/EthernetSwitches/Switch1/ACLs/ACL1/Rules/Rule1',
|
||||
redfish_version=self.acl_rule_col.redfish_version
|
||||
)
|
||||
|
||||
@mock.patch.object(acl_rule, 'ACLRule', autospec=True)
|
||||
def test_get_members(self, mock_acl_rule):
|
||||
members = self.acl_rule_col.get_members()
|
||||
self.assertEqual(mock_acl_rule.call_count, 1)
|
||||
self.assertIsInstance(members, list)
|
||||
self.assertEqual(1, len(members))
|
Loading…
x
Reference in New Issue
Block a user