diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index a5d8b0c30a..7259e424de 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -32,6 +32,7 @@ from openstackclient.common import exceptions from openstackclient.common import parseractions from openstackclient.common import utils from openstackclient.i18n import _ # noqa +from openstackclient.network import common def _format_servers_list_networks(networks): @@ -187,6 +188,10 @@ class CreateServer(show.ShowOne): log = logging.getLogger(__name__ + '.CreateServer') + def _is_neutron_enabled(self): + service_catalog = self.app.client_manager.auth_ref.service_catalog + return 'network' in service_catalog.get_endpoints() + def get_parser(self, prog_name): parser = super(CreateServer, self).get_parser(prog_name) parser.add_argument( @@ -372,10 +377,39 @@ class CreateServer(show.ShowOne): block_device_mapping.update({dev_key: block_volume}) nics = [] + if parsed_args.nic: + neutron_enabled = self._is_neutron_enabled() for nic_str in parsed_args.nic: - nic_info = {"net-id": "", "v4-fixed-ip": ""} + nic_info = {"net-id": "", "v4-fixed-ip": "", + "v6-fixed-ip": "", "port-id": ""} nic_info.update(dict(kv_str.split("=", 1) for kv_str in nic_str.split(","))) + if bool(nic_info["net-id"]) == bool(nic_info["port-id"]): + msg = _("either net-id or port-id should be specified " + "but not both") + raise exceptions.CommandError(msg) + if neutron_enabled: + network_client = self.app.client_manager.network + if nic_info["net-id"]: + nic_info["net-id"] = common.find(network_client, + 'network', + 'networks', + nic_info["net-id"]) + if nic_info["port-id"]: + nic_info["port-id"] = common.find(network_client, + 'port', + 'ports', + nic_info["port-id"]) + else: + if nic_info["net-id"]: + nic_info["net-id"] = utils.find_resource( + compute_client.networks, + nic_info["net-id"] + ).id + if nic_info["port-id"]: + msg = _("can't create server with port specified " + "since neutron not enabled") + raise exceptions.CommandError(msg) nics.append(nic_info) hints = {} diff --git a/openstackclient/tests/compute/v2/fakes.py b/openstackclient/tests/compute/v2/fakes.py index e5ed5cbd7d..a22c1ce027 100644 --- a/openstackclient/tests/compute/v2/fakes.py +++ b/openstackclient/tests/compute/v2/fakes.py @@ -17,6 +17,7 @@ import mock from openstackclient.tests import fakes from openstackclient.tests.image.v2 import fakes as image_fakes +from openstackclient.tests.network.v2 import fakes as network_fakes from openstackclient.tests import utils @@ -88,3 +89,8 @@ class TestComputev2(utils.TestCommand): endpoint=fakes.AUTH_URL, token=fakes.AUTH_TOKEN, ) + + self.app.client_manager.network = network_fakes.FakeNetworkV2Client( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) diff --git a/openstackclient/tests/compute/v2/test_server.py b/openstackclient/tests/compute/v2/test_server.py index d51beef369..5a1266970d 100644 --- a/openstackclient/tests/compute/v2/test_server.py +++ b/openstackclient/tests/compute/v2/test_server.py @@ -145,6 +145,82 @@ class TestServerCreate(TestServer): ) self.assertEqual(datalist, data) + def test_server_create_with_network(self): + arglist = [ + '--image', 'image1', + '--flavor', 'flavor1', + '--nic', 'net-id=net1', + '--nic', 'port-id=port1', + compute_fakes.server_id, + ] + verifylist = [ + ('image', 'image1'), + ('flavor', 'flavor1'), + ('nic', ['net-id=net1', 'port-id=port1']), + ('config_drive', False), + ('server_name', compute_fakes.server_id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + get_endpoints = mock.Mock() + get_endpoints.return_value = {'network': []} + self.app.client_manager.auth_ref = mock.Mock() + self.app.client_manager.auth_ref.service_catalog = mock.Mock() + self.app.client_manager.auth_ref.service_catalog.get_endpoints = ( + get_endpoints) + + list_networks = mock.Mock() + list_ports = mock.Mock() + self.app.client_manager.network.list_networks = list_networks + self.app.client_manager.network.list_ports = list_ports + list_networks.return_value = {'networks': [{'id': 'net1_uuid'}]} + list_ports.return_value = {'ports': [{'id': 'port1_uuid'}]} + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # Set expected values + kwargs = dict( + meta=None, + files={}, + reservation_id=None, + min_count=1, + max_count=1, + security_groups=[], + userdata=None, + key_name=None, + availability_zone=None, + block_device_mapping={}, + nics=[{'net-id': 'net1_uuid', + 'v4-fixed-ip': '', + 'v6-fixed-ip': '', + 'port-id': ''}, + {'net-id': '', + 'v4-fixed-ip': '', + 'v6-fixed-ip': '', + 'port-id': 'port1_uuid'}], + scheduler_hints={}, + config_drive=None, + ) + # ServerManager.create(name, image, flavor, **kwargs) + self.servers_mock.create.assert_called_with( + compute_fakes.server_id, + self.image, + self.flavor, + **kwargs + ) + + collist = ('addresses', 'flavor', 'id', 'name', 'properties') + self.assertEqual(collist, columns) + datalist = ( + '', + 'Large ()', + compute_fakes.server_id, + compute_fakes.server_name, + '', + ) + self.assertEqual(datalist, data) + @mock.patch('openstackclient.compute.v2.server.io.open') def test_server_create_userdata(self, mock_open): mock_file = mock.MagicMock(name='File')