[gandelman-a, r=gnuoy]

Advertise Nova API readiness

    Adds a new relation 'nova-api' that can be used by services that consume
    the nova api in some way or another. We use it to simply pass a flag to
    remote services that states whether the API service is ready to be used,
    based on the complete context of required interfaces.
This commit is contained in:
Liam Young 2016-02-22 12:03:52 +00:00
commit e394d07e66
4 changed files with 84 additions and 5 deletions

View File

@ -81,6 +81,7 @@ from nova_cc_utils import (
do_openstack_upgrade,
enable_services,
git_install,
is_api_ready,
keystone_ca_cert_b64,
migrate_neutron_database,
migrate_nova_database,
@ -299,6 +300,9 @@ def amqp_changed():
[nova_cell_relation_joined(rid=rid)
for rid in relation_ids('cell')]
for r_id in relation_ids('nova-api'):
nova_api_relation_joined(rid=r_id)
def conditional_neutron_migration():
if os_release('nova-common') <= 'icehouse':
@ -409,6 +413,9 @@ def postgresql_nova_db_changed():
CONFIGS.write_all()
leader_init_db_if_ready(skip_acl_check=True, skip_cells_restarts=True)
for r_id in relation_ids('nova-api'):
nova_api_relation_joined(rid=r_id)
@hooks.hook('pgsql-neutron-db-relation-changed')
@service_guard(guard_map(), CONFIGS,
@ -432,6 +439,9 @@ def image_service_changed():
CONFIGS.write(NOVA_CONF)
# TODO: special case config flag for essex (strip protocol)
for r_id in relation_ids('nova-api'):
nova_api_relation_joined(rid=r_id)
@hooks.hook('identity-service-relation-joined')
def identity_joined(rid=None):
@ -466,6 +476,9 @@ def identity_changed():
[neutron_api_relation_joined(rid) for rid in relation_ids('neutron-api')]
configure_https()
for r_id in relation_ids('nova-api'):
nova_api_relation_joined(rid=r_id)
@hooks.hook('nova-volume-service-relation-joined',
'cinder-volume-service-relation-joined')
@ -624,6 +637,9 @@ def compute_joined(rid=None, remote_restart=False):
@hooks.hook('cloud-compute-relation-changed')
def compute_changed(rid=None, unit=None):
for r_id in relation_ids('nova-api'):
nova_api_relation_joined(rid=r_id)
rel_settings = relation_get(rid=rid, unit=unit)
if not rel_settings.get('region', None) == config('region'):
relation_set(relation_id=rid, region=config('region'))
@ -1099,6 +1115,13 @@ def update_nova_consoleauth_config():
log(str(e), level='DEBUG')
def nova_api_relation_joined(rid=None):
rel_data = {
'nova-api-ready': 'yes' if is_api_ready(CONFIGS) else 'no'
}
relation_set(rid, **rel_data)
def main():
try:
hooks.execute(sys.argv)

View File

@ -35,6 +35,7 @@ from charmhelpers.contrib.openstack.utils import (
git_src_dir,
git_pip_venv_dir,
git_yaml_value,
incomplete_relation_data,
is_ip,
os_release,
save_script_rc as _save_script_rc,
@ -1399,3 +1400,7 @@ def check_optional_relations(configs):
return status_get()
else:
return 'unknown', 'No optional relations'
def is_api_ready(configs):
return (not incomplete_relation_data(configs, REQUIRED_INTERFACES))

View File

@ -218,6 +218,12 @@ class NovaCCHooksTests(CharmTestCase):
hooks.config_changed()
mock_compute_changed.assert_has_calls([call('generic_rid', 'unit/0')])
@patch.object(hooks, 'nova_api_relation_joined')
def test_compute_changed_nova_api_trigger(self, api_joined):
self.relation_ids.return_value = ['nova-api/0']
hooks.compute_changed()
api_joined.assert_called_with(rid='nova-api/0')
def test_compute_changed_ssh_migration(self):
self.test_relation.set({
'migration_auth_type': 'ssh', 'ssh_public_key': 'fookey',
@ -457,17 +463,20 @@ class NovaCCHooksTests(CharmTestCase):
configs.write = MagicMock()
hooks.postgresql_nova_db_changed()
@patch.object(hooks, 'nova_api_relation_joined')
@patch.object(hooks, 'is_db_initialised')
@patch.object(hooks, 'conditional_neutron_migration')
@patch.object(hooks, 'CONFIGS')
def test_db_changed(self, configs, cond_neutron_mig,
mock_is_db_initialised):
mock_is_db_initialised, api_joined):
self.relation_ids.return_value = ['nova-api/0']
mock_is_db_initialised.return_value = False
'No database migration is attempted when ACL list is not present'
self._shared_db_test(configs)
self.assertTrue(configs.write_all.called)
self.assertFalse(self.migrate_nova_database.called)
self.assertFalse(cond_neutron_mig.called)
api_joined.asert_called_with(rid='nova-api/0')
@patch.object(hooks, 'is_db_initialised')
@patch.object(hooks, 'CONFIGS')
@ -495,13 +504,19 @@ class NovaCCHooksTests(CharmTestCase):
self.assertTrue(configs.write_all.called)
self.assertFalse(self.migrate_nova_database.called)
@patch.object(hooks, 'nova_api_relation_joined')
@patch.object(hooks, 'is_db_initialised')
@patch.object(hooks, 'CONFIGS')
def test_postgresql_db_changed(self, configs, mock_is_db_initialised):
def test_postgresql_db_changed(self, configs, mock_is_db_initialised,
api_joined):
self.relation_ids.side_effect = [
[],
['nova-api/0']]
mock_is_db_initialised.return_value = False
self._postgresql_db_test(configs)
self.assertTrue(configs.write_all.called)
self.migrate_nova_database.assert_called_with()
api_joined.assert_called_with(rid='nova-api/0')
@patch.object(hooks, 'is_db_initialised')
@patch.object(hooks, 'nova_cell_relation_joined')
@ -540,9 +555,11 @@ class NovaCCHooksTests(CharmTestCase):
self.assertTrue(configs.write_all.called)
cell_joined.assert_called_with(rid='nova-cell-api/0')
@patch.object(hooks, 'nova_api_relation_joined')
@patch.object(hooks, 'nova_cell_relation_joined')
@patch.object(hooks, 'CONFIGS')
def test_amqp_changed_api_rel(self, configs, cell_joined):
def test_amqp_changed_api_rel(self, configs, cell_joined, api_joined):
self.relation_ids.return_value = ['nova-api/0']
configs.complete_contexts = MagicMock()
configs.complete_contexts.return_value = ['amqp']
configs.write = MagicMock()
@ -550,14 +567,19 @@ class NovaCCHooksTests(CharmTestCase):
hooks.amqp_changed()
self.assertEquals(configs.write.call_args_list,
[call('/etc/nova/nova.conf')])
api_joined.assert_called_with(rid='nova-api/0')
@patch.object(hooks, 'nova_api_relation_joined')
@patch.object(hooks, 'nova_cell_relation_joined')
@patch.object(hooks, 'CONFIGS')
def test_amqp_changed_noapi_rel(self, configs, cell_joined):
def test_amqp_changed_noapi_rel(self, configs, cell_joined, api_joined):
configs.complete_contexts = MagicMock()
configs.complete_contexts.return_value = ['amqp']
configs.write = MagicMock()
self.relation_ids.return_value = ['nova-cell-api/0']
self.relation_ids.side_effect = [
['nova-cell-api/0'],
['nova-api/0'],
]
self.is_relation_made.return_value = False
self.network_manager.return_value = 'neutron'
hooks.amqp_changed()
@ -565,6 +587,7 @@ class NovaCCHooksTests(CharmTestCase):
[call('/etc/nova/nova.conf'),
call('/etc/neutron/neutron.conf')])
cell_joined.assert_called_with(rid='nova-cell-api/0')
api_joined.assert_called_with(rid='nova-api/0')
@patch.object(hooks, 'canonical_url')
def test_nova_cell_relation_joined(self, _canonical_url):
@ -903,3 +926,17 @@ class NovaCCHooksTests(CharmTestCase):
])
mock_filter_packages.assert_called_with([])
@patch.object(hooks, 'is_api_ready')
def _test_nova_api_relation_joined(self, tgt, is_api_ready):
is_api_ready.return_value = tgt
exp = 'yes' if tgt else 'no'
hooks.nova_api_relation_joined(rid='foo')
self.relation_set.assert_called_with(
'foo', **{'nova-api-ready': exp})
def test_nova_api_relation_joined_ready(self):
self._test_nova_api_relation_joined(True)
def test_nova_api_relation_joined_not_ready(self):
self._test_nova_api_relation_joined(False)

View File

@ -1153,3 +1153,17 @@ class NovaCCUtilsTests(CharmTestCase):
self.assertTrue(self.apt_update.called)
self.apt_install.assert_called_with(['novnc', 'spice-html5',
'websockify'], fatal=True)
def _test_is_api_ready(self, tgt):
fake_config = MagicMock()
with patch.object(utils, 'incomplete_relation_data') as ird:
ird.return_value = (not tgt)
self.assertEqual(utils.is_api_ready(fake_config), tgt)
ird.assert_called_with(
fake_config, utils.REQUIRED_INTERFACES)
def test_is_api_ready_true(self):
self._test_is_api_ready(True)
def test_is_api_ready_false(self):
self._test_is_api_ready(False)