Move OVN Octavia Provider driver code to this repository
This code moves OVN Octavia provider driver from networking-ovn (branch master) repository to this repository. For first step lets move code and unit tests. Previous paths in networking-ovn tree: ./networking_ovn/octavia/ovn_driver.py -> ./ovn_octavia_provider/driver.py ./networking_ovn/tests/unit/octavia/test_ovn_driver -> ./ovn_octavia_provider/tests/unit/test_driver.py There are a few files taken directly from neutron repository that could be removed when neutron-lib including those will be released: ./ovn_octavia_provider/ovsdb/impl_idl_ovn.py ./ovn_octavia_provider/ovsdb/ovsdb_monitor.py Co-Authored-By: Brian Haley <bhaley@redhat.com> Co-Authored-By: Carlos Goncalves <cgoncalves@redhat.com> Co-Authored-By: Frode Nordahl <frode.nordahl@canonical.com> Co-Authored-By: Jakub Libosvar <libosvar@redhat.com> Co-Authored-By: Maciej Józefczyk <mjozefcz@redhat.com> Co-Authored-By: Numan Siddique <nusiddiq@redhat.com> Co-Authored-By: Reedip Banerjee <rbanerje@redhat.com> Co-Authored-By: Terry Wilson <twilson@redhat.com> Co-Authored-By: Yunxiang Tao <taoyunxiang@cmss.chinamobile.com> Co-Authored-By: zhufl <zhu.fanglei@zte.com.cn> Change-Id: I9b562c4ed5f74df2c3d600356758f4648ac7770b Related-Blueprint: neutron-ovn-merge
This commit is contained in:
parent
0c84fc2048
commit
000049c15d
94
ovn_octavia_provider/common/config.py
Normal file
94
ovn_octavia_provider/common/config.py
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
# 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 ovn_octavia_provider.i18n import _
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
ovn_opts = [
|
||||||
|
cfg.StrOpt('ovn_nb_connection',
|
||||||
|
default='tcp:127.0.0.1:6641',
|
||||||
|
help=_('The connection string for the OVN_Northbound OVSDB.\n'
|
||||||
|
'Use tcp:IP:PORT for TCP connection.\n'
|
||||||
|
'Use ssl:IP:PORT for SSL connection. The '
|
||||||
|
'ovn_nb_private_key, ovn_nb_certificate and '
|
||||||
|
'ovn_nb_ca_cert are mandatory.\n'
|
||||||
|
'Use unix:FILE for unix domain socket connection.')),
|
||||||
|
cfg.StrOpt('ovn_nb_private_key',
|
||||||
|
default='',
|
||||||
|
help=_('The PEM file with private key for SSL connection to '
|
||||||
|
'OVN-NB-DB')),
|
||||||
|
cfg.StrOpt('ovn_nb_certificate',
|
||||||
|
default='',
|
||||||
|
help=_('The PEM file with certificate that certifies the '
|
||||||
|
'private key specified in ovn_nb_private_key')),
|
||||||
|
cfg.StrOpt('ovn_nb_ca_cert',
|
||||||
|
default='',
|
||||||
|
help=_('The PEM file with CA certificate that OVN should use to'
|
||||||
|
' verify certificates presented to it by SSL peers')),
|
||||||
|
cfg.IntOpt('ovsdb_connection_timeout',
|
||||||
|
default=180,
|
||||||
|
help=_('Timeout in seconds for the OVSDB '
|
||||||
|
'connection transaction')),
|
||||||
|
cfg.IntOpt('ovsdb_retry_max_interval',
|
||||||
|
default=180,
|
||||||
|
help=_('Max interval in seconds between '
|
||||||
|
'each retry to get the OVN NB and SB IDLs')),
|
||||||
|
cfg.IntOpt('ovsdb_probe_interval',
|
||||||
|
min=0,
|
||||||
|
default=60000,
|
||||||
|
help=_('The probe interval in for the OVSDB session in '
|
||||||
|
'milliseconds. If this is zero, it disables the '
|
||||||
|
'connection keepalive feature. If non-zero the value '
|
||||||
|
'will be forced to at least 1000 milliseconds. Defaults '
|
||||||
|
'to 60 seconds.')),
|
||||||
|
]
|
||||||
|
|
||||||
|
cfg.CONF.register_opts(ovn_opts, group='ovn')
|
||||||
|
|
||||||
|
|
||||||
|
def list_opts():
|
||||||
|
return [
|
||||||
|
('ovn', ovn_opts),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def get_ovn_nb_connection():
|
||||||
|
return cfg.CONF.ovn.ovn_nb_connection
|
||||||
|
|
||||||
|
|
||||||
|
def get_ovn_nb_private_key():
|
||||||
|
return cfg.CONF.ovn.ovn_nb_private_key
|
||||||
|
|
||||||
|
|
||||||
|
def get_ovn_nb_certificate():
|
||||||
|
return cfg.CONF.ovn.ovn_nb_certificate
|
||||||
|
|
||||||
|
|
||||||
|
def get_ovn_nb_ca_cert():
|
||||||
|
return cfg.CONF.ovn.ovn_nb_ca_cert
|
||||||
|
|
||||||
|
|
||||||
|
def get_ovn_ovsdb_timeout():
|
||||||
|
return cfg.CONF.ovn.ovsdb_connection_timeout
|
||||||
|
|
||||||
|
|
||||||
|
def get_ovn_ovsdb_retry_max_interval():
|
||||||
|
return cfg.CONF.ovn.ovsdb_retry_max_interval
|
||||||
|
|
||||||
|
|
||||||
|
def get_ovn_ovsdb_probe_interval():
|
||||||
|
return cfg.CONF.ovn.ovsdb_probe_interval
|
22
ovn_octavia_provider/common/constants.py
Normal file
22
ovn_octavia_provider/common/constants.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
# TODO(mjozefcz): Use those variables from neutron-lib once released.
|
||||||
|
LRP_PREFIX = "lrp-"
|
||||||
|
LB_VIP_PORT_PREFIX = "ovn-lb-vip-"
|
||||||
|
OVN_PORT_NAME_EXT_ID_KEY = 'neutron:port_name'
|
||||||
|
OVN_ROUTER_NAME_EXT_ID_KEY = 'neutron:router_name'
|
||||||
|
OVN_PORT_NAME_EXT_ID_KEY = 'neutron:port_name'
|
||||||
|
OVN_PORT_FIP_EXT_ID_KEY = 'neutron:port_fip'
|
||||||
|
OVN_SUBNET_EXT_ID_KEY = 'neutron:subnet_id'
|
||||||
|
OVN_SUBNET_EXT_IDS_KEY = 'neutron:subnet_ids'
|
||||||
|
OVN_NETWORK_NAME_EXT_ID_KEY = 'neutron:network_name'
|
24
ovn_octavia_provider/common/exceptions.py
Normal file
24
ovn_octavia_provider/common/exceptions.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Copyright 2019 Red Hat, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from neutron_lib import exceptions as n_exc
|
||||||
|
|
||||||
|
from ovn_octavia_provider.i18n import _
|
||||||
|
|
||||||
|
|
||||||
|
class RevisionConflict(n_exc.NeutronException):
|
||||||
|
message = _('OVN revision number for %(resource_id)s (type: '
|
||||||
|
'%(resource_type)s) is equal or higher than the given '
|
||||||
|
'resource. Skipping update')
|
33
ovn_octavia_provider/common/utils.py
Normal file
33
ovn_octavia_provider/common/utils.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# 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 ovn_octavia_provider.common import constants
|
||||||
|
|
||||||
|
|
||||||
|
def ovn_name(id):
|
||||||
|
# The name of the OVN entry will be neutron-<UUID>
|
||||||
|
# This is due to the fact that the OVN application checks if the name
|
||||||
|
# is a UUID. If so then there will be no matches.
|
||||||
|
# We prefix the UUID to enable us to use the Neutron UUID when
|
||||||
|
# updating, deleting etc.
|
||||||
|
return 'neutron-%s' % id
|
||||||
|
|
||||||
|
|
||||||
|
def ovn_lrouter_port_name(id):
|
||||||
|
# The name of the OVN lrouter port entry will be lrp-<UUID>
|
||||||
|
# This is to distinguish with the name of the connected lswitch patch port,
|
||||||
|
# which is named with neutron port uuid, so that OVS patch ports are
|
||||||
|
# generated properly. The pairing patch port names will be:
|
||||||
|
# - patch-lrp-<UUID>-to-<UUID>
|
||||||
|
# - patch-<UUID>-to-lrp-<UUID>
|
||||||
|
# lrp stands for Logical Router Port
|
||||||
|
return constants.LRP_PREFIX + '%s' % id
|
1856
ovn_octavia_provider/driver.py
Normal file
1856
ovn_octavia_provider/driver.py
Normal file
File diff suppressed because it is too large
Load Diff
20
ovn_octavia_provider/i18n.py
Normal file
20
ovn_octavia_provider/i18n.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import oslo_i18n as i18n
|
||||||
|
|
||||||
|
_translators = i18n.TranslatorFactory(domain='octavia')
|
||||||
|
|
||||||
|
# The primary translation function using the well-known name "_"
|
||||||
|
_ = _translators.primary
|
138
ovn_octavia_provider/ovsdb/impl_idl_ovn.py
Normal file
138
ovn_octavia_provider/ovsdb/impl_idl_ovn.py
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
# 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 contextlib
|
||||||
|
|
||||||
|
from neutron_lib import exceptions as n_exc
|
||||||
|
from oslo_log import log
|
||||||
|
from ovsdbapp.backend import ovs_idl
|
||||||
|
from ovsdbapp.backend.ovs_idl import idlutils
|
||||||
|
from ovsdbapp.backend.ovs_idl import transaction as idl_trans
|
||||||
|
from ovsdbapp.schema.ovn_northbound import impl_idl as nb_impl_idl
|
||||||
|
import tenacity
|
||||||
|
|
||||||
|
from ovn_octavia_provider.common import config
|
||||||
|
from ovn_octavia_provider.common import exceptions as ovn_exc
|
||||||
|
from ovn_octavia_provider.i18n import _
|
||||||
|
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class OvnNbTransaction(idl_trans.Transaction):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
# NOTE(lucasagomes): The bump_nb_cfg parameter is only used by
|
||||||
|
# the agents health status check
|
||||||
|
self.bump_nb_cfg = kwargs.pop('bump_nb_cfg', False)
|
||||||
|
super(OvnNbTransaction, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def pre_commit(self, txn):
|
||||||
|
if not self.bump_nb_cfg:
|
||||||
|
return
|
||||||
|
self.api.nb_global.increment('nb_cfg')
|
||||||
|
|
||||||
|
|
||||||
|
# This version of Backend doesn't use a class variable for ovsdb_connection
|
||||||
|
# and therefor allows networking-ovn to manage connection scope on its own
|
||||||
|
class Backend(ovs_idl.Backend):
|
||||||
|
lookup_table = {}
|
||||||
|
|
||||||
|
def __init__(self, connection):
|
||||||
|
self.ovsdb_connection = connection
|
||||||
|
super(Backend, self).__init__(connection)
|
||||||
|
|
||||||
|
def start_connection(self, connection):
|
||||||
|
try:
|
||||||
|
self.ovsdb_connection.start()
|
||||||
|
except Exception as e:
|
||||||
|
connection_exception = OvsdbConnectionUnavailable(
|
||||||
|
db_schema=self.schema, error=e)
|
||||||
|
LOG.exception(connection_exception)
|
||||||
|
raise connection_exception
|
||||||
|
|
||||||
|
@property
|
||||||
|
def idl(self):
|
||||||
|
return self.ovsdb_connection.idl
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tables(self):
|
||||||
|
return self.idl.tables
|
||||||
|
|
||||||
|
_tables = tables
|
||||||
|
|
||||||
|
def is_table_present(self, table_name):
|
||||||
|
return table_name in self._tables
|
||||||
|
|
||||||
|
def is_col_present(self, table_name, col_name):
|
||||||
|
return self.is_table_present(table_name) and (
|
||||||
|
col_name in self._tables[table_name].columns)
|
||||||
|
|
||||||
|
def create_transaction(self, check_error=False, log_errors=True):
|
||||||
|
return idl_trans.Transaction(
|
||||||
|
self, self.ovsdb_connection, self.ovsdb_connection.timeout,
|
||||||
|
check_error, log_errors)
|
||||||
|
|
||||||
|
# Check for a column match in the table. If not found do a retry with
|
||||||
|
# a stop delay of 10 secs. This function would be useful if the caller
|
||||||
|
# wants to verify for the presence of a particular row in the table
|
||||||
|
# with the column match before doing any transaction.
|
||||||
|
# Eg. We can check if Logical_Switch row is present before adding a
|
||||||
|
# logical switch port to it.
|
||||||
|
@tenacity.retry(retry=tenacity.retry_if_exception_type(RuntimeError),
|
||||||
|
wait=tenacity.wait_exponential(),
|
||||||
|
stop=tenacity.stop_after_delay(10),
|
||||||
|
reraise=True)
|
||||||
|
def check_for_row_by_value_and_retry(self, table, column, match):
|
||||||
|
try:
|
||||||
|
idlutils.row_by_value(self.idl, table, column, match)
|
||||||
|
except idlutils.RowNotFound:
|
||||||
|
msg = (_("%(match)s does not exist in %(column)s of %(table)s")
|
||||||
|
% {'match': match, 'column': column, 'table': table})
|
||||||
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
|
|
||||||
|
class OvsdbConnectionUnavailable(n_exc.ServiceUnavailable):
|
||||||
|
message = _("OVS database connection to %(db_schema)s failed with error: "
|
||||||
|
"'%(error)s'. Verify that the OVS and OVN services are "
|
||||||
|
"available and that the 'ovn_nb_connection' and "
|
||||||
|
"'ovn_sb_connection' configuration options are correct.")
|
||||||
|
|
||||||
|
|
||||||
|
class OvsdbNbOvnIdl(nb_impl_idl.OvnNbApiIdlImpl, Backend):
|
||||||
|
def __init__(self, connection):
|
||||||
|
super(OvsdbNbOvnIdl, self).__init__(connection)
|
||||||
|
self.idl._session.reconnect.set_probe_interval(
|
||||||
|
config.get_ovn_ovsdb_probe_interval())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nb_global(self):
|
||||||
|
return next(iter(self.tables['NB_Global'].rows.values()))
|
||||||
|
|
||||||
|
def create_transaction(self, check_error=False, log_errors=True,
|
||||||
|
bump_nb_cfg=False):
|
||||||
|
return OvnNbTransaction(
|
||||||
|
self, self.ovsdb_connection, self.ovsdb_connection.timeout,
|
||||||
|
check_error, log_errors, bump_nb_cfg=bump_nb_cfg)
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def transaction(self, *args, **kwargs):
|
||||||
|
"""A wrapper on the ovsdbapp transaction to work with revisions.
|
||||||
|
|
||||||
|
This method is just a wrapper around the ovsdbapp transaction
|
||||||
|
to handle revision conflicts correctly.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with super(OvsdbNbOvnIdl, self).transaction(*args, **kwargs) as t:
|
||||||
|
yield t
|
||||||
|
except ovn_exc.RevisionConflict as e:
|
||||||
|
LOG.info('Transaction aborted. Reason: %s', e)
|
90
ovn_octavia_provider/ovsdb/ovsdb_monitor.py
Normal file
90
ovn_octavia_provider/ovsdb/ovsdb_monitor.py
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
# Copyright 2020 Red Hat, 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
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
from oslo_log import log
|
||||||
|
from ovs.stream import Stream
|
||||||
|
from ovsdbapp.backend.ovs_idl import connection
|
||||||
|
from ovsdbapp.backend.ovs_idl import idlutils
|
||||||
|
from ovsdbapp import event
|
||||||
|
|
||||||
|
from ovn_octavia_provider.common import config as ovn_config
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class BaseOvnIdl(connection.OvsdbIdl):
|
||||||
|
@classmethod
|
||||||
|
def from_server(cls, connection_string, schema_name):
|
||||||
|
_check_and_set_ssl_files(schema_name)
|
||||||
|
helper = idlutils.get_schema_helper(connection_string, schema_name)
|
||||||
|
helper.register_all()
|
||||||
|
return cls(connection_string, helper)
|
||||||
|
|
||||||
|
|
||||||
|
class OvnIdl(BaseOvnIdl):
|
||||||
|
|
||||||
|
def __init__(self, driver, remote, schema):
|
||||||
|
super(OvnIdl, self).__init__(remote, schema)
|
||||||
|
self.driver = driver
|
||||||
|
self.notify_handler = OvnDbNotifyHandler(driver)
|
||||||
|
# ovsdb lock name to acquire.
|
||||||
|
# This event lock is used to handle the notify events sent by idl.Idl
|
||||||
|
# idl.Idl will call notify function for the "update" rpc method it
|
||||||
|
# receives from the ovsdb-server.
|
||||||
|
# This event lock is required for the following reasons
|
||||||
|
# - If there are multiple neutron servers running, OvnWorkers of
|
||||||
|
# these neutron servers would receive the notify events from
|
||||||
|
# idl.Idl
|
||||||
|
#
|
||||||
|
# - we do not want all the neutron servers to handle these events
|
||||||
|
#
|
||||||
|
# - only the neutron server which has the lock will handle the
|
||||||
|
# notify events.
|
||||||
|
#
|
||||||
|
# - In case the neutron server which owns this lock goes down,
|
||||||
|
# ovsdb server would assign the lock to one of the other neutron
|
||||||
|
# servers.
|
||||||
|
self.event_lock_name = "ovn_provider_driver_event_lock"
|
||||||
|
|
||||||
|
def notify(self, event, row, updates=None):
|
||||||
|
# Do not handle the notification if the event lock is requested,
|
||||||
|
# but not granted by the ovsdb-server.
|
||||||
|
if self.is_lock_contended:
|
||||||
|
return
|
||||||
|
self.notify_handler.notify(event, row, updates)
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def post_connect(self):
|
||||||
|
"""Should be called after the idl has been initialized"""
|
||||||
|
|
||||||
|
|
||||||
|
class OvnDbNotifyHandler(event.RowEventHandler):
|
||||||
|
def __init__(self, driver):
|
||||||
|
super(OvnDbNotifyHandler, self).__init__()
|
||||||
|
self.driver = driver
|
||||||
|
|
||||||
|
|
||||||
|
def _check_and_set_ssl_files(schema_name):
|
||||||
|
if schema_name == 'OVN_Northbound':
|
||||||
|
priv_key_file = ovn_config.get_ovn_nb_private_key()
|
||||||
|
cert_file = ovn_config.get_ovn_nb_certificate()
|
||||||
|
ca_cert_file = ovn_config.get_ovn_nb_ca_cert()
|
||||||
|
|
||||||
|
Stream.ssl_set_private_key_file(priv_key_file)
|
||||||
|
Stream.ssl_set_certificate_file(cert_file)
|
||||||
|
Stream.ssl_set_ca_cert_file(ca_cert_file)
|
222
ovn_octavia_provider/tests/unit/fakes.py
Normal file
222
ovn_octavia_provider/tests/unit/fakes.py
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
#
|
||||||
|
# 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
|
||||||
|
|
||||||
|
import mock
|
||||||
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
|
|
||||||
|
class FakeResource(dict):
|
||||||
|
|
||||||
|
def __init__(self, manager=None, info=None, loaded=False, methods=None):
|
||||||
|
"""Set attributes and methods for a resource.
|
||||||
|
|
||||||
|
:param manager:
|
||||||
|
The resource manager
|
||||||
|
:param Dictionary info:
|
||||||
|
A dictionary with all attributes
|
||||||
|
:param bool loaded:
|
||||||
|
True if the resource is loaded in memory
|
||||||
|
:param Dictionary methods:
|
||||||
|
A dictionary with all methods
|
||||||
|
"""
|
||||||
|
info = info or {}
|
||||||
|
super(FakeResource, self).__init__(info)
|
||||||
|
methods = methods or {}
|
||||||
|
|
||||||
|
self.__name__ = type(self).__name__
|
||||||
|
self.manager = manager
|
||||||
|
self._info = info
|
||||||
|
self._add_details(info)
|
||||||
|
self._add_methods(methods)
|
||||||
|
self._loaded = loaded
|
||||||
|
# Add a revision number by default
|
||||||
|
setattr(self, 'revision_number', 1)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def db_obj(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def _add_details(self, info):
|
||||||
|
for (k, v) in info.items():
|
||||||
|
setattr(self, k, v)
|
||||||
|
|
||||||
|
def _add_methods(self, methods):
|
||||||
|
"""Fake methods with MagicMock objects.
|
||||||
|
|
||||||
|
For each <@key, @value> pairs in methods, add an callable MagicMock
|
||||||
|
object named @key as an attribute, and set the mock's return_value to
|
||||||
|
@value. When users access the attribute with (), @value will be
|
||||||
|
returned, which looks like a function call.
|
||||||
|
"""
|
||||||
|
for (name, ret) in methods.items():
|
||||||
|
method = mock.MagicMock(return_value=ret)
|
||||||
|
setattr(self, name, method)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
reprkeys = sorted(k for k in self.__dict__.keys() if k[0] != '_' and
|
||||||
|
k != 'manager')
|
||||||
|
info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys)
|
||||||
|
return "<%s %s>" % (self.__class__.__name__, info)
|
||||||
|
|
||||||
|
def keys(self):
|
||||||
|
return self._info.keys()
|
||||||
|
|
||||||
|
def info(self):
|
||||||
|
return self._info
|
||||||
|
|
||||||
|
def update(self, info):
|
||||||
|
super(FakeResource, self).update(info)
|
||||||
|
self._add_details(info)
|
||||||
|
|
||||||
|
|
||||||
|
class FakeOvsdbRow(FakeResource):
|
||||||
|
"""Fake one or more OVSDB rows."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_one_ovsdb_row(attrs=None, methods=None):
|
||||||
|
"""Create a fake OVSDB row.
|
||||||
|
|
||||||
|
:param Dictionary attrs:
|
||||||
|
A dictionary with all attributes
|
||||||
|
:param Dictionary methods:
|
||||||
|
A dictionary with all methods
|
||||||
|
:return:
|
||||||
|
A FakeResource object faking the OVSDB row
|
||||||
|
"""
|
||||||
|
attrs = attrs or {}
|
||||||
|
methods = methods or {}
|
||||||
|
|
||||||
|
# Set default attributes.
|
||||||
|
fake_uuid = uuidutils.generate_uuid()
|
||||||
|
ovsdb_row_attrs = {
|
||||||
|
'uuid': fake_uuid,
|
||||||
|
'name': 'name-' + fake_uuid,
|
||||||
|
'external_ids': {},
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set default methods.
|
||||||
|
ovsdb_row_methods = {
|
||||||
|
'addvalue': None,
|
||||||
|
'delete': None,
|
||||||
|
'delvalue': None,
|
||||||
|
'verify': None,
|
||||||
|
'setkey': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Overwrite default attributes and methods.
|
||||||
|
ovsdb_row_attrs.update(attrs)
|
||||||
|
ovsdb_row_methods.update(methods)
|
||||||
|
|
||||||
|
return FakeResource(info=copy.deepcopy(ovsdb_row_attrs),
|
||||||
|
loaded=True,
|
||||||
|
methods=copy.deepcopy(ovsdb_row_methods))
|
||||||
|
|
||||||
|
|
||||||
|
class FakeSubnet(object):
|
||||||
|
"""Fake one or more subnets."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_one_subnet(attrs=None):
|
||||||
|
"""Create a fake subnet.
|
||||||
|
|
||||||
|
:param Dictionary attrs:
|
||||||
|
A dictionary with all attributes
|
||||||
|
:return:
|
||||||
|
A FakeResource object faking the subnet
|
||||||
|
"""
|
||||||
|
attrs = attrs or {}
|
||||||
|
|
||||||
|
# Set default attributes.
|
||||||
|
fake_uuid = uuidutils.generate_uuid()
|
||||||
|
subnet_attrs = {
|
||||||
|
'id': 'subnet-id-' + fake_uuid,
|
||||||
|
'name': 'subnet-name-' + fake_uuid,
|
||||||
|
'network_id': 'network-id-' + fake_uuid,
|
||||||
|
'cidr': '10.10.10.0/24',
|
||||||
|
'tenant_id': 'project-id-' + fake_uuid,
|
||||||
|
'enable_dhcp': True,
|
||||||
|
'dns_nameservers': [],
|
||||||
|
'allocation_pools': [],
|
||||||
|
'host_routes': [],
|
||||||
|
'ip_version': 4,
|
||||||
|
'gateway_ip': '10.10.10.1',
|
||||||
|
'ipv6_address_mode': 'None',
|
||||||
|
'ipv6_ra_mode': 'None',
|
||||||
|
'subnetpool_id': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Overwrite default attributes.
|
||||||
|
subnet_attrs.update(attrs)
|
||||||
|
|
||||||
|
return FakeResource(info=copy.deepcopy(subnet_attrs),
|
||||||
|
loaded=True)
|
||||||
|
|
||||||
|
|
||||||
|
class FakeOVNPort(object):
|
||||||
|
"""Fake one or more ports."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_one_port(attrs=None):
|
||||||
|
"""Create a fake ovn port.
|
||||||
|
|
||||||
|
:param Dictionary attrs:
|
||||||
|
A dictionary with all attributes
|
||||||
|
:return:
|
||||||
|
A FakeResource object faking the port
|
||||||
|
"""
|
||||||
|
attrs = attrs or {}
|
||||||
|
|
||||||
|
# Set default attributes.
|
||||||
|
fake_uuid = uuidutils.generate_uuid()
|
||||||
|
port_attrs = {
|
||||||
|
'addresses': [],
|
||||||
|
'dhcpv4_options': '',
|
||||||
|
'dhcpv6_options': [],
|
||||||
|
'enabled': True,
|
||||||
|
'external_ids': {},
|
||||||
|
'name': fake_uuid,
|
||||||
|
'options': {},
|
||||||
|
'parent_name': [],
|
||||||
|
'port_security': [],
|
||||||
|
'tag': [],
|
||||||
|
'tag_request': [],
|
||||||
|
'type': '',
|
||||||
|
'up': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Overwrite default attributes.
|
||||||
|
port_attrs.update(attrs)
|
||||||
|
return type('Logical_Switch_Port', (object, ), port_attrs)
|
||||||
|
|
||||||
|
|
||||||
|
class FakeOVNRouter(object):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_one_router(attrs=None):
|
||||||
|
router_attrs = {
|
||||||
|
'enabled': False,
|
||||||
|
'external_ids': {},
|
||||||
|
'load_balancer': [],
|
||||||
|
'name': '',
|
||||||
|
'nat': [],
|
||||||
|
'options': {},
|
||||||
|
'ports': [],
|
||||||
|
'static_routes': [],
|
||||||
|
}
|
||||||
|
|
||||||
|
# Overwrite default attributes.
|
||||||
|
router_attrs.update(attrs)
|
||||||
|
return type('Logical_Router', (object, ), router_attrs)
|
449
ovn_octavia_provider/tests/unit/schemas/ovn-nb.ovsschema
Normal file
449
ovn_octavia_provider/tests/unit/schemas/ovn-nb.ovsschema
Normal file
@ -0,0 +1,449 @@
|
|||||||
|
{
|
||||||
|
"name": "OVN_Northbound",
|
||||||
|
"version": "5.16.0",
|
||||||
|
"cksum": "923459061 23095",
|
||||||
|
"tables": {
|
||||||
|
"NB_Global": {
|
||||||
|
"columns": {
|
||||||
|
"nb_cfg": {"type": {"key": "integer"}},
|
||||||
|
"sb_cfg": {"type": {"key": "integer"}},
|
||||||
|
"hv_cfg": {"type": {"key": "integer"}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}},
|
||||||
|
"connections": {
|
||||||
|
"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "Connection"},
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"ssl": {
|
||||||
|
"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "SSL"},
|
||||||
|
"min": 0, "max": 1}},
|
||||||
|
"options": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}},
|
||||||
|
"ipsec": {"type": "boolean"}},
|
||||||
|
"maxRows": 1,
|
||||||
|
"isRoot": true},
|
||||||
|
"Logical_Switch": {
|
||||||
|
"columns": {
|
||||||
|
"name": {"type": "string"},
|
||||||
|
"ports": {"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "Logical_Switch_Port",
|
||||||
|
"refType": "strong"},
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"acls": {"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "ACL",
|
||||||
|
"refType": "strong"},
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"qos_rules": {"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "QoS",
|
||||||
|
"refType": "strong"},
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"load_balancer": {"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "Load_Balancer",
|
||||||
|
"refType": "weak"},
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"dns_records": {"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "DNS",
|
||||||
|
"refType": "weak"},
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"other_config": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}}},
|
||||||
|
"isRoot": true},
|
||||||
|
"Logical_Switch_Port": {
|
||||||
|
"columns": {
|
||||||
|
"name": {"type": "string"},
|
||||||
|
"type": {"type": "string"},
|
||||||
|
"options": {
|
||||||
|
"type": {"key": "string",
|
||||||
|
"value": "string",
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"parent_name": {"type": {"key": "string", "min": 0, "max": 1}},
|
||||||
|
"tag_request": {
|
||||||
|
"type": {"key": {"type": "integer",
|
||||||
|
"minInteger": 0,
|
||||||
|
"maxInteger": 4095},
|
||||||
|
"min": 0, "max": 1}},
|
||||||
|
"tag": {
|
||||||
|
"type": {"key": {"type": "integer",
|
||||||
|
"minInteger": 1,
|
||||||
|
"maxInteger": 4095},
|
||||||
|
"min": 0, "max": 1}},
|
||||||
|
"addresses": {"type": {"key": "string",
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"dynamic_addresses": {"type": {"key": "string",
|
||||||
|
"min": 0,
|
||||||
|
"max": 1}},
|
||||||
|
"port_security": {"type": {"key": "string",
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"up": {"type": {"key": "boolean", "min": 0, "max": 1}},
|
||||||
|
"enabled": {"type": {"key": "boolean", "min": 0, "max": 1}},
|
||||||
|
"dhcpv4_options": {"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "DHCP_Options",
|
||||||
|
"refType": "weak"},
|
||||||
|
"min": 0,
|
||||||
|
"max": 1}},
|
||||||
|
"dhcpv6_options": {"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "DHCP_Options",
|
||||||
|
"refType": "weak"},
|
||||||
|
"min": 0,
|
||||||
|
"max": 1}},
|
||||||
|
"ha_chassis_group": {
|
||||||
|
"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "HA_Chassis_Group",
|
||||||
|
"refType": "strong"},
|
||||||
|
"min": 0,
|
||||||
|
"max": 1}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}}},
|
||||||
|
"indexes": [["name"]],
|
||||||
|
"isRoot": false},
|
||||||
|
"Address_Set": {
|
||||||
|
"columns": {
|
||||||
|
"name": {"type": "string"},
|
||||||
|
"addresses": {"type": {"key": "string",
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}}},
|
||||||
|
"indexes": [["name"]],
|
||||||
|
"isRoot": true},
|
||||||
|
"Port_Group": {
|
||||||
|
"columns": {
|
||||||
|
"name": {"type": "string"},
|
||||||
|
"ports": {"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "Logical_Switch_Port",
|
||||||
|
"refType": "weak"},
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"acls": {"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "ACL",
|
||||||
|
"refType": "strong"},
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}}},
|
||||||
|
"indexes": [["name"]],
|
||||||
|
"isRoot": true},
|
||||||
|
"Load_Balancer": {
|
||||||
|
"columns": {
|
||||||
|
"name": {"type": "string"},
|
||||||
|
"vips": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}},
|
||||||
|
"protocol": {
|
||||||
|
"type": {"key": {"type": "string",
|
||||||
|
"enum": ["set", ["tcp", "udp"]]},
|
||||||
|
"min": 0, "max": 1}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}}},
|
||||||
|
"isRoot": true},
|
||||||
|
"ACL": {
|
||||||
|
"columns": {
|
||||||
|
"name": {"type": {"key": {"type": "string",
|
||||||
|
"maxLength": 63},
|
||||||
|
"min": 0, "max": 1}},
|
||||||
|
"priority": {"type": {"key": {"type": "integer",
|
||||||
|
"minInteger": 0,
|
||||||
|
"maxInteger": 32767}}},
|
||||||
|
"direction": {"type": {"key": {"type": "string",
|
||||||
|
"enum": ["set", ["from-lport", "to-lport"]]}}},
|
||||||
|
"match": {"type": "string"},
|
||||||
|
"action": {"type": {"key": {"type": "string",
|
||||||
|
"enum": ["set", ["allow", "allow-related", "drop", "reject"]]}}},
|
||||||
|
"log": {"type": "boolean"},
|
||||||
|
"severity": {"type": {"key": {"type": "string",
|
||||||
|
"enum": ["set",
|
||||||
|
["alert", "warning",
|
||||||
|
"notice", "info",
|
||||||
|
"debug"]]},
|
||||||
|
"min": 0, "max": 1}},
|
||||||
|
"meter": {"type": {"key": "string", "min": 0, "max": 1}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}}},
|
||||||
|
"isRoot": false},
|
||||||
|
"QoS": {
|
||||||
|
"columns": {
|
||||||
|
"priority": {"type": {"key": {"type": "integer",
|
||||||
|
"minInteger": 0,
|
||||||
|
"maxInteger": 32767}}},
|
||||||
|
"direction": {"type": {"key": {"type": "string",
|
||||||
|
"enum": ["set", ["from-lport", "to-lport"]]}}},
|
||||||
|
"match": {"type": "string"},
|
||||||
|
"action": {"type": {"key": {"type": "string",
|
||||||
|
"enum": ["set", ["dscp"]]},
|
||||||
|
"value": {"type": "integer",
|
||||||
|
"minInteger": 0,
|
||||||
|
"maxInteger": 63},
|
||||||
|
"min": 0, "max": "unlimited"}},
|
||||||
|
"bandwidth": {"type": {"key": {"type": "string",
|
||||||
|
"enum": ["set", ["rate",
|
||||||
|
"burst"]]},
|
||||||
|
"value": {"type": "integer",
|
||||||
|
"minInteger": 1,
|
||||||
|
"maxInteger": 4294967295},
|
||||||
|
"min": 0, "max": "unlimited"}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}}},
|
||||||
|
"isRoot": false},
|
||||||
|
"Meter": {
|
||||||
|
"columns": {
|
||||||
|
"name": {"type": "string"},
|
||||||
|
"unit": {"type": {"key": {"type": "string",
|
||||||
|
"enum": ["set", ["kbps", "pktps"]]}}},
|
||||||
|
"bands": {"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "Meter_Band",
|
||||||
|
"refType": "strong"},
|
||||||
|
"min": 1,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}}},
|
||||||
|
"indexes": [["name"]],
|
||||||
|
"isRoot": true},
|
||||||
|
"Meter_Band": {
|
||||||
|
"columns": {
|
||||||
|
"action": {"type": {"key": {"type": "string",
|
||||||
|
"enum": ["set", ["drop"]]}}},
|
||||||
|
"rate": {"type": {"key": {"type": "integer",
|
||||||
|
"minInteger": 1,
|
||||||
|
"maxInteger": 4294967295}}},
|
||||||
|
"burst_size": {"type": {"key": {"type": "integer",
|
||||||
|
"minInteger": 0,
|
||||||
|
"maxInteger": 4294967295}}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}}},
|
||||||
|
"isRoot": false},
|
||||||
|
"Logical_Router": {
|
||||||
|
"columns": {
|
||||||
|
"name": {"type": "string"},
|
||||||
|
"ports": {"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "Logical_Router_Port",
|
||||||
|
"refType": "strong"},
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"static_routes": {"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "Logical_Router_Static_Route",
|
||||||
|
"refType": "strong"},
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"policies": {
|
||||||
|
"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "Logical_Router_Policy",
|
||||||
|
"refType": "strong"},
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"enabled": {"type": {"key": "boolean", "min": 0, "max": 1}},
|
||||||
|
"nat": {"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "NAT",
|
||||||
|
"refType": "strong"},
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"load_balancer": {"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "Load_Balancer",
|
||||||
|
"refType": "weak"},
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"options": {
|
||||||
|
"type": {"key": "string",
|
||||||
|
"value": "string",
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}}},
|
||||||
|
"isRoot": true},
|
||||||
|
"Logical_Router_Port": {
|
||||||
|
"columns": {
|
||||||
|
"name": {"type": "string"},
|
||||||
|
"gateway_chassis": {
|
||||||
|
"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "Gateway_Chassis",
|
||||||
|
"refType": "strong"},
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"ha_chassis_group": {
|
||||||
|
"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "HA_Chassis_Group",
|
||||||
|
"refType": "strong"},
|
||||||
|
"min": 0,
|
||||||
|
"max": 1}},
|
||||||
|
"options": {
|
||||||
|
"type": {"key": "string",
|
||||||
|
"value": "string",
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"networks": {"type": {"key": "string",
|
||||||
|
"min": 1,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"mac": {"type": "string"},
|
||||||
|
"peer": {"type": {"key": "string", "min": 0, "max": 1}},
|
||||||
|
"enabled": {"type": {"key": "boolean", "min": 0, "max": 1}},
|
||||||
|
"ipv6_ra_configs": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}}},
|
||||||
|
"indexes": [["name"]],
|
||||||
|
"isRoot": false},
|
||||||
|
"Logical_Router_Static_Route": {
|
||||||
|
"columns": {
|
||||||
|
"ip_prefix": {"type": "string"},
|
||||||
|
"policy": {"type": {"key": {"type": "string",
|
||||||
|
"enum": ["set", ["src-ip",
|
||||||
|
"dst-ip"]]},
|
||||||
|
"min": 0, "max": 1}},
|
||||||
|
"nexthop": {"type": "string"},
|
||||||
|
"output_port": {"type": {"key": "string", "min": 0, "max": 1}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}}},
|
||||||
|
"isRoot": false},
|
||||||
|
"Logical_Router_Policy": {
|
||||||
|
"columns": {
|
||||||
|
"priority": {"type": {"key": {"type": "integer",
|
||||||
|
"minInteger": 0,
|
||||||
|
"maxInteger": 32767}}},
|
||||||
|
"match": {"type": "string"},
|
||||||
|
"action": {"type": {
|
||||||
|
"key": {"type": "string",
|
||||||
|
"enum": ["set", ["allow", "drop", "reroute"]]}}},
|
||||||
|
"nexthop": {"type": {"key": "string", "min": 0, "max": 1}}},
|
||||||
|
"isRoot": false},
|
||||||
|
"NAT": {
|
||||||
|
"columns": {
|
||||||
|
"external_ip": {"type": "string"},
|
||||||
|
"external_mac": {"type": {"key": "string",
|
||||||
|
"min": 0, "max": 1}},
|
||||||
|
"logical_ip": {"type": "string"},
|
||||||
|
"logical_port": {"type": {"key": "string",
|
||||||
|
"min": 0, "max": 1}},
|
||||||
|
"type": {"type": {"key": {"type": "string",
|
||||||
|
"enum": ["set", ["dnat",
|
||||||
|
"snat",
|
||||||
|
"dnat_and_snat"
|
||||||
|
]]}}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}}},
|
||||||
|
"isRoot": false},
|
||||||
|
"DHCP_Options": {
|
||||||
|
"columns": {
|
||||||
|
"cidr": {"type": "string"},
|
||||||
|
"options": {"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}}},
|
||||||
|
"isRoot": true},
|
||||||
|
"Connection": {
|
||||||
|
"columns": {
|
||||||
|
"target": {"type": "string"},
|
||||||
|
"max_backoff": {"type": {"key": {"type": "integer",
|
||||||
|
"minInteger": 1000},
|
||||||
|
"min": 0,
|
||||||
|
"max": 1}},
|
||||||
|
"inactivity_probe": {"type": {"key": "integer",
|
||||||
|
"min": 0,
|
||||||
|
"max": 1}},
|
||||||
|
"other_config": {"type": {"key": "string",
|
||||||
|
"value": "string",
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"external_ids": {"type": {"key": "string",
|
||||||
|
"value": "string",
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"is_connected": {"type": "boolean", "ephemeral": true},
|
||||||
|
"status": {"type": {"key": "string",
|
||||||
|
"value": "string",
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"},
|
||||||
|
"ephemeral": true}},
|
||||||
|
"indexes": [["target"]]},
|
||||||
|
"DNS": {
|
||||||
|
"columns": {
|
||||||
|
"records": {"type": {"key": "string",
|
||||||
|
"value": "string",
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"external_ids": {"type": {"key": "string",
|
||||||
|
"value": "string",
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}}},
|
||||||
|
"isRoot": true},
|
||||||
|
"SSL": {
|
||||||
|
"columns": {
|
||||||
|
"private_key": {"type": "string"},
|
||||||
|
"certificate": {"type": "string"},
|
||||||
|
"ca_cert": {"type": "string"},
|
||||||
|
"bootstrap_ca_cert": {"type": "boolean"},
|
||||||
|
"ssl_protocols": {"type": "string"},
|
||||||
|
"ssl_ciphers": {"type": "string"},
|
||||||
|
"external_ids": {"type": {"key": "string",
|
||||||
|
"value": "string",
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}}},
|
||||||
|
"maxRows": 1},
|
||||||
|
"Gateway_Chassis": {
|
||||||
|
"columns": {
|
||||||
|
"name": {"type": "string"},
|
||||||
|
"chassis_name": {"type": "string"},
|
||||||
|
"priority": {"type": {"key": {"type": "integer",
|
||||||
|
"minInteger": 0,
|
||||||
|
"maxInteger": 32767}}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}},
|
||||||
|
"options": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}}},
|
||||||
|
"indexes": [["name"]],
|
||||||
|
"isRoot": false},
|
||||||
|
"HA_Chassis": {
|
||||||
|
"columns": {
|
||||||
|
"chassis_name": {"type": "string"},
|
||||||
|
"priority": {"type": {"key": {"type": "integer",
|
||||||
|
"minInteger": 0,
|
||||||
|
"maxInteger": 32767}}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}}},
|
||||||
|
"isRoot": false},
|
||||||
|
"HA_Chassis_Group": {
|
||||||
|
"columns": {
|
||||||
|
"name": {"type": "string"},
|
||||||
|
"ha_chassis": {
|
||||||
|
"type": {"key": {"type": "uuid",
|
||||||
|
"refTable": "HA_Chassis",
|
||||||
|
"refType": "strong"},
|
||||||
|
"min": 0,
|
||||||
|
"max": "unlimited"}},
|
||||||
|
"external_ids": {
|
||||||
|
"type": {"key": "string", "value": "string",
|
||||||
|
"min": 0, "max": "unlimited"}}},
|
||||||
|
"indexes": [["name"]],
|
||||||
|
"isRoot": true}}
|
||||||
|
}
|
2141
ovn_octavia_provider/tests/unit/test_driver.py
Normal file
2141
ovn_octavia_provider/tests/unit/test_driver.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,5 @@ ovsdbapp>=0.17.0 # Apache-2.0
|
|||||||
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
||||||
tenacity>=4.4.0 # Apache-2.0
|
tenacity>=4.4.0 # Apache-2.0
|
||||||
Babel!=2.4.0,>=2.3.4 # BSD
|
Babel!=2.4.0,>=2.3.4 # BSD
|
||||||
neutron>=13.0.0.0b2 # Apache-2.0
|
|
||||||
octavia-lib>=1.3.1 # Apache-2.0
|
octavia-lib>=1.3.1 # Apache-2.0
|
||||||
python-neutronclient>=6.7.0 # Apache-2.0
|
python-neutronclient>=6.7.0 # Apache-2.0
|
||||||
|
@ -25,3 +25,8 @@ packages =
|
|||||||
[global]
|
[global]
|
||||||
setup-hooks =
|
setup-hooks =
|
||||||
pbr.hooks.setup_hook
|
pbr.hooks.setup_hook
|
||||||
|
|
||||||
|
|
||||||
|
[entry_points]
|
||||||
|
octavia.api.drivers =
|
||||||
|
ovn = ovn_octavia_provider.driver:OvnProviderDriver
|
||||||
|
@ -17,3 +17,4 @@ testresources>=2.0.0 # Apache-2.0/BSD
|
|||||||
testscenarios>=0.4 # Apache-2.0/BSD
|
testscenarios>=0.4 # Apache-2.0/BSD
|
||||||
WebTest>=2.0.27 # MIT
|
WebTest>=2.0.27 # MIT
|
||||||
testtools>=2.2.0 # MIT
|
testtools>=2.2.0 # MIT
|
||||||
|
neutron>=15.0.0 # Apache-2.0
|
||||||
|
Loading…
Reference in New Issue
Block a user