Browse Source

Complement Octavia client with a set of features

* Commands added: loadbalancer failover, loadbalancer amphora.
* Allow to filter 'list' calls.
e.g. list all pools that correspond with a given loadbalancer ID.
* Rename API internally, from load_balancer_v2 to Octavia.

Task: 5742
Story: 2001224

Change-Id: I7c38471073d8990de054def3d1d99f2c0524c26e
changes/66/522666/18 1.3.0
Bar RH 4 years ago
committed by Michael Johnson
parent
commit
922edce32a
25 changed files with 700 additions and 175 deletions
  1. +10
    -0
      doc/source/cli/osc/v2/load-balancer.rst
  2. +13
    -6
      octaviaclient/api/constants.py
  3. +0
    -0
      octaviaclient/api/v2/__init__.py
  4. +53
    -12
      octaviaclient/api/v2/octavia.py
  5. +3
    -3
      octaviaclient/osc/plugin.py
  6. +117
    -0
      octaviaclient/osc/v2/amphora.py
  7. +32
    -3
      octaviaclient/osc/v2/constants.py
  8. +8
    -2
      octaviaclient/osc/v2/listener.py
  9. +23
    -0
      octaviaclient/osc/v2/load_balancer.py
  10. +8
    -2
      octaviaclient/osc/v2/pool.py
  11. +61
    -32
      octaviaclient/osc/v2/utils.py
  12. +115
    -92
      octaviaclient/tests/unit/api/test_octavia.py
  13. +42
    -8
      octaviaclient/tests/unit/osc/v2/fakes.py
  14. +175
    -0
      octaviaclient/tests/unit/osc/v2/test_amphora.py
  15. +1
    -1
      octaviaclient/tests/unit/osc/v2/test_health_monitor.py
  16. +1
    -1
      octaviaclient/tests/unit/osc/v2/test_l7policy.py
  17. +1
    -1
      octaviaclient/tests/unit/osc/v2/test_l7rule.py
  18. +1
    -1
      octaviaclient/tests/unit/osc/v2/test_listener.py
  19. +19
    -1
      octaviaclient/tests/unit/osc/v2/test_load_balancer.py
  20. +3
    -3
      octaviaclient/tests/unit/osc/v2/test_member.py
  21. +1
    -1
      octaviaclient/tests/unit/osc/v2/test_pool.py
  22. +1
    -1
      octaviaclient/tests/unit/osc/v2/test_quota.py
  23. +4
    -5
      octaviaclient/tests/utils.py
  24. +5
    -0
      releasenotes/notes/add-new-commands-and-options-d520b36d870cbcb4.yaml
  25. +3
    -0
      setup.cfg

+ 10
- 0
doc/source/cli/osc/v2/load-balancer.rst View File

@ -26,6 +26,9 @@ loadbalancer
.. autoprogram-cliff:: openstack.load_balancer.v2
:command: loadbalancer stats show
.. autoprogram-cliff:: openstack.load_balancer.v2
:command: loadbalancer failover
========
listener
========
@ -74,3 +77,10 @@ quota
.. autoprogram-cliff:: openstack.load_balancer.v2
:command: loadbalancer quota *
=======
amphora
=======
.. autoprogram-cliff:: openstack.load_balancer.v2
:command: loadbalancer amphora *

+ 13
- 6
octaviaclient/api/constants.py View File

