Merge "Jobboard based controller"

This commit is contained in:
Zuul 2020-04-09 00:10:44 +00:00 committed by Gerrit Code Review
commit 73fbc05386
32 changed files with 1280 additions and 601 deletions

View File

@ -225,6 +225,36 @@ function create_octavia_accounts {
fi fi
} }
function install_redis {
if is_fedora; then
install_package redis
elif is_ubuntu; then
install_package redis-server
elif is_suse; then
install_package redis
else
exit_distro_not_supported "redis installation"
fi
start_service redis
pip_install_gr redis
}
function uninstall_redis {
if is_fedora; then
uninstall_package redis
elif is_ubuntu; then
uninstall_package redis-server
elif is_suse; then
uninstall_package redis
fi
stop_service redis
pip_unistall redis
}
function octavia_configure { function octavia_configure {
sudo mkdir -m 755 -p $OCTAVIA_CONF_DIR sudo mkdir -m 755 -p $OCTAVIA_CONF_DIR
@ -250,7 +280,9 @@ function octavia_configure {
iniset $OCTAVIA_CONF api_settings api_handler queue_producer iniset $OCTAVIA_CONF api_settings api_handler queue_producer
iniset $OCTAVIA_CONF database connection "mysql+pymysql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_HOST}:3306/octavia" iniset $OCTAVIA_CONF database connection "mysql+pymysql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_HOST}:3306/octavia"
if [[ ${OCTAVIA_ENABLE_AMPHORAV2_PROVIDER} = True ]]; then
iniset $OCTAVIA_CONF task_flow persistence_connection "mysql+pymysql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_HOST}:3306/octavia_persistence"
fi
# Configure keystone auth_token for all users # Configure keystone auth_token for all users
configure_keystone_authtoken_middleware $OCTAVIA_CONF octavia configure_keystone_authtoken_middleware $OCTAVIA_CONF octavia
@ -324,12 +356,22 @@ function octavia_configure {
if [ $OCTAVIA_NODE == 'main' ] || [ $OCTAVIA_NODE == 'standalone' ] || [ $OCTAVIA_NODE == 'api' ]; then if [ $OCTAVIA_NODE == 'main' ] || [ $OCTAVIA_NODE == 'standalone' ] || [ $OCTAVIA_NODE == 'api' ]; then
recreate_database_mysql octavia recreate_database_mysql octavia
octavia-db-manage upgrade head octavia-db-manage upgrade head
if [[ ${OCTAVIA_ENABLE_AMPHORAV2_PROVIDER} = True ]]; then
recreate_database_mysql octavia_persistence
octavia-db-manage upgrade_persistence
fi
fi fi
if [[ -a $OCTAVIA_CERTS_DIR ]] ; then if [[ -a $OCTAVIA_CERTS_DIR ]] ; then
rm -rf $OCTAVIA_CERTS_DIR rm -rf $OCTAVIA_CERTS_DIR
fi fi
# amphorav2 required redis installation
if [[ ${OCTAVIA_ENABLE_AMPHORAV2_PROVIDER} = True ]]; then
install_redis
fi
if [[ "$(trueorfalse False OCTAVIA_USE_PREGENERATED_CERTS)" == "True" ]]; then if [[ "$(trueorfalse False OCTAVIA_USE_PREGENERATED_CERTS)" == "True" ]]; then
cp -rfp ${OCTAVIA_PREGENERATED_CERTS_DIR} ${OCTAVIA_CERTS_DIR} cp -rfp ${OCTAVIA_PREGENERATED_CERTS_DIR} ${OCTAVIA_CERTS_DIR}
else else
@ -615,6 +657,10 @@ function octavia_cleanup {
sudo rm -rf $NOVA_STATE_PATH $NOVA_AUTH_CACHE_DIR sudo rm -rf $NOVA_STATE_PATH $NOVA_AUTH_CACHE_DIR
if [[ ${OCTAVIA_ENABLE_AMPHORAV2_PROVIDER} = True ]]; then
uninstall_redis
fi
sudo rm -f /etc/rsyslog.d/10-octavia-log-offloading.conf sudo rm -f /etc/rsyslog.d/10-octavia-log-offloading.conf
restart_service rsyslog restart_service rsyslog

View File

@ -33,6 +33,8 @@ OCTAVIA_PORT=${OCTAVIA_PORT:-"9876"}
OCTAVIA_HA_PORT=${OCTAVIA_HA_PORT:-"9875"} OCTAVIA_HA_PORT=${OCTAVIA_HA_PORT:-"9875"}
OCTAVIA_HM_LISTEN_PORT=${OCTAVIA_HM_LISTEN_PORT:-"5555"} OCTAVIA_HM_LISTEN_PORT=${OCTAVIA_HM_LISTEN_PORT:-"5555"}
OCTAVIA_ENABLE_AMPHORAV2_PROVIDER=${OCTAVIA_ENABLE_AMPHORAV2_PROVIDER:-False}
OCTAVIA_MGMT_SUBNET=${OCTAVIA_MGMT_SUBNET:-"192.168.0.0/24"} OCTAVIA_MGMT_SUBNET=${OCTAVIA_MGMT_SUBNET:-"192.168.0.0/24"}
OCTAVIA_MGMT_SUBNET_START=${OCTAVIA_MGMT_SUBNET_START:-"192.168.0.2"} OCTAVIA_MGMT_SUBNET_START=${OCTAVIA_MGMT_SUBNET_START:-"192.168.0.2"}
OCTAVIA_MGMT_SUBNET_END=${OCTAVIA_MGMT_SUBNET_END:-"192.168.0.200"} OCTAVIA_MGMT_SUBNET_END=${OCTAVIA_MGMT_SUBNET_END:-"192.168.0.200"}

View File

@ -0,0 +1,31 @@
..
Copyright 2020 Mirantis Inc.
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.
Amphorav2
=========
This is extension of the reference driver for Octavia. It adopts taskflow
jobboard feature and saves task states into the persistence backend, this
allows to continue task execution if controller work was interrupted.
Default provider name: **amphorav2**
The driver package: https://pypi.org/project/octavia/
The driver source: https://opendev.org/openstack/octavia/
The documentation: https://docs.openstack.org/octavia/latest/
Where to report issues with the driver: https://storyboard.openstack.org/#!/project/openstack/octavia

View File

@ -45,6 +45,8 @@ your Octavia API instances.
.. include:: amphora.rst .. include:: amphora.rst
.. include:: amphorav2.rst
.. include:: f5.rst .. include:: f5.rst
.. include:: ovn.rst .. include:: ovn.rst

View File

@ -0,0 +1,84 @@
.. _install-amphorav2:
Additional configuration steps to configure amphorav2 provider
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you would like to use amphorav2 provider for load-balancer service the
following additional steps are required.
Prerequisites
-------------
Amphorav2 provider requires creation of additional database
``octavia_persistence`` to store info about state of tasks and progress of its
execution.
Also to monitor progress on taskflow jobs amphorav2 provider uses
jobboard. As jobboard backend could be used Redis or Zookeeper key-value
storages. Operator should chose the one that is more preferable for specific
cloud. The default is Redis.
1. Create the database, complete these steps:
* Use the database access client to connect to the database
server as the ``root`` user:
.. code-block:: console
# mysql
* Create the ``octavia_persistence`` database:
.. code-block:: console
CREATE DATABASE octavia_persistence;
* Grant proper access to the ``octavia_persistence`` database:
.. code-block:: console
GRANT ALL PRIVILEGES ON octavia.* TO 'octavia_persistence'@'localhost' \
IDENTIFIED BY 'OCTAVIA_DBPASS';
GRANT ALL PRIVILEGES ON octavia.* TO 'octavia_persistence'@'%' \
IDENTIFIED BY 'OCTAVIA_DBPASS';
Replace OCTAVIA_DBPASS with a suitable password.
2. Install desired key-value backend (Redis or Zookeper).
Additional configuration to octavia components
----------------------------------------------
1. Edit the ``/etc/octavia/octavia.conf`` file ``[task_flow]`` section
* Configure database access for persistence backend:
.. code-block:: ini
[task_flow]
persistence_connection = mysql+pymysql://octavia:OCTAVIA_DBPASS@controller/octavia_persistence
Replace OCTAVIA_DBPASS with the password you chose for the Octavia databases.
* Set desired jobboard backend and its configuration:
.. code-block:: ini
[task_flow]
jobboard_backend_driver = 'redis_taskflow_driver'
jobboard_backend_hosts = KEYVALUE_HOST_IPS
jobboard_backend_port = KEYVALUE_PORT
jobboard_backend_password = OCTAVIA_JOBBOARDPASS
jobboard_backend_namespace = 'octavia_jobboard'
Replace OCTAVIA_JOBBOARDPASS with the password you chose for the Octavia
key-value storage.
Replace KEYVALUE_HOST_IPS and KEYVALUE_PORT with ip and port which
chosen key-value storage is using.
2. Populate the octavia database:
.. code-block:: console
# octavia-db-manage --config-file /etc/octavia/octavia.conf upgrade_persistence

View File

@ -17,3 +17,4 @@ Note that installation and configuration vary by distribution.
:maxdepth: 2 :maxdepth: 2
install-ubuntu.rst install-ubuntu.rst
install-amphorav2.rst

View File

@ -289,6 +289,49 @@
# for debugging purposes. # for debugging purposes.
# disable_revert = False # disable_revert = False
# Persistence database, which will be used to store tasks states.
# Database connection url with db name (string value)
#persistence_connection = sqlite://
# Jobboard backend driver that will monitor job state. (string value)
# Possible values:
# - redis_taskflow_driver: Driver that will use Redis to store job states.
# - zookeeper_taskflow_driver: Driver that will use Zookeeper to store job
# states.
#jobboard_backend_driver = redis_taskflow_driver
# Jobboard backend server host(s). (list value)
#jobboard_backend_hosts = 127.0.0.1
# Jobboard backend server port (port value)
# Minimum value: 0
# Maximum value: 65535
#jobboard_backend_port = 6379
# Jobboard backend server password (string value)
#jobboard_backend_password =
# Jobboard name that should be used to store taskflow job id and
# claims for it. (string value)
#jobboard_backend_namespace = octavia_jobboard
# Redis jobboard backend ssl configuration options. (dict value)
# SSL is disabled by default
#jobboard_redis_backend_ssl_options = ssl:False,ssl_ca_certs:None,ssl_cert_reqs:required,ssl_certfile:None,ssl_keyfile:None
# Zookeeper jobboard backend ssl configuration options. (dict value)
# SSL is disabled by default
#jobboard_zookeeper_ssl_options = use_ssl:False,certfile:None,keyfile:None,keyfile_password:None,verify_certs:True
# For backends like redis claiming jobs requiring setting the expiry -
# how many seconds the claim should be retained for. (integer value)
#jobboard_expiration_time = 30
# If for analysis required saving logbooks info, set this parameter to
# True. By default remove logbook from persistence backend when job
# completed. (boolean value)
#jobboard_save_logbook = false
[oslo_messaging] [oslo_messaging]
# Queue Consumer Thread Pool Size # Queue Consumer Thread Pool Size
# rpc_thread_pool_size = 2 # rpc_thread_pool_size = 2

View File

@ -149,12 +149,13 @@ Sphinx==1.6.2
sphinxcontrib-svg2pdfconverter==0.1.0 sphinxcontrib-svg2pdfconverter==0.1.0
sphinxcontrib-websupport==1.0.1 sphinxcontrib-websupport==1.0.1
SQLAlchemy==1.0.10 SQLAlchemy==1.0.10
SQLAlchemy-Utils==0.30.11
sqlalchemy-migrate==0.11.0 sqlalchemy-migrate==0.11.0
sqlparse==0.2.4 sqlparse==0.2.4
statsd==3.2.2 statsd==3.2.2
stestr==2.0.0 stestr==2.0.0
stevedore==1.20.0 stevedore==1.20.0
taskflow==2.16.0 taskflow==4.1.0
tempest==17.1.0 tempest==17.1.0
Tempita==0.5.2 Tempita==0.5.2
tenacity==5.0.4 tenacity==5.0.4

View File

@ -14,6 +14,7 @@
import copy import copy
from dateutil import parser
import netaddr import netaddr
from wsme import types as wtypes from wsme import types as wtypes
@ -127,12 +128,19 @@ class BaseType(wtypes.Base, metaclass=BaseMeta):
:param data_model: data model to convert from :param data_model: data model to convert from
:param children: convert child data models :param children: convert child data models
""" """
type_dict = data_model.to_dict()
# We need to have json convertible data for storing it in persistence
# jobboard backend.
for k, v in type_dict.items():
if ('_at' in k or 'expiration' in k) and v is not None:
type_dict[k] = parser.parse(v)
if not hasattr(cls, '_type_to_model_map'): if not hasattr(cls, '_type_to_model_map'):
return cls(**data_model.to_dict()) return cls(**type_dict)
dm_to_type_map = {value: key dm_to_type_map = {value: key
for key, value in cls._type_to_model_map.items()} for key, value in cls._type_to_model_map.items()}
type_dict = data_model.to_dict()
new_dict = copy.deepcopy(type_dict) new_dict = copy.deepcopy(type_dict)
for key, value in type_dict.items(): for key, value in type_dict.items():
if isinstance(value, dict): if isinstance(value, dict):

View File

@ -98,10 +98,15 @@ class FailoverController(base.BaseController):
def __init__(self, amp_id): def __init__(self, amp_id):
super(FailoverController, self).__init__() super(FailoverController, self).__init__()
topic = cfg.CONF.oslo_messaging.topic if CONF.api_settings.default_provider_driver == constants.AMPHORAV2:
topic = constants.TOPIC_AMPHORA_V2
version = "2.0"
else:
topic = cfg.CONF.oslo_messaging.topic
version = "1.0"
self.target = messaging.Target( self.target = messaging.Target(
namespace=constants.RPC_NAMESPACE_CONTROLLER_AGENT, namespace=constants.RPC_NAMESPACE_CONTROLLER_AGENT,
topic=topic, version="1.0", fanout=False) topic=topic, version=version, fanout=False)
self.client = rpc.get_client(self.target) self.client = rpc.get_client(self.target)
self.amp_id = amp_id self.amp_id = amp_id
@ -143,11 +148,17 @@ class AmphoraUpdateController(base.BaseController):
def __init__(self, amp_id): def __init__(self, amp_id):
super(AmphoraUpdateController, self).__init__() super(AmphoraUpdateController, self).__init__()
topic = cfg.CONF.oslo_messaging.topic
if CONF.api_settings.default_provider_driver == constants.AMPHORAV2:
topic = constants.TOPIC_AMPHORA_V2
version = "2.0"
else:
topic = cfg.CONF.oslo_messaging.topic
version = "1.0"
self.transport = messaging.get_rpc_transport(cfg.CONF) self.transport = messaging.get_rpc_transport(cfg.CONF)
self.target = messaging.Target( self.target = messaging.Target(
namespace=constants.RPC_NAMESPACE_CONTROLLER_AGENT, namespace=constants.RPC_NAMESPACE_CONTROLLER_AGENT,
topic=topic, version="1.0", fanout=False) topic=topic, version=version, fanout=False)
self.client = messaging.RPCClient(self.transport, target=self.target) self.client = messaging.RPCClient(self.transport, target=self.target)
self.amp_id = amp_id self.amp_id = amp_id

View File

@ -15,14 +15,38 @@
import concurrent.futures import concurrent.futures
import datetime import datetime
import functools
from oslo_config import cfg from oslo_config import cfg
from taskflow import engines as tf_engines from oslo_log import log
from oslo_utils import uuidutils
from taskflow.conductors.backends import impl_blocking
from taskflow import engines
from taskflow import exceptions as taskflow_exc
from taskflow.listeners import base
from taskflow.listeners import logging
from taskflow.persistence import models
from taskflow import states
from octavia.amphorae.driver_exceptions import exceptions
LOG = log.getLogger(__name__)
CONF = cfg.CONF CONF = cfg.CONF
# We do not need to log retry exception information. Warning "Could not connect
# to instance" will be logged as usual.
def retryMaskFilter(record):
if record.exc_info is not None and isinstance(
record.exc_info[1], exceptions.AmpConnectionRetry):
return False
return True
LOG.logger.addFilter(retryMaskFilter)
class BaseTaskFlowEngine(object): class BaseTaskFlowEngine(object):
"""This is the task flow engine """This is the task flow engine
@ -37,7 +61,7 @@ class BaseTaskFlowEngine(object):
max_workers=CONF.task_flow.max_workers) max_workers=CONF.task_flow.max_workers)
def _taskflow_load(self, flow, **kwargs): def _taskflow_load(self, flow, **kwargs):
eng = tf_engines.load( eng = engines.load(
flow, flow,
engine=CONF.task_flow.engine, engine=CONF.task_flow.engine,
executor=self.executor, executor=self.executor,
@ -47,3 +71,108 @@ class BaseTaskFlowEngine(object):
eng.prepare() eng.prepare()
return eng return eng
class ExtendExpiryListener(base.Listener):
def __init__(self, engine, job):
super(ExtendExpiryListener, self).__init__(engine)
self.job = job
def _task_receiver(self, state, details):
self.job.extend_expiry(cfg.CONF.task_flow.jobboard_expiration_time)
def _flow_receiver(self, state, details):
self.job.extend_expiry(cfg.CONF.task_flow.jobboard_expiration_time)
def _retry_receiver(self, state, details):
self.job.extend_expiry(cfg.CONF.task_flow.jobboard_expiration_time)
class DynamicLoggingConductor(impl_blocking.BlockingConductor):
def _listeners_from_job(self, job, engine):
listeners = super(DynamicLoggingConductor, self)._listeners_from_job(
job, engine)
listeners.append(logging.DynamicLoggingListener(engine, log=LOG))
return listeners
def _on_job_done(self, job, fut):
super(DynamicLoggingConductor, self)._on_job_done(job, fut)
# Double check that job is complete.
if (not CONF.task_flow.jobboard_save_logbook and
job.state == states.COMPLETE):
LOG.debug("Job %s is complete. Cleaning up job logbook.", job.name)
try:
self._persistence.get_connection().destroy_logbook(
job.book.uuid)
except taskflow_exc.NotFound:
LOG.debug("Logbook for job %s has been already cleaned up",
job.name)
class RedisDynamicLoggingConductor(DynamicLoggingConductor):
def _listeners_from_job(self, job, engine):
listeners = super(RedisDynamicLoggingConductor,
self)._listeners_from_job(job, engine)
listeners.append(ExtendExpiryListener(engine, job))
return listeners
class TaskFlowServiceController(object):
def __init__(self, driver):
self.driver = driver
def run_poster(self, flow_factory, *args, wait=False, **kwargs):
with self.driver.persistence_driver.get_persistence() as persistence:
with self.driver.job_board(persistence) as job_board:
job_id = uuidutils.generate_uuid()
job_name = '-'.join([flow_factory.__name__, job_id])
job_logbook = models.LogBook(job_name)
flow_detail = models.FlowDetail(
job_name, job_id)
job_details = {
'store': kwargs.pop('store')
}
job_logbook.add(flow_detail)
persistence.get_connection().save_logbook(job_logbook)
engines.save_factory_details(flow_detail, flow_factory,
args, kwargs,
backend=persistence)
job_board.post(job_name, book=job_logbook,
details=job_details)
if wait:
self._wait_for_job(job_board)
return job_id
def _wait_for_job(self, job_board):
# Wait for job to its complete state
for job in job_board.iterjobs():
LOG.debug("Waiting for job %s to finish", job.name)
job.wait()
def run_conductor(self, name):
with self.driver.persistence_driver.get_persistence() as persistence:
with self.driver.job_board(persistence) as board:
# Redis do not expire jobs by default, so jobs won't be resumed
# with restart of controller. Add expiry for board and use
# special listener.
if (CONF.task_flow.jobboard_backend_driver ==
'redis_taskflow_driver'):
conductor = RedisDynamicLoggingConductor(
name, board, persistence=persistence,
engine=CONF.task_flow.engine)
board.claim = functools.partial(
board.claim,
expiry=CONF.task_flow.jobboard_expiration_time)
else:
conductor = DynamicLoggingConductor(
name, board, persistence=persistence,
engine=CONF.task_flow.engine)
conductor.run()

View File

@ -92,7 +92,8 @@ api_opts = [
'Amphora driver.'), 'Amphora driver.'),
default={'amphora': 'The Octavia Amphora driver.', default={'amphora': 'The Octavia Amphora driver.',
'octavia': 'Deprecated alias of the Octavia Amphora ' 'octavia': 'Deprecated alias of the Octavia Amphora '
'driver.'}), 'driver.',
}),
cfg.StrOpt('default_provider_driver', default='amphora', cfg.StrOpt('default_provider_driver', default='amphora',
help=_('Default provider driver.')), help=_('Default provider driver.')),
cfg.IntOpt('udp_connect_min_interval_health_monitor', cfg.IntOpt('udp_connect_min_interval_health_monitor',
@ -461,7 +462,46 @@ task_flow_opts = [
help=_('If True, disables the controller worker taskflow ' help=_('If True, disables the controller worker taskflow '
'flows from reverting. This will leave resources in ' 'flows from reverting. This will leave resources in '
'an inconsistent state and should only be used for ' 'an inconsistent state and should only be used for '
'debugging purposes.')) 'debugging purposes.')),
cfg.StrOpt('persistence_connection',
default='sqlite://',
help='Persistence database, which will be used to store tasks '
'states. Database connection url with db name'),
cfg.StrOpt('jobboard_backend_driver',
default='redis_taskflow_driver',
choices=['redis_taskflow_driver', 'zookeeper_taskflow_driver'],
help='Jobboard backend driver that will monitor job state.'),
cfg.ListOpt('jobboard_backend_hosts', default=['127.0.0.1'],
help='Jobboard backend server host(s).'),
cfg.PortOpt('jobboard_backend_port', default=6379,
help='Jobboard backend server port'),
cfg.StrOpt('jobboard_backend_password', default='', secret=True,
help='Jobboard backend server password'),
cfg.StrOpt('jobboard_backend_namespace', default='octavia_jobboard',
help='Jobboard name that should be used to store taskflow '
'job id and claims for it.'),
cfg.DictOpt('jobboard_redis_backend_ssl_options',
help='Redis jobboard backend ssl configuration options.',
default={'ssl': False,
'ssl_keyfile': None,
'ssl_certfile': None,
'ssl_ca_certs': None,
'ssl_cert_reqs': 'required'}),
cfg.DictOpt('jobboard_zookeeper_ssl_options',
help='Zookeeper jobboard backend ssl configuration options.',
default={'use_ssl': False,
'keyfile': None,
'keyfile_password': None,
'certfile': None,
'verify_certs': True}),
cfg.IntOpt('jobboard_expiration_time', default=30,
help='For backends like redis claiming jobs requiring setting '
'the expiry - how many seconds the claim should be '
'retained for.'),
cfg.BoolOpt('jobboard_save_logbook', default=False,
help='If for analysis required saving logbooks info, set this '
'parameter to True. By default remove logbook from '
'persistence backend when job completed.'),
] ]
core_cli_opts = [] core_cli_opts = []

View File

@ -718,6 +718,7 @@ RBAC_GET_STATUS = 'get_status'
# PROVIDERS # PROVIDERS
OCTAVIA = 'octavia' OCTAVIA = 'octavia'
AMPHORAV2 = 'amphorav2'
# systemctl commands # systemctl commands
DISABLE = 'disable' DISABLE = 'disable'

View File

@ -14,6 +14,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 datetime
import re import re
from sqlalchemy.orm import collections from sqlalchemy.orm import collections
@ -34,7 +35,11 @@ class BaseDataModel(object):
# tags is a list, it doesn't need recurse # tags is a list, it doesn't need recurse
ret[attr] = value ret[attr] = value
continue continue
# We need to have json convertible data for storing it in
# persistence jobboard backend.
if isinstance(value, datetime.datetime):
ret[attr] = value.isoformat()
continue
if recurse: if recurse:
if isinstance(getattr(self, attr), list): if isinstance(getattr(self, attr), list):
ret[attr] = [] ret[attr] = []

View File

@ -23,7 +23,8 @@ from oslo_log import log as logging
from oslo_utils import excutils from oslo_utils import excutils
from octavia.common import constants from octavia.common import constants
from octavia.controller.worker.v1 import controller_worker as cw from octavia.controller.worker.v1 import controller_worker as cw1
from octavia.controller.worker.v2 import controller_worker as cw2
from octavia.db import api as db_api from octavia.db import api as db_api
from octavia.db import repositories as repo from octavia.db import repositories as repo
@ -57,7 +58,10 @@ def update_stats_on_done(stats, fut):
class HealthManager(object): class HealthManager(object):
def __init__(self, exit_event): def __init__(self, exit_event):
self.cw = cw.ControllerWorker() if CONF.api_settings.default_provider_driver == constants.AMPHORAV2:
self.cw = cw2.ControllerWorker()
else:
self.cw = cw1.ControllerWorker()
self.threads = CONF.health_manager.failover_threads self.threads = CONF.health_manager.failover_threads
self.executor = futures.ThreadPoolExecutor(max_workers=self.threads) self.executor = futures.ThreadPoolExecutor(max_workers=self.threads)
self.amp_repo = repo.AmphoraRepository() self.amp_repo = repo.AmphoraRepository()

View File

@ -21,7 +21,8 @@ from oslo_utils import timeutils
from sqlalchemy.orm import exc as sqlalchemy_exceptions from sqlalchemy.orm import exc as sqlalchemy_exceptions
from octavia.common import constants from octavia.common import constants
from octavia.controller.worker.v1 import controller_worker as cw from octavia.controller.worker.v1 import controller_worker as cw1
from octavia.controller.worker.v2 import controller_worker as cw2
from octavia.db import api as db_api from octavia.db import api as db_api
from octavia.db import repositories as repo from octavia.db import repositories as repo
@ -34,7 +35,12 @@ class SpareAmphora(object):
self.amp_repo = repo.AmphoraRepository() self.amp_repo = repo.AmphoraRepository()
self.spares_repo = repo.SparesPoolRepository() self.spares_repo = repo.SparesPoolRepository()
self.az_repo = repo.AvailabilityZoneRepository() self.az_repo = repo.AvailabilityZoneRepository()
self.cw = cw.ControllerWorker() if CONF.api_settings.default_provider_driver == constants.AMPHORAV2:
self.cw = cw2.ControllerWorker()
self.check_booting_amphora = True
else:
self.cw = cw1.ControllerWorker()
self.check_booting_amphora = False
def spare_check(self): def spare_check(self):
"""Checks the DB for the Spare amphora count. """Checks the DB for the Spare amphora count.
@ -74,7 +80,8 @@ class SpareAmphora(object):
# will function more accurately if the operator actually # will function more accurately if the operator actually
# configures the AZ setting properly. # configures the AZ setting properly.
curr_spare_cnt = self.amp_repo.get_spare_amphora_count( curr_spare_cnt = self.amp_repo.get_spare_amphora_count(
session, availability_zone=az_name) session, availability_zone=az_name,
check_booting_amphora=self.check_booting_amphora)
LOG.debug("Current Spare Amphora count for AZ %s: %d", LOG.debug("Current Spare Amphora count for AZ %s: %d",
az_name, curr_spare_cnt) az_name, curr_spare_cnt)
diff_count = conf_spare_cnt - curr_spare_cnt diff_count = conf_spare_cnt - curr_spare_cnt
@ -151,7 +158,10 @@ class DatabaseCleanup(object):
class CertRotation(object): class CertRotation(object):
def __init__(self): def __init__(self):
self.threads = CONF.house_keeping.cert_rotate_threads self.threads = CONF.house_keeping.cert_rotate_threads
self.cw = cw.ControllerWorker() if CONF.api_settings.default_provider_driver == constants.AMPHORAV2:
self.cw = cw2.ControllerWorker()
else:
self.cw = cw1.ControllerWorker()
def rotate(self): def rotate(self):
"""Check the amphora db table for expiring auth certs.""" """Check the amphora db table for expiring auth certs."""

View File

@ -16,6 +16,7 @@ import cotyledon
from oslo_log import log as logging from oslo_log import log as logging
import oslo_messaging as messaging import oslo_messaging as messaging
from oslo_messaging.rpc import dispatcher from oslo_messaging.rpc import dispatcher
from oslo_utils import uuidutils
from octavia.common import constants from octavia.common import constants
from octavia.common import rpc from octavia.common import rpc
@ -46,6 +47,9 @@ class ConsumerService(cotyledon.Service):
access_policy=self.access_policy access_policy=self.access_policy
) )
self.message_listener.start() self.message_listener.start()
for e in self.endpoints:
e.worker.services_controller.run_conductor(
'octavia-task-flow-conductor-%s' % uuidutils.generate_uuid())
def terminate(self): def terminate(self):
if self.message_listener: if self.message_listener:

View File

@ -13,26 +13,18 @@
# under the License. # under the License.
# #
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import excutils from oslo_utils import excutils
from sqlalchemy.orm import exc as db_exceptions from sqlalchemy.orm import exc as db_exceptions
from taskflow.listeners import logging as tf_logging from stevedore import driver as stevedore_driver
import tenacity import tenacity
from octavia.amphorae.driver_exceptions import exceptions
from octavia.api.drivers import utils as provider_utils from octavia.api.drivers import utils as provider_utils
from octavia.common import base_taskflow from octavia.common import base_taskflow
from octavia.common import constants from octavia.common import constants
from octavia.controller.worker.v2.flows import amphora_flows from octavia.controller.worker.v2.flows import flow_utils
from octavia.controller.worker.v2.flows import health_monitor_flows from octavia.controller.worker.v2 import taskflow_jobboard_driver as tsk_driver
from octavia.controller.worker.v2.flows import l7policy_flows
from octavia.controller.worker.v2.flows import l7rule_flows
from octavia.controller.worker.v2.flows import listener_flows
from octavia.controller.worker.v2.flows import load_balancer_flows
from octavia.controller.worker.v2.flows import member_flows
from octavia.controller.worker.v2.flows import pool_flows
from octavia.db import api as db_apis from octavia.db import api as db_apis
from octavia.db import repositories as repo from octavia.db import repositories as repo
@ -45,35 +37,14 @@ RETRY_BACKOFF = 1
RETRY_MAX = 5 RETRY_MAX = 5
# We do not need to log retry exception information. Warning "Could not connect
# to instance" will be logged as usual.
def retryMaskFilter(record):
if record.exc_info is not None and isinstance(
record.exc_info[1], exceptions.AmpConnectionRetry):
return False
return True
LOG.logger.addFilter(retryMaskFilter)
def _is_provisioning_status_pending_update(lb_obj): def _is_provisioning_status_pending_update(lb_obj):
return not lb_obj.provisioning_status == constants.PENDING_UPDATE return not lb_obj.provisioning_status == constants.PENDING_UPDATE
class ControllerWorker(base_taskflow.BaseTaskFlowEngine): class ControllerWorker(object):
def __init__(self): def __init__(self):
self._amphora_flows = amphora_flows.AmphoraFlows()
self._health_monitor_flows = health_monitor_flows.HealthMonitorFlows()
self._lb_flows = load_balancer_flows.LoadBalancerFlows()
self._listener_flows = listener_flows.ListenerFlows()
self._member_flows = member_flows.MemberFlows()
self._pool_flows = pool_flows.PoolFlows()
self._l7policy_flows = l7policy_flows.L7PolicyFlows()
self._l7rule_flows = l7rule_flows.L7RuleFlows()
self._amphora_repo = repo.AmphoraRepository() self._amphora_repo = repo.AmphoraRepository()
self._amphora_health_repo = repo.AmphoraHealthRepository() self._amphora_health_repo = repo.AmphoraHealthRepository()
self._health_mon_repo = repo.HealthMonitorRepository() self._health_mon_repo = repo.HealthMonitorRepository()
@ -86,7 +57,13 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
self._flavor_repo = repo.FlavorRepository() self._flavor_repo = repo.FlavorRepository()
self._az_repo = repo.AvailabilityZoneRepository() self._az_repo = repo.AvailabilityZoneRepository()
super(ControllerWorker, self).__init__() persistence = tsk_driver.MysqlPersistenceDriver()
self.jobboard_driver = stevedore_driver.DriverManager(
namespace='octavia.worker.jobboard_driver',
name=CONF.task_flow.jobboard_backend_driver,
invoke_args=(persistence,),
invoke_on_load=True).driver
@tenacity.retry( @tenacity.retry(
retry=( retry=(
@ -99,12 +76,16 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
return repo.get(db_apis.get_session(), id=id) return repo.get(db_apis.get_session(), id=id)
@property
def services_controller(self):
return base_taskflow.TaskFlowServiceController(self.jobboard_driver)
def create_amphora(self, availability_zone=None): def create_amphora(self, availability_zone=None):
"""Creates an Amphora. """Creates an Amphora.
This is used to create spare amphora. This is used to create spare amphora.
:returns: amphora_id :returns: uuid
""" """
try: try:
store = {constants.BUILD_TYPE_PRIORITY: store = {constants.BUILD_TYPE_PRIORITY:
@ -115,13 +96,11 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
store[constants.AVAILABILITY_ZONE] = ( store[constants.AVAILABILITY_ZONE] = (
self._az_repo.get_availability_zone_metadata_dict( self._az_repo.get_availability_zone_metadata_dict(
db_apis.get_session(), availability_zone)) db_apis.get_session(), availability_zone))
create_amp_tf = self._taskflow_load( job_id = self.services_controller.run_poster(
self._amphora_flows.get_create_amphora_flow(), flow_utils.get_create_amphora_flow,
store=store) store=store, wait=True)
with tf_logging.DynamicLoggingListener(create_amp_tf, log=LOG):
create_amp_tf.run()
return create_amp_tf.storage.fetch('amphora') return job_id
except Exception as e: except Exception as e:
LOG.error('Failed to create an amphora due to: {}'.format(str(e))) LOG.error('Failed to create an amphora due to: {}'.format(str(e)))
@ -134,13 +113,16 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
""" """
amphora = self._amphora_repo.get(db_apis.get_session(), amphora = self._amphora_repo.get(db_apis.get_session(),
id=amphora_id) id=amphora_id)
delete_amp_tf = self._taskflow_load( store = {constants.AMPHORA: amphora.to_dict()}
self._amphora_flows.get_delete_amphora_flow(), self.services_controller.run_poster(
store={constants.AMPHORA: amphora.to_dict()}) flow_utils.get_delete_amphora_flow,
with tf_logging.DynamicLoggingListener(delete_amp_tf, store=store)
log=LOG):
delete_amp_tf.run()
@tenacity.retry(
retry=tenacity.retry_if_exception_type(db_exceptions.NoResultFound),
wait=tenacity.wait_incrementing(
RETRY_INITIAL_DELAY, RETRY_BACKOFF, RETRY_MAX),
stop=tenacity.stop_after_attempt(RETRY_ATTEMPTS))
def create_health_monitor(self, health_monitor): def create_health_monitor(self, health_monitor):
"""Creates a health monitor. """Creates a health monitor.
@ -162,16 +144,14 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
provider_utils.db_listeners_to_provider_dicts_list_of_dicts( provider_utils.db_listeners_to_provider_dicts_list_of_dicts(
pool.listeners)) pool.listeners))
create_hm_tf = self._taskflow_load( store = {constants.HEALTH_MON: health_monitor,
self._health_monitor_flows.get_create_health_monitor_flow(), constants.POOL_ID: pool.id,
store={constants.HEALTH_MON: health_monitor, constants.LISTENERS: listeners_dicts,
constants.POOL_ID: pool.id, constants.LOADBALANCER_ID: load_balancer.id,
constants.LISTENERS: listeners_dicts, constants.LOADBALANCER: provider_lb}
constants.LOADBALANCER_ID: load_balancer.id, self.services_controller.run_poster(
constants.LOADBALANCER: provider_lb}) flow_utils.get_create_health_monitor_flow,
with tf_logging.DynamicLoggingListener(create_hm_tf, store=store)
log=LOG):
create_hm_tf.run()
def delete_health_monitor(self, health_monitor): def delete_health_monitor(self, health_monitor):
"""Deletes a health monitor. """Deletes a health monitor.
@ -193,17 +173,15 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
provider_utils.db_listeners_to_provider_dicts_list_of_dicts( provider_utils.db_listeners_to_provider_dicts_list_of_dicts(
pool.listeners)) pool.listeners))
delete_hm_tf = self._taskflow_load( store = {constants.HEALTH_MON: health_monitor,
self._health_monitor_flows.get_delete_health_monitor_flow(), constants.POOL_ID: pool.id,
store={constants.HEALTH_MON: health_monitor, constants.LISTENERS: listeners_dicts,
constants.POOL_ID: pool.id, constants.LOADBALANCER_ID: load_balancer.id,
constants.LISTENERS: listeners_dicts, constants.LOADBALANCER: provider_lb,
constants.LOADBALANCER_ID: load_balancer.id, constants.PROJECT_ID: load_balancer.project_id}
constants.LOADBALANCER: provider_lb, self.services_controller.run_poster(
constants.PROJECT_ID: load_balancer.project_id}) flow_utils.get_delete_health_monitor_flow,
with tf_logging.DynamicLoggingListener(delete_hm_tf, store=store)
log=LOG):
delete_hm_tf.run()
def update_health_monitor(self, original_health_monitor, def update_health_monitor(self, original_health_monitor,
health_monitor_updates): health_monitor_updates):
@ -236,18 +214,21 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer( provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer(
load_balancer).to_dict() load_balancer).to_dict()
update_hm_tf = self._taskflow_load( store = {constants.HEALTH_MON: original_health_monitor,
self._health_monitor_flows.get_update_health_monitor_flow(), constants.POOL_ID: pool.id,
store={constants.HEALTH_MON: original_health_monitor, constants.LISTENERS: listeners_dicts,
constants.POOL_ID: pool.id, constants.LOADBALANCER_ID: load_balancer.id,
constants.LISTENERS: listeners_dicts, constants.LOADBALANCER: provider_lb,
constants.LOADBALANCER_ID: load_balancer.id, constants.UPDATE_DICT: health_monitor_updates}
constants.LOADBALANCER: provider_lb, self.services_controller.run_poster(
constants.UPDATE_DICT: health_monitor_updates}) flow_utils.get_update_health_monitor_flow,
with tf_logging.DynamicLoggingListener(update_hm_tf, store=store)
log=LOG):
update_hm_tf.run()
@tenacity.retry(
retry=tenacity.retry_if_exception_type(db_exceptions.NoResultFound),
wait=tenacity.wait_incrementing(
RETRY_INITIAL_DELAY, RETRY_BACKOFF, RETRY_MAX),
stop=tenacity.stop_after_attempt(RETRY_ATTEMPTS))
def create_listener(self, listener): def create_listener(self, listener):
"""Creates a listener. """Creates a listener.
@ -272,14 +253,13 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer( provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer(
load_balancer).to_dict() load_balancer).to_dict()
create_listener_tf = self._taskflow_load( store = {constants.LISTENERS: dict_listeners,
self._listener_flows.get_create_listener_flow(), constants.LOADBALANCER: provider_lb,
store={constants.LISTENERS: dict_listeners, constants.LOADBALANCER_ID: load_balancer.id}
constants.LOADBALANCER: provider_lb,
constants.LOADBALANCER_ID: load_balancer.id}) self.services_controller.run_poster(
with tf_logging.DynamicLoggingListener(create_listener_tf, flow_utils.get_create_listener_flow,
log=LOG): store=store)
create_listener_tf.run()
def delete_listener(self, listener): def delete_listener(self, listener):
"""Deletes a listener. """Deletes a listener.
@ -292,15 +272,13 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
# the project ID # the project ID
lb = self._lb_repo.get(db_apis.get_session(), lb = self._lb_repo.get(db_apis.get_session(),
id=listener[constants.LOADBALANCER_ID]) id=listener[constants.LOADBALANCER_ID])
delete_listener_tf = self._taskflow_load( store = {constants.LISTENER: listener,
self._listener_flows.get_delete_listener_flow(), constants.LOADBALANCER_ID:
store={constants.LISTENER: listener, listener[constants.LOADBALANCER_ID],
constants.LOADBALANCER_ID: constants.PROJECT_ID: lb.project_id}
listener[constants.LOADBALANCER_ID], self.services_controller.run_poster(
constants.PROJECT_ID: lb.project_id}) flow_utils.get_delete_listener_flow,
with tf_logging.DynamicLoggingListener(delete_listener_tf, store=store)
log=LOG):
delete_listener_tf.run()
def update_listener(self, listener, listener_updates): def update_listener(self, listener, listener_updates):
"""Updates a listener. """Updates a listener.
@ -312,14 +290,13 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
""" """
db_lb = self._lb_repo.get(db_apis.get_session(), db_lb = self._lb_repo.get(db_apis.get_session(),
id=listener[constants.LOADBALANCER_ID]) id=listener[constants.LOADBALANCER_ID])
update_listener_tf = self._taskflow_load( store = {constants.LISTENER: listener,
self._listener_flows.get_update_listener_flow(), constants.UPDATE_DICT: listener_updates,
store={constants.LISTENER: listener, constants.LOADBALANCER_ID: db_lb.id,
constants.UPDATE_DICT: listener_updates, constants.LISTENERS: [listener]}
constants.LOADBALANCER_ID: db_lb.id, self.services_controller.run_poster(
constants.LISTENERS: [listener]}) flow_utils.get_update_listener_flow,
with tf_logging.DynamicLoggingListener(update_listener_tf, log=LOG): store=store)
update_listener_tf.run()
@tenacity.retry( @tenacity.retry(
retry=tenacity.retry_if_exception_type(db_exceptions.NoResultFound), retry=tenacity.retry_if_exception_type(db_exceptions.NoResultFound),
@ -364,13 +341,10 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
store[constants.UPDATE_DICT] = { store[constants.UPDATE_DICT] = {
constants.TOPOLOGY: topology constants.TOPOLOGY: topology
} }
self.services_controller.run_poster(
create_lb_flow = self._lb_flows.get_create_load_balancer_flow( flow_utils.get_create_load_balancer_flow,
topology=topology, listeners=listeners_dicts) topology, listeners=listeners_dicts,
store=store)
create_lb_tf = self._taskflow_load(create_lb_flow, store=store)
with tf_logging.DynamicLoggingListener(create_lb_tf, log=LOG):
create_lb_tf.run()
def delete_load_balancer(self, load_balancer, cascade=False): def delete_load_balancer(self, load_balancer, cascade=False):
"""Deletes a load balancer by de-allocating Amphorae. """Deletes a load balancer by de-allocating Amphorae.
@ -381,25 +355,19 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
""" """
db_lb = self._lb_repo.get(db_apis.get_session(), db_lb = self._lb_repo.get(db_apis.get_session(),
id=load_balancer[constants.LOADBALANCER_ID]) id=load_balancer[constants.LOADBALANCER_ID])
store = {} store = {constants.LOADBALANCER: load_balancer,
constants.SERVER_GROUP_ID: db_lb.server_group_id,
constants.PROJECT_ID: db_lb.project_id}
if cascade: if cascade:
flow = self._lb_flows.get_cascade_delete_load_balancer_flow( store.update(flow_utils.get_delete_pools_store(db_lb))
load_balancer) store.update(flow_utils.get_delete_listeners_store(db_lb))
store.update(self._lb_flows.get_delete_pools_store(db_lb)) self.services_controller.run_poster(
store.update(self._lb_flows.get_delete_listeners_store(db_lb)) flow_utils.get_cascade_delete_load_balancer_flow,
load_balancer, store=store)
else: else:
flow = self._lb_flows.get_delete_load_balancer_flow( self.services_controller.run_poster(
load_balancer) flow_utils.get_delete_load_balancer_flow,
store.update({constants.LOADBALANCER: load_balancer, load_balancer, store=store)
constants.SERVER_GROUP_ID: db_lb.server_group_id,
constants.PROJECT_ID: db_lb.project_id})
delete_lb_tf = self._taskflow_load(flow, store=store)
with tf_logging.DynamicLoggingListener(delete_lb_tf,
log=LOG):
delete_lb_tf.run()
def update_load_balancer(self, original_load_balancer, def update_load_balancer(self, original_load_balancer,
load_balancer_updates): load_balancer_updates):
@ -410,17 +378,14 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
:returns: None :returns: None
:raises LBNotFound: The referenced load balancer was not found :raises LBNotFound: The referenced load balancer was not found
""" """
store = {constants.LOADBALANCER: original_load_balancer,
constants.LOADBALANCER_ID:
original_load_balancer[constants.LOADBALANCER_ID],
constants.UPDATE_DICT: load_balancer_updates}
update_lb_tf = self._taskflow_load( self.services_controller.run_poster(
self._lb_flows.get_update_load_balancer_flow(), flow_utils.get_update_load_balancer_flow,
store={constants.LOADBALANCER: original_load_balancer, store=store)
constants.LOADBALANCER_ID:
original_load_balancer[constants.LOADBALANCER_ID],
constants.UPDATE_DICT: load_balancer_updates})
with tf_logging.DynamicLoggingListener(update_lb_tf,
log=LOG):
update_lb_tf.run()
def create_member(self, member): def create_member(self, member):
"""Creates a pool member. """Creates a pool member.
@ -452,12 +417,9 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
else: else:
store[constants.AVAILABILITY_ZONE] = {} store[constants.AVAILABILITY_ZONE] = {}
create_member_tf = self._taskflow_load( self.services_controller.run_poster(
self._member_flows.get_create_member_flow(), flow_utils.get_create_member_flow,
store=store) store=store)
with tf_logging.DynamicLoggingListener(create_member_tf,
log=LOG):
create_member_tf.run()
def delete_member(self, member): def delete_member(self, member):
"""Deletes a pool member. """Deletes a pool member.
@ -491,13 +453,9 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
else: else:
store[constants.AVAILABILITY_ZONE] = {} store[constants.AVAILABILITY_ZONE] = {}
delete_member_tf = self._taskflow_load( self.services_controller.run_poster(
self._member_flows.get_delete_member_flow(), flow_utils.get_delete_member_flow,
store=store store=store)
)
with tf_logging.DynamicLoggingListener(delete_member_tf,
log=LOG):
delete_member_tf.run()
def batch_update_members(self, old_members, new_members, def batch_update_members(self, old_members, new_members,
updated_members): updated_members):
@ -543,13 +501,10 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
else: else:
store[constants.AVAILABILITY_ZONE] = {} store[constants.AVAILABILITY_ZONE] = {}
batch_update_members_tf = self._taskflow_load( self.services_controller.run_poster(
self._member_flows.get_batch_update_members_flow( flow_utils.get_batch_update_members_flow,
provider_old_members, new_members, updated_members), provider_old_members, new_members, updated_members,
store=store) store=store)
with tf_logging.DynamicLoggingListener(batch_update_members_tf,
log=LOG):
batch_update_members_tf.run()
def update_member(self, member, member_updates): def update_member(self, member, member_updates):
"""Updates a pool member. """Updates a pool member.
@ -584,13 +539,15 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
else: else:
store[constants.AVAILABILITY_ZONE] = {} store[constants.AVAILABILITY_ZONE] = {}
update_member_tf = self._taskflow_load( self.services_controller.run_poster(
self._member_flows.get_update_member_flow(), flow_utils.get_update_member_flow,
store=store) store=store)
with tf_logging.DynamicLoggingListener(update_member_tf,
log=LOG):
update_member_tf.run()
@tenacity.retry(
retry=tenacity.retry_if_exception_type(db_exceptions.NoResultFound),
wait=tenacity.wait_incrementing(
RETRY_INITIAL_DELAY, RETRY_BACKOFF, RETRY_MAX),
stop=tenacity.stop_after_attempt(RETRY_ATTEMPTS))
def create_pool(self, pool): def create_pool(self, pool):
"""Creates a node pool. """Creates a node pool.
@ -616,15 +573,13 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
provider_utils.db_listeners_to_provider_dicts_list_of_dicts( provider_utils.db_listeners_to_provider_dicts_list_of_dicts(
db_pool.listeners)) db_pool.listeners))
create_pool_tf = self._taskflow_load( store = {constants.POOL_ID: pool[constants.POOL_ID],
self._pool_flows.get_create_pool_flow(), constants.LISTENERS: listeners_dicts,
store={constants.POOL_ID: pool[constants.POOL_ID], constants.LOADBALANCER_ID: load_balancer.id,
constants.LISTENERS: listeners_dicts, constants.LOADBALANCER: provider_lb}
constants.LOADBALANCER_ID: load_balancer.id, self.services_controller.run_poster(
constants.LOADBALANCER: provider_lb}) flow_utils.get_create_pool_flow,
with tf_logging.DynamicLoggingListener(create_pool_tf, store=store)
log=LOG):
create_pool_tf.run()
def delete_pool(self, pool): def delete_pool(self, pool):
"""Deletes a node pool. """Deletes a node pool.
@ -644,16 +599,14 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer( provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer(
load_balancer).to_dict() load_balancer).to_dict()
delete_pool_tf = self._taskflow_load( store = {constants.POOL_ID: pool[constants.POOL_ID],
self._pool_flows.get_delete_pool_flow(), constants.LISTENERS: listeners_dicts,
store={constants.POOL_ID: pool[constants.POOL_ID], constants.LOADBALANCER: provider_lb,
constants.LISTENERS: listeners_dicts, constants.LOADBALANCER_ID: load_balancer.id,
constants.LOADBALANCER: provider_lb, constants.PROJECT_ID: db_pool.project_id}
constants.LOADBALANCER_ID: load_balancer.id, self.services_controller.run_poster(
constants.PROJECT_ID: db_pool.project_id}) flow_utils.get_delete_pool_flow,
with tf_logging.DynamicLoggingListener(delete_pool_tf, store=store)
log=LOG):
delete_pool_tf.run()
def update_pool(self, origin_pool, pool_updates): def update_pool(self, origin_pool, pool_updates):
"""Updates a node pool. """Updates a node pool.
@ -682,16 +635,14 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
provider_utils.db_listeners_to_provider_dicts_list_of_dicts( provider_utils.db_listeners_to_provider_dicts_list_of_dicts(
db_pool.listeners)) db_pool.listeners))
update_pool_tf = self._taskflow_load( store = {constants.POOL_ID: db_pool.id,
self._pool_flows.get_update_pool_flow(), constants.LISTENERS: listeners_dicts,
store={constants.POOL_ID: db_pool.id, constants.LOADBALANCER: provider_lb,
constants.LISTENERS: listeners_dicts, constants.LOADBALANCER_ID: load_balancer.id,
constants.LOADBALANCER: provider_lb, constants.UPDATE_DICT: pool_updates}
constants.LOADBALANCER_ID: load_balancer.id, self.services_controller.run_poster(
constants.UPDATE_DICT: pool_updates}) flow_utils.get_update_pool_flow,
with tf_logging.DynamicLoggingListener(update_pool_tf, store=store)
log=LOG):
update_pool_tf.run()
def create_l7policy(self, l7policy): def create_l7policy(self, l7policy):
"""Creates an L7 Policy. """Creates an L7 Policy.
@ -707,15 +658,13 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
provider_utils.db_listeners_to_provider_dicts_list_of_dicts( provider_utils.db_listeners_to_provider_dicts_list_of_dicts(
[db_listener])) [db_listener]))
create_l7policy_tf = self._taskflow_load( store = {constants.L7POLICY: l7policy,
self._l7policy_flows.get_create_l7policy_flow(), constants.LISTENERS: listeners_dicts,
store={constants.L7POLICY: l7policy, constants.LOADBALANCER_ID: db_listener.load_balancer.id
constants.LISTENERS: listeners_dicts, }
constants.LOADBALANCER_ID: db_listener.load_balancer.id self.services_controller.run_poster(
}) flow_utils.get_create_l7policy_flow,
with tf_logging.DynamicLoggingListener(create_l7policy_tf, store=store)
log=LOG):
create_l7policy_tf.run()
def delete_l7policy(self, l7policy): def delete_l7policy(self, l7policy):
"""Deletes an L7 policy. """Deletes an L7 policy.
@ -730,15 +679,13 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
provider_utils.db_listeners_to_provider_dicts_list_of_dicts( provider_utils.db_listeners_to_provider_dicts_list_of_dicts(
[db_listener])) [db_listener]))
delete_l7policy_tf = self._taskflow_load( store = {constants.L7POLICY: l7policy,
self._l7policy_flows.get_delete_l7policy_flow(), constants.LISTENERS: listeners_dicts,
store={constants.L7POLICY: l7policy, constants.LOADBALANCER_ID: db_listener.load_balancer.id
constants.LISTENERS: listeners_dicts, }
constants.LOADBALANCER_ID: db_listener.load_balancer.id self.services_controller.run_poster(
}) flow_utils.get_delete_l7policy_flow,
with tf_logging.DynamicLoggingListener(delete_l7policy_tf, store=store)
log=LOG):
delete_l7policy_tf.run()
def update_l7policy(self, original_l7policy, l7policy_updates): def update_l7policy(self, original_l7policy, l7policy_updates):
"""Updates an L7 policy. """Updates an L7 policy.
@ -755,15 +702,13 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
provider_utils.db_listeners_to_provider_dicts_list_of_dicts( provider_utils.db_listeners_to_provider_dicts_list_of_dicts(
[db_listener])) [db_listener]))
update_l7policy_tf = self._taskflow_load( store = {constants.L7POLICY: original_l7policy,
self._l7policy_flows.get_update_l7policy_flow(), constants.LISTENERS: listeners_dicts,
store={constants.L7POLICY: original_l7policy, constants.LOADBALANCER_ID: db_listener.load_balancer.id,
constants.LISTENERS: listeners_dicts, constants.UPDATE_DICT: l7policy_updates}
constants.LOADBALANCER_ID: db_listener.load_balancer.id, self.services_controller.run_poster(
constants.UPDATE_DICT: l7policy_updates}) flow_utils.get_update_l7policy_flow,
with tf_logging.DynamicLoggingListener(update_l7policy_tf, store=store)
log=LOG):
update_l7policy_tf.run()
def create_l7rule(self, l7rule): def create_l7rule(self, l7rule):
"""Creates an L7 Rule. """Creates an L7 Rule.
@ -783,17 +728,15 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
l7policy_dict = provider_utils.db_l7policy_to_provider_l7policy( l7policy_dict = provider_utils.db_l7policy_to_provider_l7policy(
db_l7policy) db_l7policy)
create_l7rule_tf = self._taskflow_load( store = {constants.L7RULE: l7rule,
self._l7rule_flows.get_create_l7rule_flow(), constants.L7POLICY: l7policy_dict.to_dict(),
store={constants.L7RULE: l7rule, constants.L7POLICY_ID: db_l7policy.id,
constants.L7POLICY: l7policy_dict.to_dict(), constants.LISTENERS: listeners_dicts,
constants.LISTENERS: listeners_dicts, constants.LOADBALANCER_ID: load_balancer.id
constants.L7POLICY_ID: db_l7policy.id, }
constants.LOADBALANCER_ID: load_balancer.id self.services_controller.run_poster(
}) flow_utils.get_create_l7rule_flow,
with tf_logging.DynamicLoggingListener(create_l7rule_tf, store=store)
log=LOG):
create_l7rule_tf.run()
def delete_l7rule(self, l7rule): def delete_l7rule(self, l7rule):
"""Deletes an L7 rule. """Deletes an L7 rule.
@ -811,17 +754,15 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
provider_utils.db_listeners_to_provider_dicts_list_of_dicts( provider_utils.db_listeners_to_provider_dicts_list_of_dicts(
[db_l7policy.listener])) [db_l7policy.listener]))
delete_l7rule_tf = self._taskflow_load( store = {constants.L7RULE: l7rule,
self._l7rule_flows.get_delete_l7rule_flow(), constants.L7POLICY: l7policy.to_dict(),
store={constants.L7RULE: l7rule, constants.LISTENERS: listeners_dicts,
constants.L7POLICY: l7policy.to_dict(), constants.L7POLICY_ID: db_l7policy.id,
constants.LISTENERS: listeners_dicts, constants.LOADBALANCER_ID: load_balancer.id
constants.L7POLICY_ID: db_l7policy.id, }
constants.LOADBALANCER_ID: load_balancer.id self.services_controller.run_poster(
}) flow_utils.get_delete_l7rule_flow,
with tf_logging.DynamicLoggingListener(delete_l7rule_tf, store=store)
log=LOG):
delete_l7rule_tf.run()
def update_l7rule(self, original_l7rule, l7rule_updates): def update_l7rule(self, original_l7rule, l7rule_updates):
"""Updates an L7 rule. """Updates an L7 rule.
@ -841,17 +782,15 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
l7policy_dict = provider_utils.db_l7policy_to_provider_l7policy( l7policy_dict = provider_utils.db_l7policy_to_provider_l7policy(
db_l7policy) db_l7policy)
update_l7rule_tf = self._taskflow_load( store = {constants.L7RULE: original_l7rule,
self._l7rule_flows.get_update_l7rule_flow(), constants.L7POLICY: l7policy_dict.to_dict(),
store={constants.L7RULE: original_l7rule, constants.LISTENERS: listeners_dicts,
constants.L7POLICY: l7policy_dict.to_dict(), constants.L7POLICY_ID: db_l7policy.id,
constants.LISTENERS: listeners_dicts, constants.LOADBALANCER_ID: load_balancer.id,
constants.L7POLICY_ID: db_l7policy.id, constants.UPDATE_DICT: l7rule_updates}
constants.LOADBALANCER_ID: load_balancer.id, self.services_controller.run_poster(
constants.UPDATE_DICT: l7rule_updates}) flow_utils.get_update_l7rule_flow,
with tf_logging.DynamicLoggingListener(update_l7rule_tf, store=store)
log=LOG):
update_l7rule_tf.run()
def _perform_amphora_failover(self, amp, priority): def _perform_amphora_failover(self, amp, priority):
"""Internal method to perform failover operations for an amphora. """Internal method to perform failover operations for an amphora.
@ -903,7 +842,7 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
lb).to_dict() if lb else lb lb).to_dict() if lb else lb
if CONF.nova.enable_anti_affinity and lb: if CONF.nova.enable_anti_affinity and lb:
stored_params[constants.SERVER_GROUP_ID] = lb.server_group_id stored_params[constants.SERVER_GROUP_ID] = lb.server_group_id
if lb and lb.flavor_id: if lb is not None and lb.flavor_id:
stored_params[constants.FLAVOR] = ( stored_params[constants.FLAVOR] = (
self._flavor_repo.get_flavor_metadata_dict( self._flavor_repo.get_flavor_metadata_dict(
db_apis.get_session(), lb.flavor_id)) db_apis.get_session(), lb.flavor_id))
@ -916,13 +855,10 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
else: else:
stored_params[constants.AVAILABILITY_ZONE] = {} stored_params[constants.AVAILABILITY_ZONE] = {}
failover_amphora_tf = self._taskflow_load( self.services_controller.run_poster(
self._amphora_flows.get_failover_flow( flow_utils.get_failover_flow,
role=amp.role, load_balancer=provider_lb), role=amp.role, load_balancer=provider_lb,
store=stored_params) store=stored_params, wait=True)
with tf_logging.DynamicLoggingListener(failover_amphora_tf, log=LOG):
failover_amphora_tf.run()
LOG.info("Successfully completed the failover for an amphora: %s", LOG.info("Successfully completed the failover for an amphora: %s",
{"id": amp.id, {"id": amp.id,
@ -1019,14 +955,12 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
id=amphora_id) id=amphora_id)
LOG.info("Start amphora cert rotation, amphora's id is: %s", amp.id) LOG.info("Start amphora cert rotation, amphora's id is: %s", amp.id)
certrotation_amphora_tf = self._taskflow_load( store = {constants.AMPHORA: amp.to_dict(),
self._amphora_flows.cert_rotate_amphora_flow(), constants.AMPHORA_ID: amphora_id}
store={constants.AMPHORA: amp.to_dict(),
constants.AMPHORA_ID: amphora_id})
with tf_logging.DynamicLoggingListener(certrotation_amphora_tf, self.services_controller.run_poster(
log=LOG): flow_utils.cert_rotate_amphora_flow,
certrotation_amphora_tf.run() store=store)
def update_amphora_agent_config(self, amphora_id): def update_amphora_agent_config(self, amphora_id):
"""Update the amphora agent configuration. """Update the amphora agent configuration.
@ -1048,11 +982,9 @@ class ControllerWorker(base_taskflow.BaseTaskFlowEngine):
flavor = self._flavor_repo.get_flavor_metadata_dict( flavor = self._flavor_repo.get_flavor_metadata_dict(
db_apis.get_session(), lb.flavor_id) db_apis.get_session(), lb.flavor_id)
update_amphora_tf = self._taskflow_load( store = {constants.AMPHORA: amp.to_dict(),
self._amphora_flows.update_amphora_config_flow(), constants.FLAVOR: flavor}
store={constants.AMPHORA: amp.to_dict(),
constants.FLAVOR: flavor})
with tf_logging.DynamicLoggingListener(update_amphora_tf, self.services_controller.run_poster(
log=LOG): flow_utils.update_amphora_config_flow,
update_amphora_tf.run() store=store)

View File

@ -0,0 +1,158 @@
# 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 octavia.common import constants
from octavia.controller.worker.v2.flows import amphora_flows
from octavia.controller.worker.v2.flows import health_monitor_flows
from octavia.controller.worker.v2.flows import l7policy_flows
from octavia.controller.worker.v2.flows import l7rule_flows
from octavia.controller.worker.v2.flows import listener_flows
from octavia.controller.worker.v2.flows import load_balancer_flows
from octavia.controller.worker.v2.flows import member_flows
from octavia.controller.worker.v2.flows import pool_flows
LB_FLOWS = load_balancer_flows.LoadBalancerFlows()
AMP_FLOWS = amphora_flows.AmphoraFlows()
HM_FLOWS = health_monitor_flows.HealthMonitorFlows()
L7_POLICY_FLOWS = l7policy_flows.L7PolicyFlows()
L7_RULES_FLOWS = l7rule_flows.L7RuleFlows()
LISTENER_FLOWS = listener_flows.ListenerFlows()
M_FLOWS = member_flows.MemberFlows()
P_FLOWS = pool_flows.PoolFlows()
def get_create_load_balancer_flow(topology, listeners=None):
return LB_FLOWS.get_create_load_balancer_flow(topology,
listeners=listeners)
def get_delete_load_balancer_flow(lb):
return LB_FLOWS.get_delete_load_balancer_flow(lb)
def get_delete_listeners_store(lb):
return LB_FLOWS.get_delete_listeners_store(lb)
def get_delete_pools_store(lb):
return LB_FLOWS.get_delete_pools_store(lb)
def get_cascade_delete_load_balancer_flow(lb):
return LB_FLOWS.get_cascade_delete_load_balancer_flow(lb)
def get_update_load_balancer_flow():
return LB_FLOWS.get_update_load_balancer_flow()
def get_create_amphora_flow():
return AMP_FLOWS.get_create_amphora_flow()
def get_delete_amphora_flow():
return AMP_FLOWS.get_delete_amphora_flow()
def get_failover_flow(role=constants.ROLE_STANDALONE, load_balancer=None):
return AMP_FLOWS.get_failover_flow(role=role, load_balancer=load_balancer)
def cert_rotate_amphora_flow():
return AMP_FLOWS.cert_rotate_amphora_flow()
def update_amphora_config_flow():
return AMP_FLOWS.update_amphora_config_flow()
def get_create_health_monitor_flow():
return HM_FLOWS.get_create_health_monitor_flow()
def get_delete_health_monitor_flow():
return HM_FLOWS.get_delete_health_monitor_flow()
def get_update_health_monitor_flow():
return HM_FLOWS.get_update_health_monitor_flow()
def get_create_l7policy_flow():
return L7_POLICY_FLOWS.get_create_l7policy_flow()
def get_delete_l7policy_flow():
return L7_POLICY_FLOWS.get_delete_l7policy_flow()
def get_update_l7policy_flow():
return L7_POLICY_FLOWS.get_update_l7policy_flow()
def get_create_l7rule_flow():
return L7_RULES_FLOWS.get_create_l7rule_flow()
def get_delete_l7rule_flow():
return L7_RULES_FLOWS.get_delete_l7rule_flow()
def get_update_l7rule_flow():
return L7_RULES_FLOWS.get_update_l7rule_flow()
def get_create_listener_flow():
return LISTENER_FLOWS.get_create_listener_flow()
def get_create_all_listeners_flow():
return LISTENER_FLOWS.get_create_all_listeners_flow()
def get_delete_listener_flow():
return LISTENER_FLOWS.get_delete_listener_flow()
def get_update_listener_flow():
return LISTENER_FLOWS.get_update_listener_flow()
def get_create_member_flow():
return M_FLOWS.get_create_member_flow()
def get_delete_member_flow():
return M_FLOWS.get_delete_member_flow()
def get_update_member_flow():
return M_FLOWS.get_update_member_flow()
def get_batch_update_members_flow(old_members, new_members, updated_members):
return M_FLOWS.get_batch_update_members_flow(old_members, new_members,
updated_members)
def get_create_pool_flow():
return P_FLOWS.get_create_pool_flow()
def get_delete_pool_flow():
return P_FLOWS.get_delete_pool_flow()
def get_update_pool_flow():
return P_FLOWS.get_update_pool_flow()

View File

@ -0,0 +1,102 @@
# 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 abc
import contextlib
from oslo_config import cfg
from oslo_log import log
from taskflow.jobs import backends as job_backends
from taskflow.persistence import backends as persistence_backends
LOG = log.getLogger(__name__)
CONF = cfg.CONF
class JobboardTaskFlowDriver(object, metaclass=abc.ABCMeta):
@abc.abstractmethod
def job_board(self, persistence):
"""Setting up jobboard backend based on configuration setting.
:param persistence: taskflow persistence backend instance
:return: taskflow jobboard backend instance
"""
class MysqlPersistenceDriver(object):
def __init__(self):
self.persistence_conf = {
'connection': CONF.task_flow.persistence_connection,
'max_pool_size': CONF.database.max_pool_size,
'max_overflow': CONF.database.max_overflow,
'pool_timeout': CONF.database.pool_timeout,
}
def initialize(self):
# Run migrations once on service start.
backend = persistence_backends.fetch(self.persistence_conf)
with contextlib.closing(backend):
with contextlib.closing(backend.get_connection()) as connection:
connection.upgrade()
@contextlib.contextmanager
def get_persistence(self):
# Rewrite taskflow get backend, so it won't run migrations on each call
backend = persistence_backends.fetch(self.persistence_conf)
with contextlib.closing(backend):
with contextlib.closing(backend.get_connection()) as conn:
conn.validate()
yield backend
class ZookeeperTaskFlowDriver(JobboardTaskFlowDriver):
def __init__(self, persistence_driver):
self.persistence_driver = persistence_driver
def job_board(self, persistence):
job_backends_hosts = ','.join(
['%s:%s' % (host, CONF.task_flow.jobboard_backend_port)
for host in CONF.task_flow.jobboard_backend_hosts])
jobboard_backend_conf = {
'board': 'zookeeper',
'hosts': job_backends_hosts,
'path': '/' + CONF.task_flow.jobboard_backend_namespace,
}
jobboard_backend_conf.update(
CONF.task_flow.jobboard_zookeeper_ssl_options)
return job_backends.backend(CONF.task_flow.jobboard_name,
jobboard_backend_conf,
persistence=persistence)
class RedisTaskFlowDriver(JobboardTaskFlowDriver):
def __init__(self, persistence_driver):
self.persistence_driver = persistence_driver
def job_board(self, persistence):
jobboard_backend_conf = {
'board': 'redis',
'host': CONF.task_flow.jobboard_backend_hosts[0],
'port': CONF.task_flow.jobboard_backend_port,
'password': CONF.task_flow.jobboard_backend_password,
'namespace': CONF.task_flow.jobboard_backend_namespace,
}
jobboard_backend_conf.update(
CONF.task_flow.jobboard_redis_backend_ssl_options)
return job_backends.backend(
CONF.task_flow.jobboard_backend_namespace,
jobboard_backend_conf,
persistence=persistence)

View File

@ -22,10 +22,15 @@ from oslo_config import cfg
from oslo_db import options from oslo_db import options
from oslo_log import log from oslo_log import log
from octavia.controller.worker.v2 import taskflow_jobboard_driver
from octavia.i18n import _ from octavia.i18n import _
CONF = cfg.CONF CONF = cfg.CONF
options.set_defaults(CONF) options.set_defaults(CONF)
# Setting explicitly here needed for taskflow persistence successful
# initialization
options.set_defaults(CONF, max_pool_size=10, max_overflow=20,
pool_timeout=10)
log.set_defaults() log.set_defaults()
log.register_options(CONF) log.register_options(CONF)
log.setup(CONF, 'octavia-db-manage') log.setup(CONF, 'octavia-db-manage')
@ -85,6 +90,14 @@ def do_revision(config, cmd):
sql=CONF.command.sql) sql=CONF.command.sql)
def do_persistence_upgrade(config, cmd):
opt = cfg.StrOpt('persistence_connection',
default='sqlite://')
cfg.CONF.register_opts([opt], group='task_flow')
persistence = taskflow_jobboard_driver.MysqlPersistenceDriver()
persistence.initialize()
def add_command_parsers(subparsers): def add_command_parsers(subparsers):
for name in ['current', 'history', 'branches']: for name in ['current', 'history', 'branches']:
parser = add_alembic_subparser(subparsers, name) parser = add_alembic_subparser(subparsers, name)
@ -101,6 +114,11 @@ def add_command_parsers(subparsers):
parser.add_argument('revision', nargs='?') parser.add_argument('revision', nargs='?')
parser.set_defaults(func=do_upgrade) parser.set_defaults(func=do_upgrade)
parser = subparsers.add_parser(
"upgrade_persistence",
help="Run migrations for persistence backend")
parser.set_defaults(func=do_persistence_upgrade)
parser = subparsers.add_parser('downgrade', help="(No longer supported)") parser = subparsers.add_parser('downgrade', help="(No longer supported)")
parser.add_argument('None', nargs='?', help="Downgrade not supported") parser.add_argument('None', nargs='?', help="Downgrade not supported")
parser.set_defaults(func=no_downgrade) parser.set_defaults(func=no_downgrade)

