Add tag support for Octavia resources

Add tag support for load balancers, listeners, pools, health monitors,
members, l7policies and l7rules.
Tags can be set when creating a resource, and can be modified using
set/unset CLI calls.
Filtering by tags is also supported when listing resources.

This commit also fixes some errors when using set/unset l7rule CLI with
the --wait flag (l7rule_id and l7policy_id parameters were swapped in
partial function calls).

Story: 2008347
Task: 41249

Change-Id: I1d5119cb5ce9da0fd6c7a39aeb371a507607b9d7
This commit is contained in:
Gregory Thiemonge 2020-11-13 08:12:31 +01:00
parent 1a133a3320
commit 9c4b85a523
18 changed files with 1513 additions and 61 deletions

View File

@ -32,6 +32,7 @@ LOAD_BALANCER_ROWS = (
'vip_port_id', 'vip_port_id',
'vip_qos_policy_id', 'vip_qos_policy_id',
'vip_subnet_id', 'vip_subnet_id',
'tags',
) )
LOAD_BALANCER_COLUMNS = ( LOAD_BALANCER_COLUMNS = (
@ -79,7 +80,8 @@ LISTENER_ROWS = (
'allowed_cidrs', 'allowed_cidrs',
'tls_ciphers', 'tls_ciphers',
'tls_versions', 'tls_versions',
'alpn_protocols') 'alpn_protocols',
'tags')
LISTENER_COLUMNS = ( LISTENER_COLUMNS = (
'id', 'id',
@ -112,7 +114,8 @@ POOL_ROWS = (
'crl_container_ref', 'crl_container_ref',
'tls_enabled', 'tls_enabled',
'tls_ciphers', 'tls_ciphers',
'tls_versions') 'tls_versions',
'tags')
POOL_COLUMNS = ( POOL_COLUMNS = (
'id', 'id',
@ -138,8 +141,8 @@ MEMBER_ROWS = (
'weight', 'weight',
'monitor_port', 'monitor_port',
'monitor_address', 'monitor_address',
'backup' 'backup',
) 'tags')
MEMBER_COLUMNS = ( MEMBER_COLUMNS = (
'id', 'id',
@ -168,7 +171,8 @@ L7POLICY_ROWS = (
'id', 'id',
'operating_status', 'operating_status',
'name', 'name',
'redirect_http_code') 'redirect_http_code',
'tags')
L7POLICY_COLUMNS = ( L7POLICY_COLUMNS = (
'id', 'id',
@ -191,7 +195,8 @@ L7RULE_ROWS = (
'project_id', 'project_id',
'type', 'type',
'id', 'id',
'operating_status') 'operating_status',
'tags')
L7RULE_COLUMNS = ( L7RULE_COLUMNS = (
'id', 'id',
@ -223,8 +228,8 @@ MONITOR_ROWS = (
'id', 'id',
'operating_status', 'operating_status',
'http_version', 'http_version',
'domain_name' 'domain_name',
) 'tags')
MONITOR_COLUMNS = ( MONITOR_COLUMNS = (
'id', 'id',

View File

@ -21,6 +21,7 @@ from cliff import lister
from osc_lib.command import command from osc_lib.command import command
from osc_lib import exceptions from osc_lib import exceptions
from osc_lib import utils from osc_lib import utils
from osc_lib.utils import tags as _tag
from oslo_utils import uuidutils from oslo_utils import uuidutils
from octaviaclient.osc.v2 import constants as const from octaviaclient.osc.v2 import constants as const
@ -140,6 +141,9 @@ class CreateHealthMonitor(command.ShowOne):
help='Wait for action to complete', help='Wait for action to complete',
) )
_tag.add_tag_option_to_parser_for_create(
parser, 'health monitor')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -164,7 +168,8 @@ class CreateHealthMonitor(command.ShowOne):
data['healthmonitor']['id'])) data['healthmonitor']['id']))
} }
formatters = {'pools': v2_utils.format_list} formatters = {'pools': v2_utils.format_list,
'tags': v2_utils.format_list_flat}
return (rows, return (rows,
(utils.get_dict_properties(data['healthmonitor'], (utils.get_dict_properties(data['healthmonitor'],
@ -214,6 +219,8 @@ class ListHealthMonitor(lister.Lister):
def get_parser(self, prog_name): def get_parser(self, prog_name):
parser = super().get_parser(prog_name) parser = super().get_parser(prog_name)
_tag.add_tag_filtering_option_to_parser(parser, 'health monitor')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -262,7 +269,8 @@ class ShowHealthMonitor(command.ShowOne):
data = self.app.client_manager.load_balancer.health_monitor_show( data = self.app.client_manager.load_balancer.health_monitor_show(
health_monitor_id=health_monitor_id, health_monitor_id=health_monitor_id,
) )
formatters = {'pools': v2_utils.format_list} formatters = {'pools': v2_utils.format_list,
'tags': v2_utils.format_list_flat}
return (rows, return (rows,
(utils.get_dict_properties(data, rows, formatters=formatters))) (utils.get_dict_properties(data, rows, formatters=formatters)))
@ -364,6 +372,8 @@ class SetHealthMonitor(command.Command):
help='Wait for action to complete', help='Wait for action to complete',
) )
_tag.add_tag_option_to_parser_for_set(parser, 'health monitor')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -372,6 +382,10 @@ class SetHealthMonitor(command.Command):
hm_id = attrs.pop('health_monitor_id') hm_id = attrs.pop('health_monitor_id')
v2_utils.set_tags_for_set(
self.app.client_manager.load_balancer.health_monitor_show,
hm_id, attrs, clear_tags=parsed_args.no_tag)
body = {'healthmonitor': attrs} body = {'healthmonitor': attrs}
self.app.client_manager.load_balancer.health_monitor_set( self.app.client_manager.load_balancer.health_monitor_set(
@ -437,17 +451,24 @@ class UnsetHealthMonitor(command.Command):
action='store_true', action='store_true',
help='Wait for action to complete', help='Wait for action to complete',
) )
_tag.add_tag_option_to_parser_for_unset(parser, 'health monitor')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
unset_args = v2_utils.get_unsets(parsed_args) unset_args = v2_utils.get_unsets(parsed_args)
if not unset_args: if not unset_args and not parsed_args.all_tag:
return return
hm_id = v2_utils.get_resource_id( hm_id = v2_utils.get_resource_id(
self.app.client_manager.load_balancer.health_monitor_list, self.app.client_manager.load_balancer.health_monitor_list,
'healthmonitors', parsed_args.health_monitor) 'healthmonitors', parsed_args.health_monitor)
v2_utils.set_tags_for_unset(
self.app.client_manager.load_balancer.health_monitor_show,
hm_id, unset_args, clear_tags=parsed_args.all_tag)
body = {'healthmonitor': unset_args} body = {'healthmonitor': unset_args}
self.app.client_manager.load_balancer.health_monitor_set( self.app.client_manager.load_balancer.health_monitor_set(

View File

@ -20,6 +20,7 @@ from cliff import lister
from osc_lib.command import command from osc_lib.command import command
from osc_lib import exceptions from osc_lib import exceptions
from osc_lib import utils from osc_lib import utils
from osc_lib.utils import tags as _tag
from oslo_utils import uuidutils from oslo_utils import uuidutils
from octaviaclient.osc.v2 import constants as const from octaviaclient.osc.v2 import constants as const
@ -112,6 +113,9 @@ class CreateL7Policy(command.ShowOne):
help='Wait for action to complete', help='Wait for action to complete',
) )
_tag.add_tag_option_to_parser_for_create(
parser, 'l7policy')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -138,7 +142,8 @@ class CreateL7Policy(command.ShowOne):
data['l7policy']['id'])) data['l7policy']['id']))
} }
formatters = {'rules': v2_utils.format_list} formatters = {'rules': v2_utils.format_list,
'tags': v2_utils.format_list_flat}
return (rows, (utils.get_dict_properties( return (rows, (utils.get_dict_properties(
data['l7policy'], rows, formatters=formatters))) data['l7policy'], rows, formatters=formatters)))
@ -192,6 +197,8 @@ class ListL7Policy(lister.Lister):
"(name or ID)." "(name or ID)."
) )
_tag.add_tag_filtering_option_to_parser(parser, 'l7policy')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -241,7 +248,8 @@ class ShowL7Policy(command.ShowOne):
data = self.app.client_manager.load_balancer.l7policy_show( data = self.app.client_manager.load_balancer.l7policy_show(
l7policy_id=l7policy_id, l7policy_id=l7policy_id,
) )
formatters = {'rules': v2_utils.format_list} formatters = {'rules': v2_utils.format_list,
'tags': v2_utils.format_list_flat}
return (rows, (utils.get_dict_properties( return (rows, (utils.get_dict_properties(
data, rows, formatters=formatters))) data, rows, formatters=formatters)))
@ -325,6 +333,8 @@ class SetL7Policy(command.Command):
help='Wait for action to complete', help='Wait for action to complete',
) )
_tag.add_tag_option_to_parser_for_set(parser, 'l7policy')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -334,6 +344,10 @@ class SetL7Policy(command.Command):
validate.check_l7policy_attrs(attrs) validate.check_l7policy_attrs(attrs)
l7policy_id = attrs.pop('l7policy_id') l7policy_id = attrs.pop('l7policy_id')
v2_utils.set_tags_for_set(
self.app.client_manager.load_balancer.l7policy_show,
l7policy_id, attrs, clear_tags=parsed_args.no_tag)
body = {'l7policy': attrs} body = {'l7policy': attrs}
self.app.client_manager.load_balancer.l7policy_set( self.app.client_manager.load_balancer.l7policy_set(
@ -378,17 +392,24 @@ class UnsetL7Policy(command.Command):
action='store_true', action='store_true',
help='Wait for action to complete', help='Wait for action to complete',
) )
_tag.add_tag_option_to_parser_for_unset(parser, 'l7policy')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
unset_args = v2_utils.get_unsets(parsed_args) unset_args = v2_utils.get_unsets(parsed_args)
if not unset_args: if not unset_args and not parsed_args.all_tag:
return return
policy_id = v2_utils.get_resource_id( policy_id = v2_utils.get_resource_id(
self.app.client_manager.load_balancer.l7policy_list, self.app.client_manager.load_balancer.l7policy_list,
'l7policies', parsed_args.l7policy) 'l7policies', parsed_args.l7policy)
v2_utils.set_tags_for_unset(
self.app.client_manager.load_balancer.l7policy_show,
policy_id, unset_args, clear_tags=parsed_args.all_tag)
body = {'l7policy': unset_args} body = {'l7policy': unset_args}
self.app.client_manager.load_balancer.l7policy_set( self.app.client_manager.load_balancer.l7policy_set(

View File

@ -22,6 +22,7 @@ from cliff import lister
from osc_lib.command import command from osc_lib.command import command
from osc_lib import exceptions from osc_lib import exceptions
from osc_lib import utils from osc_lib import utils
from osc_lib.utils import tags as _tag
from oslo_utils import uuidutils from oslo_utils import uuidutils
from octaviaclient.osc.v2 import constants as const from octaviaclient.osc.v2 import constants as const
@ -95,6 +96,9 @@ class CreateL7Rule(command.ShowOne):
help='Wait for action to complete', help='Wait for action to complete',
) )
_tag.add_tag_option_to_parser_for_create(
parser, 'l7rule')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -126,8 +130,10 @@ class CreateL7Rule(command.ShowOne):
l7policy_id, data['rule']['id'])) l7policy_id, data['rule']['id']))
} }
formatters = {'tags': v2_utils.format_list_flat}
return (rows, (utils.get_dict_properties( return (rows, (utils.get_dict_properties(
data['rule'], rows, formatters={}))) data['rule'], rows, formatters=formatters)))
class DeleteL7Rule(command.Command): class DeleteL7Rule(command.Command):
@ -165,11 +171,11 @@ class DeleteL7Rule(command.Command):
if parsed_args.wait: if parsed_args.wait:
l7rule_show = functools.partial( l7rule_show = functools.partial(
self.app.client_manager.load_balancer.l7rule_show, self.app.client_manager.load_balancer.l7rule_show,
attrs['l7policy_id'] attrs['l7rule_id']
) )
v2_utils.wait_for_delete( v2_utils.wait_for_delete(
status_f=l7rule_show, status_f=l7rule_show,
res_id=attrs['l7rule_id'] res_id=attrs['l7policy_id']
) )
@ -185,6 +191,8 @@ class ListL7Rule(lister.Lister):
help='l7policy to list rules for (name or ID).' help='l7policy to list rules for (name or ID).'
) )
_tag.add_tag_filtering_option_to_parser(parser, 'l7rule')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -192,7 +200,7 @@ class ListL7Rule(lister.Lister):
attrs = v2_utils.get_l7rule_attrs(self.app.client_manager, parsed_args) attrs = v2_utils.get_l7rule_attrs(self.app.client_manager, parsed_args)
data = self.app.client_manager.load_balancer.l7rule_list( data = self.app.client_manager.load_balancer.l7rule_list(
l7policy_id=attrs['l7policy_id'] **attrs
) )
return (columns, return (columns,
@ -237,9 +245,10 @@ class ShowL7Rule(command.ShowOne):
l7rule_id=attrs['l7rule_id'], l7rule_id=attrs['l7rule_id'],
l7policy_id=attrs['l7policy_id'] l7policy_id=attrs['l7policy_id']
) )
formatters = {'tags': v2_utils.format_list_flat}
return (rows, (utils.get_dict_properties( return (rows, (utils.get_dict_properties(
data, rows, formatters={}))) data, rows, formatters=formatters)))
class SetL7Rule(command.Command): class SetL7Rule(command.Command):
@ -307,6 +316,8 @@ class SetL7Rule(command.Command):
help='Wait for action to complete', help='Wait for action to complete',
) )
_tag.add_tag_option_to_parser_for_set(parser, 'l7rule')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -316,6 +327,15 @@ class SetL7Rule(command.Command):
l7policy_id = attrs.pop('l7policy_id') l7policy_id = attrs.pop('l7policy_id')
l7rule_id = attrs.pop('l7rule_id') l7rule_id = attrs.pop('l7rule_id')
# l7rule_id is the first argument in l7rule_show
l7rule_show = functools.partial(
self.app.client_manager.load_balancer.l7rule_show,
l7rule_id
)
v2_utils.set_tags_for_set(
l7rule_show, l7policy_id, attrs, clear_tags=parsed_args.no_tag)
body = {'rule': attrs} body = {'rule': attrs}
self.app.client_manager.load_balancer.l7rule_set( self.app.client_manager.load_balancer.l7rule_set(
@ -325,13 +345,9 @@ class SetL7Rule(command.Command):
) )
if parsed_args.wait: if parsed_args.wait:
l7rule_show = functools.partial(
self.app.client_manager.load_balancer.l7rule_show,
l7policy_id
)
v2_utils.wait_for_active( v2_utils.wait_for_active(
status_f=l7rule_show, status_f=l7rule_show,
res_id=l7rule_id res_id=l7policy_id
) )
@ -366,28 +382,35 @@ class UnsetL7Rule(command.Command):
action='store_true', action='store_true',
help='Wait for action to complete', help='Wait for action to complete',
) )
_tag.add_tag_option_to_parser_for_unset(parser, 'l7rule')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
unset_args = v2_utils.get_unsets(parsed_args) unset_args = v2_utils.get_unsets(parsed_args)
if not unset_args: if not unset_args and not parsed_args.all_tag:
return return
policy_id = v2_utils.get_resource_id( policy_id = v2_utils.get_resource_id(
self.app.client_manager.load_balancer.l7policy_list, self.app.client_manager.load_balancer.l7policy_list,
'l7policies', parsed_args.l7policy) 'l7policies', parsed_args.l7policy)
l7rule_show = functools.partial(
self.app.client_manager.load_balancer.l7rule_show,
parsed_args.l7rule_id
)
v2_utils.set_tags_for_unset(
l7rule_show, policy_id, unset_args,
clear_tags=parsed_args.all_tag)
body = {'rule': unset_args} body = {'rule': unset_args}
self.app.client_manager.load_balancer.l7rule_set( self.app.client_manager.load_balancer.l7rule_set(
l7policy_id=policy_id, l7rule_id=parsed_args.l7rule_id, json=body) l7policy_id=policy_id, l7rule_id=parsed_args.l7rule_id, json=body)
if parsed_args.wait: if parsed_args.wait:
l7rule_show = functools.partial(
self.app.client_manager.load_balancer.l7rule_show,
policy_id
)
v2_utils.wait_for_active( v2_utils.wait_for_active(
status_f=l7rule_show, status_f=l7rule_show,
res_id=parsed_args.l7rule_id res_id=policy_id,
) )

