Files
charm-ovn-chassis/unit_tests/test_lib_charm_openstack_ovn_chassis.py
Frode Nordahl 3253c42659 Clean up optional OpenStack metadata enablement
Use the ``networking-ovn-metadata-agent`` package

Use flags for tracking OpenStack metadata enablement.  The initial
version used the c-h kv interface directly for reasons that astounds
the author.

Change-Id: I51a03651e1931b4194b09b43acfb873d0cc896f6
2019-11-08 17:44:50 +01:00

204 lines
8.0 KiB
Python

# Copyright 2019 Canonical Ltd
#
# 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 io
import mock
import os
import charms_openstack.test_utils as test_utils
import charm.openstack.ovn_chassis as ovn_chassis
class TestOVNConfigProperties(test_utils.PatchHelper):
def test_ovn_key(self):
self.assertEquals(ovn_chassis.ovn_key(None),
os.path.join(ovn_chassis.OVS_ETCDIR, 'key_host'))
def test_ovn_cert(self):
self.assertEquals(ovn_chassis.ovn_cert(None),
os.path.join(ovn_chassis.OVS_ETCDIR, 'cert_host'))
def test_ovn_ca_cert(self):
cls = mock.MagicMock()
cls.charm_instance.name = mock.PropertyMock().return_value = 'name'
self.assertEquals(ovn_chassis.ovn_ca_cert(cls),
os.path.join(ovn_chassis.OVS_ETCDIR, 'name.crt'))
class Helper(test_utils.PatchHelper):
def setUp(self):
super().setUp()
self.patch_release(ovn_chassis.OVNChassisCharm.release)
self.patch_object(ovn_chassis.reactive, 'is_flag_set',
return_value=False)
self.target = ovn_chassis.OVNChassisCharm()
# remove the 'is_flag_set' patch so the tests can use it
self._patches['is_flag_set'].stop()
setattr(self, 'is_flag_set', None)
del(self._patches['is_flag_set'])
del(self._patches_start['is_flag_set'])
def patch_target(self, attr, return_value=None):
mocked = mock.patch.object(self.target, attr)
self._patches[attr] = mocked
started = mocked.start()
started.return_value = return_value
self._patches_start[attr] = started
setattr(self, attr, started)
class TestOVNChassisCharm(Helper):
def test_optional_openstack_metadata(self):
self.assertEquals(self.target.packages, ['ovn-host'])
self.assertEquals(self.target.services, ['ovn-host'])
self.patch_object(ovn_chassis.reactive, 'is_flag_set',
return_value=True)
c = ovn_chassis.OVNChassisCharm()
self.assertEquals(c.packages, [
'ovn-host', 'networking-ovn-metadata-agent', 'haproxy'
])
self.assertEquals(c.services, [
'ovn-host', 'networking-ovn-metadata-agent'])
def test_run(self):
self.patch_object(ovn_chassis.subprocess, 'run')
self.patch_object(ovn_chassis.ch_core.hookenv, 'log')
self.target.run('some', 'args')
self.run.assert_called_once_with(
('some', 'args'),
stdout=ovn_chassis.subprocess.PIPE,
stderr=ovn_chassis.subprocess.STDOUT,
check=True,
universal_newlines=True)
def test_configure_tls(self):
self.patch_target('get_certs_and_keys')
self.get_certs_and_keys.return_value = [{
'cert': 'fakecert',
'key': 'fakekey',
'cn': 'fakecn',
'ca': 'fakeca',
'chain': 'fakechain',
}]
with mock.patch('builtins.open', create=True) as mocked_open:
mocked_file = mock.MagicMock(spec=io.FileIO)
mocked_open.return_value = mocked_file
self.target.configure_cert = mock.MagicMock()
self.target.run = mock.MagicMock()
self.target.configure_tls()
mocked_open.assert_called_once_with(
'/etc/openvswitch/ovn-chassis.crt', 'w')
mocked_file.__enter__().write.assert_called_once_with(
'fakeca\nfakechain')
self.target.configure_cert.assert_called_once_with(
ovn_chassis.OVS_ETCDIR,
'fakecert',
'fakekey',
cn='host')
def test_configure_ovs(self):
self.patch_target('run')
self.patch_target('restart_all')
self.patch_object(ovn_chassis, 'ovn_key')
self.patch_object(ovn_chassis, 'ovn_cert')
self.patch_object(ovn_chassis, 'ovn_ca_cert')
ovsdb_interface = mock.MagicMock()
db_sb_connection_strs = mock.PropertyMock().return_value = ['dbsbconn']
ovsdb_interface.db_sb_connection_strs = db_sb_connection_strs
cluster_local_addr = mock.PropertyMock().return_value = (
'cluster_local_addr')
ovsdb_interface.cluster_local_addr = cluster_local_addr
self.target.configure_ovs(ovsdb_interface)
self.run.assert_has_calls([
mock.call('ovs-vsctl', 'set-ssl', mock.ANY, mock.ANY, mock.ANY),
mock.call('ovs-vsctl', 'set', 'open', '.',
'external-ids:ovn-encap-type=geneve', '--',
'set', 'open', '.',
'external-ids:ovn-encap-ip=cluster_local_addr', '--',
'set', 'open', '.',
'external-ids:system-id=cluster_local_addr'),
mock.call('ovs-vsctl', 'set', 'open', '.',
'external-ids:ovn-remote=dbsbconn'),
])
def test_configure_bridges(self):
self.patch_object(ovn_chassis.os_context, 'NeutronPortContext')
npc = mock.MagicMock()
def _fake_resolve_ports(mac_or_if):
result = []
for entry in mac_or_if:
if ':' in entry:
result.append('eth0')
continue
result.append(entry)
return result
npc.resolve_ports.side_effect = _fake_resolve_ports
self.NeutronPortContext.return_value = npc
self.patch_target('config')
self.config.__getitem__.side_effect = [
'00:01:02:03:04:05:br-provider eth5:br-other',
'provider:br-provider other:br-other']
self.patch_object(ovn_chassis.ovsdb, 'SimpleOVSDB')
bridges = mock.MagicMock()
bridges.find.side_effect = [
[
{'name': 'delete-bridge'},
{'name': 'br-other'}
],
StopIteration,
]
ports = mock.MagicMock()
ports.find.side_effect = [[{'name': 'delete-port'}]]
opvs = mock.MagicMock()
self.SimpleOVSDB.side_effect = [bridges, ports, opvs]
self.patch_object(ovn_chassis.ovsdb, 'del_br')
self.patch_object(ovn_chassis.ovsdb, 'del_port')
self.patch_object(ovn_chassis.ovsdb, 'add_br')
self.patch_object(ovn_chassis.ovsdb, 'list_ports')
self.list_ports().__iter__.return_value = []
self.patch_object(ovn_chassis.ovsdb, 'add_port')
self.target.configure_bridges()
npc.resolve_ports.assert_has_calls([
mock.call(['00:01:02:03:04:05']),
mock.call(['eth5']),
], any_order=True)
bridges.find.assert_has_calls([
mock.call('name=br-provider'),
mock.call('name=br-other'),
], any_order=True)
self.del_br.assert_called_once_with('delete-bridge')
self.del_port.assert_called_once_with('br-other', 'delete-port')
self.add_br.assert_has_calls([
mock.call('br-provider', ('charm-ovn-chassis', 'managed')),
mock.call('br-other', ('charm-ovn-chassis', 'managed')),
], any_order=True)
self.add_port.assert_has_calls([
mock.call(
'br-provider', 'eth0', ('charm-ovn-chassis', 'br-provider')),
mock.call(
'br-other', 'eth5', ('charm-ovn-chassis', 'br-other')),
], any_order=True)
opvs.set.assert_has_calls([
mock.call('.', 'external_ids:ovn-bridge-mappings',
'other:br-other,provider:br-provider'),
mock.call('.', 'external_ids:ovn-cms-options',
'enable-chassis-as-gw'),
])