View File

@ -1249,21 +1249,31 @@ class AmphoraRepository(BaseRepository):
return db_lb.to_data_model() return db_lb.to_data_model()
return None return None
def get_spare_amphora_count(self, session, availability_zone=None): def get_spare_amphora_count(self, session, availability_zone=None,
check_booting_amphora=False):
"""Get the count of the spare amphora. """Get the count of the spare amphora.
:returns: Number of current spare amphora. :returns: Number of current spare amphora.
""" """
filters = { filters = {
'status': consts.AMPHORA_READY,
'load_balancer_id': None 'load_balancer_id': None
} }
# For jobboard based controller amphora in booting/pending create state
# can reach READY state after restart of housekeeping/worker service,
# so include amphora in these state to query
if check_booting_amphora:
status = [consts.AMPHORA_READY,
consts.AMPHORA_BOOTING,
consts.PENDING_CREATE]
else:
status = [consts.AMPHORA_READY]
if availability_zone is not None: if availability_zone is not None:
filters['cached_zone'] = availability_zone filters['cached_zone'] = availability_zone
with session.begin(subtransactions=True): with session.begin(subtransactions=True):
count = session.query(self.model_class).filter_by( count = session.query(self.model_class).filter_by(
**filters).count() **filters).filter(self.model_class.status.in_(status)).count()
return count return count

