Implement provider drivers - Load Balancer
This patch adds provider driver support to the Octavia v2 API, starting with the load balancer API. This patch also creates a provider driver for Octavia, initially fully implementing the load balancer methods. Follow on patches will implement the remain parts of the API. Change-Id: Ia15280827799d1800c23ed76d2af0e3596b9d2f7 Story: 1655768 Task: 5165
This commit is contained in:
parent
dfa7ef2ab3
commit
7b2621fe29
@ -43,6 +43,12 @@
|
||||
# Enable/disable ability for users to create PING type Health Monitors
|
||||
# allow_ping_health_monitors = True
|
||||
|
||||
# List of enabled provider drivers
|
||||
# enabled_provider_drivers = octavia, amphora
|
||||
|
||||
# Default provider driver
|
||||
# default_provider_driver = amphora
|
||||
|
||||
[database]
|
||||
# This line MUST be changed to actually run the plugin.
|
||||
# Example:
|
||||
|
@ -28,6 +28,7 @@ app = {
|
||||
# WSME Configurations
|
||||
# See https://wsme.readthedocs.org/en/latest/integrate.html#configuration
|
||||
wsme = {
|
||||
# Keeping debug True for now so we can easily troubleshoot.
|
||||
'debug': True
|
||||
# Provider driver uses 501 if the driver is not installed.
|
||||
# Don't dump a stack trace for 501s
|
||||
'debug': False
|
||||
}
|
||||
|
11
octavia/api/drivers/amphora_driver/__init__.py
Normal file
11
octavia/api/drivers/amphora_driver/__init__.py
Normal file
@ -0,0 +1,11 @@
|
||||
# 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.
|
163
octavia/api/drivers/amphora_driver/driver.py
Normal file
163
octavia/api/drivers/amphora_driver/driver.py
Normal file
@ -0,0 +1,163 @@
|
||||
# Copyright 2018 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 oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
import oslo_messaging as messaging
|
||||
|
||||
from octavia.api.drivers import exceptions
|
||||
from octavia.api.drivers import provider_base as driver_base
|
||||
from octavia.api.drivers import utils as driver_utils
|
||||
from octavia.common import constants as consts
|
||||
from octavia.common import data_models
|
||||
from octavia.common import utils
|
||||
from octavia.network import base as network_base
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.import_group('oslo_messaging', 'octavia.common.config')
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AmphoraProviderDriver(driver_base.ProviderDriver):
|
||||
def __init__(self):
|
||||
super(AmphoraProviderDriver, self).__init__()
|
||||
topic = cfg.CONF.oslo_messaging.topic
|
||||
self.transport = messaging.get_rpc_transport(cfg.CONF)
|
||||
self.target = messaging.Target(
|
||||
namespace=consts.RPC_NAMESPACE_CONTROLLER_AGENT,
|
||||
topic=topic, version="1.0", fanout=False)
|
||||
self.client = messaging.RPCClient(self.transport, target=self.target)
|
||||
|
||||
# Load Balancer
|
||||
def create_vip_port(self, loadbalancer_id, project_id, vip_dictionary):
|
||||
vip_obj = driver_utils.provider_vip_dict_to_vip_obj(vip_dictionary)
|
||||
lb_obj = data_models.LoadBalancer(id=loadbalancer_id,
|
||||
project_id=project_id, vip=vip_obj)
|
||||
|
||||
network_driver = utils.get_network_driver()
|
||||
try:
|
||||
vip = network_driver.allocate_vip(lb_obj)
|
||||
except network_base.AllocateVIPException as e:
|
||||
raise exceptions.DriverError(user_fault_string=e.orig_msg,
|
||||
operator_fault_string=e.orig_msg)
|
||||
|
||||
LOG.info('Amphora provider created VIP port %s for load balancer %s.',
|
||||
vip.port_id, loadbalancer_id)
|
||||
return driver_utils.vip_dict_to_provider_dict(vip.to_dict())
|
||||
|
||||
def loadbalancer_create(self, loadbalancer):
|
||||
payload = {consts.LOAD_BALANCER_ID: loadbalancer.loadbalancer_id}
|
||||
self.client.cast({}, 'create_load_balancer', **payload)
|
||||
|
||||
def loadbalancer_delete(self, loadbalancer_id, cascade=False):
|
||||
payload = {consts.LOAD_BALANCER_ID: loadbalancer_id,
|
||||
'cascade': cascade}
|
||||
self.client.cast({}, 'delete_load_balancer', **payload)
|
||||
|
||||
def loadbalancer_failover(self, loadbalancer_id):
|
||||
payload = {consts.LOAD_BALANCER_ID: loadbalancer_id}
|
||||
self.client.cast({}, 'failover_load_balancer', **payload)
|
||||
|
||||
def loadbalancer_update(self, loadbalancer):
|
||||
# Adapt the provider data model to the queue schema
|
||||
lb_dict = loadbalancer.to_dict()
|
||||
if 'admin_state_up' in lb_dict:
|
||||
lb_dict['enabled'] = lb_dict.pop('admin_state_up')
|
||||
lb_id = lb_dict.pop('loadbalancer_id')
|
||||
|
||||
payload = {consts.LOAD_BALANCER_ID: lb_id,
|
||||
consts.LOAD_BALANCER_UPDATES: lb_dict}
|
||||
self.client.cast({}, 'update_load_balancer', **payload)
|
||||
|
||||
# Listener
|
||||
def listener_create(self, listener):
|
||||
payload = {consts.LISTENER_ID: listener.listener_id}
|
||||
self.client.cast({}, 'create_listener', **payload)
|
||||
|
||||
def listener_delete(self, listener_id):
|
||||
payload = {consts.LISTENER_ID: listener_id}
|
||||
self.client.cast({}, 'delete_listener', **payload)
|
||||
|
||||
def listener_update(self, listener):
|
||||
pass
|
||||
|
||||
# Pool
|
||||
def pool_create(self, pool):
|
||||
payload = {consts.POOL_ID: pool.pool_id}
|
||||
self.client.cast({}, 'create_pool', **payload)
|
||||
|
||||
def pool_delete(self, pool_id):
|
||||
payload = {consts.POOL_ID: pool_id}
|
||||
self.client.cast({}, 'delete_pool', **payload)
|
||||
|
||||
def pool_update(self, pool):
|
||||
pass
|
||||
|
||||
# Member
|
||||
def member_create(self, member):
|
||||
payload = {consts.MEMBER_ID: member.member_id}
|
||||
self.client.cast({}, 'create_member', **payload)
|
||||
|
||||
def member_delete(self, member_id):
|
||||
payload = {consts.MEMBER_ID: member_id}
|
||||
self.client.cast({}, 'delete_member', **payload)
|
||||
|
||||
def member_update(self, member):
|
||||
pass
|
||||
|
||||
def member_batch_update(self, members):
|
||||
pass
|
||||
|
||||
# Health Monitor
|
||||
def health_monitor_create(self, healthmonitor):
|
||||
payload = {consts.HEALTH_MONITOR_ID: healthmonitor.healthmonitor_id}
|
||||
self.client.cast({}, 'create_health_monitor', **payload)
|
||||
|
||||
def health_monitor_delete(self, healthmonitor_id):
|
||||
payload = {consts.HEALTH_MONITOR_ID: healthmonitor_id}
|
||||
self.client.cast({}, 'delete_health_monitor', **payload)
|
||||
|
||||
def health_monitor_update(self, healthmonitor):
|
||||
pass
|
||||
|
||||
# L7 Policy
|
||||
def l7policy_create(self, l7policy):
|
||||
payload = {consts.L7POLICY_ID: l7policy.l7policy_id}
|
||||
self.client.cast({}, 'create_l7policy', **payload)
|
||||
|
||||
def l7policy_delete(self, l7policy_id):
|
||||
payload = {consts.L7POLICY_ID: l7policy_id}
|
||||
self.client.cast({}, 'delete_l7policy', **payload)
|
||||
|
||||
def l7policy_update(self, l7policy):
|
||||
pass
|
||||
|
||||
# L7 Rule
|
||||
def l7rule_create(self, l7rule):
|
||||
payload = {consts.L7RULE_ID: l7rule.l7rule_id}
|
||||
self.client.cast({}, 'create_l7rule', **payload)
|
||||
|
||||
def l7rule_delete(self, l7rule_id):
|
||||
payload = {consts.L7RULE_ID: l7rule_id}
|
||||
self.client.cast({}, 'delete_l7rule', **payload)
|
||||
|
||||
def l7rule_update(self, l7rule):
|
||||
pass
|
||||
|
||||
# Flavor
|
||||
def get_supported_flavor_metadata(self):
|
||||
pass
|
||||
|
||||
def validate_flavor(self, flavor_metadata):
|
||||
pass
|
@ -17,9 +17,14 @@
|
||||
|
||||
import six
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BaseDataModel(object):
|
||||
def to_dict(self, calling_classes=None, recurse=False, **kwargs):
|
||||
def to_dict(self, calling_classes=None, recurse=False,
|
||||
render_unsets=False, **kwargs):
|
||||
"""Converts a data model to a dictionary."""
|
||||
calling_classes = calling_classes or []
|
||||
ret = {}
|
||||
@ -36,24 +41,35 @@ class BaseDataModel(object):
|
||||
if type(self) not in calling_classes:
|
||||
ret[attr].append(
|
||||
item.to_dict(calling_classes=(
|
||||
calling_classes + [type(self)])))
|
||||
calling_classes + [type(self)]),
|
||||
render_unsets=render_unsets))
|
||||
else:
|
||||
ret[attr] = None
|
||||
ret[attr].append(None)
|
||||
else:
|
||||
ret[attr] = item
|
||||
ret[attr].append(item)
|
||||
elif isinstance(getattr(self, attr), BaseDataModel):
|
||||
if type(self) not in calling_classes:
|
||||
ret[attr] = value.to_dict(
|
||||
render_unsets=render_unsets,
|
||||
calling_classes=calling_classes + [type(self)])
|
||||
else:
|
||||
ret[attr] = None
|
||||
elif six.PY2 and isinstance(value, six.text_type):
|
||||
ret[attr.encode('utf8')] = value.encode('utf8')
|
||||
elif isinstance(value, UnsetType):
|
||||
if render_unsets:
|
||||
ret[attr] = None
|
||||
else:
|
||||
continue
|
||||
else:
|
||||
ret[attr] = value
|
||||
else:
|
||||
if isinstance(getattr(self, attr), (BaseDataModel, list)):
|
||||
ret[attr] = None
|
||||
if (isinstance(getattr(self, attr), (BaseDataModel, list)) or
|
||||
isinstance(value, UnsetType)):
|
||||
if render_unsets:
|
||||
ret[attr] = None
|
||||
else:
|
||||
continue
|
||||
else:
|
||||
ret[attr] = value
|
||||
|
||||
@ -72,32 +88,49 @@ class BaseDataModel(object):
|
||||
return cls(**dict)
|
||||
|
||||
|
||||
class UnsetType(object):
|
||||
def __bool__(self):
|
||||
return False
|
||||
__nonzero__ = __bool__
|
||||
|
||||
def __repr__(self):
|
||||
return 'Unset'
|
||||
|
||||
|
||||
Unset = UnsetType()
|
||||
|
||||
|
||||
class LoadBalancer(BaseDataModel):
|
||||
def __init__(self, admin_state_up=None, description=None, flavor=None,
|
||||
listeners=None, loadbalancer_id=None, name=None,
|
||||
project_id=None, vip_address=None, vip_network_id=None,
|
||||
vip_port_id=None, vip_subnet_id=None):
|
||||
def __init__(self, admin_state_up=Unset, description=Unset, flavor=Unset,
|
||||
listeners=Unset, loadbalancer_id=Unset, name=Unset,
|
||||
pools=Unset, project_id=Unset, vip_address=Unset,
|
||||
vip_network_id=Unset, vip_port_id=Unset, vip_subnet_id=Unset,
|
||||
vip_qos_policy_id=Unset):
|
||||
|
||||
self.admin_state_up = admin_state_up
|
||||
self.description = description
|
||||
self.flavor = flavor or {}
|
||||
self.listeners = listeners or []
|
||||
self.flavor = flavor
|
||||
self.listeners = listeners
|
||||
self.loadbalancer_id = loadbalancer_id
|
||||
self.name = name
|
||||
self.pools = pools
|
||||
self.project_id = project_id
|
||||
self.vip_address = vip_address
|
||||
self.vip_network_id = vip_network_id
|
||||
self.vip_port_id = vip_port_id
|
||||
self.vip_subnet_id = vip_subnet_id
|
||||
self.vip_qos_policy_id = vip_qos_policy_id
|
||||
|
||||
|
||||
class Listener(BaseDataModel):
|
||||
def __init__(self, admin_state_up=None, connection_limit=None,
|
||||
default_pool=None, default_pool_id=None,
|
||||
default_tls_container=None, description=None,
|
||||
insert_headers=None, l7policies=None, listener_id=None,
|
||||
loadbalancer_id=None, name=None, protocol=None,
|
||||
protocol_port=None, sni_containers=None):
|
||||
def __init__(self, admin_state_up=Unset, connection_limit=Unset,
|
||||
default_pool=Unset, default_pool_id=Unset,
|
||||
default_tls_container=Unset, description=Unset,
|
||||
insert_headers=Unset, l7policies=Unset, listener_id=Unset,
|
||||
loadbalancer_id=Unset, name=Unset, protocol=Unset,
|
||||
protocol_port=Unset, sni_containers=Unset,
|
||||
timeout_client_data=Unset, timeout_member_connect=Unset,
|
||||
timeout_member_data=Unset, timeout_tcp_inspect=Unset):
|
||||
|
||||
self.admin_state_up = admin_state_up
|
||||
self.connection_limit = connection_limit
|
||||
@ -105,40 +138,43 @@ class Listener(BaseDataModel):
|
||||
self.default_pool_id = default_pool_id
|
||||
self.default_tls_container = default_tls_container
|
||||
self.description = description
|
||||
self.insert_headers = insert_headers or {}
|
||||
self.l7policies = l7policies or []
|
||||
self.insert_headers = insert_headers
|
||||
self.l7policies = l7policies
|
||||
self.listener_id = listener_id
|
||||
self.loadbalancer_id = loadbalancer_id
|
||||
self.name = name
|
||||
self.protocol = protocol
|
||||
self.protocol_port = protocol_port
|
||||
self.sni_containers = sni_containers
|
||||
self.timeout_client_data = timeout_client_data
|
||||
self.timeout_member_connect = timeout_member_connect
|
||||
self.timeout_member_data = timeout_member_data
|
||||
self.timeout_tcp_inspect = timeout_tcp_inspect
|
||||
|
||||
|
||||
class Pool(BaseDataModel):
|
||||
def __init__(self, admin_state_up=None, description=None,
|
||||
healthmonitor=None, lb_algorithm=None, listener_id=None,
|
||||
loadbalancer_id=None, members=None, name=None, pool_id=None,
|
||||
protocol=None, session_persistence=None):
|
||||
def __init__(self, admin_state_up=Unset, description=Unset,
|
||||
healthmonitor=Unset, lb_algorithm=Unset,
|
||||
loadbalancer_id=Unset, members=Unset, name=Unset,
|
||||
pool_id=Unset, protocol=Unset, session_persistence=Unset):
|
||||
|
||||
self.admin_state_up = admin_state_up
|
||||
self.description = description
|
||||
self.healthmonitor = healthmonitor
|
||||
self.lb_algorithm = lb_algorithm
|
||||
self.listener_id = listener_id
|
||||
self.loadbalancer_id = loadbalancer_id
|
||||
self.members = members or []
|
||||
self.members = members
|
||||
self.name = name
|
||||
self.pool_id = pool_id
|
||||
self.protocol = protocol
|
||||
self.session_persistence = session_persistence or {}
|
||||
self.session_persistence = session_persistence
|
||||
|
||||
|
||||
class Member(BaseDataModel):
|
||||
def __init__(self, address=None, admin_state_up=None, member_id=None,
|
||||
monitor_address=None, monitor_port=None, name=None,
|
||||
pool_id=None, protocol_port=None, subnet_id=None,
|
||||
weight=None):
|
||||
def __init__(self, address=Unset, admin_state_up=Unset, member_id=Unset,
|
||||
monitor_address=Unset, monitor_port=Unset, name=Unset,
|
||||
pool_id=Unset, protocol_port=Unset, subnet_id=Unset,
|
||||
weight=Unset, backup=Unset):
|
||||
|
||||
self.address = address
|
||||
self.admin_state_up = admin_state_up
|
||||
@ -150,13 +186,14 @@ class Member(BaseDataModel):
|
||||
self.protocol_port = protocol_port
|
||||
self.subnet_id = subnet_id
|
||||
self.weight = weight
|
||||
self.backup = backup
|
||||
|
||||
|
||||
class HealthMonitor(BaseDataModel):
|
||||
def __init__(self, admin_state_up=None, delay=None, expected_codes=None,
|
||||
healthmonitor_id=None, http_method=None, max_retries=None,
|
||||
max_retries_down=None, name=None, pool_id=None, timeout=None,
|
||||
type=None, url_path=None):
|
||||
def __init__(self, admin_state_up=Unset, delay=Unset, expected_codes=Unset,
|
||||
healthmonitor_id=Unset, http_method=Unset, max_retries=Unset,
|
||||
max_retries_down=Unset, name=Unset, pool_id=Unset,
|
||||
timeout=Unset, type=Unset, url_path=Unset):
|
||||
|
||||
self.admin_state_up = admin_state_up
|
||||
self.delay = delay
|
||||
@ -173,9 +210,10 @@ class HealthMonitor(BaseDataModel):
|
||||
|
||||
|
||||
class L7Policy(BaseDataModel):
|
||||
def __init__(self, action=None, admin_state_up=None, description=None,
|
||||
l7policy_id=None, listener_id=None, name=None, position=None,
|
||||
redirect_pool_id=None, redirect_url=None, rules=None):
|
||||
def __init__(self, action=Unset, admin_state_up=Unset, description=Unset,
|
||||
l7policy_id=Unset, listener_id=Unset, name=Unset,
|
||||
position=Unset, redirect_pool_id=Unset, redirect_url=Unset,
|
||||
rules=Unset):
|
||||
|
||||
self.action = action
|
||||
self.admin_state_up = admin_state_up
|
||||
@ -186,13 +224,13 @@ class L7Policy(BaseDataModel):
|
||||
self.position = position
|
||||
self.redirect_pool_id = redirect_pool_id
|
||||
self.redirect_url = redirect_url
|
||||
self.rules = rules or []
|
||||
self.rules = rules
|
||||
|
||||
|
||||
class L7Rule(BaseDataModel):
|
||||
def __init__(self, admin_state_up=None, compare_type=None, invert=None,
|
||||
key=None, l7policy_id=None, l7rule_id=None, type=None,
|
||||
value=None):
|
||||
def __init__(self, admin_state_up=Unset, compare_type=Unset, invert=Unset,
|
||||
key=Unset, l7policy_id=Unset, l7rule_id=Unset, type=Unset,
|
||||
value=Unset):
|
||||
|
||||
self.admin_state_up = admin_state_up
|
||||
self.compare_type = compare_type
|
||||
@ -205,10 +243,12 @@ class L7Rule(BaseDataModel):
|
||||
|
||||
|
||||
class VIP(BaseDataModel):
|
||||
def __init__(self, vip_address=None, vip_network_id=None, vip_port_id=None,
|
||||
vip_subnet_id=None):
|
||||
def __init__(self, vip_address=Unset, vip_network_id=Unset,
|
||||
vip_port_id=Unset, vip_subnet_id=Unset,
|
||||
vip_qos_policy_id=Unset):
|
||||
|
||||
self.vip_address = vip_address
|
||||
self.vip_network_id = vip_network_id
|
||||
self.vip_port_id = vip_port_id
|
||||
self.vip_subnet_id = vip_subnet_id
|
||||
self.vip_qos_policy_id = vip_qos_policy_id
|
||||
|
50
octavia/api/drivers/driver_factory.py
Normal file
50
octavia/api/drivers/driver_factory.py
Normal file
@ -0,0 +1,50 @@
|
||||
# Copyright 2018 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 oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from stevedore import driver as stevedore_driver
|
||||
from wsme import types as wtypes
|
||||
|
||||
from octavia.common import exceptions
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_driver(provider):
|
||||
# If this came in None it must be a load balancer that existed before
|
||||
# provider support was added. These must be of type 'amphora' and not
|
||||
# whatever the current "default" is set to.
|
||||
if isinstance(provider, wtypes.UnsetType):
|
||||
provider = CONF.api_settings.default_provider_driver
|
||||
elif not provider:
|
||||
provider = 'amphora'
|
||||
|
||||
if provider not in CONF.api_settings.enabled_provider_drivers:
|
||||
LOG.warning("Requested provider driver '%s' was not enabled in the "
|
||||
"configuration file.", provider)
|
||||
raise exceptions.ProviderNotEnabled(prov=provider)
|
||||
|
||||
try:
|
||||
driver = stevedore_driver.DriverManager(
|
||||
namespace='octavia.api.drivers',
|
||||
name=provider,
|
||||
invoke_on_load=True).driver
|
||||
driver.name = provider
|
||||
except Exception as e:
|
||||
LOG.error('Unable to load provider driver %s due to: %s',
|
||||
provider, e)
|
||||
raise exceptions.ProviderNotFound(prov=provider)
|
||||
return driver
|
@ -27,14 +27,15 @@ class NoopManager(object):
|
||||
self.driverconfig = {}
|
||||
|
||||
# Load Balancer
|
||||
def create_vip_port(self, loadbalancer_id, vip_dictionary):
|
||||
def create_vip_port(self, loadbalancer_id, project_id, vip_dictionary):
|
||||
LOG.debug('Provider %s no-op, create_vip_port loadbalancer %s',
|
||||
self.__class__.__name__, loadbalancer_id)
|
||||
|
||||
self.driverconfig[loadbalancer_id] = (loadbalancer_id, vip_dictionary,
|
||||
self.driverconfig[loadbalancer_id] = (loadbalancer_id, project_id,
|
||||
vip_dictionary,
|
||||
'create_vip_port')
|
||||
|
||||
vip_address = vip_dictionary.get('vip_address', '192.0.2.5')
|
||||
vip_address = vip_dictionary.get('vip_address', '198.0.2.5')
|
||||
vip_network_id = vip_dictionary.get('vip_network_id',
|
||||
uuidutils.generate_uuid())
|
||||
vip_port_id = vip_dictionary.get('vip_port_id',
|
||||
@ -222,8 +223,9 @@ class NoopProviderDriver(driver_base.ProviderDriver):
|
||||
self.driver = NoopManager()
|
||||
|
||||
# Load Balancer
|
||||
def create_vip_port(self, loadbalancer_id, vip_dictionary):
|
||||
return self.driver.create_vip_port(loadbalancer_id, vip_dictionary)
|
||||
def create_vip_port(self, loadbalancer_id, project_id, vip_dictionary):
|
||||
return self.driver.create_vip_port(loadbalancer_id, project_id,
|
||||
vip_dictionary)
|
||||
|
||||
def loadbalancer_create(self, loadbalancer):
|
||||
self.driver.loadbalancer_create(loadbalancer)
|
||||
|
@ -19,8 +19,11 @@ from octavia.api.drivers import exceptions
|
||||
|
||||
|
||||
class ProviderDriver(object):
|
||||
# name is for internal Octavia use and should not be used by drivers
|
||||
name = None
|
||||
|
||||
# Load Balancer
|
||||
def create_vip_port(self, loadbalancer_id, vip_dictionary):
|
||||
def create_vip_port(self, loadbalancer_id, project_id, vip_dictionary):
|
||||
"""Creates a port for a load balancer VIP.
|
||||
|
||||
If the driver supports creating VIP ports, the driver will create a
|
||||
@ -30,6 +33,8 @@ class ProviderDriver(object):
|
||||
|
||||
:param loadbalancer_id: ID of loadbalancer.
|
||||
:type loadbalancer_id: string
|
||||
:param project_id: The project ID to create the VIP under.
|
||||
:type project_id: string
|
||||
:param: vip_dictionary: The VIP dictionary.
|
||||
:type vip_dictionary: dict
|
||||
:returns: VIP dictionary with vip_port_id.
|
||||
@ -37,7 +42,11 @@ class ProviderDriver(object):
|
||||
:raises NotImplementedError: The driver does not support creating
|
||||
VIP ports.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support creating VIP '
|
||||
'ports.',
|
||||
operator_fault_string='This provider does not support creating '
|
||||
'VIP ports. Octavia will create it.')
|
||||
|
||||
def loadbalancer_create(self, loadbalancer):
|
||||
"""Creates a new load balancer.
|
||||
@ -50,7 +59,11 @@ class ProviderDriver(object):
|
||||
:raises UnsupportedOptionError: The driver does not
|
||||
support one of the configuration options.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support creating '
|
||||
'load balancers.',
|
||||
operator_fault_string='This provider does not support creating '
|
||||
'load balancers. What?')
|
||||
|
||||
def loadbalancer_delete(self, loadbalancer_id, cascade=False):
|
||||
"""Deletes a load balancer.
|
||||
@ -64,7 +77,11 @@ class ProviderDriver(object):
|
||||
:raises DriverError: An unexpected error occurred in the driver.
|
||||
:raises NotImplementedError: if driver does not support request.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support deleting '
|
||||
'load balancers.',
|
||||
operator_fault_string='This provider does not support deleting '
|
||||
'load balancers.')
|
||||
|
||||
def loadbalancer_failover(self, loadbalancer_id):
|
||||
"""Performs a fail over of a load balancer.
|
||||
@ -75,7 +92,11 @@ class ProviderDriver(object):
|
||||
:raises DriverError: An unexpected error occurred in the driver.
|
||||
:raises: NotImplementedError if driver does not support request.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support failing over '
|
||||
'load balancers.',
|
||||
operator_fault_string='This provider does not support failing '
|
||||
'over load balancers.')
|
||||
|
||||
def loadbalancer_update(self, loadbalancer):
|
||||
"""Updates a load balancer.
|
||||
@ -88,7 +109,11 @@ class ProviderDriver(object):
|
||||
:raises UnsupportedOptionError: The driver does not
|
||||
support one of the configuration options.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support updating '
|
||||
'load balancers.',
|
||||
operator_fault_string='This provider does not support updating '
|
||||
'load balancers.')
|
||||
|
||||
# Listener
|
||||
def listener_create(self, listener):
|
||||
@ -102,7 +127,11 @@ class ProviderDriver(object):
|
||||
:raises UnsupportedOptionError: if driver does not
|
||||
support one of the configuration options.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support creating '
|
||||
'listeners.',
|
||||
operator_fault_string='This provider does not support creating '
|
||||
'listeners.')
|
||||
|
||||
def listener_delete(self, listener_id):
|
||||
"""Deletes a listener.
|
||||
@ -113,7 +142,11 @@ class ProviderDriver(object):
|
||||
:raises DriverError: An unexpected error occurred in the driver.
|
||||
:raises NotImplementedError: if driver does not support request.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support deleting '
|
||||
'listeners.',
|
||||
operator_fault_string='This provider does not support deleting '
|
||||
'listeners.')
|
||||
|
||||
def listener_update(self, listener):
|
||||
"""Updates a listener.
|
||||
@ -126,7 +159,11 @@ class ProviderDriver(object):
|
||||
:raises UnsupportedOptionError: if driver does not
|
||||
support one of the configuration options.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support updating '
|
||||
'listeners.',
|
||||
operator_fault_string='This provider does not support updating '
|
||||
'listeners.')
|
||||
|
||||
# Pool
|
||||
def pool_create(self, pool):
|
||||
@ -140,7 +177,11 @@ class ProviderDriver(object):
|
||||
:raises UnsupportedOptionError: if driver does not
|
||||
support one of the configuration options.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support creating '
|
||||
'pools.',
|
||||
operator_fault_string='This provider does not support creating '
|
||||
'pools.')
|
||||
|
||||
def pool_delete(self, pool_id):
|
||||
"""Deletes a pool and its members.
|
||||
@ -151,7 +192,11 @@ class ProviderDriver(object):
|
||||
:raises DriverError: An unexpected error occurred in the driver.
|
||||
:raises NotImplementedError: if driver does not support request.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support deleting '
|
||||
'pools.',
|
||||
operator_fault_string='This provider does not support deleting '
|
||||
'pools.')
|
||||
|
||||
def pool_update(self, pool):
|
||||
"""Updates a pool.
|
||||
@ -164,7 +209,11 @@ class ProviderDriver(object):
|
||||
:raises UnsupportedOptionError: if driver does not
|
||||
support one of the configuration options.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support updating '
|
||||
'pools.',
|
||||
operator_fault_string='This provider does not support updating '
|
||||
'pools.')
|
||||
|
||||
# Member
|
||||
def member_create(self, member):
|
||||
@ -178,7 +227,11 @@ class ProviderDriver(object):
|
||||
:raises UnsupportedOptionError: if driver does not
|
||||
support one of the configuration options.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support creating '
|
||||
'members.',
|
||||
operator_fault_string='This provider does not support creating '
|
||||
'members.')
|
||||
|
||||
def member_delete(self, member_id):
|
||||
"""Deletes a pool member.
|
||||
@ -189,7 +242,11 @@ class ProviderDriver(object):
|
||||
:raises DriverError: An unexpected error occurred in the driver.
|
||||
:raises NotImplementedError: if driver does not support request.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support deleting '
|
||||
'members.',
|
||||
operator_fault_string='This provider does not support deleting '
|
||||
'members.')
|
||||
|
||||
def member_update(self, member):
|
||||
"""Updates a pool member.
|
||||
@ -202,7 +259,11 @@ class ProviderDriver(object):
|
||||
:raises UnsupportedOptionError: if driver does not
|
||||
support one of the configuration options.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support updating '
|
||||
'members.',
|
||||
operator_fault_string='This provider does not support updating '
|
||||
'members.')
|
||||
|
||||
def member_batch_update(self, members):
|
||||
"""Creates, updates, or deletes a set of pool members.
|
||||
@ -215,7 +276,11 @@ class ProviderDriver(object):
|
||||
:raises UnsupportedOptionError: if driver does not
|
||||
support one of the configuration options.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support batch '
|
||||
'updating members.',
|
||||
operator_fault_string='This provider does not support batch '
|
||||
'updating members.')
|
||||
|
||||
# Health Monitor
|
||||
def health_monitor_create(self, healthmonitor):
|
||||
@ -229,7 +294,11 @@ class ProviderDriver(object):
|
||||
:raises UnsupportedOptionError: if driver does not
|
||||
support one of the configuration options.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support creating '
|
||||
'health monitors.',
|
||||
operator_fault_string='This provider does not support creating '
|
||||
'health monitors.')
|
||||
|
||||
def health_monitor_delete(self, healthmonitor_id):
|
||||
"""Deletes a healthmonitor_id.
|
||||
@ -240,7 +309,11 @@ class ProviderDriver(object):
|
||||
:raises DriverError: An unexpected error occurred in the driver.
|
||||
:raises NotImplementedError: if driver does not support request.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support deleting '
|
||||
'health monitors.',
|
||||
operator_fault_string='This provider does not support deleting '
|
||||
'health monitors.')
|
||||
|
||||
def health_monitor_update(self, healthmonitor):
|
||||
"""Updates a health monitor.
|
||||
@ -253,7 +326,11 @@ class ProviderDriver(object):
|
||||
:raises UnsupportedOptionError: if driver does not
|
||||
support one of the configuration options.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support updating '
|
||||
'health monitors.',
|
||||
operator_fault_string='This provider does not support updating '
|
||||
'health monitors.')
|
||||
|
||||
# L7 Policy
|
||||
def l7policy_create(self, l7policy):
|
||||
@ -267,7 +344,11 @@ class ProviderDriver(object):
|
||||
:raises UnsupportedOptionError: if driver does not
|
||||
support one of the configuration options.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support creating '
|
||||
'l7policies.',
|
||||
operator_fault_string='This provider does not support creating '
|
||||
'l7policies.')
|
||||
|
||||
def l7policy_delete(self, l7policy_id):
|
||||
"""Deletes an L7 policy.
|
||||
@ -278,7 +359,11 @@ class ProviderDriver(object):
|
||||
:raises DriverError: An unexpected error occurred in the driver.
|
||||
:raises NotImplementedError: if driver does not support request.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support deleting '
|
||||
'l7policies.',
|
||||
operator_fault_string='This provider does not support deleting '
|
||||
'l7policies.')
|
||||
|
||||
def l7policy_update(self, l7policy):
|
||||
"""Updates an L7 policy.
|
||||
@ -291,7 +376,11 @@ class ProviderDriver(object):
|
||||
:raises UnsupportedOptionError: if driver does not
|
||||
support one of the configuration options.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support updating '
|
||||
'l7policies.',
|
||||
operator_fault_string='This provider does not support updating '
|
||||
'l7policies.')
|
||||
|
||||
# L7 Rule
|
||||
def l7rule_create(self, l7rule):
|
||||
@ -305,7 +394,11 @@ class ProviderDriver(object):
|
||||
:raises UnsupportedOptionError: if driver does not
|
||||
support one of the configuration options.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support creating '
|
||||
'l7rules.',
|
||||
operator_fault_string='This provider does not support creating '
|
||||
'l7rules.')
|
||||
|
||||
def l7rule_delete(self, l7rule_id):
|
||||
"""Deletes an L7 rule.
|
||||
@ -316,7 +409,11 @@ class ProviderDriver(object):
|
||||
:raises DriverError: An unexpected error occurred in the driver.
|
||||
:raises NotImplementedError: if driver does not support request.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support deleting '
|
||||
'l7rules.',
|
||||
operator_fault_string='This provider does not support deleting '
|
||||
'l7rules.')
|
||||
|
||||
def l7rule_update(self, l7rule):
|
||||
"""Updates an L7 rule.
|
||||
@ -329,7 +426,11 @@ class ProviderDriver(object):
|
||||
:raises UnsupportedOptionError: if driver does not
|
||||
support one of the configuration options.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support updating '
|
||||
'l7rules.',
|
||||
operator_fault_string='This provider does not support updating '
|
||||
'l7rules.')
|
||||
|
||||
# Flavor
|
||||
def get_supported_flavor_metadata(self):
|
||||
@ -342,7 +443,11 @@ class ProviderDriver(object):
|
||||
:raises DriverError: An unexpected error occurred in the driver.
|
||||
:raises NotImplementedError: The driver does not support flavors.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support getting the '
|
||||
'supported flavor metadata.',
|
||||
operator_fault_string='This provider does not support getting '
|
||||
'the supported flavor metadata.')
|
||||
|
||||
def validate_flavor(self, flavor_metadata):
|
||||
"""Validates if driver can support the flavor.
|
||||
@ -355,4 +460,8 @@ class ProviderDriver(object):
|
||||
:raises UnsupportedOptionError: if driver does not
|
||||
support one of the configuration options.
|
||||
"""
|
||||
raise exceptions.NotImplementedError()
|
||||
raise exceptions.NotImplementedError(
|
||||
user_fault_string='This provider does not support validating '
|
||||
'flavors.',
|
||||
operator_fault_string='This provider does not support validating '
|
||||
'the supported flavor metadata.')
|
||||
|
353
octavia/api/drivers/utils.py
Normal file
353
octavia/api/drivers/utils.py
Normal file
@ -0,0 +1,353 @@
|
||||
# Copyright 2018 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 copy
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from stevedore import driver as stevedore_driver
|
||||
|
||||
from octavia.api.drivers import data_models as driver_dm
|
||||
from octavia.api.drivers import exceptions as driver_exceptions
|
||||
from octavia.common import data_models
|
||||
from octavia.common import exceptions
|
||||
from octavia.common.tls_utils import cert_parser
|
||||
from octavia.i18n import _
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
def call_provider(provider, driver_method, *args, **kwargs):
|
||||
"""Wrap calls to the provider driver to handle driver errors.
|
||||
|
||||
This allows Octavia to return user friendly errors when a provider driver
|
||||
has an issue.
|
||||
|
||||
:param driver_method: Method in the driver to call.
|
||||
:raises ProviderDriverError: Catch all driver error.
|
||||
:raises ProviderNotImplementedError: The driver doesn't support this
|
||||
action.
|
||||
:raises ProviderUnsupportedOptionError: The driver doesn't support a
|
||||
provided option.
|
||||
"""
|
||||
|
||||
try:
|
||||
return driver_method(*args, **kwargs)
|
||||
except driver_exceptions.DriverError as e:
|
||||
LOG.exception("Provider '%s' raised a driver error: %s",
|
||||
provider, e.operator_fault_string)
|
||||
raise exceptions.ProviderDriverError(prov=provider,
|
||||
user_msg=e.user_fault_string)
|
||||
except driver_exceptions.NotImplementedError as e:
|
||||
LOG.info("Provider '%s' raised a not implemented error: %s",
|
||||
provider, e.operator_fault_string)
|
||||
raise exceptions.ProviderNotImplementedError(
|
||||
prov=provider, user_msg=e.user_fault_string)
|
||||
except driver_exceptions.UnsupportedOptionError as e:
|
||||
LOG.info("Provider '%s' raised an unsupported option error: "
|
||||
"%s", provider, e.operator_fault_string)
|
||||
raise exceptions.ProviderUnsupportedOptionError(
|
||||
prov=provider, user_msg=e.user_fault_string)
|
||||
except Exception as e:
|
||||
LOG.exception("Provider '%s' raised an unkown error: %s",
|
||||
provider, e)
|
||||
raise exceptions.ProviderDriverError(prov=provider, user_msg=e)
|
||||
|
||||
|
||||
def _base_to_provider_dict(current_dict, include_project_id=False):
|
||||
new_dict = copy.deepcopy(current_dict)
|
||||
if 'provisioning_status' in new_dict:
|
||||
del new_dict['provisioning_status']
|
||||
if 'operating_status' in new_dict:
|
||||
del new_dict['operating_status']
|
||||
if 'provider' in new_dict:
|
||||
del new_dict['provider']
|
||||
if 'created_at' in new_dict:
|
||||
del new_dict['created_at']
|
||||
if 'updated_at' in new_dict:
|
||||
del new_dict['updated_at']
|
||||
if 'enabled' in new_dict:
|
||||
new_dict['admin_state_up'] = new_dict.pop('enabled')
|
||||
if 'project_id' in new_dict and not include_project_id:
|
||||
del new_dict['project_id']
|
||||
return new_dict
|
||||
|
||||
|
||||
# Note: The provider dict returned from this method will have provider
|
||||
# data model objects in it.
|
||||
def lb_dict_to_provider_dict(lb_dict, vip=None,
|
||||
db_pools=None, db_listeners=None):
|
||||
new_lb_dict = _base_to_provider_dict(lb_dict, include_project_id=True)
|
||||
new_lb_dict['loadbalancer_id'] = new_lb_dict.pop('id')
|
||||
if vip:
|
||||
new_lb_dict['vip_address'] = vip.ip_address
|
||||
new_lb_dict['vip_network_id'] = vip.network_id
|
||||
new_lb_dict['vip_port_id'] = vip.port_id
|
||||
new_lb_dict['vip_subnet_id'] = vip.subnet_id
|
||||
new_lb_dict['vip_qos_policy_id'] = vip.qos_policy_id
|
||||
|
||||
if db_pools:
|
||||
new_lb_dict['pools'] = db_pools_to_provider_pools(db_pools)
|
||||
if db_listeners:
|
||||
new_lb_dict['listeners'] = db_listeners_to_provider_listeners(
|
||||
db_listeners)
|
||||
return new_lb_dict
|
||||
|
||||
|
||||
def db_listeners_to_provider_listeners(db_listeners):
|
||||
provider_listeners = []
|
||||
for listener in db_listeners:
|
||||
new_listener_dict = listener_dict_to_provider_dict(
|
||||
listener.to_dict(recurse=True))
|
||||
if ('default_pool' in new_listener_dict and
|
||||
new_listener_dict['default_pool']):
|
||||
provider_pool = db_pool_to_provider_pool(listener.default_pool)
|
||||
new_listener_dict['default_pool_id'] = provider_pool.pool_id
|
||||
new_listener_dict['default_pool'] = provider_pool
|
||||
if 'l7policies' in new_listener_dict:
|
||||
new_listener_dict['l7policies'] = (
|
||||
db_l7policies_to_provider_l7policies(listener.l7policies))
|
||||
provider_listeners.append(
|
||||
driver_dm.Listener.from_dict(new_listener_dict))
|
||||
return provider_listeners
|
||||
|
||||
|
||||
def listener_dict_to_provider_dict(listener_dict):
|
||||
new_listener_dict = _base_to_provider_dict(listener_dict)
|
||||
new_listener_dict['listener_id'] = new_listener_dict.pop('id')
|
||||
if 'load_balancer_id' in new_listener_dict:
|
||||
new_listener_dict['loadbalancer_id'] = new_listener_dict.pop(
|
||||
'load_balancer_id')
|
||||
|
||||
# Pull the certs out of the certificate manager to pass to the provider
|
||||
if 'tls_certificate_id' in new_listener_dict:
|
||||
del new_listener_dict['tls_certificate_id']
|
||||
if 'sni_containers' in new_listener_dict:
|
||||
del new_listener_dict['sni_containers']
|
||||
listener_obj = data_models.Listener(**listener_dict)
|
||||
if listener_obj.tls_certificate_id or listener_obj.sni_containers:
|
||||
SNI_objs = []
|
||||
for sni in listener_obj.sni_containers:
|
||||
if isinstance(sni, data_models.SNI):
|
||||
SNI_objs.append(sni)
|
||||
elif isinstance(sni, dict):
|
||||
sni_obj = data_models.SNI(**sni)
|
||||
SNI_objs.append(sni_obj)
|
||||
else:
|
||||
raise Exception(_('Invalid SNI container on listener'))
|
||||
listener_obj.sni_containers = SNI_objs
|
||||
cert_manager = stevedore_driver.DriverManager(
|
||||
namespace='octavia.cert_manager',
|
||||
name=CONF.certificates.cert_manager,
|
||||
invoke_on_load=True,
|
||||
).driver
|
||||
cert_dict = cert_parser.load_certificates_data(cert_manager,
|
||||
listener_obj)
|
||||
new_listener_dict['default_tls_container'] = cert_dict['tls_cert']
|
||||
new_listener_dict['sni_containers'] = cert_dict['sni_certs']
|
||||
|
||||
# Remove the DB back references
|
||||
if 'load_balancer' in new_listener_dict:
|
||||
del new_listener_dict['load_balancer']
|
||||
if 'peer_port' in new_listener_dict:
|
||||
del new_listener_dict['peer_port']
|
||||
if 'pools' in new_listener_dict:
|
||||
del new_listener_dict['pools']
|
||||
if 'stats' in new_listener_dict:
|
||||
del new_listener_dict['stats']
|
||||
|
||||
if ('default_pool' in new_listener_dict and
|
||||
new_listener_dict['default_pool']):
|
||||
pool = new_listener_dict.pop('default_pool')
|
||||
new_listener_dict['default_pool'] = pool_dict_to_provider_dict(pool)
|
||||
provider_l7policies = []
|
||||
l7policies = new_listener_dict.pop('l7policies')
|
||||
for l7policy in l7policies:
|
||||
provider_l7policy = l7policy_dict_to_provider_dict(l7policy)
|
||||
provider_l7policies.append(provider_l7policy)
|
||||
new_listener_dict['l7policies'] = provider_l7policies
|
||||
return new_listener_dict
|
||||
|
||||
|
||||
def db_pools_to_provider_pools(db_pools):
|
||||
provider_pools = []
|
||||
for pool in db_pools:
|
||||
provider_pools.append(db_pool_to_provider_pool(pool))
|
||||
return provider_pools
|
||||
|
||||
|
||||
def db_pool_to_provider_pool(db_pool):
|
||||
new_pool_dict = pool_dict_to_provider_dict(db_pool.to_dict(recurse=True))
|
||||
# Replace the sub-dicts with objects
|
||||
if 'health_monitor' in new_pool_dict:
|
||||
del new_pool_dict['health_monitor']
|
||||
if db_pool.health_monitor:
|
||||
provider_healthmonitor = db_HM_to_provider_HM(db_pool.health_monitor)
|
||||
new_pool_dict['healthmonitor'] = provider_healthmonitor
|
||||
# Don't leave a 'members' None here, we want it to pass through to Unset
|
||||
if 'members' in new_pool_dict:
|
||||
del new_pool_dict['members']
|
||||
if db_pool.members:
|
||||
provider_members = db_members_to_provider_members(db_pool.members)
|
||||
new_pool_dict['members'] = provider_members
|
||||
return driver_dm.Pool.from_dict(new_pool_dict)
|
||||
|
||||
|
||||
def pool_dict_to_provider_dict(pool_dict):
|
||||
new_pool_dict = _base_to_provider_dict(pool_dict)
|
||||
new_pool_dict['pool_id'] = new_pool_dict.pop('id')
|
||||
# Remove the DB back references
|
||||
if ('session_persistence' in new_pool_dict and
|
||||
new_pool_dict['session_persistence']):
|
||||
if 'pool_id' in new_pool_dict['session_persistence']:
|
||||
del new_pool_dict['session_persistence']['pool_id']
|
||||
if 'pool' in new_pool_dict['session_persistence']:
|
||||
del new_pool_dict['session_persistence']['pool']
|
||||
if 'l7policies' in new_pool_dict:
|
||||
del new_pool_dict['l7policies']
|
||||
if 'listeners' in new_pool_dict:
|
||||
del new_pool_dict['listeners']
|
||||
if 'load_balancer' in new_pool_dict:
|
||||
del new_pool_dict['load_balancer']
|
||||
if 'load_balancer_id' in new_pool_dict:
|
||||
new_pool_dict['loadbalancer_id'] = new_pool_dict.pop(
|
||||
'load_balancer_id')
|
||||
if 'health_monitor' in new_pool_dict and new_pool_dict['health_monitor']:
|
||||
hm = new_pool_dict.pop('health_monitor')
|
||||
new_pool_dict['healthmonitor'] = hm_dict_to_provider_dict(hm)
|
||||
if 'members' in new_pool_dict and new_pool_dict['members']:
|
||||
members = new_pool_dict.pop('members')
|
||||
provider_members = []
|
||||
for member in members:
|
||||
provider_member = member_dict_to_provider_dict(member)
|
||||
provider_members.append(provider_member)
|
||||
new_pool_dict['members'] = provider_members
|
||||
return new_pool_dict
|
||||
|
||||
|
||||
def db_members_to_provider_members(db_members):
|
||||
provider_members = []
|
||||
for member in db_members:
|
||||
new_member_dict = member_dict_to_provider_dict(member.to_dict())
|
||||
provider_members.append(driver_dm.Member.from_dict(new_member_dict))
|
||||
return provider_members
|
||||
|
||||
|
||||
def member_dict_to_provider_dict(member_dict):
|
||||
new_member_dict = _base_to_provider_dict(member_dict)
|
||||
new_member_dict['member_id'] = new_member_dict.pop('id')
|
||||
if 'ip_address' in new_member_dict:
|
||||
new_member_dict['address'] = new_member_dict.pop('ip_address')
|
||||
# Remove the DB back references
|
||||
if 'pool' in new_member_dict:
|
||||
del new_member_dict['pool']
|
||||
return new_member_dict
|
||||
|
||||
|
||||
def db_HM_to_provider_HM(db_hm):
|
||||
new_HM_dict = hm_dict_to_provider_dict(db_hm.to_dict())
|
||||
return driver_dm.HealthMonitor.from_dict(new_HM_dict)
|
||||
|
||||
|
||||
def hm_dict_to_provider_dict(hm_dict):
|
||||
new_hm_dict = _base_to_provider_dict(hm_dict)
|
||||
new_hm_dict['healthmonitor_id'] = new_hm_dict.pop('id')
|
||||
if 'fall_threshold' in new_hm_dict:
|
||||
new_hm_dict['max_retries_down'] = new_hm_dict.pop('fall_threshold')
|
||||
if 'rise_threshold' in new_hm_dict:
|
||||
new_hm_dict['max_retries'] = new_hm_dict.pop('rise_threshold')
|
||||
# Remove the DB back references
|
||||
if 'pool' in new_hm_dict:
|
||||
del new_hm_dict['pool']
|
||||
return new_hm_dict
|
||||
|
||||
|
||||
def db_l7policies_to_provider_l7policies(db_l7policies):
|
||||
provider_l7policies = []
|
||||
for l7policy in db_l7policies:
|
||||
new_l7policy_dict = l7policy_dict_to_provider_dict(
|
||||
l7policy.to_dict(recurse=True))
|
||||
if 'l7rules' in new_l7policy_dict:
|
||||
del new_l7policy_dict['l7rules']
|
||||
new_l7rules = db_l7rules_to_provider_l7rules(l7policy.l7rules)
|
||||
new_l7policy_dict['rules'] = new_l7rules
|
||||
provider_l7policies.append(
|
||||
driver_dm.L7Policy.from_dict(new_l7policy_dict))
|
||||
return provider_l7policies
|
||||
|
||||
|
||||
def l7policy_dict_to_provider_dict(l7policy_dict):
|
||||
new_l7policy_dict = _base_to_provider_dict(l7policy_dict)
|
||||
new_l7policy_dict['l7policy_id'] = new_l7policy_dict.pop('id')
|
||||
# Remove the DB back references
|
||||
if 'listener' in new_l7policy_dict:
|
||||
del new_l7policy_dict['listener']
|
||||
if 'redirect_pool' in new_l7policy_dict:
|
||||
del new_l7policy_dict['redirect_pool']
|
||||
if 'l7rules' in new_l7policy_dict and new_l7policy_dict['l7rules']:
|
||||
rules = new_l7policy_dict.pop('l7rules')
|
||||
provider_rules = []
|
||||
for rule in rules:
|
||||
provider_rule = l7rule_dict_to_provider_dict(rule)
|
||||
provider_rules.append(provider_rule)
|
||||
new_l7policy_dict['rules'] = provider_rules
|
||||
return new_l7policy_dict
|
||||
|
||||
|
||||
def db_l7rules_to_provider_l7rules(db_l7rules):
|
||||
provider_l7rules = []
|
||||
for l7rule in db_l7rules:
|
||||
new_l7rule_dict = l7rule_dict_to_provider_dict(l7rule.to_dict())
|
||||
provider_l7rules.append(driver_dm.L7Rule.from_dict(new_l7rule_dict))
|
||||
return provider_l7rules
|
||||
|
||||
|
||||
def l7rule_dict_to_provider_dict(l7rule_dict):
|
||||
new_l7rule_dict = _base_to_provider_dict(l7rule_dict)
|
||||
new_l7rule_dict['l7rule_id'] = new_l7rule_dict.pop('id')
|
||||
# Remove the DB back references
|
||||
if 'l7policy' in new_l7rule_dict:
|
||||
del new_l7rule_dict['l7policy']
|
||||
return new_l7rule_dict
|
||||
|
||||
|
||||
def vip_dict_to_provider_dict(vip_dict):
|
||||
new_vip_dict = {}
|
||||
if 'ip_address' in vip_dict:
|
||||
new_vip_dict['vip_address'] = vip_dict['ip_address']
|
||||
if 'network_id' in vip_dict:
|
||||
new_vip_dict['vip_network_id'] = vip_dict['network_id']
|
||||
if 'port_id' in vip_dict:
|
||||
new_vip_dict['vip_port_id'] = vip_dict['port_id']
|
||||
if 'subnet_id' in vip_dict:
|
||||
new_vip_dict['vip_subnet_id'] = vip_dict['subnet_id']
|
||||
if 'qos_policy_id' in vip_dict:
|
||||
new_vip_dict['vip_qos_policy_id'] = vip_dict['qos_policy_id']
|
||||
return new_vip_dict
|
||||
|
||||
|
||||
def provider_vip_dict_to_vip_obj(vip_dictionary):
|
||||
vip_obj = data_models.Vip()
|
||||
if 'vip_address' in vip_dictionary:
|
||||
vip_obj.ip_address = vip_dictionary['vip_address']
|
||||
if 'vip_network_id' in vip_dictionary:
|
||||
vip_obj.network_id = vip_dictionary['vip_network_id']
|
||||
if 'vip_port_id' in vip_dictionary:
|
||||
vip_obj.port_id = vip_dictionary['vip_port_id']
|
||||
if 'vip_subnet_id' in vip_dictionary:
|
||||
vip_obj.subnet_id = vip_dictionary['vip_subnet_id']
|
||||
if 'vip_qos_policy_id' in vip_dictionary:
|
||||
vip_obj.qos_policy_id = vip_dictionary['vip_qos_policy_id']
|
||||
return vip_obj
|
@ -197,6 +197,7 @@ class L7PolicyController(base.BaseController):
|
||||
l7rule.L7RuleController(db_policy.id)._graph_create(
|
||||
lock_session, r))
|
||||
|
||||
db_policy.l7rules = new_rules
|
||||
return db_policy
|
||||
|
||||
@wsme_pecan.wsexpose(l7policy_types.L7PolicyRootResponse,
|
||||
|
@ -272,7 +272,8 @@ class ListenersController(base.BaseController):
|
||||
l7p['redirect_pool_id'] = pool_id
|
||||
new_l7ps.append(l7policy.L7PolicyController()._graph_create(
|
||||
lock_session, l7p))
|
||||
return db_listener, new_l7ps
|
||||
db_listener.l7policies = new_l7ps
|
||||
return db_listener
|
||||
|
||||
@wsme_pecan.wsexpose(listener_types.ListenerRootResponse, wtypes.text,
|
||||
body=listener_types.ListenerRootPUT, status_code=200)
|
||||
|
@ -22,6 +22,9 @@ import pecan
|
||||
from wsme import types as wtypes
|
||||
from wsmeext import pecan as wsme_pecan
|
||||
|
||||
from octavia.api.drivers import data_models as driver_dm
|
||||
from octavia.api.drivers import driver_factory
|
||||
from octavia.api.drivers import utils as driver_utils
|
||||
from octavia.api.v2.controllers import base
|
||||
from octavia.api.v2.controllers import listener
|
||||
from octavia.api.v2.controllers import pool
|
||||
@ -249,6 +252,9 @@ class LoadBalancersController(base.BaseController):
|
||||
|
||||
self._validate_vip_request_object(load_balancer)
|
||||
|
||||
# Load the driver early as it also provides validation
|
||||
driver = driver_factory.get_driver(load_balancer.provider)
|
||||
|
||||
lock_session = db_api.get_session(autocommit=False)
|
||||
try:
|
||||
if self.repositories.check_quota_met(
|
||||
@ -265,35 +271,58 @@ class LoadBalancersController(base.BaseController):
|
||||
))
|
||||
vip_dict = lb_dict.pop('vip', {})
|
||||
|
||||
# Make sure we store the right provider in the DB
|
||||
lb_dict['provider'] = driver.name
|
||||
|
||||
# NoneType can be weird here, have to force type a second time
|
||||
listeners = lb_dict.pop('listeners', []) or []
|
||||
pools = lb_dict.pop('pools', []) or []
|
||||
|
||||
# TODO(johnsom) Remove provider and flavor from the lb_dict
|
||||
# as they have not been implemented beyond the API yet.
|
||||
# Remove these lines as they are implemented.
|
||||
if 'provider' in lb_dict:
|
||||
del lb_dict['provider']
|
||||
if 'flavor_id' in lb_dict:
|
||||
del lb_dict['flavor_id']
|
||||
# TODO(johnsom) Remove flavor from the lb_dict
|
||||
# as it has not been implemented beyond the API yet.
|
||||
# Remove this line when it is implemented.
|
||||
lb_dict.pop('flavor', None)
|
||||
|
||||
db_lb = self.repositories.create_load_balancer_and_vip(
|
||||
lock_session, lb_dict, vip_dict)
|
||||
|
||||
# create vip port if not exist
|
||||
vip = self._create_vip_port_if_not_exist(db_lb)
|
||||
# See if the provider driver wants to create the VIP port
|
||||
try:
|
||||
provider_vip_dict = driver_utils.vip_dict_to_provider_dict(
|
||||
vip_dict)
|
||||
vip_dict = driver_utils.call_provider(
|
||||
driver.name, driver.create_vip_port, db_lb.id,
|
||||
db_lb.project_id, provider_vip_dict)
|
||||
vip = driver_utils.provider_vip_dict_to_vip_obj(vip_dict)
|
||||
except exceptions.ProviderNotImplementedError:
|
||||
# create vip port if not exist, driver didn't want to create
|
||||
# the VIP port
|
||||
vip = self._create_vip_port_if_not_exist(db_lb)
|
||||
LOG.info('Created VIP port %s for provider %s.',
|
||||
vip.port_id, driver.name)
|
||||
|
||||
self.repositories.vip.update(
|
||||
lock_session, db_lb.id,
|
||||
ip_address=vip.ip_address,
|
||||
port_id=vip.port_id,
|
||||
network_id=vip.network_id,
|
||||
subnet_id=vip.subnet_id
|
||||
)
|
||||
subnet_id=vip.subnet_id)
|
||||
|
||||
if listeners or pools:
|
||||
db_pools, db_lists = self._graph_create(
|
||||
context.session, lock_session, db_lb, listeners, pools)
|
||||
|
||||
# Prepare the data for the driver data model
|
||||
driver_lb_dict = driver_utils.lb_dict_to_provider_dict(
|
||||
lb_dict, vip |