示例#1
0
def get_state(breadcrumbs, k):
    '''
    build a state request message, send and return the result

    breadcrumbs - breadcrumbs dict
    k - key for pertinent breadcrumb
    '''
    msgTx = bc_common.build_msg(breadcrumbs, k)
    msgTx.state.Clear()
    bc_common.send_msg(breadcrumbs, k, msgTx)

    msgRx = bc_common.recv_msg(breadcrumbs, k)

    return msgRx
示例#2
0
def get_file(breadcrumbs, k, task_id):
    '''
    build a file download request message, send and return the result

    breadcrumbs - breadcrumbs dict
    k - key for pertinent breadcrumb
    '''
    msgTx = bc_common.build_msg(breadcrumbs, k)
    msgTx.taskOutputRequest.position = 0
    msgTx.taskOutputRequest.maximumDataSize = 65535
    msgTx.taskOutputRequest.id = task_id
    bc_common.send_msg(breadcrumbs, k, msgTx)

    msgRx = bc_common.recv_msg(breadcrumbs, k)

    return msgRx
示例#3
0
def set_name(breadcrumbs, k, name):
    '''
    change the name of a breadcrumb

    breadcrumbs - breadcrumbs dict
    k - key for pertinent breadcrumb
    name - new name for breadcrumb
    '''
    msgTx = bc_common.build_msg(breadcrumbs, k)
    msgTx.config.general.name = name

    bc_common.send_msg(breadcrumbs, k, msgTx)

    msgRx = bc_common.recv_msg(breadcrumbs, k)

    return msgRx
示例#4
0
def set_watch(breadcrumbs, k, watches, interval=5):
    '''
    build a watch request message, send and return the result

    breadcrumbs - breadcrumbs dict
    k - key for pertinent breadcrumb
    watches - list of BCMessage paths to watch (assuming state. prefix)
    interval - interval to ask for them to be watch
    '''
    msgTx = bc_common.build_msg(breadcrumbs, k)
    for w in watches:
        watchObj = msgTx.watchRequest.watchObject.add()
        watchObj.messagePath = w
        watchObj.interval = interval

    bc_common.send_msg(breadcrumbs, k, msgTx)

    msgRx = bc_common.recv_msg(breadcrumbs, k)

    return msgRx
示例#5
0
def get_trace(breadcrumbs, k, ip):
    '''
    build a trace request message, send and return the result

    breadcrumbs - breadcrumbs dict
    k - key for pertinent breadcrumb
    '''
    msgTx = bc_common.build_msg(breadcrumbs, k)
    tasks = {
        k: v for
        k, v in
        Message_pb2.Common_pb2.TaskCommand.TaskAction.items()
    }
    msgTx.runTask.action = tasks['TRACE']
    msgTx.runTask.arguments = ip
    bc_common.send_msg(breadcrumbs, k, msgTx)

    msgRx = bc_common.recv_msg(breadcrumbs, k)

    return msgRx
示例#6
0
def reboot(breadcrumbs, k):
    '''
    reboot a breadcrumb

    breadcrumbs - breadcrumbs dict
    k - key for pertinent breadcrumb
    '''
    msgTx = bc_common.build_msg(breadcrumbs, k)
    tasks = {
        k: v for
        k, v in
        Message_pb2.Common_pb2.TaskCommand.TaskAction.items()
    }
    msgTx.runTask.action = tasks['REBOOT']

    bc_common.send_msg(breadcrumbs, k, msgTx)

    msgRx = bc_common.recv_msg(breadcrumbs, k)

    return msgRx
