diff --git a/doc/source/command-objects/server.rst b/doc/source/command-objects/server.rst index 55b39ef57d..dc78080b6d 100644 --- a/doc/source/command-objects/server.rst +++ b/doc/source/command-objects/server.rst @@ -138,6 +138,8 @@ Create a new server [--availability-zone <zone-name>] [--block-device-mapping <dev-name=mapping> [...] ] [--nic <net-id=net-uuid,v4-fixed-ip=ip-addr,v6-fixed-ip=ip-addr,port-id=port-uuid,auto,none> [...] ] + [--network <network>] + [--port <port>] [--hint <key=value> [...] ] [--config-drive <value>|True ] [--min <count>] @@ -206,6 +208,20 @@ Create a new server Specifying a --nic of auto or none cannot be used with any other --nic value. +.. option:: --network <network> + + Create a NIC on the server and connect it to network. + Specify option multiple times to create multiple NICs. + For more options on NICs see --nic parameter. + network: attach NIC to this network + +.. option:: --port <port> + + Create a NIC on the server and connect it to port. + Specify option multiple times to create multiple NICs. + For more options on NICs see --nic parameter. + port: attach NIC to this port + .. option:: --hint <key=value> Hints for the scheduler (optional extension) @@ -230,6 +246,16 @@ Create a new server New server name +.. + +The parameters ``--network <network>`` and ``--port <port>`` are actually +wrappers to ``--nic net-id=<network>`` and ``--nic port-id=<port>``. ``--nic`` +also provides additional options to specify an IP address, automatic network +assignment and NICs which are not assigned to any port. This functionality +is not part of ``--network`` and ``--port``, which aim to provide a simple +syntax for the standard use cases of connecting a new server to a given +network or port. + server delete ------------- diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index 81efd9f309..8b4a37217b 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -110,6 +110,16 @@ def _get_ip_address(addresses, address_type, ip_address_family): ) +def _prefix_checked_value(prefix): + def func(value): + if ',' in value or '=' in value: + msg = _("Invalid argument %s, " + "characters ',' and '=' are not allowed") % value + raise argparse.ArgumentTypeError(msg) + return prefix + value + return func + + def _prep_server_detail(compute_client, image_client, server): """Prepare the detailed server dict for printing @@ -447,7 +457,6 @@ class CreateServer(command.ShowOne): metavar="<net-id=net-uuid,v4-fixed-ip=ip-addr,v6-fixed-ip=ip-addr," "port-id=port-uuid,auto,none>", action='append', - default=[], help=_("Create a NIC on the server. " "Specify option multiple times to create multiple NICs. " "Either net-id or port-id must be provided, but not both. " @@ -460,6 +469,28 @@ class CreateServer(command.ShowOne): "allocate a network. Specifying a --nic of auto or none " "cannot be used with any other --nic value."), ) + parser.add_argument( + '--network', + metavar="<network>", + action='append', + dest='nic', + type=_prefix_checked_value('net-id='), + help=_("Create a NIC on the server and connect it to network. " + "Specify option multiple times to create multiple NICs. " + "For more options on NICs see --nic parameter. " + "network: attach NIC to this network "), + ) + parser.add_argument( + '--port', + metavar="<port>", + action='append', + dest='nic', + type=_prefix_checked_value('port-id='), + help=_("Create a NIC on the server and connect it to port. " + "Specify option multiple times to create multiple NICs. " + "For more options on NICs see --nic parameter. " + "port: attach NIC this port "), + ) parser.add_argument( '--hint', metavar='<key=value>', @@ -592,6 +623,8 @@ class CreateServer(command.ShowOne): nics = [] auto_or_none = False + if parsed_args.nic is None: + parsed_args.nic = [] for nic_str in parsed_args.nic: # Handle the special auto/none cases if nic_str in ('auto', 'none'): @@ -607,7 +640,7 @@ class CreateServer(command.ShowOne): msg = _('Invalid --nic argument %s.') % nic_str raise exceptions.CommandError(msg) if bool(nic_info["net-id"]) == bool(nic_info["port-id"]): - msg = _("either net-id or port-id should be specified " + msg = _("either network or port should be specified " "but not both") raise exceptions.CommandError(msg) if self.app.client_manager.is_network_endpoint_enabled(): @@ -636,7 +669,8 @@ class CreateServer(command.ShowOne): if auto_or_none: if len(nics) > 1: msg = _('Specifying a --nic of auto or none cannot ' - 'be used with any other --nic value.') + 'be used with any other --nic, --network ' + 'or --port value.') raise exceptions.CommandError(msg) nics = nics[0] else: diff --git a/openstackclient/tests/unit/compute/v2/test_server.py b/openstackclient/tests/unit/compute/v2/test_server.py index cde43d3222..5d086149e8 100644 --- a/openstackclient/tests/unit/compute/v2/test_server.py +++ b/openstackclient/tests/unit/compute/v2/test_server.py @@ -447,14 +447,18 @@ class TestServerCreate(TestServer): arglist = [ '--image', 'image1', '--flavor', 'flavor1', - '--nic', 'net-id=net1', - '--nic', 'port-id=port1', + '--network', 'net1', + '--nic', 'net-id=net1,v4-fixed-ip=10.0.0.2', + '--port', 'port1', + '--network', 'net1', + '--nic', 'port-id=port2', self.new_server.name, ] verifylist = [ ('image', 'image1'), ('flavor', 'flavor1'), - ('nic', ['net-id=net1', 'port-id=port1']), + ('nic', ['net-id=net1', 'net-id=net1,v4-fixed-ip=10.0.0.2', + 'port-id=port1', 'net-id=net1', 'port-id=port2']), ('config_drive', False), ('server_name', self.new_server.name), ] @@ -474,20 +478,28 @@ class TestServerCreate(TestServer): network_client.find_port = find_port network_resource = mock.Mock() network_resource.id = 'net1_uuid' - port_resource = mock.Mock() - port_resource.id = 'port1_uuid' + port1_resource = mock.Mock() + port1_resource.id = 'port1_uuid' + port2_resource = mock.Mock() + port2_resource.id = 'port2_uuid' find_network.return_value = network_resource - find_port.return_value = port_resource + find_port.side_effect = (lambda port_id, ignore_missing: + {"port1": port1_resource, + "port2": port2_resource}[port_id]) # Mock sdk APIs. _network = mock.Mock() _network.id = 'net1_uuid' - _port = mock.Mock() - _port.id = 'port1_uuid' + _port1 = mock.Mock() + _port1.id = 'port1_uuid' + _port2 = mock.Mock() + _port2.id = 'port2_uuid' find_network = mock.Mock() find_port = mock.Mock() find_network.return_value = _network - find_port.return_value = _port + find_port.side_effect = (lambda port_id, ignore_missing: + {"port1": _port1, + "port2": _port2}[port_id]) self.app.client_manager.network.find_network = find_network self.app.client_manager.network.find_port = find_port @@ -512,10 +524,22 @@ class TestServerCreate(TestServer): 'v4-fixed-ip': '', 'v6-fixed-ip': '', 'port-id': ''}, + {'net-id': 'net1_uuid', + 'v4-fixed-ip': '10.0.0.2', + 'v6-fixed-ip': '', + 'port-id': ''}, {'net-id': '', 'v4-fixed-ip': '', 'v6-fixed-ip': '', - 'port-id': 'port1_uuid'}], + 'port-id': 'port1_uuid'}, + {'net-id': 'net1_uuid', + 'v4-fixed-ip': '', + 'v6-fixed-ip': '', + 'port-id': ''}, + {'net-id': '', + 'v4-fixed-ip': '', + 'v6-fixed-ip': '', + 'port-id': 'port2_uuid'}], scheduler_hints={}, config_drive=None, ) diff --git a/releasenotes/notes/bug-1612898-bea3b68251d12d81.yaml b/releasenotes/notes/bug-1612898-bea3b68251d12d81.yaml new file mode 100644 index 0000000000..e31b75d20a --- /dev/null +++ b/releasenotes/notes/bug-1612898-bea3b68251d12d81.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Add ``--network`` and ``--port`` options to ``server create`` command + as alternatives to ``--nic`` option. + [Bug `1612898 <https://bugs.launchpad.net/bugs/1612898>`_]