View File

@ -3260,6 +3260,21 @@ class AmphoraRepositoryTest(BaseRepositoryTest):
count = self.amphora_repo.get_spare_amphora_count(self.session) count = self.amphora_repo.get_spare_amphora_count(self.session)
self.assertEqual(2, count) self.assertEqual(2, count)
def test_get_spare_amphora_count_check_booting_amphora_true(self):
count = self.amphora_repo.get_spare_amphora_count(
self.session, check_booting_amphora=True)
self.assertEqual(0, count)
amphora1 = self.create_amphora(self.FAKE_UUID_1)
self.amphora_repo.update(self.session, amphora1.id,
status=constants.AMPHORA_READY,)
amphora2 = self.create_amphora(self.FAKE_UUID_2)
self.amphora_repo.update(self.session, amphora2.id,
status=constants.AMPHORA_BOOTING)
count = self.amphora_repo.get_spare_amphora_count(
self.session, check_booting_amphora=True)
self.assertEqual(2, count)
def test_get_none_cert_expired_amphora(self): def test_get_none_cert_expired_amphora(self):
# test with no expired amphora # test with no expired amphora
amp = self.amphora_repo.get_cert_expiring_amphora(self.session) amp = self.amphora_repo.get_cert_expiring_amphora(self.session)

View File

