Merge "Add pools scenarios for octavia"
This commit is contained in:
commit
140d017877
@ -24,12 +24,15 @@ Added
|
|||||||
|
|
||||||
* Added neutron trunk scenarios
|
* Added neutron trunk scenarios
|
||||||
* Added barbican scenarios.
|
* Added barbican scenarios.
|
||||||
* Added octavia scenarios.
|
|
||||||
* [scenario plugin] Octavia.create_and_list_loadbalancers
|
* [scenario plugin] Octavia.create_and_list_loadbalancers
|
||||||
* [scenario plugin] Octavia.create_and_delete_loadbalancers
|
* [scenario plugin] Octavia.create_and_delete_loadbalancers
|
||||||
* [scenario plugin] Octavia.create_and_update_loadbalancers
|
* [scenario plugin] Octavia.create_and_update_loadbalancers
|
||||||
* [scenario plugin] Octavia.create_and_stats_loadbalancers
|
* [scenario plugin] Octavia.create_and_stats_loadbalancers
|
||||||
* [scenario plugin] Octavia.create_and_show_loadbalancers
|
* [scenario plugin] Octavia.create_and_show_loadbalancers
|
||||||
|
* [scenario plugin] Octavia.create_and_list_pools
|
||||||
|
* [scenario plugin] Octavia.create_and_delete_pools
|
||||||
|
* [scenario plugin] Octavia.create_and_update_pools
|
||||||
|
* [scenario plugin] Octavia.create_and_show_pools
|
||||||
* Support for osprofiler config in Devstack plugin.
|
* Support for osprofiler config in Devstack plugin.
|
||||||
* Added property 'floating_ip_enabled' in magnum cluster_templates context.
|
* Added property 'floating_ip_enabled' in magnum cluster_templates context.
|
||||||
|
|
||||||
|
@ -110,3 +110,83 @@
|
|||||||
sla:
|
sla:
|
||||||
failure_rate:
|
failure_rate:
|
||||||
max: 0
|
max: 0
|
||||||
|
-
|
||||||
|
title: Octavia.create_and_list_pools
|
||||||
|
workloads:
|
||||||
|
-
|
||||||
|
scenario:
|
||||||
|
Octavia.create_and_list_pools:
|
||||||
|
protocol: "HTTP"
|
||||||
|
lb_algorithm: "ROUND_ROBIN"
|
||||||
|
runner:
|
||||||
|
constant:
|
||||||
|
times: 2
|
||||||
|
concurrency: 2
|
||||||
|
contexts:
|
||||||
|
users:
|
||||||
|
tenants: 2
|
||||||
|
roles: ["load-balancer_member"]
|
||||||
|
network: {}
|
||||||
|
sla:
|
||||||
|
failure_rate:
|
||||||
|
max: 0
|
||||||
|
-
|
||||||
|
title: Octavia.create_and_delete_pools
|
||||||
|
workloads:
|
||||||
|
-
|
||||||
|
scenario:
|
||||||
|
Octavia.create_and_delete_pools:
|
||||||
|
protocol: "HTTP"
|
||||||
|
lb_algorithm: "ROUND_ROBIN"
|
||||||
|
runner:
|
||||||
|
constant:
|
||||||
|
times: 2
|
||||||
|
concurrency: 2
|
||||||
|
contexts:
|
||||||
|
users:
|
||||||
|
tenants: 2
|
||||||
|
roles: ["load-balancer_member"]
|
||||||
|
network: {}
|
||||||
|
sla:
|
||||||
|
failure_rate:
|
||||||
|
max: 0
|
||||||
|
-
|
||||||
|
title: Octavia.create_and_update_pools
|
||||||
|
workloads:
|
||||||
|
-
|
||||||
|
scenario:
|
||||||
|
Octavia.create_and_update_pools:
|
||||||
|
protocol: "HTTP"
|
||||||
|
lb_algorithm: "ROUND_ROBIN"
|
||||||
|
runner:
|
||||||
|
constant:
|
||||||
|
times: 2
|
||||||
|
concurrency: 2
|
||||||
|
contexts:
|
||||||
|
users:
|
||||||
|
tenants: 2
|
||||||
|
roles: ["load-balancer_member"]
|
||||||
|
network: {}
|
||||||
|
sla:
|
||||||
|
failure_rate:
|
||||||
|
max: 0
|
||||||
|
-
|
||||||
|
title: Octavia.create_and_show_pools
|
||||||
|
workloads:
|
||||||
|
-
|
||||||
|
scenario:
|
||||||
|
Octavia.create_and_show_pools:
|
||||||
|
protocol: "HTTP"
|
||||||
|
lb_algorithm: "ROUND_ROBIN"
|
||||||
|
runner:
|
||||||
|
constant:
|
||||||
|
times: 2
|
||||||
|
concurrency: 2
|
||||||
|
contexts:
|
||||||
|
users:
|
||||||
|
tenants: 2
|
||||||
|
roles: ["load-balancer_member"]
|
||||||
|
network: {}
|
||||||
|
sla:
|
||||||
|
failure_rate:
|
||||||
|
max: 0
|
||||||
|
@ -323,10 +323,12 @@ class NeutronV2Loadbalancer(NeutronLbaasV2Mixin):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# OCTAVIA
|
||||||
|
|
||||||
|
|
||||||
@base.resource("octavia", "loadbalancer", order=next(_neutron_order),
|
@base.resource("octavia", "loadbalancer", order=next(_neutron_order),
|
||||||
tenant_resource=True)
|
tenant_resource=True)
|
||||||
class OctaviaLoadbalancer(base.ResourceManager):
|
class OctaviaMixIn(base.ResourceManager):
|
||||||
|
|
||||||
def _client(self):
|
def _client(self):
|
||||||
return octavia.Octavia(self.admin or self.user)
|
return octavia.Octavia(self.admin or self.user)
|
||||||
@ -353,6 +355,12 @@ class OctaviaLoadbalancer(base.ResourceManager):
|
|||||||
return self._client().load_balancer_list()["loadbalancers"]
|
return self._client().load_balancer_list()["loadbalancers"]
|
||||||
|
|
||||||
|
|
||||||
|
@base.resource("octavia", "pools", order=next(_neutron_order),
|
||||||
|
tenant_resource=True)
|
||||||
|
class OctaviaPools(OctaviaMixIn):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
@base.resource("neutron", "bgpvpn", order=next(_neutron_order),
|
@base.resource("neutron", "bgpvpn", order=next(_neutron_order),
|
||||||
admin_required=True, perform_for_admin_only=True)
|
admin_required=True, perform_for_admin_only=True)
|
||||||
class NeutronBgpvpn(NeutronMixin):
|
class NeutronBgpvpn(NeutronMixin):
|
||||||
@ -406,8 +414,8 @@ class NeutronPort(NeutronMixin):
|
|||||||
for port in ports:
|
for port in ports:
|
||||||
if not port.get("name"):
|
if not port.get("name"):
|
||||||
parent_name = None
|
parent_name = None
|
||||||
if (port["device_owner"] in self.ROUTER_INTERFACE_OWNERS or
|
if (port["device_owner"] in self.ROUTER_INTERFACE_OWNERS
|
||||||
port["device_owner"] == self.ROUTER_GATEWAY_OWNER):
|
or port["device_owner"] == self.ROUTER_GATEWAY_OWNER):
|
||||||
# first case is a port created while adding an interface to
|
# first case is a port created while adding an interface to
|
||||||
# the subnet
|
# the subnet
|
||||||
# second case is a port created while adding gateway for
|
# second case is a port created while adding gateway for
|
||||||
@ -426,8 +434,8 @@ class NeutronPort(NeutronMixin):
|
|||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
device_owner = self.raw_resource["device_owner"]
|
device_owner = self.raw_resource["device_owner"]
|
||||||
if (device_owner in self.ROUTER_INTERFACE_OWNERS or
|
if (device_owner in self.ROUTER_INTERFACE_OWNERS
|
||||||
device_owner == self.ROUTER_GATEWAY_OWNER):
|
or device_owner == self.ROUTER_GATEWAY_OWNER):
|
||||||
if device_owner == self.ROUTER_GATEWAY_OWNER:
|
if device_owner == self.ROUTER_GATEWAY_OWNER:
|
||||||
self._manager().remove_gateway_router(
|
self._manager().remove_gateway_router(
|
||||||
self.raw_resource["device_id"])
|
self.raw_resource["device_id"])
|
||||||
@ -590,9 +598,9 @@ class GlanceImage(base.ResourceManager):
|
|||||||
return image.Image(self.admin or self.user)
|
return image.Image(self.admin or self.user)
|
||||||
|
|
||||||
def list(self):
|
def list(self):
|
||||||
images = (self._client().list_images(owner=self.tenant_uuid) +
|
images = (self._client().list_images(owner=self.tenant_uuid)
|
||||||
self._client().list_images(status="deactivated",
|
+ self._client().list_images(status="deactivated",
|
||||||
owner=self.tenant_uuid))
|
owner=self.tenant_uuid))
|
||||||
return images
|
return images
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
|
155
rally_openstack/scenarios/octavia/pools.py
Normal file
155
rally_openstack/scenarios/octavia/pools.py
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
# Copyright 2018: Red Hat 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 rally.task import validation
|
||||||
|
|
||||||
|
from rally_openstack import consts
|
||||||
|
from rally_openstack import scenario
|
||||||
|
from rally_openstack.scenarios.octavia import utils
|
||||||
|
|
||||||
|
"""Scenarios for Octavia Loadbalancer pools."""
|
||||||
|
|
||||||
|
|
||||||
|
@validation.add("required_services", services=[consts.Service.OCTAVIA])
|
||||||
|
@validation.add("required_platform", platform="openstack", users=True)
|
||||||
|
@validation.add("required_contexts", contexts=["network"])
|
||||||
|
@scenario.configure(context={"cleanup@openstack": ["octavia"]},
|
||||||
|
name="Octavia.create_and_list_pools",
|
||||||
|
platform="openstack")
|
||||||
|
class CreateAndListPools(utils.OctaviaBase):
|
||||||
|
|
||||||
|
def run(self, protocol, lb_algorithm):
|
||||||
|
"""Create a loadbalancer pool per each subnet and then pools.
|
||||||
|
|
||||||
|
:param protocol: protocol for which the pool listens
|
||||||
|
:param lb_algorithm: loadbalancer algorithm
|
||||||
|
"""
|
||||||
|
subnets = []
|
||||||
|
loadbalancers = []
|
||||||
|
networks = self.context.get("tenant", {}).get("networks", [])
|
||||||
|
for network in networks:
|
||||||
|
subnets.extend(network.get("subnets", []))
|
||||||
|
for subnet_id in subnets:
|
||||||
|
lb = self.octavia.load_balancer_create(
|
||||||
|
subnet_id=subnet_id)
|
||||||
|
loadbalancers.append(lb)
|
||||||
|
|
||||||
|
for loadbalancer in loadbalancers:
|
||||||
|
self.octavia.wait_for_loadbalancer_prov_status(loadbalancer)
|
||||||
|
self.octavia.pool_create(
|
||||||
|
lb_id=loadbalancer["loadbalancer"]["id"],
|
||||||
|
protocol=protocol, lb_algorithm=lb_algorithm)
|
||||||
|
self.octavia.pool_list()
|
||||||
|
|
||||||
|
|
||||||
|
@validation.add("required_services", services=[consts.Service.OCTAVIA])
|
||||||
|
@validation.add("required_platform", platform="openstack", users=True)
|
||||||
|
@validation.add("required_contexts", contexts=["network"])
|
||||||
|
@scenario.configure(context={"cleanup@openstack": ["octavia"]},
|
||||||
|
name="Octavia.create_and_delete_pools",
|
||||||
|
platform="openstack")
|
||||||
|
class CreateAndDeletePools(utils.OctaviaBase):
|
||||||
|
|
||||||
|
def run(self, protocol, lb_algorithm):
|
||||||
|
"""Create a pool per each subnet and then delete pool
|
||||||
|
|
||||||
|
:param protocol: protocol for which the pool listens
|
||||||
|
:param lb_algorithm: loadbalancer algorithm
|
||||||
|
"""
|
||||||
|
subnets = []
|
||||||
|
loadbalancers = []
|
||||||
|
networks = self.context.get("tenant", {}).get("networks", [])
|
||||||
|
for network in networks:
|
||||||
|
subnets.extend(network.get("subnets", []))
|
||||||
|
for subnet_id in subnets:
|
||||||
|
lb = self.octavia.load_balancer_create(
|
||||||
|
subnet_id=subnet_id)
|
||||||
|
loadbalancers.append(lb)
|
||||||
|
|
||||||
|
for loadbalancer in loadbalancers:
|
||||||
|
self.octavia.wait_for_loadbalancer_prov_status(loadbalancer)
|
||||||
|
pools = self.octavia.pool_create(
|
||||||
|
lb_id=loadbalancer["loadbalancer"]["id"],
|
||||||
|
protocol=protocol, lb_algorithm=lb_algorithm)
|
||||||
|
self.octavia.pool_delete(pools["id"])
|
||||||
|
|
||||||
|
|
||||||
|
@validation.add("required_services", services=[consts.Service.OCTAVIA])
|
||||||
|
@validation.add("required_platform", platform="openstack", users=True)
|
||||||
|
@validation.add("required_contexts", contexts=["network"])
|
||||||
|
@scenario.configure(context={"cleanup@openstack": ["octavia"]},
|
||||||
|
name="Octavia.create_and_update_pools",
|
||||||
|
platform="openstack")
|
||||||
|
class CreateAndUpdatePools(utils.OctaviaBase):
|
||||||
|
|
||||||
|
def run(self, protocol, lb_algorithm):
|
||||||
|
"""Create a pool per each subnet and then update
|
||||||
|
|
||||||
|
:param protocol: protocol for which the pool listens
|
||||||
|
:param lb_algorithm: loadbalancer algorithm
|
||||||
|
"""
|
||||||
|
subnets = []
|
||||||
|
loadbalancers = []
|
||||||
|
networks = self.context.get("tenant", {}).get("networks", [])
|
||||||
|
for network in networks:
|
||||||
|
subnets.extend(network.get("subnets", []))
|
||||||
|
for subnet_id in subnets:
|
||||||
|
lb = self.octavia.load_balancer_create(
|
||||||
|
subnet_id=subnet_id)
|
||||||
|
loadbalancers.append(lb)
|
||||||
|
|
||||||
|
update_pool = {
|
||||||
|
"name": self.generate_random_name()
|
||||||
|
}
|
||||||
|
|
||||||
|
for loadbalancer in loadbalancers:
|
||||||
|
self.octavia.wait_for_loadbalancer_prov_status(loadbalancer)
|
||||||
|
pools = self.octavia.pool_create(
|
||||||
|
lb_id=loadbalancer["loadbalancer"]["id"],
|
||||||
|
protocol=protocol, lb_algorithm=lb_algorithm)
|
||||||
|
self.octavia.pool_set(
|
||||||
|
pool_id=pools["id"], pool_update_args=update_pool)
|
||||||
|
|
||||||
|
|
||||||
|
@validation.add("required_services", services=[consts.Service.OCTAVIA])
|
||||||
|
@validation.add("required_platform", platform="openstack", users=True)
|
||||||
|
@validation.add("required_contexts", contexts=["network"])
|
||||||
|
@scenario.configure(context={"cleanup@openstack": ["octavia"]},
|
||||||
|
name="Octavia.create_and_show_pools",
|
||||||
|
platform="openstack")
|
||||||
|
class CreateAndShowPools(utils.OctaviaBase):
|
||||||
|
|
||||||
|
def run(self, protocol, lb_algorithm):
|
||||||
|
"""Create a pool per each subnet and show it
|
||||||
|
|
||||||
|
:param protocol: protocol for which the pool listens
|
||||||
|
:param lb_algorithm: loadbalancer algorithm
|
||||||
|
"""
|
||||||
|
subnets = []
|
||||||
|
loadbalancers = []
|
||||||
|
networks = self.context.get("tenant", {}).get("networks", [])
|
||||||
|
for network in networks:
|
||||||
|
subnets.extend(network.get("subnets", []))
|
||||||
|
for subnet_id in subnets:
|
||||||
|
lb = self.octavia.load_balancer_create(
|
||||||
|
subnet_id=subnet_id)
|
||||||
|
loadbalancers.append(lb)
|
||||||
|
|
||||||
|
for loadbalancer in loadbalancers:
|
||||||
|
self.octavia.wait_for_loadbalancer_prov_status(loadbalancer)
|
||||||
|
pools = self.octavia.pool_create(
|
||||||
|
lb_id=loadbalancer["loadbalancer"]["id"],
|
||||||
|
protocol=protocol, lb_algorithm=lb_algorithm)
|
||||||
|
self.octavia.pool_show(pools["id"])
|
27
rally_openstack/scenarios/octavia/utils.py
Normal file
27
rally_openstack/scenarios/octavia/utils.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Copyright 2018: Red Hat 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 rally_openstack import scenario
|
||||||
|
from rally_openstack.services.loadbalancer import octavia
|
||||||
|
|
||||||
|
|
||||||
|
class OctaviaBase(scenario.OpenStackScenario):
|
||||||
|
"""Base class for Octavia scenarios with basic atomic actions."""
|
||||||
|
|
||||||
|
def __init__(self, context=None, admin_clients=None, clients=None):
|
||||||
|
super(OctaviaBase, self).__init__(context, admin_clients, clients)
|
||||||
|
self.octavia = octavia.Octavia(
|
||||||
|
self._clients, name_generator=self.generate_random_name,
|
||||||
|
atomic_inst=self.atomic_actions())
|
@ -196,16 +196,53 @@ class Octavia(service.Service):
|
|||||||
"""
|
"""
|
||||||
return self._clients.octavia().pool_list(**kwargs)
|
return self._clients.octavia().pool_list(**kwargs)
|
||||||
|
|
||||||
|
def update_pool_resource(self, pool):
|
||||||
|
try:
|
||||||
|
new_pool = self._clients.octavia().pool_show(pool["id"])
|
||||||
|
except Exception as e:
|
||||||
|
if getattr(e, "status_code", 400) == 404:
|
||||||
|
raise exceptions.GetResourceNotFound(resource=pool)
|
||||||
|
raise exceptions.GetResourceFailure(resource=pool, err=e)
|
||||||
|
return new_pool
|
||||||
|
|
||||||
@atomic.action_timer("octavia.pool_create")
|
@atomic.action_timer("octavia.pool_create")
|
||||||
def pool_create(self, **kwargs):
|
def pool_create(self, lb_id, protocol, lb_algorithm,
|
||||||
|
description=None, admin_state_up=True,
|
||||||
|
session_persistence=None):
|
||||||
"""Create a pool
|
"""Create a pool
|
||||||
|
|
||||||
:param kwargs:
|
:param lb_id: ID of the loadbalancer
|
||||||
Parameters to create a listener with (expects json=)
|
:param protocol: protocol of the resource
|
||||||
|
:param lb_algorithm: loadbalancing algorithm of the pool
|
||||||
|
:param description: a human readable description of the pool
|
||||||
|
:param admin_state_up: administrative state of the resource
|
||||||
|
:param session_persistence: a json object specifiying the session
|
||||||
|
persistence of the pool
|
||||||
:return:
|
:return:
|
||||||
A dict of the created pool's settings
|
A dict of the created pool's settings
|
||||||
"""
|
"""
|
||||||
return self._clients.octavia().pool_create(**kwargs)
|
args = {
|
||||||
|
"name": self.generate_random_name(),
|
||||||
|
"loadbalancer_id": lb_id,
|
||||||
|
"protocol": protocol,
|
||||||
|
"lb_algorithm": lb_algorithm,
|
||||||
|
"description": description,
|
||||||
|
"admin_state_up": admin_state_up,
|
||||||
|
"session_persistence": session_persistence
|
||||||
|
}
|
||||||
|
pool = self._clients.octavia().pool_create(
|
||||||
|
json={"pool": args})
|
||||||
|
pool = pool["pool"]
|
||||||
|
pool = utils.wait_for_status(
|
||||||
|
pool,
|
||||||
|
ready_statuses=["ACTIVE"],
|
||||||
|
status_attr="provisioning_status",
|
||||||
|
update_resource=self.update_pool_resource,
|
||||||
|
timeout=CONF.openstack.octavia_create_loadbalancer_timeout,
|
||||||
|
check_interval=(
|
||||||
|
CONF.openstack.octavia_create_loadbalancer_poll_interval)
|
||||||
|
)
|
||||||
|
return pool
|
||||||
|
|
||||||
@atomic.action_timer("octavia.pool_delete")
|
@atomic.action_timer("octavia.pool_delete")
|
||||||
def pool_delete(self, pool_id):
|
def pool_delete(self, pool_id):
|
||||||
@ -230,17 +267,18 @@ class Octavia(service.Service):
|
|||||||
return self._clients.octavia().pool_show(pool_id)
|
return self._clients.octavia().pool_show(pool_id)
|
||||||
|
|
||||||
@atomic.action_timer("octavia.pool_set")
|
@atomic.action_timer("octavia.pool_set")
|
||||||
def pool_set(self, pool_id, **kwargs):
|
def pool_set(self, pool_id, pool_update_args):
|
||||||
"""Update a pool's settings
|
"""Update a pool's settings
|
||||||
|
|
||||||
:param pool_id:
|
:param pool_id:
|
||||||
ID of the pool to update
|
ID of the pool to update
|
||||||
:param kwargs:
|
:param pool_update_args:
|
||||||
A dict of arguments to update a pool
|
A dict of arguments to update a pool
|
||||||
:return:
|
:return:
|
||||||
Response Code from the API
|
Response Code from the API
|
||||||
"""
|
"""
|
||||||
return self._clients.octavia().pool_set(pool_id, **kwargs)
|
return self._clients.octavia().pool_set(
|
||||||
|
pool_id, json={"pool": pool_update_args})
|
||||||
|
|
||||||
@atomic.action_timer("octavia.member_list")
|
@atomic.action_timer("octavia.member_list")
|
||||||
def member_list(self, pool_id, **kwargs):
|
def member_list(self, pool_id, **kwargs):
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"Octavia.create_and_delete_pools": [
|
||||||
|
{
|
||||||
|
"args": {
|
||||||
|
"protocol": "HTTP",
|
||||||
|
"lb_algorithm": "ROUND_ROBIN"
|
||||||
|
},
|
||||||
|
"runner": {
|
||||||
|
"type": "constant",
|
||||||
|
"times": 5,
|
||||||
|
"concurrency": 2
|
||||||
|
},
|
||||||
|
"context": {
|
||||||
|
"users": {
|
||||||
|
"tenants": 2,
|
||||||
|
"users_per_tenant": 2
|
||||||
|
},
|
||||||
|
"roles": ["load-balancer_member"],
|
||||||
|
"network": {}
|
||||||
|
},
|
||||||
|
"sla": {
|
||||||
|
"failure_rate": {
|
||||||
|
"max": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
Octavia.create_and_delete_pools:
|
||||||
|
-
|
||||||
|
args:
|
||||||
|
protocol: "HTTP"
|
||||||
|
lb_algorithm: "ROUND_ROBIN"
|
||||||
|
runner:
|
||||||
|
type: "constant"
|
||||||
|
times: 5
|
||||||
|
concurrency: 2
|
||||||
|
context:
|
||||||
|
users:
|
||||||
|
tenants: 2
|
||||||
|
users_per_tenant: 2
|
||||||
|
roles:
|
||||||
|
- load-balancer_member
|
||||||
|
network: {}
|
||||||
|
sla:
|
||||||
|
failure_rate:
|
||||||
|
max: 0
|
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"Octavia.create_and_list_pools": [
|
||||||
|
{
|
||||||
|
"args": {
|
||||||
|
"protocol": "HTTP",
|
||||||
|
"lb_algorithm": "ROUND_ROBIN"
|
||||||
|
},
|
||||||
|
"runner": {
|
||||||
|
"type": "constant",
|
||||||
|
"times": 5,
|
||||||
|
"concurrency": 2
|
||||||
|
},
|
||||||
|
"context": {
|
||||||
|
"users": {
|
||||||
|
"tenants": 2,
|
||||||
|
"users_per_tenant": 2
|
||||||
|
},
|
||||||
|
"roles": ["load-balancer_member"],
|
||||||
|
"network": {}
|
||||||
|
},
|
||||||
|
"sla": {
|
||||||
|
"failure_rate": {
|
||||||
|
"max": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
Octavia.create_and_list_pools:
|
||||||
|
-
|
||||||
|
args:
|
||||||
|
protocol: "HTTP"
|
||||||
|
lb_algorithm: "ROUND_ROBIN"
|
||||||
|
runner:
|
||||||
|
type: "constant"
|
||||||
|
times: 5
|
||||||
|
concurrency: 2
|
||||||
|
context:
|
||||||
|
users:
|
||||||
|
tenants: 2
|
||||||
|
users_per_tenant: 2
|
||||||
|
roles:
|
||||||
|
- load-balancer_member
|
||||||
|
network: {}
|
||||||
|
sla:
|
||||||
|
failure_rate:
|
||||||
|
max: 0
|
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"Octavia.create_and_show_pools": [
|
||||||
|
{
|
||||||
|
"args": {
|
||||||
|
"protocol": "HTTP",
|
||||||
|
"lb_algorithm": "ROUND_ROBIN"
|
||||||
|
},
|
||||||
|
"runner": {
|
||||||
|
"type": "constant",
|
||||||
|
"times": 5,
|
||||||
|
"concurrency": 2
|
||||||
|
},
|
||||||
|
"context": {
|
||||||
|
"users": {
|
||||||
|
"tenants": 2,
|
||||||
|
"users_per_tenant": 2
|
||||||
|
},
|
||||||
|
"roles": ["load-balancer_member"],
|
||||||
|
"network": {}
|
||||||
|
},
|
||||||
|
"sla": {
|
||||||
|
"failure_rate": {
|
||||||
|
"max": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
Octavia.create_and_show_pools:
|
||||||
|
-
|
||||||
|
args:
|
||||||
|
protocol: "HTTP"
|
||||||
|
lb_algorithm: "ROUND_ROBIN"
|
||||||
|
runner:
|
||||||
|
type: "constant"
|
||||||
|
times: 5
|
||||||
|
concurrency: 2
|
||||||
|
context:
|
||||||
|
users:
|
||||||
|
tenants: 2
|
||||||
|
users_per_tenant: 2
|
||||||
|
roles:
|
||||||
|
- load-balancer_member
|
||||||
|
network: {}
|
||||||
|
sla:
|
||||||
|
failure_rate:
|
||||||
|
max: 0
|
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"Octavia.create_and_update_pools": [
|
||||||
|
{
|
||||||
|
"args": {
|
||||||
|
"protocol": "HTTP",
|
||||||
|
"lb_algorithm": "ROUND_ROBIN"
|
||||||
|
},
|
||||||
|
"runner": {
|
||||||
|
"type": "constant",
|
||||||
|
"times": 5,
|
||||||
|
"concurrency": 2
|
||||||
|
},
|
||||||
|
"context": {
|
||||||
|
"users": {
|
||||||
|
"tenants": 2,
|
||||||
|
"users_per_tenant": 2
|
||||||
|
},
|
||||||
|
"roles": ["load-balancer_member"],
|
||||||
|
"network": {}
|
||||||
|
},
|
||||||
|
"sla": {
|
||||||
|
"failure_rate": {
|
||||||
|
"max": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
Octavia.create_and_update_pools:
|
||||||
|
-
|
||||||
|
args:
|
||||||
|
protocol: "HTTP"
|
||||||
|
lb_algorithm: "ROUND_ROBIN"
|
||||||
|
runner:
|
||||||
|
type: "constant"
|
||||||
|
times: 5
|
||||||
|
concurrency: 2
|
||||||
|
context:
|
||||||
|
users:
|
||||||
|
tenants: 2
|
||||||
|
users_per_tenant: 2
|
||||||
|
roles:
|
||||||
|
- load-balancer_member
|
||||||
|
network: {}
|
||||||
|
sla:
|
||||||
|
failure_rate:
|
||||||
|
max: 0
|
@ -1222,7 +1222,7 @@ class BarbicanSecretsTestCase(test.TestCase):
|
|||||||
class OctaviaResourceTestCase(test.TestCase):
|
class OctaviaResourceTestCase(test.TestCase):
|
||||||
|
|
||||||
def get_octavia(self):
|
def get_octavia(self):
|
||||||
octavia = resources.OctaviaLoadbalancer()
|
octavia = resources.OctaviaMixIn()
|
||||||
octavia._service = "octavia"
|
octavia._service = "octavia"
|
||||||
octavia._manager = mock.Mock()
|
octavia._manager = mock.Mock()
|
||||||
return octavia
|
return octavia
|
||||||
|
149
tests/unit/scenarios/loadbalancer/test_pools.py
Normal file
149
tests/unit/scenarios/loadbalancer/test_pools.py
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
# Copyright 2018: Red Hat 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.
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from rally_openstack.scenarios.octavia import pools
|
||||||
|
from tests.unit import test
|
||||||
|
|
||||||
|
|
||||||
|
class PoolsTestCase(test.ScenarioTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(PoolsTestCase, self).setUp()
|
||||||
|
patch = mock.patch(
|
||||||
|
"rally_openstack.services.loadbalancer.octavia.Octavia")
|
||||||
|
self.addCleanup(patch.stop)
|
||||||
|
self.mock_loadbalancers = patch.start()
|
||||||
|
|
||||||
|
def _get_context(self):
|
||||||
|
context = super(PoolsTestCase, self).get_test_context()
|
||||||
|
context.update({
|
||||||
|
"user": {
|
||||||
|
"id": "fake_user",
|
||||||
|
"tenant_id": "fake_tenant",
|
||||||
|
"credential": mock.MagicMock()
|
||||||
|
},
|
||||||
|
"tenant": {"id": "fake_tenant",
|
||||||
|
"networks": [{"id": "fake_net",
|
||||||
|
"subnets": ["fake_subnet"]}]}})
|
||||||
|
return context
|
||||||
|
|
||||||
|
def test_create_and_list_pools(self):
|
||||||
|
loadbalancer_service = self.mock_loadbalancers.return_value
|
||||||
|
scenario = pools.CreateAndListPools(self._get_context())
|
||||||
|
scenario.run(protocol="HTTP", lb_algorithm="ROUND_ROBIN")
|
||||||
|
loadbalancer = [{
|
||||||
|
"loadbalancer": {
|
||||||
|
"id": "loadbalancer-id"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
subnets = []
|
||||||
|
mock_has_calls = []
|
||||||
|
networks = self._get_context()["tenant"]["networks"]
|
||||||
|
for network in networks:
|
||||||
|
subnets.extend(network.get("subnets", []))
|
||||||
|
for subnet in subnets:
|
||||||
|
mock_has_calls.append(mock.call(subnet_id="fake_subnet"))
|
||||||
|
loadbalancer_service.load_balancer_create.assert_has_calls(
|
||||||
|
mock_has_calls)
|
||||||
|
for lb in loadbalancer:
|
||||||
|
self.assertEqual(
|
||||||
|
1, loadbalancer_service.wait_for_loadbalancer_prov_status
|
||||||
|
.call_count)
|
||||||
|
self.assertEqual(1,
|
||||||
|
loadbalancer_service.pool_create.call_count)
|
||||||
|
loadbalancer_service.pool_list.assert_called_once_with()
|
||||||
|
|
||||||
|
def test_create_and_delete_pools(self):
|
||||||
|
loadbalancer_service = self.mock_loadbalancers.return_value
|
||||||
|
scenario = pools.CreateAndDeletePools(self._get_context())
|
||||||
|
scenario.run(protocol="HTTP", lb_algorithm="ROUND_ROBIN")
|
||||||
|
loadbalancer = [{
|
||||||
|
"loadbalancer": {
|
||||||
|
"id": "loadbalancer-id"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
subnets = []
|
||||||
|
mock_has_calls = []
|
||||||
|
networks = self._get_context()["tenant"]["networks"]
|
||||||
|
for network in networks:
|
||||||
|
subnets.extend(network.get("subnets", []))
|
||||||
|
for subnet in subnets:
|
||||||
|
mock_has_calls.append(mock.call(subnet_id="fake_subnet"))
|
||||||
|
loadbalancer_service.load_balancer_create.assert_has_calls(
|
||||||
|
mock_has_calls)
|
||||||
|
for lb in loadbalancer:
|
||||||
|
self.assertEqual(
|
||||||
|
1, loadbalancer_service.wait_for_loadbalancer_prov_status
|
||||||
|
.call_count)
|
||||||
|
self.assertEqual(1,
|
||||||
|
loadbalancer_service.pool_create.call_count)
|
||||||
|
self.assertEqual(1,
|
||||||
|
loadbalancer_service.pool_delete.call_count)
|
||||||
|
|
||||||
|
def test_create_and_update_pools(self):
|
||||||
|
loadbalancer_service = self.mock_loadbalancers.return_value
|
||||||
|
scenario = pools.CreateAndUpdatePools(self._get_context())
|
||||||
|
scenario.run(protocol="HTTP", lb_algorithm="ROUND_ROBIN")
|
||||||
|
loadbalancer = [{
|
||||||
|
"loadbalancer": {
|
||||||
|
"id": "loadbalancer-id"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
subnets = []
|
||||||
|
mock_has_calls = []
|
||||||
|
networks = self._get_context()["tenant"]["networks"]
|
||||||
|
for network in networks:
|
||||||
|
subnets.extend(network.get("subnets", []))
|
||||||
|
for subnet in subnets:
|
||||||
|
mock_has_calls.append(mock.call(subnet_id="fake_subnet"))
|
||||||
|
loadbalancer_service.load_balancer_create.assert_has_calls(
|
||||||
|
mock_has_calls)
|
||||||
|
for lb in loadbalancer:
|
||||||
|
self.assertEqual(
|
||||||
|
1, loadbalancer_service.wait_for_loadbalancer_prov_status
|
||||||
|
.call_count)
|
||||||
|
self.assertEqual(1,
|
||||||
|
loadbalancer_service.pool_create.call_count)
|
||||||
|
self.assertEqual(1,
|
||||||
|
loadbalancer_service.pool_set.call_count)
|
||||||
|
|
||||||
|
def test_create_and_show_pools(self):
|
||||||
|
loadbalancer_service = self.mock_loadbalancers.return_value
|
||||||
|
scenario = pools.CreateAndShowPools(self._get_context())
|
||||||
|
scenario.run(protocol="HTTP", lb_algorithm="ROUND_ROBIN")
|
||||||
|
loadbalancer = [{
|
||||||
|
"loadbalancer": {
|
||||||
|
"id": "loadbalancer-id"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
subnets = []
|
||||||
|
mock_has_calls = []
|
||||||
|
networks = self._get_context()["tenant"]["networks"]
|
||||||
|
for network in networks:
|
||||||
|
subnets.extend(network.get("subnets", []))
|
||||||
|
for subnet in subnets:
|
||||||
|
mock_has_calls.append(mock.call(subnet_id="fake_subnet"))
|
||||||
|
loadbalancer_service.load_balancer_create.assert_has_calls(
|
||||||
|
mock_has_calls)
|
||||||
|
for lb in loadbalancer:
|
||||||
|
self.assertEqual(
|
||||||
|
1, loadbalancer_service.wait_for_loadbalancer_prov_status
|
||||||
|
.call_count)
|
||||||
|
self.assertEqual(1,
|
||||||
|
loadbalancer_service.pool_create.call_count)
|
||||||
|
self.assertEqual(1,
|
||||||
|
loadbalancer_service.pool_show.call_count)
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from rally_openstack.scenarios.octavia import loadbalancers
|
from rally_openstack.scenarios.octavia import utils
|
||||||
from tests.unit import test
|
from tests.unit import test
|
||||||
|
|
||||||
|
|
||||||
@ -42,6 +42,6 @@ class LoadBalancerBaseTestCase(test.ScenarioTestCase):
|
|||||||
self.mock_service = patch.start()
|
self.mock_service = patch.start()
|
||||||
|
|
||||||
def test_octavia_base(self):
|
def test_octavia_base(self):
|
||||||
base = loadbalancers.OctaviaBase(self.context)
|
base = utils.OctaviaBase(self.context)
|
||||||
self.assertEqual(base.octavia,
|
self.assertEqual(base.octavia,
|
||||||
self.mock_service.return_value)
|
self.mock_service.return_value)
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import fixtures
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from rally.common import cfg
|
from rally.common import cfg
|
||||||
@ -31,6 +32,9 @@ class LoadBalancerServiceTestCase(test.TestCase):
|
|||||||
self.name_generator = mock.MagicMock()
|
self.name_generator = mock.MagicMock()
|
||||||
self.service = octavia.Octavia(self.clients,
|
self.service = octavia.Octavia(self.clients,
|
||||||
name_generator=self.name_generator)
|
name_generator=self.name_generator)
|
||||||
|
self.mock_wait_for_status = fixtures.MockPatch(
|
||||||
|
"rally.task.utils.wait_for_status")
|
||||||
|
self.useFixture(self.mock_wait_for_status)
|
||||||
|
|
||||||
def _get_context(self):
|
def _get_context(self):
|
||||||
context = test.get_test_context()
|
context = test.get_test_context()
|
||||||
@ -164,11 +168,47 @@ class LoadBalancerServiceTestCase(test.TestCase):
|
|||||||
self._test_atomic_action_timer(self.atomic_actions(),
|
self._test_atomic_action_timer(self.atomic_actions(),
|
||||||
"octavia.pool_list")
|
"octavia.pool_list")
|
||||||
|
|
||||||
|
def test_update_pool_resource(self):
|
||||||
|
fake_pool = {"id": "pool-id"}
|
||||||
|
self.service.update_pool_resource(fake_pool)
|
||||||
|
self.service._clients.octavia().pool_show \
|
||||||
|
.assert_called_once_with("pool-id")
|
||||||
|
|
||||||
|
def test_update_pool_resource_fail_404(self):
|
||||||
|
fake_pool = {"id": "pool-id"}
|
||||||
|
ex = Exception()
|
||||||
|
ex.status_code = 404
|
||||||
|
self.service._clients.octavia().pool_show.side_effect = ex
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.GetResourceNotFound,
|
||||||
|
self.service.update_pool_resource, fake_pool)
|
||||||
|
|
||||||
|
def test_update_pool_resource_fail(self):
|
||||||
|
fake_pool = {"id": "pool-id"}
|
||||||
|
ex = Exception()
|
||||||
|
self.service._clients.octavia().pool_show.side_effect = ex
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.GetResourceFailure,
|
||||||
|
self.service.update_pool_resource, fake_pool)
|
||||||
|
|
||||||
def test_pool_create(self):
|
def test_pool_create(self):
|
||||||
self.service.pool_create()
|
self.service.generate_random_name = mock.MagicMock(
|
||||||
self.assertEqual(
|
return_value="pool")
|
||||||
1, self.service._clients.octavia().pool_create.call_count)
|
self.service.pool_create(
|
||||||
self.service._clients.octavia().pool_create.assert_called_once_with()
|
lb_id="loadbalancer-id",
|
||||||
|
protocol="HTTP",
|
||||||
|
lb_algorithm="ROUND_ROBIN")
|
||||||
|
self.service._clients.octavia().pool_create \
|
||||||
|
.assert_called_once_with(
|
||||||
|
json={"pool": {
|
||||||
|
"lb_algorithm": "ROUND_ROBIN",
|
||||||
|
"protocol": "HTTP",
|
||||||
|
"description": None,
|
||||||
|
"admin_state_up": True,
|
||||||
|
"session_persistence": None,
|
||||||
|
"loadbalancer_id": "loadbalancer-id",
|
||||||
|
"name": "pool"}})
|
||||||
|
|
||||||
self._test_atomic_action_timer(self.atomic_actions(),
|
self._test_atomic_action_timer(self.atomic_actions(),
|
||||||
"octavia.pool_create")
|
"octavia.pool_create")
|
||||||
|
|
||||||
@ -187,9 +227,14 @@ class LoadBalancerServiceTestCase(test.TestCase):
|
|||||||
"octavia.pool_show")
|
"octavia.pool_show")
|
||||||
|
|
||||||
def test_pool_set(self):
|
def test_pool_set(self):
|
||||||
self.service.pool_set(pool_id="fake_pool")
|
pool_update_args = {"name": "new-pool-name"}
|
||||||
|
self.service.pool_set(
|
||||||
|
pool_id="fake_pool",
|
||||||
|
pool_update_args=pool_update_args)
|
||||||
self.service._clients.octavia().pool_set \
|
self.service._clients.octavia().pool_set \
|
||||||
.assert_called_once_with("fake_pool")
|
.assert_called_once_with(
|
||||||
|
"fake_pool",
|
||||||
|
json={"pool": {"name": "new-pool-name"}})
|
||||||
self._test_atomic_action_timer(self.atomic_actions(),
|
self._test_atomic_action_timer(self.atomic_actions(),
|
||||||
"octavia.pool_set")
|
"octavia.pool_set")
|
||||||
|
|
||||||
@ -338,14 +383,14 @@ class LoadBalancerServiceTestCase(test.TestCase):
|
|||||||
|
|
||||||
def test_quota_list(self):
|
def test_quota_list(self):
|
||||||
self.service.quota_list(params="fake_params")
|
self.service.quota_list(params="fake_params")
|
||||||
self.service._clients.octavia().quota_list\
|
self.service._clients.octavia().quota_list \
|
||||||
.assert_called_once_with("fake_params")
|
.assert_called_once_with("fake_params")
|
||||||
self._test_atomic_action_timer(self.atomic_actions(),
|
self._test_atomic_action_timer(self.atomic_actions(),
|
||||||
"octavia.quota_list")
|
"octavia.quota_list")
|
||||||
|
|
||||||
def test_quota_show(self):
|
def test_quota_show(self):
|
||||||
self.service.quota_show(project_id="fake_project")
|
self.service.quota_show(project_id="fake_project")
|
||||||
self.service._clients.octavia().quota_show\
|
self.service._clients.octavia().quota_show \
|
||||||
.assert_called_once_with("fake_project")
|
.assert_called_once_with("fake_project")
|
||||||
self._test_atomic_action_timer(self.atomic_actions(),
|
self._test_atomic_action_timer(self.atomic_actions(),
|
||||||
"octavia.quota_show")
|
"octavia.quota_show")
|
||||||
@ -389,15 +434,14 @@ class LoadBalancerServiceTestCase(test.TestCase):
|
|||||||
def test_update_loadbalancer_resource(self):
|
def test_update_loadbalancer_resource(self):
|
||||||
fake_lb = {"id": "fake_lb"}
|
fake_lb = {"id": "fake_lb"}
|
||||||
self.service.update_loadbalancer_resource(lb=fake_lb)
|
self.service.update_loadbalancer_resource(lb=fake_lb)
|
||||||
self.service._clients.octavia().load_balancer_show. \
|
self.service._clients.octavia().load_balancer_show \
|
||||||
assert_called_once_with("fake_lb")
|
.assert_called_once_with("fake_lb")
|
||||||
|
|
||||||
def test_update_loadbalancer_resource_fail_404(self):
|
def test_update_loadbalancer_resource_fail_404(self):
|
||||||
fake_lb = {"id": "fake_lb"}
|
fake_lb = {"id": "fake_lb"}
|
||||||
ex = Exception()
|
ex = Exception()
|
||||||
ex.status_code = 404
|
ex.status_code = 404
|
||||||
self.service._clients.octavia().load_balancer_show.side_effect = \
|
self.service._clients.octavia().load_balancer_show.side_effect = ex
|
||||||
ex
|
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exceptions.GetResourceNotFound,
|
exceptions.GetResourceNotFound,
|
||||||
self.service.update_loadbalancer_resource, fake_lb)
|
self.service.update_loadbalancer_resource, fake_lb)
|
||||||
@ -405,8 +449,7 @@ class LoadBalancerServiceTestCase(test.TestCase):
|
|||||||
def test_update_loadbalancer_resource_fail(self):
|
def test_update_loadbalancer_resource_fail(self):
|
||||||
fake_lb = {"id": "fake_lb"}
|
fake_lb = {"id": "fake_lb"}
|
||||||
ex = Exception()
|
ex = Exception()
|
||||||
self.service._clients.octavia().load_balancer_show.side_effect = \
|
self.service._clients.octavia().load_balancer_show.side_effect = ex
|
||||||
ex
|
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exceptions.GetResourceFailure,
|
exceptions.GetResourceFailure,
|
||||||
self.service.update_loadbalancer_resource, fake_lb)
|
self.service.update_loadbalancer_resource, fake_lb)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user