Exemplo n.º 1
0
    def decompose_incoming_envelope(self, ctx, message=XmlDocument.REQUEST):
        """
        For TR-069, the SOAP fault message (CPE->ACS) contains useful
        information, and should not result in another fault response (ACS->CPE).
        Strip the outer SOAP fault structure, so that the CWMP fault structure
        is treated as a normal RPC call (to the 'Fault' function).
        """
        super(Tr069Soap11, self).decompose_incoming_envelope(ctx, message)

        if ctx.in_body_doc.tag == '{%s}Fault' % self.ns_soap_env:
            faultstring = ctx.in_body_doc.findtext('faultstring')
            if not faultstring or 'CWMP fault' not in faultstring:
                # Not a CWMP fault
                return

            # Strip SOAP fault structure, leaving inner CWMP fault structure
            detail_elem = ctx.in_body_doc.find('detail')
            if detail_elem is not None:
                detail_children = list(detail_elem)
                if len(detail_children):
                    if len(detail_children) > 1:
                        logger.warning("Multiple detail elements found in SOAP"
                                       " fault - using first one")
                    ctx.in_body_doc = detail_children[0]
                    ctx.method_request_string = ctx.in_body_doc.tag
                    self.validate_body(ctx, message)
Exemplo n.º 2
0
    def handle_tr069_message(
        self,
        ctx: WsgiMethodContext,
        tr069_message: ComplexModelBase,
    ) -> Any:
        """ Delegate message handling to the appropriate eNB state machine """
        client_ip = self._get_client_ip(ctx)
        if isinstance(tr069_message, models.Inform):
            try:
                self._update_device_mapping(client_ip, tr069_message)
            except UnrecognizedEnodebError as err:
                logger.warning(
                    'Received TR-069 Inform message from an '
                    'unrecognized device. '
                    'Ending TR-069 session with empty HTTP '
                    'response. Error: (%s)', err)
                return models.DummyInput()

        handler = self._get_handler(client_ip)
        if handler is None:
            logger.warning('Received non-Inform TR-069 message from unknown '
                           'eNB. Ending session with empty HTTP response.')
            return models.DummyInput()

        return handler.handle_tr069_message(tr069_message)
Exemplo n.º 3
0
def _parse_sw_version(version_str):
    """
    Parse SW version string.
    Expects format: BaiStation_V100R001C00B110SPC003
    For the above version string, returns: [100, 1, 0, 110, 3]
    Note: trailing characters (for dev builds) are ignored. Null is returned
    for version strings that don't match the above format.
    """
    logger.debug('Got firmware version: %s', version_str)

    version = re.findall(
        r'BaiStation_V(\d{3})R(\d{3})C(\d{2})B(\d{3})SPC(\d{3})', version_str)
    if not version:
        return None
    elif len(version) > 1:
        logger.warning('SW version (%s) not formatted as expected',
                       version_str)
    version_int = []
    for num in version[0]:
        try:
            version_int.append(int(num))
        except ValueError:
            logger.warning('SW version (%s) not formatted as expected',
                           version_str)
            return None

    logger.debug('Parsed firmware version: %s', version_int)

    return version_int
Exemplo n.º 4
0
def get_all_enb_state(
        print_grpc_payload: bool = False) -> Optional[Dict[int, int]]:
    """
    Make RPC call to 'GetENBState' method of s1ap service
    """
    try:
        chan = ServiceRegistry.get_rpc_channel(
            S1AP_SERVICE_NAME,
            ServiceRegistry.LOCAL,
        )
    except ValueError:
        logger.error('Cant get RPC channel to %s', S1AP_SERVICE_NAME)
        return {}
    client = S1apServiceStub(chan)
    try:
        request = Void()
        print_grpc(
            request,
            print_grpc_payload,
            "Get All eNB State Request:",
        )
        res = client.GetENBState(request, DEFAULT_GRPC_TIMEOUT)
        print_grpc(
            res,
            print_grpc_payload,
            "Get All eNB State Response:",
        )
        return res.enb_state_map
    except grpc.RpcError as err:
        logger.warning(
            "GetEnbState error: [%s] %s",
            err.code(),
            err.details(),
        )
    return {}