@ -66,3 +66,86 @@ class TestBaseTaskFlowEngine(base.TestCase):
_engine_mock.compile.assert_called_once_with() _engine_mock.compile.assert_called_once_with()
_engine_mock.prepare.assert_called_once_with() _engine_mock.prepare.assert_called_once_with()
class TestTaskFlowServiceController(base.TestCase):
_mock_uuid = '9a2ebc48-cd3e-429e-aa04-e32f5fc5442a'
def setUp(self):
self.conf = oslo_fixture.Config(cfg.CONF)
self.conf.config(group="task_flow", engine='parallel')
self.driver_mock = mock.MagicMock()
self.persistence_mock = mock.MagicMock()
self.jobboard_mock = mock.MagicMock()
self.driver_mock.job_board.return_value = self.jobboard_mock
self.driver_mock.persistence_driver.get_persistence.return_value = (
self.persistence_mock)
self.service_controller = base_taskflow.TaskFlowServiceController(
self.driver_mock)
super(TestTaskFlowServiceController, self).setUp()
@mock.patch('oslo_utils.uuidutils.generate_uuid', return_value=_mock_uuid)
@mock.patch('taskflow.engines.save_factory_details')
def test_run_poster(self, mock_engines, mockuuid):
flow_factory = mock.MagicMock()
flow_factory.__name__ = 'testname'
job_name = 'testname-%s' % self._mock_uuid
job_details = {'store': 'test'}
with mock.patch.object(self.service_controller, '_wait_for_job'
) as wait:
uuid = self.service_controller.run_poster(flow_factory,
**job_details)
save_logbook = self.persistence_mock.__enter__().get_connection(
).save_logbook
save_logbook.assert_called()
self.assertEqual(job_name, save_logbook.call_args[0][0].name)
mock_engines.assert_called()
save_args = mock_engines.call_args
self.assertEqual(job_name, save_args[0][0].name)
self.assertEqual(self._mock_uuid, save_args[0][0].uuid)
self.assertEqual(flow_factory, save_args[0][1])
self.assertEqual(self.persistence_mock.__enter__(),
save_args[1]['backend'])
self.jobboard_mock.__enter__().post.assert_called()
post_args = self.jobboard_mock.__enter__().post.call_args
self.assertEqual(job_name, post_args[0][0])
self.assertEqual(job_details, post_args[1]['details'])
wait.assert_not_called()
self.assertEqual(self._mock_uuid, uuid)
@mock.patch('oslo_utils.uuidutils.generate_uuid', return_value=_mock_uuid)
@mock.patch('taskflow.engines.save_factory_details')
def test_run_poster_wait(self, mock_engines, mockuuid):
flow_factory = mock.MagicMock()
flow_factory.__name__ = 'testname'
job_details = {'store': 'test'}
with mock.patch.object(self.service_controller, '_wait_for_job'
) as wait:
uuid = self.service_controller.run_poster(flow_factory, wait=True,
**job_details)
self.persistence_mock.__enter__().get_connection(
).save_logbook.assert_called()
mock_engines.assert_called()
self.jobboard_mock.__enter__().post.assert_called()
wait.assert_called_once_with(self.jobboard_mock.__enter__())
self.assertEqual(self._mock_uuid, uuid)
@mock.patch('octavia.common.base_taskflow.RedisDynamicLoggingConductor')
@mock.patch('octavia.common.base_taskflow.DynamicLoggingConductor')
def test_run_conductor(self, dynamiccond, rediscond):
self.service_controller.run_conductor("test")
rediscond.assert_called_once_with(
"test", self.jobboard_mock.__enter__(),
persistence=self.persistence_mock.__enter__(),
engine='parallel')
self.conf.config(group="task_flow",
jobboard_backend_driver='zookeeper_taskflow_driver')
self.service_controller.run_conductor("test2")
dynamiccond.assert_called_once_with(
"test2", self.jobboard_mock.__enter__(),
persistence=self.persistence_mock.__enter__(),
engine='parallel')

View File

@ -45,11 +45,14 @@ class TestHealthManager(base.TestCase):
@mock.patch('octavia.db.api.wait_for_connection') @mock.patch('octavia.db.api.wait_for_connection')
@mock.patch('octavia.controller.worker.v1.controller_worker.' @mock.patch('octavia.controller.worker.v1.controller_worker.'
'ControllerWorker.failover_amphora') 'ControllerWorker.failover_amphora')
@mock.patch('octavia.controller.worker.v2.controller_worker.'
'ControllerWorker.failover_amphora')
@mock.patch('octavia.db.repositories.AmphoraHealthRepository.' @mock.patch('octavia.db.repositories.AmphoraHealthRepository.'
'get_stale_amphora') 'get_stale_amphora')
@mock.patch('octavia.db.api.get_session') @mock.patch('octavia.db.api.get_session')
def test_health_check_stale_amphora(self, session_mock, get_stale_amp_mock, def test_health_check_stale_amphora(self, session_mock, get_stale_amp_mock,
failover_mock, db_wait_mock): failover_mockv2, failover_mock,
db_wait_mock):
conf = oslo_fixture.Config(cfg.CONF) conf = oslo_fixture.Config(cfg.CONF)
conf.config(group="health_manager", heartbeat_timeout=5) conf.config(group="health_manager", heartbeat_timeout=5)
amphora_health = mock.MagicMock() amphora_health = mock.MagicMock()
@ -86,11 +89,14 @@ class TestHealthManager(base.TestCase):
@mock.patch('octavia.controller.worker.v1.controller_worker.' @mock.patch('octavia.controller.worker.v1.controller_worker.'
'ControllerWorker.failover_amphora') 'ControllerWorker.failover_amphora')
@mock.patch('octavia.controller.worker.v2.controller_worker.'
'ControllerWorker.failover_amphora')
@mock.patch('octavia.db.repositories.AmphoraHealthRepository.' @mock.patch('octavia.db.repositories.AmphoraHealthRepository.'
'get_stale_amphora', return_value=None) 'get_stale_amphora', return_value=None)
@mock.patch('octavia.db.api.get_session') @mock.patch('octavia.db.api.get_session')
def test_health_check_nonstale_amphora(self, session_mock, def test_health_check_nonstale_amphora(self, session_mock,
get_stale_amp_mock, failover_mock): get_stale_amp_mock, failover_mockv2,
failover_mock):
get_stale_amp_mock.side_effect = [None, TestException('test')] get_stale_amp_mock.side_effect = [None, TestException('test')]
exit_event = threading.Event() exit_event = threading.Event()
@ -98,15 +104,20 @@ class TestHealthManager(base.TestCase):
hm.health_check() hm.health_check()
session_mock.assert_called_once_with(autocommit=False) session_mock.assert_called_once_with(autocommit=False)
self.assertFalse(failover_mock.called) if CONF.api_settings.default_provider_driver == 'amphorav2':
self.assertFalse(failover_mockv2.called)
else:
self.assertFalse(failover_mock.called)
@mock.patch('octavia.controller.worker.v1.controller_worker.' @mock.patch('octavia.controller.worker.v1.controller_worker.'
'ControllerWorker.failover_amphora') 'ControllerWorker.failover_amphora')
@mock.patch('octavia.controller.worker.v2.controller_worker.'
'ControllerWorker.failover_amphora')
@mock.patch('octavia.db.repositories.AmphoraHealthRepository.' @mock.patch('octavia.db.repositories.AmphoraHealthRepository.'
'get_stale_amphora', return_value=None) 'get_stale_amphora', return_value=None)
@mock.patch('octavia.db.api.get_session') @mock.patch('octavia.db.api.get_session')
def test_health_check_exit(self, session_mock, get_stale_amp_mock, def test_health_check_exit(self, session_mock, get_stale_amp_mock,
failover_mock): failover_mockv2, failover_mock):
get_stale_amp_mock.return_value = None get_stale_amp_mock.return_value = None
exit_event = threading.Event() exit_event = threading.Event()
@ -114,15 +125,20 @@ class TestHealthManager(base.TestCase):
hm.health_check() hm.health_check()
session_mock.assert_called_once_with(autocommit=False) session_mock.assert_called_once_with(autocommit=False)
self.assertFalse(failover_mock.called) if CONF.api_settings.default_provider_driver == 'amphorav2':
self.assertFalse(failover_mockv2.called)
else:
self.assertFalse(failover_mock.called)
@mock.patch('octavia.controller.worker.v1.controller_worker.' @mock.patch('octavia.controller.worker.v1.controller_worker.'
'ControllerWorker.failover_amphora') 'ControllerWorker.failover_amphora')
@mock.patch('octavia.controller.worker.v2.controller_worker.'
'ControllerWorker.failover_amphora')
@mock.patch('octavia.db.repositories.AmphoraHealthRepository.' @mock.patch('octavia.db.repositories.AmphoraHealthRepository.'
'get_stale_amphora', return_value=None) 'get_stale_amphora', return_value=None)
@mock.patch('octavia.db.api.get_session') @mock.patch('octavia.db.api.get_session')
def test_health_check_db_error(self, session_mock, get_stale_amp_mock, def test_health_check_db_error(self, session_mock, get_stale_amp_mock,
failover_mock): failover_mockv2, failover_mock):
get_stale_amp_mock.return_value = None get_stale_amp_mock.return_value = None
mock_session = mock.MagicMock() mock_session = mock.MagicMock()

View File

@ -45,6 +45,9 @@ class TestSpareCheck(base.TestCase):
def setUp(self): def setUp(self):
super(TestSpareCheck, self).setUp() super(TestSpareCheck, self).setUp()
self.CONF = self.useFixture(oslo_fixture.Config(cfg.CONF))
self.CONF.config(group="api_settings",
default_provider_driver='amphora')
self.spare_amp = house_keeping.SpareAmphora() self.spare_amp = house_keeping.SpareAmphora()
self.amp_repo = mock.MagicMock() self.amp_repo = mock.MagicMock()
self.az_repo = mock.MagicMock() self.az_repo = mock.MagicMock()
@ -53,7 +56,6 @@ class TestSpareCheck(base.TestCase):
self.spare_amp.amp_repo = self.amp_repo self.spare_amp.amp_repo = self.amp_repo
self.spare_amp.az_repo = self.az_repo self.spare_amp.az_repo = self.az_repo
self.spare_amp.cw = self.cw self.spare_amp.cw = self.cw
self.CONF = self.useFixture(oslo_fixture.Config(cfg.CONF))
@mock.patch('octavia.db.api.get_session') @mock.patch('octavia.db.api.get_session')
def test_spare_check_diff_count(self, session): def test_spare_check_diff_count(self, session):
@ -90,8 +92,10 @@ class TestSpareCheck(base.TestCase):
az1.name, az2.name) az1.name, az2.name)
self.spare_amp.spare_check() self.spare_amp.spare_check()
calls = [mock.call(session, availability_zone=az1.name), calls = [mock.call(session, availability_zone=az1.name,
mock.call(session, availability_zone=az2.name)] check_booting_amphora=False),
mock.call(session, availability_zone=az2.name,
check_booting_amphora=False)]
self.amp_repo.get_spare_amphora_count.assert_has_calls(calls, self.amp_repo.get_spare_amphora_count.assert_has_calls(calls,
any_order=True) any_order=True)
@ -251,6 +255,7 @@ class TestDatabaseCleanup(base.TestCase):
class TestCertRotation(base.TestCase): class TestCertRotation(base.TestCase):
def setUp(self): def setUp(self):
super(TestCertRotation, self).setUp() super(TestCertRotation, self).setUp()
self.CONF = self.useFixture(oslo_fixture.Config(cfg.CONF))
@mock.patch('octavia.controller.worker.v1.controller_worker.' @mock.patch('octavia.controller.worker.v1.controller_worker.'
'ControllerWorker.amphora_cert_rotation') 'ControllerWorker.amphora_cert_rotation')
@ -261,6 +266,8 @@ class TestCertRotation(base.TestCase):
cert_exp_amp_mock, cert_exp_amp_mock,
amp_cert_mock amp_cert_mock
): ):
self.CONF.config(group="api_settings",
default_provider_driver='amphora')
amphora = mock.MagicMock() amphora = mock.MagicMock()
amphora.id = AMPHORA_ID amphora.id = AMPHORA_ID
@ -281,6 +288,8 @@ class TestCertRotation(base.TestCase):
cert_exp_amp_mock, cert_exp_amp_mock,
amp_cert_mock amp_cert_mock
): ):
self.CONF.config(group="api_settings",
default_provider_driver='amphora')
amphora = mock.MagicMock() amphora = mock.MagicMock()
amphora.id = AMPHORA_ID amphora.id = AMPHORA_ID
@ -300,9 +309,67 @@ class TestCertRotation(base.TestCase):
def test_cert_rotation_non_expired_amphora(self, session, def test_cert_rotation_non_expired_amphora(self, session,
cert_exp_amp_mock, cert_exp_amp_mock,
amp_cert_mock): amp_cert_mock):
self.CONF.config(group="api_settings",
default_provider_driver='amphora')
session.return_value = session session.return_value = session
cert_exp_amp_mock.return_value = None cert_exp_amp_mock.return_value = None
cr = house_keeping.CertRotation() cr = house_keeping.CertRotation()
cr.rotate() cr.rotate()
self.assertFalse(amp_cert_mock.called) self.assertFalse(amp_cert_mock.called)
@mock.patch('octavia.controller.worker.v2.controller_worker.'
'ControllerWorker.amphora_cert_rotation')
@mock.patch('octavia.db.repositories.AmphoraRepository.'
'get_cert_expiring_amphora')
@mock.patch('octavia.db.api.get_session')
def test_cert_rotation_expired_amphora_with_exception_amphorav2(
self, session, cert_exp_amp_mock, amp_cert_mock):
self.CONF.config(group="api_settings",
default_provider_driver='amphorav2')
amphora = mock.MagicMock()
amphora.id = AMPHORA_ID
session.return_value = session
cert_exp_amp_mock.side_effect = [amphora, TestException(
'break_while')]
cr = house_keeping.CertRotation()
self.assertRaises(TestException, cr.rotate)
amp_cert_mock.assert_called_once_with(AMPHORA_ID)
@mock.patch('octavia.controller.worker.v2.controller_worker.'
'ControllerWorker.amphora_cert_rotation')
@mock.patch('octavia.db.repositories.AmphoraRepository.'
'get_cert_expiring_amphora')
@mock.patch('octavia.db.api.get_session')
def test_cert_rotation_expired_amphora_without_exception_amphorav2(
self, session, cert_exp_amp_mock, amp_cert_mock):
self.CONF.config(group="api_settings",
default_provider_driver='amphorav2')
amphora = mock.MagicMock()
amphora.id = AMPHORA_ID
session.return_value = session
cert_exp_amp_mock.side_effect = [amphora, None]
cr = house_keeping.CertRotation()
self.assertIsNone(cr.rotate())
amp_cert_mock.assert_called_once_with(AMPHORA_ID)
@mock.patch('octavia.controller.worker.v2.controller_worker.'
'ControllerWorker.amphora_cert_rotation')
@mock.patch('octavia.db.repositories.AmphoraRepository.'
'get_cert_expiring_amphora')
@mock.patch('octavia.db.api.get_session')
def test_cert_rotation_non_expired_amphora_amphorav2(
self, session, cert_exp_amp_mock, amp_cert_mock):
self.CONF.config(group="api_settings",
default_provider_driver='amphorav2')
session.return_value = session
cert_exp_amp_mock.return_value = None
cr = house_keeping.CertRotation()
cr.rotate()
self.assertFalse(amp_cert_mock.called)

View File

