diff options
Diffstat (limited to 'contrail-openstack/hooks/contrail_openstack_hooks.py')
-rwxr-xr-x | contrail-openstack/hooks/contrail_openstack_hooks.py | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/contrail-openstack/hooks/contrail_openstack_hooks.py b/contrail-openstack/hooks/contrail_openstack_hooks.py new file mode 100755 index 0000000..b0d7ce4 --- /dev/null +++ b/contrail-openstack/hooks/contrail_openstack_hooks.py @@ -0,0 +1,241 @@ +#!/usr/bin/env python + +import json +from subprocess import CalledProcessError, check_output +import sys +import uuid + +from charmhelpers.core.hookenv import ( + Hooks, + UnregisteredHookError, + config, + log, + related_units, + relation_get, + relation_ids, + relation_set, + status_set, + leader_get, + leader_set, + is_leader, + application_version_set, +) + +from charmhelpers.core.host import ( + restart_on_change, +) + +from charmhelpers.fetch import ( + apt_install, + apt_update, + apt_upgrade, + configure_sources +) + +from contrail_openstack_utils import ( + write_configs, + update_service_ips, +) + +NEUTRON_API_PACKAGES = ["neutron-plugin-contrail"] + + +hooks = Hooks() +config = config() + + +@hooks.hook("install.real") +def install(): + status_set('maintenance', 'Installing...') + configure_sources(True, "install-sources", "install-keys") + apt_update(fatal=True) + apt_upgrade(fatal=True, dist=False) + status_set("blocked", "Missing relation to contrail-controller") + + +@hooks.hook("config-changed") +def config_changed(): + if config.changed("install-sources") or config.changed("install-keys"): + configure_sources(True, "install-sources", "install-keys") + apt_update(fatal=True) + apt_upgrade(fatal=True, dist=False) + + if is_leader(): + _configure_metadata_shared_secret() + + +@hooks.hook("leader-elected") +def leader_elected(): + _configure_metadata_shared_secret() + _notify_clients() + + +@hooks.hook("leader-settings-changed") +def leader_settings_changed(): + _notify_clients() + + +@hooks.hook("contrail-controller-relation-joined") +def contrail_controller_joined(): + if not is_leader(): + return + + data = _get_orchestrator_info() + relation_set(**data) + + +@hooks.hook("contrail-controller-relation-changed") +@restart_on_change({"/etc/neutron/plugins/opencontrail/ContrailPlugin.ini": + ["neutron-server"]}) +def contrail_controller_changed(): + data = relation_get() + + def _update_config(key, data_key): + if data_key in data: + val = data[data_key] + if val is not None: + config[key] = val + else: + config.pop(key, None) + + _update_config("auth_info", "auth-info") + _update_config("ssl_ca", "ssl-ca") + _update_config("api_vip", "api-vip") + _update_config("api_ip", "private-address") + _update_config("api_port", "port") + config.save() + write_configs() + + status_set("active", "Unit is ready") + + # auth_info can affect endpoints + changed = update_service_ips() + if changed and is_leader(): + data = _get_orchestrator_info() + for rid in relation_ids("contrail-controller"): + relation_set(relation_id=rid, **data) + + +@hooks.hook("contrail-controller-relation-departed") +@restart_on_change({"/etc/neutron/plugins/opencontrail/ContrailPlugin.ini": + ["neutron-server"]}) +def contrail_cotroller_departed(): + units = [unit for rid in relation_ids("contrail-controller") + for unit in related_units(rid)] + if units: + return + + for key in ["auth_info", "ssl_ca", "api_vip", "api_ip", "api_port"]: + config.pop(key, None) + config.save() + write_configs() + status_set("blocked", "Missing relation to contrail-controller") + + +def _configure_metadata_shared_secret(): + secret = leader_get("metadata-shared-secret") + if config["enable-metadata-server"] and not secret: + secret = str(uuid.uuid4()) + elif not config["enable-metadata-server"] and secret: + secret = None + else: + return + + leader_set(settings={"metadata-shared-secret": secret}) + + +def _notify_clients(): + # notify clients + data = _get_orchestrator_info() + for rid in relation_ids("contrail-controller"): + relation_set(relation_id=rid, **data) + for rid in relation_ids("nova-compute"): + nova_compute_joined(rid) + + +def _get_orchestrator_info(): + info = {"cloud_orchestrator": "openstack"} + + if config["enable-metadata-server"]: + info["metadata_shared_secret"] = leader_get("metadata-shared-secret") + + def _add_to_info(key): + value = config.get(key) + if value: + info[key] = value + + _add_to_info("compute_service_ip") + _add_to_info("image_service_ip") + _add_to_info("network_service_ip") + return {"orchestrator-info": json.dumps(info)} + + +@hooks.hook("neutron-api-relation-joined") +def neutron_api_joined(): + apt_install(NEUTRON_API_PACKAGES, fatal=True) + try: + cmd = ["dpkg-query", "-f", "${Version}\\n", + "-W", "neutron-plugin-contrail"] + version = check_output(cmd).decode("UTF-8").rstrip() + application_version_set(version) + except CalledProcessError as e: + log("Couldn't detect installed application version: " + str(e)) + + # create plugin config + base = "neutron_plugin_contrail.plugins.opencontrail" + plugin = base + ".contrail_plugin.NeutronPluginContrailCoreV2" + service_plugins = base + ".loadbalancer.v2.plugin.LoadBalancerPluginV2" + extensions = [ + "/usr/lib/python2.7/dist-packages/neutron_plugin_contrail/extensions", + "/usr/lib/python2.7/dist-packages/neutron_lbaas/extensions"] + conf = { + "neutron-api": { + "/etc/neutron/neutron.conf": { + "sections": { + "DEFAULT": [ + ("api_extensions_path", ":".join(extensions)) + ] + } + } + } + } + settings = { + "neutron-plugin": "contrail", + "core-plugin": plugin, + "neutron-plugin-config": + "/etc/neutron/plugins/opencontrail/ContrailPlugin.ini", + "service-plugins": service_plugins, + "quota-driver": base + ".quota.driver.QuotaDriver", + "subordinate_configuration": json.dumps(conf)} + relation_set(relation_settings=settings) + + +@hooks.hook("nova-compute-relation-joined") +def nova_compute_joined(rel_id=None): + # create plugin config + conf = { + "nova-compute": { + "/etc/nova/nova.conf": { + "sections": { + "DEFAULT": [ + ("firewall_driver", "nova.virt.firewall.NoopFirewallDriver") + ] + } + } + } + } + settings = { + "metadata-shared-secret": leader_get("metadata-shared-secret"), + "subordinate_configuration": json.dumps(conf)} + relation_set(relation_id=rel_id, relation_settings=settings) + + +def main(): + try: + hooks.execute(sys.argv) + except UnregisteredHookError as e: + log("Unknown hook {} - skipping.".format(e)) + + +if __name__ == "__main__": + main() |