def get_error_summary(self, service_names): configs = { service_name: load_service_mconfig_as_json(service_name) for service_name in service_names } res = { service_name: Errors(log_level=configs[service_name]['logLevel'], error_count=0) for service_name in service_names } syslog_path = '/var/log/syslog' if not os.access(syslog_path, os.R_OK): raise PermissionError( 'syslog is not readable. ' 'Try `sudo chmod a+r {}`. ' 'Or execute the command with sudo ' 'permissions: `venvsudo`'.format(syslog_path)) with open(syslog_path, 'r') as f: for line in f: for service_name in service_names: if service_name not in line: continue # Reset the counter for restart/start if 'Starting {}...'.format(service_name) in line: res[service_name].error_count = 0 elif 'ERROR' in line: res[service_name].error_count += 1 return res
def get_context(): """ Provide context to pass to Jinja2 for templating. """ context = {} cfg = load_service_config("dnsd") try: mconfig = load_service_mconfig_as_json("dnsd") except LoadConfigError as err: logging.warning("Error! Using default config because: %s", err) mconfig = DnsD() ip = get_ip_from_if_cidr(cfg['enodeb_interface']) dhcp_block_size = cfg['dhcp_block_size'] available_hosts = list(ipaddress.IPv4Interface(ip).network.hosts()) if dhcp_block_size < len(available_hosts): context['dhcp_range'] = { "lower": str(available_hosts[-dhcp_block_size]), "upper": str(available_hosts[-1]), } else: logging.fatal("Not enough available hosts to allocate a DHCP block of \ %d addresses." % (dhcp_block_size)) context['addresses'] = _get_addresses(cfg, mconfig) return context
def main(): parser = create_parser() args = parser.parse_args() # import after parsing command line because import is sluggish from magma.configuration.mconfig_managers \ import load_service_mconfig_as_json # set up logging logging.basicConfig( level=logging.INFO, format='[%(asctime)s %(levelname)s %(name)s] %(message)s') mconfig = load_service_mconfig_as_json(args.service) # if a variable was not specified, pretty print config and exit if args.variable is None: print(mconfig, end="") sys.exit(0) var = getattr(mconfig, args.variable) if args.test: if var: # if true, then return 0 (zero means success) sys.exit(0) # exit code 2 to distinguish from exit code 1, # which is returned after python exceptions. sys.exit(2) # not a boolean, print the config print(var) sys.exit(0)
def main(): """ conditionally start a systemd service based on an mconfig Example usage: ExecStart=/usr/sbin/magma_conditional_service.py \ --service service \ --variable enable \ service.sh start """ parser = create_parser() args = parser.parse_args() logging.basicConfig( level=logging.INFO, format='[%(asctime)s %(levelname)s %(name)s] %(message)s') mconfig = load_service_mconfig_as_json(args.service) var = getattr(mconfig, args.variable) serviceEnabled = bool(var) if getattr(args, "not"): # 'not' is a reserved keyword serviceEnabled = not serviceEnabled execArgs = [args.command] + args.args if serviceEnabled: logging.info("service enabled, starting: %s" % " ".join([shlex.quote(a) for a in execArgs])) os.execv(execArgs[0], execArgs) else: info = "service disabled since config %s.%s==%s %%s" % ( args.service, args.variable, bool(var), ) if args.oneshot: logging.info(info, "(oneshot, exiting...)") return 0 elif args.forking: writePIDCmd = "" if args.forking_pid_file: writePIDCmd = "( echo $! > %s )" % args.forking_pid_file logging.info(info, "(forking, pid_file=%s)" % args.forking_pid_file) # TODO: use os.fork(), when it works on all devices. forkArgs = [ "/bin/sh", "-c", "while true; do sleep 600; done & %s " "# conditional_service disabled since config %s.%s==%s" % (writePIDCmd, args.service, args.variable, bool(var)), ] os.execv(forkArgs[0], forkArgs) else: logging.info(info, "(simple)") while True: time.sleep(600)
def _get_attached_enodeb_tacs(): mme_config = load_service_mconfig_as_json("mme") # attachedEnodebTacs overrides 'tac', which is being deprecated, but for # now, both are supported tac = mme_config["tac"] attached_enodeb_tacs = mme_config["attachedEnodebTacs"] if len(attached_enodeb_tacs) == 0: return [tac] return attached_enodeb_tacs
def _get_dns_ip(iface_config): """ Get dnsd interface IP without netmask. If caching is enabled, use the ip of interface that dnsd listens over. Otherwise, just use dns server in yml. """ if load_service_mconfig_as_json("mme")["enableDnsCaching"]: iface_name = get_service_config_value("dnsd", iface_config, "") return get_ip_from_if(iface_name) return get_service_config_value("spgw", "ipv4_dns", "")
def _get_non_eps_service_control(): non_eps_service_control = \ load_service_mconfig_as_json("mme")["nonEpsServiceControl"] if non_eps_service_control: if non_eps_service_control == 0: return "OFF" elif non_eps_service_control == 1: return "CSFB_SMS" elif non_eps_service_control == 2: return "SMS" return "OFF"
def _get_enb_yang_config( device_config: EnodebConfiguration, ) -> Optional[SingleEnodebConfig]: """" Proof of concept configuration function to load eNB configs from YANG data model. Attempts to load configuration from YANG for the eNodeB if an entry exists with a matching serial number. Args: device_config: eNodeB device configuration Returns: None or a SingleEnodebConfig from YANG with matching serial number """ enb = [] mme_list = [] mme_address = None mme_port = None try: enb_serial = \ device_config.get_parameter(ParameterName.SERIAL_NUMBER) config = json.loads( load_service_mconfig_as_json('yang').get('value', '{}'), ) enb.extend( filter( lambda entry: entry['serial'] == enb_serial, config.get('cellular', {}).get('enodeb', []), ), ) except (ValueError, KeyError, LoadConfigError): return None if len(enb) == 0: return None enb_config = enb[0].get('config', {}) mme_list.extend(enb_config.get('mme', [])) if len(mme_list) > 0: mme_address = mme_list[0].get('host') mme_port = mme_list[0].get('port') single_enodeb_config = SingleEnodebConfig( earfcndl=enb_config.get('earfcndl'), subframe_assignment=enb_config.get('subframe_assignment'), special_subframe_pattern=enb_config.get('special_subframe_pattern'), pci=enb_config.get('pci'), plmnid_list=",".join(enb_config.get('plmnid', [])), tac=enb_config.get('tac'), bandwidth_mhz=enb_config.get('bandwidth_mhz'), cell_id=enb_config.get('cell_id'), allow_enodeb_transmit=enb_config.get('transmit_enabled'), mme_address=mme_address, mme_port=mme_port, ) return single_enodeb_config
def gateway_health_status(): config = load_service_mconfig_as_json('mme') # eNB status for #eNBs connected chan = ServiceRegistry.get_rpc_channel('enodebd', ServiceRegistry.LOCAL) client = EnodebdStub(chan) status = client.GetStatus(Void()) mme_log_path = '/var/log/mme.log' health_summary = AGWHealthSummary( relay_enabled=config['relayEnabled'], nb_enbs_connected=status.meta['n_enodeb_connected'], allocated_ips=get_allocated_ips(), subscriber_table=get_subscriber_table(), registration_success_rate=get_registration_success_rate(mme_log_path), ) return str(health_summary)
def generate_template_config(service, template, out_dirname, context): """ Generate the config from the jinja template. Args: service (str): Name of the magma service. Used for looking up the config and mconfig template (str): Name of the input template, which is also used for choosing the output filename out_dirname (str): Path of the output file context (map): Context to use for Jinja (the .yml config and mconfig will be added into this context) """ # Get the template and the output filenames template_filename = _get_template_filename(template) out_filename = _get_template_out_filename(template, out_dirname) logging.info( "Generating config file: [%s] using template: [%s]" % ( out_filename, template_filename, ), ) template_context = {} # Generate the content to use from the service yml config and mconfig. try: template_context.update(load_service_config(service)) except LoadConfigError as err: logging.warning(err) template_context.update(context) try: mconfig = load_service_mconfig_as_json(service) template_context.update(mconfig) except LoadConfigError as err: logging.warning(err) # Export snowflake to template. # TODO: export a hardware-derived ID that can be used by a field tech # to easily identify a specific device. template_context.setdefault("snowflake", make_snowflake()) # Create the config file based on the template template_str = open(template_filename, 'r').read() output = Template(template_str).render(template_context) os.makedirs(out_dirname, exist_ok=True) write_to_file_atomically(out_filename, output)
def get_error_summary(self, service_names): """Get the list of services with the error count. Args: service_names: List of service names. Returns: A dictionary with service name as a key and the Errors object as a value. Raises: PermissionError: User has no permision to exectue the command """ configs = { service_name: load_service_mconfig_as_json(service_name) for service_name in service_names } res = { service_name: Errors( log_level=configs[service_name].get('logLevel', 'INFO'), error_count=0, ) for service_name in service_names } syslog_path = '/var/log/syslog' if not os.access(syslog_path, os.R_OK): raise PermissionError( 'syslog is not readable. ' 'Try `sudo chmod a+r {}`. ' 'Or execute the command with sudo ' 'permissions: `venvsudo`'.format(syslog_path), ) with open(syslog_path, 'r', encoding='utf-8') as f: for line in f: for service_name in service_names: if service_name not in line: continue # Reset the counter for restart/start if 'Starting {}...'.format(service_name) in line: res[service_name].error_count = 0 elif 'ERROR' in line: res[service_name].error_count += 1 return res
def get_context(): """ Provide context to pass to Jinja2 for templating. """ context = {} cfg = load_service_config("lighttpd") ip = "127.0.0.1" enable_caching = False try: mconfig = load_service_mconfig_as_json('lighttpd') enable_caching = mconfig.enable_caching except LoadConfigError: logging.info("Using default values for service 'lighttpd'") if enable_caching: ip = get_ip_from_if(cfg['interface']) context['interface_ip'] = ip context['store_root'] = cfg['store_root'] return context
def gateway_health_status(self): config = load_service_mconfig_as_json('mme') # eNB status for #eNBs connected chan = ServiceRegistry.get_rpc_channel( 'enodebd', ServiceRegistry.LOCAL, ) client = EnodebdStub(chan) status = client.GetStatus(Void()) mme_log_path = '/var/log/mme.log' health_summary = AGWHealthSummary( hss_relay_enabled=config.get('hssRelayEnabled', False), nb_enbs_connected=status.meta.get('n_enodeb_connected', 0), allocated_ips=self.get_allocated_ips(), subscriber_table=self.get_subscriber_table(), core_dumps=self.get_core_dumps(), registration_success_rate=self.get_registration_success_rate( mme_log_path, ), ) return health_summary
def main(): parser = create_parser() args = parser.parse_args() # import after parsing command line because import is sluggish from magma.configuration.mconfig_managers import ( load_service_mconfig_as_json, ) # set up logging logging.basicConfig( level=logging.INFO, format='[%(asctime)s %(levelname)s %(name)s] %(message)s', ) mconfig_json = load_service_mconfig_as_json(args.service) # if a variable was not specified, pretty print config and exit if args.variable is None: for k, v in mconfig_json.items(): # Keys shouldn't have spaces in them, but just in case # Values also shouldn't have newlines, but if they do, this will # print differently than if called with --variable print(k.replace(" ", "_"), str(v).replace("\n", r"\n")) sys.exit(0) var = mconfig_json[args.variable] if args.test: if var: # if true, then return 0 (zero means success) sys.exit(0) # exit code 2 to distinguish from exit code 1, # which is returned after python exceptions. sys.exit(2) # not a boolean, print the config print(var) sys.exit(0)
def _get_csfb_mnc(): csfb_mnc = load_service_mconfig_as_json("mme")["csfbMnc"] if csfb_mnc: return csfb_mnc return ""
def _get_lac(): lac = load_service_mconfig_as_json("mme")["lac"] if lac: return lac return 0
def _get_relay_enabled(): if load_service_mconfig_as_json("mme")["relayEnabled"]: return "yes" return "no"