@ -50,7 +50,8 @@ class TestConsumer(base.TestRpc):
mock_endpoint.assert_called_once_with() mock_endpoint.assert_called_once_with()
@mock.patch.object(messaging, 'get_rpc_server') @mock.patch.object(messaging, 'get_rpc_server')
def test_consumer_terminate(self, mock_rpc_server): @mock.patch.object(endpoints, 'Endpoints')
def test_consumer_terminate(self, mock_endpoint, mock_rpc_server):
mock_rpc_server_rv = mock.Mock() mock_rpc_server_rv = mock.Mock()
mock_rpc_server.return_value = mock_rpc_server_rv mock_rpc_server.return_value = mock_rpc_server_rv

View File

@ -19,10 +19,10 @@ from oslo_config import fixture as oslo_fixture
from oslo_utils import uuidutils from oslo_utils import uuidutils
from octavia.api.drivers import utils as provider_utils from octavia.api.drivers import utils as provider_utils
from octavia.common import base_taskflow
from octavia.common import constants from octavia.common import constants
from octavia.common import data_models from octavia.common import data_models
from octavia.controller.worker.v2 import controller_worker from octavia.controller.worker.v2 import controller_worker
from octavia.controller.worker.v2.flows import flow_utils
import octavia.tests.unit.base as base import octavia.tests.unit.base as base
@ -107,7 +107,7 @@ class TestException(Exception):
return_value=_member_mock) return_value=_member_mock)
@mock.patch('octavia.db.repositories.PoolRepository.get', @mock.patch('octavia.db.repositories.PoolRepository.get',
return_value=_db_pool_mock) return_value=_db_pool_mock)
@mock.patch('octavia.common.base_taskflow.BaseTaskFlowEngine._taskflow_load', @mock.patch('octavia.common.base_taskflow.TaskFlowServiceController',
return_value=_flow_mock) return_value=_flow_mock)
@mock.patch('taskflow.listeners.logging.DynamicLoggingListener') @mock.patch('taskflow.listeners.logging.DynamicLoggingListener')
@mock.patch('octavia.db.api.get_session', return_value=_db_session) @mock.patch('octavia.db.api.get_session', return_value=_db_session)
@ -137,8 +137,8 @@ class TestControllerWorker(base.TestCase):
_db_load_balancer_mock.listeners = [_listener_mock] _db_load_balancer_mock.listeners = [_listener_mock]
_db_load_balancer_mock.to_dict.return_value = {'id': LB_ID} _db_load_balancer_mock.to_dict.return_value = {'id': LB_ID}
fetch_mock = mock.MagicMock(return_value=AMP_ID) fetch_mock = mock.MagicMock()
_flow_mock.storage.fetch = fetch_mock _flow_mock.driver.persistence = fetch_mock
_db_pool_mock.id = POOL_ID _db_pool_mock.id = POOL_ID
_db_health_mon_mock.pool_id = POOL_ID _db_health_mon_mock.pool_id = POOL_ID
@ -170,22 +170,17 @@ class TestControllerWorker(base.TestCase):
_flow_mock.reset_mock() _flow_mock.reset_mock()
cw = controller_worker.ControllerWorker() cw = controller_worker.ControllerWorker()
amp = cw.create_amphora() cw.create_amphora()
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with( assert_called_once_with(
'TEST', flow_utils.get_create_amphora_flow,
wait=True,
store={constants.BUILD_TYPE_PRIORITY: store={constants.BUILD_TYPE_PRIORITY:
constants.LB_CREATE_SPARES_POOL_PRIORITY, constants.LB_CREATE_SPARES_POOL_PRIORITY,
constants.FLAVOR: None, constants.FLAVOR: None,
constants.AVAILABILITY_ZONE: None})) constants.AVAILABILITY_ZONE: None}))
_flow_mock.run.assert_called_once_with()
_flow_mock.storage.fetch.assert_called_once_with('amphora')
self.assertEqual(AMP_ID, amp)
@mock.patch('octavia.db.repositories.AvailabilityZoneRepository.' @mock.patch('octavia.db.repositories.AvailabilityZoneRepository.'
'get_availability_zone_metadata_dict') 'get_availability_zone_metadata_dict')
@mock.patch('octavia.controller.worker.v2.flows.' @mock.patch('octavia.controller.worker.v2.flows.'
@ -211,22 +206,17 @@ class TestControllerWorker(base.TestCase):
az_data = {constants.COMPUTE_ZONE: az} az_data = {constants.COMPUTE_ZONE: az}
mock_get_az_metadata.return_value = az_data mock_get_az_metadata.return_value = az_data
cw = controller_worker.ControllerWorker() cw = controller_worker.ControllerWorker()
amp = cw.create_amphora(availability_zone=az) cw.create_amphora(availability_zone=az)
mock_get_az_metadata.assert_called_once_with(_db_session, az) mock_get_az_metadata.assert_called_once_with(_db_session, az)
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with( assert_called_once_with(
'TEST', flow_utils.get_create_amphora_flow,
wait=True,
store={constants.BUILD_TYPE_PRIORITY: store={constants.BUILD_TYPE_PRIORITY:
constants.LB_CREATE_SPARES_POOL_PRIORITY, constants.LB_CREATE_SPARES_POOL_PRIORITY,
constants.FLAVOR: None, constants.FLAVOR: None,
constants.AVAILABILITY_ZONE: az_data})) constants.AVAILABILITY_ZONE: az_data}))
_flow_mock.run.assert_called_once_with()
_flow_mock.storage.fetch.assert_called_once_with('amphora')
self.assertEqual(AMP_ID, amp)
@mock.patch('octavia.controller.worker.v2.flows.' @mock.patch('octavia.controller.worker.v2.flows.'
'amphora_flows.AmphoraFlows.get_delete_amphora_flow', 'amphora_flows.AmphoraFlows.get_delete_amphora_flow',
return_value='TEST') return_value='TEST')
@ -254,11 +244,10 @@ class TestControllerWorker(base.TestCase):
id=AMP_ID) id=AMP_ID)
mock_amp_repo_get.return_value = _db_amphora_mock mock_amp_repo_get.return_value = _db_amphora_mock
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with( assert_called_once_with(
'TEST', store={constants.AMPHORA: _db_amphora_mock.to_dict()})) flow_utils.get_delete_amphora_flow,
store={constants.AMPHORA: _db_amphora_mock.to_dict()}))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.' @mock.patch('octavia.controller.worker.v2.flows.'
'health_monitor_flows.HealthMonitorFlows.' 'health_monitor_flows.HealthMonitorFlows.'
@ -285,8 +274,9 @@ class TestControllerWorker(base.TestCase):
provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer( provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer(
_db_load_balancer_mock).to_dict() _db_load_balancer_mock).to_dict()
mock_health_mon_repo_get.return_value = _db_health_mon_mock mock_health_mon_repo_get.return_value = _db_health_mon_mock
(base_taskflow.BaseTaskFlowEngine._taskflow_load.
assert_called_once_with(_flow_mock, (cw.services_controller.run_poster.
assert_called_once_with(flow_utils.get_create_health_monitor_flow,
store={constants.HEALTH_MON: store={constants.HEALTH_MON:
_health_mon_mock, _health_mon_mock,
constants.LISTENERS: constants.LISTENERS:
@ -298,14 +288,7 @@ class TestControllerWorker(base.TestCase):
constants.POOL_ID: constants.POOL_ID:
POOL_ID})) POOL_ID}))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.'
'health_monitor_flows.HealthMonitorFlows.'
'get_delete_health_monitor_flow',
return_value=_flow_mock)
def test_delete_health_monitor(self, def test_delete_health_monitor(self,
mock_get_delete_hm_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -326,8 +309,8 @@ class TestControllerWorker(base.TestCase):
cw.delete_health_monitor(_health_mon_mock) cw.delete_health_monitor(_health_mon_mock)
mock_health_mon_repo_get.return_value = _db_health_mon_mock mock_health_mon_repo_get.return_value = _db_health_mon_mock
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with(_flow_mock, assert_called_once_with(flow_utils.get_delete_health_monitor_flow,
store={constants.HEALTH_MON: store={constants.HEALTH_MON:
_health_mon_mock, _health_mon_mock,
constants.LISTENERS: constants.LISTENERS:
@ -340,14 +323,7 @@ class TestControllerWorker(base.TestCase):
POOL_ID, POOL_ID,
constants.PROJECT_ID: PROJECT_ID})) constants.PROJECT_ID: PROJECT_ID}))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.'
'health_monitor_flows.HealthMonitorFlows.'
'get_update_health_monitor_flow',
return_value=_flow_mock)
def test_update_health_monitor(self, def test_update_health_monitor(self,
mock_get_update_hm_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -370,8 +346,8 @@ class TestControllerWorker(base.TestCase):
provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer( provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer(
_db_load_balancer_mock).to_dict() _db_load_balancer_mock).to_dict()
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with(_flow_mock, assert_called_once_with(flow_utils.get_update_health_monitor_flow,
store={constants.HEALTH_MON: store={constants.HEALTH_MON:
_health_mon_mock, _health_mon_mock,
constants.POOL_ID: POOL_ID, constants.POOL_ID: POOL_ID,
@ -384,13 +360,7 @@ class TestControllerWorker(base.TestCase):
constants.UPDATE_DICT: constants.UPDATE_DICT:
HEALTH_UPDATE_DICT})) HEALTH_UPDATE_DICT}))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.'
'listener_flows.ListenerFlows.get_create_listener_flow',
return_value=_flow_mock)
def test_create_listener(self, def test_create_listener(self,
mock_get_create_listener_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -413,20 +383,14 @@ class TestControllerWorker(base.TestCase):
provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer( provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer(
_db_load_balancer_mock).to_dict() _db_load_balancer_mock).to_dict()
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with( assert_called_once_with(
_flow_mock, store={ flow_utils.get_create_listener_flow, store={
constants.LOADBALANCER: provider_lb, constants.LOADBALANCER: provider_lb,
constants.LOADBALANCER_ID: LB_ID, constants.LOADBALANCER_ID: LB_ID,
constants.LISTENERS: [listener_dict]})) constants.LISTENERS: [listener_dict]}))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.'
'listener_flows.ListenerFlows.get_delete_listener_flow',
return_value=_flow_mock)
def test_delete_listener(self, def test_delete_listener(self,
mock_get_delete_listener_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -446,19 +410,14 @@ class TestControllerWorker(base.TestCase):
cw = controller_worker.ControllerWorker() cw = controller_worker.ControllerWorker()
cw.delete_listener(listener_dict) cw.delete_listener(listener_dict)
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with( assert_called_once_with(
_flow_mock, store={constants.LISTENER: self.ref_listener_dict, flow_utils.get_delete_listener_flow,
constants.LOADBALANCER_ID: LB_ID, store={constants.LISTENER: self.ref_listener_dict,
constants.PROJECT_ID: PROJECT_ID})) constants.LOADBALANCER_ID: LB_ID,
constants.PROJECT_ID: PROJECT_ID}))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.'
'listener_flows.ListenerFlows.get_update_listener_flow',
return_value=_flow_mock)
def test_update_listener(self, def test_update_listener(self,
mock_get_update_listener_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -479,8 +438,8 @@ class TestControllerWorker(base.TestCase):
cw = controller_worker.ControllerWorker() cw = controller_worker.ControllerWorker()
cw.update_listener(listener_dict, LISTENER_UPDATE_DICT) cw.update_listener(listener_dict, LISTENER_UPDATE_DICT)
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with(_flow_mock, assert_called_once_with(flow_utils.get_update_listener_flow,
store={constants.LISTENER: listener_dict, store={constants.LISTENER: listener_dict,
constants.UPDATE_DICT: constants.UPDATE_DICT:
LISTENER_UPDATE_DICT, LISTENER_UPDATE_DICT,
@ -488,14 +447,8 @@ class TestControllerWorker(base.TestCase):
constants.LISTENERS: constants.LISTENERS:
[listener_dict]})) [listener_dict]}))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.load_balancer_flows.'
'LoadBalancerFlows.get_create_load_balancer_flow',
return_value=_flow_mock)
def test_create_load_balancer_single( def test_create_load_balancer_single(
self, self,
mock_get_create_load_balancer_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -512,9 +465,7 @@ class TestControllerWorker(base.TestCase):
self.conf.config(group="controller_worker", self.conf.config(group="controller_worker",
loadbalancer_topology=constants.TOPOLOGY_SINGLE) loadbalancer_topology=constants.TOPOLOGY_SINGLE)
_flow_mock.reset_mock() _flow_mock.reset_mock()
mock_taskflow_load.reset_mock()
mock_eng = mock.Mock()
mock_taskflow_load.return_value = mock_eng
store = { store = {
constants.LOADBALANCER_ID: LB_ID, constants.LOADBALANCER_ID: LB_ID,
'update_dict': {'topology': constants.TOPOLOGY_SINGLE}, 'update_dict': {'topology': constants.TOPOLOGY_SINGLE},
@ -530,19 +481,13 @@ class TestControllerWorker(base.TestCase):
cw = controller_worker.ControllerWorker() cw = controller_worker.ControllerWorker()
cw.create_load_balancer(_load_balancer_mock) cw.create_load_balancer(_load_balancer_mock)
mock_get_create_load_balancer_flow.assert_called_with( cw.services_controller.run_poster.assert_called_with(
topology=constants.TOPOLOGY_SINGLE, listeners=[]) flow_utils.get_create_load_balancer_flow,
mock_taskflow_load.assert_called_with( constants.TOPOLOGY_SINGLE, listeners=[], store=store)
mock_get_create_load_balancer_flow.return_value, store=store)
mock_eng.run.assert_any_call()
self.assertEqual(4, mock_lb_repo_get.call_count) self.assertEqual(4, mock_lb_repo_get.call_count)
@mock.patch('octavia.controller.worker.v2.flows.load_balancer_flows.'
'LoadBalancerFlows.get_create_load_balancer_flow',
return_value=_flow_mock)
def test_create_load_balancer_active_standby( def test_create_load_balancer_active_standby(
self, self,
mock_get_create_load_balancer_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -560,9 +505,6 @@ class TestControllerWorker(base.TestCase):
loadbalancer_topology=constants.TOPOLOGY_ACTIVE_STANDBY) loadbalancer_topology=constants.TOPOLOGY_ACTIVE_STANDBY)
_flow_mock.reset_mock() _flow_mock.reset_mock()
mock_taskflow_load.reset_mock()
mock_eng = mock.Mock()
mock_taskflow_load.return_value = mock_eng
store = { store = {
constants.LOADBALANCER_ID: LB_ID, constants.LOADBALANCER_ID: LB_ID,
'update_dict': {'topology': constants.TOPOLOGY_ACTIVE_STANDBY}, 'update_dict': {'topology': constants.TOPOLOGY_ACTIVE_STANDBY},
@ -577,17 +519,12 @@ class TestControllerWorker(base.TestCase):
cw = controller_worker.ControllerWorker() cw = controller_worker.ControllerWorker()
cw.create_load_balancer(_load_balancer_mock) cw.create_load_balancer(_load_balancer_mock)
mock_get_create_load_balancer_flow.assert_called_with( cw.services_controller.run_poster.assert_called_with(
topology=constants.TOPOLOGY_ACTIVE_STANDBY, listeners=[]) flow_utils.get_create_load_balancer_flow,
mock_taskflow_load.assert_called_with( constants.TOPOLOGY_ACTIVE_STANDBY, listeners=[], store=store)
mock_get_create_load_balancer_flow.return_value, store=store)
mock_eng.run.assert_any_call()
@mock.patch('octavia.controller.worker.v2.flows.load_balancer_flows.'
'LoadBalancerFlows.get_create_load_balancer_flow')
def test_create_load_balancer_full_graph_single( def test_create_load_balancer_full_graph_single(
self, self,
mock_get_create_load_balancer_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -612,8 +549,6 @@ class TestControllerWorker(base.TestCase):
lb = data_models.LoadBalancer(id=LB_ID, listeners=listeners, lb = data_models.LoadBalancer(id=LB_ID, listeners=listeners,
topology=constants.TOPOLOGY_SINGLE) topology=constants.TOPOLOGY_SINGLE)
mock_lb_repo_get.return_value = lb mock_lb_repo_get.return_value = lb
mock_eng = mock.Mock()
mock_taskflow_load.return_value = mock_eng
store = { store = {
constants.LOADBALANCER_ID: LB_ID, constants.LOADBALANCER_ID: LB_ID,
'update_dict': {'topology': constants.TOPOLOGY_SINGLE}, 'update_dict': {'topology': constants.TOPOLOGY_SINGLE},
@ -625,25 +560,12 @@ class TestControllerWorker(base.TestCase):
cw = controller_worker.ControllerWorker() cw = controller_worker.ControllerWorker()
cw.create_load_balancer(_load_balancer_mock) cw.create_load_balancer(_load_balancer_mock)
# mock_create_single_topology.assert_called_once() cw.services_controller.run_poster.assert_called_with(
# mock_create_active_standby_topology.assert_not_called() flow_utils.get_create_load_balancer_flow,
mock_get_create_load_balancer_flow.assert_called_with( constants.TOPOLOGY_SINGLE, listeners=dict_listeners, store=store)
topology=constants.TOPOLOGY_SINGLE, listeners=dict_listeners)
mock_taskflow_load.assert_called_with(
mock_get_create_load_balancer_flow.return_value, store=store)
mock_eng.run.assert_any_call()
@mock.patch('octavia.controller.worker.v2.flows.load_balancer_flows.'
'LoadBalancerFlows.get_create_load_balancer_flow')
@mock.patch('octavia.controller.worker.v2.flows.load_balancer_flows.'
'LoadBalancerFlows._create_single_topology')
@mock.patch('octavia.controller.worker.v2.flows.load_balancer_flows.'
'LoadBalancerFlows._create_active_standby_topology')
def test_create_load_balancer_full_graph_active_standby( def test_create_load_balancer_full_graph_active_standby(
self, self,
mock_create_active_standby_topology,
mock_create_single_topology,
mock_get_create_load_balancer_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -668,9 +590,10 @@ class TestControllerWorker(base.TestCase):
lb = data_models.LoadBalancer( lb = data_models.LoadBalancer(
id=LB_ID, listeners=listeners, id=LB_ID, listeners=listeners,
topology=constants.TOPOLOGY_ACTIVE_STANDBY) topology=constants.TOPOLOGY_ACTIVE_STANDBY)
dict_listeners = [listener.to_dict() for listener in
provider_utils.db_listeners_to_provider_listeners(
listeners)]
mock_lb_repo_get.return_value = lb mock_lb_repo_get.return_value = lb
mock_eng = mock.Mock()
mock_taskflow_load.return_value = mock_eng
store = { store = {
constants.LOADBALANCER_ID: LB_ID, constants.LOADBALANCER_ID: LB_ID,
'update_dict': {'topology': constants.TOPOLOGY_ACTIVE_STANDBY}, 'update_dict': {'topology': constants.TOPOLOGY_ACTIVE_STANDBY},
@ -682,18 +605,12 @@ class TestControllerWorker(base.TestCase):
cw = controller_worker.ControllerWorker() cw = controller_worker.ControllerWorker()
cw.create_load_balancer(_load_balancer_mock) cw.create_load_balancer(_load_balancer_mock)
mock_get_create_load_balancer_flow.assert_called_with( cw.services_controller.run_poster.assert_called_with(
topology=constants.TOPOLOGY_ACTIVE_STANDBY, flow_utils.get_create_load_balancer_flow,
listeners=dict_listeners) constants.TOPOLOGY_ACTIVE_STANDBY, listeners=dict_listeners,
mock_taskflow_load.assert_called_with( store=store)
mock_get_create_load_balancer_flow.return_value, store=store)
mock_eng.run.assert_any_call()
@mock.patch('octavia.controller.worker.v2.flows.load_balancer_flows.'
'LoadBalancerFlows.get_delete_load_balancer_flow',
return_value=_flow_mock)
def test_delete_load_balancer_without_cascade(self, def test_delete_load_balancer_without_cascade(self,
mock_get_delete_lb_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -715,22 +632,18 @@ class TestControllerWorker(base.TestCase):
_db_session, _db_session,
id=LB_ID) id=LB_ID)
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with( assert_called_once_with(
_flow_mock, flow_utils.get_delete_load_balancer_flow,
_load_balancer_mock,
store={constants.LOADBALANCER: _load_balancer_mock, store={constants.LOADBALANCER: _load_balancer_mock,
constants.SERVER_GROUP_ID: constants.SERVER_GROUP_ID:
_db_load_balancer_mock.server_group_id, _db_load_balancer_mock.server_group_id,
constants.PROJECT_ID: _db_load_balancer_mock.project_id, constants.PROJECT_ID: _db_load_balancer_mock.project_id,
})) }))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.load_balancer_flows.'
'LoadBalancerFlows.get_cascade_delete_load_balancer_flow',
return_value=_flow_mock)
def test_delete_load_balancer_with_cascade(self, def test_delete_load_balancer_with_cascade(self,
mock_get_delete_lb_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -753,9 +666,10 @@ class TestControllerWorker(base.TestCase):
id=LB_ID) id=LB_ID)
list_name = 'listener_%s' % _listener_mock.id list_name = 'listener_%s' % _listener_mock.id
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with( assert_called_once_with(
_flow_mock, flow_utils.get_cascade_delete_load_balancer_flow,
_load_balancer_mock,
store={constants.LOADBALANCER: _load_balancer_mock, store={constants.LOADBALANCER: _load_balancer_mock,
list_name: self.ref_listener_dict, list_name: self.ref_listener_dict,
constants.LOADBALANCER_ID: LB_ID, constants.LOADBALANCER_ID: LB_ID,
@ -764,16 +678,11 @@ class TestControllerWorker(base.TestCase):
constants.PROJECT_ID: _db_load_balancer_mock.project_id, constants.PROJECT_ID: _db_load_balancer_mock.project_id,
}) })
) )
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.load_balancer_flows.'
'LoadBalancerFlows.get_update_load_balancer_flow',
return_value=_flow_mock)
@mock.patch('octavia.db.repositories.ListenerRepository.get_all', @mock.patch('octavia.db.repositories.ListenerRepository.get_all',
return_value=([_listener_mock], None)) return_value=([_listener_mock], None))
def test_update_load_balancer(self, def test_update_load_balancer(self,
mock_listener_repo_get_all, mock_listener_repo_get_all,
mock_get_update_lb_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -793,8 +702,8 @@ class TestControllerWorker(base.TestCase):
change = 'TEST2' change = 'TEST2'
cw.update_load_balancer(_load_balancer_mock, change) cw.update_load_balancer(_load_balancer_mock, change)
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with(_flow_mock, assert_called_once_with(flow_utils.get_update_load_balancer_flow,
store={constants.UPDATE_DICT: change, store={constants.UPDATE_DICT: change,
constants.LOADBALANCER: constants.LOADBALANCER:
_load_balancer_mock, _load_balancer_mock,
@ -802,8 +711,6 @@ class TestControllerWorker(base.TestCase):
_db_load_balancer_mock.id, _db_load_balancer_mock.id,
})) }))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.' @mock.patch('octavia.controller.worker.v2.flows.'
'member_flows.MemberFlows.get_create_member_flow', 'member_flows.MemberFlows.get_create_member_flow',
return_value=_flow_mock) return_value=_flow_mock)
@ -833,17 +740,18 @@ class TestControllerWorker(base.TestCase):
provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer( provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer(
_db_load_balancer_mock).to_dict() _db_load_balancer_mock).to_dict()
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with( assert_called_once_with(flow_utils.get_create_member_flow,
_flow_mock, store={constants.MEMBER: _member,
store={constants.MEMBER: _member, constants.LISTENERS:
constants.LISTENERS: [self.ref_listener_dict], [self.ref_listener_dict],
constants.LOADBALANCER_ID: LB_ID, constants.LOADBALANCER_ID:
constants.LOADBALANCER: provider_lb, LB_ID,
constants.POOL_ID: POOL_ID, constants.LOADBALANCER:
constants.AVAILABILITY_ZONE: {}})) provider_lb,
constants.POOL_ID:
_flow_mock.run.assert_called_once_with() POOL_ID,
constants.AVAILABILITY_ZONE: {}}))
@mock.patch('octavia.controller.worker.v2.flows.' @mock.patch('octavia.controller.worker.v2.flows.'
'member_flows.MemberFlows.get_delete_member_flow', 'member_flows.MemberFlows.get_delete_member_flow',
@ -873,21 +781,16 @@ class TestControllerWorker(base.TestCase):
provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer( provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer(
_db_load_balancer_mock).to_dict() _db_load_balancer_mock).to_dict()
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with( assert_called_once_with(
_flow_mock, store={constants.MEMBER: _member, flow_utils.get_delete_member_flow,
constants.LISTENERS: store={constants.MEMBER: _member,
[self.ref_listener_dict], constants.LISTENERS: [self.ref_listener_dict],
constants.LOADBALANCER_ID: constants.LOADBALANCER_ID: LB_ID,
LB_ID, constants.LOADBALANCER: provider_lb,
constants.LOADBALANCER: constants.POOL_ID: POOL_ID,
provider_lb, constants.PROJECT_ID: PROJECT_ID,
constants.POOL_ID: constants.AVAILABILITY_ZONE: {}}))
POOL_ID,
constants.PROJECT_ID: PROJECT_ID,
constants.AVAILABILITY_ZONE: {}}))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.' @mock.patch('octavia.controller.worker.v2.flows.'
'member_flows.MemberFlows.get_update_member_flow', 'member_flows.MemberFlows.get_update_member_flow',
@ -917,9 +820,8 @@ class TestControllerWorker(base.TestCase):
cw.update_member(_member, MEMBER_UPDATE_DICT) cw.update_member(_member, MEMBER_UPDATE_DICT)
provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer( provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer(
_db_load_balancer_mock).to_dict() _db_load_balancer_mock).to_dict()
(cw.services_controller.run_poster.
(base_taskflow.BaseTaskFlowEngine._taskflow_load. assert_called_once_with(flow_utils.get_update_member_flow,
assert_called_once_with(_flow_mock,
store={constants.MEMBER: _member, store={constants.MEMBER: _member,
constants.LISTENERS: constants.LISTENERS:
[self.ref_listener_dict], [self.ref_listener_dict],
@ -933,8 +835,6 @@ class TestControllerWorker(base.TestCase):
MEMBER_UPDATE_DICT, MEMBER_UPDATE_DICT,
constants.AVAILABILITY_ZONE: {}})) constants.AVAILABILITY_ZONE: {}}))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.' @mock.patch('octavia.controller.worker.v2.flows.'
'member_flows.MemberFlows.get_batch_update_members_flow', 'member_flows.MemberFlows.get_batch_update_members_flow',
return_value=_flow_mock) return_value=_flow_mock)
@ -958,15 +858,25 @@ class TestControllerWorker(base.TestCase):
_flow_mock.reset_mock() _flow_mock.reset_mock()
mock_get_az_metadata_dict.return_value = {} mock_get_az_metadata_dict.return_value = {}
cw = controller_worker.ControllerWorker() cw = controller_worker.ControllerWorker()
old_member = mock.MagicMock()
old_member.to_dict.return_value = {'id': 9,
constants.POOL_ID: 'testtest'}
mock_member_repo_get.side_effect = [_member_mock, old_member]
cw.batch_update_members([{constants.MEMBER_ID: 9, cw.batch_update_members([{constants.MEMBER_ID: 9,
constants.POOL_ID: 'testtest'}], constants.POOL_ID: 'testtest'}],
[{constants.MEMBER_ID: 11}], [{constants.MEMBER_ID: 11}],
[MEMBER_UPDATE_DICT]) [MEMBER_UPDATE_DICT])
provider_m = provider_utils.db_member_to_provider_member(_member_mock)
old_provider_m = provider_utils.db_member_to_provider_member(
old_member).to_dict()
provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer( provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer(
_db_load_balancer_mock).to_dict() _db_load_balancer_mock).to_dict()
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with( assert_called_once_with(
_flow_mock, flow_utils.get_batch_update_members_flow,
[old_provider_m],
[{'member_id': 11}],
[(provider_m.to_dict(), MEMBER_UPDATE_DICT)],
store={constants.LISTENERS: [self.ref_listener_dict], store={constants.LISTENERS: [self.ref_listener_dict],
constants.LOADBALANCER_ID: LB_ID, constants.LOADBALANCER_ID: LB_ID,
constants.LOADBALANCER: provider_lb, constants.LOADBALANCER: provider_lb,
@ -974,13 +884,7 @@ class TestControllerWorker(base.TestCase):
constants.PROJECT_ID: PROJECT_ID, constants.PROJECT_ID: PROJECT_ID,
constants.AVAILABILITY_ZONE: {}})) constants.AVAILABILITY_ZONE: {}}))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.'
'pool_flows.PoolFlows.get_create_pool_flow',
return_value=_flow_mock)
def test_create_pool(self, def test_create_pool(self,
mock_get_create_listener_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -1001,8 +905,8 @@ class TestControllerWorker(base.TestCase):
provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer( provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer(
_db_load_balancer_mock).to_dict() _db_load_balancer_mock).to_dict()
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with(_flow_mock, assert_called_once_with(flow_utils.get_create_pool_flow,
store={constants.POOL_ID: POOL_ID, store={constants.POOL_ID: POOL_ID,
constants.LOADBALANCER_ID: constants.LOADBALANCER_ID:
LB_ID, LB_ID,
@ -1011,14 +915,9 @@ class TestControllerWorker(base.TestCase):
constants.LOADBALANCER: constants.LOADBALANCER:
provider_lb})) provider_lb}))
_flow_mock.run.assert_called_once_with()
self.assertEqual(1, mock_pool_repo_get.call_count) self.assertEqual(1, mock_pool_repo_get.call_count)
@mock.patch('octavia.controller.worker.v2.flows.'
'pool_flows.PoolFlows.get_delete_pool_flow',
return_value=_flow_mock)
def test_delete_pool(self, def test_delete_pool(self,
mock_get_delete_listener_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -1038,8 +937,8 @@ class TestControllerWorker(base.TestCase):
cw.delete_pool(_pool_mock) cw.delete_pool(_pool_mock)
provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer( provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer(
_db_load_balancer_mock).to_dict() _db_load_balancer_mock).to_dict()
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with(_flow_mock, assert_called_once_with(flow_utils.get_delete_pool_flow,
store={constants.POOL_ID: POOL_ID, store={constants.POOL_ID: POOL_ID,
constants.LOADBALANCER_ID: constants.LOADBALANCER_ID:
LB_ID, LB_ID,
@ -1049,13 +948,7 @@ class TestControllerWorker(base.TestCase):
provider_lb, provider_lb,
constants.PROJECT_ID: PROJECT_ID})) constants.PROJECT_ID: PROJECT_ID}))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.'
'pool_flows.PoolFlows.get_update_pool_flow',
return_value=_flow_mock)
def test_update_pool(self, def test_update_pool(self,
mock_get_update_listener_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -1076,8 +969,8 @@ class TestControllerWorker(base.TestCase):
cw.update_pool(_pool_mock, POOL_UPDATE_DICT) cw.update_pool(_pool_mock, POOL_UPDATE_DICT)
provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer( provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer(
_db_load_balancer_mock).to_dict() _db_load_balancer_mock).to_dict()
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with(_flow_mock, assert_called_once_with(flow_utils.get_update_pool_flow,
store={constants.POOL_ID: POOL_ID, store={constants.POOL_ID: POOL_ID,
constants.LISTENERS: constants.LISTENERS:
[self.ref_listener_dict], [self.ref_listener_dict],
@ -1088,13 +981,7 @@ class TestControllerWorker(base.TestCase):
constants.UPDATE_DICT: constants.UPDATE_DICT:
POOL_UPDATE_DICT})) POOL_UPDATE_DICT}))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.'
'l7policy_flows.L7PolicyFlows.get_create_l7policy_flow',
return_value=_flow_mock)
def test_create_l7policy(self, def test_create_l7policy(self,
mock_get_create_listener_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -1116,20 +1003,14 @@ class TestControllerWorker(base.TestCase):
} }
cw.create_l7policy(l7policy_mock) cw.create_l7policy(l7policy_mock)
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with(_flow_mock, assert_called_once_with(flow_utils.get_create_l7policy_flow,
store={constants.L7POLICY: l7policy_mock, store={constants.L7POLICY: l7policy_mock,
constants.LISTENERS: constants.LISTENERS:
[self.ref_listener_dict], [self.ref_listener_dict],
constants.LOADBALANCER_ID: LB_ID})) constants.LOADBALANCER_ID: LB_ID}))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.'
'l7policy_flows.L7PolicyFlows.get_delete_l7policy_flow',
return_value=_flow_mock)
def test_delete_l7policy(self, def test_delete_l7policy(self,
mock_get_delete_listener_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -1151,21 +1032,15 @@ class TestControllerWorker(base.TestCase):
} }
cw.delete_l7policy(l7policy_mock) cw.delete_l7policy(l7policy_mock)
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with(_flow_mock, assert_called_once_with(flow_utils.get_delete_l7policy_flow,
store={constants.L7POLICY: l7policy_mock, store={constants.L7POLICY: l7policy_mock,
constants.LISTENERS: constants.LISTENERS:
[self.ref_listener_dict], [self.ref_listener_dict],
constants.LOADBALANCER_ID: constants.LOADBALANCER_ID:
LB_ID})) LB_ID}))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.'
'l7policy_flows.L7PolicyFlows.get_update_l7policy_flow',
return_value=_flow_mock)
def test_update_l7policy(self, def test_update_l7policy(self,
mock_get_update_listener_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -1190,8 +1065,8 @@ class TestControllerWorker(base.TestCase):
cw.update_l7policy(l7policy_mock, L7POLICY_UPDATE_DICT) cw.update_l7policy(l7policy_mock, L7POLICY_UPDATE_DICT)
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with(_flow_mock, assert_called_once_with(flow_utils.get_update_l7policy_flow,
store={constants.L7POLICY: l7policy_mock, store={constants.L7POLICY: l7policy_mock,
constants.LISTENERS: constants.LISTENERS:
[self.ref_listener_dict], [self.ref_listener_dict],
@ -1200,13 +1075,7 @@ class TestControllerWorker(base.TestCase):
constants.UPDATE_DICT: constants.UPDATE_DICT:
L7POLICY_UPDATE_DICT})) L7POLICY_UPDATE_DICT}))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.'
'l7rule_flows.L7RuleFlows.get_create_l7rule_flow',
return_value=_flow_mock)
def test_create_l7rule(self, def test_create_l7rule(self,
mock_get_create_listener_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -1228,8 +1097,9 @@ class TestControllerWorker(base.TestCase):
l7_policy = provider_utils.db_l7policy_to_provider_l7policy( l7_policy = provider_utils.db_l7policy_to_provider_l7policy(
_l7policy_mock) _l7policy_mock)
(base_taskflow.BaseTaskFlowEngine._taskflow_load.
assert_called_once_with(_flow_mock, (cw.services_controller.run_poster.
assert_called_once_with(flow_utils.get_create_l7rule_flow,
store={constants.L7RULE: store={constants.L7RULE:
_l7rule_mock.to_dict(), _l7rule_mock.to_dict(),
constants.L7POLICY: constants.L7POLICY:
@ -1240,13 +1110,7 @@ class TestControllerWorker(base.TestCase):
[self.ref_listener_dict] [self.ref_listener_dict]
})) }))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.'
'l7rule_flows.L7RuleFlows.get_delete_l7rule_flow',
return_value=_flow_mock)
def test_delete_l7rule(self, def test_delete_l7rule(self,
mock_get_delete_listener_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -1266,8 +1130,8 @@ class TestControllerWorker(base.TestCase):
l7_policy = provider_utils.db_l7policy_to_provider_l7policy( l7_policy = provider_utils.db_l7policy_to_provider_l7policy(
_l7policy_mock) _l7policy_mock)
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with(_flow_mock, assert_called_once_with(flow_utils.get_delete_l7rule_flow,
store={ store={
constants.L7RULE: constants.L7RULE:
_l7rule_mock.to_dict(), _l7rule_mock.to_dict(),
@ -1279,13 +1143,7 @@ class TestControllerWorker(base.TestCase):
constants.LOADBALANCER_ID: LB_ID, constants.LOADBALANCER_ID: LB_ID,
})) }))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.controller.worker.v2.flows.'
'l7rule_flows.L7RuleFlows.get_update_l7rule_flow',
return_value=_flow_mock)
def test_update_l7rule(self, def test_update_l7rule(self,
mock_get_update_listener_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -1306,8 +1164,8 @@ class TestControllerWorker(base.TestCase):
l7_policy = provider_utils.db_l7policy_to_provider_l7policy( l7_policy = provider_utils.db_l7policy_to_provider_l7policy(
_l7policy_mock) _l7policy_mock)
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with(_flow_mock, assert_called_once_with(flow_utils.get_update_l7rule_flow,
store={ store={
constants.L7RULE: constants.L7RULE:
_l7rule_mock.to_dict(), _l7rule_mock.to_dict(),
@ -1320,19 +1178,13 @@ class TestControllerWorker(base.TestCase):
constants.UPDATE_DICT: constants.UPDATE_DICT:
L7RULE_UPDATE_DICT})) L7RULE_UPDATE_DICT}))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.db.repositories.AvailabilityZoneRepository.' @mock.patch('octavia.db.repositories.AvailabilityZoneRepository.'
'get_availability_zone_metadata_dict', return_value={}) 'get_availability_zone_metadata_dict', return_value={})
@mock.patch('octavia.db.repositories.FlavorRepository.' @mock.patch('octavia.db.repositories.FlavorRepository.'
'get_flavor_metadata_dict', return_value={}) 'get_flavor_metadata_dict', return_value={})
@mock.patch('octavia.controller.worker.v2.flows.'
'amphora_flows.AmphoraFlows.get_failover_flow',
return_value=_flow_mock)
@mock.patch('octavia.db.repositories.LoadBalancerRepository.update') @mock.patch('octavia.db.repositories.LoadBalancerRepository.update')
def test_failover_amphora(self, def test_failover_amphora(self,
mock_update, mock_update,
mock_get_failover_flow,
mock_get_flavor_meta, mock_get_flavor_meta,
mock_get_az_meta, mock_get_az_meta,
mock_api_get_session, mock_api_get_session,
@ -1348,13 +1200,17 @@ class TestControllerWorker(base.TestCase):
mock_amp_repo_get): mock_amp_repo_get):
_flow_mock.reset_mock() _flow_mock.reset_mock()
_db_amphora_mock.reset_mock()
mock_amp_repo_get.return_value = _db_amphora_mock
cw = controller_worker.ControllerWorker() cw = controller_worker.ControllerWorker()
cw.failover_amphora(AMP_ID) cw.failover_amphora(AMP_ID)
mock_amp_repo_get.return_value = _db_amphora_mock mock_lb_repo_get.return_value = _db_load_balancer_mock
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with( assert_called_once_with(
_flow_mock, flow_utils.get_failover_flow,
role=_db_amphora_mock.role,
load_balancer={},
wait=True,
store={constants.FAILED_AMPHORA: _db_amphora_mock.to_dict(), store={constants.FAILED_AMPHORA: _db_amphora_mock.to_dict(),
constants.LOADBALANCER_ID: constants.LOADBALANCER_ID:
_db_amphora_mock.load_balancer_id, _db_amphora_mock.load_balancer_id,
@ -1364,7 +1220,6 @@ class TestControllerWorker(base.TestCase):
constants.AVAILABILITY_ZONE: {} constants.AVAILABILITY_ZONE: {}
})) }))
_flow_mock.run.assert_called_once_with()
mock_update.assert_called_with(_db_session, LB_ID, mock_update.assert_called_with(_db_session, LB_ID,
provisioning_status=constants.ACTIVE) provisioning_status=constants.ACTIVE)
@ -1447,11 +1302,7 @@ class TestControllerWorker(base.TestCase):
@mock.patch( @mock.patch(
'octavia.db.repositories.AmphoraRepository.get_lb_for_amphora', 'octavia.db.repositories.AmphoraRepository.get_lb_for_amphora',
return_value=None) return_value=None)
@mock.patch('octavia.controller.worker.v2.flows.'
'amphora_flows.AmphoraFlows.get_failover_flow',
return_value=_flow_mock)
def test_failover_spare_amphora(self, def test_failover_spare_amphora(self,
mock_get_failover_flow,
mock_get_lb_for_amphora, mock_get_lb_for_amphora,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
@ -1472,14 +1323,17 @@ class TestControllerWorker(base.TestCase):
mock_amphora.id = AMP_ID mock_amphora.id = AMP_ID
mock_amphora.status = constants.AMPHORA_READY mock_amphora.status = constants.AMPHORA_READY
mock_amphora.load_balancer_id = None mock_amphora.load_balancer_id = None
mock_amphora.role = constants.ROLE_STANDALONE
cw = controller_worker.ControllerWorker() cw = controller_worker.ControllerWorker()
cw._perform_amphora_failover(mock_amphora, cw._perform_amphora_failover(mock_amphora,
constants.LB_CREATE_FAILOVER_PRIORITY) constants.LB_CREATE_FAILOVER_PRIORITY)
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with( assert_called_once_with(
_flow_mock, flow_utils.get_failover_flow,
role=constants.ROLE_STANDALONE, load_balancer=None,
wait=True,
store={constants.FAILED_AMPHORA: mock_amphora.to_dict(), store={constants.FAILED_AMPHORA: mock_amphora.to_dict(),
constants.LOADBALANCER_ID: None, constants.LOADBALANCER_ID: None,
constants.BUILD_TYPE_PRIORITY: constants.BUILD_TYPE_PRIORITY:
@ -1488,8 +1342,6 @@ class TestControllerWorker(base.TestCase):
constants.AVAILABILITY_ZONE: {} constants.AVAILABILITY_ZONE: {}
})) }))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.db.repositories.AmphoraHealthRepository.delete') @mock.patch('octavia.db.repositories.AmphoraHealthRepository.delete')
def test_failover_deleted_amphora(self, def test_failover_deleted_amphora(self,
mock_delete, mock_delete,
@ -1567,9 +1419,6 @@ class TestControllerWorker(base.TestCase):
'get_availability_zone_metadata_dict', return_value={}) 'get_availability_zone_metadata_dict', return_value={})
@mock.patch('octavia.db.repositories.FlavorRepository.' @mock.patch('octavia.db.repositories.FlavorRepository.'
'get_flavor_metadata_dict', return_value={}) 'get_flavor_metadata_dict', return_value={})
@mock.patch('octavia.controller.worker.v2.flows.'
'amphora_flows.AmphoraFlows.get_failover_flow',
return_value=_flow_mock)
@mock.patch( @mock.patch(
'octavia.db.repositories.AmphoraRepository.get_lb_for_amphora', 'octavia.db.repositories.AmphoraRepository.get_lb_for_amphora',
return_value=_db_load_balancer_mock) return_value=_db_load_balancer_mock)
@ -1577,7 +1426,6 @@ class TestControllerWorker(base.TestCase):
def test_failover_amphora_anti_affinity(self, def test_failover_amphora_anti_affinity(self,
mock_update, mock_update,
mock_get_lb_for_amphora, mock_get_lb_for_amphora,
mock_get_update_listener_flow,
mock_get_flavor_meta, mock_get_flavor_meta,
mock_get_az_meta, mock_get_az_meta,
mock_api_get_session, mock_api_get_session,
@ -1598,10 +1446,15 @@ class TestControllerWorker(base.TestCase):
cw = controller_worker.ControllerWorker() cw = controller_worker.ControllerWorker()
cw.failover_amphora(AMP_ID) cw.failover_amphora(AMP_ID)
provider_lb = provider_utils.db_loadbalancer_to_provider_loadbalancer(
_db_load_balancer_mock).to_dict()
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with( assert_called_once_with(
_flow_mock, flow_utils.get_failover_flow,
role=_db_amphora_mock.role,
load_balancer=provider_lb,
wait=True,
store={constants.FAILED_AMPHORA: _db_amphora_mock.to_dict(), store={constants.FAILED_AMPHORA: _db_amphora_mock.to_dict(),
constants.LOADBALANCER_ID: constants.LOADBALANCER_ID:
_db_amphora_mock.load_balancer_id, _db_amphora_mock.load_balancer_id,
@ -1612,15 +1465,10 @@ class TestControllerWorker(base.TestCase):
constants.AVAILABILITY_ZONE: {} constants.AVAILABILITY_ZONE: {}
})) }))
_flow_mock.run.assert_called_once_with()
mock_update.assert_called_with(_db_session, LB_ID, mock_update.assert_called_with(_db_session, LB_ID,
provisioning_status=constants.ACTIVE) provisioning_status=constants.ACTIVE)
@mock.patch('octavia.controller.worker.v2.flows.'
'amphora_flows.AmphoraFlows.cert_rotate_amphora_flow',
return_value=_flow_mock)
def test_amphora_cert_rotation(self, def test_amphora_cert_rotation(self,
mock_get_update_listener_flow,
mock_api_get_session, mock_api_get_session,
mock_dyn_log_listener, mock_dyn_log_listener,
mock_taskflow_load, mock_taskflow_load,
@ -1636,22 +1484,17 @@ class TestControllerWorker(base.TestCase):
cw = controller_worker.ControllerWorker() cw = controller_worker.ControllerWorker()
cw.amphora_cert_rotation(AMP_ID) cw.amphora_cert_rotation(AMP_ID)
mock_amp_repo_get.return_value = _db_amphora_mock mock_amp_repo_get.return_value = _db_amphora_mock
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with(_flow_mock, assert_called_once_with(flow_utils.cert_rotate_amphora_flow,
store={constants.AMPHORA: store={constants.AMPHORA:
_db_amphora_mock.to_dict(), _db_amphora_mock.to_dict(),
constants.AMPHORA_ID: constants.AMPHORA_ID:
_amphora_mock[constants.ID]})) _amphora_mock[constants.ID]}))
_flow_mock.run.assert_called_once_with()
@mock.patch('octavia.db.repositories.FlavorRepository.' @mock.patch('octavia.db.repositories.FlavorRepository.'
'get_flavor_metadata_dict') 'get_flavor_metadata_dict')
@mock.patch('octavia.db.repositories.AmphoraRepository.get_lb_for_amphora') @mock.patch('octavia.db.repositories.AmphoraRepository.get_lb_for_amphora')
@mock.patch('octavia.controller.worker.v2.flows.'
'amphora_flows.AmphoraFlows.update_amphora_config_flow',
return_value=_flow_mock)
def test_update_amphora_agent_config(self, def test_update_amphora_agent_config(self,
mock_update_flow,
mock_get_lb_for_amp, mock_get_lb_for_amp,
mock_flavor_meta, mock_flavor_meta,
mock_api_get_session, mock_api_get_session,
@ -1676,27 +1519,24 @@ class TestControllerWorker(base.TestCase):
mock_amp_repo_get.assert_called_once_with(_db_session, id=AMP_ID) mock_amp_repo_get.assert_called_once_with(_db_session, id=AMP_ID)
mock_get_lb_for_amp.assert_called_once_with(_db_session, AMP_ID) mock_get_lb_for_amp.assert_called_once_with(_db_session, AMP_ID)
mock_flavor_meta.assert_called_once_with(_db_session, 'vanilla') mock_flavor_meta.assert_called_once_with(_db_session, 'vanilla')
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with(_flow_mock, assert_called_once_with(flow_utils.update_amphora_config_flow,
store={constants.AMPHORA: store={constants.AMPHORA:
_db_amphora_mock.to_dict(), _db_amphora_mock.to_dict(),
constants.FLAVOR: {'test': 'dict'}})) constants.FLAVOR: {'test': 'dict'}}))
_flow_mock.run.assert_called_once_with()
# Test with no flavor # Test with no flavor
_flow_mock.reset_mock() _flow_mock.reset_mock()
mock_amp_repo_get.reset_mock() mock_amp_repo_get.reset_mock()
mock_get_lb_for_amp.reset_mock() mock_get_lb_for_amp.reset_mock()
mock_flavor_meta.reset_mock() mock_flavor_meta.reset_mock()
base_taskflow.BaseTaskFlowEngine._taskflow_load.reset_mock()
mock_lb.flavor_id = None mock_lb.flavor_id = None
cw.update_amphora_agent_config(AMP_ID) cw.update_amphora_agent_config(AMP_ID)
mock_amp_repo_get.assert_called_once_with(_db_session, id=AMP_ID) mock_amp_repo_get.assert_called_once_with(_db_session, id=AMP_ID)
mock_get_lb_for_amp.assert_called_once_with(_db_session, AMP_ID) mock_get_lb_for_amp.assert_called_once_with(_db_session, AMP_ID)
mock_flavor_meta.assert_not_called() mock_flavor_meta.assert_not_called()
(base_taskflow.BaseTaskFlowEngine._taskflow_load. (cw.services_controller.run_poster.
assert_called_once_with(_flow_mock, assert_called_once_with(flow_utils.update_amphora_config_flow,
store={constants.AMPHORA: store={constants.AMPHORA:
_db_amphora_mock.to_dict(), _db_amphora_mock.to_dict(),
constants.FLAVOR: {}})) constants.FLAVOR: {}}))
_flow_mock.run.assert_called_once_with()