Exemplo n.º 5
0
 def _assert_param_in_model(self, param_name: ParameterName) -> None:
     trparam_model = self.data_model
     tr_param = trparam_model.get_parameter(param_name)
     if tr_param is None:
         logger.warning('Parameter <%s> not defined in model', param_name)
         raise ConfigurationError(
             f"Parameter not defined in model: {param_name}")
Exemplo n.º 6
0
async def set_enodebd_iptables_rule():
    """
    Remove & Set iptable rules for exposing public IP
    for enobeb instead of private IP..
    """
    # Remove & Set iptable rules for exposing public ip
    # for enobeb instead of private
    cfg = load_service_config('enodebd')
    port, interface = cfg['tr069']['port'], cfg['tr069']['interface']
    enodebd_public_ip = cfg['tr069']['public_ip']
    # IPv4 only as iptables only works for IPv4. TODO: Investigate ip6tables?
    enodebd_ip = get_ip_from_if(interface, preference=IpPreference.IPV4_ONLY)
    # Incoming data from 192.88.99.142 -> enodebd address (eg 192.168.60.142)
    enodebd_netmask = get_if_ip_with_netmask(
        interface,
        preference=IpPreference.IPV4_ONLY,
    )[1]
    verify_config = does_iface_config_match_expected(
        enodebd_ip,
        enodebd_netmask,
    )
    if not verify_config:
        logger.warning(
            'The IP address of the %s interface is %s. The '
            'expected IP addresses are %s', interface, enodebd_ip,
            str(EXPECTED_IP4))
    await check_and_apply_iptables_rules(
        port,
        enodebd_public_ip,
        enodebd_ip,
    )
Exemplo n.º 7
0
def bandwidth(bandwidth_rbs: Union[str, int, float]) -> float:
    """
    Map bandwidth in number of RBs to MHz
    TODO: TR-196 spec says this should be '6' rather than 'n6', but
    BaiCells eNodeB uses 'n6'. Need to resolve this.

    Args:
        bandwidth_rbs (str): Bandwidth in number of RBs
    Returns:
        str: Bandwidth in MHz
    """
    if bandwidth_rbs in BANDWIDTH_RBS_TO_MHZ_MAP:
        return BANDWIDTH_RBS_TO_MHZ_MAP[bandwidth_rbs]

    logger.warning('Unknown bandwidth_rbs (%s)', str(bandwidth_rbs))
    if bandwidth_rbs in BANDWIDTH_MHZ_LIST:
        return bandwidth_rbs
    elif isinstance(bandwidth_rbs, str):
        mhz = None
        if bandwidth_rbs.isdigit():
            mhz = int(bandwidth_rbs)
        elif bandwidth_rbs.replace('.', '', 1).isdigit():
            mhz = float(bandwidth_rbs)
        if mhz in BANDWIDTH_MHZ_LIST:
            return mhz
    raise ConfigurationError('Unknown bandwidth specification (%s)' %
                             str(bandwidth_rbs))
