Exemplo n.º 1
0
 def __init__(self):
     self._conf = ConfigDB()
     # initialise logging level from DB (if set - otherwise 'warning')
     # NB - this is the ONLY time changes to the log level are actually
     # passed to the logging framework
     log_level = self._conf.get("logger.global.log_level", "warning")
     logger.DefaultLogger.update_handler(level=log_level)
     logger.notice("EndagaD started")
Exemplo n.º 2
0
def try_to_autoupgrade():
    """The gatekeeper of the upgrade_endaga method.

    Autoupgrades can be configured to run as soon as new software is available
    via the autoupgrade.in_window configdb key.  This method will invoke
    upgrade_endaga if autoupgrades are enabled.  If windowed upgrades are
    enabled, this will check if it's the right time and if an upgrade hasn't
    been run recently (default for "recently" is the last ten minutes).
    """
    conf = ConfigDB()
    window_duration = 10 * conf.get('registration_interval', 60)
    last_upgrade_format = '%Y-%m-%d %H:%M:%S'
    # Do nothing if autoupgrades are disabled.
    if not conf.get('autoupgrade.enabled', False):
        return
    # Also do nothing if there is no new metapackage available.  This info is
    # propagated for the beta and stable channels via the checkin response.
    channel = conf.get('autoupgrade.channel', 'stable')
    key = 'autoupgrade.latest_%s_version' % channel
    available_version = sortable_version(conf.get(key, '0.3.29'))
    installed_version = sortable_version(conf['endaga_version'])
    if available_version <= installed_version:
        return
    # If we're configured to only upgrade in a window (as opposed to as soon as
    # a new package is available), we need some additional checks.
    if conf.get('autoupgrade.in_window', False):
        # Do nothing if we've already performed an upgrade recently.
        last_upgrade = conf.get('autoupgrade.last_upgrade',
                                '2015-07-14 02:30:15')
        last_upgrade = datetime.strptime(last_upgrade, last_upgrade_format)
        now = datetime.utcnow()
        delta = (now - last_upgrade).total_seconds()
        if delta < window_duration:
            return
        # See if we're in the upgrade window.  Get the current time and the
        # window_start time as datetimes.  These are weird "date-less"
        # datetimes -- both dates will be 1-1-1900 but the part that we care
        # about, the times, will be comparable.
        window_format = '%H:%M:%S'
        now = datetime.strptime(now.strftime(window_format), window_format)
        window_start = conf.get('autoupgrade.window_start', '02:30:00')
        window_start = datetime.strptime(window_start, window_format)
        # Fail if we're currently before or after the window.
        if now < window_start:
            return
        if now > window_start + timedelta(seconds=window_duration):
            return
    # All checks pass, perform the upgrade and save the last upgraded time.
    upgrade_endaga(conf.get('autoupgrade.channel', 'stable'))
    conf['autoupgrade.last_upgrade'] = datetime.strftime(
        datetime.utcnow(), last_upgrade_format)
Exemplo n.º 3
0
def get_vpn_ip():
    """
    Gets the system VPN IP, or returns None if no VPN is up.
    """
    try:
        # Pylint gets confused about the contents of this package for some
        # reason.
        # pylint: disable=no-member
        conf = ConfigDB()
        ifname = conf.get('external_interface')  # vpn_interface?
        assert ifname is not None, \
            "VPN interface ('external_interface') not configured"
        return netifaces.ifaddresses(ifname)[netifaces.AF_INET][0]['addr']
    except Exception:
        return None
Exemplo n.º 4
0
 def __init__(self, user, port, call_handler, sms_handler,
              self_ip="127.0.0.1", other_ip="127.0.0.1"):
     #add user to the fakebts list of camped subscribers
     self.conf = ConfigDB()
     if 'fakebts.camped' not in self.conf:
         self.conf['fakebts.camped'] = json.dumps([])
     self.conf['fakebts.camped'] = json.dumps(json.loads(self.conf['fakebts.camped']) + [user])
