diff options
author | Stuart Mackie <wsmackie@juniper.net> | 2017-07-25 10:37:57 -0700 |
---|---|---|
committer | Stuart Mackie <wsmackie@juniper.net> | 2017-07-25 10:37:57 -0700 |
commit | 711967ae9639095ce41500bb0e6f80c8b80fab95 (patch) | |
tree | 07f598b35664ddbd269b76f21cf587f5679cab86 /contrail-controller/hooks/contrail_controller_hooks.py | |
parent | efd4f1414b79dd51c6316a73893ade33bc9f668e (diff) |
Contrail charms
Change-Id: I2d259d03f63fce38348b8384e26ac23e3fce44a8
Signed-off-by: Stuart Mackie <wsmackie@juniper.net>
Diffstat (limited to 'contrail-controller/hooks/contrail_controller_hooks.py')
-rwxr-xr-x | contrail-controller/hooks/contrail_controller_hooks.py | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/contrail-controller/hooks/contrail_controller_hooks.py b/contrail-controller/hooks/contrail_controller_hooks.py new file mode 100755 index 0000000..4cf9db8 --- /dev/null +++ b/contrail-controller/hooks/contrail_controller_hooks.py @@ -0,0 +1,416 @@ +#!/usr/bin/env python + +import json +import sys +import uuid +import yaml + +from charmhelpers.core.hookenv import ( + Hooks, + UnregisteredHookError, + config, + log, + is_leader, + leader_get, + leader_set, + relation_get, + relation_ids, + relation_set, + relation_id, + related_units, + status_set, + remote_unit, + local_unit, + ERROR, +) + +from charmhelpers.fetch import ( + apt_install, + apt_upgrade, + apt_update +) + +from contrail_controller_utils import ( + update_charm_status, + CONTAINER_NAME, + get_analytics_list, + get_controller_ips, +) +from common_utils import ( + get_ip, + fix_hostname, + json_loads, +) +from docker_utils import ( + add_docker_repo, + DOCKER_PACKAGES, + is_container_launched, +) + +PACKAGES = [] + +hooks = Hooks() +config = config() + + +@hooks.hook("install.real") +def install(): + status_set("maintenance", "Installing...") + + # TODO: try to remove this call + fix_hostname() + + apt_upgrade(fatal=True, dist=True) + add_docker_repo() + apt_update(fatal=False) + apt_install(PACKAGES + DOCKER_PACKAGES, fatal=True) + + update_charm_status() + + +@hooks.hook("leader-elected") +def leader_elected(): + if not leader_get("db_user"): + user = "controller" + password = uuid.uuid4().hex + leader_set(db_user=user, db_password=password) + + if not leader_get("rabbitmq_user"): + user = "contrail" + password = uuid.uuid4().hex + vhost = "contrail" + leader_set(rabbitmq_user=user, + rabbitmq_password=password, + rabbitmq_vhost=vhost) + update_northbound_relations() + + ip_list = leader_get("controller_ip_list") + ips = get_controller_ips() + if not ip_list: + ip_list = ips.values() + log("IP_LIST: {} IPS: {}".format(str(ip_list), str(ips))) + leader_set(controller_ip_list=json.dumps(ip_list), + controller_ips=json.dumps(ips)) + # TODO: pass this list to all south/north relations + else: + current_ip_list = ips.values() + dead_ips = set(ip_list).difference(current_ip_list) + new_ips = set(current_ip_list).difference(ip_list) + if new_ips: + log("There are a new controllers that are not in the list: " + + str(new_ips), level=ERROR) + if dead_ips: + log("There are a dead controllers that are in the list: " + + str(dead_ips), level=ERROR) + + update_charm_status() + + +@hooks.hook("leader-settings-changed") +def leader_settings_changed(): + update_charm_status() + + +@hooks.hook("controller-cluster-relation-joined") +def cluster_joined(): + settings = {"unit-address": get_ip()} + relation_set(relation_settings=settings) + update_charm_status() + + +@hooks.hook("controller-cluster-relation-changed") +def cluster_changed(): + if not is_leader(): + return + data = relation_get() + ip = data.get("unit-address") + if not ip: + log("There is no unit-address in the relation") + return + unit = remote_unit() + _address_changed(unit, ip) + update_charm_status() + + +def _address_changed(unit, ip): + ip_list = json_loads(leader_get("controller_ip_list"), list()) + ips = json_loads(leader_get("controller_ips"), dict()) + if ip in ip_list: + return + old_ip = ips.get(unit) + if old_ip: + index = ip_list.index(old_ip) + ip_list[index] = ip + ips[unit] = ip + else: + ip_list.append(ip) + ips[unit] = ip + + log("IP_LIST: {} IPS: {}".format(str(ip_list), str(ips))) + leader_set(controller_ip_list=json.dumps(ip_list), + controller_ips=json.dumps(ips)) + + +@hooks.hook("controller-cluster-relation-departed") +def cluster_departed(): + if not is_leader(): + return + unit = remote_unit() + ips = json_loads(leader_get("controller_ips"), dict()) + if unit not in ips: + return + old_ip = ips.pop(unit) + ip_list = json_loads(leader_get("controller_ip_list"), list()) + ip_list.remove(old_ip) + + log("IP_LIST: {} IPS: {}".format(str(ip_list), str(ips))) + leader_set(controller_ip_list=json.dumps(ip_list), + controller_ips=json.dumps(ips)) + update_charm_status() + + +@hooks.hook("config-changed") +def config_changed(): + auth_mode = config.get("auth-mode") + if auth_mode not in ("rbac", "cloud-admin", "no-auth"): + raise Exception("Config is invalid. auth-mode must one of: " + "rbac, cloud-admin, no-auth.") + + if config.changed("control-network"): + ip = get_ip() + settings = {"private-address": ip} + rnames = ("contrail-controller", + "contrail-analytics", "contrail-analyticsdb", + "http-services", "https-services") + for rname in rnames: + for rid in relation_ids(rname): + relation_set(relation_id=rid, relation_settings=settings) + settings = {"unit-address": ip} + for rid in relation_ids("controller-cluster"): + relation_set(relation_id=rid, relation_settings=settings) + if is_leader(): + _address_changed(local_unit(), ip) + + update_charm_status() + + if not is_leader(): + return + + update_northbound_relations() + update_southbound_relations() + + +def update_northbound_relations(rid=None): + settings = { + "auth-mode": config.get("auth-mode"), + "auth-info": config.get("auth_info"), + "orchestrator-info": config.get("orchestrator_info"), + "ssl-ca": config.get("ssl_ca"), + "ssl-cert": config.get("ssl_cert"), + "ssl-key": config.get("ssl_key"), + "rabbitmq_user": leader_get("rabbitmq_user"), + "rabbitmq_password": leader_get("rabbitmq_password"), + "rabbitmq_vhost": leader_get("rabbitmq_vhost"), + } + + if rid: + relation_set(relation_id=rid, relation_settings=settings) + return + + for rid in relation_ids("contrail-analytics"): + relation_set(relation_id=rid, relation_settings=settings) + for rid in relation_ids("contrail-analyticsdb"): + relation_set(relation_id=rid, relation_settings=settings) + + +def update_southbound_relations(rid=None): + settings = { + "api-vip": config.get("vip"), + "analytics-server": json.dumps(get_analytics_list()), + "auth-mode": config.get("auth-mode"), + "auth-info": config.get("auth_info"), + "ssl-ca": config.get("ssl_ca"), + "orchestrator-info": config.get("orchestrator_info"), + } + for rid in ([rid] if rid else relation_ids("contrail-controller")): + relation_set(relation_id=rid, relation_settings=settings) + + +@hooks.hook("contrail-controller-relation-joined") +def contrail_controller_joined(): + settings = {"private-address": get_ip(), "port": 8082} + relation_set(relation_settings=settings) + if is_leader(): + update_southbound_relations(rid=relation_id()) + + +@hooks.hook("contrail-controller-relation-changed") +def contrail_controller_changed(): + data = relation_get() + if "orchestrator-info" in data: + config["orchestrator_info"] = data["orchestrator-info"] + # TODO: set error if orchestrator is changed and container was started + # with another orchestrator + if is_leader(): + update_southbound_relations() + update_northbound_relations() + update_charm_status() + + +@hooks.hook("contrail-controller-relation-departed") +def contrail_controller_departed(): + if not remote_unit().startswith("contrail-openstack-compute"): + return + + units = [unit for rid in relation_ids("contrail-openstack-compute") + for unit in related_units(rid)] + if units: + return + config.pop("orchestrator_info") + if is_leader(): + update_northbound_relations() + if is_container_launched(CONTAINER_NAME): + status_set( + "blocked", + "Container is present but cloud orchestrator was disappeared." + " Please kill container by yourself or restore cloud orchestrator.") + + +@hooks.hook("contrail-analytics-relation-joined") +def analytics_joined(): + settings = {"private-address": get_ip()} + relation_set(relation_settings=settings) + if is_leader(): + update_northbound_relations(rid=relation_id()) + update_southbound_relations() + update_charm_status() + + +@hooks.hook("contrail-analytics-relation-changed") +@hooks.hook("contrail-analytics-relation-departed") +def analytics_changed_departed(): + update_charm_status() + if is_leader(): + update_southbound_relations() + + +@hooks.hook("contrail-analyticsdb-relation-joined") +def analyticsdb_joined(): + settings = {"private-address": get_ip()} + relation_set(relation_settings=settings) + if is_leader(): + update_northbound_relations(rid=relation_id()) + + +@hooks.hook("contrail-auth-relation-changed") +def contrail_auth_changed(): + auth_info = relation_get("auth-info") + if auth_info is not None: + config["auth_info"] = auth_info + else: + config.pop("auth_info", None) + + if is_leader(): + update_northbound_relations() + update_southbound_relations() + update_charm_status() + + +@hooks.hook("contrail-auth-relation-departed") +def contrail_auth_departed(): + units = [unit for rid in relation_ids("contrail-auth") + for unit in related_units(rid)] + if units: + return + config.pop("auth_info", None) + + if is_leader(): + update_northbound_relations() + update_southbound_relations() + update_charm_status() + + +@hooks.hook("update-status") +def update_status(): + update_charm_status(update_config=False) + + +@hooks.hook("upgrade-charm") +def upgrade_charm(): + # NOTE: old image can not be deleted if container is running. + # TODO: so think about killing the container + + # NOTE: this hook can be fired when either resource changed or charm code + # changed. so if code was changed then we may need to update config + update_charm_status() + + +def _http_services(): + name = local_unit().replace("/", "-") + addr = get_ip() + return [ + {"service_name": "contrail-webui-http", + "service_host": "*", + "service_port": 8080, + "service_options": [ + "timeout client 86400000", + "mode http", + "balance roundrobin", + "cookie SERVERID insert indirect nocache", + "timeout server 30000", + "timeout connect 4000", + ], + "servers": [[name, addr, 8080, + "cookie " + addr + " weight 1 maxconn 1024 check port 8082"]]}, + {"service_name": "contrail-api", + "service_host": "*", + "service_port": 8082, + "service_options": [ + "timeout client 3m", + "option nolinger", + "timeout server 3m", + "balance roundrobin", + ], + "servers": [[name, addr, 8082, "check inter 2000 rise 2 fall 3"]]} + ] + + +@hooks.hook("http-services-relation-joined") +def http_services_joined(): + relation_set(services=yaml.dump(_http_services())) + + +def _https_services(): + name = local_unit().replace("/", "-") + addr = get_ip() + return [ + {"service_name": "contrail-webui-https", + "service_host": "*", + "service_port": 8143, + "service_options": [ + "timeout client 86400000", + "mode http", + "balance roundrobin", + "cookie SERVERID insert indirect nocache", + "timeout server 30000", + "timeout connect 4000", + ], + "servers": [[name, addr, 8143, + "cookie " + addr + " weight 1 maxconn 1024 check port 8082"]]}, + ] + + +@hooks.hook("https-services-relation-joined") +def https_services_joined(): + relation_set(services=yaml.dump(_https_services())) + + +def main(): + try: + hooks.execute(sys.argv) + except UnregisteredHookError as e: + log("Unknown hook {} - skipping.".format(e)) + + +if __name__ == "__main__": + main() |