Exemplo n.º 8
0
    def postprocess(
        self,
        mconfig: Any,
        service_cfg: Any,
        desired_cfg: EnodebConfiguration,
    ) -> None:
        # TODO: Get this config from the domain proxy
        # TODO @amarpad, set these when DProxy integration is done.
        # For now the radio will directly talk to the SAS and get these
        # attributes.
        desired_cfg.delete_parameter(ParameterName.EARFCNDL)
        desired_cfg.delete_parameter(ParameterName.DL_BANDWIDTH)
        desired_cfg.delete_parameter(ParameterName.UL_BANDWIDTH)

        # go through misc parameters and set them to default.
        for name, val in FreedomFiOneMiscParameters.defaults.items():
            desired_cfg.set_parameter(name, val)

        # Bump up the parameter key version
        self.acs.parameter_version_inc()

        # Workaround a bug in Sercomm firmware in release 3920, 3921
        # where the meaning of CellReservedForOperatorUse is wrong.
        # Set to True to ensure the PLMN is not reserved
        num_plmns = self.acs.data_model.get_num_plmns()
        for i in range(1, num_plmns + 1):
            object_name = ParameterName.PLMN_N % i
            desired_cfg.set_parameter_for_object(
                param_name=ParameterName.PLMN_N_CELL_RESERVED % i,
                value=True,
                object_name=object_name,
            )

        if self.WEB_UI_ENABLE_LIST_KEY in service_cfg:
            serial_nos = service_cfg.get(self.WEB_UI_ENABLE_LIST_KEY)
            if self.acs.device_cfg.has_parameter(
                    ParameterName.SERIAL_NUMBER, ):
                if self.acs.get_parameter(ParameterName.SERIAL_NUMBER) in \
                        serial_nos:
                    desired_cfg.set_parameter(
                        FreedomFiOneMiscParameters.WEB_UI_ENABLE,
                        True,
                    )
            else:
                # This should not happen
                EnodebdLogger.error("Serial number unknown for device")

        if self.SAS_KEY not in service_cfg:
            return

        sas_cfg = service_cfg[self.SAS_KEY]
        sas_param_names = self.acs.data_model.get_sas_param_names()
        for name, val in sas_cfg.items():
            if name not in sas_param_names:
                EnodebdLogger.warning("Ignoring attribute %s", name)
                continue
            desired_cfg.set_parameter(name, val)
Exemplo n.º 9
0
def _read_gps_coords_from_file():
    try:
        with open(CACHED_GPS_COORD_FILE_PATH) as f:
            lines = f.readlines()
            if len(lines) != 2:
                logger.warning(
                    'Expected to find 2 lines in GPS '
                    'coordinate file but only found %d', len(lines))
                return '0', '0'
            return tuple(map(lambda l: l.strip(), lines))
    except OSError:
        logger.warning('Could not open cached GPS coordinate file')
        return '0', '0'
Exemplo n.º 10
0
def _format_as_bool(
    param_value: Union[bool, str, int],
    param_name: Optional[Union[ParameterName, str]] = None,
) -> bool:
    """ Returns '1' for true, and '0' for false """
    stripped_value = str(param_value).lower().strip()
    if stripped_value in {'true', '1'}:
        return True
    elif stripped_value in {'false', '0'}:
        return False
    else:
        logger.warning('%s parameter not understood (%s)', param_name,
                       param_value)
        return False
Exemplo n.º 11
0
def check_rules(prerouting_rules: List[str], port: str, enodebd_public_ip: str,
                private_ip: str) -> None:
    unexpected_rules = []
    pattern = r'DNAT\s+tcp\s+--\s+anywhere\s+{pub_ip}\s+tcp\s+dpt:{dport} to:{ip}'.format(
        pub_ip=enodebd_public_ip,
        dport=port,
        ip=private_ip,
    )
    for rule in prerouting_rules:
        match = re.search(pattern, rule)
        if not match:
            unexpected_rules.append(rule)
    if unexpected_rules:
        logger.warning('The following Prerouting rule(s) are unexpected')
        for rule in unexpected_rules:
            logger.warning(rule)
Exemplo n.º 12
0
def get_all_enb_state() -> Optional[Dict[int, int]]:
    """
    Make RPC call to 'GetENBState' method of s1ap service
    """
    try:
        chan = ServiceRegistry.get_rpc_channel(S1AP_SERVICE_NAME,
                                               ServiceRegistry.LOCAL)
    except ValueError:
        logger.error('Cant get RPC channel to %s', S1AP_SERVICE_NAME)
        return {}
    client = S1apServiceStub(chan)
    try:
        res = client.GetENBState(Void(), DEFAULT_GRPC_TIMEOUT)
        return res.enb_state_map
    except grpc.RpcError as err:
        logger.warning("GetEnbState error: [%s] %s", err.code(), err.details())
    return {}
