diff --git a/requirements.txt b/requirements.txt index c0a2ec8b45..051430d0b6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,6 +12,8 @@ SQLAlchemy<1.1.0,>=1.0.10 # MIT six>=1.9.0 # MIT stevedore>=1.17.1 # Apache-2.0 neutron-lib>=0.4.0 # Apache-2.0 +osc-lib>=1.2.0 # Apache-2.0 +python-openstackclient>=3.3.0 # Apache-2.0 oslo.concurrency>=3.8.0 # Apache-2.0 oslo.config!=3.18.0,>=3.14.0 # Apache-2.0 oslo.db!=4.13.1,!=4.13.2,>=4.10.0 # Apache-2.0 diff --git a/setup.cfg b/setup.cfg index abb047b6bd..6a95ac832c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -46,6 +46,15 @@ oslo.config.opts = nsx = vmware_nsx.opts:list_opts networking_sfc.flowclassifier.drivers = vmware-nsxv-sfc = vmware_nsx.services.flowclassifier.nsx_v.driver:NsxvFlowClassifierDriver +openstack.cli.extension = + nsxclient = vmware_nsx.osc.plugin +openstack.nsxclient.v2 = + port_create = vmware_nsx.osc.v2.port:NsxCreatePort + port_set = vmware_nsx.osc.v2.port:NsxSetPort + router_create = vmware_nsx.osc.v2.router:NsxCreateRouter + router_set = vmware_nsx.osc.v2.router:NsxSetRouter + subnet_create = vmware_nsx.osc.v2.subnet:NsxCreateSubnet + subnet_set = vmware_nsx.osc.v2.subnet:NsxSetSubnet [build_sphinx] source-dir = doc/source diff --git a/test-requirements.txt b/test-requirements.txt index 75d3ae71dc..f90a040098 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -24,3 +24,5 @@ reno>=1.8.0 # Apache2 bandit>=1.1.0 # Apache-2.0 tempest>=12.1.0 # Apache-2.0 pylint==1.4.5 # GPLv2 +python-openstackclient>=3.3.0 # Apache-2.0 +requests-mock>=1.1 # Apache-2.0 diff --git a/vmware_nsx/extensions/routertype.py b/vmware_nsx/extensions/routertype.py index 84e41f1e57..89e5719ccf 100644 --- a/vmware_nsx/extensions/routertype.py +++ b/vmware_nsx/extensions/routertype.py @@ -17,10 +17,11 @@ from neutron_lib import constants ROUTER_TYPE = 'router_type' +VALID_TYPES = ['shared', 'exclusive'] EXTENDED_ATTRIBUTES_2_0 = { 'routers': { ROUTER_TYPE: {'allow_post': True, 'allow_put': True, - 'validate': {'type:values': ['shared', 'exclusive']}, + 'validate': {'type:values': VALID_TYPES}, 'default': constants.ATTR_NOT_SPECIFIED, 'is_visible': True}, } diff --git a/vmware_nsx/osc/__init__.py b/vmware_nsx/osc/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vmware_nsx/osc/plugin.py b/vmware_nsx/osc/plugin.py new file mode 100644 index 0000000000..64d29af03c --- /dev/null +++ b/vmware_nsx/osc/plugin.py @@ -0,0 +1,51 @@ +# Copyright 2016 OpenStack Foundation +# 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 logging + +from osc_lib import utils + +LOG = logging.getLogger(__name__) + +DEFAULT_API_VERSION = '2' +API_VERSION_OPTION = 'vmware_nsx_api_version' +API_NAME = 'nsxclient' +API_VERSIONS = { + '2.0': 'nsxclient.v2_0.client.Client', + '2': 'nsxclient.v2_0.client.Client', +} + + +def make_client(instance): + """Returns a client.""" + nsxclient = utils.get_client_class( + API_NAME, + instance._api_version[API_NAME], + API_VERSIONS) + LOG.debug('Instantiating vmware nsx client: %s', nsxclient) + + client = nsxclient(session=instance.session, + region_name=instance._region_name, + endpoint_type=instance._interface, + insecure=instance._insecure, + ca_cert=instance._cacert) + return client + + +def build_option_parser(parser): + """Hook to add global options""" + + return parser diff --git a/vmware_nsx/osc/v2/__init__.py b/vmware_nsx/osc/v2/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vmware_nsx/osc/v2/port.py b/vmware_nsx/osc/v2/port.py new file mode 100644 index 0000000000..efc5c445ed --- /dev/null +++ b/vmware_nsx/osc/v2/port.py @@ -0,0 +1,85 @@ +# Copyright 2016 VMware, 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. + +"""Port action implementations with nsx extensions""" + +from openstackclient.network.v2 import port + +from vmware_nsx._i18n import _ +from vmware_nsx.osc.v2 import utils + + +def add_nsx_extensions_to_parser(parser, client_manager): + # Provider security group + if 'provider-security-group' in utils.get_extensions(client_manager): + parser.add_argument( + '--provider-security-groups', + metavar='', + action='append', + dest='provider_security_groups', + help=_("Provider security groups") + ) + if 'vnic-index' in utils.get_extensions(client_manager): + # vnic index + parser.add_argument( + '--vnic-index', + type=int, + metavar='', + help=_("Vnic index") + ) + + +# overriding the port module global method, to add the nsx extensions +super_get_attrs = port._get_attrs + + +def _get_plugin_attrs(client_manager, parsed_args): + attrs = super_get_attrs(client_manager, parsed_args) + # Provider security groups + if 'provider-security-group' in utils.get_extensions(client_manager): + if parsed_args.provider_security_groups is not None: + attrs['provider_security_groups'] = ( + parsed_args.provider_security_groups) + parsed_args.provider_security_groups = None + if 'vnic-index' in utils.get_extensions(client_manager): + # Vnic index + if parsed_args.vnic_index is not None: + attrs['vnic_index'] = parsed_args.vnic_index + parsed_args.vnic_index = None + + return attrs + + +port._get_attrs = _get_plugin_attrs + + +class NsxCreatePort(port.CreatePort): + """Create a new port with vmware nsx extensions """ + + def get_parser(self, prog_name): + # Add the nsx attributes to the neutron port attributes + parser = super(NsxCreatePort, self).get_parser(prog_name) + add_nsx_extensions_to_parser(parser, self.app.client_manager) + return parser + + +class NsxSetPort(port.SetPort): + """Set port properties with vmware nsx extensions """ + + def get_parser(self, prog_name): + # Add the nsx attributes to the neutron port attributes + parser = super(NsxSetPort, self).get_parser(prog_name) + add_nsx_extensions_to_parser(parser, self.app.client_manager) + return parser diff --git a/vmware_nsx/osc/v2/router.py b/vmware_nsx/osc/v2/router.py new file mode 100644 index 0000000000..2aa8c1f9ba --- /dev/null +++ b/vmware_nsx/osc/v2/router.py @@ -0,0 +1,86 @@ +# Copyright 2016 VMware, 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. + +"""Router action implementations with nsx extensions""" + +from openstackclient.network.v2 import router + +from vmware_nsx._i18n import _ +from vmware_nsx.extensions import routersize +from vmware_nsx.extensions import routertype +from vmware_nsx.osc.v2 import utils + + +def add_nsx_extensions_to_parser(parser, client_manager): + if 'nsxv-router-size' in utils.get_extensions(client_manager): + # router-size + parser.add_argument( + '--router-size', + metavar='', + choices=routersize.VALID_EDGE_SIZES, + help=_("Router Size") + ) + if 'nsxv-router-type' in utils.get_extensions(client_manager): + # router-type + parser.add_argument( + '--router-type', + metavar='', + choices=routertype.VALID_TYPES, + help=_("Router Type") + ) + + +# overriding the router module global method, to add the nsx extensions +super_get_attrs = router._get_attrs + + +def _get_plugin_attrs(client_manager, parsed_args): + attrs = super_get_attrs(client_manager, parsed_args) + + if 'nsxv-router-type' in utils.get_extensions(client_manager): + # Router type + if parsed_args.router_type is not None: + attrs['router_type'] = parsed_args.router_type + parsed_args.router_type = None + if 'nsxv-router-size' in utils.get_extensions(client_manager): + # Router size + if parsed_args.router_size is not None: + attrs['router_size'] = parsed_args.router_size + parsed_args.router_size = None + + return attrs + + +router._get_attrs = _get_plugin_attrs + + +class NsxCreateRouter(router.CreateRouter): + """Create a new router with vmware nsx extensions """ + + def get_parser(self, prog_name): + # Add the nsx attributes to the neutron router attributes + parser = super(NsxCreateRouter, self).get_parser(prog_name) + add_nsx_extensions_to_parser(parser, self.app.client_manager) + return parser + + +class NsxSetRouter(router.SetRouter): + """Set router properties with vmware nsx extensions """ + + def get_parser(self, prog_name): + # Add the nsx attributes to the neutron router attributes + parser = super(NsxSetRouter, self).get_parser(prog_name) + add_nsx_extensions_to_parser(parser, self.app.client_manager) + return parser diff --git a/vmware_nsx/osc/v2/subnet.py b/vmware_nsx/osc/v2/subnet.py new file mode 100644 index 0000000000..a1d2025c4e --- /dev/null +++ b/vmware_nsx/osc/v2/subnet.py @@ -0,0 +1,83 @@ +# Copyright 2016 VMware, 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. + +"""Subnet extensions action implementations""" + +from openstackclient.network.v2 import subnet + +from vmware_nsx._i18n import _ +from vmware_nsx.osc.v2 import utils + + +def add_nsx_extensions_to_parser(parser, client_manager): + if 'dhcp-mtu' in utils.get_extensions(client_manager): + # DHCP MTU + parser.add_argument( + '--dhcp-mtu', + type=int, + metavar='', + help=_("DHCP MTU") + ) + if 'dns-search-domain' in utils.get_extensions(client_manager): + # DNS search domain + parser.add_argument( + '--dns-search-domain', + metavar='', + help=_("DNS search Domain") + ) + + +# overriding the subnet module global method, to add the nsx extensions +super_get_attrs = subnet._get_attrs + + +def _get_plugin_attrs(client_manager, parsed_args, is_create=True): + attrs = super_get_attrs(client_manager, parsed_args, is_create) + + if 'dhcp-mtu' in utils.get_extensions(client_manager): + # DHCP MTU + if parsed_args.dhcp_mtu is not None: + attrs['dhcp_mtu'] = int(parsed_args.dhcp_mtu) + parsed_args.dhcp_mtu = None + if 'dns-search-domain' in utils.get_extensions(client_manager): + # DNS search domain + if parsed_args.dns_search_domain is not None: + attrs['dns_search_domain'] = parsed_args.dns_search_domain + parsed_args.dns_search_domain = None + + return attrs + + +subnet._get_attrs = _get_plugin_attrs + + +class NsxCreateSubnet(subnet.CreateSubnet): + """Create a new subnet with vmware nsx extensions """ + + def get_parser(self, prog_name): + # Add the nsx attributes to the neutron subnet attributes + parser = super(NsxCreateSubnet, self).get_parser(prog_name) + add_nsx_extensions_to_parser(parser, self.app.client_manager) + return parser + + +class NsxSetSubnet(subnet.SetSubnet): + """Set subnet properties with vmware nsx extensions """ + + def get_parser(self, prog_name): + # Add the nsx attributes to the neutron subnet attributes + parser = super(NsxSetSubnet, self).get_parser(prog_name) + add_nsx_extensions_to_parser(parser, self.app.client_manager) + return parser diff --git a/vmware_nsx/osc/v2/utils.py b/vmware_nsx/osc/v2/utils.py new file mode 100644 index 0000000000..69c5b20f31 --- /dev/null +++ b/vmware_nsx/osc/v2/utils.py @@ -0,0 +1,36 @@ +# Copyright 2016 VMware, 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 osc_lib import utils as osc_utils + + +cached_extensions = None + + +def get_extensions(client_manager): + """Return a list of all current extensions aliases""" + # Return previously calculated results + if cached_extensions is not None: + return cached_extensions + # Get supported extensions from the manager + data = client_manager.network.extensions() + extensions = [] + for s in data: + prop = osc_utils.get_item_properties( + s, ('Alias',), formatters={}) + extensions.append(prop[0]) + # Save the results in the global cache + global cached_extensions + cached_extensions = extensions + return extensions diff --git a/vmware_nsx/tests/unit/osc/__init__.py b/vmware_nsx/tests/unit/osc/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vmware_nsx/tests/unit/osc/v2/__init__.py b/vmware_nsx/tests/unit/osc/v2/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vmware_nsx/tests/unit/osc/v2/test_port.py b/vmware_nsx/tests/unit/osc/v2/test_port.py new file mode 100644 index 0000000000..08806737e2 --- /dev/null +++ b/vmware_nsx/tests/unit/osc/v2/test_port.py @@ -0,0 +1,128 @@ +# Copyright 2016 VMware, 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 mock +import re + +from openstackclient.tests.unit.network.v2 import test_port +from openstackclient.tests.unit import utils as tests_utils + +from vmware_nsx.osc.v2 import port + + +supported_extensions = ('vnic-index', 'provider-security-group') + + +class TestCreatePort(test_port.TestCreatePort): + + def setUp(self): + super(TestCreatePort, self).setUp() + # Get the command object to test + self.cmd = port.NsxCreatePort(self.app, self.namespace) + # mock the relevant extensions + get_ext = mock.patch('vmware_nsx.osc.v2.utils.get_extensions').start() + get_ext.return_value = supported_extensions + + def _test_create_with_arg_and_val(self, arg_name, arg_val, is_valid=True): + self.network.create_port.reset_mock() + # add '--' to the arg name and change '_' to '-' + conv_name = '--' + re.sub('_', '-', arg_name) + arglist = [ + self._port.name, + '--network', self._port.network_id, + conv_name, str(arg_val) + ] + verifylist = [ + ('name', self._port.name), + ('network', self._port.network_id,), + (arg_name, arg_val), + ('enable', True), + ] + if not is_valid: + self.assertRaises(tests_utils.ParserException, self.check_parser, + self.cmd, arglist, verifylist) + return + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = (self.cmd.take_action(parsed_args)) + self.network.create_port.assert_called_once_with(**{ + 'admin_state_up': True, + 'network_id': self._port.network_id, + 'name': self._port.name, + arg_name: arg_val, + }) + + ref_columns, ref_data = self._get_common_cols_data(self._port) + self.assertEqual(ref_columns, columns) + self.assertEqual(ref_data, data) + + def _test_create_with_vnix_index(self, val, is_valid=True): + self._test_create_with_arg_and_val('vnic_index', val, is_valid) + + def test_create_with_vnic_index(self): + self._test_create_with_vnix_index(1) + + def test_create_with_illegal_vnic_index(self): + self._test_create_with_vnix_index('illegal', is_valid=False) + + +class TestSetPort(test_port.TestSetPort): + + def setUp(self): + super(TestSetPort, self).setUp() + # Get the command object to test + self.cmd = port.NsxSetPort(self.app, self.namespace) + # mock the relevant extensions + get_ext = mock.patch('vmware_nsx.osc.v2.utils.get_extensions').start() + get_ext.return_value = supported_extensions + + def _test_set_with_arg_and_val(self, arg_name, arg_val, is_valid=True): + self.network.update_port.reset_mock() + # add '--' to the arg name and change '_' to '-' + conv_name = '--' + re.sub('_', '-', arg_name) + arglist = [ + self._port.name, + conv_name, str(arg_val) + ] + verifylist = [ + ('port', self._port.name), + (arg_name, arg_val) + ] + if not is_valid: + self.assertRaises(tests_utils.ParserException, self.check_parser, + self.cmd, arglist, verifylist) + return + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + attrs = {arg_name: arg_val} + self.network.update_port.assert_called_once_with( + self._port, **attrs) + self.assertIsNone(result) + + def _test_set_Vnic_index(self, val, is_valid=True): + self._test_set_with_arg_and_val('vnic_index', val, is_valid) + + def test_set_vnic_index(self): + self._test_set_Vnic_index(1) + + def test_set_illegal_vnic_index(self): + # check illegal index + self._test_set_Vnic_index('illegal', is_valid=False) + +# TODO(asarfaty): add tests for provider-security-groups diff --git a/vmware_nsx/tests/unit/osc/v2/test_router.py b/vmware_nsx/tests/unit/osc/v2/test_router.py new file mode 100644 index 0000000000..d72b5df654 --- /dev/null +++ b/vmware_nsx/tests/unit/osc/v2/test_router.py @@ -0,0 +1,151 @@ +# Copyright 2016 VMware, 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 mock +import re + +from openstackclient.tests.unit.network.v2 import test_router +from openstackclient.tests.unit import utils as tests_utils + +from vmware_nsx.extensions import routersize +from vmware_nsx.extensions import routertype +from vmware_nsx.osc.v2 import router + + +supported_extensions = ('nsxv-router-size', 'nsxv-router-type') + + +class TestCreateRouter(test_router.TestCreateRouter): + + def setUp(self): + super(TestCreateRouter, self).setUp() + # Get the command object to test + self.cmd = router.NsxCreateRouter(self.app, self.namespace) + # mock the relevant extensions + get_ext = mock.patch('vmware_nsx.osc.v2.utils.get_extensions').start() + get_ext.return_value = supported_extensions + + def _test_create_with_arg_and_val(self, arg_name, arg_val, is_valid=True): + self.network.create_router.reset_mock() + # add '--' to the arg name and change '_' to '-' + conv_name = '--' + re.sub('_', '-', arg_name) + arglist = [ + self.new_router.name, + conv_name, arg_val + ] + verifylist = [ + ('name', self.new_router.name), + (arg_name, arg_val), + ('enable', True), + ('distributed', False), + ] + if not is_valid: + self.assertRaises(tests_utils.ParserException, self.check_parser, + self.cmd, arglist, verifylist) + return + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = (self.cmd.take_action(parsed_args)) + self.network.create_router.assert_called_once_with(**{ + 'admin_state_up': True, + 'name': self.new_router.name, + arg_name: arg_val, + }) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + def _test_create_with_size(self, size, is_valid=True): + self._test_create_with_arg_and_val('router_size', size, is_valid) + + def test_create_with_sizes(self): + # check all router types + for rtr_size in routersize.VALID_EDGE_SIZES: + self._test_create_with_size(rtr_size) + + def test_create_with_illegal_size(self): + self._test_create_with_size('illegal', is_valid=False) + + def _test_create_with_type(self, rtr_type, is_valid=True): + self._test_create_with_arg_and_val('router_type', rtr_type, is_valid) + + def test_create_with_types(self): + # check all router types + for rtr_type in routertype.VALID_TYPES: + self._test_create_with_type(rtr_type) + + def test_create_with_illegal_type(self): + self._test_create_with_type('illegal', is_valid=False) + + +class TestSetRouter(test_router.TestSetRouter): + + def setUp(self): + super(TestSetRouter, self).setUp() + # Get the command object to test + self.cmd = router.NsxSetRouter(self.app, self.namespace) + # mock the relevant extensions + get_ext = mock.patch('vmware_nsx.osc.v2.utils.get_extensions').start() + get_ext.return_value = supported_extensions + + def _test_set_with_arg_and_val(self, arg_name, arg_val, is_valid=True): + self.network.update_router.reset_mock() + # add '--' to the arg name and change '_' to '-' + conv_name = '--' + re.sub('_', '-', arg_name) + arglist = [ + self._router.name, + conv_name, arg_val + ] + verifylist = [ + ('router', self._router.name), + (arg_name, arg_val) + ] + if not is_valid: + self.assertRaises(tests_utils.ParserException, self.check_parser, + self.cmd, arglist, verifylist) + return + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + attrs = {arg_name: arg_val} + self.network.update_router.assert_called_once_with( + self._router, **attrs) + self.assertIsNone(result) + + def _test_set_size(self, size, is_valid=True): + self._test_set_with_arg_and_val('router_size', size, is_valid) + + def test_set_sizes(self): + # check all router types + for rtr_size in routersize.VALID_EDGE_SIZES: + self._test_set_size(rtr_size) + + def test_set_illegal_size(self): + # check illegal size + self._test_set_size('illegal', is_valid=False) + + def _test_set_type(self, rtr_type, is_valid=True): + self._test_set_with_arg_and_val('router_type', rtr_type, is_valid) + + def test_set_types(self): + # check all router types + for rtr_type in routertype.VALID_TYPES: + self._test_set_type(rtr_type) + + def test_set_illegal_type(self): + self._test_set_type('illegal', is_valid=False) diff --git a/vmware_nsx/tests/unit/osc/v2/test_subnet.py b/vmware_nsx/tests/unit/osc/v2/test_subnet.py new file mode 100644 index 0000000000..f4344f56d4 --- /dev/null +++ b/vmware_nsx/tests/unit/osc/v2/test_subnet.py @@ -0,0 +1,145 @@ +# Copyright 2016 VMware, 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 mock +import re + +from openstackclient.tests.unit.network.v2 import test_subnet +from openstackclient.tests.unit import utils as tests_utils + +from vmware_nsx.osc.v2 import subnet + + +supported_extensions = ('dhcp-mtu', 'dns-search-domain') + + +class TestCreateSubnet(test_subnet.TestCreateSubnet): + + def setUp(self): + super(TestCreateSubnet, self).setUp() + # Get the command object to test + self.cmd = subnet.NsxCreateSubnet(self.app, self.namespace) + # mock the relevant extensions + get_ext = mock.patch('vmware_nsx.osc.v2.utils.get_extensions').start() + get_ext.return_value = supported_extensions + + def _test_create_with_arg_and_val(self, arg_name, arg_val, is_valid=True): + self.network.create_subnet = mock.Mock(return_value=self._subnet) + # add '--' to the arg name and change '_' to '-' + conv_name = '--' + re.sub('_', '-', arg_name) + arglist = [ + "--subnet-range", self._subnet.cidr, + "--network", self._subnet.network_id, + conv_name, str(arg_val), + self._subnet.name + ] + verifylist = [ + ('name', self._subnet.name), + ('subnet_range', self._subnet.cidr), + ('network', self._subnet.network_id), + ('ip_version', self._subnet.ip_version), + ('gateway', 'auto'), + (arg_name, arg_val), + ] + if not is_valid: + self.assertRaises(tests_utils.ParserException, self.check_parser, + self.cmd, arglist, verifylist) + return + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + self.network.create_subnet.assert_called_once_with(**{ + 'cidr': mock.ANY, + 'ip_version': mock.ANY, + 'network_id': mock.ANY, + 'name': self._subnet.name, + arg_name: arg_val, + }) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + def _test_create_with_mtu(self, mtu, is_valid=True): + self._test_create_with_arg_and_val('dhcp_mtu', mtu, is_valid) + + def test_create_with_mtu(self): + # check a valid value + self._test_create_with_mtu(1500) + + def test_create_with_illegal_mtu(self): + self._test_create_with_mtu('illegal', is_valid=False) + + def _test_create_with_search_domain(self, val, is_valid=True): + self._test_create_with_arg_and_val('dns_search_domain', val, is_valid) + + def test_create_with_search_domain(self): + # check a valid value + self._test_create_with_search_domain('www.aaa.com') + + # Cannot check illegal search domain - validation is on the server side + + +class TestSetSubnet(test_subnet.TestSetSubnet): + + def setUp(self): + super(TestSetSubnet, self).setUp() + # Get the command object to test + self.cmd = subnet.NsxSetSubnet(self.app, self.namespace) + # mock the relevant extensions + get_ext = mock.patch('vmware_nsx.osc.v2.utils.get_extensions').start() + get_ext.return_value = supported_extensions + + def _test_set_with_arg_and_val(self, arg_name, arg_val, is_valid=True): + # add '--' to the arg name and change '_' to '-' + conv_name = '--' + re.sub('_', '-', arg_name) + arglist = [ + conv_name, str(arg_val), + self._subnet.name, + ] + verifylist = [ + (arg_name, arg_val), + ('subnet', self._subnet.name), + ] + + if not is_valid: + self.assertRaises(tests_utils.ParserException, self.check_parser, + self.cmd, arglist, verifylist) + return + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) + attrs = { + arg_name: arg_val + } + self.network.update_subnet.assert_called_with(self._subnet, **attrs) + self.assertIsNone(result) + + def _test_set_mtu(self, mtu, is_valid=True): + self._test_set_with_arg_and_val('dhcp_mtu', mtu, is_valid) + + def test_set_mtu(self): + # check a valid value + self._test_set_mtu(1500) + + def test_set_illegal_mtu(self): + self._test_set_mtu('illegal', is_valid=False) + + def _test_set_with_search_domain(self, val, is_valid=True): + self._test_set_with_arg_and_val('dns_search_domain', val, is_valid) + + def test_set_with_search_domain(self): + # check a valid value + self._test_set_with_search_domain('www.aaa.com')