Exemplo n.º 5
0
def main():
    """Main routine run by gprsd."""
    # Initialize some timestamps and connect to the ConfigDB.
    now = time.time()
    last_scrape_time = now
    last_event_generation_time = now
    last_removal_of_old_data = now
    config_db = ConfigDB()
    while True:
        now = time.time()
        # Get GPRS usage data and store it in the DB.
        if (now - last_scrape_time >
                config_db['gprsd_cli_scrape_period']):
            last_scrape_time = now
            utilities.gather_gprs_data()
        # Generate events for the EventStore with data from the GPRS table.
        if (now - last_event_generation_time >
                config_db['gprsd_event_generation_period']):
            last_event_generation_time = now
            start_time = now - config_db['gprsd_event_generation_period']
            utilities.generate_gprs_events(start_time, now)
        # Clean old records out of the GPRS table.
        if (now - last_removal_of_old_data >
                config_db['gprsd_cleanup_period']):
            last_removal_of_old_data = now
            utilities.clean_old_gprs_records(
                now - config_db['gprsd_max_data_age'])
        # Wait for a bit, then do it again.
        time.sleep(SLEEP_TIME)
Exemplo n.º 6
0
 def __init__(self):
     self.conf = ConfigDB()
     self.subscribers = Subscribers(
         host=self.conf['bts.osmocom.ip'],
         port=self.conf['bts.osmocom.bsc_vty_port'],
         hlr_loc=self.conf['bts.osmocom.hlr_loc'],
         timeout=self.conf['bss_timeout'])
Exemplo n.º 7
0
 def __init__(self):
     self.conf = ConfigDB()
     self.defaults = {
         'sddch': 8,
         'tchf': 4,
         'pch': 2,
         'agch': 2,
         'pdch': 2,
         'mnc': "001",
         'mnc': "01",
         'c0': 51,
         'band': "GSM900",
         'shortName': "fakeBTS",
         'openRegistration': ".*",
         'timer.3212': 6,
         'camped': json.dumps([]),
     }
 def setUpClass(cls):
     """Setup the test app."""
     cls.test_app = TestApp(core.federer.app.wsgifunc())
     cls.endpoint = '/config/deactivate_subscriber'
     # Setup a serializer so we can send signed data.  Bootstrap the secret.
     config_db = ConfigDB()
     config_db['bts_secret'] = 'yup'
     cls.serializer = itsdangerous.JSONWebSignatureSerializer(
         config_db['bts_secret'])
def get_vpn_ip():
    """
    Gets the system VPN IP, or returns None if no VPN is up.
    """
    try:
        # Pylint gets confused about the contents of this package for some
        # reason.
        # pylint: disable=no-member
        conf = ConfigDB()
        ifname = conf['external_interface']
        return netifaces.ifaddresses(ifname)[netifaces.AF_INET][0]['addr']
    except:
        return None
 def setUpClass(cls):
     """Setup the ConfigDB with a fake secret, and mock other items."""
     cls.config_db = ConfigDB()
     cls.config_db['bts_secret'] = 'test-secret-123'
     cls.original_logger = interconnect.logger
     cls.mock_logger = mock.Mock()
     interconnect.logger = cls.mock_logger
     # Mock bts for TMSIs
     cls.original_bts = interconnect.bts
     interconnect.bts = mocks.MockBTS()
     # Mock subscriber
     cls.original_subscriber = interconnect.subscriber
     interconnect.subscriber = mocks.MockSubscriber()
Exemplo n.º 11
0
 def __init__(self):
     self.conf = ConfigDB()
     self.subscribers = Subscribers(
         host=self.conf['bts.osmocom.ip'],
         port=self.conf['bts.osmocom.bsc_vty_port'],
         hlr_loc=self.conf['bts.osmocom.hlr_loc'],
         timeout=self.conf['bss_timeout'])
     self.network = Network(host=self.conf['bts.osmocom.ip'],
                            port=self.conf['bts.osmocom.bsc_vty_port'],
                            timeout=self.conf['bss_timeout'])
     self.bts = BTS(host=self.conf['bts.osmocom.ip'],
                    port=self.conf['bts.osmocom.bsc_vty_port'],
                    timeout=self.conf['bss_timeout'])
     self.trx = TRX(host=self.conf['bts.osmocom.ip'],
                    port=self.conf['bts.osmocom.bsc_vty_port'],
                    timeout=self.conf['bss_timeout'])
Exemplo n.º 12
0
 def __init__(self,
              user,
              port,
              call_handler,
              sms_handler,
              self_ip="127.0.0.1",
              other_ip="127.0.0.1"):
     BaseFakePhone.__init__(self,
                            user,
                            port,
                            call_handler,
                            sms_handler,
                            self_ip=self_ip,
                            other_ip=other_ip)
     self.user = user
     self.conf = ConfigDB()
     self.port = port
     self.sms_h = sms_handler
     self.call_h = call_handler
     self.self_ip = self_ip
     self.other_ip = other_ip
