Add amphora update service client and API test

This patch adds a service client for the amphora agent configuration update
API and adds an API test for the amphora configuration update API.

It also adds the service client for amphora failover and cleans up some
client credintials in the amphora scenario tests.

Change-Id: I4b1a1f48d2f619b883619811539ddb262d6b5f45
This commit is contained in:
Michael Johnson 2019-01-25 15:42:13 -08:00
parent 2734ffe0ea
commit 2b10e0a447
4 changed files with 176 additions and 8 deletions

View File

@ -157,3 +157,73 @@ class AmphoraClient(base_client.BaseLBaaSClient):
return jsonutils.loads(body.decode('utf-8'))[self.stats_root_tag]
else:
return jsonutils.loads(body.decode('utf-8'))
def update_amphora_config(self, amphora_id):
"""Update the amphora agent configuration.
:param amphora_id: The ID of the amphora to update.
:raises AssertionError: if the expected_code isn't a valid http success
response code
:raises BadRequest: If a 400 response code is received
:raises Conflict: If a 409 response code is received
:raises Forbidden: If a 403 response code is received
:raises Gone: If a 410 response code is received
:raises InvalidContentType: If a 415 response code is received
:raises InvalidHTTPResponseBody: The response body wasn't valid JSON
:raises InvalidHttpSuccessCode: if the read code isn't an expected
http success code
:raises NotFound: If a 404 response code is received
:raises NotImplemented: If a 501 response code is received
:raises OverLimit: If a 413 response code is received and over_limit is
not in the response body
:raises RateLimitExceeded: If a 413 response code is received and
over_limit is in the response body
:raises ServerFault: If a 500 response code is received
:raises Unauthorized: If a 401 response code is received
:raises UnexpectedContentType: If the content-type of the response
isn't an expect type
:raises UnexpectedResponseCode: If a response code above 400 is
received and it doesn't fall into any
of the handled checks
:raises UnprocessableEntity: If a 422 response code is received and
couldn't be parsed
:returns: None
"""
uri = '{0}/{1}/config'.format(self.uri, amphora_id)
response, body = self.put(uri, '')
self.expected_success(202, response.status)
def amphora_failover(self, amphora_id):
"""Failover an amphora.
:param amphora_id: The ID of the amphora to failover.
:raises AssertionError: if the expected_code isn't a valid http success
response code
:raises BadRequest: If a 400 response code is received
:raises Conflict: If a 409 response code is received
:raises Forbidden: If a 403 response code is received
:raises Gone: If a 410 response code is received
:raises InvalidContentType: If a 415 response code is received
:raises InvalidHTTPResponseBody: The response body wasn't valid JSON
:raises InvalidHttpSuccessCode: if the read code isn't an expected
http success code
:raises NotFound: If a 404 response code is received
:raises NotImplemented: If a 501 response code is received
:raises OverLimit: If a 413 response code is received and over_limit is
not in the response body
:raises RateLimitExceeded: If a 413 response code is received and
over_limit is in the response body
:raises ServerFault: If a 500 response code is received
:raises Unauthorized: If a 401 response code is received
:raises UnexpectedContentType: If the content-type of the response
isn't an expect type
:raises UnexpectedResponseCode: If a response code above 400 is
received and it doesn't fall into any
of the handled checks
:raises UnprocessableEntity: If a 422 response code is received and
couldn't be parsed
:returns: None
"""
uri = '{0}/{1}/failover'.format(self.uri, amphora_id)
response, body = self.put(uri, '')
self.expected_success(202, response.status)

View File

@ -0,0 +1,98 @@
# Copyright 2019 Rackspace US Inc. All rights reserved.
#
# 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.
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions
from octavia_tempest_plugin.common import constants as const
from octavia_tempest_plugin.tests import test_base
from octavia_tempest_plugin.tests import waiters
CONF = config.CONF
class AmphoraAPITest(test_base.LoadBalancerBaseTest):
"""Test the amphora object API."""
@classmethod
def skip_checks(cls):
super(AmphoraAPITest, cls).skip_checks()
if CONF.load_balancer.provider not in ['amphora', 'octavia']:
raise cls.skipException("Amphora tests require provider 'amphora' "
"or 'octavia' (alias to 'amphora', "
" deprecated) set.")
@classmethod
def resource_setup(cls):
"""Setup resources needed by the tests."""
super(AmphoraAPITest, cls).resource_setup()
lb_name = data_utils.rand_name("lb_member_lb1-amphora-api")
lb_kwargs = {const.PROVIDER: CONF.load_balancer.provider,
const.NAME: lb_name}
cls._setup_lb_network_kwargs(lb_kwargs)
lb = cls.mem_lb_client.create_loadbalancer(**lb_kwargs)
cls.lb_id = lb[const.ID]
cls.addClassResourceCleanup(
cls.mem_lb_client.cleanup_loadbalancer,
cls.lb_id)
waiters.wait_for_status(cls.mem_lb_client.show_loadbalancer,
cls.lb_id, const.PROVISIONING_STATUS,
const.ACTIVE,
CONF.load_balancer.lb_build_interval,
CONF.load_balancer.lb_build_timeout)
@decorators.idempotent_id('b7fc231b-dcfa-47a5-99f3-ec5ddcc48f30')
def test_amphora_update(self):
"""Tests the amphora agent configuration update API
* Tests that users without the loadbalancer admin role cannot
update an amphora.
* Update the amphora.
"""
# We have to do this here as the api_version and clients are not
# setup in time to use a decorator or the skip_checks mixin
if not self.lb_admin_amphora_client.is_version_supported(
self.api_version, '2.7'):
raise self.skipException('Amphora update is only available on '
'Octavia API version 2.7 or newer.')
amphorae = self.lb_admin_amphora_client.list_amphorae(
query_params='{loadbalancer_id}={lb_id}'.format(
loadbalancer_id=const.LOADBALANCER_ID, lb_id=self.lb_id))
amphora_1 = amphorae[0]
# Test that a user without the load balancer admin role cannot
# create a flavor
if CONF.load_balancer.RBAC_test_type == const.ADVANCED:
self.assertRaises(
exceptions.Forbidden,
self.os_primary.amphora_client.update_amphora_config,
amphora_1[const.ID])
self.lb_admin_amphora_client.update_amphora_config(amphora_1[const.ID])
# TODO(johnsom) Assert that an amphora config setting updated
# when we have a setting to check.
amp = self.lb_admin_amphora_client.show_amphora(amphora_1[const.ID])
self.assertEqual(const.STATUS_ALLOCATED, amp[const.STATUS])