Exemplo n.º 13
0
    def postprocess(
        self,
        mconfig: Any,
        service_cfg: Any,
        desired_cfg: EnodebConfiguration,
    ) -> None:
        # TODO: Get this config from the domain proxy
        # TODO @amarpad, set these when DProxy integration is done.
        # For now the radio will directly talk to the SAS and get these
        # attributes.
        desired_cfg.delete_parameter(ParameterName.EARFCNDL)
        desired_cfg.delete_parameter(ParameterName.DL_BANDWIDTH)
        desired_cfg.delete_parameter(ParameterName.UL_BANDWIDTH)

        # go through misc parameters and set them to default.
        for name, val in FreedomFiOneMiscParameters.defaults.items():
            desired_cfg.set_parameter(name, val)

        # Bump up the parameter key version
        self.acs.parameter_version_inc()

        if self.WEB_UI_ENABLE_LIST_KEY in service_cfg:
            serial_nos = service_cfg.get(self.WEB_UI_ENABLE_LIST_KEY)
            if self.acs.device_cfg.has_parameter(
                    ParameterName.SERIAL_NUMBER, ):
                if self.acs.get_parameter(ParameterName.SERIAL_NUMBER) in \
                        serial_nos:
                    desired_cfg.set_parameter(
                        FreedomFiOneMiscParameters.WEB_UI_ENABLE,
                        True,
                    )
            else:
                # This should not happen
                EnodebdLogger.error("Serial number unknown for device")

        if self.SAS_KEY not in service_cfg:
            return

        sas_cfg = service_cfg[self.SAS_KEY]
        sas_param_names = self.acs.data_model.get_sas_param_names()
        for name, val in sas_cfg.items():
            if name not in sas_param_names:
                EnodebdLogger.warning("Ignoring attribute %s", name)
                continue
            desired_cfg.set_parameter(name, val)
Exemplo n.º 14
0
def _get_gps_status_as_bool(enodeb: EnodebAcsStateMachine) -> bool:
    try:
        if not enodeb.has_parameter(ParameterName.GPS_STATUS):
            return False
        else:
            param = enodeb.get_parameter(ParameterName.GPS_STATUS)
            stripped_value = param.lower().strip()
            if stripped_value == '0' or stripped_value == '2':
                # 2 = GPS locking
                return False
            elif stripped_value == '1':
                return True
            else:
                logger.warning('GPS status parameter not understood (%s)',
                               param)
                return False
    except (KeyError, ConfigurationError):
        return False
