diff options
Diffstat (limited to 'contrail-openstack/hooks/contrail_openstack_utils.py')
-rw-r--r-- | contrail-openstack/hooks/contrail_openstack_utils.py | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/contrail-openstack/hooks/contrail_openstack_utils.py b/contrail-openstack/hooks/contrail_openstack_utils.py new file mode 100644 index 0000000..25f57a0 --- /dev/null +++ b/contrail-openstack/hooks/contrail_openstack_utils.py @@ -0,0 +1,168 @@ +import apt_pkg +from base64 import b64decode +import json +import os +import requests +from six.moves.urllib.parse import urlparse +from socket import gethostbyname + +from charmhelpers.core.hookenv import ( + config, + log, + WARNING, + ERROR, + relation_ids, + related_units, +) +from charmhelpers.core.host import ( + write_file, +) +from charmhelpers.core.templating import render + +apt_pkg.init() +config = config() + + +def update_service_ips(): + try: + endpoints = _get_endpoints() + except Exception as e: + log("Couldn't detect services ips: " + str(e), + level=WARNING) + return False + + changed = {} + + def _check_key(key): + val = endpoints.get(key) + if val and val != config.get(key): + config[key] = val + changed[key] = val + + _check_key("compute_service_ip") + _check_key("image_service_ip") + _check_key("network_service_ip") + if changed: + config.save() + return True + + return False + + +def _get_endpoints(): + auth_info = config.get("auth_info") + if auth_info: + auth_info = json.loads(auth_info) + if not auth_info or not auth_info.get("keystone_ip"): + raise Exception("auth_info is not ready.") + + api_ver = int(auth_info["keystone_api_version"]) + if api_ver == 2: + req_data = { + "auth": { + "tenantName": auth_info["keystone_admin_tenant"], + "passwordCredentials": { + "username": auth_info["keystone_admin_user"], + "password": auth_info["keystone_admin_password"]}}} + else: + req_data = { + "auth": { + "identity": { + "methods": ["password"], + "password": { + "user": { + "name": auth_info["keystone_admin_user"], + "domain": {"id": "default"}, + "password": auth_info["keystone_admin_password"] + } + } + } + } + } + + url = "{proto}://{ip}:{port}/{tokens}".format( + proto=auth_info["keystone_protocol"], + ip=auth_info["keystone_ip"], + port=auth_info["keystone_public_port"], + tokens=auth_info["keystone_api_tokens"]) + r = requests.post(url, headers={'Content-type': 'application/json'}, + data=json.dumps(req_data), verify=False) + content = json.loads(r.content) + result = dict() + catalog = (content["access"]["serviceCatalog"] if api_ver == 2 else + content["token"]["catalog"]) + for service in catalog: + if api_ver == 2: + # NOTE: 0 means first region. do we need to search for region? + url = service["endpoints"][0]["publicURL"] + else: + for endpoint in service["endpoints"]: + if endpoint["interface"] == "public": + url = endpoint["url"] + break + host = gethostbyname(urlparse(url).hostname) + result[service["type"] + "_service_ip"] = host + return result + + +def write_configs(): + # don't need to write any configs for nova. only for neutron. + + units = [unit for rid in relation_ids("neutron-api") + for unit in related_units(rid)] + if not units: + return + + ctx = _get_context() + + # store files in standard path + ca_path = "/etc/contrail/ssl/certs/ca-cert.pem" + ssl_ca = ctx["ssl_ca"] + _save_file(ca_path, ssl_ca) + ctx["ssl_ca_path"] = ca_path + + render("ContrailPlugin.ini", + "/etc/neutron/plugins/opencontrail/ContrailPlugin.ini", + ctx, "root", "neutron", 0o440) + + +def _get_context(): + ctx = {} + + ip = config.get("api_vip") + if not ip: + ip = config.get("api_ip") + ctx["api_server"] = ip + ctx["api_port"] = config.get("api_port") + + ssl_ca = _decode_cert("ssl_ca") + ctx["ssl_ca"] = ssl_ca + ctx["ssl_enabled"] = (ssl_ca is not None and len(ssl_ca) > 0) + log("CTX: " + str(ctx)) + + auth_info = config.get("auth_info") + if auth_info: + ctx.update(json.loads(auth_info)) + return ctx + + +def _decode_cert(key): + val = config.get(key) + if not val: + return None + try: + return b64decode(val) + except Exception as e: + log("Couldn't decode certificate from config['{}']: {}".format( + key, str(e)), level=ERROR) + return None + + +def _save_file(path, data): + if data: + fdir = os.path.dirname(path) + if not os.path.exists(fdir): + os.makedirs(fdir) + write_file(path, data, perms=0o444) + elif os.path.exists(path): + os.remove(path) |