def provision_vrouter(): host_name = gethostname() host_ip = netifaces.ifaddresses("vhost0")[netifaces.AF_INET][0]["addr"] a_port = None a_ip = config.get("contrail-api-ip") if a_ip: a_port = config.get("contrail-api-port") if a_port is None: a_port = api_port() else: a_ip, a_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) ][0] log("Provisioning vrouter {}".format(host_ip)) check_call(["contrail-provision-vrouter", "--host_name", host_name, "--host_ip", host_ip, "--api_server_ip", a_ip, "--api_server_port", str(a_port), "--oper", "add", "--admin_user", user, "--admin_password", password, "--admin_tenant_name", tenant])
def provision_local_metadata(): a_port = None a_ip = config.get("contrail-api-ip") if a_ip: a_port = config.get("contrail-api-port") if a_port is None: a_port = api_port() else: a_ip, a_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 = [ (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("Provisioning local metadata service 127.0.0.1:8775") check_call(["contrail-provision-linklocal", "--api_server_ip", a_ip, "--api_server_port", str(a_port), "--linklocal_service_name", "metadata", "--linklocal_service_ip", "169.254.169.254", "--linklocal_service_port", "80", "--ipfabric_service_ip", "127.0.0.1", "--ipfabric_service_port", "8775", "--oper", "add", "--admin_user", user, "--admin_password", password])
def contrail_api_ctx(): ip = config.get("contrail-api-ip") if ip: port = config.get("contrail-api-port") return { "api_server": ip, "api_port": port if port is not None else api_port() } 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 get_db_connection(): config = ConfigParser.RawConfigParser() config.read('/etc/neutron/neutron.conf') try: return config.get('database', 'connection') except: return None
def add_contrail_api(): # check relation dependencies if not config_get("contrail-api-configured") \ and config_get("amqp-ready") \ and config_get("cassandra-ready") \ and config_get("identity-admin-ready") \ and config_get("zookeeper-ready"): api_p = api_port() port = str(api_p) try: # wait until api is up check_url("http://localhost:" + port) except urllib2.URLError: log("contrail-api service has failed to start correctly on port {}".format(port), "CRITICAL") log("This is typically due to a runtime error in related services", "CRITICAL") raise config["contrail-api-configured"] = True # inform relations for rid in relation_ids("contrail-api"): relation_set(relation_id=rid, port=api_p, vip=config.get("vip")) configure_floating_ip_pools()
def configure_vrouter(): # run external script to configure vrouter args = ["./create-vrouter.sh"] iface = config.get("vhost-interface") if iface: args.append(iface) check_call(args, cwd="scripts")
def configure_floating_ip_pools(): if is_leader(): floating_pools = config.get("floating-ip-pools") previous_floating_pools = leader_get("floating-ip-pools") if floating_pools != previous_floating_pools: # create/destroy pools, activate/deactivate projects # according to new value pools = { (pool["project"], pool["network"], pool["pool-name"]): set(pool["target-projects"]) for pool in yaml.safe_load(floating_pools) } \ if floating_pools else {} previous_pools = {} if previous_floating_pools: for pool in yaml.safe_load(previous_floating_pools): projects = pool["target-projects"] name = (pool["project"], pool["network"], pool["pool-name"]) if name in pools: previous_pools[name] = set(projects) else: floating_ip_pool_delete(name, projects) for name, projects in pools.iteritems(): if name not in previous_pools: floating_ip_pool_create(name, projects) else: floating_ip_pool_update(name, projects, previous_pools[name]) leader_set({"floating-ip-pools": floating_pools})
def get_db_connection(): config = ConfigParser.RawConfigParser() config.read(NEUTRON_CONF) try: return config.get('database', 'connection') except: return None
def vrouter_vgw_ctx(): ctx = {} vgws = config.get("virtual-gateways") if vgws: vgws = yaml.safe_load(vgws) map(lambda item: item.update(domain="default-domain"), vgws) ctx["vgws"] = vgws return ctx
def _get_hugepages(): pages = config.get("dpdk-hugepages") if not pages: return None if not pages.endswith("%"): return pages pp = int(pages.rstrip("%")) return int(get_total_ram() * pp / 100 / 1024 / 2048)
def servers_ctx(): analytics_ip_list = [] for rid in relation_ids("contrail-analyticsdb"): for unit in related_units(rid): utype = relation_get("unit-type", unit, rid) ip = relation_get("private-address", unit, rid) if ip and utype == "analytics": analytics_ip_list.append(ip) return { "controller_servers": common_utils.json_loads(config.get("controller_ips"), list()), "control_servers": common_utils.json_loads(config.get("controller_data_ips"), list()), "analytics_servers": analytics_ip_list }
def update_unit_status(): if not config.get("vrouter-provisioned"): units = [ unit for rid in relation_ids("contrail-controller") for unit in related_units(rid) ] if units: status_set("waiting", "There is no enough info to provision.") else: status_set("blocked", "Missing relation to contrail-controller") status, _ = _get_agent_status() if status == 'initializing': # some hacks log("Run agent hack: service restart") service_restart("contrail-vrouter-agent") sleep(10) status, msg = _get_agent_status() if status == 'initializing' and "(No Configuration for self)" in msg: log("Run agent hack: reinitialize config client") ip = config.get("api_ip") try: params = ["curl", "-s"] proto = "http" ssl_enabled = config.get("ssl_enabled", False) if ssl_enabled: params.extend([ "--cacert", "/etc/contrail/ssl/certs/ca-cert.pem", "--cert", "/etc/contrail/ssl/certs/server.pem", "--key", "/etc/contrail/ssl/private/server-privkey.pem" ]) proto = "https" url = ("{proto}://{ip}:8083/Snh_ConfigClientReinitReq?".format( proto=proto, ip=ip)) params.append(url) check_call(params) sleep(5) status, _ = _get_agent_status() except Exception as e: log("Reinitialize returns error: " + str(e)) if status == 'active': status_set("active", "Unit is ready") return status_set("waiting", "vrouter-agent is not up")
def control_node_departed(): if not units("control-node") \ and not units("contrail-discovery") \ and not config.get("discovery-server-ip"): config["control-node-ready"] = False check_vrouter() check_local_metadata() control_node_relation()
def config_changed(): if config_get("contrail-api-configured"): configure_floating_ip_pools() vip = config.get("vip") for rid in relation_ids("contrail-api"): relation_set(relation_id=rid, vip=vip) for rid in relation_ids("contrail-discovery"): relation_set(relation_id=rid, vip=vip)
def _render_config(): # From https://docs.docker.com/config/daemon/systemd/#httphttps-proxy if len(config.get('no_proxy')) > 2023: raise Exception('no_proxy longer than 2023 chars.') render('docker-proxy.conf', '/etc/systemd/system/docker.service.d/docker-proxy.conf', config) check_call(['systemctl', 'daemon-reload']) service_restart('docker')
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-enabled": config.get("ssl_enabled", False), "rabbitmq_user": RABBITMQ_USER, "rabbitmq_vhost": RABBITMQ_VHOST, "configdb_cassandra_user": leader_get("db_user"), "configdb_cassandra_password": leader_get("db_password"), } if config.get("use-external-rabbitmq"): settings["rabbitmq_password"] = config.get("rabbitmq_password") settings["rabbitmq_hosts"] = config.get("rabbitmq_hosts") else: settings["rabbitmq_password"] = leader_get("rabbitmq_password_int") settings["rabbitmq_hosts"] = None 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 configure_vrouter_interface(): # run external script to configure vrouter args = ["./create-vrouter.sh"] if config["remove-juju-bridge"]: args.append("-b") iface = config.get("physical-interface") if iface: args.append(iface) check_call(args, cwd="scripts")
def set_dpdk_options(): mask = config.get("dpdk-coremask") service = "/usr/bin/contrail-vrouter-dpdk" mask_arg = mask if mask.startswith("0x") else "-c " + mask if not init_is_systemd(): srv = "/etc/contrail/supervisord_vrouter_files/contrail-vrouter-dpdk.ini" with open(srv, "r") as f: data = f.readlines() for index, line in enumerate(data): if not (line.startswith("command=") and service in line): continue original_args = line.split(service)[1].rstrip() command_args_dict, other_args = _get_args_from_command_string( original_args) config_args_dict = _dpdk_args_from_config_to_dict() command_args_dict.update(config_args_dict) dpdk_args_string = " ".join(" ".join(_) for _ in command_args_dict.items()) args = dpdk_args_string + other_args newline = 'command=taskset ' + mask_arg + ' ' + service + ' ' + args + '\n' data[index] = newline with open(srv, "w") as f: f.writelines(data) service_restart("contrail-vrouter-dpdk") return # systemd magic srv_orig = "/lib/systemd/system/contrail-vrouter-dpdk.service" with open(srv_orig, "r") as f: data = f.readlines() for line in data: if not line.startswith("ExecStart="): continue original_args = line.split(service)[1].rstrip() dpdk_args_dict, other_args = _get_args_from_command_string( original_args) config_args_dict = _dpdk_args_from_config_to_dict() dpdk_args_dict.update(config_args_dict) break else: dpdk_args_dict = _dpdk_args_from_config_to_dict() other_args = " --no-daemon --socket-mem 1024" dpdk_args_string = " ".join(" ".join(_) for _ in dpdk_args_dict.items()) args = dpdk_args_string + other_args srv_dir = "/etc/systemd/system/contrail-vrouter-dpdk.service.d/" try: os.mkdir(srv_dir) except: pass with open(srv_dir + "/override.conf", "w") as f: f.write("[Service]\nExecStart=\n") f.write("ExecStart=/usr/bin/taskset {mask} {service} {args}".format( service=service, mask=mask_arg, args=args)) check_call(["systemctl", "daemon-reload"]) service_restart("contrail-vrouter-dpdk")
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 contrail_controller_joined(rel_id=None): settings = { 'unit-type': 'openstack', 'use-internal-endpoints': config.get('use-internal-endpoints') } relation_set(relation_id=rel_id, relation_settings=settings) if is_leader(): data = _get_orchestrator_info() relation_set(relation_id=rel_id, **data)
def get_context(): ctx = {} ctx["api_servers"] = common_utils.json_loads(config.get("controller_ips"), list()) for rid in relation_ids("contrail-controller"): for unit in related_units(rid): ssl_enabled = relation_get("ssl-enabled", unit, rid) if ssl_enabled: ctx["ssl_enabled"] = ssl_enabled ca_cert = relation_get("ca-cert", unit, rid) if ca_cert: ctx["ca_cert_data"] = ca_cert log("CTX: " + str(ctx)) auth_info = config.get("auth_info") if auth_info: ctx.update(json.loads(auth_info)) return ctx
def launch_docker_image(name, additional_args=[]): image_name = config.get("image-name") image_tag = config.get("image-tag") if not image_name or not image_tag: log("Docker image is not available", level=ERROR) return image_id = "{}:{}".format(image_name, image_tag) args = [ DOCKER_CLI, "run", "--net=host", "--cap-add=AUDIT_WRITE", "--privileged", "--restart=unless-stopped", "--volume=/etc/contrailctl:/etc/contrailctl", "--name=%s" % name ] args.extend(additional_args) args.extend(["-itd", image_id]) log("Run container with cmd: " + ' '.join(args)) check_call(args)
def render_logging(): driver = config.get("docker-log-driver") options = config.get("docker-log-options", '').split() if not driver and not options: return '' logging = 'logging:\n' if driver: logging += " driver: {}\n".format(driver) if options: logging += " options:\n" # yaml is created manually because of redis.yaml that is created by # controller and analytics and should be exactly the same to avoid # config_changed hooks starting options.sort() for opt in options: option = opt.split('=') logging += ' {}: "{}"\n'.format(option[0], option[1]) return logging
def update_relations(rid=None): auth_info = config.get("auth_info") if auth_info: data = json.loads(auth_info) data["keystone_ssl_ca"] = _decode_cert("ssl_ca") auth_info = json.dumps(data) settings = {"auth-info": auth_info} for rid in ([rid] if rid else relation_ids("contrail-auth")): relation_set(relation_id=rid, relation_settings=settings)
def pull_images(): tag = config.get('image-tag') for image in IMAGES: try: docker_utils.pull(image, tag) except Exception as e: log("Can't load image {}".format(e), level=ERROR) raise Exception('Image could not be pulled: {}:{}'.format( image, tag))
def http_services_joined(rel_id=None): vip = config.get("api_vip") func = close_port if vip else open_port try: func(8081, "TCP") except Exception: pass data = list() if not vip else _http_services(str(vip)) relation_set(relation_id=rel_id, services=yaml.dump(data))
def _notify_neutron(rid=None): rids = [rid] if rid else relation_ids("neutron-api") if not rids: return version = utils.get_openstack_version_codename('neutron') utils.deploy_openstack_code( "contrail-openstack-neutron-init", "neutron", {"OPENSTACK_VERSION": utils.PACKAGE_CODENAMES['neutron'][version]}) # create plugin config contrail_version = common_utils.get_contrail_version() plugin_path = utils.get_component_sys_paths("neutron") base = "neutron_plugin_contrail.plugins.opencontrail" plugin = base + ".contrail_plugin.NeutronPluginContrailCoreV2" # pass just separator to prevent setting of default list service_plugins = "contrail-timestamp," if contrail_version >= 1909: service_plugins += "contrail-trunk," if contrail_version >= 2005 and version > 12: service_plugins += "contrail-tags," if version < 15: service_plugins += base + ".loadbalancer.v2.plugin.LoadBalancerPluginV2," contrail_plugin_extension = plugin_path + "/neutron_plugin_contrail/extensions" neutron_lbaas_extensions = plugin_path + "/neutron_lbaas/extensions" extensions = [contrail_plugin_extension, neutron_lbaas_extensions] conf = { "neutron-api": { "/etc/neutron/neutron.conf": { "sections": { "DEFAULT": [("api_extensions_path", ":".join(extensions))] } } } } settings = { "neutron-plugin": "contrail", "core-plugin": plugin, "neutron-plugin-config": "/etc/neutron/plugins/opencontrail/ContrailPlugin.ini", "service-plugins": service_plugins, "quota-driver": base + ".quota.driver.QuotaDriver", "subordinate_configuration": json.dumps(conf), } auth_mode = config.get("auth_mode", "cloud-admin") if auth_mode == "rbac": settings["extra_middleware"] = [{ "name": "user_token", "type": "filter", "config": { "paste.filter_factory": base + ".neutron_middleware:token_factory" } }] for rid in rids: relation_set(relation_id=rid, relation_settings=settings)
def pull(self, image, tag): def _check_ctr_presence(): try: check_call([CTR_CLI, "--version"], stderr=DEVNULL) return True except Exception: return False if not _check_ctr_presence(): status_set("waiting", "Waiting for containerd installation") return False docker_user = config.get("docker-user") docker_password = config.get("docker-password") registry_insecure = config.get("docker-registry-insecure") image_id = self.get_image_id(image, tag) # check image presense # use check_output to avoid printing output to log output = check_output( [CTR_CLI, "image", "check", "name=={}".format(image_id)]) if output: return pull_opts = "" if docker_user: pull_opts += "--user " + docker_user if docker_password: pull_opts += ":" + docker_password if registry_insecure: insecure_opts = "-k" # pull image. Insert retries to cover issue when image cannot be pulled due to vrouter restart for i in range(10): try: check_call([ CTR_CLI, "image", "pull", pull_opts, insecure_opts, self.get_image_id(image, tag) ], stdout=DEVNULL) break except Exception as e: log("Cannot pull image {}:{}. {}".format(image, tag, e)) # retry time.sleep(30)
def vhost_gateway(iface): # determine vhost gateway gateway = config.get("vhost-gateway") if gateway == "auto": for line in check_output(["route", "-n"]).splitlines()[2:]: l = line.decode('UTF-8').split() if "G" in l[3] and l[7] == iface: return l[1] gateway = None return gateway
def _decode_cert(key): val = config.get(key) if not val: return None try: return base64.b64decode(val).decode() except Exception as e: log("Couldn't decode certificate from config['{}']: {}".format( key, str(e)), level=ERROR) return None
def _value_changed(rel_data, rel_key, cfg_key): if rel_key not in rel_data: # data is absent in relation. it means that remote charm doesn't # send it due to lack of information return value = rel_data[rel_key] if value is not None: config[cfg_key] = value elif value is None and config.get(cfg_key) is not None: config.pop(cfg_key, None)
def action_upgrade(): mode = config.get("maintenance") if not mode: return stop_agent() if mode == 'issu': _run_services(get_context()) elif mode == 'ziu': update_ziu("upgrade")
def action_upgrade(params): mode = config.get("maintenance") if not mode: return log("Upgrade action params: {}".format(params)) stop_agent(params["stop_agent"]) if mode == 'issu': _run_services(get_context()) elif mode == 'ziu': update_ziu("upgrade")
def get_context(): ctx = {} ctx["module"] = MODULE ctx["log_level"] = config.get("log-level", "SYS_NOTICE") ctx["container_registry"] = config.get("docker-registry") ctx["container_tag"] = config.get("image-tag") ctx["command_ip"] = common_utils.get_ip() ctx["contrail_container_tag"] = config.get("image-tag") ctx.update(common_utils.json_loads(config.get("orchestrator_info"), dict())) if not ctx.get("cloud_orchestrators"): ctx["cloud_orchestrators"] = list( ctx.get("cloud_orchestrator")) if ctx.get( "cloud_orchestrator") else list() log("CTX: {}".format(ctx)) return ctx
def _apply_insecure(): if not config.get("docker-registry-insecure"): return # NOTE: take just host and port from registry definition docker_registry = config.get("docker-registry").split('/')[0] log("Re-configure docker daemon") dc = _load_json_file("/etc/docker/daemon.json") cv = dc.get("insecure-registries", list()) if docker_registry in cv: return cv.append(docker_registry) dc["insecure-registries"] = cv _save_json_file("/etc/docker/daemon.json", dc) log("Restarting docker service") service_restart('docker')
def container_engine(): global _container_engine if _container_engine: return _container_engine if config.get("container_runtime", "docker") == "containerd": _container_engine = containerd_engine.Containerd() else: _container_engine = docker_engine.Docker() return _container_engine
def run(image, tag, volumes, remove=False, env_dict=None): image_id = get_image_id(image, tag) args = [DOCKER_CLI, "run"] if remove: args.append("--rm") args.extend(["-i", "--network", "host"]) for volume in volumes: args.extend(["-v", volume]) if env_dict: for key in env_dict: args.extend(["-e", "{}={}".format(key, env_dict[key])]) log_driver = config.get("docker-log-driver") if log_driver: args.extend(["--log-driver", log_driver]) log_options = config.get("docker-log-options") if log_options: for opt in log_options.split(): args.extend(["--log-opt", opt]) args.extend([image_id]) check_call(args)
def update_http_relations(rid=None): rids = [rid] if rid else relation_ids("http-services") if not rids: return vip = config.get("vip") _configure_ports(close_port if vip else open_port, ["8082", "8080"]) data = yaml.dump(_http_services(str(vip))) for rid in rids: relation_set(relation_id=rid, services=data)
def contrail_status_cmd(name, plugins_dir): script_name = 'check_contrail_status_{}.py'.format(name) tag = config.get('image-tag') cver = '5.1' if '5.0' in tag: cver = '5.0' check_contrail_status_script = os.path.join(plugins_dir, script_name) check_contrail_status_cmd = ('{} {}'.format(check_contrail_status_script, cver)) return check_contrail_status_cmd
def validate_config(config): """ Check that config is valid. :return: None """ max_line = 2048 line_prefix_len = len('Environment="NO_PROXY=""') remain_len = max_line - line_prefix_len if len(config.get('no_proxy', '')) > remain_len: raise ConfigError('no_proxy longer than {} chars.'.format(remain_len))
def auth_token_config(setting): """ Returns currently configured value for setting in api-paste.ini's authtoken section, or None. """ config = ConfigParser.RawConfigParser() config.read("/etc/nova/api-paste.ini") try: value = config.get("filter:authtoken", setting) except: return None if value.startswith("%"): return None return value
def auth_token_config(setting): ''' Returns currently configured value for setting in api-paste.ini's authtoken section, or None. ''' config = ConfigParser.RawConfigParser() config.read('/etc/nova/api-paste.ini') try: value = config.get('filter:authtoken', setting) except: return None if value.startswith('%'): return None return value
def auth_token_config(setting): """ Returns currently configured value for setting in vsm.conf's authtoken section, or None. """ config = ConfigParser.RawConfigParser() config.read('/etc/vsm/vsm.conf') try: value = config.get('keystone_authtoken', setting) except: return None if value.startswith('%'): return None return value
def contrail_discovery_ctx(): ip = config.get("discovery-server-ip") if ip: return { "discovery_server": ip, "discovery_port": discovery_port() } 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_api_joined(): if config_get("contrail-api-configured"): relation_set(port=api_port(), vip=config.get("vip"))
def contrail_discovery_joined(): relation_set(port=discovery_port(), vip=config.get("vip"))