@ -11,27 +11,34 @@
# under the License.
#
BASE_LOADBALANCER_URL = '/loadbalancers'
BASE_LBAAS_ENDPOINT = '/lbaas'
BASE_OCTAVIA_ENDPOINT = '/octavia'
BASE_LOADBALANCER_URL = BASE_LBAAS_ENDPOINT + '/loadbalancers'
BASE_SINGLE_LB_URL = BASE_LOADBALANCER_URL + '/{uuid}'
BASE_LB_STATS_URL = BASE_SINGLE_LB_URL + '/stats'
BASE_LOADBALANCER_FAILOVER_URL = BASE_SINGLE_LB_URL + '/failover'
BASE_LISTENER_URL = '/listeners'
BASE_LISTENER_URL = BASE_LBAAS_ENDPOINT + '/listeners'
BASE_SINGLE_LISTENER_URL = BASE_LISTENER_URL + '/{uuid}'
BASE_POOL_URL = '/pools'
BASE_POOL_URL = BASE_LBAAS_ENDPOINT + '/pools'
BASE_SINGLE_POOL_URL = BASE_POOL_URL + '/{pool_id}'
BASE_MEMBER_URL = BASE_SINGLE_POOL_URL + '/members'
BASE_SINGLE_MEMBER_URL = BASE_MEMBER_URL + '/{member_id}'
BASE_HEALTH_MONITOR_URL = '/healthmonitors'
BASE_HEALTH_MONITOR_URL = BASE_LBAAS_ENDPOINT + '/healthmonitors'
BASE_SINGLE_HEALTH_MONITOR_URL = BASE_HEALTH_MONITOR_URL + '/{uuid}'
BASE_L7POLICY_URL = '/l7policies'
BASE_L7POLICY_URL = BASE_LBAAS_ENDPOINT + '/l7policies'
BASE_SINGLE_L7POLICY_URL = BASE_L7POLICY_URL + '/{policy_uuid}'
BASE_L7RULE_URL = BASE_SINGLE_L7POLICY_URL + '/rules'
BASE_SINGLE_L7RULE_URL = BASE_SINGLE_L7POLICY_URL + '/rules/{rule_uuid}'
BASE_QUOTA_URL = '/quotas'
BASE_QUOTA_URL = BASE_LBAAS_ENDPOINT + '/quotas'
BASE_SINGLE_QUOTA_URL = BASE_QUOTA_URL + '/{uuid}'
BASE_QUOTA_DEFAULT_URL = BASE_QUOTA_URL + '/defaults'
BASE_AMPHORA_URL = BASE_OCTAVIA_ENDPOINT + "/amphorae"
BASE_SINGLE_AMPHORA_URL = BASE_AMPHORA_URL + "/{amphora_id}"

+ 0
- 0
octaviaclient/api/v2/__init__.py View File


octaviaclient/api/load_balancer_v2.py → octaviaclient/api/v2/octavia.py View File


+ 3
- 3
octaviaclient/osc/plugin.py View File

