From 4faa7f927149a5c4ef7a03523f7bc14523cb9baa Mon Sep 17 00:00:00 2001 From: Stuart Mackie Date: Fri, 7 Oct 2016 12:24:58 -0700 Subject: Charms for Contrail 3.1 with Mitaka Change-Id: Id37f3b9743d1974e31fcd7cd9c54be41bb0c47fb Signed-off-by: Stuart Mackie --- .../hooks/contrail_control_utils.py | 249 +++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 charms/trusty/contrail-control/hooks/contrail_control_utils.py (limited to 'charms/trusty/contrail-control/hooks/contrail_control_utils.py') diff --git a/charms/trusty/contrail-control/hooks/contrail_control_utils.py b/charms/trusty/contrail-control/hooks/contrail_control_utils.py new file mode 100644 index 0000000..fad2d11 --- /dev/null +++ b/charms/trusty/contrail-control/hooks/contrail_control_utils.py @@ -0,0 +1,249 @@ +import functools +import os +import pwd +import shutil +from socket import gethostbyname, gethostname +from subprocess import ( + CalledProcessError, + check_call, + check_output +) +from time import sleep, time + +import apt_pkg +from apt_pkg import version_compare +import json + +from charmhelpers.core.hookenv import ( + local_unit, + log, + related_units, + relation_get, + relation_ids, + relation_type, + remote_unit, + unit_get +) +from charmhelpers.core.host import service_restart +from charmhelpers.core.templating import render + +apt_pkg.init() + +def dpkg_version(pkg): + try: + return check_output(["dpkg-query", "-f", "${Version}\\n", "-W", pkg]).rstrip() + except CalledProcessError: + return None + +CONTRAIL_VERSION = dpkg_version("contrail-control") + +def retry(f=None, timeout=10, delay=2): + """Retry decorator. + + Provides a decorator that can be used to retry a function if it raises + an exception. + + :param timeout: timeout in seconds (default 10) + :param delay: retry delay in seconds (default 2) + + Examples:: + + # retry fetch_url function + @retry + def fetch_url(): + # fetch url + + # retry fetch_url function for 60 secs + @retry(timeout=60) + def fetch_url(): + # fetch url + """ + if not f: + return functools.partial(retry, timeout=timeout, delay=delay) + @functools.wraps(f) + def func(*args, **kwargs): + start = time() + error = None + while True: + try: + return f(*args, **kwargs) + except Exception as e: + error = e + elapsed = time() - start + if elapsed >= timeout: + raise error + remaining = timeout - elapsed + if delay <= remaining: + sleep(delay) + else: + sleep(remaining) + raise error + return func + +def contrail_api_ctx(): + ctxs = [ { "api_server": gethostbyname(relation_get("private-address", unit, rid)), + "api_port": port } + for rid in relation_ids("contrail-api") + for unit, port in + ((unit, relation_get("port", unit, rid)) for unit in related_units(rid)) + if port ] + return ctxs[0] if ctxs else {} + +def contrail_ctx(): + return { "host_ip": gethostbyname(unit_get("private-address")) } + +def contrail_discovery_ctx(): + ctxs = [ { "discovery_server": vip if vip \ + else gethostbyname(relation_get("private-address", unit, rid)), + "discovery_port": port } + for rid in relation_ids("contrail-discovery") + for unit, port, vip in + ((unit, relation_get("port", unit, rid), relation_get("vip", unit, rid)) + for unit in related_units(rid)) + if port ] + return ctxs[0] if ctxs else {} + +def contrail_ifmap_ctx(): + ctxs = [] + unit = local_unit() + for rid in relation_ids("contrail-ifmap"): + for u in related_units(rid): + creds = relation_get("creds", u, rid) + if creds: + creds = json.loads(creds) + if unit in creds: + cs = creds[unit] + ctx = {} + ctx["ifmap_user"] = cs["username"] + ctx["ifmap_password"] = cs["password"] + ctxs.append(ctx) + return ctxs[0] if ctxs else {} + +@retry(timeout=300) +def contrail_provision_control(hostname, ip, router_asn, api_ip, api_port, op, + user, password, tenant): + check_call(["contrail-provision-control", + "--host_name", hostname, + "--host_ip", ip, + "--router_asn", str(router_asn), + "--api_server_ip", api_ip, + "--api_server_port", str(api_port), + "--oper", op, + "--admin_user", user, + "--admin_password", password, + "--admin_tenant_name", tenant]) + +def fix_nodemgr(): + # add files missing from contrail-nodemgr package + shutil.copy("files/contrail-nodemgr-control.ini", + "/etc/contrail/supervisord_control_files") + pw = pwd.getpwnam("contrail") + os.chown("/etc/contrail/supervisord_control_files/contrail-nodemgr-control.ini", + pw.pw_uid, pw.pw_gid) + shutil.copy("files/contrail-control-nodemgr", "/etc/init.d") + os.chmod("/etc/init.d/contrail-control-nodemgr", 0755) + + # fake ntp status when inside a container + if is_container(): + shutil.copy("files/ntpq-nodemgr", "/usr/local/bin/ntpq") + + service_restart("supervisor-control") + +def fix_permissions(): + os.chmod("/etc/contrail", 0755) + os.chown("/etc/contrail", 0, 0) + +def identity_admin_ctx(): + ctxs = [ { "auth_host": gethostbyname(hostname), + "auth_port": relation_get("service_port", unit, rid) } + for rid in relation_ids("identity-admin") + for unit, hostname in + ((unit, relation_get("service_hostname", unit, rid)) for unit in related_units(rid)) + if hostname ] + return ctxs[0] if ctxs else {} + +def is_container(): + """Return boolean determining if inside container""" + try: + check_call(["running-in-container"]) + return True + except CalledProcessError: + return False + +def provision_control(): + hostname = gethostname() + ip = gethostbyname(unit_get("private-address")) + api_ip, api_port = [ (gethostbyname(relation_get("private-address", unit, rid)), + port) + for rid in relation_ids("contrail-api") + for unit, port in + ((unit, relation_get("port", unit, rid)) for unit in related_units(rid)) + if port ][0] + user, password, tenant = [ (relation_get("service_username", unit, rid), + relation_get("service_password", unit, rid), + relation_get("service_tenant_name", unit, rid)) + for rid in relation_ids("identity-admin") + for unit in related_units(rid) + if relation_get("service_hostname", unit, rid) ][0] + log("Provisioning control {}".format(ip)) + contrail_provision_control(hostname, ip, 64512, api_ip, api_port, "add", + user, password, tenant) + +def units(relation): + """Return a list of units for the specified relation""" + return [ unit for rid in relation_ids(relation) + for unit in related_units(rid) ] + +def unprovision_control(): + if not remote_unit(): + return + hostname = gethostname() + ip = gethostbyname(unit_get("private-address")) + relation = relation_type() + api_ip = None + api_port = None + if relation == "contrail-api": + api_ip = gethostbyname(relation_get("private-address")) + api_port = relation_get("port") + else: + api_ip, api_port = [ (gethostbyname(relation_get("private-address", unit, rid)), + relation_get("port", unit, rid)) + for rid in relation_ids("contrail-api") + for unit in related_units(rid) ][0] + user = None + password = None + tenant = None + if relation == "identity-admin": + user = relation_get("service_username") + password = relation_get("service_password") + tenant = relation_get("service_tenant_name") + else: + user, password, tenant = [ (relation_get("service_username", unit, rid), + relation_get("service_password", unit, rid), + relation_get("service_tenant_name", unit, rid)) + for rid in relation_ids("identity-admin") + for unit in related_units(rid) ][0] + log("Unprovisioning control {}".format(ip)) + contrail_provision_control(hostname, ip, 64512, api_ip, api_port, "del", + user, password, tenant) + +def write_control_config(): + ctx = {} + ctx.update(contrail_ctx()) + ctx.update(contrail_discovery_ctx()) + ctx.update(contrail_ifmap_ctx()) + target = "/etc/contrail/contrail-control.conf" \ + if version_compare(CONTRAIL_VERSION, "2.0") >= 0 \ + else "/etc/contrail/control-node.conf" + render("control-node.conf", target, ctx, "root", "contrail", 0440) + +def write_nodemgr_config(): + ctx = contrail_discovery_ctx() + render("contrail-control-nodemgr.conf", + "/etc/contrail/contrail-control-nodemgr.conf", ctx) + +def write_vnc_api_config(): + ctx = {} + ctx.update(contrail_api_ctx()) + ctx.update(identity_admin_ctx()) + render("vnc_api_lib.ini", "/etc/contrail/vnc_api_lib.ini", ctx) -- cgit 1.2.3-korg