Exemplo n.º 15
0
    def _check_mme_connection(self) -> None:
        """
        Check if eNodeB should be connected to MME but isn't, and maybe reboot.

        If the eNB doesn't report connection to MME within a timeout period,
        get it to reboot in the hope that it will fix things.

        Usually, enodebd polls the eNodeB for whether it is connected to MME.
        This method checks the last polled MME connection status, and if
        eNodeB should be connected to MME but it isn't.
        """
        if self.device_cfg.has_parameter(ParameterName.MME_STATUS) and \
                self.device_cfg.get_parameter(ParameterName.MME_STATUS):
            is_mme_connected = 1
        else:
            is_mme_connected = 0

        # True if we would expect MME to be connected, but it isn't
        is_mme_unexpectedly_dc = \
            self.is_enodeb_connected() \
            and self.is_enodeb_configured() \
            and self.mconfig.allow_enodeb_transmit \
            and not is_mme_connected

        if is_mme_unexpectedly_dc:
            logger.warning(
                'eNodeB is connected to AGw, is configured, '
                'and has AdminState enabled for transmit. '
                'MME connection to eNB is missing.', )
            if self.mme_timer is None:
                logger.warning(
                    'eNodeB will be rebooted if MME connection '
                    'is not established in: %s seconds.',
                    self.MME_DISCONNECT_ENODEB_REBOOT_TIMER,
                )
                metrics.STAT_ENODEB_REBOOT_TIMER_ACTIVE.set(1)
                self.mme_timer = \
                    StateMachineTimer(self.MME_DISCONNECT_ENODEB_REBOOT_TIMER)
            elif self.mme_timer.is_done():
                logger.warning(
                    'eNodeB has not established MME connection '
                    'within %s seconds - rebooting!',
                    self.MME_DISCONNECT_ENODEB_REBOOT_TIMER,
                )
                metrics.STAT_ENODEB_REBOOTS.labels(
                    cause='MME disconnect').inc()
                metrics.STAT_ENODEB_REBOOT_TIMER_ACTIVE.set(0)
                self.mme_timer = None
                self.reboot_asap()
            else:
                # eNB is not connected to MME, but we're still waiting to see
                # if it will connect within the timeout period.
                # Take no action for now.
                pass
        else:
            if self.mme_timer is not None:
                logger.info('eNodeB has established MME connection.')
                self.mme_timer = None
            metrics.STAT_ENODEB_REBOOT_TIMER_ACTIVE.set(0)
Exemplo n.º 16
0
def _get_and_cache_gps_coords(enodeb: EnodebAcsStateMachine) -> Tuple[str, str]:
    """
    Read the GPS coordinates of the enB from its configuration or the
    cached coordinate file if the preceding read fails. If reading from
    enB configuration succeeds, this method will cache the new coordinates.

    Returns:
        (str, str): GPS latitude, GPS longitude
    """
    lat, lon = '', ''
    try:
        lat = enodeb.get_parameter(ParameterName.GPS_LAT)
        lon = enodeb.get_parameter(ParameterName.GPS_LONG)

        if lat != _gps_lat_cached or lon != _gps_lon_cached:
            _cache_new_gps_coords(lat, lon)
        return lat, lon
    except (KeyError, ConfigurationError):
        return _get_cached_gps_coords()
    except ValueError:
        logger.warning('GPS lat/long not understood (%s/%s)', lat, lon)
        return '0', '0'
Exemplo n.º 17
0
    def read_msg(self, message: Any) -> AcsReadMsgResult:
        """ Process GetParameterValuesResponse """
        if not isinstance(message, models.GetParameterValuesResponse):
            return AcsReadMsgResult(False, None)

        path_to_val = {}
        if hasattr(message.ParameterList, 'ParameterValueStruct') and \
                message.ParameterList.ParameterValueStruct is not None:
            for param_value_struct in message.ParameterList.ParameterValueStruct:
                path_to_val[param_value_struct.Name] = \
                    param_value_struct.Value.Data
        logger.debug('Received object parameters: %s', str(path_to_val))

        # Number of PLMN objects reported can be incorrect. Let's count them
        num_plmns = 0
        obj_to_params = self.acs.data_model.get_numbered_param_names()
        while True:
            obj_name = ParameterName.PLMN_N % (num_plmns + 1)
            if obj_name not in obj_to_params or len(
                    obj_to_params[obj_name]) == 0:
                logger.warning(
                    "eNB has PLMN %s but not defined in model",
                    obj_name,
                )
                break
            param_name_list = obj_to_params[obj_name]
            obj_path = self.acs.data_model.get_parameter(
                param_name_list[0]).path
            if obj_path not in path_to_val:
                break
            if not self.acs.device_cfg.has_object(obj_name):
                self.acs.device_cfg.add_object(obj_name)
            num_plmns += 1
            for name in param_name_list:
                path = self.acs.data_model.get_parameter(name).path
                value = path_to_val[path]
                magma_val = \
                    self.acs.data_model.transform_for_magma(name, value)
                self.acs.device_cfg.set_parameter_for_object(
                    name,
                    magma_val,
                    obj_name,
                )
        num_plmns_reported = \
                int(self.acs.device_cfg.get_parameter(ParameterName.NUM_PLMNS))
        if num_plmns != num_plmns_reported:
            logger.warning(
                "eNB reported %d PLMNs but found %d",
                num_plmns_reported,
                num_plmns,
            )
            self.acs.device_cfg.set_parameter(
                ParameterName.NUM_PLMNS,
                num_plmns,
            )

        # Now we can have the desired state
        if self.acs.desired_cfg is None:
            self.acs.desired_cfg = build_desired_config(
                self.acs.mconfig,
                self.acs.service_config,
                self.acs.device_cfg,
                self.acs.data_model,
                self.acs.config_postprocessor,
            )

        if len(
                get_all_objects_to_delete(
                    self.acs.desired_cfg,
                    self.acs.device_cfg,
                ), ) > 0:
            return AcsReadMsgResult(True, self.rm_obj_transition)
        elif len(
                get_all_objects_to_add(
                    self.acs.desired_cfg,
                    self.acs.device_cfg,
                ), ) > 0:
            return AcsReadMsgResult(True, self.add_obj_transition)
        elif len(
                get_all_param_values_to_set(
                    self.acs.desired_cfg,
                    self.acs.device_cfg,
                    self.acs.data_model,
                ), ) > 0:
            return AcsReadMsgResult(True, self.set_params_transition)
        return AcsReadMsgResult(True, self.skip_transition)
