charm-octavia/unit_tests/test_octavia_handlers.py
Edward Hope-Morley 6e8468a896 Fix o-hm0 port creation from action
Defer hm port setup to main charm code instead of
doing it as part of action. This means we get to
avoid the error prone action method of creating
the port.

Closes-Bug: #1902765

Change-Id: Ieab07308103c791f899ec9cb8066283540f9d96e
2020-11-05 12:06:54 +00:00

259 lines
11 KiB
Python

# Copyright 2018 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 json
import mock
import charm.openstack.octavia as octavia
import reactive.octavia_handlers as handlers
import charms_openstack.test_utils as test_utils
class TestRegisteredHooks(test_utils.TestRegisteredHooks):
def test_hooks(self):
defaults = [
'charm.installed',
'amqp.connected',
'shared-db.connected',
'identity-service.connected',
'config.changed',
'update-status',
'upgrade-charm',
'certificates.available',
]
hook_set = {
'when': {
'render': ('shared-db.available',
'identity-service.available',
'amqp.available',
'leadership.set.heartbeat-key',),
'init_db': ('config.rendered',),
'cluster_connected': ('ha.connected',),
'generate_heartbeat_key': ('leadership.is_leader',),
'setup_neutron_lbaas_proxy': (
'neutron-api.available',),
'setup_hm_port': (
'identity-service.available',
'neutron-api.available',
'sdn-subordinate.available',
'amqp.available',),
'update_controller_ip_port_list': (
'leadership.is_leader',
'identity-service.available',
'neutron-api.available',
'amqp.available',),
'setup_endpoint_connection': (
'identity-service.connected',),
'maybe_enable_ovn_driver': (
'ovsdb-subordinate.available',),
'update_nagios': (
'charm.installed',
'nrpe-external-master.available',),
'action_setup_hm_port':
('charm.octavia.action_setup_hm_port',),
},
'when_any': {
'sdn_joined': ('neutron-openvswitch.connected',
'ovsdb-subordinate.available'),
'nagios_config_changed': (
'config.changed.nagios_context',
'config.changed.nagios_servicegroups'),
},
'when_none': {
'sdn_broken': ('neutron-openvswitch.connected',
'ovsdb-subordinate.available'),
},
'when_not': {
'init_db': ('db.synced', 'is-update-status-hook'),
'cluster_connected': ('ha.available', 'is-update-status-hook'),
'generate_heartbeat_key': ('leadership.set.heartbeat-key',
'is-update-status-hook'),
'disable_ovn_driver': ('ovsdb-subordinate.available',),
'maybe_enable_ovn_driver': ('is-update-status-hook',),
'setup_endpoint_connection': ('is-update-status-hook',),
'setup_neutron_lbaas_proxy': ('is-update-status-hook',),
'setup_hm_port': ('is-update-status-hook',),
'update_controller_ip_port_list': ('is-update-status-hook',),
'render': ('is-update-status-hook',),
'update_nagios': ('octavia.nrpe.configured',
'is-update-status-hook'),
},
'hook': {
'upgrade_charm': ('upgrade-charm',),
},
}
# test that the hooks were registered via the
# reactive.octavia_handlers
self.registered_hooks_test_helper(handlers, hook_set, defaults)
class TestOctaviaHandlers(test_utils.PatchHelper):
def setUp(self):
super().setUp()
self.patch_release(octavia.RockyOctaviaCharm.release)
self.octavia_charm = mock.MagicMock()
self.patch_object(handlers.charm, 'provide_charm_instance',
new=mock.MagicMock())
self.provide_charm_instance().__enter__.return_value = \
self.octavia_charm
self.provide_charm_instance().__exit__.return_value = None
def test_setup_endpoint_connection(self):
keystone = mock.MagicMock()
handlers.setup_endpoint_connection(keystone)
keystone.register_endpoints.assert_called_once_with(
self.octavia_charm.service_type,
self.octavia_charm.region,
self.octavia_charm.public_url,
self.octavia_charm.internal_url,
self.octavia_charm.admin_url,
requested_roles=octavia.OCTAVIA_ROLES)
self.octavia_charm.assess_status.assert_called_once_with()
def test_generate_heartbeat_key(self):
self.patch('charms.leadership.leader_set', 'leader_set')
self.patch('uuid.uuid4', 'uuid4')
self.uuid4.return_value = fake_uuid4 = 'FAKE-UUID4-STRING'
handlers.generate_heartbeat_key()
self.leader_set.assert_called_once_with(
{'heartbeat-key': fake_uuid4})
self.uuid4.assert_called_once_with()
def test_neutron_lbaas_proxy(self):
self.patch('charms.reactive.endpoint_from_flag', 'endpoint_from_flag')
endpoint = mock.MagicMock()
self.endpoint_from_flag.return_value = endpoint
self.patch('charms_openstack.ip.canonical_url', 'canonical_url')
self.canonical_url.return_value = 'http://1.2.3.4'
self.octavia_charm.api_port.return_value = '1234'
handlers.setup_neutron_lbaas_proxy()
self.canonical_url.assert_called_with(endpoint_type='int')
endpoint.publish_load_balancer_info.assert_called_with(
'octavia', 'http://1.2.3.4:1234')
def test_setup_hm_port(self):
self.patch('charms.reactive.endpoint_from_flag', 'endpoint_from_flag')
self.patch('charms.reactive.set_flag', 'set_flag')
self.patch_object(handlers.api_crud, 'setup_hm_port')
handlers.setup_hm_port()
self.setup_hm_port.assert_called_with(
self.endpoint_from_flag(),
self.octavia_charm,
host_id=self.endpoint_from_flag().host())
self.set_flag.assert_called_once_with('config.changed')
self.setup_hm_port.reset_mock()
ovsdb_subordinate = mock.MagicMock()
identity_service = mock.MagicMock()
self.endpoint_from_flag.side_effect = [
None, ovsdb_subordinate, identity_service]
handlers.setup_hm_port()
self.setup_hm_port.assert_called_with(
identity_service,
self.octavia_charm,
host_id=ovsdb_subordinate.chassis_name)
def test_update_controller_ip_port_list(self):
self.patch('charms.reactive.endpoint_from_flag', 'endpoint_from_flag')
self.patch('charms.leadership.leader_set', 'leader_set')
self.patch('charms.leadership.leader_get', 'leader_get')
self.patch_object(handlers.api_crud, 'get_port_ips')
self.get_port_ips.return_value = [
'2001:db8:42::42',
'2001:db8:42::51',
]
handlers.update_controller_ip_port_list()
self.leader_set.assert_called_once_with(
{
'controller-ip-port-list': json.dumps([
'2001:db8:42::42',
'2001:db8:42::51',
])})
def test_render(self):
self.patch('charms.reactive.set_state', 'set_state')
self.patch_object(handlers.api_crud, 'create_nova_keypair')
self.patch_object(handlers.charm, 'optional_interfaces')
self.optional_interfaces.return_value = ('fake', 'interface', 'list')
handlers.render('arg1', 'arg2')
self.octavia_charm.render_with_interfaces.assert_called_once_with(
('fake', 'interface', 'list'))
self.optional_interfaces.assert_called_once_with(
('arg1', 'arg2'), 'ovsdb-subordinate.available',
'ovsdb-cms.available')
self.octavia_charm.configure_ssl.assert_called_once_with()
self.octavia_charm.enable_webserver_site.assert_called_once_with()
self.octavia_charm.assess_status.assert_called_once_with()
self.set_state.assert_called_once_with('config.rendered')
def test_init_db(self):
self.patch('charms.reactive.set_state', 'set_state')
handlers.init_db()
self.octavia_charm.db_sync.assert_called_once_with()
self.octavia_charm.restart_all.assert_called_once_with()
self.set_state.assert_called_once_with('db.synced')
self.octavia_charm.assess_status.assert_called_once_with()
def test_cluster_connected(self):
hacluster = mock.MagicMock()
handlers.cluster_connected(hacluster)
self.octavia_charm.configure_ha_resources.assert_called_once_with(
hacluster)
self.octavia_charm.assess_status.assert_called_once_with()
def test_disable_ovn_driver(self):
self.patch_object(octavia.reactive, 'clear_flag')
handlers.disable_ovn_driver()
self.clear_flag.assert_called_once_with(
'charm.octavia.enable-ovn-driver')
def test_maybe_enable_ovn_driver(self):
ovsdb = mock.MagicMock()
ovsdb.ovn_configured = True
self.patch_object(octavia.reactive, 'endpoint_from_flag')
self.endpoint_from_flag.return_value = ovsdb
self.patch_object(octavia.reactive, 'set_flag')
handlers.maybe_enable_ovn_driver()
self.endpoint_from_flag.assert_called_once_with(
'ovsdb-subordinate.available')
self.set_flag.assert_called_once_with(
'charm.octavia.enable-ovn-driver')
self.octavia_charm.install.assert_called_once_with()
self.octavia_charm.assess_status.assert_called_once_with()
def test_update_nagios(self):
self.patch_object(handlers.nrpe, 'get_nagios_unit_name',
return_value=mock.sentinel.unit_name)
nrpe_instance = mock.MagicMock()
self.patch_object(handlers.nrpe, 'NRPE', return_value=nrpe_instance)
self.patch_object(handlers.nrpe, 'add_init_service_checks')
self.patch('charms.reactive.set_state')
handlers.update_nagios()
self.add_init_service_checks.assert_called_once_with(
nrpe_instance, self.octavia_charm.full_service_list,
mock.sentinel.unit_name)
nrpe_instance.write.assert_called_once()
self.set_state.assert_called_once_with('octavia.nrpe.configured')
def test_nagios_config_changed(self):
self.patch('charms.reactive.remove_state')
handlers.nagios_config_changed()
self.remove_state.assert_any_call('octavia.nrpe.configured')
self.remove_state.assert_any_call('config.changed.nagios_context')
self.remove_state.assert_any_call(
'config.changed.nagios_servicegroups')
self.assertEqual(self.remove_state.call_count, 3)