@ -14,7 +14,7 @@
import logging
from octaviaclient.api import load_balancer_v2
from octaviaclient.api.v2 import octavia
from osc_lib import utils
LOG = logging.getLogger(__name__)
@ -24,7 +24,7 @@ API_VERSION_OPTION = 'os_loadbalancer_api_version'
API_NAME = 'load_balancer'
LOAD_BALANCER_API_TYPE = 'loadbalancer'
LOAD_BALANCER_API_VERSIONS = {
'2.0': 'octaviaclient.api.load_balancer_v2.APIv2',
'2.0': 'octaviaclient.api.v2.octavia.OctaviaAPI',
}
@ -35,7 +35,7 @@ def make_client(instance):
region_name=instance.region_name,
interface=instance.interface,
)
client = load_balancer_v2.APIv2(
client = octavia.OctaviaAPI(
session=instance.session,
service_type='load-balancer',
endpoint=endpoint,


+ 117
- 0
octaviaclient/osc/v2/amphora.py View File

@ -0,0 +1,117 @@
# 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.
#
"""Amphora action implementation"""
from cliff import lister
from osc_lib.command import command
from osc_lib import utils
from octaviaclient.osc.v2 import constants as const
from octaviaclient.osc.v2 import utils as v2_utils
class ListAmphora(lister.Lister):
"""List amphorae"""
def get_parser(self, prog_name):
parser = super(ListAmphora, self).get_parser(prog_name)
parser.add_argument(
'--loadbalancer',
metavar='<loadbalancer>',
dest='loadbalancer',
help="Filter by load balancer (name or ID).",
)
parser.add_argument(
'--compute-id',
metavar='<compute-id>',
help="Filter by compute ID.",
)
role_choices = {'MASTER', 'BACKUP', 'STANDALONE'}
parser.add_argument(
'--role',
metavar='{' + ','.join(role_choices) + '}',
choices=role_choices,
type=lambda s: s.upper(), # case insensitive
help="Filter by role."
)
status_choices = {
'ALLOCATED', 'BOOTING', 'DELETED', 'ERROR',
'PENDING_CREATE', 'PENDING_DELETE', 'READY',
}
parser.add_argument(
'--status', '--provisioning-status',
dest='status',
metavar='{' + ','.join(status_choices) + '}',
choices=status_choices,
type=lambda s: s.upper(), # case insensitive
help="Filter by amphora provisioning status."
)
return parser
def take_action(self, parsed_args):
columns = const.AMPHORA_COLUMNS
attrs = v2_utils.get_amphora_attrs(self.app.client_manager,
parsed_args)
data = self.app.client_manager.load_balancer.amphora_list(**attrs)
formatters = {
'amphorae': v2_utils.format_list,
}
return (
columns,
(utils.get_dict_properties(
amp,
columns,
formatters=formatters,
) for amp in data['amphorae']),
)
class ShowAmphora(command.ShowOne):
"""Show the details of a single amphora"""
def get_parser(self, prog_name):
parser = super(ShowAmphora, self).get_parser(prog_name)
parser.add_argument(
'amphora_id',
metavar='<amphora-id>',
help='UUID of the amphora.',
)
return parser
def take_action(self, parsed_args):
attrs = v2_utils.get_amphora_attrs(self.app.client_manager,
parsed_args)
data = self.app.client_manager.load_balancer.amphora_show(
amphora_id=attrs.pop('amphora_id'),
)
rows = const.AMPHORA_ROWS
formatters = {
'loadbalancers': v2_utils.format_list,
'amphorae': v2_utils.format_list,
}
return (rows, utils.get_dict_properties(data, rows,
formatters=formatters))

+ 32
- 3
octaviaclient/osc/v2/constants.py View File

@ -29,7 +29,8 @@ LOAD_BALANCER_ROWS = (
'vip_address',
'vip_network_id',
'vip_port_id',
'vip_subnet_id')
'vip_subnet_id',
)
LOAD_BALANCER_COLUMNS = (
'id',
@ -212,7 +213,7 @@ QUOTA_ROWS = (
'listener',
'pool',
'health_monitor',
'member'
'member',
)
QUOTA_COLUMNS = (
@ -221,5 +222,33 @@ QUOTA_COLUMNS = (
'listener',
'pool',
'health_monitor',
'member'
'member',
)
AMPHORA_ROWS = (
'id',
'loadbalancer_id',
'compute_id',
'lb_network_ip',
'vrrp_ip',
'ha_ip',
'vrrp_port_id',
'ha_port_id',
'cert_expiration',
'cert_busy',
'role',
'status',
'vrrp_interface',
'vrrp_id',
'vrrp_priority',
'cached_zone',
)
AMPHORA_COLUMNS = (
'id',
'loadbalancer_id',
'status',
'role',
'lb_network_ip',
'ha_ip',
)

+ 8
- 2
octaviaclient/osc/v2/listener.py View File

@ -31,7 +31,7 @@ class CreateListener(command.ShowOne):
parser.add_argument(
'loadbalancer',
metavar='<load_balancer>',
metavar='<loadbalancer>',
help="Load balancer for the listener (name or ID)."
)
parser.add_argument(
@ -155,12 +155,17 @@ class ListListener(lister.Lister):
def get_parser(self, prog_name):
parser = super(ListListener, self).get_parser(prog_name)
# Filtering will soon be implemented to allow this
parser.add_argument(
'--name',
metavar='<name>',
help="List listeners by listener name."
)
parser.add_argument(
'--loadbalancer',
metavar='<loadbalancer>',
help="Filter by load balancer (name or ID).",
)
admin_group = parser.add_mutually_exclusive_group()
admin_group.add_argument(
'--enable',
@ -174,6 +179,7 @@ class ListListener(lister.Lister):
default=None,
help="List disabled listeners."
)
parser.add_argument(
'--project',
metavar='<project>',


+ 23
- 0
octaviaclient/osc/v2/load_balancer.py View File

@ -81,6 +81,7 @@ class CreateLoadBalancer(command.ShowOne):
metavar='<project>',
help="Project for the load balancer (name or ID)."
)
admin_group = parser.add_mutually_exclusive_group()
admin_group.add_argument(
'--enable',
@ -148,6 +149,27 @@ class DeleteLoadBalancer(command.Command):
lb_id=lb_id, **attrs)
class FailoverLoadBalancer(command.Command):
"""Trigger load balancer failover"""
def get_parser(self, prog_name):
parser = super(FailoverLoadBalancer, self).get_parser(prog_name)
parser.add_argument(
'loadbalancer',
metavar='<load_balancer>',
help="Name or UUID of the load balancer."
)
return parser
def take_action(self, parsed_args):
attrs = v2_utils.get_loadbalancer_attrs(self.app.client_manager,
parsed_args)
self.app.client_manager.load_balancer.load_balancer_failover(
lb_id=attrs.pop('loadbalancer_id'))
class ListLoadBalancer(lister.Lister):
"""List load balancers"""
@ -250,6 +272,7 @@ class SetLoadBalancer(command.Command):
metavar='<description>',
help="Set load balancer description."
)
admin_group = parser.add_mutually_exclusive_group()
admin_group.add_argument(
'--enable',


+ 8
- 2
octaviaclient/osc/v2/pool.py View File

@ -127,12 +127,18 @@ class ListPool(lister.Lister):
def get_parser(self, prog_name):
parser = super(ListPool, self).get_parser(prog_name)
parser.add_argument(
'--loadbalancer',
metavar='<loadbalancer>',
help="Filter by load balancer (name or ID).",
)
return parser
def take_action(self, parsed_args):
columns = const.POOL_COLUMNS
data = self.app.client_manager.load_balancer.pool_list()
attrs = v2_utils.get_pool_attrs(self.app.client_manager, parsed_args)
data = self.app.client_manager.load_balancer.pool_list(**attrs)
formatters = {'loadbalancers': v2_utils.format_list,
'members': v2_utils.format_list,
'listeners': v2_utils.format_list}


+ 61
- 32
octaviaclient/osc/v2/utils.py View File

@ -17,6 +17,47 @@ from osc_lib import exceptions
from openstackclient.identity import common as identity_common
def _map_attrs(args, source_attr_map):
res = {}
for k, v in args.items():
if (v is None) or (k not in source_attr_map):
continue
source_val = source_attr_map[k]
# Attributes with 2 values map directly to a callable
if len(source_val) == 2:
res[source_val[0]] = source_val[1](v)
# Attributes with 3 values map directly to a resource
elif len(source_val) == 3:
if not isinstance(v, list):
res[source_val[0]] = get_resource_id(
source_val[2],
source_val[1],
v,
)
else:
res[source_val[0]] = [get_resource_id(
source_val[2],
source_val[1],
x,
) for x in v]
# Attributes with 4 values map to a resource with a parent
elif len(source_val) == 4:
parent = source_attr_map[source_val[2]]
parent_id = get_resource_id(
parent[2],
parent[1],
args[source_val[2]],
)
child = source_val
res[child[0]] = get_resource_id(
child[3],
child[1],
{child[0]: str(v), parent[0]: str(parent_id)},
)
return res
def get_resource_id(resource, resource_name, name):
"""Converts a resource name into a UUID for consumption for the API
@ -359,6 +400,26 @@ def get_quota_attrs(client_manager, parsed_args):
return attrs
def get_amphora_attrs(client_manager, parsed_args):
attr_map = {
'amphora_id': (
'amphora_id',
'amphorae',
client_manager.load_balancer.amphora_list,
),
'loadbalancer': (
'loadbalancer_id',
'loadbalancers',
client_manager.load_balancer.load_balancer_list,
),
'compute_id': ('compute_id', str),
'role': ('role', str),
'status': ('status', str),
}
return _map_attrs(vars(parsed_args), attr_map)
def format_list(data):
return '\n'.join(i['id'] for i in data)
@ -378,35 +439,3 @@ def _format_kv(data):
formatted_kv[k] = v
return formatted_kv
def _map_attrs(attrs, attr_map):
mapped_attrs = {}
for k, v in attrs.items():
if v is not None and k in attr_map.keys():
# Attributes with 2 values map directly to a callable
if len(attr_map[k]) is 2:
mapped_attrs[attr_map[k][0]] = attr_map[k][1](v)
# Attributes with 3 values map directly to a resource
elif len(attr_map[k]) is 3:
mapped_attrs[attr_map[k][0]] = get_resource_id(
attr_map[k][2],
attr_map[k][1],
v
)
# Attributes with 4 values map to a resource with a parent
else:
parent = attr_map[attr_map[k][2]]
parent_id = get_resource_id(
parent[2],
parent[1],
attrs[attr_map[k][2]]
)
child = attr_map[k]
mapped_attrs[child[0]] = get_resource_id(
child[3],
child[1],
{child[0]: str(v), parent[0]: str(parent_id)}
)
return mapped_attrs

octaviaclient/tests/unit/api/test_load_balancer.py → octaviaclient/tests/unit/api/test_octavia.py View File


+ 42
- 8
octaviaclient/tests/unit/osc/v2/fakes.py View File

@ -28,7 +28,7 @@ LOADBALANCER = {
}
class FakeLoadBalancerv2Client(object):
class FakeOctaviaClient(object):
def __init__(self, **kwargs):
self.load_balancers = mock.Mock()
self.load_balancers.resource_class = fakes.FakeResource(None, {})
@ -36,11 +36,11 @@ class FakeLoadBalancerv2Client(object):
self.management_url = kwargs['endpoint']
class TestLoadBalancerv2(utils.TestCommand):
class TestOctaviaClient(utils.TestCommand):
def setUp(self):
super(TestLoadBalancerv2, self).setUp()
self.app.client_manager.load_balancer = FakeLoadBalancerv2Client(
super(TestOctaviaClient, self).setUp()
self.app.client_manager.load_balancer = FakeOctaviaClient(
endpoint=fakes.AUTH_URL,
token=fakes.AUTH_TOKEN,
)
@ -112,7 +112,7 @@ class FakeListener(object):
class FakePool(object):
"""Fake one or more pool."""
"""Fake one or more pools."""
@staticmethod
def create_one_pool(attrs=None):
@ -142,6 +142,7 @@ class FakePool(object):
class FakeMember(object):
"""Fake one or more members."""
@staticmethod
def create_member(attrs=None):
@ -170,7 +171,7 @@ class FakeMember(object):
class FakeL7Policy(object):
"""Fake one or more L7policy."""
"""Fake one or more L7policies."""
@staticmethod
def create_one_l7policy(attrs=None):
@ -199,7 +200,7 @@ class FakeL7Policy(object):
class FakeL7Rule(object):
"""Fake one or more L7policy."""
"""Fake one or more L7rules."""
@staticmethod
def create_one_l7rule(attrs=None):
@ -229,7 +230,7 @@ class FakeL7Rule(object):
class FakeHM(object):
"""Fake one or more L7policy."""
"""Fake one or more health monitors."""
@staticmethod
def create_one_health_monitor(attrs=None):
@ -289,3 +290,36 @@ class FakeQT(object):
loaded=True)
return qt
class FakeAmphora(object):
"""Fake one or more amphorae."""
@staticmethod
def create_one_amphora(attrs=None):
attrs = attrs or {}
amphora = {
"id": uuidutils.generate_uuid(dashed=True),
"loadbalancer_id": uuidutils.generate_uuid(dashed=True),
"compute_id": uuidutils.generate_uuid(dashed=True),
"lb_network_ip": "192.168.1.3",
"vrrp_ip": "192.168.1.6",
"ha_ip": "192.168.1.10",
"vrrp_port_id": uuidutils.generate_uuid(dashed=True),
"ha_port_id": uuidutils.generate_uuid(dashed=True),
"cert_expiration": "2019-09-19 00:34:51",
"cert_busy": 0,
"role": "BACKUP",
"status": "ALLOCATED",
"vrrp_interface": "eth1",
"vrrp_id": 1,
"vrrp_priority": 200,
"cached_zone": "zone2",
}
amphora.update(attrs)
return fakes.FakeResource(
info=copy.deepcopy(amphora),
loaded=True)

+ 175
- 0
octaviaclient/tests/unit/osc/v2/test_amphora.py View File

@ -0,0 +1,175 @@
# 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.
#
import copy
import mock
import osc_lib.tests.utils as osc_test_utils
from octaviaclient.osc.v2 import amphora
from octaviaclient.osc.v2 import constants
from octaviaclient.tests.unit.osc.v2 import fakes as amp_fakes
AUTH_TOKEN = "foobar"
AUTH_URL = "http://192.0.2.2"
class TestAmphora(amp_fakes.TestOctaviaClient):
_amp = amp_fakes.FakeAmphora.create_one_amphora()
columns = constants.AMPHORA_COLUMNS
rows = constants.AMPHORA_ROWS
data_show = (
(
_amp.id,
_amp.loadbalancer_id,
_amp.compute_id,
_amp.lb_network_ip,
_amp.vrrp_ip,
_amp.ha_ip,
_amp.vrrp_port_id,
_amp.ha_port_id,
_amp.cert_expiration,
_amp.cert_busy,
_amp.role,
_amp.status,
_amp.vrrp_interface,
_amp.vrrp_id,
_amp.vrrp_priority,
_amp.cached_zone,
),
)
info_show = {
'id': _amp.id,
'loadbalancer_id': _amp.loadbalancer_id,
'compute_id': _amp.compute_id,
'lb_network_ip': _amp.lb_network_ip,
'vrrp_ip': _amp.vrrp_ip,
'ha_ip': _amp.ha_ip,
'vrrp_port_id': _amp.vrrp_port_id,
'ha_port_id': _amp.ha_port_id,
'cert_expiration': _amp.cert_expiration,
'cert_busy': _amp.cert_busy,
'role': _amp.role,
'status': _amp.status,
'vrrp_interface': _amp.vrrp_interface,
'vrrp_id': _amp.vrrp_id,
'vrrp_priority': _amp.vrrp_priority,
'cached_zone': _amp.cached_zone,
}
data_list = (
(
_amp.id,
_amp.loadbalancer_id,
_amp.status,
_amp.role,
_amp.lb_network_ip,
_amp.ha_ip,
),
)
info_list = {
'amphorae':
[{
'id': _amp.id,
'loadbalancer_id': _amp.loadbalancer_id,
'status': _amp.status,
'role': _amp.role,
'lb_network_ip': _amp.lb_network_ip,
'ha_ip': _amp.ha_ip,
}],
}
amp_info = copy.deepcopy(info_list)
def setUp(self):
super(TestAmphora, self).setUp()
self.api_mock = mock.Mock()
self.api_mock.amphora_list.return_value = self.amp_info
self.api_mock.amphora_show.return_value = {
"amphora": self.amp_info['amphorae'][0],
}
lb_client = self.app.client_manager
lb_client.load_balancer = self.api_mock
class TestAmphoraList(TestAmphora):
def setUp(self):
super(TestAmphoraList, self).setUp()
self.cmd = amphora.ListAmphora(self.app, None)
def test_amphora_list_no_options(self):
arglist = []
verify_list = []
parsed_args = self.check_parser(self.cmd, arglist, verify_list)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.amphora_list.assert_called_with()
self.assertEqual(self.columns, columns)
self.assertEqual(self.data_list, tuple(data))
@mock.patch('octaviaclient.osc.v2.utils.get_amphora_attrs')
def test_amphora_list_with_loadbalancer(self, mock_client):
mock_client.return_value = {
'loadbalancer_id': self._amp.loadbalancer_id,
'compute_id': self._amp.compute_id,
'role': self._amp.role,
'status': self._amp.status,
}
arglist = [
'--loadbalancer', self._amp.loadbalancer_id,
'--compute-id', self._amp.compute_id,
'--role', 'Master',
'--status', 'allocAted',
]
verify_list = [
('loadbalancer', self._amp.loadbalancer_id),
('compute_id', self._amp.compute_id),
('role', 'MASTER'),
('status', 'ALLOCATED'),
]
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.data_list, tuple(data))
class TestAmphoraShow(TestAmphora):
def setUp(self):
super(TestAmphoraShow, self).setUp()
self.cmd = amphora.ShowAmphora(self.app, None)
def test_amphora_show_no_args(self):
self.assertRaises(
osc_test_utils.ParserException,
self.check_parser, self.cmd, [], [],
)
@mock.patch('octaviaclient.osc.v2.utils.get_amphora_attrs')
def test_amphora_show(self, mock_client):
mock_client.return_value = {'amphora_id': self._amp.id}
arglist = [self._amp.id]
verify_list = [('amphora_id', self._amp.id)]
parsed_args = self.check_parser(self.cmd, arglist, verify_list)
rows, data = self.cmd.take_action(parsed_args)
self.assertEqual(self.rows, rows)
self.api_mock.amphora_show.assert_called_with(amphora_id=self._amp.id)

+ 1
- 1
octaviaclient/tests/unit/osc/v2/test_health_monitor.py View File

@ -23,7 +23,7 @@ AUTH_TOKEN = "foobar"
AUTH_URL = "http://192.0.2.2"
class TestHealthMonitor(hm_fakes.TestLoadBalancerv2):
class TestHealthMonitor(hm_fakes.TestOctaviaClient):
_hm = hm_fakes.FakeHM.create_one_health_monitor()


+ 1
- 1
octaviaclient/tests/unit/osc/v2/test_l7policy.py View File

@ -23,7 +23,7 @@ AUTH_TOKEN = "foobar"
AUTH_URL = "http://192.0.2.2"
class TestL7Policy(po_fakes.TestLoadBalancerv2):
class TestL7Policy(po_fakes.TestOctaviaClient):
_l7po = po_fakes.FakeL7Policy.create_one_l7policy()


+ 1
- 1
octaviaclient/tests/unit/osc/v2/test_l7rule.py View File

@ -21,7 +21,7 @@ AUTH_TOKEN = "foobar"
AUTH_URL = "http://192.0.2.2"
class TestL7Policy(ru_fakes.TestLoadBalancerv2):
class TestL7Policy(ru_fakes.TestOctaviaClient):
_l7ru = ru_fakes.FakeL7Rule.create_one_l7rule()
_l7po = ru_fakes.FakeL7Policy.create_one_l7policy()


+ 1
- 1
octaviaclient/tests/unit/osc/v2/test_listener.py View File

@ -23,7 +23,7 @@ AUTH_TOKEN = "foobar"
AUTH_URL = "http://192.0.2.2"
class TestListener(li_fakes.TestLoadBalancerv2):
class TestListener(li_fakes.TestOctaviaClient):
_li = li_fakes.FakeListener.create_one_listener()


+ 19
- 1
octaviaclient/tests/unit/osc/v2/test_load_balancer.py View File

@ -24,7 +24,7 @@ AUTH_TOKEN = "foobar"
AUTH_URL = "http://192.0.2.2"
class TestLoadBalancer(lb_fakes.TestLoadBalancerv2):
class TestLoadBalancer(lb_fakes.TestOctaviaClient):
_lb = lb_fakes.FakeLoadBalancer.create_one_load_balancer()
@ -257,3 +257,21 @@ class TestLoadBalancerStats(TestLoadBalancer):
self.cmd.take_action(parsed_args)
self.api_mock.load_balancer_stats_show.assert_called_with(
lb_id=self._lb.id)
class TestLoadBalancerFailover(TestLoadBalancer):
def setUp(self):
super(TestLoadBalancerFailover, self).setUp()
self.cmd = load_balancer.FailoverLoadBalancer(self.app, None)
def test_load_balancer_failover(self):
arglist = [self._lb.id]
verifylist = [
('loadbalancer', self._lb.id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.load_balancer_failover.assert_called_with(
lb_id=self._lb.id)

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

@ -17,10 +17,10 @@ import mock
from octaviaclient.osc.v2 import member
from octaviaclient.tests.unit.osc.v2 import fakes as mem_fakes
from osc_lib.tests.utils import ParserException
import osc_lib.tests.utils as osc_test_utils
class TestMember(mem_fakes.TestLoadBalancerv2):
class TestMember(mem_fakes.TestOctaviaClient):
mem = mem_fakes.FakeMember.create_member()
@ -84,7 +84,7 @@ class TestListMember(TestMember):
arglist = []
verifylist = []
self.assertRaises(ParserException,
self.assertRaises(osc_test_utils.ParserException,
self.check_parser, self.cmd, arglist, verifylist)
@mock.patch('octaviaclient.osc.v2.utils.get_member_attrs')


+ 1
- 1
octaviaclient/tests/unit/osc/v2/test_pool.py View File

@ -23,7 +23,7 @@ AUTH_TOKEN = "foobar"
AUTH_URL = "http://192.0.2.2"
class TestPool(po_fakes.TestLoadBalancerv2):
class TestPool(po_fakes.TestOctaviaClient):
_po = po_fakes.FakePool.create_one_pool()


+ 1
- 1
octaviaclient/tests/unit/osc/v2/test_quota.py View File

@ -23,7 +23,7 @@ AUTH_TOKEN = "foobar"
AUTH_URL = "http://192.0.2.2"
class TestQuota(qt_fakes.TestLoadBalancerv2):
class TestQuota(qt_fakes.TestOctaviaClient):
_qt = qt_fakes.FakeQT.create_one_quota()


+ 4
- 5
octaviaclient/tests/utils.py View File

@ -19,10 +19,7 @@ import os
import testtools
from octaviaclient.tests import fakes
class ParserException(Exception):
pass
import osc_lib.tests.utils as osc_test_utils
class TestCase(testtools.TestCase):
@ -65,8 +62,10 @@ class TestCommand(TestCase):
cmd_parser = cmd.get_parser('check_parser')
try:
parsed_args = cmd_parser.parse_args(args)
except osc_test_utils.ParserException:
raise
except SystemExit:
raise ParserException("Argument parse failed")
raise osc_test_utils.ParserException("Argument parse failed")
for av in verify_args:
attr, value = av
if attr:


+ 5
- 0
releasenotes/notes/add-new-commands-and-options-d520b36d870cbcb4.yaml View File

@ -0,0 +1,5 @@
---
features:
- Loadbalancer failover command, which allows to trigger failover protocol.
- Amphora commands, to query amphorae by ID or by loadbalancer ID, etc.
- Filter 'list' calls by loadbalancer ID, for both listeners and pools.

+ 3
- 0
setup.cfg View File

@ -33,6 +33,7 @@ openstack.load_balancer.v2 =
loadbalancer_delete = octaviaclient.osc.v2.load_balancer:DeleteLoadBalancer
loadbalancer_set = octaviaclient.osc.v2.load_balancer:SetLoadBalancer
loadbalancer_stats_show = octaviaclient.osc.v2.load_balancer:ShowLoadBalancerStats
loadbalancer_failover = octaviaclient.osc.v2.load_balancer:FailoverLoadBalancer
loadbalancer_listener_create = octaviaclient.osc.v2.listener:CreateListener
loadbalancer_listener_list = octaviaclient.osc.v2.listener:ListListener
loadbalancer_listener_show = octaviaclient.osc.v2.listener:ShowListener
@ -68,6 +69,8 @@ openstack.load_balancer.v2 =
loadbalancer_quota_defaults_show = octaviaclient.osc.v2.quota:ShowQuotaDefaults
loadbalancer_quota_reset = octaviaclient.osc.v2.quota:ResetQuota
loadbalancer_quota_set = octaviaclient.osc.v2.quota:SetQuota
loadbalancer_amphora_list = octaviaclient.osc.v2.amphora:ListAmphora
loadbalancer_amphora_show = octaviaclient.osc.v2.amphora:ShowAmphora
[build_sphinx]
source-dir = doc/source


Loading…
Cancel
Save