Exemplo n.º 13
0
class EndagaD(object):
    """
    Thin wrapper around the main loop that communicates with the cloud
    service. Manages registration, checkin and associated responses.
    """
    def __init__(self):
        self._conf = ConfigDB()
        # initialise logging level from DB (if set - otherwise 'warning')
        # NB - this is the ONLY time changes to the log level are actually
        # passed to the logging framework
        log_level = self._conf.get("logger.global.log_level", "warning")
        logger.DefaultLogger.update_handler(level=log_level)
        logger.notice("EndagaD started")

    def _reset_bts_config(self):
        logger.notice("Performing set_factory")
        try:
            if bts.set_factory_config():
                logger.notice("Restarting BTS")
                bts.restart()
                Service.SystemService("freeswitch").restart()
        except BSSError as e:
            logger.error("bts is probably down: %s" % e)
        except Exception as e:
            # OSError, IOError or whatever envoy will raise
            logger.critical("something unexpected happened: %s" % e)

    def run(self):
        """
        Main loop for endagad. This moves the system through the various
        states of operation -- it should be a state machine really!

        General flow is:
        1) Tries to get configuration from server to produce VPN keys
        2) Generates keys locally.
        3) Sends CSR for signing, returns that.
        4) Starts system services (FS, BTS, etc) and configures them
        appropriately. Note configuration can change depending on registration
        and VPN state of the system.
        5) Runs checkin periodically.
        """
        eapi = interconnect.endaga_ic(self._conf)
        if 'registration_interval' not in self._conf:
            self._conf['registration_interval'] = 60

        UNHEALTHY_THRESH = self._conf.get('bts.unhealthy_threshold', 3)
        unhealthy_count = UNHEALTHY_THRESH  # fail quickly on first pass
        while True:
            # Retrieve keys/tokens, or do nothing if we have them.
            logger.notice("Performing gen_keys")
            registration.generate_keys()

            # generate_keys() loads auth token on success. Need to update the
            # interconnect client's token if so.
            if eapi.token is None:
                eapi.token = self._conf['endaga_token']

            # Try to register/get VPN credentials.  Tries forever if fails.
            logger.notice("Performing register")
            registration.register(eapi)

            # Registered, start services and tries to start VPN.  Stop
            # everything otherwise.
            logger.notice("Performing clear_pid")
            registration.clear_old_pid()
            logger.notice("Performing update_vpn")
            registration.update_vpn()

            # At this point, all services should be up, so we can perform
            # additional configuration.
            self._reset_bts_config()

            # Update the inbound_url if the VPN is up.
            if system_utilities.get_vpn_ip() is not None:
                logger.notice("Performing register_update")
                registration.register_update(eapi)
                logger.notice("Performing ensure_fs_external_bound")
                registration.ensure_fs_external_bound_to_vpn()

            # Send checkin to cloud
            try:
                # Sends events, tries to get config info. Can proceed w/o VPN.
                logger.notice("Performing checkin.")
                checkin_data = eapi.checkin(timeout=30)
                logger.notice("Performing system health check.")
                if not registration.system_healthcheck(checkin_data):
                    unhealthy_count += 1
                    logger.notice("System unhealthy: %d" % unhealthy_count)
                else:
                    unhealthy_count = 0
            except (ConnectionError, Timeout):
                logger.error(
                    "checkin failed due to connection error or timeout.")
            except BSSError as e:
                logger.error("bts exception: %s" % e)

            if unhealthy_count > UNHEALTHY_THRESH:
                logger.notice("BTS seems unhealthy, restarting BTS services.")
                bts.restart()
                Service.SystemService("freeswitch").restart()

            # Upgrade the endaga metapackage, when appropriate and only if that
            # feature is enabled.
            logger.notice("Performing autoupgrade")
            system_utilities.try_to_autoupgrade()

            # Sleep for some amount of time before retrying
            logger.notice("Performing sleep")
            time.sleep(self._conf['registration_interval'])
Exemplo n.º 14
0
 def __init__(self):
     self.conf = ConfigDB()
     self.smqueue = openbts.components.SMQueue(
         socket_timeout=self.conf['bss_timeout'],
         cli_timeout=self.conf['bss_timeout'])
Exemplo n.º 15
0
import gettext
import traceback

import itsdangerous

from ccm.common import logger
from core import billing
from core import events
from core import freeswitch_interconnect
from core.subscriber import subscriber
from core.config_database import ConfigDB
from core.message_database import MessageDB