View File

@ -0,0 +1,7 @@
---
features:
- |
Operators can now use the amphorav2 provider which uses jobboard-based
controller. A jobboard controller solves the issue with resources stuck in
PENDING_* states by writing info about task states in persistent backend
and monitoring job claims via jobboard.

View File

@ -6,6 +6,7 @@ cotyledon>=1.3.0 # Apache-2.0
pecan>=1.3.2 # BSD pecan>=1.3.2 # BSD
pbr!=2.1.0,>=2.0.0 # Apache-2.0 pbr!=2.1.0,>=2.0.0 # Apache-2.0
SQLAlchemy!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8,>=1.0.10 # MIT SQLAlchemy!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8,>=1.0.10 # MIT
SQLAlchemy-Utils>=0.30.11
Babel!=2.4.0,>=2.3.4 # BSD Babel!=2.4.0,>=2.3.4 # BSD
futurist>=1.2.0 # Apache-2.0 futurist>=1.2.0 # Apache-2.0
requests>=2.14.2 # Apache-2.0 requests>=2.14.2 # Apache-2.0
@ -37,7 +38,7 @@ python-cinderclient>=3.3.0 # Apache-2.0
pyOpenSSL>=17.1.0 # Apache-2.0 pyOpenSSL>=17.1.0 # Apache-2.0
WSME>=0.8.0 # MIT WSME>=0.8.0 # MIT
Jinja2>=2.10 # BSD License (3 clause) Jinja2>=2.10 # BSD License (3 clause)
taskflow>=2.16.0 # Apache-2.0 taskflow>=4.1.0 # Apache-2.0
diskimage-builder>=2.24.0 # Apache-2.0 diskimage-builder>=2.24.0 # Apache-2.0
castellan>=0.16.0 # Apache-2.0 castellan>=0.16.0 # Apache-2.0
tenacity>=5.0.4 # Apache-2.0 tenacity>=5.0.4 # Apache-2.0