示例#7
0
def gatherer(breadcrumbs, k, trace_ip):
    '''
    designed to be spawned as a thread; loops around and gathers all the BC
    stats

    breadcrumbs - breadcrumbs dict
    k - key for pertinent breadcrumb
    trace_ip - ip address of trace target
    '''
    pnow = datetime.datetime.now()
    print pnow,  'gatherer - started', k
    first_run = True
    stat = {
        'timestamp': None,
        'ip': '',
        'name': '',
        'wireless': {},
        'wired': {},
        'nexthop_mac': '',
        'nexthop_via': ''
    }

    while 1:
        try:
            bc_common.connect(
                breadcrumbs,
                k,
                role='ADMIN',
                password='******'
            )
        except:
            pnow = datetime.datetime.now()
            print pnow,  'gatherer - connect failed', k
            time.sleep(5)
            continue
        while 1:
            # build stat structure
            now = datetime.datetime.now()
            stat['timestamp'] = now

            # get complete breadcrumb state first time, set watch for updates
            if first_run:
                # get full state
                try:
                    response = bc_query.get_state(breadcrumbs, k)
                    first_run = False
                except:
                    traceback.print_exc()
                    pnow = datetime.datetime.now()
                    print pnow,  'gatherer - get_state failed', k
                    break

                # setup watch
                try:
                    bc_query.set_watch(
                        breadcrumbs,
                        k,
                        [
                            'system.ipv4',
                            'wired',
                            'wireless',
                            'task',
                            'configuration.saved.general.name'
                        ],
                        8  # watch response interval
                    )
                except:
                    pnow = datetime.datetime.now()
                    print pnow,  'gatherer - set_watch failed', k
                    break

            else:
                # block until watch response received
                try:
                    response = bc_common.recv_msg(breadcrumbs, k).watchResponse
                except:
                    pnow = datetime.datetime.now()
                    print pnow,  'gatherer - recv_msg failed', k
                    break

            # get ip
            stat['ip'] = breadcrumbs[k]['ip']

            # get name
            name = response.state.configuration.saved.general.name
            if name != '':
                stat['name'] = name

            # get wired data
            for wv in response.state.wired:
                try:
                    wmac = ':'.join([
                        str(hex(x)).split('x')[1].zfill(2)
                        for x in struct.unpack("BBBBBB", wv.mac)
                    ])
                except:
                    continue
                if wmac not in stat['wired']:
                    stat['wired'][wmac] = {}
                stat['wired'][wmac].update({
                    'name': wv.name,
                    'rx_bytes': wv.stats.rxBytes,
                    'tx_bytes': wv.stats.txBytes,
                })

            # get wireless data
            for wv in response.state.wireless:
                try:
                    wmac = ':'.join([
                        str(hex(x)).split('x')[1].zfill(2)
                        for x in struct.unpack("BBBBBB", wv.mac)
                    ])
                except:
                    continue
                if wmac not in stat['wireless']:
                    stat['wireless'][wmac] = {'peers': {}}
                stat['wireless'][wmac].update({
                    'name': wv.name,
                    'noise': wv.noise,
                    'channel': wv.channel,
                    'txpower': wv.txpower,
                    'tx_bytes': wv.stats.txBytes,
                    'rx_bytes': wv.stats.rxBytes,
                    'peers': {}
                })
                # get peer data
                for pv in wv.peer:
                    try:
                        pmac = ':'.join([
                            str(hex(x)).split('x')[1].zfill(2)
                            for x in struct.unpack("BBBBBB", pv.mac)
                        ])
                    except:
                        continue
                    if pmac not in stat['wireless'][wmac]['peers']:
                        stat['wireless'][wmac]['peers'][pmac] = {}
                    stat['wireless'][wmac]['peers'][pmac].update({
                        'cost': pv.cost,
                        'rate': pv.rate / 10,
                        'rssi': pv.signal
                    })

            # make sure trace succeeded
            need_to_trace = False
            tasks = {
                v: k for k, v in
                Common_pb2.TaskCommand.TaskAction.items()
            }
            statuses = {
                v: k for k, v in
                Common_pb2.TaskStatus.TaskState.items()
            }
            if tasks[response.state.task.command.action] != 'TRACE':
                pnow = datetime.datetime.now()
                print pnow,  'gatherer - last task not trace', k, '(%s)' % (
                    tasks[response.state.task.command.action]
                )
                need_to_trace = True
            elif statuses[response.state.task.status.state] in [
                                                                'DELAYED',
                                                                'QUEUED',
                                                                'RUNNING'
                                                            ]:
                pnow = datetime.datetime.now()
                print pnow,  'gatherer - trace still underway', k, '(%s)' % (
                    statuses[response.state.task.status.state]
                )
                need_to_trace = False
            elif statuses[response.state.task.status.state] == 'FAILED':
                pnow = datetime.datetime.now()
                print pnow,  'gatherer - trace failed', k, '(%s)' % (
                    statuses[response.state.task.status.state]
                )
                need_to_trace = True
            elif statuses[response.state.task.status.state] == 'SUCCESS':
                # go and get the gzip'd trace dump
                try:
                    response = bc_query.get_file(
                        breadcrumbs,
                        k,
                        response.state.task.status.id
                    )
                except:
                    break
                statuses = {
                    v: k for k, v in
                    Common_pb2.TaskOutputResponse.Status.items()
                }
                if statuses[response.taskOutputResponse.status] != 'SUCCESS':
                    pnow = datetime.datetime.now()
                    print pnow,  'download failed'
                    continue

                # decompress the trace dump
                zfile = StringIO.StringIO()
                zfile.write(response.taskOutputResponse.data)
                zfile.seek(0)
                try:
                    data = gzip.GzipFile(
                        fileobj=zfile, mode='rb'
                    ).read().strip()
                except:
                    traceback.print_exc()
                    pnow = datetime.datetime.now()
                    print pnow,  'gunzip failed'
                    continue

                # parse the trace dump
                lines = data.split('\n')[2:]
                if len(lines) > 0:
                    if 'peer=' in lines[0]:
                        stat['nexthop_via'] = 'mesh'  # mesh/failed backhaul
                        stat['nexthop_mac'] = lines[0].split(
                            'peer='
                        )[1].split('/')[0].lower()
                    else:
                        stat['nexthop_via'] = 'wire'  # ingress/has backhaul
                        stat['nexthop_mac'] = lines[0].split()[2].lower()

                need_to_trace = True

            if need_to_trace:
                # request a trace task (only returns status of request)
                try:
                    response = bc_query.get_trace(breadcrumbs, k, trace_ip)
                    time.sleep(5)
                except:
                    pnow = datetime.datetime.now()
                    print pnow,  'gatherer - get_trace failed', k
                    break

            if 'stats' not in breadcrumbs[k]:
                breadcrumbs[k]['stats'] = []

            breadcrumbs[k]['stats'] += [stat]

            breadcrumbs[k]['stats'] = breadcrumbs[k]['stats'][-2:]

            pnow = datetime.datetime.now()
            print pnow,  'gatherer - got stats for', k

            snooze = 8 - (datetime.datetime.now() - now).total_seconds()

            time.sleep(snooze if snooze >= 0 else 0)

        try:
            bc_common.disconnect(
                breadcrumbs,
                k
            )
        except:
            pnow = datetime.datetime.now()
            print pnow,  'gatherer - connect failed', k
            time.sleep(5)
            continue

        time.sleep(4)
