From 013c9a4f3a44cb0b81fc7affe9b933e701cb5dba Mon Sep 17 00:00:00 2001 From: melanie witt Date: Fri, 2 Nov 2018 22:27:55 +0000 Subject: Handle multiple ports in AddFloatingIP AddFloatingIP refers to an old nova proxy API to neutron that was deprecated in nova. The neutron API for floating IP associate requires a port to be specified. Currently, the code is selecting the first port if the server has multiple ports. But, an attempt to associate the first port with a floating IP can fail if the first port is not on a network that is attached to an external gateway. In order to make the command work better for users who have a server with multiple ports, we can: 1. Select the port corresponding to the fixed_ip_address, if one was specified 2. Try to associate the floating IP with each port until one of the attempts succeeds, else re-raise the last exception. (404 ExternalGatewayForFloatingIPNotFound from neutron) This also fixes incorrect FakeFloatingIP attributes that were being set in the TestServerAddFloatingIPNetwork unit tests, which were causing the tests to use None as parsed args for ip-address and --fixed-ip-address and thus bypassing code in the 'if parsed_args.fixed_ip_address:' block. Task: 27800 Story: 2004263 Change-Id: I11fbcebf6b00f12a030b000c84dcf1d6b5e86250 --- openstackclient/compute/v2/server.py | 51 +++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 7 deletions(-) (limited to 'openstackclient/compute') diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index 4b0aedd7..9051c8d2 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -23,6 +23,7 @@ import os from novaclient import api_versions from novaclient.v2 import servers +from openstack import exceptions as sdk_exceptions from osc_lib.cli import parseractions from osc_lib.command import command from osc_lib import exceptions @@ -251,13 +252,16 @@ class AddFloatingIP(network_common.NetworkAndComputeCommand): parser.add_argument( "ip_address", metavar="", - help=_("Floating IP address to assign to server (IP only)"), + help=_("Floating IP address to assign to the first available " + "server port (IP only)"), ) parser.add_argument( "--fixed-ip-address", metavar="", help=_( - "Fixed IP address to associate with this floating IP address" + "Fixed IP address to associate with this floating IP address. " + "The first server port containing the fixed IP address will " + "be used" ), ) return parser @@ -274,12 +278,45 @@ class AddFloatingIP(network_common.NetworkAndComputeCommand): compute_client.servers, parsed_args.server, ) - port = list(client.ports(device_id=server.id))[0] - attrs['port_id'] = port.id + ports = list(client.ports(device_id=server.id)) + # If the fixed IP address was specified, we need to find the + # corresponding port. if parsed_args.fixed_ip_address: - attrs['fixed_ip_address'] = parsed_args.fixed_ip_address - - client.update_ip(obj, **attrs) + fip_address = parsed_args.fixed_ip_address + attrs['fixed_ip_address'] = fip_address + for port in ports: + for ip in port.fixed_ips: + if ip['ip_address'] == fip_address: + attrs['port_id'] = port.id + break + else: + continue + break + if 'port_id' not in attrs: + msg = _('No port found for fixed IP address %s') + raise exceptions.CommandError(msg % fip_address) + client.update_ip(obj, **attrs) + else: + # It's possible that one or more ports are not connected to a + # router and thus could fail association with a floating IP. + # Try each port until one succeeds. If none succeed, re-raise the + # last exception. + error = None + for port in ports: + attrs['port_id'] = port.id + try: + client.update_ip(obj, **attrs) + except sdk_exceptions.NotFoundException as exp: + # 404 ExternalGatewayForFloatingIPNotFound from neutron + LOG.info('Skipped port %s because it is not attached to ' + 'an external gateway', port.id) + error = exp + continue + else: + error = None + break + if error: + raise error def take_action_compute(self, client, parsed_args): client.api.floating_ip_add( -- cgit v1.2.1