View File

@ -115,11 +115,11 @@ class AmphoraScenarioTest(test_base.LoadBalancerBaseTest):
# Test that a user with cloud admin role can list the amphorae
if not CONF.load_balancer.RBAC_test_type == const.NONE:
adm = self.os_admin.amphora_client.list_amphorae()
adm = self.lb_admin_amphora_client.list_amphorae()
self.assertTrue(len(adm) >= 2 * self._expected_amp_count(adm))
# Get an actual list of the amphorae
amphorae = self.os_admin.amphora_client.list_amphorae()
amphorae = self.lb_admin_amphora_client.list_amphorae()
# There should be AT LEAST 2, there may be more depending on the
# configured topology, or if there are other LBs created besides ours
@ -127,7 +127,7 @@ class AmphoraScenarioTest(test_base.LoadBalancerBaseTest):
len(amphorae) >= 2 * self._expected_amp_count(amphorae))
show_amphora_response_fields = const.SHOW_AMPHORA_RESPONSE_FIELDS
if self.mem_amphora_client.is_version_supported(
if self.lb_admin_amphora_client.is_version_supported(
self.api_version, '2.1'):
show_amphora_response_fields.append('created_at')
show_amphora_response_fields.append('updated_at')
@ -140,7 +140,7 @@ class AmphoraScenarioTest(test_base.LoadBalancerBaseTest):
self.assertIn(field, amp)
amp_id = amp[const.ID]
amp_obj = self.os_admin.amphora_client.show_amphora(
amp_obj = self.lb_admin_amphora_client.show_amphora(
amphora_id=amp_id)
# Make sure all of the fields exist on the amp show record
@ -148,7 +148,7 @@ class AmphoraScenarioTest(test_base.LoadBalancerBaseTest):
self.assertIn(field, amp_obj)
# Verify a few of the fields are the right type
if self.mem_amphora_client.is_version_supported(
if self.lb_admin_amphora_client.is_version_supported(
self.api_version, '2.1'):
parser.parse(amp_obj[const.CREATED_AT])
parser.parse(amp_obj[const.UPDATED_AT])
@ -175,13 +175,13 @@ class AmphoraScenarioTest(test_base.LoadBalancerBaseTest):
self.assertEqual(amp[field], amp_obj[field])
# Test filtering by loadbalancer_id
amphorae = self.os_admin.amphora_client.list_amphorae(
amphorae = self.lb_admin_amphora_client.list_amphorae(
query_params='{loadbalancer_id}={lb_id}'.format(
loadbalancer_id=const.LOADBALANCER_ID, lb_id=self.lb_id))
self.assertEqual(self._expected_amp_count(amphorae), len(amphorae))
self.assertEqual(self.lb_id, amphorae[0][const.LOADBALANCER_ID])
amphorae = self.os_admin.amphora_client.list_amphorae(
amphorae = self.lb_admin_amphora_client.list_amphorae(
query_params='{loadbalancer_id}={lb_id}'.format(
loadbalancer_id=const.LOADBALANCER_ID, lb_id=lb_id))
self.assertEqual(self._expected_amp_count(amphorae), len(amphorae))

View File

@ -121,7 +121,7 @@ class LoadBalancerBaseTest(test.BaseTestCase):
cls.os_roles_lb_member.healthmonitor_client)
cls.mem_l7policy_client = cls.os_roles_lb_member.l7policy_client
cls.mem_l7rule_client = cls.os_roles_lb_member.l7rule_client
cls.mem_amphora_client = cls.os_roles_lb_member.amphora_client
cls.lb_admin_amphora_client = cls.os_roles_lb_admin.amphora_client
cls.lb_admin_flavor_profile_client = (
cls.os_roles_lb_admin.flavor_profile_client)
cls.lb_admin_flavor_client = cls.os_roles_lb_admin.flavor_client