ic: add support for OVN_IC_Northbound schema
This change provides 'OvnIcNbApiIdlImpl' class for interaction with 'ovn_ic_nb.db' and adds functions and commands to add, delete and list rows of 'Transit_Switch' table in 'OVN_IC_Northbound' schema. Closes-Bug: 1944441 Change-Id: I322f05c1a91113a9470218946b7ce151a63737be
This commit is contained in:
parent
3a5927938b
commit
39426dbd4d
0
ovsdbapp/schema/ovn_ic_northbound/__init__.py
Normal file
0
ovsdbapp/schema/ovn_ic_northbound/__init__.py
Normal file
61
ovsdbapp/schema/ovn_ic_northbound/api.py
Normal file
61
ovsdbapp/schema/ovn_ic_northbound/api.py
Normal file
@ -0,0 +1,61 @@
|
||||
# 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 ovsdbapp import api
|
||||
|
||||
|
||||
class API(api.API, metaclass=abc.ABCMeta):
|
||||
"""An API based off of the ovn-ic-nbctl CLI interface
|
||||
|
||||
This API basically mirrors the ovn-ic-nbctl operations with these changes:
|
||||
1. Methods that create objects will return a read-only view of the object
|
||||
2. Methods which list objects will return a list of read-only view objects
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def ts_add(self, switch, may_exist=False, **columns):
|
||||
"""Create a transit switch named 'switch'
|
||||
|
||||
:param switch: The name of the switch
|
||||
:type switch: string or uuid.UUID
|
||||
:param may_exist: If True, don't fail if the switch already exists
|
||||
:type may_exist: boolean
|
||||
:param columns: Additional columns to directly set on the switch
|
||||
:returns: :class:`Command` with RowView result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def ts_del(self, switch, if_exists=False):
|
||||
"""Delete transit switch 'switch' and all its ports
|
||||
|
||||
:param switch: The name or uuid of the switch
|
||||
:type switch: string or uuid.UUID
|
||||
:param if_exists: If True, don't fail if the switch doesn't exist
|
||||
:type if_exists: boolean
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def ts_list(self):
|
||||
"""Get all transit switches
|
||||
|
||||
:returns: :class:`Command` with RowView list result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def ts_get(self, switch):
|
||||
"""Get transit switch for 'switch'
|
||||
|
||||
:returns: :class:`Command` with RowView result
|
||||
"""
|
67
ovsdbapp/schema/ovn_ic_northbound/commands.py
Normal file
67
ovsdbapp/schema/ovn_ic_northbound/commands.py
Normal file
@ -0,0 +1,67 @@
|
||||
# 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 ovsdbapp.backend.ovs_idl import command as cmd
|
||||
from ovsdbapp.backend.ovs_idl import idlutils
|
||||
from ovsdbapp.backend.ovs_idl import rowview
|
||||
|
||||
|
||||
class TsAddCommand(cmd.AddCommand):
|
||||
table_name = 'Transit_Switch'
|
||||
|
||||
def __init__(self, api, switch, may_exist=False, **columns):
|
||||
super().__init__(api)
|
||||
self.switch = switch
|
||||
self.columns = columns
|
||||
self.may_exist = may_exist
|
||||
|
||||
def run_idl(self, txn):
|
||||
# There is requirement for name to be unique
|
||||
# (index in ovn-ic-nb.ovsschema)
|
||||
switch = idlutils.row_by_value(self.api.idl, self.table_name, 'name',
|
||||
self.switch, None)
|
||||
if switch:
|
||||
if self.may_exist:
|
||||
self.result = rowview.RowView(switch)
|
||||
return
|
||||
raise RuntimeError("Transit Switch %s exists" % self.switch)
|
||||
switch = txn.insert(self.api.tables[self.table_name])
|
||||
switch.name = self.switch
|
||||
self.set_columns(switch, **self.columns)
|
||||
self.result = switch.uuid
|
||||
|
||||
|
||||
class TsDelCommand(cmd.BaseCommand):
|
||||
def __init__(self, api, switch, if_exists=False):
|
||||
super().__init__(api)
|
||||
self.switch = switch
|
||||
self.if_exists = if_exists
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
switch = self.api.lookup('Transit_Switch', self.switch)
|
||||
switch.delete()
|
||||
except idlutils.RowNotFound as e:
|
||||
if self.if_exists:
|
||||
return
|
||||
msg = "Transit Switch %s does not exist" % self.switch
|
||||
raise RuntimeError(msg) from e
|
||||
|
||||
|
||||
class TsListCommand(cmd.ReadOnlyCommand):
|
||||
def run_idl(self, txn):
|
||||
table = self.api.tables['Transit_Switch']
|
||||
self.result = [rowview.RowView(r) for r in table.rows.values()]
|
||||
|
||||
|
||||
class TsGetCommand(cmd.BaseGetRowCommand):
|
||||
table = 'Transit_Switch'
|
35
ovsdbapp/schema/ovn_ic_northbound/impl_idl.py
Normal file
35
ovsdbapp/schema/ovn_ic_northbound/impl_idl.py
Normal file
@ -0,0 +1,35 @@
|
||||
# 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 ovsdbapp.backend import ovs_idl
|
||||
from ovsdbapp.backend.ovs_idl import idlutils
|
||||
from ovsdbapp.schema.ovn_ic_northbound import api
|
||||
from ovsdbapp.schema.ovn_ic_northbound import commands as cmd
|
||||
|
||||
|
||||
class OvnIcNbApiIdlImpl(ovs_idl.Backend, api.API):
|
||||
schema = 'OVN_IC_Northbound'
|
||||
lookup_table = {
|
||||
'Transit_Switch': idlutils.RowLookup('Transit_Switch', 'name', None),
|
||||
}
|
||||
|
||||
def ts_add(self, switch, may_exist=False, **columns):
|
||||
return cmd.TsAddCommand(self, switch, may_exist, **columns)
|
||||
|
||||
def ts_del(self, switch, if_exists=False):
|
||||
return cmd.TsDelCommand(self, switch, if_exists)
|
||||
|
||||
def ts_list(self):
|
||||
return cmd.TsListCommand(self)
|
||||
|
||||
def ts_get(self, switch):
|
||||
return cmd.TsGetCommand(self, switch)
|
@ -30,7 +30,9 @@ class FunctionalTestCase(base.TestCase):
|
||||
ovsvenv.setUp()
|
||||
schema_map = {'Open_vSwitch': ovsvenv.ovs_connection,
|
||||
'OVN_Northbound': ovsvenv.ovnnb_connection,
|
||||
'OVN_Southbound': ovsvenv.ovnsb_connection}
|
||||
'OVN_Southbound': ovsvenv.ovnsb_connection,
|
||||
'OVN_IC_Northbound': ovsvenv.ovn_icnb_connection,
|
||||
}
|
||||
ovsvenvlog = None
|
||||
if os.getenv('KEEP_VENV') and os.getenv('VIRTUAL_ENV'):
|
||||
ovsvenvlog = open(os.path.join(os.getenv('VIRTUAL_ENV'),
|
||||
|
@ -0,0 +1,18 @@
|
||||
# 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 ovsdbapp.tests.functional.schema import fixtures
|
||||
|
||||
|
||||
class TransitSwitchesFixture(fixtures.ImplIdlFixture):
|
||||
create = 'ts_add'
|
||||
delete = 'ts_del'
|
@ -0,0 +1,95 @@
|
||||
# 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 ovsdbapp.schema.ovn_ic_northbound import impl_idl
|
||||
from ovsdbapp.tests.functional import base
|
||||
from ovsdbapp.tests.functional.schema.ovn_ic_northbound import fixtures
|
||||
from ovsdbapp.tests import utils
|
||||
|
||||
|
||||
class OvnIcNorthboundTest(base.FunctionalTestCase):
|
||||
schemas = ['OVN_IC_Northbound']
|
||||
|
||||
def setUp(self):
|
||||
super(OvnIcNorthboundTest, self).setUp()
|
||||
self.api = impl_idl.OvnIcNbApiIdlImpl(self.connection)
|
||||
self.table = self.api.tables['Transit_Switch']
|
||||
|
||||
def _ts_add(self, *args, **kwargs):
|
||||
fix = self.useFixture(fixtures.TransitSwitchesFixture(self.api, *args,
|
||||
**kwargs))
|
||||
self.assertIn(fix.obj.uuid, self.table.rows)
|
||||
return fix.obj
|
||||
|
||||
def _test_ts_get(self, col):
|
||||
ts = self._ts_add(switch=utils.get_rand_device_name())
|
||||
val = getattr(ts, col)
|
||||
found = self.api.ts_get(val).execute(check_error=True)
|
||||
self.assertEqual(ts, found)
|
||||
|
||||
def test_ts_get_uuid(self):
|
||||
self._test_ts_get('uuid')
|
||||
|
||||
def test_ts_get_name(self):
|
||||
self._test_ts_get('name')
|
||||
|
||||
def test_ts_add_name(self):
|
||||
name = utils.get_rand_device_name()
|
||||
ts = self._ts_add(name)
|
||||
self.assertEqual(name, ts.name)
|
||||
|
||||
def test_ts_add_existing(self):
|
||||
name = utils.get_rand_device_name()
|
||||
self._ts_add(name)
|
||||
cmd = self.api.ts_add(name)
|
||||
self.assertRaises(RuntimeError, cmd.execute, check_error=True)
|
||||
|
||||
def test_ts_add_may_exist(self):
|
||||
name = utils.get_rand_device_name()
|
||||
sw = self._ts_add(name)
|
||||
sw2 = self.api.ts_add(name, may_exist=True).execute(check_error=True)
|
||||
self.assertEqual(sw, sw2)
|
||||
|
||||
def test_ts_add_columns(self):
|
||||
external_ids = {'mykey': 'myvalue', 'yourkey': 'yourvalue'}
|
||||
ts = self._ts_add(switch=utils.get_rand_device_name(),
|
||||
external_ids=external_ids)
|
||||
self.assertEqual(external_ids, ts.external_ids)
|
||||
|
||||
def test_ts_del(self):
|
||||
sw = self._ts_add(switch=utils.get_rand_device_name())
|
||||
self.api.ts_del(sw.uuid).execute(check_error=True)
|
||||
self.assertNotIn(sw.uuid, self.table.rows)
|
||||
|
||||
def test_ts_del_by_name(self):
|
||||
name = utils.get_rand_device_name()
|
||||
self._ts_add(name)
|
||||
self.api.ts_del(name).execute(check_error=True)
|
||||
found = self.api.ts_get(name).execute()
|
||||
self.assertIsNone(found)
|
||||
|
||||
def test_ts_del_no_existing(self):
|
||||
name = utils.get_rand_device_name()
|
||||
cmd = self.api.ts_del(name)
|
||||
self.assertRaises(RuntimeError, cmd.execute, check_error=True)
|
||||
|
||||
def test_ts_del_if_exists(self):
|
||||
name = utils.get_rand_device_name()
|
||||
self.api.ts_del(name, if_exists=True).execute(check_error=True)
|
||||
found = self.api.ts_get(name).execute()
|
||||
self.assertIsNone(found)
|
||||
|
||||
def test_ts_list(self):
|
||||
switches = {self._ts_add(str(i)) for i in range(3)}
|
||||
switch_set = set(self.api.ts_list().execute(check_error=True))
|
||||
self.assertTrue(switches.issubset(switch_set))
|
@ -151,8 +151,10 @@ class OvsOvnVenvFixture(OvsVenvFixture):
|
||||
os.path.join(os.path.sep, 'usr', 'local', 'share', 'ovn'),
|
||||
os.path.join(os.path.sep, 'usr', 'share', 'ovn')) + (
|
||||
OvsVenvFixture.OVS_PATHS)
|
||||
|
||||
NBSCHEMA = 'ovn-nb.ovsschema'
|
||||
SBSCHEMA = 'ovn-sb.ovsschema'
|
||||
IC_NBSCHEMA = 'ovn-ic-nb.ovsschema'
|
||||
|
||||
def __init__(self, venv, ovndir=None, add_chassis=False, **kwargs):
|
||||
self.add_chassis = add_chassis
|
||||
@ -162,7 +164,8 @@ class OvsOvnVenvFixture(OvsVenvFixture):
|
||||
":{0}/controller:{0}/northd:{0}/utilities".format(ovndir))
|
||||
super().__init__(venv, **kwargs)
|
||||
self.ovndir = self._share_path(self.OVN_PATHS, ovndir,
|
||||
[self.SBSCHEMA, self.NBSCHEMA])
|
||||
[self.SBSCHEMA, self.NBSCHEMA,
|
||||
self.IC_NBSCHEMA])
|
||||
self.env.update({'OVN_RUNDIR': self.venv})
|
||||
|
||||
@property
|
||||
@ -173,6 +176,10 @@ class OvsOvnVenvFixture(OvsVenvFixture):
|
||||
def ovnnb_schema(self):
|
||||
return os.path.join(self.ovndir, self.NBSCHEMA)
|
||||
|
||||
@property
|
||||
def ovn_icnb_schema(self):
|
||||
return os.path.join(self.ovndir, self.IC_NBSCHEMA)
|
||||
|
||||
@property
|
||||
def ovnnb_connection(self):
|
||||
return 'unix:' + os.path.join(self.venv, 'ovnnb_db.sock')
|
||||
@ -181,38 +188,45 @@ class OvsOvnVenvFixture(OvsVenvFixture):
|
||||
def ovnsb_connection(self):
|
||||
return 'unix:' + os.path.join(self.venv, 'ovnsb_db.sock')
|
||||
|
||||
@property
|
||||
def ovn_icnb_connection(self):
|
||||
return 'unix:' + os.path.join(self.venv, 'ovn_ic_nb_db.sock')
|
||||
|
||||
def setup_dbs(self):
|
||||
super().setup_dbs()
|
||||
self.create_db('ovnsb.db', self.ovnsb_schema)
|
||||
self.create_db('ovnnb.db', self.ovnnb_schema)
|
||||
self.create_db('ovn_ic_nb.db', self.ovn_icnb_schema)
|
||||
|
||||
def start_ovsdb_processes(self):
|
||||
super().start_ovsdb_processes()
|
||||
self.call(['ovsdb-server', '--detach', '--no-chdir', '-vconsole:off',
|
||||
'--pidfile=%s' % os.path.join(self.venv, 'ovnnb_db.pid'),
|
||||
'--log-file=%s' % os.path.join(self.venv, 'ovnnb_db.log'),
|
||||
'--remote=db:OVN_Northbound,NB_Global,connections',
|
||||
'--private-key=db:OVN_Northbound,SSL,private_key',
|
||||
'--certificate=db:OVN_Northbound,SSL,certificate',
|
||||
'--ca-cert=db:OVN_Northbound,SSL,ca_cert',
|
||||
'--ssl-protocols=db:OVN_Northbound,SSL,ssl_protocols',
|
||||
'--ssl-ciphers=db:OVN_Northbound,SSL,ssl_ciphers',
|
||||
'--remote=p' + self.ovnnb_connection, 'ovnnb.db'])
|
||||
self.call(['ovsdb-server', '--detach', '--no-chdir', '-vconsole:off',
|
||||
'--pidfile=%s' % os.path.join(self.venv, 'ovnsb_db.pid'),
|
||||
'--log-file=%s' % os.path.join(self.venv, 'ovnsb_db.log'),
|
||||
'--remote=db:OVN_Southbound,SB_Global,connections',
|
||||
'--private-key=db:OVN_Southbound,SSL,private_key',
|
||||
'--certificate=db:OVN_Southbound,SSL,certificate',
|
||||
'--ca-cert=db:OVN_Southbound,SSL,ca_cert',
|
||||
'--ssl-protocols=db:OVN_Southbound,SSL,ssl_protocols',
|
||||
'--ssl-ciphers=db:OVN_Southbound,SSL,ssl_ciphers',
|
||||
'--remote=p' + self.ovnsb_connection, 'ovnsb.db'])
|
||||
for connection, schema, db_name, table in [
|
||||
(self.ovnnb_connection,
|
||||
"OVN_Northbound", "ovnnb", "NB_Global"),
|
||||
(self.ovnsb_connection,
|
||||
"OVN_Southbound", "ovnsb", "SB_Global"),
|
||||
(self.ovn_icnb_connection,
|
||||
"OVN_IC_Northbound", "ovn_ic_nb", "IC_NB_Global"),
|
||||
]:
|
||||
self.call(['ovsdb-server',
|
||||
'--detach', '--no-chdir', '-vconsole:off',
|
||||
'--pidfile=%s' % os.path.join(self.venv,
|
||||
'%s_db.pid' % (db_name)),
|
||||
'--log-file=%s' % os.path.join(self.venv,
|
||||
'%s_db.log' % (db_name)),
|
||||
'--remote=db:%s,%s,connections' % (schema, table),
|
||||
'--private-key=db:%s,SSL,private_key' % (schema),
|
||||
'--certificate=db:%s,SSL,certificate' % (schema),
|
||||
'--ca-cert=db:%s,SSL,ca_cert' % (schema),
|
||||
'--ssl-protocols=db:%s,SSL,ssl_protocols' % (schema),
|
||||
'--ssl-ciphers=db:%s,SSL,ssl_ciphers' % (schema),
|
||||
'--remote=p' + connection, '%s.db' % (db_name)])
|
||||
|
||||
def init_processes(self):
|
||||
super().init_processes()
|
||||
self.call(['ovn-nbctl', 'init'])
|
||||
self.call(['ovn-sbctl', 'init'])
|
||||
self.call(['ovn-ic-nbctl', 'init'])
|
||||
if self.add_chassis:
|
||||
self.call([
|
||||
'ovs-vsctl', 'set', 'open', '.',
|
||||
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Added support for the "OVN_IC_Northbound" schema. The ``OvnIcNbApiIdlImpl`` class provides
|
||||
interaction with "ovn_ic_nb.db" and adds support to add, delete and list registers rows of
|
||||
"Transit_Switch" table.
|
Loading…
x
Reference in New Issue
Block a user