View File

@ -19,6 +19,7 @@ from cliff import lister
from osc_lib.command import command from osc_lib.command import command
from osc_lib import exceptions from osc_lib import exceptions
from osc_lib import utils from osc_lib import utils
from osc_lib.utils import tags as _tag
from oslo_utils import uuidutils from oslo_utils import uuidutils
from octaviaclient.osc.v2 import constants as const from octaviaclient.osc.v2 import constants as const
@ -200,6 +201,9 @@ class CreateListener(command.ShowOne):
"by the listener (can be set multiple times)." "by the listener (can be set multiple times)."
) )
_tag.add_tag_option_to_parser_for_create(
parser, 'listener')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -229,7 +233,8 @@ class CreateListener(command.ShowOne):
'pools': v2_utils.format_list, 'pools': v2_utils.format_list,
'l7policies': v2_utils.format_list, 'l7policies': v2_utils.format_list,
'insert_headers': v2_utils.format_hash, 'insert_headers': v2_utils.format_hash,
'allowed_cidrs': v2_utils.format_list_flat} 'allowed_cidrs': v2_utils.format_list_flat,
'tags': v2_utils.format_list_flat}
return (rows, return (rows,
(utils.get_dict_properties(data['listener'], (utils.get_dict_properties(data['listener'],
@ -308,6 +313,9 @@ class ListListener(lister.Lister):
metavar='<project>', metavar='<project>',
help="List listeners by project ID." help="List listeners by project ID."
) )
_tag.add_tag_filtering_option_to_parser(parser, 'listener')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -357,7 +365,8 @@ class ShowListener(command.ShowOne):
'pools': v2_utils.format_list, 'pools': v2_utils.format_list,
'l7policies': v2_utils.format_list, 'l7policies': v2_utils.format_list,
'insert_headers': v2_utils.format_hash, 'insert_headers': v2_utils.format_hash,
'allowed_cidrs': v2_utils.format_list_flat} 'allowed_cidrs': v2_utils.format_list_flat,
'tags': v2_utils.format_list_flat}
return rows, utils.get_dict_properties(data, rows, return rows, utils.get_dict_properties(data, rows,
formatters=formatters) formatters=formatters)
@ -519,6 +528,8 @@ class SetListener(command.Command):
"by the listener (can be set multiple times)." "by the listener (can be set multiple times)."
) )
_tag.add_tag_option_to_parser_for_set(parser, 'listener')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -527,6 +538,10 @@ class SetListener(command.Command):
listener_id = attrs.pop('listener_id') listener_id = attrs.pop('listener_id')
v2_utils.set_tags_for_set(
self.app.client_manager.load_balancer.listener_show,
listener_id, attrs, clear_tags=parsed_args.no_tag)
body = {'listener': attrs} body = {'listener': attrs}
self.app.client_manager.load_balancer.listener_set( self.app.client_manager.load_balancer.listener_set(
@ -648,17 +663,24 @@ class UnsetListener(command.Command):
action='store_true', action='store_true',
help="Clear all ALPN protocols from the listener." help="Clear all ALPN protocols from the listener."
) )
_tag.add_tag_option_to_parser_for_unset(parser, 'listener')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
unset_args = v2_utils.get_unsets(parsed_args) unset_args = v2_utils.get_unsets(parsed_args)
if not unset_args: if not unset_args and not parsed_args.all_tag:
return return
listener_id = v2_utils.get_resource_id( listener_id = v2_utils.get_resource_id(
self.app.client_manager.load_balancer.listener_list, self.app.client_manager.load_balancer.listener_list,
'listeners', parsed_args.listener) 'listeners', parsed_args.listener)
v2_utils.set_tags_for_unset(
self.app.client_manager.load_balancer.listener_show,
listener_id, unset_args, clear_tags=parsed_args.all_tag)
body = {'listener': unset_args} body = {'listener': unset_args}
self.app.client_manager.load_balancer.listener_set( self.app.client_manager.load_balancer.listener_set(

View File

@ -17,6 +17,7 @@ from cliff import lister
from osc_lib.command import command from osc_lib.command import command
from osc_lib import exceptions from osc_lib import exceptions
from osc_lib import utils from osc_lib import utils
from osc_lib.utils import tags as _tag
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
from oslo_utils import uuidutils from oslo_utils import uuidutils
@ -132,6 +133,9 @@ class CreateLoadBalancer(command.ShowOne):
help='Wait for action to complete', help='Wait for action to complete',
) )
_tag.add_tag_option_to_parser_for_create(
parser, 'load balancer')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -159,7 +163,8 @@ class CreateLoadBalancer(command.ShowOne):
formatters = { formatters = {
'listeners': v2_utils.format_list, 'listeners': v2_utils.format_list,
'pools': v2_utils.format_list, 'pools': v2_utils.format_list,
'l7policies': v2_utils.format_list 'l7policies': v2_utils.format_list,
'tags': v2_utils.format_list_flat
} }
return (rows, return (rows,
@ -326,6 +331,8 @@ class ListLoadBalancer(lister.Lister):
help="List load balancers according to their availability zone." help="List load balancers according to their availability zone."
) )
_tag.add_tag_filtering_option_to_parser(parser, 'load balancer')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -380,7 +387,8 @@ class ShowLoadBalancer(command.ShowOne):
formatters = { formatters = {
'listeners': v2_utils.format_list, 'listeners': v2_utils.format_list,
'pools': v2_utils.format_list, 'pools': v2_utils.format_list,
'l7policies': v2_utils.format_list 'l7policies': v2_utils.format_list,
'tags': v2_utils.format_list_flat
} }
return (rows, (utils.get_dict_properties( return (rows, (utils.get_dict_properties(
@ -433,12 +441,19 @@ class SetLoadBalancer(command.Command):
help='Wait for action to complete', help='Wait for action to complete',
) )
_tag.add_tag_option_to_parser_for_set(parser, 'load balancer')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
attrs = v2_utils.get_loadbalancer_attrs(self.app.client_manager, attrs = v2_utils.get_loadbalancer_attrs(self.app.client_manager,
parsed_args) parsed_args)
lb_id = attrs.pop('loadbalancer_id') lb_id = attrs.pop('loadbalancer_id')
v2_utils.set_tags_for_set(
self.app.client_manager.load_balancer.load_balancer_show,
lb_id, attrs, clear_tags=parsed_args.no_tag)
body = {'loadbalancer': attrs} body = {'loadbalancer': attrs}
self.app.client_manager.load_balancer.load_balancer_set( self.app.client_manager.load_balancer.load_balancer_set(
@ -484,17 +499,23 @@ class UnsetLoadBalancer(command.Command):
help='Wait for action to complete', help='Wait for action to complete',
) )
_tag.add_tag_option_to_parser_for_unset(parser, 'load balancer')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
unset_args = v2_utils.get_unsets(parsed_args) unset_args = v2_utils.get_unsets(parsed_args)
if not unset_args: if not unset_args and not parsed_args.all_tag:
return return
lb_id = v2_utils.get_resource_id( lb_id = v2_utils.get_resource_id(
self.app.client_manager.load_balancer.load_balancer_list, self.app.client_manager.load_balancer.load_balancer_list,
'loadbalancers', parsed_args.loadbalancer) 'loadbalancers', parsed_args.loadbalancer)
v2_utils.set_tags_for_unset(
self.app.client_manager.load_balancer.load_balancer_show,
lb_id, unset_args, clear_tags=parsed_args.all_tag)
body = {'loadbalancer': unset_args} body = {'loadbalancer': unset_args}
self.app.client_manager.load_balancer.load_balancer_set( self.app.client_manager.load_balancer.load_balancer_set(

View File

@ -21,6 +21,7 @@ from cliff import lister
from osc_lib.command import command from osc_lib.command import command
from osc_lib import exceptions from osc_lib import exceptions
from osc_lib import utils from osc_lib import utils
from osc_lib.utils import tags as _tag
from oslo_utils import uuidutils from oslo_utils import uuidutils
from octaviaclient.osc.v2 import constants as const from octaviaclient.osc.v2 import constants as const
@ -40,16 +41,17 @@ class ListMember(lister.Lister):
help="Pool name or ID to list the members of." help="Pool name or ID to list the members of."
) )
_tag.add_tag_filtering_option_to_parser(parser, 'member')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
columns = const.MEMBER_COLUMNS columns = const.MEMBER_COLUMNS
attrs = v2_utils.get_member_attrs(self.app.client_manager, parsed_args) attrs = v2_utils.get_member_attrs(self.app.client_manager, parsed_args)
pool_id = attrs.pop('pool_id')
data = self.app.client_manager.load_balancer.member_list( data = self.app.client_manager.load_balancer.member_list(
pool_id=pool_id) **attrs)
return (columns, return (columns,
(utils.get_dict_properties( (utils.get_dict_properties(
@ -97,8 +99,10 @@ class ShowMember(command.ShowOne):
data = self.app.client_manager.load_balancer.member_show( data = self.app.client_manager.load_balancer.member_show(
pool_id=pool_id, member_id=member_id) pool_id=pool_id, member_id=member_id)
formatters = {'tags': v2_utils.format_list_flat}
return (rows, (utils.get_dict_properties( return (rows, (utils.get_dict_properties(
data, rows, formatters={}))) data, rows, formatters=formatters)))
class CreateMember(command.ShowOne): class CreateMember(command.ShowOne):
@ -189,6 +193,9 @@ class CreateMember(command.ShowOne):
help='Wait for action to complete', help='Wait for action to complete',
) )
_tag.add_tag_option_to_parser_for_create(
parser, 'member')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -218,9 +225,11 @@ class CreateMember(command.ShowOne):
pool_id, data['member']['id'])) pool_id, data['member']['id']))
} }
formatters = {'tags': v2_utils.format_list_flat}
return (rows, return (rows,
(utils.get_dict_properties( (utils.get_dict_properties(
data['member'], rows, formatters={}))) data['member'], rows, formatters=formatters)))
class SetMember(command.Command): class SetMember(command.Command):
@ -294,6 +303,8 @@ class SetMember(command.Command):
help='Wait for action to complete', help='Wait for action to complete',
) )
_tag.add_tag_option_to_parser_for_set(parser, 'member')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -303,6 +314,14 @@ class SetMember(command.Command):
pool_id = attrs.pop('pool_id') pool_id = attrs.pop('pool_id')
member_id = attrs.pop('member_id') member_id = attrs.pop('member_id')
member_show = functools.partial(
self.app.client_manager.load_balancer.member_show,
pool_id
)
v2_utils.set_tags_for_set(
member_show, member_id, attrs, clear_tags=parsed_args.no_tag)
post_data = {"member": attrs} post_data = {"member": attrs}
self.app.client_manager.load_balancer.member_set( self.app.client_manager.load_balancer.member_set(
@ -312,10 +331,6 @@ class SetMember(command.Command):
) )
if parsed_args.wait: if parsed_args.wait:
member_show = functools.partial(
self.app.client_manager.load_balancer.member_show,
pool_id
)
v2_utils.wait_for_active( v2_utils.wait_for_active(
status_f=member_show, status_f=member_show,
res_id=member_id res_id=member_id
@ -414,32 +429,39 @@ class UnsetMember(command.Command):
action='store_true', action='store_true',
help='Wait for action to complete', help='Wait for action to complete',
) )
_tag.add_tag_option_to_parser_for_unset(parser, 'member')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
unset_args = v2_utils.get_unsets(parsed_args) unset_args = v2_utils.get_unsets(parsed_args)
if not unset_args: if not unset_args and not parsed_args.all_tag:
return return
pool_id = v2_utils.get_resource_id( pool_id = v2_utils.get_resource_id(
self.app.client_manager.load_balancer.pool_list, self.app.client_manager.load_balancer.pool_list,
'pools', parsed_args.pool) 'pools', parsed_args.pool)
member_show = functools.partial(
self.app.client_manager.load_balancer.member_show,
pool_id
)
member_dict = {'pool_id': pool_id, 'member_id': parsed_args.member} member_dict = {'pool_id': pool_id, 'member_id': parsed_args.member}
member_id = v2_utils.get_resource_id( member_id = v2_utils.get_resource_id(
self.app.client_manager.load_balancer.member_list, self.app.client_manager.load_balancer.member_list,
'members', member_dict) 'members', member_dict)
v2_utils.set_tags_for_unset(
member_show, member_id, unset_args,
clear_tags=parsed_args.all_tag)
body = {'member': unset_args} body = {'member': unset_args}
self.app.client_manager.load_balancer.member_set( self.app.client_manager.load_balancer.member_set(
pool_id=pool_id, member_id=member_id, json=body) pool_id=pool_id, member_id=member_id, json=body)
if parsed_args.wait: if parsed_args.wait:
member_show = functools.partial(
self.app.client_manager.load_balancer.member_show,
pool_id
)
v2_utils.wait_for_active( v2_utils.wait_for_active(
status_f=member_show, status_f=member_show,
res_id=member_id res_id=member_id

View File

@ -19,6 +19,7 @@ from cliff import lister
from osc_lib.command import command from osc_lib.command import command
from osc_lib import exceptions from osc_lib import exceptions
from osc_lib import utils from osc_lib import utils
from osc_lib.utils import tags as _tag
from oslo_utils import uuidutils from oslo_utils import uuidutils
from octaviaclient.osc.v2 import constants as const from octaviaclient.osc.v2 import constants as const
@ -146,6 +147,9 @@ class CreatePool(command.ShowOne):
"by the pool (can be set multiple times)." "by the pool (can be set multiple times)."
) )
_tag.add_tag_option_to_parser_for_create(
parser, 'pool')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -171,7 +175,8 @@ class CreatePool(command.ShowOne):
formatters = {'loadbalancers': v2_utils.format_list, formatters = {'loadbalancers': v2_utils.format_list,
'members': v2_utils.format_list, 'members': v2_utils.format_list,
'listeners': v2_utils.format_list, 'listeners': v2_utils.format_list,
'session_persistence': v2_utils.format_hash} 'session_persistence': v2_utils.format_hash,
'tags': v2_utils.format_list_flat}
return (rows, (utils.get_dict_properties( return (rows, (utils.get_dict_properties(
data['pool'], rows, formatters=formatters, data['pool'], rows, formatters=formatters,
@ -222,6 +227,8 @@ class ListPool(lister.Lister):
help="Filter by load balancer (name or ID).", help="Filter by load balancer (name or ID).",
) )
_tag.add_tag_filtering_option_to_parser(parser, 'pool')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -271,7 +278,8 @@ class ShowPool(command.ShowOne):
formatters = {'loadbalancers': v2_utils.format_list, formatters = {'loadbalancers': v2_utils.format_list,
'members': v2_utils.format_list, 'members': v2_utils.format_list,
'listeners': v2_utils.format_list, 'listeners': v2_utils.format_list,
'session_persistence': v2_utils.format_hash} 'session_persistence': v2_utils.format_hash,
'tags': v2_utils.format_list_flat}
return (rows, (utils.get_dict_properties( return (rows, (utils.get_dict_properties(
data, rows, formatters=formatters, data, rows, formatters=formatters,
@ -382,12 +390,18 @@ class SetPool(command.Command):
) )
_tag.add_tag_option_to_parser_for_set(parser, 'pool')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
attrs = v2_utils.get_pool_attrs(self.app.client_manager, parsed_args) attrs = v2_utils.get_pool_attrs(self.app.client_manager, parsed_args)
pool_id = attrs.pop('pool_id') pool_id = attrs.pop('pool_id')
v2_utils.set_tags_for_set(
self.app.client_manager.load_balancer.pool_show,
pool_id, attrs, clear_tags=parsed_args.no_tag)
body = {'pool': attrs} body = {'pool': attrs}
self.app.client_manager.load_balancer.pool_set( self.app.client_manager.load_balancer.pool_set(
@ -458,17 +472,24 @@ class UnsetPool(command.Command):
action='store_true', action='store_true',
help='Wait for action to complete', help='Wait for action to complete',
) )
_tag.add_tag_option_to_parser_for_unset(parser, 'pool')
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
unset_args = v2_utils.get_unsets(parsed_args) unset_args = v2_utils.get_unsets(parsed_args)
if not unset_args: if not unset_args and not parsed_args.all_tag:
return return
pool_id = v2_utils.get_resource_id( pool_id = v2_utils.get_resource_id(
self.app.client_manager.load_balancer.pool_list, self.app.client_manager.load_balancer.pool_list,
'pools', parsed_args.pool) 'pools', parsed_args.pool)
v2_utils.set_tags_for_unset(
self.app.client_manager.load_balancer.pool_show,
pool_id, unset_args, clear_tags=parsed_args.all_tag)
body = {'pool': unset_args} body = {'pool': unset_args}
self.app.client_manager.load_balancer.pool_set( self.app.client_manager.load_balancer.pool_set(

View File

@ -124,6 +124,16 @@ def get_resource_id(resource, resource_name, name):
raise osc_exc.CommandError(msg) from e raise osc_exc.CommandError(msg) from e
def add_tags_attr_map(attr_map):
tags_attr_map = {
'tags': ('tags', list),
'any_tags': ('tags-any', list),
'not_tags': ('not-tags', list),
'not_any_tags': ('not-tags-any', list),
}
attr_map.update(tags_attr_map)
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),
@ -174,8 +184,8 @@ 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),
} }
add_tags_attr_map(attr_map)
_attrs = vars(parsed_args) _attrs = vars(parsed_args)
attrs = _map_attrs(_attrs, attr_map) attrs = _map_attrs(_attrs, attr_map)
@ -229,6 +239,7 @@ def get_listener_attrs(client_manager, parsed_args):
'tls_versions': ('tls_versions', list), 'tls_versions': ('tls_versions', list),
'alpn_protocols': ('alpn_protocols', list), 'alpn_protocols': ('alpn_protocols', list),
} }
add_tags_attr_map(attr_map)
_attrs = vars(parsed_args) _attrs = vars(parsed_args)
attrs = _map_attrs(_attrs, attr_map) attrs = _map_attrs(_attrs, attr_map)
@ -277,6 +288,7 @@ def get_pool_attrs(client_manager, parsed_args):
'tls_ciphers': ('tls_ciphers', str), 'tls_ciphers': ('tls_ciphers', str),
'tls_versions': ('tls_versions', list), 'tls_versions': ('tls_versions', list),
} }
add_tags_attr_map(attr_map)
_attrs = vars(parsed_args) _attrs = vars(parsed_args)
attrs = _map_attrs(_attrs, attr_map) attrs = _map_attrs(_attrs, attr_map)
@ -318,6 +330,7 @@ def get_member_attrs(client_manager, parsed_args):
'enable': ('admin_state_up', lambda x: True), 'enable': ('admin_state_up', lambda x: True),
'disable': ('admin_state_up', lambda x: False), 'disable': ('admin_state_up', lambda x: False),
} }
add_tags_attr_map(attr_map)
_attrs = vars(parsed_args) _attrs = vars(parsed_args)
attrs = _map_attrs(_attrs, attr_map) attrs = _map_attrs(_attrs, attr_map)
@ -357,6 +370,7 @@ def get_l7policy_attrs(client_manager, parsed_args):
'enable': ('admin_state_up', lambda x: True), 'enable': ('admin_state_up', lambda x: True),
'disable': ('admin_state_up', lambda x: False) 'disable': ('admin_state_up', lambda x: False)
} }
add_tags_attr_map(attr_map)
_attrs = vars(parsed_args) _attrs = vars(parsed_args)
attrs = _map_attrs(_attrs, attr_map) attrs = _map_attrs(_attrs, attr_map)
@ -391,6 +405,7 @@ def get_l7rule_attrs(client_manager, parsed_args):
'enable': ('admin_state_up', lambda x: True), 'enable': ('admin_state_up', lambda x: True),
'disable': ('admin_state_up', lambda x: False) 'disable': ('admin_state_up', lambda x: False)
} }
add_tags_attr_map(attr_map)
_attrs = vars(parsed_args) _attrs = vars(parsed_args)
attrs = _map_attrs(_attrs, attr_map) attrs = _map_attrs(_attrs, attr_map)
@ -429,6 +444,7 @@ def get_health_monitor_attrs(client_manager, parsed_args):
'http_version': ('http_version', float), 'http_version': ('http_version', float),
'domain_name': ('domain_name', str) 'domain_name': ('domain_name', str)
} }
add_tags_attr_map(attr_map)
_attrs = vars(parsed_args) _attrs = vars(parsed_args)
attrs = _map_attrs(_attrs, attr_map) attrs = _map_attrs(_attrs, attr_map)
@ -604,8 +620,13 @@ def _format_str_if_need_treat_unset(data):
def get_unsets(parsed_args): def get_unsets(parsed_args):
return {arg: None for arg, value in vars(parsed_args).items() if unsets = {}
value is True and arg != 'wait'} for arg, value in vars(parsed_args).items():
if value and arg == 'tags':
unsets[arg] = value
elif value is True and arg not in ('wait', 'all_tag'):
unsets[arg] = None
return unsets
def wait_for_active(status_f, res_id): def wait_for_active(status_f, res_id):
@ -642,3 +663,23 @@ def wait_for_delete(status_f, res_id,
except exceptions.OctaviaClientException as e: except exceptions.OctaviaClientException as e:
if e.code != 404: if e.code != 404:
raise raise
def set_tags_for_set(resource_get, resource_id, attrs, clear_tags=False):
if attrs.get('tags'):
resource = resource_get(resource_id)
tags = set([] if clear_tags else resource['tags'])
tags |= set(attrs['tags'])
attrs['tags'] = list(tags)
elif clear_tags:
attrs['tags'] = []
def set_tags_for_unset(resource_get, resource_id, attrs, clear_tags=False):
if clear_tags:
attrs['tags'] = []
elif attrs.get('tags'):
resource = resource_get(resource_id)
tags = set(resource['tags'])
tags -= set(attrs['tags'])
attrs['tags'] = list(tags)

View File

@ -81,7 +81,8 @@ LISTENER_ATTRS = {
"allowed_cidrs": ['192.0.2.0/24', '198.51.100.0/24'], "allowed_cidrs": ['192.0.2.0/24', '198.51.100.0/24'],
'tls_ciphers': "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256", 'tls_ciphers': "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256",
'tls_versions': ['TLSv1.1', 'TLSv1.2'], 'tls_versions': ['TLSv1.1', 'TLSv1.2'],
'alpn_protocols': ['h2', 'http/1.1'] 'alpn_protocols': ['h2', 'http/1.1'],
"tags": ["foo", "bar"]
} }
LOADBALANCER_ATTRS = { LOADBALANCER_ATTRS = {
@ -96,6 +97,7 @@ 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),
"tags": ["foo", "bar"]
} }
L7POLICY_ATTRS = { L7POLICY_ATTRS = {
@ -159,7 +161,8 @@ POOL_ATTRS = {
"crl_container_ref": uuidutils.generate_uuid(), "crl_container_ref": uuidutils.generate_uuid(),
"tls_enabled": True, "tls_enabled": True,
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256", "tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256",
"tls_versions": ['TLSv1.1', 'TLSv1.2'] "tls_versions": ['TLSv1.1', 'TLSv1.2'],
"tags": ["foo", "bar"],
} }
QUOTA_ATTRS = { QUOTA_ATTRS = {

View File

@ -60,6 +60,62 @@ class TestHealthMonitorList(TestHealthMonitor):
self.assertEqual(self.columns, columns) self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data)) self.assertEqual(self.datalist, tuple(data))
def test_health_monitor_list_with_tags(self):
arglist = ['--tags', 'foo,bar']
verifylist = [('tags', ['foo', 'bar'])]
expected_attrs = {
'tags': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.health_monitor_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_health_monitor_list_with_any_tags(self):
arglist = ['--any-tags', 'foo,bar']
verifylist = [('any_tags', ['foo', 'bar'])]
expected_attrs = {
'tags-any': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.health_monitor_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_health_monitor_list_with_not_tags(self):
arglist = ['--not-tags', 'foo,bar']
verifylist = [('not_tags', ['foo', 'bar'])]
expected_attrs = {
'not-tags': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.health_monitor_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_health_monitor_list_with_not_any_tags(self):
arglist = ['--not-any-tags', 'foo,bar']
verifylist = [('not_any_tags', ['foo', 'bar'])]
expected_attrs = {
'not-tags-any': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.health_monitor_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
class TestHealthMonitorDelete(TestHealthMonitor): class TestHealthMonitorDelete(TestHealthMonitor):
@ -189,6 +245,32 @@ class TestHealthMonitorCreate(TestHealthMonitor):
sleep_time=mock.ANY, sleep_time=mock.ANY,
status_field='provisioning_status') status_field='provisioning_status')
@mock.patch('octaviaclient.osc.v2.utils.get_health_monitor_attrs')
def test_health_monitor_create_with_tag(self, mock_attrs):
mock_attrs.return_value = self.hm_info
arglist = ['mock_pool_id',
'--name', self._hm.name,
'--delay', str(self._hm.delay),
'--timeout', str(self._hm.timeout),
'--max-retries', str(self._hm.max_retries),
'--type', self._hm.type.lower(),
'--tag', 'foo']
verifylist = [
('pool', 'mock_pool_id'),
('name', self._hm.name),
('delay', str(self._hm.delay)),
('timeout', str(self._hm.timeout)),
('max_retries', self._hm.max_retries),
('type', self._hm.type),
('tags', ['foo'])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.health_monitor_create.assert_called_with(
json={'healthmonitor': self.hm_info})
class TestHealthMonitorShow(TestHealthMonitor): class TestHealthMonitorShow(TestHealthMonitor):
@ -257,6 +339,43 @@ class TestHealthMonitorSet(TestHealthMonitor):
sleep_time=mock.ANY, sleep_time=mock.ANY,
status_field='provisioning_status') status_field='provisioning_status')
def test_health_monitor_set_tag(self):
self.api_mock.health_monitor_show.return_value = {
'tags': ['foo']
}
arglist = [self._hm.id, '--tag', 'bar']
verifylist = [
('health_monitor', self._hm.id),
('tags', ['bar']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.health_monitor_set.assert_called_once()
kwargs = self.api_mock.health_monitor_set.mock_calls[0][2]
tags = kwargs['json']['healthmonitor']['tags']
self.assertEqual(2, len(tags))
self.assertIn('foo', tags)
self.assertIn('bar', tags)
def test_health_monitor_set_tag_no_tag(self):
self.api_mock.health_monitor_show.return_value = {
'tags': ['foo']
}
arglist = [self._hm.id, '--tag', 'bar', '--no-tag']
verifylist = [
('health_monitor', self._hm.id),
('tags', ['bar']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.health_monitor_set.assert_called_once_with(
self._hm.id,
json={"healthmonitor": {"tags": ['bar']}})
class TestHealthMonitorUnset(TestHealthMonitor): class TestHealthMonitorUnset(TestHealthMonitor):
PARAMETERS = ('name', 'domain_name', 'expected_codes', 'http_method', PARAMETERS = ('name', 'domain_name', 'expected_codes', 'http_method',
@ -350,3 +469,41 @@ class TestHealthMonitorUnset(TestHealthMonitor):
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.api_mock.health_monitor_set.assert_not_called() self.api_mock.health_monitor_set.assert_not_called()
def test_health_monitor_unset_tag(self):
self.api_mock.health_monitor_set.reset_mock()
self.api_mock.health_monitor_show.return_value = {
'tags': ['foo', 'bar']
}
arglist = [self._hm.id, '--tag', 'foo']
verifylist = [
('health_monitor', self._hm.id),
('tags', ['foo']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.health_monitor_set.assert_called_once_with(
self._hm.id,
json={"healthmonitor": {"tags": ['bar']}})
def test_health_monitor_unset_all_tag(self):
self.api_mock.health_monitor_set.reset_mock()
self.api_mock.health_monitor_show.return_value = {
'tags': ['foo', 'bar']
}
arglist = [self._hm.id, '--all-tag']
verifylist = [
('health_monitor', self._hm.id),
('all_tag', True),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.health_monitor_set.assert_called_once_with(
self._hm.id,
json={"healthmonitor": {"tags": []}})

View File

@ -76,6 +76,62 @@ class TestL7PolicyList(TestL7Policy):
self.assertEqual(self.columns, columns) self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data)) self.assertEqual(self.datalist, tuple(data))
def test_l7policy_list_with_tags(self):
arglist = ['--tags', 'foo,bar']
verifylist = [('tags', ['foo', 'bar'])]
expected_attrs = {
'tags': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.l7policy_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_l7policy_list_with_any_tags(self):
arglist = ['--any-tags', 'foo,bar']
verifylist = [('any_tags', ['foo', 'bar'])]
expected_attrs = {
'tags-any': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.l7policy_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_l7policy_list_with_not_tags(self):
arglist = ['--not-tags', 'foo,bar']
verifylist = [('not_tags', ['foo', 'bar'])]
expected_attrs = {
'not-tags': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.l7policy_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_l7policy_list_with_not_any_tags(self):
arglist = ['--not-any-tags', 'foo,bar']
verifylist = [('not_any_tags', ['foo', 'bar'])]
expected_attrs = {
'not-tags-any': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.l7policy_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
class TestL7PolicyDelete(TestL7Policy): class TestL7PolicyDelete(TestL7Policy):
@ -205,6 +261,40 @@ class TestL7PolicyCreate(TestL7Policy):
sleep_time=mock.ANY, sleep_time=mock.ANY,
status_field='provisioning_status') status_field='provisioning_status')
@mock.patch('octaviaclient.osc.v2.utils.get_l7policy_attrs')
def test_l7policy_create_with_tag(self, mock_attrs):
mock_attrs.return_value = {
'listener_id': self._l7po.listener_id,
'name': self._l7po.name,
'action': 'REDIRECT_TO_POOL',
'redirect_pool_id': self._l7po.redirect_pool_id,
'tags': ['foo']
}
arglist = ['mock_li_id',
'--name', self._l7po.name,
'--action', 'REDIRECT_TO_POOL'.lower(),
'--redirect-pool', self._l7po.redirect_pool_id,
'--tag', 'foo']
verifylist = [
('listener', 'mock_li_id'),
('name', self._l7po.name),
('action', 'REDIRECT_TO_POOL'),
('redirect_pool', self._l7po.redirect_pool_id),
('tags', ['foo'])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.l7policy_create.assert_called_with(
json={'l7policy': {
'listener_id': self._l7po.listener_id,
'name': self._l7po.name,
'action': 'REDIRECT_TO_POOL',
'redirect_pool_id': self._l7po.redirect_pool_id,
'tags': ['foo']}})
class TestL7PolicyShow(TestL7Policy): class TestL7PolicyShow(TestL7Policy):
@ -268,6 +358,44 @@ class TestL7PolicySet(TestL7Policy):
sleep_time=mock.ANY, sleep_time=mock.ANY,
status_field='provisioning_status') status_field='provisioning_status')
def test_l7policy_set_tag(self):
self.api_mock.l7policy_show.return_value = {
'tags': ['foo']
}
arglist = [self._l7po.id, '--tag', 'bar']
verifylist = [
('l7policy', self._l7po.id),
('tags', ['bar']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.l7policy_set.assert_called_once()
kwargs = self.api_mock.l7policy_set.mock_calls[0][2]
tags = kwargs['json']['l7policy']['tags']
self.assertEqual(2, len(tags))
self.assertIn('foo', tags)
self.assertIn('bar', tags)
def test_l7policy_set_tag_no_tag(self):
self.api_mock.l7policy_show.return_value = {
'tags': ['foo']
}
arglist = [self._l7po.id, '--tag', 'bar', '--no-tag']
verifylist = [
('l7policy', self._l7po.id),
('tags', ['bar']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.l7policy_set.assert_called_once_with(
self._l7po.id,
json={'l7policy': {'tags': ['bar']}}
)
class TestL7PolicyUnset(TestL7Policy): class TestL7PolicyUnset(TestL7Policy):
PARAMETERS = ('name', 'description', 'redirect_http_code') PARAMETERS = ('name', 'description', 'redirect_http_code')
@ -348,3 +476,43 @@ class TestL7PolicyUnset(TestL7Policy):
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.api_mock.l7policy_set.assert_not_called() self.api_mock.l7policy_set.assert_not_called()
def test_l7policy_unset_tag(self):
self.api_mock.l7policy_set.reset_mock()
self.api_mock.l7policy_show.return_value = {
'tags': ['foo', 'bar']
}
arglist = [self._l7po.id, '--tag', 'foo']
verifylist = [
('l7policy', self._l7po.id),
('tags', ['foo']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.l7policy_set.assert_called_once_with(
self._l7po.id,
json={'l7policy': {'tags': ['bar']}}
)
def test_l7policy_unset_all_tag(self):
self.api_mock.l7policy_set.reset_mock()
self.api_mock.l7policy_show.return_value = {
'tags': ['foo', 'bar']
}
arglist = [self._l7po.id, '--all-tag']
verifylist = [
('l7policy', self._l7po.id),
('all_tag', True),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.l7policy_set.assert_called_once_with(
self._l7po.id,
json={'l7policy': {'tags': []}}
)

View File

@ -62,6 +62,74 @@ class TestL7RuleList(TestL7Rule):
self.assertEqual(self.columns, columns) self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data)) self.assertEqual(self.datalist, tuple(data))
def test_l7rule_list_with_tags(self):
arglist = [self._l7po.id,
'--tags', 'foo,bar']
verifylist = [('l7policy', self._l7po.id),
('tags', ['foo', 'bar'])]
expected_attrs = {
'l7policy_id': self._l7po.id,
'tags': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.l7rule_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_l7rule_list_with_any_tags(self):
arglist = [self._l7po.id,
'--any-tags', 'foo,bar']
verifylist = [('l7policy', self._l7po.id),
('any_tags', ['foo', 'bar'])]
expected_attrs = {
'l7policy_id': self._l7po.id,
'tags-any': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.l7rule_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_l7rule_list_with_not_tags(self):
arglist = [self._l7po.id,
'--not-tags', 'foo,bar']
verifylist = [('l7policy', self._l7po.id),
('not_tags', ['foo', 'bar'])]
expected_attrs = {
'l7policy_id': self._l7po.id,
'not-tags': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.l7rule_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_l7rule_list_with_not_any_tags(self):
arglist = [self._l7po.id,
'--not-any-tags', 'foo,bar']
verifylist = [('l7policy', self._l7po.id),
('not_any_tags', ['foo', 'bar'])]
expected_attrs = {
'l7policy_id': self._l7po.id,
'not-tags-any': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.l7rule_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
class TestL7RuleDelete(TestL7Rule): class TestL7RuleDelete(TestL7Rule):
@ -110,7 +178,7 @@ class TestL7RuleDelete(TestL7Rule):
) )
mock_wait.assert_called_once_with( mock_wait.assert_called_once_with(
manager=mock.ANY, manager=mock.ANY,
res_id=self._l7ru.id, res_id=self._l7po.id,
sleep_time=mock.ANY, sleep_time=mock.ANY,
status_field='provisioning_status') status_field='provisioning_status')
@ -199,6 +267,40 @@ class TestL7RuleCreate(TestL7Rule):
sleep_time=mock.ANY, sleep_time=mock.ANY,
status_field='provisioning_status') status_field='provisioning_status')
@mock.patch('octaviaclient.osc.v2.utils.get_l7rule_attrs')
def test_l7rule_create_with_tag(self, mock_attrs):
mock_attrs.return_value = {
'l7policy_id': self._l7po.id,
'compare-type': 'ENDS_WITH',
'value': '.example.com',
'type': 'HOST_NAME',
'tags': ['foo']
}
arglist = [self._l7po.id,
'--compare-type', 'ENDS_WITH',
'--value', '.example.com',
'--type', 'HOST_NAME'.lower(),
'--tag', 'foo']
verifylist = [
('l7policy', self._l7po.id),
('compare_type', 'ENDS_WITH'),
('value', '.example.com'),
('type', 'HOST_NAME'),
('tags', ['foo'])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.l7rule_create.assert_called_with(
l7policy_id=self._l7po.id,
json={'rule': {
'compare-type': 'ENDS_WITH',
'value': '.example.com',
'type': 'HOST_NAME',
'tags': ['foo']}
})
class TestL7RuleShow(TestL7Rule): class TestL7RuleShow(TestL7Rule):
@ -285,10 +387,72 @@ class TestL7RuleSet(TestL7Rule):
json={'rule': {'admin_state_up': False}}) json={'rule': {'admin_state_up': False}})
mock_wait.assert_called_once_with( mock_wait.assert_called_once_with(
status_f=mock.ANY, status_f=mock.ANY,
res_id=self._l7ru.id, res_id=self._l7po.id,
sleep_time=mock.ANY, sleep_time=mock.ANY,
status_field='provisioning_status') status_field='provisioning_status')
@mock.patch('octaviaclient.osc.v2.utils.get_l7rule_attrs')
def test_l7rule_set_tag(self, mock_attrs):
self.api_mock.l7rule_show.return_value = {
'tags': ['foo']
}
mock_attrs.return_value = {
'l7policy_id': self._l7po.id,
'l7rule_id': self._l7ru.id,
'tags': ['bar']
}
arglist = [
self._l7po.id,
self._l7ru.id,
'--tag', 'bar'
]
verifylist = [
('l7policy', self._l7po.id),
('l7rule', self._l7ru.id),
('tags', ['bar'])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.l7rule_set.assert_called_once()
kwargs = self.api_mock.l7rule_set.mock_calls[0][2]
tags = kwargs['json']['rule']['tags']
self.assertEqual(2, len(tags))
self.assertIn('foo', tags)
self.assertIn('bar', tags)
@mock.patch('octaviaclient.osc.v2.utils.get_l7rule_attrs')
def test_l7rule_set_tag_no_tag(self, mock_attrs):
self.api_mock.l7rule_show.return_value = {
'tags': ['foo']
}
mock_attrs.return_value = {
'l7policy_id': self._l7po.id,
'l7rule_id': self._l7ru.id,
'tags': ['bar']
}
arglist = [
self._l7po.id,
self._l7ru.id,
'--tag', 'bar', '--no-tag'
]
verifylist = [
('l7policy', self._l7po.id),
('l7rule', self._l7ru.id),
('tags', ['bar']),
('no_tag', True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.l7rule_set.assert_called_once_with(
l7policy_id=self._l7po.id,
l7rule_id=self._l7ru.id,
json={'rule': {'tags': ['bar']}}
)
class TestL7RuleUnset(TestL7Rule): class TestL7RuleUnset(TestL7Rule):
PARAMETERS = ('invert', 'key') PARAMETERS = ('invert', 'key')
@ -340,7 +504,7 @@ class TestL7RuleUnset(TestL7Rule):
l7policy_id=self._l7po.id, l7rule_id=self._l7ru.id, json=ref_body) l7policy_id=self._l7po.id, l7rule_id=self._l7ru.id, json=ref_body)
mock_wait.assert_called_once_with( mock_wait.assert_called_once_with(
status_f=mock.ANY, status_f=mock.ANY,
res_id=self._l7ru.id, res_id=self._l7po.id,
sleep_time=mock.ANY, sleep_time=mock.ANY,
status_field='provisioning_status') status_field='provisioning_status')
@ -367,3 +531,63 @@ class TestL7RuleUnset(TestL7Rule):
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.api_mock.l7rule_set.assert_not_called() self.api_mock.l7rule_set.assert_not_called()
@mock.patch('octaviaclient.osc.v2.utils.get_l7rule_attrs')
def test_l7rule_unset_tag(self, mock_attrs):
self.api_mock.l7rule_show.return_value = {
'tags': ['foo', 'bar']
}
mock_attrs.return_value = {
'l7policy_id': self._l7po.id,
'l7rule_id': self._l7ru.id,
'tags': ['foo', 'bar']
}
arglist = [
self._l7po.id,
self._l7ru.id,
'--tag', 'foo'
]
verifylist = [
('l7policy', self._l7po.id),
('l7rule_id', self._l7ru.id),
('tags', ['foo'])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.l7rule_set.assert_called_once_with(
l7policy_id=self._l7po.id,
l7rule_id=self._l7ru.id,
json={'rule': {'tags': ['bar']}}
)
@mock.patch('octaviaclient.osc.v2.utils.get_l7rule_attrs')
def test_l7rule_unset_all_tags(self, mock_attrs):
self.api_mock.l7rule_show.return_value = {
'tags': ['foo', 'bar']
}
mock_attrs.return_value = {
'l7policy_id': self._l7po.id,
'l7rule_id': self._l7ru.id,
'tags': ['foo', 'bar']
}
arglist = [
self._l7po.id,
self._l7ru.id,
'--all-tag'
]
verifylist = [
('l7policy', self._l7po.id),
('l7rule_id', self._l7ru.id),
('all_tag', True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.l7rule_set.assert_called_once_with(
l7policy_id=self._l7po.id,
l7rule_id=self._l7ru.id,
json={'rule': {'tags': []}}
)

View File

@ -67,6 +67,60 @@ class TestListenerList(TestListener):
self.assertEqual(self.columns, columns) self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data)) self.assertEqual(self.datalist, tuple(data))
def test_listener_list_with_tags(self):
arglist = ['--tags', 'foo,bar']
verifylist = [('tags', ['foo', 'bar'])]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.listener_list.assert_called_with(
tags=['foo', 'bar'])
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_listener_list_with_any_tags(self):
arglist = ['--any-tags', 'foo,bar']
verifylist = [('any_tags', ['foo', 'bar'])]
expected_attrs = {
"tags-any": ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.listener_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_listener_list_with_not_tags(self):
arglist = ['--not-tags', 'foo,bar']
verifylist = [('not_tags', ['foo', 'bar'])]
expected_attrs = {
"not-tags": ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.listener_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_listener_list_with_not_any_tags(self):
arglist = ['--not-any-tags', 'foo,bar']
verifylist = [('not_any_tags', ['foo', 'bar'])]
expected_attrs = {
"not-tags-any": ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.listener_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
class TestListenerDelete(TestListener): class TestListenerDelete(TestListener):
@ -255,6 +309,27 @@ class TestListenerCreate(TestListener):
self.api_mock.listener_create.assert_called_with( self.api_mock.listener_create.assert_called_with(
json={'listener': self.listener_info}) json={'listener': self.listener_info})
@mock.patch('octaviaclient.osc.v2.utils.get_listener_attrs')
def test_listener_create_with_tag(self, mock_client):
mock_client.return_value = self.listener_info
arglist = ['mock_lb_id',
'--name', self._listener.name,
'--protocol', 'HTTP',
'--protocol-port', '80',
'--tag', 'foo']
verifylist = [
('loadbalancer', 'mock_lb_id'),
('name', self._listener.name),
('protocol', 'HTTP'),
('protocol_port', 80),
('tags', ['foo']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.listener_create.assert_called_with(
json={'listener': self.listener_info})
class TestListenerShow(TestListener): class TestListenerShow(TestListener):
@ -369,6 +444,44 @@ class TestListenerSet(TestListener):
sleep_time=mock.ANY, sleep_time=mock.ANY,
status_field='provisioning_status') status_field='provisioning_status')
def test_listener_set_tag(self):
self.api_mock.listener_show.return_value = {
'tags': ['foo']
}
arglist = [self._listener.id, '--tag', 'bar']
verifylist = [
('listener', self._listener.id),
('tags', ['bar']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.listener_set.assert_called_once()
kwargs = self.api_mock.listener_set.mock_calls[0][2]
tags = kwargs['json']['listener']['tags']
self.assertEqual(2, len(tags))
self.assertIn('foo', tags)
self.assertIn('bar', tags)
def test_listener_set_tag_no_tag(self):
self.api_mock.listener_show.return_value = {
'tags': ['foo']
}
arglist = [self._listener.id, '--tag', 'bar', '--no-tag']
verifylist = [
('listener', self._listener.id),
('tags', ['bar']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.listener_set.assert_called_once_with(
self._listener.id,
json={"listener": {"tags": ['bar']}}
)
class TestListenerStatsShow(TestListener): class TestListenerStatsShow(TestListener):
@ -529,3 +642,43 @@ class TestListenerUnset(TestListener):
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.api_mock.listener_set.assert_not_called() self.api_mock.listener_set.assert_not_called()
def test_listener_unset_tag(self):
self.api_mock.listener_set.reset_mock()
self.api_mock.listener_show.return_value = {
'tags': ['foo', 'bar']
}
arglist = [self._listener.id, '--tag', 'foo']
verifylist = [
('listener', self._listener.id),
('tags', ['foo']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.listener_set.assert_called_once_with(
self._listener.id,
json={"listener": {"tags": ['bar']}}
)
def test_listener_unset_all_tag(self):
self.api_mock.listener_set.reset_mock()
self.api_mock.listener_show.return_value = {
'tags': ['foo', 'bar']
}
arglist = [self._listener.id, '--all-tag']
verifylist = [
('listener', self._listener.id),
('all_tag', True),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.listener_set.assert_called_once_with(
self._listener.id,
json={"listener": {"tags": []}}
)

View File

@ -196,6 +196,74 @@ class TestLoadBalancerList(TestLoadBalancer):
self.assertEqual(self.columns, columns) self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data)) self.assertEqual(self.datalist, tuple(data))
@mock.patch('octaviaclient.osc.v2.utils.get_loadbalancer_attrs')
def test_load_balancer_list_with_tags(self, mock_client):
mock_client.return_value = {
'tags': self._lb.tags,
}
arglist = [
'--tags', ",".join(self._lb.tags),
]
verify_list = [
('tags', self._lb.tags),
]
parsed_args = self.check_parser(self.cmd, arglist, verify_list)
columns, data = self.cmd.take_action(parsed_args)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
@mock.patch('octaviaclient.osc.v2.utils.get_loadbalancer_attrs')
def test_load_balancer_list_with_any_tags(self, mock_client):
mock_client.return_value = {
'tags': self._lb.tags,
}
arglist = [
'--any-tags', ",".join(self._lb.tags),
]
verify_list = [
('any_tags', self._lb.tags),
]
parsed_args = self.check_parser(self.cmd, arglist, verify_list)
columns, data = self.cmd.take_action(parsed_args)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
@mock.patch('octaviaclient.osc.v2.utils.get_loadbalancer_attrs')
def test_load_balancer_list_with_not_tags(self, mock_client):
mock_client.return_value = {
'tags': self._lb.tags[0],
}
arglist = [
'--any-tags', ",".join(self._lb.tags),
]
verify_list = [
('any_tags', self._lb.tags),
]
parsed_args = self.check_parser(self.cmd, arglist, verify_list)
columns, data = self.cmd.take_action(parsed_args)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
@mock.patch('octaviaclient.osc.v2.utils.get_loadbalancer_attrs')
def test_load_balancer_list_with_not_any_tags(self, mock_client):
mock_client.return_value = {
'tags': self._lb.tags[0],
}
arglist = [
'--not-any-tags', ",".join(self._lb.tags),
]
verify_list = [
('not_any_tags', self._lb.tags),
]
parsed_args = self.check_parser(self.cmd, arglist, verify_list)
columns, data = self.cmd.take_action(parsed_args)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
class TestLoadBalancerDelete(TestLoadBalancer): class TestLoadBalancerDelete(TestLoadBalancer):
@ -353,6 +421,31 @@ 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_tags(self, mock_client):
lb_info = copy.deepcopy(self.lb_info)
lb_info.update({'tags': self._lb.tags})
mock_client.return_value = lb_info
arglist = [
'--name', self._lb.name,
'--vip-network-id', self._lb.vip_network_id,
'--project', self._lb.project_id,
'--tag', self._lb.tags[0],
'--tag', self._lb.tags[1],
]
verifylist = [
('name', self._lb.name),
('vip_network_id', self._lb.vip_network_id),
('project', self._lb.project_id),
('tags', self._lb.tags),
]
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': 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_missing_args(self, mock_client): def test_load_balancer_create_missing_args(self, mock_client):
attrs_list = self.lb_info attrs_list = self.lb_info
@ -474,6 +567,61 @@ class TestLoadBalancerSet(TestLoadBalancer):
sleep_time=mock.ANY, sleep_time=mock.ANY,
status_field='provisioning_status') status_field='provisioning_status')
@mock.patch('octaviaclient.osc.v2.utils.get_loadbalancer_attrs')
def test_load_balancer_set_tag(self, mock_attrs):
self.api_mock.load_balancer_show.return_value = {
'tags': ['foo']
}
mock_attrs.return_value = {
'loadbalancer_id': self._lb.id,
'tags': ['bar']
}
arglist = [self._lb.id, '--tag', 'bar']
verifylist = [
('loadbalancer', self._lb.id),
('tags', ['bar'])
]
try:
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
except Exception as e:
self.fail("%s raised unexpectedly" % e)
self.api_mock.load_balancer_set.assert_called_once()
kwargs = self.api_mock.load_balancer_set.mock_calls[0][2]
tags = kwargs['json']['loadbalancer']['tags']
self.assertEqual(2, len(tags))
self.assertIn('foo', tags)
self.assertIn('bar', tags)
@mock.patch('octaviaclient.osc.v2.utils.get_loadbalancer_attrs')
def test_load_balancer_set_tag_no_tag(self, mock_attrs):
self.api_mock.load_balancer_show.return_value = {
'tags': ['foo']
}
mock_attrs.return_value = {
'loadbalancer_id': self._lb.id,
'tags': ['bar']
}
arglist = [self._lb.id, '--tag', 'bar', '--no-tag']
verifylist = [
('loadbalancer', self._lb.id),
('tags', ['bar'])
]
try:
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
except Exception as e:
self.fail("%s raised unexpectedly" % e)
self.api_mock.load_balancer_set.assert_called_once_with(
self._lb.id,
json={'loadbalancer': {'tags': ['bar']}})
@mock.patch('octaviaclient.osc.v2.utils.get_loadbalancer_attrs') @mock.patch('octaviaclient.osc.v2.utils.get_loadbalancer_attrs')
def test_load_balancer_remove_qos_policy(self, mock_attrs): def test_load_balancer_remove_qos_policy(self, mock_attrs):
mock_attrs.return_value = { mock_attrs.return_value = {
@ -658,3 +806,45 @@ class TestLoadBalancerUnset(TestLoadBalancer):
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.api_mock.load_balancer_set.assert_not_called() self.api_mock.load_balancer_set.assert_not_called()
def test_load_balancer_unset_tag(self):
self.api_mock.load_balancer_show.return_value = {
'tags': ['foo', 'bar']
}
arglist = [self._lb.id, '--tag', 'foo']
verifylist = [
('loadbalancer', self._lb.id),
('tags', ['foo'])
]
try:
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
except Exception as e:
self.fail("%s raised unexpectedly" % e)
self.api_mock.load_balancer_set.assert_called_once_with(
self._lb.id,
json={'loadbalancer': {'tags': ['bar']}})
def test_load_balancer_unset_all_tag(self):
self.api_mock.load_balancer_show.return_value = {
'tags': ['foo', 'bar']
}
arglist = [self._lb.id, '--all-tag']
verifylist = [
('loadbalancer', self._lb.id),
('all_tag', True)
]
try:
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
except Exception as e:
self.fail("%s raised unexpectedly" % e)
self.api_mock.load_balancer_set.assert_called_once_with(
self._lb.id,
json={'loadbalancer': {'tags': []}})

View File

@ -71,7 +71,78 @@ class TestListMember(TestMember):
columns, data = self.cmd.take_action(parsed_args) columns, data = self.cmd.take_action(parsed_args)
self.api_mock.member_list.assert_called_once_with(pool_id='pool_id') self.api_mock.member_list.assert_called_once_with(
pool_id='pool_id',
project_id=self._mem.project_id)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_member_list_with_tags(self):
arglist = [self._mem.pool_id,
'--tags', 'foo,bar']
verifylist = [('pool', self._mem.pool_id),
('tags', ['foo', 'bar'])]
expected_attrs = {
'pool_id': self._mem.pool_id,
'tags': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.member_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_member_list_with_any_tags(self):
arglist = [self._mem.pool_id,
'--any-tags', 'foo,bar']
verifylist = [('pool', self._mem.pool_id),
('any_tags', ['foo', 'bar'])]
expected_attrs = {
'pool_id': self._mem.pool_id,
'tags-any': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.member_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_member_list_with_not_tags(self):
arglist = [self._mem.pool_id,
'--not-tags', 'foo,bar']
verifylist = [('pool', self._mem.pool_id),
('not_tags', ['foo', 'bar'])]
expected_attrs = {
'pool_id': self._mem.pool_id,
'not-tags': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.member_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_member_list_with_not_any_tags(self):
arglist = [self._mem.pool_id,
'--not-any-tags', 'foo,bar']
verifylist = [('pool', self._mem.pool_id),
('not_any_tags', ['foo', 'bar'])]
expected_attrs = {
'pool_id': self._mem.pool_id,
'not-tags-any': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.member_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns) self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data)) self.assertEqual(self.datalist, tuple(data))
@ -151,6 +222,32 @@ class TestCreateMember(TestMember):
sleep_time=mock.ANY, sleep_time=mock.ANY,
status_field='provisioning_status') status_field='provisioning_status')
@mock.patch('octaviaclient.osc.v2.utils.get_member_attrs')
def test_member_create_with_tag(self, mock_attrs):
mock_attrs.return_value = {
'ip_address': '192.0.2.122',
'protocol_port': self._mem.protocol_port,
'pool_id': self._mem.pool_id,
'tags': ['foo']}
arglist = ['pool_id', '--address', '192.0.2.122',
'--protocol-port', '80',
'--tag', 'foo']
verifylist = [
('address', '192.0.2.122'),
('protocol_port', 80),
('tags', ['foo'])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.member_create.assert_called_with(
pool_id=self._mem.pool_id, json={
'member': {'ip_address': '192.0.2.122',
'protocol_port': self._mem.protocol_port,
'tags': ['foo']
}})
class TestMemberDelete(TestMember): class TestMemberDelete(TestMember):
@ -250,6 +347,56 @@ class TestMemberSet(TestMember):
sleep_time=mock.ANY, sleep_time=mock.ANY,
status_field='provisioning_status') status_field='provisioning_status')
@mock.patch('octaviaclient.osc.v2.utils.get_member_attrs')
def test_member_set_tag(self, mock_attrs):
self.api_mock.member_show.return_value = {
'tags': ['foo']
}
mock_attrs.return_value = {'pool_id': self._mem.pool_id,
'member_id': self._mem.id,
'tags': ['bar']}
arglist = [self._mem.pool_id, self._mem.id,
'--tag', 'bar']
verifylist = [
('pool', self._mem.pool_id),
('member', self._mem.id),
('tags', ['bar'])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.member_set.assert_called_once()
kwargs = self.api_mock.member_set.mock_calls[0][2]
tags = kwargs['json']['member']['tags']
self.assertEqual(2, len(tags))
self.assertIn('foo', tags)
self.assertIn('bar', tags)
@mock.patch('octaviaclient.osc.v2.utils.get_member_attrs')
def test_member_set_tag_no_tag(self, mock_attrs):
self.api_mock.member_show.return_value = {
'tags': ['foo']
}
mock_attrs.return_value = {'pool_id': self._mem.pool_id,
'member_id': self._mem.id,
'tags': ['bar']}
arglist = [self._mem.pool_id, self._mem.id,
'--tag', 'bar', '--no-tag']
verifylist = [
('pool', self._mem.pool_id),
('member', self._mem.id),
('tags', ['bar'])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.member_set.assert_called_once_with(
pool_id=self._mem.pool_id,
member_id=self._mem.id,
json={'member': {'tags': ['bar']}})
class TestMemberShow(TestMember): class TestMemberShow(TestMember):
@ -368,3 +515,51 @@ class TestMemberUnset(TestMember):
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.api_mock.member_set.assert_not_called() self.api_mock.member_set.assert_not_called()
@mock.patch('octaviaclient.osc.v2.utils.get_member_attrs')
def test_member_unset_tag(self, mock_attrs):
self.api_mock.member_show.return_value = {
'tags': ['foo', 'bar']
}
mock_attrs.return_value = {'pool_id': self._mem.pool_id,
'member_id': self._mem.id,
'tags': ['bar']}
arglist = [self._mem.pool_id, self._mem.id,
'--tag', 'bar']
verifylist = [
('pool', self._mem.pool_id),
('member', self._mem.id),
('tags', ['bar'])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.member_set.assert_called_once_with(
pool_id=self._mem.pool_id,
member_id=self._mem.id,
json={'member': {'tags': ['foo']}})
@mock.patch('octaviaclient.osc.v2.utils.get_member_attrs')
def test_member_unset_all_tags(self, mock_attrs):
self.api_mock.member_show.return_value = {
'tags': ['foo', 'bar']
}
mock_attrs.return_value = {'pool_id': self._mem.pool_id,
'member_id': self._mem.id,
'tags': ['foo', 'bar']}
arglist = [self._mem.pool_id, self._mem.id,
'--all-tag']
verifylist = [
('pool', self._mem.pool_id),
('member', self._mem.id),
('all_tag', True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.member_set.assert_called_once_with(
pool_id=self._mem.pool_id,
member_id=self._mem.id,
json={'member': {'tags': []}})

View File

@ -58,6 +58,62 @@ class TestPoolList(TestPool):
self.assertEqual(self.columns, columns) self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data)) self.assertEqual(self.datalist, tuple(data))
def test_pool_list_with_tags(self):
arglist = ['--tags', 'foo,bar']
verifylist = [('tags', ['foo', 'bar'])]
expected_attrs = {
'tags': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.pool_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_pool_list_with_any_tags(self):
arglist = ['--any-tags', 'foo,bar']
verifylist = [('any_tags', ['foo', 'bar'])]
expected_attrs = {
'tags-any': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.pool_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_pool_list_with_not_tags(self):
arglist = ['--not-tags', 'foo,bar']
verifylist = [('not_tags', ['foo', 'bar'])]
expected_attrs = {
'not-tags': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.pool_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_pool_list_with_not_any_tags(self):
arglist = ['--not-any-tags', 'foo,bar']
verifylist = [('not_any_tags', ['foo', 'bar'])]
expected_attrs = {
'not-tags-any': ['foo', 'bar']
}
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.pool_list.assert_called_with(**expected_attrs)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
class TestPoolDelete(TestPool): class TestPoolDelete(TestPool):
@ -149,6 +205,28 @@ class TestPoolCreate(TestPool):
self.api_mock.pool_create.assert_called_with( self.api_mock.pool_create.assert_called_with(
json={'pool': self.pool_info}) json={'pool': self.pool_info})
@mock.patch('octaviaclient.osc.v2.utils.get_pool_attrs')
def test_pool_create_with_tag(self, mock_attrs):
mock_attrs.return_value = self.pool_info
arglist = ['--loadbalancer', 'mock_lb_id',
'--name', self._po.name,
'--protocol', 'HTTP',
'--lb-algorithm', 'ROUND_ROBIN',
'--tag', 'foo']
verifylist = [
('loadbalancer', 'mock_lb_id'),
('name', self._po.name),
('protocol', 'HTTP'),
('lb_algorithm', 'ROUND_ROBIN'),
('tags', ['foo'])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.pool_create.assert_called_with(
json={'pool': self.pool_info})
@mock.patch('osc_lib.utils.wait_for_status') @mock.patch('osc_lib.utils.wait_for_status')
@mock.patch('octaviaclient.osc.v2.utils.get_pool_attrs') @mock.patch('octaviaclient.osc.v2.utils.get_pool_attrs')
def test_pool_create_wait(self, mock_attrs, mock_wait): def test_pool_create_wait(self, mock_attrs, mock_wait):
@ -253,6 +331,43 @@ class TestPoolSet(TestPool):
sleep_time=mock.ANY, sleep_time=mock.ANY,
status_field='provisioning_status') status_field='provisioning_status')
def test_pool_set_tag(self):
self.api_mock.pool_show.return_value = {
'tags': ['foo']
}
arglist = [self._po.id, '--tag', 'bar']
verifylist = [
('pool', self._po.id),
('tags', ['bar']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.pool_set.assert_called_once()
kwargs = self.api_mock.pool_set.mock_calls[0][2]
tags = kwargs['json']['pool']['tags']
self.assertEqual(2, len(tags))
self.assertIn('foo', tags)
self.assertIn('bar', tags)
def test_pool_set_tag_no_tag(self):
self.api_mock.pool_show.return_value = {
'tags': ['foo']
}
arglist = [self._po.id, '--tag', 'bar', '--no-tag']
verifylist = [
('pool', self._po.id),
('tags', ['bar']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.pool_set.assert_called_once_with(
self._po.id,
json={"pool": {"tags": ["bar"]}})
class TestPoolUnset(TestPool): class TestPoolUnset(TestPool):
PARAMETERS = ('name', 'description', 'ca_tls_container_ref', PARAMETERS = ('name', 'description', 'ca_tls_container_ref',
@ -350,3 +465,41 @@ class TestPoolUnset(TestPool):
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.api_mock.pool_set.assert_not_called() self.api_mock.pool_set.assert_not_called()
def test_pool_unset_tag(self):
self.api_mock.pool_set.reset_mock()
self.api_mock.pool_show.return_value = {
'tags': ['foo', 'bar']
}
arglist = [self._po.id, '--tag', 'foo']
verifylist = [
('pool', self._po.id),
('tags', ['foo']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.pool_set.assert_called_once_with(
self._po.id,
json={"pool": {"tags": ["bar"]}})
def test_pool_unset_all_tag(self):
self.api_mock.pool_set.reset_mock()
self.api_mock.pool_show.return_value = {
'tags': ['foo', 'bar']
}
arglist = [self._po.id, '--all-tag']
verifylist = [
('pool', self._po.id),
('all_tag', True),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.pool_set.assert_called_once_with(
self._po.id,
json={"pool": {"tags": []}})

View File

@ -0,0 +1,12 @@
---
features:
- |
Add support for tags for Octavia resources. Tags are supported with load
balancers, listeners, pools, members, health monitors, l7policies and
l7rules.
Tags can be added when creating a resource, and they can be set and unset.
Tags allow also to filter elements when listing Octavia resources.
fixes:
- |
Fix errors when combining set/unset CLI for l7rule resources and the --wait
option.