cdb = ConfigDB()
gt = gettext.translation(
    "endaga", cdb['localedir'], [cdb['locale'], "en"]).gettext
# Hardcode the dashboard's from_number.
DASHBOARD_FROM_NUMBER = '0000'


class incoming(object):
    def __init__(self):
        self.conf = cdb
        self.fs_ic = freeswitch_interconnect.freeswitch_ic(self.conf)
        self.tariff_type = "off_network_receive"
        self.msgid_db = MessageDB()

    def bill(self, to_number, from_number):
        try:
Exemplo n.º 16
0
# Copyright (c) 2016-present, Facebook, Inc.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree. An additional grant
# of patent rights can be found in the PATENTS file in the same directory.

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

from core.config_database import ConfigDB

#
# Override stubs with system specific implementation
#
conf = ConfigDB()

if conf['bts.type'] == 'fake':
    from . import _fakehlr
    subscriber = _fakehlr.FakeSubscriberDB()
elif conf['bts.type'] == 'osmocom':
    from . import _osmocom
    subscriber = _osmocom.OsmocomSubscriber()
else:
    from . import _openbts
    subscriber = _openbts.OpenBTSSubscriber()
Exemplo n.º 17
0
class CheckinHandler(object):

    CONFIG_SECTION = "config"
    EVENTS_SECTION = "events"
    SUBSCRIBERS_SECTION = "subscribers"

    # NOTE: Keys in section_ctx dictionary below must match the keys of
    # optimized checkin sections: "config", "events", "subscribers", etc.
    section_ctx = {
        CONFIG_SECTION: delta.DeltaProtocolCtx(),
        # Note: EVENTS_SECTION is not optimized
        SUBSCRIBERS_SECTION: delta.DeltaProtocolCtx(),
    }

    def __init__(self, response):
        self.conf = ConfigDB()
        self.eventstore = EventStore()
        r = self.validate(response)
        self.process(r)

    def process(self, resp_dict):
        """Process sections of a checkin response.

        Right now we have three sections: config, events, and subscribers.
        """
        if 'status' in resp_dict and resp_dict['status'] == 'deregistered':
            reset_registration()
        for section in resp_dict:
            if section == CheckinHandler.CONFIG_SECTION:
                self.process_config(resp_dict[section])
            elif section == CheckinHandler.EVENTS_SECTION:
                self.process_events(resp_dict[section])
            elif section == CheckinHandler.SUBSCRIBERS_SECTION:
                self.process_subscribers(resp_dict[section])
            elif section != 'status':
                logger.error("Unexpected checkin section: %s" % section)

    def validate(self, response):
        """Validates a response.

        Args:
          response: decoded json response from the server as a python
                    dictionary.

        Returns: a python dictionary containing the checkin response, otherwise
                 throws errors.
        """
        r = json.loads(response)
        return r['response']

    @delta.DeltaCapable(section_ctx['config'], True)
    def process_config(self, config_dict):
        for section in config_dict:
            if section == "endaga":
                self.conf.process_config_update(config_dict[section])
            # TODO cloud should use generic key names not openbts specific
            elif section == "openbts":
                bts.process_bts_settings(config_dict[section])
            elif section == "prices":
                process_prices(config_dict['prices'], self.conf)
            elif section == "autoupgrade":
                self.process_autoupgrade(config_dict['autoupgrade'])

    # wrap the subscriber method in order to keep delta context encapsulated
    @delta.DeltaCapable(section_ctx['subscribers'], True)
    def process_subscribers(self, data_dict):
        subscriber.process_update(data_dict)

    def process_events(self, data_dict):
        """Process information about events.

        Right now, there should only be one value here: seqno, which denotes
        the highest seqno for this BTS for which the server has ack'd.
        """
        if "seqno" in data_dict:
            seqno = int(data_dict['seqno'])
            self.eventstore.ack(seqno)

    def process_autoupgrade(self, data):
        """Process information about autoupgrade preferences.

        Args:
          data: a dict of the form {
            'enabled': True,
            'channel': 'dev',
            'in_window': True,  # whether to upgrade in a window or not.  If
                                # not, this means we should upgrade as soon as
                                # new packages are available.
            'window_start': '02:45:00'
            'latest_stable_version': '1.2.3',
            'latest_beta_version': '5.6.7',
          }

        The configdb keys are prefixed with "autoupgrade." (e.g.
        autoupgrade.enabled).
        """
        for key in ('enabled', 'channel', 'in_window', 'window_start',
                    'latest_stable_version', 'latest_beta_version'):
            configdb_key = 'autoupgrade.%s' % key
            # Set the value if it's not already in the config db or if it's
            # changed.
            existing_value = self.conf.get(configdb_key, None)
            if existing_value != data[key]:
                self.conf[configdb_key] = data[key]
 def setUpClass(cls):
     cls.config_db = ConfigDB()
     cls.key = 'test-key'
            break
        time.sleep(1)


