Merge "Add the functionality to support adding acl rule"
This commit is contained in:
commit
d58aa90f83
@ -13,11 +13,17 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from jsonschema import validate
|
||||||
from sushy.resources import base
|
from sushy.resources import base
|
||||||
from sushy import utils
|
from sushy import utils
|
||||||
|
|
||||||
|
from rsd_lib.resources.v2_1.ethernet_switch import schemas as acl_rule_schema
|
||||||
from rsd_lib import utils as rsd_lib_utils
|
from rsd_lib import utils as rsd_lib_utils
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class IPSourceField(base.CompositeField):
|
class IPSourceField(base.CompositeField):
|
||||||
ipv4_address = base.Field('IPv4Address')
|
ipv4_address = base.Field('IPv4Address')
|
||||||
@ -117,3 +123,16 @@ class ACLRuleCollection(base.ResourceCollectionBase):
|
|||||||
super(ACLRuleCollection, self).__init__(connector,
|
super(ACLRuleCollection, self).__init__(connector,
|
||||||
path,
|
path,
|
||||||
redfish_version)
|
redfish_version)
|
||||||
|
|
||||||
|
def add_acl_rule(self, acl_rule_req):
|
||||||
|
"""Add a acl rule
|
||||||
|
|
||||||
|
:param acl_rule: JSON for acl_rule
|
||||||
|
:returns: The location of the acl rule
|
||||||
|
"""
|
||||||
|
target_uri = self._path
|
||||||
|
validate(acl_rule_req, acl_rule_schema.acl_rule_req_schema)
|
||||||
|
resp = self._conn.post(target_uri, data=acl_rule_req)
|
||||||
|
acl_rule_url = resp.headers['Location']
|
||||||
|
LOG.info("ACL Rule add at %s", acl_rule_url)
|
||||||
|
return acl_rule_url[acl_rule_url.find(self._path):]
|
||||||
|
@ -39,3 +39,123 @@ vlan_network_interface_req_schema = {
|
|||||||
],
|
],
|
||||||
'additionalProperties': False
|
'additionalProperties': False
|
||||||
}
|
}
|
||||||
|
|
||||||
|
acl_rule_req_schema = {
|
||||||
|
'type': 'object',
|
||||||
|
'oneOf': [
|
||||||
|
{
|
||||||
|
'properties': {
|
||||||
|
'Action': {'enum': ['Forward']}
|
||||||
|
},
|
||||||
|
'required': ['ForwardMirrorInterface']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'properties': {
|
||||||
|
'Action': {'enum': ['Mirror']}
|
||||||
|
},
|
||||||
|
'required': ['ForwardMirrorInterface',
|
||||||
|
'MirrorPortRegion', 'MirrorType']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'properties': {
|
||||||
|
'Action': {'enum': ['Permit', 'Deny']}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'properties': {
|
||||||
|
'RuleId': {'type': 'number'},
|
||||||
|
'Action': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': ['Permit', 'Deny', 'Forward', 'Mirror']
|
||||||
|
},
|
||||||
|
'ForwardMirrorInterface': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'@odata.id': {
|
||||||
|
'type': 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'required': ['@odata.id']
|
||||||
|
},
|
||||||
|
'MirrorPortRegion': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'@odata.id': {
|
||||||
|
'type': 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'required': ['@odata.id']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'MirrorType': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': ['Egress', 'Ingress', 'Bidirectional', 'Redirect']
|
||||||
|
},
|
||||||
|
'Condition': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'IPSource': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'IPv4Addresses': {'type': 'string'},
|
||||||
|
'Mask': {'type': ['string', 'null']}
|
||||||
|
},
|
||||||
|
'required': ['IPv4Address']
|
||||||
|
},
|
||||||
|
'IPDestination': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'IPv4Address': {'type': 'string'},
|
||||||
|
'Mask': {'type': ['string', 'null']}
|
||||||
|
},
|
||||||
|
'required': ['IPv4Address']
|
||||||
|
},
|
||||||
|
'MACSource': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'MACAddress': {'type': 'string'},
|
||||||
|
'Mask': {'type': ['string', 'null']}
|
||||||
|
},
|
||||||
|
'required': ['MACAddress']
|
||||||
|
},
|
||||||
|
'MACDestination': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'MACAddress': {'type': 'string'},
|
||||||
|
'Mask': {'type': ['string', 'null']}
|
||||||
|
},
|
||||||
|
'required': ['MACAddress']
|
||||||
|
},
|
||||||
|
'VLANId': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'Id': {'type': 'number'},
|
||||||
|
'Mask': {'type': ['number', 'null']}
|
||||||
|
},
|
||||||
|
'required': ['Id']
|
||||||
|
},
|
||||||
|
'L4SourcePort': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'Port': {'type': 'number'},
|
||||||
|
'Mask': {'type': ['number', 'null']}
|
||||||
|
},
|
||||||
|
'required': ['Port']
|
||||||
|
},
|
||||||
|
'L4DestinationPort': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'Port': {'type': 'number'},
|
||||||
|
'Mask': {'type': ['number', 'null']}
|
||||||
|
},
|
||||||
|
'required': ['Port']
|
||||||
|
},
|
||||||
|
'L4Protocol': {'type': ['number', 'null']}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'required': ['Action', 'Condition'],
|
||||||
|
'additionalProperties': False
|
||||||
|
}
|
||||||
|
@ -14,11 +14,13 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import jsonschema
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
import testtools
|
import testtools
|
||||||
|
|
||||||
from rsd_lib.resources.v2_1.ethernet_switch import acl_rule
|
from rsd_lib.resources.v2_1.ethernet_switch import acl_rule
|
||||||
|
from rsd_lib.tests.unit.fakes import request_fakes
|
||||||
|
|
||||||
|
|
||||||
class ACLRuleTestCase(testtools.TestCase):
|
class ACLRuleTestCase(testtools.TestCase):
|
||||||
@ -79,6 +81,12 @@ class ACLRuleCollectionTestCase(testtools.TestCase):
|
|||||||
with open('rsd_lib/tests/unit/json_samples/v2_1/'
|
with open('rsd_lib/tests/unit/json_samples/v2_1/'
|
||||||
'acl_rule_collection.json', 'r') as f:
|
'acl_rule_collection.json', 'r') as f:
|
||||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
self.conn.post.return_value = \
|
||||||
|
request_fakes.fake_request_post(
|
||||||
|
None,
|
||||||
|
headers={"Location": "https://localhost:8443/redfish/v1/"
|
||||||
|
"EthernetSwitches/Switch1/ACLs/ACL1/"
|
||||||
|
"Rules/Rule1"})
|
||||||
|
|
||||||
self.acl_rule_col = acl_rule.ACLRuleCollection(
|
self.acl_rule_col = acl_rule.ACLRuleCollection(
|
||||||
self.conn,
|
self.conn,
|
||||||
@ -99,16 +107,151 @@ class ACLRuleCollectionTestCase(testtools.TestCase):
|
|||||||
def test_get_member(self, mock_acl_rule):
|
def test_get_member(self, mock_acl_rule):
|
||||||
self.acl_rule_col.get_member(
|
self.acl_rule_col.get_member(
|
||||||
'/redfish/v1/EthernetSwitches/Switch1/ACLs/ACL1/Rules/Rule1')
|
'/redfish/v1/EthernetSwitches/Switch1/ACLs/ACL1/Rules/Rule1')
|
||||||
|
|
||||||
mock_acl_rule.assert_called_once_with(
|
mock_acl_rule.assert_called_once_with(
|
||||||
self.acl_rule_col._conn,
|
self.acl_rule_col._conn,
|
||||||
'/redfish/v1/EthernetSwitches/Switch1/ACLs/ACL1/Rules/Rule1',
|
'/redfish/v1/EthernetSwitches/Switch1/ACLs/ACL1/Rules/Rule1',
|
||||||
redfish_version=self.acl_rule_col.redfish_version
|
redfish_version=self.acl_rule_col.redfish_version)
|
||||||
)
|
|
||||||
|
|
||||||
@mock.patch.object(acl_rule, 'ACLRule', autospec=True)
|
@mock.patch.object(acl_rule, 'ACLRule', autospec=True)
|
||||||
def test_get_members(self, mock_acl_rule):
|
def test_get_members(self, mock_acl_rule):
|
||||||
members = self.acl_rule_col.get_members()
|
members = self.acl_rule_col.get_members()
|
||||||
|
calls = [
|
||||||
|
mock.call(self.acl_rule_col._conn,
|
||||||
|
'/redfish/v1/EthernetSwitches/Switch1/ACLs/ACL1/'
|
||||||
|
'Rules/Rule1',
|
||||||
|
redfish_version=self.acl_rule_col.redfish_version)
|
||||||
|
]
|
||||||
|
mock_acl_rule.assert_has_calls(calls)
|
||||||
self.assertEqual(mock_acl_rule.call_count, 1)
|
self.assertEqual(mock_acl_rule.call_count, 1)
|
||||||
self.assertIsInstance(members, list)
|
self.assertIsInstance(members, list)
|
||||||
self.assertEqual(1, len(members))
|
self.assertEqual(1, len(members))
|
||||||
|
|
||||||
|
def test_add_acl_rule_reqs(self):
|
||||||
|
reqs = {
|
||||||
|
'RuleId': 1,
|
||||||
|
'Action': 'Mirror',
|
||||||
|
'ForwardMirrorInterface': {
|
||||||
|
'@odata.id': '/redfish/v1/EthernetSwitches/Switch1/Ports/Port9'
|
||||||
|
},
|
||||||
|
'MirrorPortRegion': [
|
||||||
|
{
|
||||||
|
'@odata.id': '/redfish/v1/EthernetSwitches/Switch1/Ports/'
|
||||||
|
'Port1'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'MirrorType': 'Bidirectional',
|
||||||
|
'Condition': {
|
||||||
|
'IPSource': {
|
||||||
|
'IPv4Address': '192.168.8.0',
|
||||||
|
'Mask': '0.0.0.255'
|
||||||
|
},
|
||||||
|
'IPDestination': {
|
||||||
|
'IPv4Address': '192.168.1.0'
|
||||||
|
},
|
||||||
|
'MACSource': {
|
||||||
|
'MACAddress': '00:11:22:33:44:55',
|
||||||
|
},
|
||||||
|
'MACDestination': {
|
||||||
|
'MACAddress': '55:44:33:22:11:00'
|
||||||
|
},
|
||||||
|
'VLANid': {
|
||||||
|
'Id': 1088,
|
||||||
|
'Mask': 4095
|
||||||
|
},
|
||||||
|
'L4SourcePort': {
|
||||||
|
'Port': 22,
|
||||||
|
'Mask': 255
|
||||||
|
},
|
||||||
|
'L4DestinationPort': {
|
||||||
|
'Port': 22,
|
||||||
|
'Mask': 255
|
||||||
|
},
|
||||||
|
'L4Protocol': 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = self.acl_rule_col.add_acl_rule(reqs)
|
||||||
|
self.acl_rule_col._conn.post.assert_called_once_with(
|
||||||
|
'/redfish/v1/EthernetSwitches/Switch1/ACLs/ACL1/Rules',
|
||||||
|
data=reqs)
|
||||||
|
self.assertEqual(result,
|
||||||
|
'/redfish/v1/EthernetSwitches/Switch1/ACLs/ACL1/'
|
||||||
|
'Rules/Rule1')
|
||||||
|
|
||||||
|
def test_add_acl_rule_invalid_reqs(self):
|
||||||
|
reqs = {
|
||||||
|
'RuleId': 1,
|
||||||
|
'Action': 'Mirror',
|
||||||
|
'ForwardMirrorInterface': {
|
||||||
|
'@odata.id': '/redfish/v1/EthernetSwitches/Switch1/Ports/Port9'
|
||||||
|
},
|
||||||
|
'MirrorPortRegion': [
|
||||||
|
{
|
||||||
|
'@odata.id': '/redfish/v1/EthernetSwitches/Switch1/Ports/'
|
||||||
|
'Port1'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'MirrorType': 'Bidirectional',
|
||||||
|
'Condition': {
|
||||||
|
'IPSource': {
|
||||||
|
'IPv4Address': '192.168.8.0',
|
||||||
|
'Mask': '0.0.0.255'
|
||||||
|
},
|
||||||
|
'IPDestination': {
|
||||||
|
'IPv4Address': '192.168.1.0'
|
||||||
|
},
|
||||||
|
'MACSource': {
|
||||||
|
'MACAddress': '00:11:22:33:44:55',
|
||||||
|
},
|
||||||
|
'MACDestination': {
|
||||||
|
'MACAddress': '55:44:33:22:11:00'
|
||||||
|
},
|
||||||
|
'VLANid': {
|
||||||
|
'Id': 1088,
|
||||||
|
'Mask': 4095
|
||||||
|
},
|
||||||
|
'L4SourcePort': {
|
||||||
|
'Port': 22,
|
||||||
|
'Mask': 255
|
||||||
|
},
|
||||||
|
'L4DestinationPort': {
|
||||||
|
'Port': 22,
|
||||||
|
'Mask': 255
|
||||||
|
},
|
||||||
|
'L4Protocol': 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Missing field
|
||||||
|
acl_rule_req = reqs.copy()
|
||||||
|
acl_rule_req.pop('Action')
|
||||||
|
self.assertRaises(jsonschema.exceptions.ValidationError,
|
||||||
|
self.acl_rule_col.add_acl_rule,
|
||||||
|
acl_rule_req)
|
||||||
|
|
||||||
|
# Wrong format
|
||||||
|
acl_rule_req = reqs.copy()
|
||||||
|
acl_rule_req.update({'RuleId': 'WrongFormat'})
|
||||||
|
self.assertRaises(jsonschema.exceptions.ValidationError,
|
||||||
|
self.acl_rule_col.add_acl_rule,
|
||||||
|
acl_rule_req)
|
||||||
|
|
||||||
|
# Wrong additional fields
|
||||||
|
acl_rule_req = reqs.copy()
|
||||||
|
acl_rule_req['Additional'] = 'AdditionalField'
|
||||||
|
self.assertRaises(jsonschema.exceptions.ValidationError,
|
||||||
|
self.acl_rule_col.add_acl_rule,
|
||||||
|
acl_rule_req)
|
||||||
|
|
||||||
|
# Wrong enum
|
||||||
|
acl_rule_req = reqs.copy()
|
||||||
|
acl_rule_req['MirrorType'] = 'WrongEnum'
|
||||||
|
self.assertRaises(jsonschema.exceptions.ValidationError,
|
||||||
|
self.acl_rule_col.add_acl_rule,
|
||||||
|
acl_rule_req)
|
||||||
|
|
||||||
|
# Wrong dependency
|
||||||
|
acl_rule_req = reqs.copy()
|
||||||
|
acl_rule_req.pop('ForwardMirrorInterface')
|
||||||
|
self.assertRaises(jsonschema.exceptions.ValidationError,
|
||||||
|
self.acl_rule_col.add_acl_rule,
|
||||||
|
acl_rule_req)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user