View File

@ -94,6 +94,9 @@ octavia.barbican_auth =
barbican_acl_auth = octavia.certificates.common.auth.barbican_acl:BarbicanACLAuth barbican_acl_auth = octavia.certificates.common.auth.barbican_acl:BarbicanACLAuth
octavia.plugins = octavia.plugins =
hot_plug_plugin = octavia.controller.worker.v1.controller_worker:ControllerWorker hot_plug_plugin = octavia.controller.worker.v1.controller_worker:ControllerWorker
octavia.worker.jobboard_driver =
redis_taskflow_driver = octavia.controller.worker.v2.taskflow_jobboard_driver:RedisTaskFlowDriver
zookeeper_taskflow_driver = octavia.controller.worker.v2.taskflow_jobboard_driver:ZookeeperTaskFlowDriver
oslo.config.opts = oslo.config.opts =
octavia = octavia.opts:list_opts octavia = octavia.opts:list_opts
oslo.policy.policies = oslo.policy.policies =

View File

@ -69,12 +69,16 @@
name: octavia-v2-dsvm-scenario-amphora-v2 name: octavia-v2-dsvm-scenario-amphora-v2
parent: octavia-v2-dsvm-scenario parent: octavia-v2-dsvm-scenario
vars: vars:
devstack_localrc:
OCTAVIA_ENABLE_AMPHORAV2_PROVIDER: True
devstack_local_conf: devstack_local_conf:
post-config: post-config:
$OCTAVIA_CONF: $OCTAVIA_CONF:
api_settings: api_settings:
default_provider_driver: amphorav2 default_provider_driver: amphorav2
enabled_provider_drivers: amphorav2:The v2 amphora driver. enabled_provider_drivers: amphorav2:The v2 amphora driver.
task_flow:
jobboard_expiration_time: 100
test-config: test-config:
"$TEMPEST_CONFIG": "$TEMPEST_CONFIG":
load_balancer: load_balancer: