Advertise API readiness to subordinates, allow subordinate specification of api_extensions

This advertises API readiness to subordinates via a new flag int the subordinate
relation. It determines readiness by the completion of required contexts. This
simply means the API service has enough of its topology completed to begin
servicing requests, and it has at least *started* the service (from the POV of
the init system). Its up to the subordinate service to ensure the API is
functional.

It also allows subordinates to specify custom api_extension_paths to neutron-api.
This commit is contained in:
Adam Gandelman 2016-02-03 11:17:14 -08:00
parent f80df9d8e1
commit 86f6174d5f
8 changed files with 98 additions and 12 deletions

View File

@ -96,7 +96,7 @@ The following is a full list of current tip repos (may not be up-to-date):
repository: 'git://github.com/openstack/python-neutronclient',
branch: master}
- {name: python-novaclient,
repository': 'git://github.com/openstack/python-novaclient',
repository: 'git://github.com/openstack/python-novaclient',
branch: master}
- {name: keystonemiddleware,
repository: 'git://github.com/openstack/keystonemiddleware',

View File

@ -318,6 +318,10 @@ class NeutronApiSDNContext(context.SubordinateConfigContext):
'templ_key': 'quota_driver',
'value': '',
},
'api-extensions-path': {
'templ_key': 'api_extensions_path',
'value': '',
},
}
for rid in relation_ids('neutron-plugin-api-subordinate'):
for unit in related_units(rid):

View File

@ -58,6 +58,7 @@ from neutron_api_utils import (
determine_ports,
do_openstack_upgrade,
git_install,
is_api_ready,
dvr_router_present,
l3ha_router_present,
migrate_neutron_database,
@ -295,6 +296,9 @@ def amqp_changed():
return
CONFIGS.write(NEUTRON_CONF)
for r_id in relation_ids('neutron-plugin-api-subordinate'):
neutron_plugin_api_subordinate_relation_joined(relid=r_id)
@hooks.hook('shared-db-relation-joined')
def db_joined():
@ -336,6 +340,9 @@ def db_changed():
CONFIGS.write_all()
conditional_neutron_migration()
for r_id in relation_ids('neutron-plugin-api-subordinate'):
neutron_plugin_api_subordinate_relation_joined(relid=r_id)
@hooks.hook('pgsql-db-relation-changed')
@restart_on_change(restart_map())
@ -343,6 +350,9 @@ def postgresql_neutron_db_changed():
CONFIGS.write(NEUTRON_CONF)
conditional_neutron_migration()
for r_id in relation_ids('neutron-plugin-api-subordinate'):
neutron_plugin_api_subordinate_relation_joined(relid=r_id)
@hooks.hook('amqp-relation-broken',
'identity-service-relation-broken',
@ -387,8 +397,8 @@ def identity_changed():
CONFIGS.write(NEUTRON_CONF)
for r_id in relation_ids('neutron-api'):
neutron_api_relation_joined(rid=r_id)
for r_id in relation_ids('neutron-plugin-api'):
neutron_plugin_api_relation_joined(rid=r_id)
for r_id in relation_ids('neutron-plugin-api-subordinate'):
neutron_plugin_api_subordinate_relation_joined(relid=r_id)
configure_https()
@ -404,6 +414,12 @@ def neutron_api_relation_joined(rid=None):
relation_data['neutron-security-groups'] = "yes"
else:
relation_data['neutron-security-groups'] = "no"
if is_api_ready(CONFIGS):
relation_data['neutron-api-ready'] = "yes"
else:
relation_data['neutron-api-ready'] = "no"
relation_set(relation_id=rid, **relation_data)
# Nova-cc may have grabbed the neutron endpoint so kick identity-service
# relation to register that its here
@ -461,6 +477,11 @@ def neutron_plugin_api_relation_joined(rid=None):
'region': config('region'),
})
if is_api_ready(CONFIGS):
relation_data['neutron-api-ready'] = "yes"
else:
relation_data['neutron-api-ready'] = "no"
relation_set(relation_id=rid, **relation_data)
@ -563,6 +584,14 @@ def zeromq_configuration_relation_joined(relid=None):
users="neutron")
@hooks.hook('neutron-plugin-api-subordinate-relation-joined')
def neutron_plugin_api_subordinate_relation_joined(relid=None):
relation_data = {'neutron-api-ready': 'no'}
if is_api_ready(CONFIGS):
relation_data['neutron-api-ready'] = "yes"
relation_set(relation_id=relid, **relation_data)
@hooks.hook('zeromq-configuration-relation-changed',
'neutron-plugin-api-subordinate-relation-changed')
@restart_on_change(restart_map(), stopstart=True)
@ -580,6 +609,7 @@ def update_nrpe_config():
nrpe_setup = nrpe.NRPE(hostname=hostname)
nrpe.copy_nrpe_checks()
nrpe.add_init_service_checks(nrpe_setup, services(), current_unit)
nrpe.add_haproxy_checks(nrpe_setup, current_unit)
nrpe_setup.write()

View File

@ -20,6 +20,7 @@ from charmhelpers.contrib.openstack.utils import (
git_pip_venv_dir,
git_yaml_value,
configure_installation_source,
incomplete_relation_data,
set_os_workload_status,
)
@ -283,7 +284,8 @@ def determine_packages(source=None):
# don't include packages that will be installed from git
packages = list(set(packages))
for p in GIT_PACKAGE_BLACKLIST:
packages.remove(p)
if p in packages:
packages.remove(p)
if get_os_codename_install_source(source) >= 'kilo':
for p in GIT_PACKAGE_BLACKLIST_KILO:
packages.remove(p)
@ -654,3 +656,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

@ -29,6 +29,10 @@ bind_port = {{ neutron_bind_port }}
bind_port = 9696
{% endif -%}
{% if api_extensions_path -%}
api_extensions_path = {{ api_extensions_path }}
{% endif -%}
{% if core_plugin -%}
core_plugin = {{ core_plugin }}
{% if service_plugins -%}
@ -68,6 +72,7 @@ nova_admin_password = {{ admin_password }}
nova_admin_auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/v2.0
{% endif -%}
{% if sections and 'DEFAULT' in sections -%}
{% for key, value in sections['DEFAULT'] -%}
{{ key }} = {{ value }}

View File

@ -562,6 +562,7 @@ class NeutronApiSDNContextTest(CharmTestCase):
self.ctxt_check(
{'neutron-plugin': 'ovs'},
{
'api_extensions_path': '',
'core_plugin': 'neutron.plugins.ml2.plugin.Ml2Plugin',
'neutron_plugin_config': ('/etc/neutron/plugins/ml2/'
'ml2_conf.ini'),
@ -577,6 +578,7 @@ class NeutronApiSDNContextTest(CharmTestCase):
self.ctxt_check(
{
'neutron-plugin': 'ovs',
'api-extensions-path': '/usr/local/share/neutron/extensions',
'core-plugin': 'neutron.plugins.ml2.plugin.MidoPlumODL',
'neutron-plugin-config': '/etc/neutron/plugins/fl/flump.ini',
'service-plugins': 'router,unicorn,rainbows',
@ -584,6 +586,7 @@ class NeutronApiSDNContextTest(CharmTestCase):
'quota-driver': 'quotadriver',
},
{
'api_extensions_path': '/usr/local/share/neutron/extensions',
'core_plugin': 'neutron.plugins.ml2.plugin.MidoPlumODL',
'neutron_plugin_config': '/etc/neutron/plugins/fl/flump.ini',
'service_plugins': 'router,unicorn,rainbows',
@ -612,6 +615,7 @@ class NeutronApiSDNContextTest(CharmTestCase):
'subordinate_configuration': json.dumps(principle_config),
},
{
'api_extensions_path': '',
'core_plugin': 'neutron.plugins.ml2.plugin.Ml2Plugin',
'neutron_plugin_config': ('/etc/neutron/plugins/ml2/'
'ml2_conf.ini'),

View File

@ -304,10 +304,15 @@ class NeutronAPIHooksTests(CharmTestCase):
relation_id=None
)
def test_amqp_changed(self):
@patch.object(hooks, 'neutron_plugin_api_subordinate_relation_joined')
def test_amqp_changed(self, plugin_joined):
self.relation_ids.return_value = ['neutron-plugin-api-subordinate:1']
self.CONFIGS.complete_contexts.return_value = ['amqp']
self._call_hook('amqp-relation-changed')
self.assertTrue(self.CONFIGS.write.called_with(NEUTRON_CONF))
self.relation_ids.assert_called_with('neutron-plugin-api-subordinate')
plugin_joined.assert_called_with(
relid='neutron-plugin-api-subordinate:1')
def test_amqp_departed(self):
self._call_hook('amqp-relation-departed')
@ -349,23 +354,33 @@ class NeutronAPIHooksTests(CharmTestCase):
'Attempting to associate a postgresql database when'
' there is already associated a mysql one')
@patch.object(hooks, 'neutron_plugin_api_subordinate_relation_joined')
@patch.object(hooks, 'conditional_neutron_migration')
def test_shared_db_changed(self, cond_neutron_mig):
def test_shared_db_changed(self, cond_neutron_mig, plugin_joined):
self.CONFIGS.complete_contexts.return_value = ['shared-db']
self.relation_ids.return_value = ['neutron-plugin-api-subordinate:1']
self._call_hook('shared-db-relation-changed')
self.assertTrue(self.CONFIGS.write_all.called)
cond_neutron_mig.assert_called_with()
self.relation_ids.assert_called_with('neutron-plugin-api-subordinate')
plugin_joined.assert_called_with(
relid='neutron-plugin-api-subordinate:1')
def test_shared_db_changed_partial_ctxt(self):
self.CONFIGS.complete_contexts.return_value = []
self._call_hook('shared-db-relation-changed')
self.assertFalse(self.CONFIGS.write_all.called)
@patch.object(hooks, 'neutron_plugin_api_subordinate_relation_joined')
@patch.object(hooks, 'conditional_neutron_migration')
def test_pgsql_db_changed(self, cond_neutron_mig):
def test_pgsql_db_changed(self, cond_neutron_mig, plugin_joined):
self.relation_ids.return_value = ['neutron-plugin-api-subordinate:1']
self._call_hook('pgsql-db-relation-changed')
self.assertTrue(self.CONFIGS.write.called)
cond_neutron_mig.assert_called_with()
self.relation_ids.assert_called_with('neutron-plugin-api-subordinate')
plugin_joined.assert_called_with(
relid='neutron-plugin-api-subordinate:1')
def test_amqp_broken(self):
self._call_hook('amqp-relation-broken')
@ -458,6 +473,7 @@ class NeutronAPIHooksTests(CharmTestCase):
'neutron-plugin': 'ovs',
'neutron-url': neutron_url,
'neutron-security-groups': 'no',
'neutron-api-ready': 'no',
}
self._call_hook('neutron-api-relation-joined')
self.relation_set.assert_called_with(
@ -473,8 +489,10 @@ class NeutronAPIHooksTests(CharmTestCase):
**_relation_data
)
@patch.object(hooks, 'is_api_ready')
@patch.object(hooks, 'canonical_url')
def test_neutron_api_relation_joined(self, _canonical_url):
def test_neutron_api_relation_joined(self, _canonical_url, api_ready):
api_ready.return_value = True
host = 'http://127.0.0.1'
port = 1234
_canonical_url.return_value = host
@ -485,6 +503,7 @@ class NeutronAPIHooksTests(CharmTestCase):
'neutron-plugin': 'ovs',
'neutron-url': neutron_url,
'neutron-security-groups': 'no',
'neutron-api-ready': 'yes',
}
self._call_hook('neutron-api-relation-joined')
self.relation_set.assert_called_with(
@ -532,7 +551,8 @@ class NeutronAPIHooksTests(CharmTestCase):
'auth_port': None,
'auth_host': None,
'service_username': None,
'service_host': None
'service_host': None,
'neutron-api-ready': 'no',
}
self.get_dvr.return_value = False
self.get_l3ha.return_value = False
@ -564,7 +584,8 @@ class NeutronAPIHooksTests(CharmTestCase):
'auth_port': None,
'auth_host': None,
'service_username': None,
'service_host': None
'service_host': None,
'neutron-api-ready': 'no',
}
self.get_dvr.return_value = True
self.get_l3ha.return_value = False
@ -596,7 +617,8 @@ class NeutronAPIHooksTests(CharmTestCase):
'auth_port': None,
'auth_host': None,
'service_username': None,
'service_host': None
'service_host': None,
'neutron-api-ready': 'no',
}
self.get_dvr.return_value = False
self.get_l3ha.return_value = True
@ -630,7 +652,8 @@ class NeutronAPIHooksTests(CharmTestCase):
'auth_port': None,
'auth_host': None,
'service_username': None,
'service_host': None
'service_host': None,
'neutron-api-ready': 'no',
}
self.get_dvr.return_value = True
self.get_l3ha.return_value = True

View File

@ -624,3 +624,17 @@ class TestNeutronAPIUtils(CharmTestCase):
rmtree.assert_any_call('/var/lib/etcd/one')
rmtree.assert_any_call('/var/lib/etcd/two')
self.service_start.assert_called_once_with('etcd')
def _test_is_api_ready(self, tgt):
fake_config = MagicMock()
with patch.object(nutils, 'incomplete_relation_data') as ird:
ird.return_value = (not tgt)
self.assertEqual(nutils.is_api_ready(fake_config), tgt)
ird.assert_called_with(
fake_config, nutils.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)