示例#8
0
def gatherer(breadcrumbs, k, trace_ip):
    '''
    designed to be spawned as a thread; loops around and gathers all the BC
    stats

    breadcrumbs - breadcrumbs dict
    k - key for pertinent breadcrumb
    trace_ip - ip address of trace target
    '''
    pnow = datetime.datetime.now()
    print pnow, 'gatherer - started', k
    first_run = True
    stat = {
        'timestamp': None,
        'ip': '',
        'name': '',
        'wireless': {},
        'wired': {},
        'nexthop_mac': '',
        'nexthop_via': ''
    }

    while 1:
        try:
            bc_common.connect(breadcrumbs,
                              k,
                              role='ADMIN',
                              password='******')
        except:
            pnow = datetime.datetime.now()
            print pnow, 'gatherer - connect failed', k
            time.sleep(5)
            continue
        while 1:
            # build stat structure
            now = datetime.datetime.now()
            stat['timestamp'] = now

            # get complete breadcrumb state first time, set watch for updates
            if first_run:
                # get full state
                try:
                    response = bc_query.get_state(breadcrumbs, k)
                    first_run = False
                except:
                    traceback.print_exc()
                    pnow = datetime.datetime.now()
                    print pnow, 'gatherer - get_state failed', k
                    break

                # setup watch
                try:
                    bc_query.set_watch(
                        breadcrumbs,
                        k,
                        [
                            'system.ipv4', 'wired', 'wireless', 'task',
                            'configuration.saved.general.name'
                        ],
                        8  # watch response interval
                    )
                except:
                    pnow = datetime.datetime.now()
                    print pnow, 'gatherer - set_watch failed', k
                    break

            else:
                # block until watch response received
                try:
                    response = bc_common.recv_msg(breadcrumbs, k).watchResponse
                except:
                    pnow = datetime.datetime.now()
                    print pnow, 'gatherer - recv_msg failed', k
                    break

            # get ip
            stat['ip'] = breadcrumbs[k]['ip']

            # get name
            name = response.state.configuration.saved.general.name
            if name != '':
                stat['name'] = name

            # get wired data
            for wv in response.state.wired:
                try:
                    wmac = ':'.join([
                        str(hex(x)).split('x')[1].zfill(2)
                        for x in struct.unpack("BBBBBB", wv.mac)
                    ])
                except:
                    continue
                if wmac not in stat['wired']:
                    stat['wired'][wmac] = {}
                stat['wired'][wmac].update({
                    'name': wv.name,
                    'rx_bytes': wv.stats.rxBytes,
                    'tx_bytes': wv.stats.txBytes,
                })

            # get wireless data
            for wv in response.state.wireless:
                try:
                    wmac = ':'.join([
                        str(hex(x)).split('x')[1].zfill(2)
                        for x in struct.unpack("BBBBBB", wv.mac)
                    ])
                except:
                    continue
                if wmac not in stat['wireless']:
                    stat['wireless'][wmac] = {'peers': {}}
                stat['wireless'][wmac].update({
                    'name': wv.name,
                    'noise': wv.noise,
                    'channel': wv.channel,
                    'txpower': wv.txpower,
                    'tx_bytes': wv.stats.txBytes,
                    'rx_bytes': wv.stats.rxBytes,
                    'peers': {}
                })
                # get peer data
                for pv in wv.peer:
                    try:
                        pmac = ':'.join([
                            str(hex(x)).split('x')[1].zfill(2)
                            for x in struct.unpack("BBBBBB", pv.mac)
                        ])
                    except:
                        continue
                    if pmac not in stat['wireless'][wmac]['peers']:
                        stat['wireless'][wmac]['peers'][pmac] = {}
                    stat['wireless'][wmac]['peers'][pmac].update({
                        'cost':
                        pv.cost,
                        'rate':
                        pv.rate / 10,
                        'rssi':
                        pv.signal
                    })

            # make sure trace succeeded
            need_to_trace = False
            tasks = {
                v: k
                for k, v in Common_pb2.TaskCommand.TaskAction.items()
            }
            statuses = {
                v: k
                for k, v in Common_pb2.TaskStatus.TaskState.items()
            }
            if tasks[response.state.task.command.action] != 'TRACE':
                pnow = datetime.datetime.now()
                print pnow, 'gatherer - last task not trace', k, '(%s)' % (
                    tasks[response.state.task.command.action])
                need_to_trace = True
            elif statuses[response.state.task.status.state] in [
                    'DELAYED', 'QUEUED', 'RUNNING'
            ]:
                pnow = datetime.datetime.now()
                print pnow, 'gatherer - trace still underway', k, '(%s)' % (
                    statuses[response.state.task.status.state])
                need_to_trace = False
            elif statuses[response.state.task.status.state] == 'FAILED':
                pnow = datetime.datetime.now()
                print pnow, 'gatherer - trace failed', k, '(%s)' % (
                    statuses[response.state.task.status.state])
                need_to_trace = True
            elif statuses[response.state.task.status.state] == 'SUCCESS':
                # go and get the gzip'd trace dump
                try:
                    response = bc_query.get_file(breadcrumbs, k,
                                                 response.state.task.status.id)
                except:
                    break
                statuses = {
                    v: k
                    for k, v in Common_pb2.TaskOutputResponse.Status.items()
                }
                if statuses[response.taskOutputResponse.status] != 'SUCCESS':
                    pnow = datetime.datetime.now()
                    print pnow, 'download failed'
                    continue

                # decompress the trace dump
                zfile = StringIO.StringIO()
                zfile.write(response.taskOutputResponse.data)
                zfile.seek(0)
                try:
                    data = gzip.GzipFile(fileobj=zfile,
                                         mode='rb').read().strip()
                except:
                    traceback.print_exc()
                    pnow = datetime.datetime.now()
                    print pnow, 'gunzip failed'
                    continue

                # parse the trace dump
                lines = data.split('\n')[2:]
                if len(lines) > 0:
                    if 'peer=' in lines[0]:
                        stat['nexthop_via'] = 'mesh'  # mesh/failed backhaul
                        stat['nexthop_mac'] = lines[0].split('peer=')[1].split(
                            '/')[0].lower()
                    else:
                        stat['nexthop_via'] = 'wire'  # ingress/has backhaul
                        stat['nexthop_mac'] = lines[0].split()[2].lower()

                need_to_trace = True

            if need_to_trace:
                # request a trace task (only returns status of request)
                try:
                    response = bc_query.get_trace(breadcrumbs, k, trace_ip)
                    time.sleep(5)
                except:
                    pnow = datetime.datetime.now()
                    print pnow, 'gatherer - get_trace failed', k
                    break

            if 'stats' not in breadcrumbs[k]:
                breadcrumbs[k]['stats'] = []

            breadcrumbs[k]['stats'] += [stat]

            breadcrumbs[k]['stats'] = breadcrumbs[k]['stats'][-2:]

            pnow = datetime.datetime.now()
            print pnow, 'gatherer - got stats for', k

            snooze = 8 - (datetime.datetime.now() - now).total_seconds()

            time.sleep(snooze if snooze >= 0 else 0)

        try:
            bc_common.disconnect(breadcrumbs, k)
        except:
            pnow = datetime.datetime.now()
            print pnow, 'gatherer - connect failed', k
            time.sleep(5)
            continue

        time.sleep(4)