Add support for ERSPAN
Add support for ERSPAN extension on the openstack port resource. Change-Id: Ie9c5b429dfab774faef92d514be9110f6795991b
This commit is contained in:
parent
35d30bcf3d
commit
f13e3d5764
111
gbpclient/gbp/v2_0/port.py
Normal file
111
gbpclient/gbp/v2_0/port.py
Normal file
@ -0,0 +1,111 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
"""
|
||||
Port extension implementations
|
||||
"""
|
||||
|
||||
from cliff import hooks
|
||||
from osc_lib.cli import parseractions
|
||||
|
||||
from openstack.network.v2 import port as port_sdk
|
||||
from openstack import resource
|
||||
|
||||
from openstackclient.i18n import _
|
||||
from openstackclient.network.v2 import port
|
||||
|
||||
|
||||
_get_attrs_port_new = port._get_attrs
|
||||
|
||||
|
||||
def _convert_erspan_config(parsed_args):
|
||||
ops = []
|
||||
for opt in parsed_args.apic_erspan_config:
|
||||
addr = {}
|
||||
addr['dest_ip'] = opt['dest-ip']
|
||||
addr['flow_id'] = opt['flow-id']
|
||||
if 'direction' in opt:
|
||||
addr['direction'] = opt['direction']
|
||||
ops.append(addr)
|
||||
return ops
|
||||
|
||||
|
||||
def _get_attrs_port_extension(client_manager, parsed_args):
|
||||
attrs = _get_attrs_port_new(client_manager, parsed_args)
|
||||
if parsed_args.apic_synchronization_state:
|
||||
attrs['apic:synchronization_state'
|
||||
] = parsed_args.apic_synchronization_state
|
||||
if parsed_args.apic_erspan_config:
|
||||
attrs['apic:erspan_config'
|
||||
] = _convert_erspan_config(parsed_args)
|
||||
if parsed_args.no_apic_erspan_config:
|
||||
attrs['apic:erspan_config'] = []
|
||||
return attrs
|
||||
|
||||
|
||||
port._get_attrs = _get_attrs_port_extension
|
||||
|
||||
port_sdk.Port.apic_synchronization_state = resource.Body(
|
||||
'apic:synchronization_state')
|
||||
port_sdk.Port.apic_erspan_config = resource.Body('apic:erspan_config')
|
||||
|
||||
|
||||
class CreateAndSetPortExtension(hooks.CommandHook):
|
||||
|
||||
def get_parser(self, parser):
|
||||
parser.add_argument(
|
||||
'--apic-synchronization-state',
|
||||
metavar="<apic_synchronization_state>",
|
||||
dest='apic_synchronization_state',
|
||||
help=_("Apic synchronization state")
|
||||
)
|
||||
parser.add_argument(
|
||||
'--apic-erspan-config',
|
||||
metavar="<apic_erspan_config>",
|
||||
dest='apic_erspan_config',
|
||||
action=parseractions.MultiKeyValueAction,
|
||||
required_keys=['flow-id', 'dest-ip'],
|
||||
optional_keys=['direction'],
|
||||
help=_("Apic ERSPAN configuration")
|
||||
)
|
||||
parser.add_argument(
|
||||
'--no-apic-erspan-config',
|
||||
dest='no_apic_erspan_config',
|
||||
action='store_true',
|
||||
help=_("Apic ERSPAN configuration")
|
||||
)
|
||||
return parser
|
||||
|
||||
def get_epilog(self):
|
||||
return ''
|
||||
|
||||
def before(self, parsed_args):
|
||||
return parsed_args
|
||||
|
||||
def after(self, parsed_args, return_code):
|
||||
return return_code
|
||||
|
||||
|
||||
class ShowPortExtension(hooks.CommandHook):
|
||||
|
||||
def get_parser(self, parser):
|
||||
return parser
|
||||
|
||||
def get_epilog(self):
|
||||
return ''
|
||||
|
||||
def before(self, parsed_args):
|
||||
return parsed_args
|
||||
|
||||
def after(self, parsed_args, return_code):
|
||||
return return_code
|
145
gbpclient/tests/unit/test_port.py
Normal file
145
gbpclient/tests/unit/test_port.py
Normal file
@ -0,0 +1,145 @@
|
||||
# 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 unittest import mock
|
||||
|
||||
from gbpclient.gbp.v2_0 import port as port_ext
|
||||
from gbpclient.tests.unit import test_cli20
|
||||
from openstackclient.network.v2 import port
|
||||
from openstackclient.tests.unit.network.v2 import fakes as network_fakes
|
||||
from openstackclient.tests.unit.network.v2 import test_port
|
||||
|
||||
|
||||
# Tests for port create with APIC extensions
|
||||
#
|
||||
class TestPortCreate(test_port.TestPort, test_cli20.CLITestV20Base):
|
||||
|
||||
_port = test_port.TestCreatePort._port
|
||||
extension_details = (
|
||||
network_fakes.FakeExtension.create_one_extension()
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
super(TestPortCreate, self).setUp()
|
||||
self.app.client_manager.network.find_extension = mock.Mock(
|
||||
return_value=self.extension_details)
|
||||
fake_net = network_fakes.FakeNetwork.create_one_network({
|
||||
'id': self._port.network_id,
|
||||
})
|
||||
self.network.find_network = mock.Mock(return_value=fake_net)
|
||||
self.network.create_port = mock.Mock(
|
||||
return_value=self._port)
|
||||
self.cmd = port.CreatePort(self.app, self.namespace)
|
||||
|
||||
def test_create_default_options(self):
|
||||
arglist = [
|
||||
self._port.name,
|
||||
"--network", self._port.network_id,
|
||||
]
|
||||
verifylist = [
|
||||
('name', self._port.name),
|
||||
('apic_erspan_config', None),
|
||||
('no_apic_erspan_config', False),
|
||||
]
|
||||
create_ext = port_ext.CreateAndSetPortExtension(self.app)
|
||||
parsed_args = self.check_parser_ext(
|
||||
self.cmd, arglist, verifylist, create_ext)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.network.create_port.assert_called_once_with(**{
|
||||
'admin_state_up': True,
|
||||
'name': self._port.name,
|
||||
'network_id': self._port.network_id,
|
||||
})
|
||||
|
||||
def test_create_all_options(self):
|
||||
arglist = [
|
||||
self._port.name,
|
||||
"--network", self._port.network_id,
|
||||
"--apic-erspan-config", "dest-ip=10.0.0.0,flow-id=1,direction=in",
|
||||
]
|
||||
verifylist = [
|
||||
('name', self._port.name),
|
||||
('apic_erspan_config', [{'dest-ip': '10.0.0.0',
|
||||
'flow-id': '1',
|
||||
'direction': 'in'}]),
|
||||
]
|
||||
create_ext = port_ext.CreateAndSetPortExtension(self.app)
|
||||
parsed_args = self.check_parser_ext(
|
||||
self.cmd, arglist, verifylist, create_ext)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.network.create_port.assert_called_once_with(**{
|
||||
'admin_state_up': True,
|
||||
'name': self._port.name,
|
||||
'apic:erspan_config': [{"dest_ip": "10.0.0.0",
|
||||
"flow_id": "1",
|
||||
"direction": "in"}],
|
||||
'network_id': self._port.network_id,
|
||||
})
|
||||
|
||||
|
||||
# Tests for port set with APIC extensions
|
||||
#
|
||||
class TestPortSet(test_port.TestPort, test_cli20.CLITestV20Base):
|
||||
|
||||
_port = test_port.TestSetPort._port
|
||||
|
||||
def setUp(self):
|
||||
super(TestPortSet, self).setUp()
|
||||
self.network.update_port = mock.Mock(return_value=None)
|
||||
self.network.find_port = mock.Mock(return_value=self._port)
|
||||
self.cmd = port.SetPort(self.app, self.namespace)
|
||||
|
||||
def test_set_no_options(self):
|
||||
arglist = [
|
||||
self._port.name,
|
||||
]
|
||||
verifylist = [
|
||||
('port', self._port.name),
|
||||
('apic_erspan_config', None),
|
||||
('no_apic_erspan_config', False),
|
||||
]
|
||||
set_ext = port_ext.CreateAndSetPortExtension(self.app)
|
||||
parsed_args = self.check_parser_ext(
|
||||
self.cmd, arglist, verifylist, set_ext)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.assertFalse(self.network.update_port.called)
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_set_all_valid_options(self):
|
||||
arglist = [
|
||||
self._port.name,
|
||||
"--apic-erspan-config", "dest-ip=10.0.0.0,flow-id=1,direction=in",
|
||||
]
|
||||
verifylist = [
|
||||
('port', self._port.name),
|
||||
('apic_erspan_config', [{'dest-ip': '10.0.0.0',
|
||||
'flow-id': '1',
|
||||
'direction': 'in'}]),
|
||||
]
|
||||
set_ext = port_ext.CreateAndSetPortExtension(self.app)
|
||||
parsed_args = self.check_parser_ext(
|
||||
self.cmd, arglist, verifylist, set_ext)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
|
||||
attrs = {
|
||||
'apic:erspan_config': [{"dest_ip": "10.0.0.0",
|
||||
"flow_id": "1",
|
||||
"direction": "in"}],
|
||||
}
|
||||
|
||||
self.network.update_port.assert_called_once_with(
|
||||
self._port, **attrs)
|
||||
self.assertIsNone(result)
|
14
setup.cfg
14
setup.cfg
@ -14,9 +14,8 @@ classifier =
|
||||
License :: OSI Approved :: Apache Software License
|
||||
Operating System :: POSIX :: Linux
|
||||
Programming Language :: Python
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.6
|
||||
Programming Language :: Python :: 3.7
|
||||
Programming Language :: Python :: 2
|
||||
Programming Language :: Python :: 2.7
|
||||
|
||||
[files]
|
||||
packages =
|
||||
@ -30,6 +29,15 @@ setup-hooks =
|
||||
console_scripts =
|
||||
gbp = gbpclient.gbpshell:main
|
||||
|
||||
openstack.cli.port_create =
|
||||
port_create_extension = gbpclient.gbp.v2_0.port:CreateAndSetPortExtension
|
||||
|
||||
openstack.cli.port_show =
|
||||
port_show_extension = gbpclient.gbp.v2_0.port:ShowPortExtension
|
||||
|
||||
openstack.cli.port_set =
|
||||
port_set_extension = gbpclient.gbp.v2_0.port:CreateAndSetPortExtension
|
||||
|
||||
openstack.cli.network_create =
|
||||
network_create_extension = gbpclient.gbp.v2_0.network:CreateAndSetNetworkExtension
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user