diff options
Diffstat (limited to 'charms/trusty/contrail-configuration/hooks/contrail_configuration_utils.py')
-rw-r--r-- | charms/trusty/contrail-configuration/hooks/contrail_configuration_utils.py | 503 |
1 files changed, 503 insertions, 0 deletions
diff --git a/charms/trusty/contrail-configuration/hooks/contrail_configuration_utils.py b/charms/trusty/contrail-configuration/hooks/contrail_configuration_utils.py new file mode 100644 index 0000000..bb11693 --- /dev/null +++ b/charms/trusty/contrail-configuration/hooks/contrail_configuration_utils.py @@ -0,0 +1,503 @@ +from collections import OrderedDict +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 +import urllib2 + +from charmhelpers.core.hookenv import ( + config, + leader_get, + log, + related_units, + relation_get, + relation_ids, + relation_type, + remote_unit, + unit_get +) + +from charmhelpers.core.host import ( + service_available, + service_restart, + service_stop +) + +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-config") + +config = config() + +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 amqp_ctx(): + ctxs = [] + servers = OrderedDict() + for rid in relation_ids("amqp"): + for unit in related_units(rid): + password = relation_get("password", unit, rid) + if not password: + continue + ctxs.append({"rabbit_user": "contrail", + "rabbit_password": password, + "rabbit_vhost": "contrail"}) + vip = relation_get("vip", unit, rid) + server = (vip if vip \ + else gethostbyname(relation_get("hostname", unit, rid))) + ":5672" + servers[server] = None + ctx = ctxs[0] if ctxs else {} + ctx["rabbit_servers"] = servers.keys() + return ctx + +def analytics_api_ctx(): + ctxs = [ { "analytics_server_ip": vip if vip \ + else gethostbyname(relation_get("private-address", unit, rid)), + "analytics_server_port": port } + for rid in relation_ids("contrail-analytics-api") + 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 api_port(): + return 8082 + +def cassandra_ctx(): + servers = [ gethostbyname(relation_get("private-address", unit, rid)) + + ":" + (rpc_port if rpc_port else port) + for rid in relation_ids("cassandra") + for unit, rpc_port, port in + ((unit, relation_get("rpc_port", unit, rid), relation_get("port", unit, rid)) + for unit in related_units(rid)) + if rpc_port or port ] \ + if config.get("cassandra-ready") else [] + return { "cassandra_servers": servers } + +def cassandra_units(): + """Return a list of cassandra units""" + return [ unit for rid in relation_ids("cassandra") + for unit in related_units(rid) + if relation_get("rpc_port", unit, rid) or relation_get("port", unit, rid) ] + +@retry(timeout=300, delay=10) +def check_url(url): + try: + urllib2.urlopen(url) + except urllib2.HTTPError: + pass + +def contrail_ctx(): + addr = gethostbyname(unit_get("private-address")) + return { "api_port": api_port(), + "ifmap_server": addr, + "disc_server": addr, + "disc_port": discovery_port() } + +def contrail_floating_ip_create(network, name): + 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("Creating floating ip pool {} for network {}".format(name, network)) + check_call(["python", "/usr/share/contrail-utils/create_floating_pool.py", + "--public_vn_name", network, + "--floating_ip_pool_name", name, + "--api_server_ip", "127.0.0.1", + "--api_server_port", str(api_port()), + "--admin_user", user, + "--admin_password", password, + "--admin_tenant", tenant]) + +def contrail_floating_ip_deactivate(project, name): + 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("Deactivating floating ip pool {} for project {}".format(name, project)) + check_call(["scripts/deactivate_floating_pool.py", + "--api_server_ip", "127.0.0.1", + "--api_server_port", str(api_port()), + "--admin_user", user, + "--admin_password", password, + "--admin_tenant", tenant, + project, name]) + +def contrail_floating_ip_delete(network, name): + 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("Deleting floating ip pool {} for network {}".format(name, network)) + check_call(["scripts/delete_floating_pool.py", + "--api_server_ip", "127.0.0.1", + "--api_server_port", str(api_port()), + "--admin_user", user, + "--admin_password", password, + "--admin_tenant", tenant, + network, name]) + +def contrail_floating_ip_use(project, name): + 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("Activating floating ip pool {} for project {}".format(name, project)) + check_call(["python", "/usr/share/contrail-utils/use_floating_pool.py", + "--project_name", project, + "--floating_ip_pool_name", name, + "--api_server_ip", "127.0.0.1", + "--api_server_port", str(api_port()), + "--admin_user", user, + "--admin_password", password, + "--admin_tenant", tenant]) + +def contrail_ifmap_ctx(): + creds = [] + cs = leader_get("ifmap-creds") + if cs: + cs = json.loads(cs) + for units in cs.itervalues(): + for c in units.itervalues(): + creds.append(c) + return { "ifmap_creds": creds } + +def discovery_port(): + return 5998 + +def fix_ifmap_server(): + # disable ifmap-server upstart service + if service_available("ifmap-server"): + service_stop("ifmap-server") + with open("/etc/init/ifmap-server.override", "w") as conf: + conf.write("manual\n") + + # use supervisord config + shutil.copy("files/ifmap.ini", "/etc/contrail/supervisord_config_files") + pw = pwd.getpwnam("contrail") + os.chown("/etc/contrail/supervisord_config_files/ifmap.ini", pw.pw_uid, + pw.pw_gid) + shutil.copy("files/ifmap", "/etc/init.d") + os.chmod("/etc/init.d/ifmap", 0755) + +def fix_nodemgr(): + # add files missing from contrail-nodemgr package + shutil.copy("files/contrail-nodemgr-config.ini", + "/etc/contrail/supervisord_config_files") + pw = pwd.getpwnam("contrail") + os.chown("/etc/contrail/supervisord_config_files/contrail-nodemgr-config.ini", + pw.pw_uid, pw.pw_gid) + shutil.copy("files/contrail-config-nodemgr", "/etc/init.d") + os.chmod("/etc/init.d/contrail-config-nodemgr", 0755) + + # fake ntp status when inside a container + if is_container(): + shutil.copy("files/ntpq-nodemgr", "/usr/local/bin/ntpq") + +def fix_permissions(): + os.chmod("/etc/contrail", 0755) + os.chown("/etc/contrail", 0, 0) + +def fix_scripts(): + version = dpkg_version("contrail-config") + if version_compare(version, "2.01") >= 0: + # supervisord and init scripts need correcting on contrail 2.01+ + for service in [ "contrail-api", "contrail-discovery" ]: + # remove hardcoded port + check_call(["sed", "-E", "-i", "-e", + "s/ --listen_port [^[:blank:]]+//", + "/etc/contrail/supervisord_config_files/{}.ini".format(service)]) + + # fix init script + check_call(["sed", "-i", "-e", + "s/`basename ${0}`$/\"`basename ${0}`:*\"/", + "/etc/init.d/{}".format(service)]) + +def fix_services(): + fix_permissions() + fix_ifmap_server() + fix_nodemgr() + fix_scripts() + service_restart("supervisor-config") + +def identity_admin_ctx(): + ctxs = [ { "auth_host": gethostbyname(hostname), + "auth_port": relation_get("service_port", unit, rid), + "admin_user": relation_get("service_username", unit, rid), + "admin_password": relation_get("service_password", unit, rid), + "admin_tenant_name": relation_get("service_tenant_name", unit, rid), + "auth_region": relation_get("service_region", 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_configuration(): + hostname = gethostname() + ip = gethostbyname(unit_get("private-address")) + 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 configuration {}".format(ip)) + check_call(["contrail-provision-config", + "--host_name", hostname, + "--host_ip", ip, + "--api_server_ip", "127.0.0.1", + "--api_server_port", str(api_port()), + "--oper", "add", + "--admin_user", user, + "--admin_password", password, + "--admin_tenant_name", tenant]) + +def provision_metadata(): + ip = [ gethostbyname(relation_get("private-address", unit, rid)) + for rid in relation_ids("neutron-metadata") + for unit in related_units(rid) ][0] + user, password = [ (relation_get("service_username", unit, rid), + relation_get("service_password", 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 metadata service {}:8775".format(ip)) + check_call(["contrail-provision-linklocal", + "--api_server_ip", "127.0.0.1", + "--api_server_port", str(api_port()), + "--linklocal_service_name", "metadata", + "--linklocal_service_ip", "169.254.169.254", + "--linklocal_service_port", "80", + "--ipfabric_service_ip", ip, + "--ipfabric_service_port", "8775", + "--oper", "add", + "--admin_user", user, + "--admin_password", password]) + +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_configuration(): + if not remote_unit(): + return + hostname = gethostname() + ip = gethostbyname(unit_get("private-address")) + relation = relation_type() + 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 configuration {}".format(ip)) + check_call(["contrail-provision-config", + "--host_name", hostname, + "--host_ip", ip, + "--api_server_ip", "127.0.0.1", + "--api_server_port", str(api_port()), + "--oper", "del", + "--admin_user", user, + "--admin_password", password, + "--admin_tenant_name", tenant]) + +def unprovision_metadata(): + if not remote_unit(): + return + relation = relation_type() + ip = None + if relation == "neutron-metadata": + ip = gethostbyname(relation_get("private-address")) + else: + ip = [ gethostbyname(relation_get("private-address", unit, rid)) + for rid in relation_ids("neutron-metadata") + for unit in related_units(rid) ][0] + user = None + password = None + if relation == "identity-admin": + user = relation_get("service_username") + password = relation_get("service_password") + else: + user, password = [ (relation_get("service_username", unit, rid), + relation_get("service_password", unit, rid)) + for rid in relation_ids("identity-admin") + for unit in related_units(rid) ][0] + log("Unprovisioning metadata service {}:8775".format(ip)) + check_call(["contrail-provision-linklocal", + "--api_server_ip", "127.0.0.1", + "--api_server_port", str(api_port()), + "--linklocal_service_name", "metadata", + "--linklocal_service_ip", "169.254.169.254", + "--linklocal_service_port", "80", + "--ipfabric_service_ip", ip, + "--ipfabric_service_port", "8775", + "--oper", "del", + "--admin_user", user, + "--admin_password", password]) + +def write_barbican_auth_config(): + ctx = identity_admin_ctx() + render("contrail-barbican-auth.conf", + "/etc/contrail/contrail-barbican-auth.conf", ctx, "root", "contrail", + 0440) + +def write_contrail_api_config(): + ctx = {} + ctx.update(contrail_ctx()) + ctx.update(cassandra_ctx()) + ctx.update(zookeeper_ctx()) + ctx.update(amqp_ctx()) + ctx.update(identity_admin_ctx()) + render("contrail-api.conf", "/etc/contrail/contrail-api.conf", ctx, "root", + "contrail", 0440) + +def write_contrail_schema_config(): + ctx = {} + ctx.update(cassandra_ctx()) + ctx.update(zookeeper_ctx()) + ctx.update(identity_admin_ctx()) + ctx.update(contrail_ctx()) + if version_compare(CONTRAIL_VERSION, "3.0") >= 0: + ctx["rabbitmq"] = True + ctx.update(amqp_ctx()) + render("contrail-schema.conf", "/etc/contrail/contrail-schema.conf", + ctx, "root", "contrail", 0440) + +def write_contrail_svc_monitor_config(): + ctx = {} + ctx.update(contrail_ctx()) + ctx.update(cassandra_ctx()) + ctx.update(zookeeper_ctx()) + ctx.update(amqp_ctx()) + ctx.update(identity_admin_ctx()) + ctx.update(analytics_api_ctx()) + render("contrail-svc-monitor.conf", + "/etc/contrail/contrail-svc-monitor.conf", ctx, "root", "contrail", + 0440) + +def write_device_manager_config(): + ctx = {} + ctx.update(contrail_ctx()) + ctx.update(zookeeper_ctx()) + ctx.update(cassandra_ctx()) + ctx.update(amqp_ctx()) + ctx.update(identity_admin_ctx()) + render("contrail-device-manager.conf", + "/etc/contrail/contrail-device-manager.conf", ctx, "root", + "contrail", 0440) + +def write_discovery_config(): + ctx = {} + ctx.update(zookeeper_ctx()) + ctx.update(cassandra_ctx()) + target = "/etc/contrail/contrail-discovery.conf" \ + if version_compare(CONTRAIL_VERSION, "1.20~") >= 0 \ + else "/etc/contrail/discovery.conf" + render("discovery.conf", target, ctx) + +def write_ifmap_config(): + ctx = contrail_ifmap_ctx() + render("basicauthusers.properties", + "/etc/ifmap-server/basicauthusers.properties", ctx, "root", + "contrail", 0440) + +def write_nodemgr_config(): + ctx = contrail_ctx() + render("contrail-config-nodemgr.conf", + "/etc/contrail/contrail-config-nodemgr.conf", ctx) + +def write_vnc_api_config(): + ctx = {} + ctx.update(contrail_ctx()) + ctx.update(identity_admin_ctx()) + render("vnc_api_lib.ini", "/etc/contrail/vnc_api_lib.ini", ctx) + +def zookeeper_ctx(): + return { "zk_servers": [ gethostbyname(relation_get("private-address", unit, rid)) + + ":" + port + for rid in relation_ids("zookeeper") + for unit, port in + ((unit, relation_get("port", unit, rid)) for unit in related_units(rid)) + if port ] } |