def call_handler(fp):
    print ("Call Received")
    fp.call_received = True


def sms_handler(fp, content):
    print ("SMS Received: " + content)
    fp.sms_received = True
    fp.content = content


CONF = ConfigDB()
FEDERER_TIMEOUT = 15  # seconds
SMQ_TIMEOUT = 15  # seconds
FS_TIMEOUT = 15  # seconds


class FakePhoneTest_01_Nominal(unittest.TestCase):
    """Testing FS functionality"""

    @classmethod
    def setUpClass(cls):
        # Mock the Endaga API endpoint in a new process.
        cls.webserver = Thread(
            target=core.tests.mock_api.APP_NOMINAL.run)
        # This is a kludge -- web.py is strict on taking the port from argv.
        sys.argv = ['8080']
Exemplo n.º 20
0
 def __init__(self):
     super(OpenBTSSubscriber, self).__init__()
     self.conf = ConfigDB()
     self.sip_auth_serve = openbts.components.SIPAuthServe(
         socket_timeout=self.conf['bss_timeout'],
         cli_timeout=self.conf['bss_timeout'])
Exemplo n.º 21
0
 def __init__(self):
     self.ic = None
     self.conf = ConfigDB()
     self.worker = self.registration_worker
     self.fs_ic = freeswitch_interconnect.freeswitch_ic(self.conf)
Exemplo n.º 22
0
 def __init__(self):
     self.conf = ConfigDB()
     self.msgid_db = MessageDB()
     self.ic = interconnect.endaga_ic(self.conf)
Exemplo n.º 23
0
class FakeBTS(BaseBTS):
    def __init__(self):
        self.conf = ConfigDB()
        self.defaults = {
            'sddch': 8,
            'tchf': 4,
            'pch': 2,
            'agch': 2,
            'pdch': 2,
            'mnc': "001",
            'mnc': "01",
            'c0': 51,
            'band': "GSM900",
            'shortName': "fakeBTS",
            'openRegistration': ".*",
            'timer.3212': 6,
            'camped': json.dumps([]),
        }

    def __get(self, name):
        db_name = "fakebts." + name
        if name in self.defaults:
            return self.conf.get(db_name, default=self.defaults[name])
        else:
            return self.conf.get(db_name)

    def __set(self, name, value):
        self.conf['fakebts.' + name] = value

    def set_factory_config(self):
        """ Done. """
        pass

    def get_camped_subscribers(self, access_period=0, auth=1):
        #camped is serialized
        camped = json.loads(self.__get('camped'))
        #not a real user, but we always need one
        camped += ['IMSI001010000000000']
        res = []
        for camp in camped:
            res.append({
                'IMSI': camp,
                'ACCESSED': time.time(),
            })
        return res

    def get_load(self):
        return {
            'sdcch_load': random.choice(range(0, self.__get('sddch'))),
            'sdcch_available': self.__get('sddch'),
            'tchf_load': random.choice(range(0, self.__get('tchf'))),
            'tchf_available': self.__get('tchf'),
            'pch_active': random.choice(range(0, self.__get('pch'))),
            'pch_total': self.__get('pch'),
            'agch_active': random.choice(range(0, self.__get('agch'))),
            'agch_pending': 0,
            'gprs_current_pdchs': random.choice(range(0, self.__get('pdch'))),
            #probably should math this
            'gprs_utilization_percentage': .4,
        }

    def get_noise(self):
        return {
            'noise_rssi_db': 60,
            'noise_ms_rssi_target_db': 80,
        }

    def set_mcc(self, mcc):
        self.__set('mcc', mcc)

    def set_mnc(self, mnc):
        self.__set('mnc', mnc)

    def set_short_name(self, short_name):
        self.__set('shortName', short_name)

    def set_open_registration(self, expression):
        self.__set('openRegistration', expression)

    def set_timer(self, timer, value):
        self.__set('timer.' + timer, value)

    def set_band(self, band):
        self.__set('band', band)

    def set_arfcn_c0(self, arfcn):
        self.__set('c0', arfcn)

    def get_mcc(self):
        return self.__get('mcc')

    def get_mnc(self):
        return self.__get('mnc')

    def get_short_name(self):
        return self.__get('shortName')

    def get_open_registration(self):
        return self.__get('openRegistration')

    def get_timer(self, timer):
        try:
            return self.__get('timer.' + timer)
        except Exception as e:
            exc_type, exc_value, exc_trace = sys.exc_info()
            raise BSSError, "%s: %s" % (exc_type, exc_value), exc_trace

    def get_available_bands(self):
        return [self.get_band()]

    def get_available_arfcns(self):
        return [self.get_arfcn_c0()]

    def get_band(self):
        return self.__get('band')

    def get_arfcn_c0(self):
        return self.__get('c0')

    def get_versions(self):
        #custom keys for this BTS type
        versions = BaseBTS.get_versions(self)
        versions['fakebts'] = self.conf['gsm_version']
        return versions
