ACTIVE-ACTIVE: Initial distributor driver

This patch is the initial implementation of a distributor driver for
Octavia Active/Active topology support.

This patch is a decompostion of the following patch:
https://review.openstack.org/#/c/313006

Story: 2001288
Task: 5836

Depends-On: I97b52b80efb33749647229a55147a08afa112dd2
Change-Id: I65e4a533caee692e1c98e8c6586c2e2132f2e34c
Co-Authored-By: Valeria Perelman <perelman@il.ibm.com>
This commit is contained in:
Michael Johnson 2017-11-13 15:56:10 -08:00
parent e49adf1f09
commit 7b1621789c
9 changed files with 279 additions and 0 deletions

View File

@ -222,6 +222,11 @@
#
# network_driver = network_noop_driver
#
# Distributor driver options are distributor_noop_driver
# single_VIP_amphora
#
# distributor_driver = distributor_noop_driver
#
# Load balancer topology options are SINGLE, ACTIVE_STANDBY
# loadbalancer_topology = SINGLE
# user_data_config_drive = False

View File

@ -331,6 +331,9 @@ controller_worker_opts = [
cfg.StrOpt('network_driver',
default='network_noop_driver',
help=_('Name of the network driver to use')),
cfg.StrOpt('distributor_driver',
default='distributor_noop_driver',
help=_('Name of the distributor driver to use')),
cfg.StrOpt('loadbalancer_topology',
default=constants.TOPOLOGY_SINGLE,
choices=constants.SUPPORTED_LB_TOPOLOGIES,

View File

View File

View File

@ -0,0 +1,144 @@
# Copyright 2016 IBM Corp.
# Copyright 2017 Rackspace, US 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.
import abc
import six
# This class describes the abstraction of a distributor interface.
# Distributor implementations may be: a noop, a single hardware device,
# a single amphora, or multiple amphora among other options.
@six.add_metaclass(abc.ABCMeta)
class DistributorDriver(object):
@abc.abstractmethod
def get_create_distributor_subflow(self):
"""Get a subflow to create a distributor
:requires: **load_balancer** (object) - Load balancer object
associated with this distributor
:provides: **distributor_id** (string) - The created distributor ID
:returns: A TaskFlow Flow that will create the distributor
This method will setup the TaskFlow Flow required to setup the
database fields and create a distributor should the driver need to
instantiate one.
The flow must store the generated distibutor ID in the flow.
"""
pass
@abc.abstractmethod
def get_delete_distributor_subflow(self):
"""Get a subflow that deletes a distributor
:requires: **distributor_id** (string) - The ID of the distributor
to delete
:returns: A TaskFlow Flow that will delete the distributor
This method will return a TaskFlow Flow that deletes the distributor
(if applicable for the driver) and cleans up any associated database
records.
"""
pass
@abc.abstractmethod
def get_add_vip_subflow(self):
"""Get a subflow that adds a VIP to a distributor
:requires: **distributor_id** (string) - The ID of the distributor
to create the VIP on.
:requires: **vip** (object) - The VIP object to create on the
distributor.
:requires: **vip_alg** (string) - The optional algorithm to use for
this VIP.
:requires: **vip_persistence** (string) - The persistence type for
this VIP.
:returns: A TaskFlow Flow that will add a VIP to the distributor
This method will return a TaskFlow Flow that adds a VIP to the
distributor by perfoming the necessary steps to plug the VIP and
configure the distributor to start receiving requests on this VIP.
"""
pass
@abc.abstractmethod
def get_remove_vip_subflow(self):
"""Get a subflow that removes a VIP from a distributor
:requires: **distributor_id** (string) - The ID of the distributor
to remove the VIP from.
:requires: **vip** (object) - The VIP object to remove from the
distributor.
:returns: A TaskFlow Flow that will remove a VIP from the distributor
This method will return a TaskFlow Flow that removes the VIP from the
distributor by reconfiguring the distributor and unplugging the
associated port.
"""
pass
@abc.abstractmethod
def get_register_amphorae_subflow(self):
"""Get a subflow that Registers amphorae with the distributor
:requires: **distributor_id** (string) - The ID of the distributor
to register the amphora on
:requires: **amphorae** (tuple) - Tuple of amphora objects to
register with the distributor.
:returns: A TaskFlow Flow that will register amphorae with the
distributor
This method will return a TaskFlow Flow that registers amphorae with
the distributor so it can begin to receive requests from the
distributor. Amphora should be ready to receive requests prior to
this call being made.
"""
pass
@abc.abstractmethod
def get_drain_amphorae_subflow(self):
"""Get a subflow that drains connections from amphorae
:requires: **distributor_id** (string) - The ID of the distributor
to drain amphorae from
:requires: **amphorae** (tuple) - Tuple of amphora objects to drain
from distributor.
:returns: A TaskFlow Flow that will drain the listed amphorae on the
distributor
This method will return a TaskFlow Flow that configures the
distributor to stop sending new connections to the amphorae in the
list. Existing connections will continue to pass traffic to the
amphorae in this list.
"""
pass
@abc.abstractmethod
def get_unregister_amphorae_subflow(self):
"""Get a subflow that unregisters amphorae from a distributor
:requires: **distributor_id** (string) - The ID of the distributor
to unregister amphorae from
:requires: **amphorae** (tuple) - Tuple of amphora objects to
unregister from distributor.
:returns: A TaskFlow Flow that will unregister amphorae from the
distributor
This method will return a TaskFlow Flow that unregisters amphorae
from the distributor. Amphorae in this list will immediately stop
receiving traffic.
"""
pass

View File

@ -0,0 +1,124 @@
# Copyright 2016 IBM Corp.
# Copyright 2017 Rackspace, US 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.
from taskflow.patterns import linear_flow
from taskflow import task
from oslo_log import log as logging
from oslo_utils import uuidutils
from octavia.distributor.drivers import driver_base
LOG = logging.getLogger(__name__)
class NoopProvidesRequiresTask(task.Task):
def __init__(self, name, provides_dicts=None, requires=None):
if provides_dicts is None:
provides_dicts = {}
super(NoopProvidesRequiresTask, self).__init__(
name=name,
provides=list(provides_dicts),
requires=requires)
self.provides_dict = provides_dicts
def execute(self, *args, **kwargs):
return self.provides_dict.values()
class NoopManager(object):
def __init__(self):
super(NoopManager, self).__init__()
def get_create_distributor_subflow(self):
LOG.debug('Distributor %s create_distributor', self.__class__.__name__)
create_distributor_flow = linear_flow.Flow('create-distributor')
create_distributor_flow.add(NoopProvidesRequiresTask(
'create-distributor-task',
requires=('load_balancer'),
provides_dicts={'distributor_id': uuidutils.generate_uuid()}))
return create_distributor_flow
def get_delete_distributor_subflow(self):
LOG.debug('Distributor %s delete_distributor', self.__class__.__name__)
delete_distributor_flow = linear_flow.Flow('delete-distributor')
delete_distributor_flow.add(NoopProvidesRequiresTask(
'delete-distributor-task', requires=('distributor_id')))
return delete_distributor_flow
def get_add_vip_subflow(self):
LOG.debug('Distributor %s add_vip', self.__class__.__name__)
add_vip_flow = linear_flow.Flow('add-vip')
add_vip_flow.add(NoopProvidesRequiresTask(
'add-vip-task', requires=('distributor_id', 'vip',
'vip_alg', 'vip_persistence')))
return add_vip_flow
def get_remove_vip_subflow(self):
LOG.debug('Distributor %s remove_vip', self.__class__.__name__)
remove_vip_flow = linear_flow.Flow('remove-vip')
remove_vip_flow.add(NoopProvidesRequiresTask('remove-vip-task',
requires=('distributor_id', 'vip')))
return remove_vip_flow
def get_register_amphorae_subflow(self):
LOG.debug('Distributor %s register_amphorae', self.__class__.__name__)
register_amphorae_flow = linear_flow.Flow('register_amphorae')
register_amphorae_flow.add(NoopProvidesRequiresTask(
'register_amphorae_task', requires=('distributor_id', 'amphorae')))
return register_amphorae_flow
def get_drain_amphorae_subflow(self):
LOG.debug('Distributor %s drain_amphorae', self.__class__.__name__)
drain_amphorae_flow = linear_flow.Flow('drain-amphorae')
drain_amphorae_flow.add(NoopProvidesRequiresTask(
'drain_amphorae_task', requires=('distributor_id', 'amphorae')))
return drain_amphorae_flow
def get_unregister_amphorae_subflow(self):
LOG.debug('Distributor %s unregister_amphorae',
self.__class__.__name__)
unregister_amphorae_flow = linear_flow.Flow('unregister_amphora')
unregister_amphorae_flow.add(NoopProvidesRequiresTask(
'unregister_amphorae_task', requires=('distributor_id',
'amphorae')))
return unregister_amphorae_flow
class NoopDistributorDriver(driver_base.DistributorDriver):
def __init__(self):
super(NoopDistributorDriver, self).__init__()
self.driver = NoopManager()
def get_create_distributor_subflow(self):
return self.driver.get_create_distributor_subflow()
def get_delete_distributor_subflow(self):
return self.driver.get_delete_distributor_subflow()
def get_add_vip_flow(self):
return self.driver.get_add_vip_subflow()
def get_remove_vip_subflow(self):
return self.driver.get_remove_vip_subflow()
def get_register_amphorae_subflow(self):
return self.driver.get_register_amphorae_subflow()
def get_drain_amphorae_subflow(self):
self.driver.get_drain_amphorae_subflow()
def get_unregister_amphorae_subflow(self):
self.driver.get_unregister_amphorae_subflow()

View File

@ -85,6 +85,9 @@ octavia.network.drivers =
network_noop_driver = octavia.network.drivers.noop_driver.driver:NoopNetworkDriver
allowed_address_pairs_driver = octavia.network.drivers.neutron.allowed_address_pairs:AllowedAddressPairsDriver
containers_driver = octavia.network.drivers.neutron.containers:ContainersDriver
octavia.distributor.drivers =
distributor_noop_driver = octavia.distributor.drivers.noop_driver.driver:NoopDistributorDriver
single_VIP_amphora = octavia.distributor.drivers.single_VIP_amphora.driver:SingleVIPAmpDistributorDriver
octavia.cert_generator =
local_cert_generator = octavia.certificates.generator.local:LocalCertGenerator
anchor_cert_generator = octavia.certificates.generator.anchor:AnchorCertGenerator