Browse Source

Add "--wait" functionality

Change-Id: Ia8e451d7f806fac7d36b2860f256eb34f9f7400e
changes/35/691135/4
Adam Harwell 2 years ago
parent
commit
ae244fcf25
22 changed files with 1441 additions and 75 deletions
  1. +26
    -0
      octaviaclient/api/exceptions.py
  2. +2
    -15
      octaviaclient/api/v2/octavia.py
  3. +42
    -4
      octaviaclient/osc/v2/amphora.py
  4. +2
    -0
      octaviaclient/osc/v2/constants.py
  5. +55
    -0
      octaviaclient/osc/v2/health_monitor.py
  6. +55
    -0
      octaviaclient/osc/v2/l7policy.py
  7. +68
    -0
      octaviaclient/osc/v2/l7rule.py
  8. +51
    -0
      octaviaclient/osc/v2/listener.py
  9. +67
    -1
      octaviaclient/osc/v2/load_balancer.py
  10. +64
    -0
      octaviaclient/osc/v2/member.py
  11. +51
    -0
      octaviaclient/osc/v2/pool.py
  12. +45
    -6
      octaviaclient/osc/v2/utils.py
  13. +33
    -32
      octaviaclient/tests/unit/api/test_octavia.py
  14. +72
    -3
      octaviaclient/tests/unit/osc/v2/test_amphora.py
  15. +103
    -0
      octaviaclient/tests/unit/osc/v2/test_health_monitor.py
  16. +103
    -0
      octaviaclient/tests/unit/osc/v2/test_l7policy.py
  17. +140
    -0
      octaviaclient/tests/unit/osc/v2/test_l7rule.py
  18. +94
    -0
      octaviaclient/tests/unit/osc/v2/test_listener.py
  19. +126
    -1
      octaviaclient/tests/unit/osc/v2/test_load_balancer.py
  20. +145
    -13
      octaviaclient/tests/unit/osc/v2/test_member.py
  21. +91
    -0
      octaviaclient/tests/unit/osc/v2/test_pool.py
  22. +6
    -0
      releasenotes/notes/add-wait-option-to-CUD-commands-97375387e7762b83.yaml

+ 26
- 0
octaviaclient/api/exceptions.py View File

@ -0,0 +1,26 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
class OctaviaClientException(Exception):
"""The base exception class for all exceptions this library raises."""
def __init__(self, code, message=None, request_id=None):
self.code = code
self.message = message or self.__class__.message
self.request_id = request_id
def __str__(self):
return "%s (HTTP %s) (Request-ID: %s)" % (self.message,
self.code,
self.request_id)

+ 2
- 15
octaviaclient/api/v2/octavia.py View File

@ -18,6 +18,7 @@ from osc_lib.api import api
from osc_lib import exceptions as osc_exc
from octaviaclient.api import constants as const
from octaviaclient.api import exceptions
def correct_return_codes(func):
@ -45,7 +46,7 @@ def correct_return_codes(func):
else:
raise
raise OctaviaClientException(
raise exceptions.OctaviaClientException(
code=code,
message=message,
request_id=request_id)
@ -934,17 +935,3 @@ class OctaviaAPI(api.BaseAPI):
response = self._delete(url)
return response
class OctaviaClientException(Exception):
"""The base exception class for all exceptions this library raises."""
def __init__(self, code, message=None, request_id=None):
self.code = code
self.message = message or self.__class__.message
self.request_id = request_id
def __str__(self):
return "%s (HTTP %s) (Request-ID: %s)" % (self.message,
self.code,
self.request_id)

+ 42
- 4
octaviaclient/osc/v2/amphora.py View File

@ -128,15 +128,32 @@ class ConfigureAmphora(command.Command):
metavar='<amphora-id>',
help='UUID of the amphora to configure.',
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
def take_action(self, parsed_args):
attrs = v2_utils.get_amphora_attrs(self.app.client_manager,
parsed_args)
amp_id = attrs.pop('amphora_id')
self.app.client_manager.load_balancer.amphora_configure(
amphora_id=attrs.pop('amphora_id'))
amphora_id=amp_id)
if parsed_args.wait:
amphora = self.app.client_manager.load_balancer.amphora_show(
amp_id)
lb_id = amphora.get('loadbalancer_id')
# TODO(rm_work): No status change if the amp isn't linked to an LB?
if lb_id:
v2_utils.wait_for_active(
status_f=(self.app.client_manager.load_balancer.
load_balancer_show),
res_id=lb_id
)
class FailoverAmphora(command.Command):
@ -150,12 +167,33 @@ class FailoverAmphora(command.Command):
metavar='<amphora-id>',
help='UUID of the amphora.',
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
def take_action(self, parsed_args):
attrs = v2_utils.get_amphora_attrs(self.app.client_manager,
parsed_args)
amp_id = attrs.pop('amphora_id')
amphora = self.app.client_manager.load_balancer.amphora_show(amp_id)
self.app.client_manager.load_balancer.amphora_failover(
amphora_id=attrs.pop('amphora_id'))
amphora_id=amp_id)
if parsed_args.wait:
lb_id = amphora.get('loadbalancer_id')
if lb_id:
v2_utils.wait_for_active(
status_f=(self.app.client_manager.load_balancer.
load_balancer_show),
res_id=lb_id
)
else:
v2_utils.wait_for_delete(
status_f=(self.app.client_manager.load_balancer.
amphora_show),
res_id=amp_id
)

+ 2
- 0
octaviaclient/osc/v2/constants.py View File

@ -313,3 +313,5 @@ FLAVORPROFILE_COLUMNS = (
'name',
'provider_name',
)
PROVISIONING_STATUS = 'provisioning_status'

+ 55
- 0
octaviaclient/osc/v2/health_monitor.py View File

@ -132,6 +132,11 @@ class CreateHealthMonitor(command.ShowOne):
default=None,
help="Disable health monitor."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -143,6 +148,20 @@ class CreateHealthMonitor(command.ShowOne):
data = self.app.client_manager.load_balancer.health_monitor_create(
json=body)
if parsed_args.wait:
pool = self.app.client_manager.load_balancer.pool_show(
data['healthmonitor']['pools'][0]['id'])
v2_utils.wait_for_active(
status_f=(self.app.client_manager.load_balancer.
load_balancer_show),
res_id=pool['loadbalancers'][0]['id']
)
data = {
'healthmonitor': (
self.app.client_manager.load_balancer.health_monitor_show(
data['healthmonitor']['id']))
}
formatters = {'pools': v2_utils.format_list}
return (rows,
@ -162,6 +181,11 @@ class DeleteHealthMonitor(command.Command):
metavar='<health_monitor>',
help="Health monitor to delete (name or ID)."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -174,6 +198,13 @@ class DeleteHealthMonitor(command.Command):
self.app.client_manager.load_balancer.health_monitor_delete(
health_monitor_id=health_monitor_id)
if parsed_args.wait:
v2_utils.wait_for_delete(
status_f=(self.app.client_manager.load_balancer.
health_monitor_show),
res_id=health_monitor_id
)
class ListHealthMonitor(lister.Lister):
"""List health monitors"""
@ -316,6 +347,11 @@ class SetHealthMonitor(command.Command):
default=None,
help="Disable health monitor."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -330,6 +366,13 @@ class SetHealthMonitor(command.Command):
self.app.client_manager.load_balancer.health_monitor_set(
hm_id, json=body)
if parsed_args.wait:
v2_utils.wait_for_active(
status_f=(self.app.client_manager.load_balancer.
health_monitor_show),
res_id=hm_id
)
class UnsetHealthMonitor(command.Command):
"""Clear health monitor settings"""
@ -378,6 +421,11 @@ class UnsetHealthMonitor(command.Command):
action='store_true',
help="Clear the health monitor URL path."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
def take_action(self, parsed_args):
@ -393,3 +441,10 @@ class UnsetHealthMonitor(command.Command):
self.app.client_manager.load_balancer.health_monitor_set(
hm_id, json=body)
if parsed_args.wait:
v2_utils.wait_for_active(
status_f=(self.app.client_manager.load_balancer.
health_monitor_show),
res_id=hm_id
)

+ 55
- 0
octaviaclient/osc/v2/l7policy.py View File

@ -104,6 +104,11 @@ class CreateL7Policy(command.ShowOne):
default=None,
help="Disable l7policy."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -117,6 +122,20 @@ class CreateL7Policy(command.ShowOne):
data = self.app.client_manager.load_balancer.l7policy_create(
json=body)
if parsed_args.wait:
listener = self.app.client_manager.load_balancer.listener_show(
data['l7policy']['listener_id'])
v2_utils.wait_for_active(
status_f=(self.app.client_manager.load_balancer.
load_balancer_show),
res_id=listener['loadbalancers'][0]['id']
)
data = {
'l7policy': (
self.app.client_manager.load_balancer.l7policy_show(
data['l7policy']['id']))
}
formatters = {'rules': v2_utils.format_list}
return (rows, (utils.get_dict_properties(
@ -134,6 +153,11 @@ class DeleteL7Policy(command.Command):
metavar="<policy>",
help="l7policy to delete (name or ID)."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -146,6 +170,13 @@ class DeleteL7Policy(command.Command):
self.app.client_manager.load_balancer.l7policy_delete(
l7policy_id=l7policy_id)
if parsed_args.wait:
v2_utils.wait_for_delete(
status_f=(self.app.client_manager.load_balancer.
l7policy_show),
res_id=l7policy_id
)
class ListL7Policy(lister.Lister):
"""List l7policies"""
@ -278,6 +309,11 @@ class SetL7Policy(command.Command):
default=None,
help="Disable l7policy."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -293,6 +329,13 @@ class SetL7Policy(command.Command):
self.app.client_manager.load_balancer.l7policy_set(
l7policy_id, json=body)
if parsed_args.wait:
v2_utils.wait_for_active(
status_f=(self.app.client_manager.load_balancer.
l7policy_show),
res_id=l7policy_id
)
class UnsetL7Policy(command.Command):
"""Clear l7policy settings"""
@ -320,6 +363,11 @@ class UnsetL7Policy(command.Command):
action='store_true',
help="Clear the l7policy redirect HTTP code."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
def take_action(self, parsed_args):
@ -335,3 +383,10 @@ class UnsetL7Policy(command.Command):
self.app.client_manager.load_balancer.l7policy_set(
policy_id, json=body)
if parsed_args.wait:
v2_utils.wait_for_active(
status_f=(self.app.client_manager.load_balancer.
l7policy_show),
res_id=policy_id
)

+ 68
- 0
octaviaclient/osc/v2/l7rule.py View File

@ -16,6 +16,8 @@
"""L7rule action implementation"""
import functools
from cliff import lister
from osc_lib.command import command
from osc_lib import utils
@ -85,6 +87,11 @@ class CreateL7Rule(command.ShowOne):
default=None,
help="Disable l7rule."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -101,6 +108,22 @@ class CreateL7Rule(command.ShowOne):
json=body
)
if parsed_args.wait:
l7policy = self.app.client_manager.load_balancer.l7policy_show(
l7policy_id)
listener = self.app.client_manager.load_balancer.listener_show(
l7policy['listener_id'])
v2_utils.wait_for_active(
status_f=(self.app.client_manager.load_balancer.
load_balancer_show),
res_id=listener['loadbalancers'][0]['id']
)
data = {
'rule': (
self.app.client_manager.load_balancer.l7rule_show(
l7policy_id, data['rule']['id']))
}
return (rows, (utils.get_dict_properties(
data['rule'], rows, formatters={})))
@ -121,6 +144,11 @@ class DeleteL7Rule(command.Command):
metavar="<rule_id>",
help="l7rule to delete."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -132,6 +160,16 @@ class DeleteL7Rule(command.Command):
l7policy_id=attrs['l7policy_id']
)
if parsed_args.wait:
l7rule_show = functools.partial(
self.app.client_manager.load_balancer.l7rule_show,
attrs['l7policy_id']
)
v2_utils.wait_for_delete(
status_f=l7rule_show,
res_id=attrs['l7rule_id']
)
class ListL7Rule(lister.Lister):
"""List l7rules for l7policy"""
@ -251,6 +289,11 @@ class SetL7Rule(command.Command):
default=None,
help="Disable l7rule."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -269,6 +312,16 @@ class SetL7Rule(command.Command):
json=body
)
if parsed_args.wait:
l7rule_show = functools.partial(
self.app.client_manager.load_balancer.l7rule_show,
l7policy_id
)
v2_utils.wait_for_active(
status_f=l7rule_show,
res_id=l7rule_id
)
class UnsetL7Rule(command.Command):
"""Clear l7rule settings"""
@ -296,6 +349,11 @@ class UnsetL7Rule(command.Command):
action='store_true',
help="Clear the l7rule key."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
def take_action(self, parsed_args):
@ -311,3 +369,13 @@ class UnsetL7Rule(command.Command):
self.app.client_manager.load_balancer.l7rule_set(
l7policy_id=policy_id, l7rule_id=parsed_args.l7rule_id, json=body)
if parsed_args.wait:
l7rule_show = functools.partial(
self.app.client_manager.load_balancer.l7rule_show,
policy_id
)
v2_utils.wait_for_active(
status_f=l7rule_show,
res_id=parsed_args.l7rule_id
)

+ 51
- 0
octaviaclient/osc/v2/listener.py View File

@ -166,6 +166,11 @@ class CreateListener(command.ShowOne):
help="CIDR to allow access to the listener (can be set multiple "
"times)."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -176,6 +181,19 @@ class CreateListener(command.ShowOne):
body = {"listener": attrs}
data = self.app.client_manager.load_balancer.listener_create(
json=body)
if parsed_args.wait:
v2_utils.wait_for_active(
status_f=(self.app.client_manager.load_balancer.
load_balancer_show),
res_id=data['listener']['loadbalancers'][0]['id']
)
data = {
'listener': (
self.app.client_manager.load_balancer.listener_show(
data['listener']['id']))
}
formatters = {'loadbalancers': v2_utils.format_list,
'pools': v2_utils.format_list,
'l7policies': v2_utils.format_list,
@ -199,6 +217,11 @@ class DeleteListener(command.Command):
metavar="<listener>",
help="Listener to delete (name or ID)"
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -211,6 +234,12 @@ class DeleteListener(command.Command):
self.app.client_manager.load_balancer.listener_delete(
listener_id=listener_id)
if parsed_args.wait:
v2_utils.wait_for_delete(
status_f=self.app.client_manager.load_balancer.listener_show,
res_id=listener_id
)
class ListListener(lister.Lister):
"""List listeners"""
@ -421,6 +450,11 @@ class SetListener(command.Command):
help="CIDR to allow access to the listener (can be set multiple "
"times)."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -435,6 +469,12 @@ class SetListener(command.Command):
self.app.client_manager.load_balancer.listener_set(
listener_id, json=body)
if parsed_args.wait:
v2_utils.wait_for_active(
status_f=self.app.client_manager.load_balancer.listener_show,
res_id=listener_id
)
class UnsetListener(command.Command):
"""Clear listener settings"""
@ -525,6 +565,11 @@ class UnsetListener(command.Command):
action='store_true',
help="Clear all allowed CIDRs from the listener."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
def take_action(self, parsed_args):
@ -541,6 +586,12 @@ class UnsetListener(command.Command):
self.app.client_manager.load_balancer.listener_set(
listener_id, json=body)
if parsed_args.wait:
v2_utils.wait_for_active(
status_f=self.app.client_manager.load_balancer.listener_show,
res_id=listener_id
)
class ShowListenerStats(command.ShowOne):
"""Shows the current statistics for a listener."""


+ 67
- 1
octaviaclient/osc/v2/load_balancer.py View File

@ -118,6 +118,11 @@ class CreateLoadBalancer(command.ShowOne):
metavar='<flavor>',
help="The name or ID of the flavor for the load balancer."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -131,6 +136,18 @@ class CreateLoadBalancer(command.ShowOne):
data = self.app.client_manager.load_balancer.load_balancer_create(
json=body)
if parsed_args.wait:
v2_utils.wait_for_active(
status_f=(self.app.client_manager.load_balancer.
load_balancer_show),
res_id=data['loadbalancer']['id']
)
data = {
'loadbalancer': (
self.app.client_manager.load_balancer.load_balancer_show(
data['loadbalancer']['id']))
}
formatters = {
'listeners': v2_utils.format_list,
'pools': v2_utils.format_list,
@ -160,6 +177,11 @@ class DeleteLoadBalancer(command.Command):
help="Cascade the delete to all child elements of the load "
"balancer."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -171,6 +193,13 @@ class DeleteLoadBalancer(command.Command):
self.app.client_manager.load_balancer.load_balancer_delete(
lb_id=lb_id, **attrs)
if parsed_args.wait:
v2_utils.wait_for_delete(
status_f=(self.app.client_manager.load_balancer.
load_balancer_show),
res_id=lb_id
)
class FailoverLoadBalancer(command.Command):
"""Trigger load balancer failover"""
@ -183,14 +212,27 @@ class FailoverLoadBalancer(command.Command):
metavar='<load_balancer>',
help="Name or UUID of the load balancer."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
def take_action(self, parsed_args):
attrs = v2_utils.get_loadbalancer_attrs(self.app.client_manager,
parsed_args)
lb_id = attrs.pop('loadbalancer_id')
self.app.client_manager.load_balancer.load_balancer_failover(
lb_id=attrs.pop('loadbalancer_id'))
lb_id=lb_id)
if parsed_args.wait:
v2_utils.wait_for_active(
status_f=(self.app.client_manager.load_balancer.
load_balancer_show),
res_id=lb_id
)
class ListLoadBalancer(lister.Lister):
@ -362,6 +404,11 @@ class SetLoadBalancer(command.Command):
default=None,
help="Disable load balancer."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -374,6 +421,13 @@ class SetLoadBalancer(command.Command):
self.app.client_manager.load_balancer.load_balancer_set(
lb_id, json=body)
if parsed_args.wait:
v2_utils.wait_for_active(
status_f=(self.app.client_manager.load_balancer.
load_balancer_show),
res_id=lb_id
)
class UnsetLoadBalancer(command.Command):
"""Clear load balancer settings"""
@ -401,6 +455,11 @@ class UnsetLoadBalancer(command.Command):
action='store_true',
help="Clear the load balancer QoS policy.",
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -418,6 +477,13 @@ class UnsetLoadBalancer(command.Command):
self.app.client_manager.load_balancer.load_balancer_set(
lb_id, json=body)
if parsed_args.wait:
v2_utils.wait_for_active(
status_f=(self.app.client_manager.load_balancer.
load_balancer_show),
res_id=lb_id
)
class ShowLoadBalancerStats(command.ShowOne):
"""Shows the current statistics for a load balancer"""


+ 64
- 0
octaviaclient/osc/v2/member.py View File

@ -15,6 +15,7 @@
"""Member action implementation"""
import functools
from cliff import lister
from osc_lib.command import command
@ -172,6 +173,11 @@ class CreateMember(command.ShowOne):
default=None,
help="Disable member"
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -186,6 +192,19 @@ class CreateMember(command.ShowOne):
json=body
)
if parsed_args.wait:
pool = self.app.client_manager.load_balancer.pool_show(pool_id)
v2_utils.wait_for_active(
status_f=(self.app.client_manager.load_balancer.
load_balancer_show),
res_id=pool['loadbalancers'][0]['id']
)
data = {
'member': (
self.app.client_manager.load_balancer.member_show(
pool_id, data['member']['id']))
}
return (rows,
(utils.get_dict_properties(
data['member'], rows, formatters={})))
@ -258,6 +277,11 @@ class SetMember(command.Command):
action='store_true',
default=None,
help="Set the admin_state_up to False")
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -273,6 +297,16 @@ class SetMember(command.Command):
json=post_data
)
if parsed_args.wait:
member_show = functools.partial(
self.app.client_manager.load_balancer.member_show,
pool_id
)
v2_utils.wait_for_active(
status_f=member_show,
res_id=member_id
)
class DeleteMember(command.Command):
"""Delete a member from a pool """
@ -291,6 +325,11 @@ class DeleteMember(command.Command):
metavar='<member>',
help="Name or ID of the member to be deleted."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -304,6 +343,16 @@ class DeleteMember(command.Command):
member_id=id
)
if parsed_args.wait:
member_show = functools.partial(
self.app.client_manager.load_balancer.member_show,
pool_id
)
v2_utils.wait_for_delete(
status_f=member_show,
res_id=id
)
class UnsetMember(command.Command):
"""Clear member settings"""
@ -346,6 +395,11 @@ class UnsetMember(command.Command):
action='store_true',
help="Reset the member weight to the API default."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
def take_action(self, parsed_args):
@ -366,3 +420,13 @@ class UnsetMember(command.Command):
self.app.client_manager.load_balancer.member_set(
pool_id=pool_id, member_id=member_id, json=body)
if parsed_args.wait:
member_show = functools.partial(
self.app.client_manager.load_balancer.member_show,
pool_id
)
v2_utils.wait_for_active(
status_f=member_show,
res_id=member_id
)

+ 51
- 0
octaviaclient/osc/v2/pool.py View File

@ -123,6 +123,11 @@ class CreatePool(command.ShowOne):
default=None,
help="Disable backend member re-encryption."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -133,6 +138,19 @@ class CreatePool(command.ShowOne):
body = {"pool": attrs}
data = self.app.client_manager.load_balancer.pool_create(
json=body)
if parsed_args.wait:
v2_utils.wait_for_active(
status_f=(self.app.client_manager.load_balancer.
load_balancer_show),
res_id=data['pool']['loadbalancers'][0]['id']
)
data = {
'pool': (
self.app.client_manager.load_balancer.pool_show(
data['pool']['id']))
}
formatters = {'loadbalancers': v2_utils.format_list,
'members': v2_utils.format_list,
'listeners': v2_utils.format_list,
@ -154,6 +172,11 @@ class DeletePool(command.Command):
metavar="<pool>",
help="Pool to delete (name or ID)."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -163,6 +186,12 @@ class DeletePool(command.Command):
self.app.client_manager.load_balancer.pool_delete(
pool_id=pool_id)
if parsed_args.wait:
v2_utils.wait_for_delete(
status_f=self.app.client_manager.load_balancer.pool_show,
res_id=pool_id
)
class ListPool(lister.Lister):
"""List pools"""
@ -306,6 +335,11 @@ class SetPool(command.Command):
default=None,
help="disable backend associated members re-encryption."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
@ -318,6 +352,12 @@ class SetPool(command.Command):
self.app.client_manager.load_balancer.pool_set(
pool_id, json=body)
if parsed_args.wait:
v2_utils.wait_for_active(
status_f=self.app.client_manager.load_balancer.pool_show,
res_id=pool_id
)
class UnsetPool(command.Command):
"""Clear pool settings"""
@ -362,6 +402,11 @@ class UnsetPool(command.Command):
action='store_true',
help="Clear the certificate reference for this pool."
)
parser.add_argument(
'--wait',
action='store_true',
help='Wait for action to complete',
)
return parser
def take_action(self, parsed_args):
@ -377,3 +422,9 @@ class UnsetPool(command.Command):
self.app.client_manager.load_balancer.pool_set(
pool_id, json=body)
if parsed_args.wait:
v2_utils.wait_for_active(
status_f=self.app.client_manager.load_balancer.pool_show,
res_id=pool_id
)

+ 45
- 6
octaviaclient/osc/v2/utils.py View File

@ -12,9 +12,13 @@
# under the License.
#
from osc_lib import exceptions
import munch
from openstackclient.identity import common as identity_common
from osc_lib import exceptions as osc_exc
from osc_lib import utils
from octaviaclient.api import exceptions
from octaviaclient.osc.v2 import constants
def _map_attrs(args, source_attr_map):
@ -95,7 +99,7 @@ def get_resource_id(resource, resource_name, name):
msg = ("{0} {1} found with name or ID of {2}. Please try "
"again with UUID".format(len(names), resource_name,
name))
raise exceptions.CommandError(msg)
raise osc_exc.CommandError(msg)
else:
return names[0].get('id')
elif resource_name == 'l7rules':
@ -110,12 +114,12 @@ def get_resource_id(resource, resource_name, name):
msg = ("{0} {1} found with name or ID of {2}. Please try "
"again with UUID".format(len(names), resource_name,
name))
raise exceptions.CommandError(msg)
raise osc_exc.CommandError(msg)
else:
return names[0].get('id')
except IndexError:
msg = "Unable to locate {0} in {1}".format(name, resource_name)
raise exceptions.CommandError(msg)
raise osc_exc.CommandError(msg)
def get_loadbalancer_attrs(client_manager, parsed_args):
@ -547,4 +551,39 @@ def _format_str_if_need_treat_unset(data):
def get_unsets(parsed_args):
return {arg: None for arg, value in vars(parsed_args).items() if
value is True}
value is True and arg != 'wait'}
def wait_for_active(status_f, res_id):
success = utils.wait_for_status(
status_f=lambda x: munch.Munch(status_f(x)),
res_id=res_id,
status_field=constants.PROVISIONING_STATUS,
sleep_time=3
)
if not success:
raise exceptions.OctaviaClientException(
code="n/a",
message="The resource did not successfully reach ACTIVE status.")
def wait_for_delete(status_f, res_id):
class Getter(object):
@staticmethod
def get(id):
return munch.Munch(status_f(id))
try:
success = utils.wait_for_delete(
manager=Getter,
res_id=res_id,
status_field=constants.PROVISIONING_STATUS,
sleep_time=3
)
if not success:
raise exceptions.OctaviaClientException(
code="n/a",
message="The resource could not be successfully deleted.")
except exceptions.OctaviaClientException as e:
if e.code != 404:
raise

+ 33
- 32
octaviaclient/tests/unit/api/test_octavia.py View File

@ -19,6 +19,7 @@ from requests_mock.contrib import fixture
from osc_lib.tests import utils
from octaviaclient.api import exceptions
from octaviaclient.api.v2 import octavia
FAKE_ACCOUNT = 'q12we34r'
@ -204,7 +205,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.load_balancer_create,
json=SINGLE_LB_RESP)
@ -226,7 +227,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.load_balancer_set,
FAKE_LB,
@ -248,7 +249,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=409,
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.load_balancer_failover,
FAKE_LB)
@ -269,7 +270,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.load_balancer_delete,
FAKE_LB)
@ -331,7 +332,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.listener_create,
json=SINGLE_LI_RESP)
@ -353,7 +354,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.listener_set,
FAKE_LI, json=SINGLE_LI_UPDATE)
@ -374,7 +375,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.listener_delete,
FAKE_LI)
@ -426,7 +427,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.pool_create,
json=SINGLE_PO_RESP)
@ -448,7 +449,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.pool_set,
FAKE_PO, json=SINGLE_PO_UPDATE)
@ -469,7 +470,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.pool_delete,
FAKE_PO)
@ -511,7 +512,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.member_create,
json=SINGLE_ME_RESP, pool_id=FAKE_PO)
@ -534,7 +535,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.member_set,
pool_id=FAKE_PO, member_id=FAKE_ME,
@ -556,7 +557,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.member_delete,
pool_id=FAKE_PO, member_id=FAKE_ME)
@ -598,7 +599,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.l7policy_create,
json=SINGLE_L7PO_RESP)
@ -620,7 +621,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.l7policy_set,
FAKE_L7PO, json=SINGLE_L7PO_UPDATE)
@ -641,7 +642,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.l7policy_delete,
FAKE_L7PO)
@ -683,7 +684,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.l7rule_create,
FAKE_L7PO, json=SINGLE_L7RU_RESP)
@ -709,7 +710,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.l7rule_set,
l7rule_id=FAKE_L7RU,
@ -735,7 +736,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.l7rule_delete,
l7rule_id=FAKE_L7RU,
@ -778,7 +779,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.health_monitor_create,
json=SINGLE_HM_RESP)
@ -800,7 +801,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.health_monitor_set,
FAKE_HM, json=SINGLE_HM_UPDATE)
@ -821,7 +822,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.health_monitor_delete,
FAKE_HM)
@ -863,7 +864,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.quota_set,
FAKE_PRJ, json=SINGLE_QT_UPDATE)
@ -884,7 +885,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.quota_reset,
FAKE_PRJ)
@ -925,7 +926,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=409,
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.amphora_configure,
FAKE_AMP)
@ -946,7 +947,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=409,
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.amphora_failover,
FAKE_AMP)
@ -1010,7 +1011,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.flavor_create,
json=SINGLE_FV_RESP)
@ -1032,7 +1033,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.flavor_set,
FAKE_FV,
@ -1054,7 +1055,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.flavor_delete,
FAKE_FV)
@ -1096,7 +1097,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.flavorprofile_create,
json=SINGLE_FVPF_RESP)
@ -1118,7 +1119,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.flavorprofile_set,
FAKE_FVPF, json=SINGLE_FVPF_UPDATE)
@ -1139,7 +1140,7 @@ class TestLoadBalancer(TestOctaviaClient):
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self.assertRaisesRegex(exceptions.OctaviaClientException,
self._error_message,
self.api.flavorprofile_delete,
FAKE_FVPF)

+ 72
- 3
octaviaclient/tests/unit/osc/v2/test_amphora.py View File

@ -38,9 +38,7 @@ class TestAmphora(fakes.TestOctaviaClient):
]}
self.api_mock = mock.Mock()
self.api_mock.amphora_list.return_value = info_list
self.api_mock.amphora_show.return_value = {
"amphora": info_list['amphorae'][0],
}
self.api_mock.amphora_show.return_value = info_list['amphorae'][0]
lb_client = self.app.client_manager
lb_client.load_balancer = self.api_mock
@ -130,6 +128,34 @@ class TestAmphoraConfigure(TestAmphora):
self.api_mock.amphora_configure.assert_called_with(
amphora_id=self._amp.id)
@mock.patch('osc_lib.utils.wait_for_status')
def test_amphora_configure_linked_wait(self, mock_wait):
arglist = [self._amp.id, '--wait']
verify_list = [('amphora_id', self._amp.id)]
parsed_args = self.check_parser(self.cmd, arglist, verify_list)
self.cmd.take_action(parsed_args)
self.api_mock.amphora_configure.assert_called_with(
amphora_id=self._amp.id)
mock_wait.assert_called_once_with(
status_f=mock.ANY,
res_id=self._amp.loadbalancer_id,
sleep_time=mock.ANY,
status_field='provisioning_status')
@mock.patch('osc_lib.utils.wait_for_status')
def test_amphora_configure_unlinked_wait(self, mock_wait):
self.api_mock.amphora_show.return_value.pop('loadbalancer_id')
arglist = [self._amp.id, '--wait']
verify_list = [('amphora_id', self._amp.id)]
parsed_args = self.check_parser(self.cmd, arglist, verify_list)
self.cmd.take_action(parsed_args)
self.api_mock.amphora_configure.assert_called_with(
amphora_id=self._amp.id)
# TODO(rm_work): No wait expected if the amp isn't linked to an LB?
mock_wait.assert_not_called()
class TestAmphoraFailover(TestAmphora):
def setUp(self):
@ -144,3 +170,46 @@ class TestAmphoraFailover(TestAmphora):
self.cmd.take_action(parsed_args)
self.api_mock.amphora_failover.assert_called_with(
amphora_id=self._amp.id)
@mock.patch('osc_lib.utils.wait_for_status')
@mock.patch('osc_lib.utils.wait_for_delete')
def test_amphora_failover_linked_wait(self, mock_wait_delete,
mock_wait_active):
arglist = [self._amp.id, '--wait']
verify_list = [
('amphora_id', self._amp.id)<