Exemplo n.º 18
0
def _set_earfcn_freq_band_mode(
    device_cfg: EnodebConfiguration,
    cfg: EnodebConfiguration,
    data_model: DataModel,
    earfcndl: int,
) -> None:
    """
    Set the following parameters:
     - EARFCNDL
     - EARFCNUL
     - Band
    """
    # Note: validation of EARFCNDL done by mapping function. If invalid
    # EARFCN, raise ConfigurationError
    try:
        band, duplex_mode, earfcnul = map_earfcndl_to_band_earfcnul_mode(
            earfcndl)
    except ValueError as err:
        raise ConfigurationError(err)

    # Verify capabilities
    duplex_capability =\
        device_cfg.get_parameter(ParameterName.DUPLEX_MODE_CAPABILITY)
    if duplex_mode == DuplexMode.TDD and duplex_capability != 'TDDMode':
        raise ConfigurationError(
            ('eNodeB duplex mode capability is <{0}>, '
             'but earfcndl is <{1}>, giving duplex '
             'mode <{2}> instead').format(duplex_capability, str(earfcndl),
                                          str(duplex_mode)))
    elif duplex_mode == DuplexMode.FDD and duplex_capability != 'FDDMode':
        raise ConfigurationError(
            ('eNodeB duplex mode capability is <{0}>, '
             'but earfcndl is <{1}>, giving duplex '
             'mode <{2}> instead').format(duplex_capability, str(earfcndl),
                                          str(duplex_mode)))
    elif duplex_mode not in [DuplexMode.TDD, DuplexMode.FDD]:
        raise ConfigurationError('Invalid duplex mode (%s)' % str(duplex_mode))

    # Baicells indicated that they no longer use the band capability list,
    # so it may not be populated correctly
    band_capability_list = device_cfg.get_parameter(
        ParameterName.BAND_CAPABILITY)
    band_capabilities = band_capability_list.split(',')
    if str(band) not in band_capabilities:
        logger.warning(
            'Band %d not in capabilities list (%s). Continuing'
            ' with config because capabilities list may not be'
            ' correct', band, band_capabilities)

    cfg.set_parameter(ParameterName.EARFCNDL, earfcndl)
    if duplex_mode == DuplexMode.FDD:
        _set_param_if_present(cfg, data_model, ParameterName.EARFCNUL,
                              earfcnul)
    else:
        logger.debug('Not setting EARFCNUL - duplex mode is not FDD')

    _set_param_if_present(cfg, data_model, ParameterName.BAND, band)

    if duplex_mode == DuplexMode.TDD:
        logger.debug('Set EARFCNDL=%d, Band=%d', earfcndl, band)
    else:
        logger.debug('Set EARFCNDL=%d, EARFCNUL=%d, Band=%d', earfcndl,
                     earfcnul, band)
