Allow creating/showing LBs with Additional VIPs

Story: 2005608
Task: 30845
Depends-On: https://review.opendev.org/660239

Change-Id: Iabb79df54c5bac5720f2d38d0c812e2ee4b189e8
This commit is contained in:
Adam Harwell 2019-06-10 18:20:19 -07:00 committed by Gregory Thiemonge
parent 685d8cecaf
commit 3b53c1b8e1
6 changed files with 94 additions and 0 deletions

View File

@ -33,6 +33,7 @@ LOAD_BALANCER_ROWS = (
'vip_qos_policy_id', 'vip_qos_policy_id',
'vip_subnet_id', 'vip_subnet_id',
'tags', 'tags',
'additional_vips',
) )
LOAD_BALANCER_COLUMNS = ( LOAD_BALANCER_COLUMNS = (

View File

@ -89,6 +89,13 @@ class CreateLoadBalancer(command.ShowOne):
metavar='<vip_qos_policy_id>', metavar='<vip_qos_policy_id>',
help="Set QoS policy ID for VIP port. Unset with 'None'.", help="Set QoS policy ID for VIP port. Unset with 'None'.",
) )
parser.add_argument(
'--additional-vip',
metavar='subnet-id=<name-or-uuid>[,ip-address=<ip>]',
action='append',
help="Expose an additional VIP on the load balancer. This "
"parameter can be provided more than once."
)
parser.add_argument( parser.add_argument(
'--project', '--project',

View File

@ -12,6 +12,9 @@
# under the License. # under the License.
# #
import functools
import ipaddress
import munch import munch
from openstackclient.identity import common as identity_common from openstackclient.identity import common as identity_common
from osc_lib import exceptions as osc_exc from osc_lib import exceptions as osc_exc
@ -181,6 +184,37 @@ def add_tags_attr_map(attr_map):
attr_map.update(tags_attr_map) attr_map.update(tags_attr_map)
def validate_vip_dict(vip_dict, client_manager):
# We have validation in two places -- _map_attrs checks sub-resources, and
# later _check_attrs does further api-specific validation. We need both for
# additional vips, so we may as well just do both here while we're at it.
if 'subnet_id' not in vip_dict:
raise osc_exc.CommandError(
'Additional VIPs must include a subnet-id.')
subnet_id = get_resource_id(client_manager.neutronclient.list_subnets,
'subnets', vip_dict['subnet_id'])
vip_dict['subnet_id'] = subnet_id
if 'ip_address' in vip_dict:
try:
ipaddress.ip_address(vip_dict['ip_address'])
except ValueError as e:
raise osc_exc.CommandError(str(e))
def handle_additional_vips(vips, client_manager):
additional_vips = []
for vip in vips:
vip_dict = {}
parts = vip.split(',')
for part in parts:
k, v = part.split('=')
vip_dict[k.replace('-', '_')] = v
validate_vip_dict(vip_dict, client_manager)
additional_vips.append(vip_dict)
return additional_vips
def get_loadbalancer_attrs(client_manager, parsed_args): def get_loadbalancer_attrs(client_manager, parsed_args):
attr_map = { attr_map = {
'name': ('name', str), 'name': ('name', str),
@ -231,6 +265,11 @@ def get_loadbalancer_attrs(client_manager, parsed_args):
client_manager.load_balancer.flavor_list client_manager.load_balancer.flavor_list
), ),
'availability_zone': ('availability_zone', str), 'availability_zone': ('availability_zone', str),
'additional_vip': (
'additional_vips',
functools.partial(
handle_additional_vips, client_manager=client_manager)
),
} }
add_tags_attr_map(attr_map) add_tags_attr_map(attr_map)

View File

@ -97,6 +97,13 @@ LOADBALANCER_ATTRS = {
"operating_status": "ONLINE", "operating_status": "ONLINE",
"provider": "octavia", "provider": "octavia",
"flavor_id": uuidutils.generate_uuid(dashed=True), "flavor_id": uuidutils.generate_uuid(dashed=True),
"additional_vips": [{
"subnet_id": uuidutils.generate_uuid(dashed=True),
"ip_address": "192.0.2.156"
}, {
"subnet_id": uuidutils.generate_uuid(dashed=True),
"ip_address": "192.0.2.179"
}],
"tags": ["foo", "bar"] "tags": ["foo", "bar"]
} }

View File

@ -398,6 +398,39 @@ class TestLoadBalancerCreate(TestLoadBalancer):
self.api_mock.load_balancer_create.assert_called_with( self.api_mock.load_balancer_create.assert_called_with(
json={'loadbalancer': lb_info}) json={'loadbalancer': lb_info})
@mock.patch('octaviaclient.osc.v2.utils.get_loadbalancer_attrs')
def test_load_balancer_create_with_additional_vips(self, mock_client):
mock_client.return_value = self.lb_info
arglist = [
'--name', self._lb.name,
'--vip-subnet-id', self._lb.vip_subnet_id,
'--project', self._lb.project_id,
'--additional-vip', 'subnet-id={},ip-address={}'.format(
self._lb.additional_vips[0]['subnet_id'],
self._lb.additional_vips[0]['ip_address']),
'--additional-vip', 'subnet-id={},ip-address={}'.format(
self._lb.additional_vips[1]['subnet_id'],
self._lb.additional_vips[1]['ip_address'])
]
verifylist = [
('name', self._lb.name),
('vip_subnet_id', self._lb.vip_subnet_id),
('project', self._lb.project_id),
('additional_vip', [
'subnet-id={},ip-address={}'.format(
self._lb.additional_vips[0]['subnet_id'],
self._lb.additional_vips[0]['ip_address']),
'subnet-id={},ip-address={}'.format(
self._lb.additional_vips[1]['subnet_id'],
self._lb.additional_vips[1]['ip_address'])])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.load_balancer_create.assert_called_with(
json={'loadbalancer': self.lb_info})
@mock.patch('octaviaclient.osc.v2.utils.get_loadbalancer_attrs') @mock.patch('octaviaclient.osc.v2.utils.get_loadbalancer_attrs')
def test_load_balancer_create_with_provider(self, mock_client): def test_load_balancer_create_with_provider(self, mock_client):
provider = 'foobar' provider = 'foobar'

View File

@ -0,0 +1,7 @@
---
features:
- |
It is now possible to create a loadbalancer with more than one VIP by
passing ``--additional-vip subnet-id=<name-or-uuid>[,ip-address=<ip>]`` to
the create command.
Additional VIPs will also appear in the ``show`` details of a loadbalancer.