Merge "Add the functionality to support adding acl rule"

This commit is contained in:
Zuul 2018-09-19 21:14:18 +00:00 committed by Gerrit Code Review
commit d58aa90f83
3 changed files with 285 additions and 3 deletions

View File

@ -13,11 +13,17 @@
# License for the specific language governing permissions and limitations
# under the License.
import logging
from jsonschema import validate
from sushy.resources import base
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
LOG = logging.getLogger(__name__)
class IPSourceField(base.CompositeField):
ipv4_address = base.Field('IPv4Address')
@ -117,3 +123,16 @@ class ACLRuleCollection(base.ResourceCollectionBase):
super(ACLRuleCollection, self).__init__(connector,
path,
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):]

View File

@ -39,3 +39,123 @@ vlan_network_interface_req_schema = {
],
'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
}

View File

@ -14,11 +14,13 @@
# under the License.
import json
import jsonschema
import mock
import testtools
from rsd_lib.resources.v2_1.ethernet_switch import acl_rule
from rsd_lib.tests.unit.fakes import request_fakes
class ACLRuleTestCase(testtools.TestCase):
@ -79,6 +81,12 @@ class ACLRuleCollectionTestCase(testtools.TestCase):
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.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.conn,
@ -99,16 +107,151 @@ class ACLRuleCollectionTestCase(testtools.TestCase):
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
)
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()
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.assertIsInstance(members, list)
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)