Exemplo n.º 19
0
 def log_error(self, format, *args):
     """ Overwrite message logging to use python logging framework rather
         than stderr """
     logger.warning("%s - %s", self.client_address[0], format % args)
Exemplo n.º 20
0
    def _parse_tdd_counters(self, enb_label, names, data):
        """
        Parse eNodeB performance management counters from TDD structure.
        Most of the logic is just to extract the correct counter based on the
        name of the statistic. Each counter is either of type 'V', which is a
        single integer value, or 'CV', which contains multiple integer
        sub-elements, named 'SV', which we add together. E.g:
        <V i="9">0</V>
        <CV i="10">
          <SN>RRC.AttConnReestab.RECONF_FAIL</SN>
          <SV>0</SV>
          <SN>RRC.AttConnReestab.HO_FAIL</SN>
          <SV>0</SV>
          <SN>RRC.AttConnReestab.OTHER</SN>
          <SV>0</SV>
        </CV>
        See tests/stats_manager_tests.py for a more complete example.
        """
        index_data_map = self._build_index_to_data_map(data)
        name_index_map = self._build_name_to_index_map(names)

        # For each performance metric, extract value from XML document and set
        # internal metric to that value.
        for pm_name, metric in self.PM_FILE_TO_METRIC_MAP.items():

            elements = pm_name.split(':')
            counter = elements.pop(0)
            if len(elements) == 0:
                subcounter = None
            else:
                subcounter = elements.pop(0)

            index = name_index_map.get(counter)
            if index is None:
                logger.warning('PM counter %s not found in PmNames', counter)
                continue

            data_el = index_data_map.get(index)
            if data_el is None:
                logger.warning('PM counter %s not found in PmData', counter)
                continue

            if data_el.tag == 'V':
                if subcounter is not None:
                    logger.warning('No subcounter in PM counter %s', counter)
                    continue

                # Data is singular value
                try:
                    value = int(data_el.text)
                except ValueError:
                    logger.info('PM value (%s) of counter %s not integer',
                                data_el.text, counter)
                    continue
            elif data_el.tag == 'CV':
                # Check whether we want just one subcounter, or sum them all
                subcounter_index = None
                if subcounter is not None:
                    index = 0
                    for sub_name_el in data_el.findall('SN'):
                        if sub_name_el.text == subcounter:
                            subcounter_index = index
                        index = index + 1

                if subcounter is not None and subcounter_index is None:
                    logger.warning('PM subcounter (%s) not found', subcounter)
                    continue

                # Data is multiple sub-elements. Sum them, or select the one
                # of interest
                value = 0
                try:
                    index = 0
                    for sub_data_el in data_el.findall('SV'):
                        if subcounter_index is None or \
                                subcounter_index == index:
                            value = value + int(sub_data_el.text)
                        index = index + 1
                except ValueError:
                    logger.error('PM value (%s) of counter %s not integer',
                                 sub_data_el.text, pm_name)
                    continue
            else:
                logger.warning('Unknown PM data type (%s) of counter %s',
                               data_el.tag, pm_name)
                continue

            # Apply new value to metric
            if pm_name == 'PDCP.UpOctUl' or pm_name == 'PDCP.UpOctDl':
                metric.labels(enb_label).set(value)
            else:
                metric.set(value)
Exemplo n.º 21
0
 def get_state(self) -> str:
     if self.state is None:
         logger.warning('ACS State machine is not in any state.')
         return 'N/A'
     return self.state.state_description()