aboutsummaryrefslogtreecommitdiffstats
path: root/contrail-controller/hooks/contrail_controller_hooks.py
diff options
context:
space:
mode:
Diffstat (limited to 'contrail-controller/hooks/contrail_controller_hooks.py')
-rwxr-xr-xcontrail-controller/hooks/contrail_controller_hooks.py416
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()