Exemplo n.º 24
0
 def __init__(self):
     self.conf = ConfigDB()
     self.openbts = openbts.components.OpenBTS(
         socket_timeout=self.conf['bss_timeout'],
         cli_timeout=self.conf['bss_timeout'])
Exemplo n.º 25
0
 def __init__(self):
     self.conf = ConfigDB()
     self.interconnect_client = interconnect.endaga_ic(self.conf)
     self.worker = self.sms_worker
Exemplo n.º 26
0
 def __init__(self, response):
     self.conf = ConfigDB()
     self.eventstore = EventStore()
     r = self.validate(response)
     self.process(r)
Exemplo n.º 27
0
 def __init__(self):
     self._conf = ConfigDB()
Exemplo n.º 28
0
    def setUpClass(cls):
        """Generate one set of checkin data to be analyzed in the tests."""
        # Mock the requests module so we don't actually POST.
        cls.original_requests = core.interconnect.requests
        cls.mock_requests = mocks.MockRequests(200)
        core.interconnect.requests = cls.mock_requests
        # Mock subscriber
        cls.original_subscriber = core.interconnect.subscriber
        core.interconnect.subscriber = mocks.MockSubscriber()

        # Mock core.events for generating usage events and handling the checkin
        # response.
        cls.original_events = core.interconnect.events
        core.interconnect.events = mocks.MockEvents()
        # Mock snowflake.
        cls.original_snowflake = core.interconnect.snowflake
        cls.mock_uuid = '09031a16-6361-4a93-a934-24c990ef4b87'
        core.interconnect.snowflake = mocks.MockSnowflake(cls.mock_uuid)
        # Mock BTS for TMSIs
        cls.original_bts = core.interconnect.bts
        core.interconnect.bts = mocks.MockBTS()
        # Mock a lot the package version numbers that should be sent in the
        # checkin.
        config_db = ConfigDB()
        cls.package_versions = {
            'endaga': '1.2.3',
            'freeswitch': '2.3.4',
            'gsm': '3.4.5',
            'python-endaga-core': '4.5.6',
            'python-gsm': '5.6.7',
        }
        for key in cls.package_versions:
            config_db['%s_version' % key] = cls.package_versions[key]
        # Mock psutil for system utilization stats.
        cls.original_psutil = core.system_utilities.psutil
        utilization = {
            'cpu_percent': 20.1,
            'memory_percent': 33.3,
            'disk_percent': 52.2,
            'bytes_sent': 1234,
            'bytes_received': 5678,
        }
        core.system_utilities.psutil = mocks.MockPSUtil(utilization)

        # Create some fake events
        es = core.interconnect.events.EventStore()
        es.add(
            cls.original_events._create_event(imsi="IMSI123",
                                              old_credit=0,
                                              new_credit=100,
                                              reason="Foo",
                                              write=False))
        es.add(
            cls.original_events._create_event(imsi="IMSI123",
                                              old_credit=0,
                                              new_credit=100,
                                              reason="Foo",
                                              write=False))
        es.add(
            cls.original_events._create_event(imsi="IMSI321",
                                              old_credit=0,
                                              new_credit=100,
                                              reason="Foo",
                                              write=False))

        # Setup a secret key.
        config_db['bts_secret'] = cls.mock_uuid
        # Attempt a checkin.
        config_db = core.config_database.ConfigDB()
        cls.endaga_ic = core.interconnect.endaga_ic(config_db)
        cls.endaga_ic.checkin()
        # Get the POSTed data and a deserialized form for convenience.
        cls.data = cls.mock_requests.post_data
        cls.deserialized_status = json.loads(cls.data['status'])