diff --git a/releasenotes/notes/net_provider-dd64b697476b7094.yaml b/releasenotes/notes/net_provider-dd64b697476b7094.yaml new file mode 100644 index 000000000..65a007302 --- /dev/null +++ b/releasenotes/notes/net_provider-dd64b697476b7094.yaml @@ -0,0 +1,3 @@ +--- +features: + - Network provider options are now accepted in create_network(). diff --git a/shade/openstackcloud.py b/shade/openstackcloud.py index bc3fec3b8..aeec649a9 100644 --- a/shade/openstackcloud.py +++ b/shade/openstackcloud.py @@ -1634,16 +1634,17 @@ class OpenStackCloud(object): "Unable to delete keypair %s: %s" % (name, e)) return True - # TODO(Shrews): This will eventually need to support tenant ID and - # provider networks, which are admin-level params. def create_network(self, name, shared=False, admin_state_up=True, - external=False): + external=False, provider=None): """Create a network. :param string name: Name of the network being created. :param bool shared: Set the network as shared. :param bool admin_state_up: Set the network administrative state to up. :param bool external: Whether this network is externally accessible. + :param dict provider: A dict of network provider options. Example:: + + { 'network_type': 'vlan', 'segmentation_id': 'vlan1' } :returns: The network object. :raises: OpenStackCloudException on operation error. @@ -1655,6 +1656,17 @@ class OpenStackCloud(object): 'admin_state_up': admin_state_up, } + if provider: + if not isinstance(provider, dict): + raise OpenStackCloudException( + "Parameter 'provider' must be a dict") + # Only pass what we know + for attr in ('physical_network', 'network_type', + 'segmentation_id'): + if attr in provider: + arg = "provider:" + attr + network[arg] = provider[attr] + # Do not send 'router:external' unless it is explicitly # set since sending it *might* cause "Forbidden" errors in # some situations. It defaults to False in the client, anyway. diff --git a/shade/tests/functional/test_network.py b/shade/tests/functional/test_network.py index 432c63061..26d4264d1 100644 --- a/shade/tests/functional/test_network.py +++ b/shade/tests/functional/test_network.py @@ -67,6 +67,21 @@ class TestNetwork(base.TestCase): self.assertTrue(net1['shared']) self.assertFalse(net1['admin_state_up']) + def test_create_network_provider_flat(self): + net1 = self.cloud.create_network( + name=self.network_name, + shared=True, + provider={ + 'physical_network': 'private', + 'network_type': 'flat', + } + ) + self.assertIn('id', net1) + self.assertEqual(self.network_name, net1['name']) + self.assertEqual('flat', net1['provider:network_type']) + self.assertEqual('private', net1['provider:physical_network']) + self.assertIsNone(net1['provider:segmentation_id']) + def test_list_networks_filtered(self): net1 = self.cloud.create_network(name=self.network_name) self.assertIsNotNone(net1) diff --git a/shade/tests/unit/test_network.py b/shade/tests/unit/test_network.py index 11b39609e..e62c6e920 100644 --- a/shade/tests/unit/test_network.py +++ b/shade/tests/unit/test_network.py @@ -50,6 +50,59 @@ class TestNetwork(base.TestCase): ) ) + @mock.patch.object(shade.OpenStackCloud, 'neutron_client') + def test_create_network_provider(self, mock_neutron): + provider_opts = {'physical_network': 'mynet', + 'network_type': 'vlan', + 'segmentation_id': 'vlan1'} + self.cloud.create_network("netname", provider=provider_opts) + mock_neutron.create_network.assert_called_once_with( + body=dict( + network={ + 'name': 'netname', + 'shared': False, + 'admin_state_up': True, + 'provider:physical_network': + provider_opts['physical_network'], + 'provider:network_type': + provider_opts['network_type'], + 'provider:segmentation_id': + provider_opts['segmentation_id'], + } + ) + ) + + @mock.patch.object(shade.OpenStackCloud, 'neutron_client') + def test_create_network_provider_ignored_value(self, mock_neutron): + provider_opts = {'physical_network': 'mynet', + 'network_type': 'vlan', + 'segmentation_id': 'vlan1', + 'should_not_be_passed': 1} + self.cloud.create_network("netname", provider=provider_opts) + mock_neutron.create_network.assert_called_once_with( + body=dict( + network={ + 'name': 'netname', + 'shared': False, + 'admin_state_up': True, + 'provider:physical_network': + provider_opts['physical_network'], + 'provider:network_type': + provider_opts['network_type'], + 'provider:segmentation_id': + provider_opts['segmentation_id'], + } + ) + ) + + def test_create_network_provider_wrong_type(self): + provider_opts = "invalid" + with testtools.ExpectedException( + shade.OpenStackCloudException, + "Parameter 'provider' must be a dict" + ): + self.cloud.create_network("netname", provider=provider_opts) + @mock.patch.object(shade.OpenStackCloud, 'get_network') @mock.patch.object(shade.OpenStackCloud, 'neutron_client') def test_delete_network(self, mock_neutron, mock_get):