Example #1
0
def updatedhcpd(path='/etc/dhcp/dhcpd.conf',
                interface='wlan0',
                gateway='192.168.8.1',
                dhcpstart='192.168.8.70',
                dhcpend='192.168.8.99'):
    from iiutilities import dblib
    from cupid import pilib
    try:
        netconfigdata = dblib.readonedbrow(pilib.dirs.dbs.system,
                                           'netconfig')[0]
        dhcpstart = netconfigdata['dhcpstart']
        dhcpend = netconfigdata['dhcpend']
        gateway = netconfigdata['gateway']
    except:
        # print('we had an error')
        pass

    myfile = open(path, 'w')

    try:
        subnet = '.'.join(gateway.split['.'][:-1]) + '.0'
    except:
        subnet = '192.168.8.0'

    filestring = 'ddns-update-style none;\noption domain-name "example.org";\n'
    filestring += 'option domain-name-servers ns1.example.org, ns2.example.org;\n'
    filestring += 'default-lease-time 600;\nmax-lease-time 7200;\nauthoritative;\nlog-facility local7;\n'
    filestring += 'subnet ' + subnet + ' netmask 255.255.255.0 {\n'
    filestring += 'range ' + dhcpstart + ' ' + dhcpend + ';\n'
    filestring += '  option domain-name-servers 8.8.8.8, 8.8.4.4;\n  option routers ' + gateway + ';\n'
    filestring += ' interface ' + interface + ';\n}'

    myfile.write(filestring)
Example #2
0
def updatehostapd(path='/etc/hostapd/hostapd.conf', interface='wlan0'):

    from iiutilities import dblib
    from cupid import pilib

    piversion = dblib.getsinglevalue(pilib.dirs.dbs.system, 'versions',
                                     'versionname')
    try:
        apsettings = dblib.readonedbrow(pilib.dirs.dbs.safe, 'apsettings')[0]
        print(apsettings)
        SSID = apsettings['SSID']
        password = apsettings['password']
    except:
        SSID = 'cupidwifi'
        password = '******'

    # print(SSID)
    myfile = open(path, 'w')
    filestring = 'interface=' + interface + '\n'

    # In these versions, we had to use an alternate driver. No more!! Built-in RPi 3 fixes this garbage.
    # Hostapd works out of the box. About time.

    if piversion in ['Pi 2 Model B', 'Model B Revision 2.0', 'Model B+']:
        filestring += 'driver=rtl871xdrv\nssid='
    else:
        filestring += 'driver=nl80211\nssid='

    filestring += SSID
    filestring += '\nchannel=6\nwmm_enabled=1\nwpa=1\nwpa_passphrase=' + password + '\nwpa_key_mgmt=WPA-PSK\n'
    filestring += 'wpa_pairwise=TKIP\nrsn_pairwise=CCMP\nauth_algs=1\nmacaddr_acl=0'

    myfile.write(filestring)
Example #3
0
def application(environ, start_response):
    import cgi
    import json
    import hashlib

    # Set top folder to allow import of modules

    import os, sys, inspect

    top_folder = \
        os.path.split(os.path.realpath(os.path.abspath(os.path.split(inspect.getfile(inspect.currentframe()))[0])))[0]
    if top_folder not in sys.path:
        sys.path.insert(0, top_folder)

    import ii_netstats

    from iiutilities import dblib, datalib
    from iiutilities.utility import newunmangle
    from time import time

    # post_env = environ.copy()
    # post_env['QUERY_STRING'] = ''
    # post = cgi.FieldStorage(
    #     fp=environ['wsgi.input'],
    #     environ=post_env,
    #     keep_blank_values=True
    # )
    # formname = post.getvalue('name')
    #
    # output = {}
    #
    # d = {}
    # for k in post.keys():
    #     # print(k)
    #     d[k] = post.getvalue(k)

    try:
        request_body_size = int(environ.get('CONTENT_LENGTH', 0))
    except ValueError:
        request_body_size = 0

    request_body = environ['wsgi.input'].read(request_body_size)
    post = json.loads(request_body.decode('utf-8'))

    status = '200 OK'
    output = {'data': [], 'message': ''}

    d = post

    wsgiauth = False
    authverified = False

    if wsgiauth:
        # Verfiy that session login information is legit: hashed password, with salt and username, match
        # hash stored in database.
        import hashlib

        if 'sessionuser' in d:
            output['message'] += 'Session user is ' + d['sessionuser'] + '. '
        else:
            output['message'] += 'No session user found. '
            d['sessionuser'] = ''

        try:
            condition = "name='" + d['sessionuser'] + "'"
            userdata = dblib.readonedbrow(inventorylib.sysvars.dirs.dbs.safe,
                                          'users',
                                          condition=condition)[0]
        except:
            output[
                'message'] += 'error in user sqlite query for session user "' + d[
                    'sessionuser'] + '". '
            userdata = {'accesskeywords': 'demo', 'admin': False}
        else:
            # Get session hpass to verify credentials
            hashedpassword = d['sessionhpass']
            hname = hashlib.new('sha1')
            hname.update(d['sessionuser'])
            hashedname = hname.hexdigest()
            hentry = hashlib.new('md5')
            hentry.update(hashedname + netstats.salt + hashedpassword)
            hashedentry = hentry.hexdigest()
            if hashedentry == userdata['password']:
                # successful auth
                output['message'] += 'Password verified. '
                authverified = True
    else:
        output['message'] += 'WSGI authorization not enabled. '

    if authverified or not wsgiauth:
        try:
            action = d['action']
        except KeyError:
            output['message'] = 'no action in request'
        else:
            # Stock functions
            if action == 'getnetstatsdata':
                output['message'] += 'getting netstats keyword found. '
                import datetime
                the_day = datetime.date.today()
                if 'day' in d:
                    # We will pass in a day in format yyyy-mm-dd or keywords, like 'today'
                    import datetime, time
                    today = datetime.date.today()
                    if d['day'] == 'today':
                        pass
                    elif d['day'] == 'prev_day':
                        the_day = today - datetime.timedelta(days=1)
                    elif d['day'] == 'prev_2_day':
                        the_day = today - datetime.timedelta(days=2)
                    elif d['day'] == 'prev_3_day':
                        the_day = today - datetime.timedelta(days=3)
                    elif d['day'] == 'prev_4_day':
                        the_day = today - datetime.timedelta(days=4)

                if the_day == datetime.date.today():
                    db_path = ii_netstats.netstats_dbpath
                else:
                    db_path_root = ii_netstats.netstats_dbpath.split('.db')[0]
                    date_string = '{}-{:02d}-{:02d}'.format(
                        the_day.year, the_day.month, the_day.day)
                    db_path = '{}_{}.db'.format(db_path_root, date_string)

                print('** DBPATH: {} '.format(db_path))
                netstats_db = dblib.sqliteDatabase(db_path)

                output['message'] += 'db path {} chosen. '.format(db_path)

                wired_history = netstats_db.read_table('wired')
                if 'dataperiod' in d:
                    output['message'] += 'Limiting returned time to ' + d[
                        'dataperiod'] + '. '
                    # default 6hrs
                    period = 6 * 3600
                    if d['dataperiod'] == '6_hrs':
                        period = 6 * 3600
                    elif d['dataperiod'] == '12_hrs':
                        period = 12 * 3600
                    elif d['dataperiod'] == '24_hrs':
                        period = 24 * 3600
                    elif d['dataperiod'] == '48_hrs':
                        period = 48 * 3600
                    elif d['dataperiod'] == '7_days':
                        period = 7 * 24 * 3600

                    unmodified_length = len(wired_history)

                    # return only data within last period
                    from operator import itemgetter
                    from iiutilities.datalib import timestringtoseconds
                    new_list = sorted(wired_history,
                                      key=itemgetter('time'),
                                      reverse=True)

                    output['message'] += 'Most recent data point: ' + new_list[
                        0]['time'] + '. '
                    new_history = []
                    most_recent_time_in_seconds = timestringtoseconds(
                        new_list[0]['time'])
                    output['message'] += 'Most recent time in seconds ' + str(
                        most_recent_time_in_seconds) + '. '

                    output['message'] += 'Oldest time in seconds ' + str(
                        timestringtoseconds(new_list[-1]['time']))
                    output['message'] += 'Span of ' + str(
                        most_recent_time_in_seconds -
                        timestringtoseconds(new_list[-1]['time'])) + '. '
                    output['message'] += 'Period of ' + str(period) + '. '

                    for item in new_list:
                        if most_recent_time_in_seconds - timestringtoseconds(
                                item['time']) < period:
                            new_history.append(item)
                    output['data'] = new_history
                    modified_length = len(wired_history)

                    output['message'] += 'Shortened data from ' + str(
                        unmodified_length) + ' to ' + str(modified_length)
                else:
                    output['data'] = wired_history
                try:
                    from urllib2 import urlopen
                    my_ip = urlopen('http://ip.42.pl/raw').read()
                except:
                    my_ip = 'unknown'
                output['host'] = my_ip
            elif action == 'gettraffichistodata':
                output['message'] += 'gettraffic histo keyword found. '
                access_db = dblib.sqliteDatabase(ii_netstats.access_dbpath)

                access_db_tablenames = access_db.get_table_names()
                # output['message'] += 'Tables to search through: ' + str(access_db_tablenames) + '. '

                tables_to_fetch = []
                for tablename in access_db_tablenames:
                    if tablename.find('remotehisto') >= 0 or tablename.find(
                            'metadata') >= 0:
                        tables_to_fetch.append(tablename)
                # output['message'] += 'Fetching tables ' + str(tables_to_fetch) + '. '
                output['data'] = {}
                for table_to_fetch in tables_to_fetch:
                    output['data'][table_to_fetch] = access_db.read_table(
                        table_to_fetch)

            elif action == 'postwirelessdata':
                output['message'] += 'postwirelessdata keyword found. '

                # nothing here yet

    if 'data' in output:
        if output['data']:
            newetag = hashlib.md5(str(output['data'])).hexdigest()
            if 'etag' in d:
                if newetag == d['etag']:
                    status = '304 Not Modified'
                    output['data'] = ''
        else:
            newetag = ''
    else:
        newetag = ''

    if 'datasize' in d:
        output['datasize'] = sys.getsizeof(output['data'])

    output['etag'] = newetag
    try:
        foutput = json.dumps(output, indent=1)
    except:
        import csv
        w = csv.writer(
            open("/usr/lib/iicontrollibs/inventory/dumperr.log", "w"))
        for key, val in output.items():
            w.writerow([key, val])

    response_headers = [('Content-type', 'application/json')]
    response_headers.append(('Etag', newetag))
    start_response(status, response_headers)

    return [foutput]
Example #4
0
def runboot():
    import subprocess
    from time import sleep

    import pilib
    import spilights
    from iiutilities import utility, dblib, datalib

    try:
        pilib.set_all_wal(False)
    except:
        print('error setting wal mode')

    interfaces = pilib.dbs.control.read_table('interfaces')

    # Clear out status bits, if for no other reason to see the LEDs come on
    for statusvalue in [
            'systemstatusstatus', 'hamachistatus', 'picontrolstatus',
            'updateiostatus', 'serialhandlerstatus'
    ]:
        dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemstatus',
                             statusvalue, 0)

    systemstatus = dblib.readonedbrow(pilib.dirs.dbs.system, 'systemstatus')[0]

    # Queue a message indicating we are rebooting
    # TODO: Make this an actions option, or put it somewhere.
    # try:
    import socket
    hostname = socket.gethostname()

    message = 'CuPID is booting:\r\n\r\n'
    notifications_email = '*****@*****.**'
    subject = 'CuPID : ' + hostname + ' : booting'
    notification_database = pilib.cupidDatabase(pilib.dirs.dbs.notifications)
    system_database = pilib.cupidDatabase(pilib.dirs.dbs.system)

    currenttime = datalib.gettimestring()
    notification_database.insert(
        'queued', {
            'type': 'email',
            'message': message,
            'options': 'email:' + notifications_email + ',subject:' + subject,
            'queuedtime': currenttime
        })
    system_database.set_single_value('notifications',
                                     'lastnotification',
                                     currenttime,
                                     condition="item='boot'")

    # except Exception as e:
    #     error_message = 'EXCEPTION in notification: {}'.format(e.message)
    #     print (error_message)
    #     utility.log(pilib.dirs.logs.system, error_message)
    # else:
    #     utility.log(pilib.dirs.logs.system, 'Boot notificaiton complete. ')

    # Start pigpiod

    subprocess.call(['killall', 'pigpiod'])
    sleep(1)
    utility.log(pilib.dirs.logs.system, 'boot: starting pigpio daemon', 3,
                pilib.loglevels.system)
    subprocess.call(['/usr/local/bin/pigpiod'])

    # Start webserver

    subprocess.call(['killall', 'nginx'])
    subprocess.call(['killall', 'uwsgi'])
    subprocess.call(['killall', 'apache2'])

    if systemstatus['webserver'] == 'apache':
        utility.log(pilib.dirs.logs.system, 'boot: starting apache', 3,
                    pilib.loglevels.system)
        subprocess.call(['service', 'apache2', 'start'])
    elif systemstatus['webserver'] == 'nginx':
        utility.log(pilib.dirs.logs.system, 'boot: starting nginx', 3,
                    pilib.loglevels.system)
        subprocess.call(['service', 'nginx', 'start'])

    # Run uwsgi daemon if nginx is running

    try:
        result = subprocess.check_output(['service', 'nginx',
                                          'status']).decode('utf-8')
    except subprocess.CalledProcessError as e:
        result = ''
        # print('I AM FAILING')
        # print e.output

    if result:
        utility.log(pilib.dirs.logs.system,
                    'boot: starting uwsgi based on nginx call', 0)
        subprocess.call([
            'uwsgi', '--emperor', '/usr/lib/iicontrollibs/wsgi/',
            '--daemonize', '/var/log/cupid/uwsgi.log'
        ])
    else:
        # print(' I KNOW NGINX IS NOT RUNNING')
        pass
    # Mount 1wire master

    subprocess.call(['killall', 'owfs'])
    subprocess.call(['killall', 'owserver'])
    subprocess.call(['killall', 'owhttpd'])

    runi2cowfs = True
    runusbowfs = False

    temp_unit = 'C'
    for interface in interfaces:
        if interface['enabled']:
            from iiutilities.datalib import parseoptions
            options_dict = parseoptions(interface['options'])
            if 'tempunit' in options_dict:
                if options_dict['tempunit'] in [
                        'F', 'f', 'Fahrenheit', 'fahrenheit'
                ]:
                    temp_unit = 'F'

            if interface['interface'] == 'I2C' and interface[
                    'type'] == 'DS2483':
                runi2cowfs = True
            if interface['interface'] == 'USB' and interface[
                    'type'] == 'DS9490':
                runusbowfs = True

            if interface['interface'] == 'SPI1' and type == 'CuPIDlights':
                spilights.updatelightsfromdb(pilib.dirs.dbs.control,
                                             'indicators', 1)
            if interface['interface'] == 'SPI0' and type == 'CuPIDlights':
                spilights.updatelightsfromdb(pilib.dirs.dbs.control,
                                             'indicators', 0)

    if runi2cowfs or runusbowfs:
        if runi2cowfs:
            utility.log(pilib.dirs.logs.system, 'boot: Running i2c owserver',
                        3, pilib.loglevels.system)
            try:
                if temp_unit == 'F':
                    subprocess.call([
                        '/opt/owfs/bin/owserver', '-F', '--i2c=/dev/i2c-1:ALL',
                        '-p', '4304'
                    ])
                else:
                    subprocess.call([
                        '/opt/owfs/bin/owserver', '--i2c=/dev/i2c-1:ALL', '-p',
                        '4304'
                    ])
            except:
                utility.log(pilib.dirs.logs.system,
                            'boot: error running i2c owserver', 1,
                            pilib.loglevels.system)
        if runusbowfs:
            utility.log(pilib.dirs.logs.system, 'boot: Running usb owserver',
                        3, pilib.loglevels.system)
            try:
                if temp_unit == 'F':
                    subprocess.call(
                        ['/opt/owfs/bin/owserver', '-F', '-u', '-p', '4304'])
                else:
                    subprocess.call(
                        ['/opt/owfs/bin/owserver', '-u', '-p', '4304'])
            except:
                utility.log(pilib.dirs.logs.system,
                            'error running usb owserver', 1,
                            pilib.loglevels.system)

        utility.log(pilib.dirs.logs.system,
                    'boot: Running owfs/owserver mount', 3,
                    pilib.loglevels.system)
        try:
            if temp_unit == 'F':
                subprocess.call(
                    ['/opt/owfs/bin/owfs', '-F', '-s', '4304', '/var/1wire/'])
            else:
                subprocess.call(
                    ['/opt/owfs/bin/owfs', '-s', '4304', '/var/1wire/'])
        except:
            utility.log(pilib.dirs.logs.system, 'boot: error running owfs', 1,
                        pilib.loglevels.system)

        utility.log(pilib.dirs.logs.system,
                    'boot: Running owhttpd/owserver mount', 3,
                    pilib.loglevels.system)
        try:
            if temp_unit == 'F':
                subprocess.call([
                    '/opt/owfs/bin/owhttpd', '-F', '-s', '4304', '-p', '4305'
                ])
            else:
                subprocess.call(
                    ['/opt/owfs/bin/owhttpd', '-s', '4304', '-p', '4305'])
        except:
            utility.log(pilib.dirs.logs.system, 'boot: error running owhttpd',
                        1, pilib.loglevels.system)

    else:
        utility.log(pilib.dirs.logs.system, 'boot: not running owfs', 3,
                    pilib.loglevels.system)

    # Run netstart script if enabled
    if systemstatus['netconfigenabled']:
        from netconfig import runconfig
        utility.log(pilib.dirs.logs.system, 'boot: running boot netconfig', 2,
                    pilib.loglevels.system)
        runconfig(onboot=True)
Example #5
0
def monitor(**kwargs):

    settings = {
        'port': None,
        'baudrate': 115200,
        'timeout': 1,
        'checkstatus': True,
        'printmessages': False,
        'debug': True
    }
    settings.update(kwargs)

    if not settings['port']:
        settings['port'] = getsystemserialport()

    import serial
    from iiutilities import datalib, dblib
    from time import mktime, localtime
    from time import sleep

    motes_db = pilib.dbs.motes
    system_db = pilib.dbs.system

    if settings['debug']:
        pilib.set_debug()
    if settings['printmessages']:
        print('Message printing is enabled.')

    data = []

    stringmessage = ''
    seriallog = True
    if seriallog:
        print('serial logging is enabled.')
        logfile = open(pilib.dirs.logs.serial, 'a', 1)
        logfile.write('\n' + datalib.gettimestring() +
                      ": Initializing serial log\n")

    if settings['checkstatus']:
        systemstatus = system_db.read_table_row('systemstatus')[0]
        runhandler = systemstatus['serialhandlerenabled']
        checktime = mktime(localtime())
        checkfrequency = 15  # seconds
        if runhandler:
            utility.log(
                pilib.dirs.logs.io,
                "Starting monitoring of serial port based on check status", 1,
                pilib.loglevels.io)
        else:
            utility.log(
                pilib.dirs.logs.io,
                "Not starting monitoring of serial port. How did I get here?",
                1, pilib.loglevels.serial)
    else:
        runhandler = True

    if runhandler:
        ser = serial.Serial(port=settings['port'],
                            baudrate=settings['baudrate'],
                            timeout=settings['timeout'])
        utility.log(
            pilib.dirs.logs.io,
            "Monitoring serial port {}, settings {}/{}".format(
                ser.name, settings['baudrate'],
                settings['timeout']), 1, pilib.loglevels.serial)
    else:
        utility.log(pilib.dirs.logs.io, 'not monitoring serial port ', 1,
                    pilib.loglevels.serial)
    while runhandler:
        # This reading has to happen faster than the messages come, or they will all be stuck together
        try:
            ch = ser.read(1).decode('utf-8')
            # if ch == '\x0D':
            #     print('carriage return')
            # elif ch == '\x00':
            #     print('null character')

            if len(ch) == 0 or ch == '\x0D':
                utility.log(pilib.dirs.logs.io, 'Time to process message ', 5,
                            pilib.loglevels.serial)

                # rec'd nothing print all
                if len(
                        data
                ) > 1:  # This will avoid processing endline characters and other trash.
                    s = ''
                    for x in data:
                        s += '%s' % x  # ord(x)

                    # clear data

                    data = []
                    # Here for diagnostics
                    # print '%s [len = %d]' % (s, len(data))

                    # now process data
                    # print(s)
                    # print(s.split('\n'))
                    try:
                        utility.log(
                            pilib.dirs.logs.serial,
                            'processing datadict from serial message of length {}'
                            .format(len(data)), 3, pilib.loglevels.serial)
                        datadicts, messages = processserialdata(s)
                    except:
                        import traceback
                        message = "An exception of occurred (line 99): {}".format(
                            traceback.format_exc())
                        utility.log(pilib.dirs.logs.serial, message, 1,
                                    pilib.loglevels.serial)

                    else:
                        for datadict, message in zip(datadicts, messages):
                            if datadict:
                                if (settings['printmessages']):
                                    print("datadict: ")
                                    print(datadict)
                                # print("message: ")
                                # print(message)

                                # publish = False
                                # for k in datadict:
                                #     # print(k + datadict[k])
                                #     if k not in ['nodeid','RX_RSSI']:
                                #         pass
                                # if 'cmd' in datadict:
                                publish = True
                                if publish:
                                    if (settings['printmessages']):
                                        print('publishing message: ')
                                        print(message)
                                    lograwmessages(message)

                                motes_db.size_table('read', **{'size': 1000})
                                try:
                                    processremotedata(datadict, message)
                                except:
                                    import traceback
                                    message = "An exception of occurred (line 184): {}".format(
                                        traceback.format_exc())
                                    utility.log(pilib.dirs.logs.serial,
                                                message, 1,
                                                pilib.loglevels.serial)

                            else:
                                if message and settings['printmessage']:
                                    print('message: \n{}'.format(message))
                                    print(message)

                            # Log message
                            if seriallog:
                                try:
                                    logfile.write(datalib.gettimestring() +
                                                  ' : ' + message + '\n')
                                except:
                                    import traceback
                                    message = "An exception of occurred (line 198): {}".format(
                                        traceback.format_exc())
                                    utility.log(pilib.dirs.logs.serial,
                                                message, 1,
                                                pilib.loglevels.serial)

                else:
                    # no data, let's see if we should send message
                    utility.log(pilib.dirs.logs.serial, 'No data, try sending',
                                1, pilib.loglevels.serial)

                # print('CLEARING DATA !!!')
                data = []
                # try:
                #     utility.log(pilib.dirs.logs.serial, "Attempting send routine", 4, pilib.loglevels.serial)
                # except Exception as e:
                #     template = "An exception of type {0} occured while doing some serial logging. Arguments:\n{1!r}"
                #     message = template.format(type(ex).__name__, ex.args)
                #     print message

                # See if there are messages to send.
                # print('LET US TRY SEND HANDLER')
                try:
                    queue_commands()
                except:
                    import traceback
                    print('ERROR IN QUEUE COMMANDS \n {}'.format(
                        traceback.format_exc()))

                try:
                    runsendhandler(ser)
                except:
                    import traceback
                    template = "An exception of in runsendhandler (line 142): {} .".format(
                        traceback.format_exc())
                    utility.log(pilib.dirs.logs.serial,
                                "Error in send routine: {}".format(template),
                                1, 1)
                # print('SEND HANDLER DONE')

                #
                #     template = "An exception of type {0} occured. Arguments:\n{1!r}"
                #     message = template.format(type(ex).__name__, ex.args)
                #     pilib.log(pilib.dirs.logs.serial, message, 1, 1)

            else:
                # print('DATA NOT ZERO')
                # print(ch)
                data.append(ch)
                stringmessage += str(ch)

            if settings['checkstatus']:
                print('checking status')
                thetime = mktime(localtime())
                if thetime - checktime > checkfrequency:
                    print('checking control status')
                    systemstatus = dblib.readonedbrow(pilib.dirs.dbs.control,
                                                      'systemstatus')[0]
                    runserialhandler = systemstatus['serialhandlerenabled']
                    if runserialhandler:
                        checktime = thetime
                        utility.log(
                            pilib.dirs.logs.io,
                            'Continuing serialhandler based on status check',
                            3, pilib.loglevels.io)
                    else:
                        runhandler = False
                        utility.log(
                            pilib.dirs.logs.io,
                            'Aborting serialhandler based on status check', 3,
                            pilib.loglevels.io)
        except KeyboardInterrupt:
            print('\n Exiting on keyboard interrupt\n')
            logfile.close()
            return
        except:
            # print('no characters available!')
            sleep(0.5)
        #     return
        #runsendhandler(ser)

    logfile.close()
    ser.close()
    return
Example #6
0
def runconfig(**kwargs):
    from iiutilities import utility
    from cupid import pilib
    from iiutilities.datalib import gettimestring
    from iiutilities import dblib
    """
    Interfaces and modes

    Interfaces:         eth0 | wlan0 | wlan1
    Modes:        dhcp|  ok  |  --   |  --
                static|  ok  |  --   |  --

               station|  --  |  ok   |  ok
                    ap|  --  |  ok   |  ok 
    """

    settings = {
        'debug': False,
        'onboot': False,
        'config_all': False,
        'ifaces_to_configure': ['wlan0'],
        'config': {
            'eth0': {
                'enabled': True,
                'mode': 'dhcp'
            },
            'wlan0': {
                'enabled': True,
                'mode': 'station',
                'config': {
                    'network_select': ['name', 'strongest'],
                    'network': 'leHouse'
                }
            }
        },
        'use_default': False
    }
    settings.update(kwargs)
    if settings['debug']:
        pilib.set_debug()

    # Get from database
    # TODO : Used passed configuration data.

    if not settings['use_default']:
        import json
        netiface_config = pilib.dbs.system.read_table('netifaceconfig')

        if not netiface_config:
            message = 'netifaceconfig table empty or not found ! '
            utility.log(pilib.dirs.logs.network, message, 0,
                        pilib.loglevels.network)
            return {'status': 1, 'status_message': message}

        settings['config'] = {}
        for iface_config in netiface_config:
            settings['config'][iface_config['name']] = iface_config

            # unpack json dump of config details
            try:
                settings['config'][
                    iface_config['name']]['config'] = json.loads(
                        iface_config['config'])
            except:
                message = 'Config entry for interface {} is empty or cannot be unpacked as json: {}. '.format(
                    iface_config['name'], iface_config['config'])
                # print(settings['config'][iface_config['name']])
                utility.log(pilib.dirs.logs.network, message, 3,
                            pilib.loglevels.network)

    utility.log(pilib.dirs.logs.network, 'Updating ifconfig file. ', 0,
                pilib.loglevels.network)

    print('MAKING CONFIG FILE WITH CONFIG')
    print(settings['config'])
    make_ifconfig_file(config=settings['config'])

    # For now, we are going to assume that we are only using one wireless interface at most as a network station
    station_interface = None
    for interface_name, interface in settings['config'].items():
        if interface['mode'] == 'station':
            station_interface = interface['name']

    utility.log(pilib.dirs.logs.network,
                'Running network reconfig (setting lastnetreconfig). ', 0,
                pilib.loglevels.network)
    dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'lastnetreconfig',
                         gettimestring())

    try:
        netconfigdata = dblib.readonedbrow(pilib.dirs.dbs.system,
                                           'netconfig')[0]
        if settings['debug']:
            print("NETCONFIG:\n{}".format(netconfigdata))
    except:
        utility.log(pilib.dirs.logs.network, 'Error reading netconfig data. ',
                    0, pilib.loglevels.network)
        return {
            'status': 1,
            'status_message': 'Error reading netconfig data. '
        }
    else:
        utility.log(pilib.dirs.logs.network,
                    'Successfully read netconfig data', 3,
                    pilib.loglevels.network)

    dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'mode',
                         netconfigdata['mode'])

    utility.log(pilib.dirs.logs.network, 'Netconfig is enabled', 3,
                pilib.loglevels.network)

    # This will grab the specified SSID and the credentials and update
    # the wpa_supplicant file. At the moment, it also looks to see if the network is available.

    if station_interface:
        utility.log(pilib.dirs.logs.network, 'Updating wpa_supplicant', 3,
                    pilib.loglevels.network)
        updatewpasupplicant(station_interface=station_interface)

    if settings['config_all']:
        utility.log(pilib.dirs.logs.network, 'Configuring all interfaces. ', 3,
                    pilib.loglevels.network)
        settings['ifaces_to_configure'] = [
            interface_name for interface_name in settings['config']
        ]

    for interface_name in settings['ifaces_to_configure']:
        utility.log(pilib.dirs.logs.network,
                    'Configuring interface: {}'.format(interface_name), 3,
                    pilib.loglevels.network)

        if interface_name not in settings['config']:
            message = 'Configuration not present for interface {}. '.format(
                interface_name)
            utility.log(pilib.dirs.logs.network, message, 1,
                        pilib.loglevels.network)
            continue

        this_config = settings['config'][interface_name]
        if settings['debug']:
            print('CONFIG: \n{}'.format(this_config))

        if this_config['mode'] == 'ap':
            killapservices()
            reset_net_iface(interface=interface_name)
            startapservices(interface_name)
        else:
            reset_net_iface(interface=interface_name)

    # Bridges require ipv4 being enabled in /etc/sysctl.conf
    # Here we are going to auto-bridge, but I think we should probably manually specify that the bridge should exist

    mode = None
    if all(interface in settings['config'] for interface in ['eth0', 'wlan0']):
        if settings['config']['wlan0']['mode'] == 'ap':
            mode = 'eth0wlan0bridge'
    if all(interface in settings['config']
           for interface in ['wlan0', 'wlan1']):
        if settings['config']['wlan0']['mode'] == 'dhcp' and settings[
                'config']['wlan1']['mode'] == 'ap':
            mode = 'wlan0wlan1bridge'
    if all(interface in settings['config']
           for interface in ['wlan0', 'wlan1']):
        if settings['config']['wlan1']['mode'] == 'dhcp' and settings[
                'config']['wlan0']['mode'] == 'ap':
            mode = 'wlan1wlan0bridge'

    if mode:
        utility.log(pilib.dirs.logs.network,
                    'Setting bridge for mode {}'.format(mode), 1,
                    pilib.loglevels.network)
        runIPTables(mode)
Example #7
0
def setstationmode(netconfigdata=None):
    import subprocess
    from iiutilities import utility
    from cupid import pilib
    from iiutilities import dblib

    utility.log(pilib.dirs.logs.network, 'Setting station mode. ', 3,
                pilib.loglevels.network)

    from time import sleep
    if not netconfigdata:
        utility.log(pilib.dirs.logs.network,
                    'Retrieving unfound netconfig data. ', 3,
                    pilib.loglevels.network)
        try:
            netconfigdata = dblib.readonedbrow(pilib.dirs.dbs.system,
                                               'netconfig')[0]
        except:
            utility.log(pilib.dirs.logs.network,
                        'Error reading netconfig data. ', 0,
                        pilib.loglevels.network)
        else:
            utility.log(pilib.dirs.logs.network, 'Read netconfig data. ', 4,
                        pilib.loglevels.network)

    killapservices()
    if netconfigdata['mode'] == 'staticeth0_stationdhcp':
        utility.log(pilib.dirs.logs.network,
                    'Configuring static eth0 and dhcp wlan0. ', 3,
                    pilib.loglevels.network)

        subprocess.call([
            '/bin/cp',
            '/usr/lib/iicontrollibs/misc/interfaces/interfaces.sta.eth0staticwlan0dhcp',
            '/etc/network/interfaces'
        ])
        reset_net_iface(interface='eth0')

        # update IP from netconfig
        utility.log(pilib.dirs.logs.network,
                    'Updating netconfig with ip ' + netconfigdata['address'],
                    3, pilib.loglevels.network)
        replaceifaceparameters(
            '/etc/network/interfaces', '/etc/network/interfaces', 'wlan0',
            ['address', 'gateway'],
            [netconfigdata['address'], netconfigdata['gateway']])

    # This is the old mode for legacy purposes and backward compatibility
    elif netconfigdata['mode'] == 'station':

        if netconfigdata['addtype'] == 'static':
            utility.log(pilib.dirs.logs.network,
                        'Configuring static address. ', 3,
                        pilib.loglevels.network)

            subprocess.call([
                '/bin/cp',
                '/usr/lib/iicontrollibs/misc/interfaces/interfaces.sta.static',
                '/etc/network/interfaces'
            ])

            # update IP from netconfig
            utility.log(
                pilib.dirs.logs.network,
                'Updating netconfig with ip ' + netconfigdata['address'], 3,
                pilib.loglevels.network)
            replaceifaceparameters(
                '/etc/network/interfaces', '/etc/network/interfaces', 'wlan0',
                ['address', 'gateway'],
                [netconfigdata['address'], netconfigdata['gateway']])
        elif netconfigdata['addtype'] == 'dhcp':
            utility.log(pilib.dirs.logs.network, 'Configuring dhcp. ', 3,
                        pilib.loglevels.network)
            subprocess.call([
                '/bin/cp',
                '/usr/lib/iicontrollibs/misc/interfaces/interfaces.sta.dhcp',
                '/etc/network/interfaces'
            ])

    utility.log(pilib.dirs.logs.network, 'Resetting wlan. ', 3,
                pilib.loglevels.network)
    reset_net_iface()
    sleep(1)
    reset_net_iface()
Example #8
0
def setsinglecontrolvalue(database, table, valuename, value, condition=None):
    from iiutilities.datalib import gettimestring
    from iiutilities import dblib
    from iiutilities import utility

    if table == 'channels':
        utility.log(dirs.logs.control,
                    "Table: " + table + " found in keywords", 4,
                    loglevels.control)

        if valuename in ['setpointvalue']:
            utility.log(dirs.logs.control,
                        "Set value: " + valuename + " found in keywords", 4,
                        loglevels.control)

            # Get the channel data
            try:
                channeldata = dblib.readonedbrow(dirs.dbs.control,
                                                 'channels',
                                                 condition=condition)[0]
            except:
                utility.log(
                    dirs.logs.control,
                    "error retrieving channel with condition " + condition, 1,
                    loglevels.control)
            else:
                utility.log(dirs.logs.control,
                            "Channel retrieval went ok with " + condition, 1,
                            loglevels.control)
                """
                This all needs to go into the picontrol section
                Set a pending value in modify channel, then picontrol processes pending setpoint

                """
                if channeldata['type'] == 'remote' and channeldata['enabled']:
                    # Process setpointvalue send for remote here to make it as fast as possible.
                    # First we need to identify the node and channel by retrieving the interface

                    channelname = channeldata['name']
                    utility.log(
                        dirs.logs.control,
                        "Processing remote setpoint for channel " +
                        channelname, 1, loglevels.io)

                    # Then go to the interfaces table to get the node and channel addresses
                    address = dblib.getsinglevalue(dirs.dbs.control,
                                                   'interfaces',
                                                   'address',
                                                   condition="name='" +
                                                   channelname + "'")
                    utility.log(dirs.logs.control,
                                "Channel has address " + address, 1,
                                loglevels.io)

                    node = address.split(':')[0]
                    channel = address.split(':')[1]

                    # If it's local, we send the command to the controller directly
                    if int(node) == 1:
                        message = '~setsv;' + channel + ';' + str(value)

                    # If not, first insert the sendmsg command to send it to the remote node
                    else:
                        message = '~sendmsg;' + node + ';;~setsv;' + channel + ';' + str(
                            value)

                    utility.log(dirs.logs.control,
                                "Sending message: " + message, 1, loglevels.io)

                    # Then queue up the message for dispatch

                    dblib.sqliteinsertsingle(dirs.dbs.motes, 'queued',
                                             [gettimestring(), message])

                # get existing pending entry
                pendingvaluelist = []

                pendingentry = dblib.getsinglevalue(database,
                                                    table,
                                                    'pending',
                                                    condition=condition)
                if pendingentry:
                    try:
                        pendingvaluelist = pendingentry.split(',')
                    except:
                        pendingvaluelist = []

                if valuename in pendingvaluelist:
                    pass
                else:
                    pendingvaluelist.append(valuename)

                pendinglistentry = ','.join(pendingvaluelist)

                dblib.setsinglevalue(database, table, 'pending',
                                     pendinglistentry, condition)
        else:
            utility.log(dirs.logs.control,
                        "Set value: " + valuename + " not found in keywords",
                        4, loglevels.control)

    # carry out original query no matter what
    response = dblib.setsinglevalue(database, table, valuename, value,
                                    condition)
    return response
Example #9
0
def update_net_status(lastnetstatus=None,
                      quiet=True,
                      ifaces_config=None,
                      netconfig_data=None):
    """
    This function does two main things:

    1. Updates netstatus table. This table contains overall status information, i.e. whether we are attached to WAN,
    hamachi, etc.

    2. Updates netiface_status table (previously netifaces table). This does some contextual stuff like getting wpastate
    info if it makes sense based on mode. Trying to get wpastate data on interfaces that don't matter is not a big deal,
    except that it takes a little time. No need wasting time if the interface is not configured to use wpa.

    3. For interfaces that have a configuration, sets status in netifaces_status based on mode

    """

    import time
    from iiutilities import netfun
    from iiutilities import dblib
    from cupid import pilib
    from iiutilities import utility
    from iiutilities import datalib
    from iiutilities.netfun import getifconfigstatus, getwpaclientstatus

    if not netconfig_data:
        netconfig_data = dblib.readonedbrow(pilib.dirs.dbs.system,
                                            'netconfig')[0]

    if not ifaces_config:

        # Get config data
        ifaces_config = pilib.dbs.system.read_table('netifaceconfig',
                                                    keyed_dict=True)

        # Unpack config
        for interface_name, element in ifaces_config.items():
            element['config'] = json.loads(element['config'])
    """ 
    We get last netstatus so that we can save last online times, previous online status, etc. 
    """

    if not lastnetstatus:
        try:
            lastnetstatus = dblib.readonedbrow(pilib.dirs.dbs.system,
                                               'netstatus')[0]
        except:
            utility.log(
                pilib.dirs.logs.system,
                'Error reading netstatus. Attempting to recreate netstatus table with default values. ',
                1, pilib.loglevels.network)
            try:
                dblib.emptyandsetdefaults(pilib.dirs.dbs.system, 'netstatus')
                lastnetstatus = dblib.readonedbrow(pilib.dirs.dbs.system,
                                                   'netstatus')[0]
            except:
                utility.log(pilib.dirs.logs.system,
                            'Error recreating netstatus. ', 1,
                            pilib.loglevels.network)

    utility.log(pilib.dirs.logs.network,
                'Reading ifaces with ifconfig status. ', 4,
                pilib.loglevels.network)

    # Returns a dictionary, config is unpacked
    ifaces_status = getifconfigstatus()
    """
    We supplement with wpa status on the wlan interfaces if station mode should be set
    Here, we need to decide which interfaces should have a proper wpa status
    """

    for interface_name, this_interface_config in ifaces_config.items():
        this_interface_status = ifaces_status[interface_name]

        # Insert mode into status
        this_interface_status['mode'] = this_interface_config['mode']

        # this_interface_status = json.loads(this_interface_status['config'])
        if this_interface_config['mode'] == 'station':
            this_interface_status['config']['wpastate'] = getwpaclientstatus(
                interface_name)
        else:
            this_interface_status['config']['wpastate'] = ''

        this_interface_status_result = check_interface_status(
            this_interface_config, this_interface_status)

        this_interface_status['status'] = this_interface_status_result[
            'status']
        this_interface_status['status_message'] = this_interface_status_result[
            'status_message']
    """ 
    Then write it to the table 
    TODO : Double-check no problems here with not recreating status from scratch (stale data, et.)
    """

    utility.log(pilib.dirs.logs.network,
                'Sending ifaces query \n {}. '.format(ifaces_status), 5,
                pilib.loglevels.network)
    # print(ifacesdictarray)
    this_schema = dblib.sqliteTableSchema([{
        'name': 'name',
        'primary': True
    }, {
        'name': 'config'
    }, {
        'name': 'status'
    }, {
        'name': 'status_message'
    }, {
        'name': 'mode'
    }])

    pilib.dbs.system.create_table('netifacestatus',
                                  schema=this_schema,
                                  queue=True)
    from copy import deepcopy
    # print('IFACES')
    # print(ifaces_status)
    for interface_name, interface in ifaces_status.items():
        insert = deepcopy(interface)

        # Pack up the interface configuration data
        try:
            insert['config'] = json.dumps(interface['config'])
        except:
            print('error with interface {}'.format(interface_name))
            print(interface)

        pilib.dbs.system.insert('netifacestatus', insert, queue=True)
    """ Now we check to see if we can connect to WAN """

    utility.log(pilib.dirs.logs.network, 'Checking pingtimes. ', 4,
                pilib.loglevels.network)
    okping = float(netconfig_data['pingthreshold'])

    pingresults = netfun.runping('8.8.8.8', quiet=quiet)

    # pingresults = [20, 20, 20]
    pingresult = sum(pingresults) / float(len(pingresults))

    if pingresult == 0:
        wanaccess = 0
        latency = 0
    else:
        latency = pingresult
        if pingresult < okping:
            wanaccess = 1
            pilib.dbs.system.set_single_value('netstatus',
                                              'WANaccess',
                                              1,
                                              queue=True)
            if lastnetstatus[
                    'WANaccess'] == 0 or not lastnetstatus['onlinetime']:
                lastnetstatus['onlinetime'] = datalib.gettimestring()

        else:
            wanaccess = 0

    if not wanaccess:
        dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'WANaccess',
                             0)
        if lastnetstatus['WANaccess'] == 1 or not lastnetstatus['offlinetime']:
            lastnetstatus['offlinetime'] = datalib.gettimestring()

    # we set all the values here, so when we retreive it we get changed and also whatever else happens to be there.
    lastnetstatus['latency'] = latency
    lastnetstatus['updatetime'] = datalib.gettimestring()
    lastnetstatus['WANaccess'] = wanaccess

    # pilib.dbs.system.insert('netstatus', lastnetstatus, queue=True)

    utility.log(pilib.dirs.logs.network, 'Done checking pings. ', 4,
                pilib.loglevels.network)

    if netconfig_data['netstatslogenabled']:
        # print('going to log stuff')
        dblib.logtimevaluedata(pilib.dirs.dbs.log, 'system_WANping',
                               time.time(), pingresult, 1000,
                               netconfig_data['netstatslogfreq'])

    #This is kinda ugly. Should be fixed.
    # netstatusdict = {'WANaccess':wanaccess, 'latency': latency, 'updatetime': updatetime}

    pilib.dbs.system.execute_queue(debug=True)
    return {
        'netstatusdict': lastnetstatus,
        'ifaces_status': ifaces_status,
        'ifaces_config': ifaces_config,
        'netconfig_data': netconfig_data
    }
Example #10
0
def run_system_status(**kwargs):
    import pilib
    import time
    from iiutilities import utility
    from iiutilities import dblib
    from iiutilities import datalib
    from iiutilities import gitupdatelib
    from iiutilities import data_agent

    settings = {'debug': False, 'quiet': False, 'force': True}
    settings.update(kwargs)

    if settings['debug']:
        print('DEBUG MODE')
        settings['quiet'] = False
        pilib.set_debug()

    # This doesn't update git libraries. It checks current versions and updates the database

    try:
        utility.log(pilib.dirs.logs.system, 'Checking git versions', 3,
                    pilib.loglevels.system)
        gitupdatelib.updaterepoversion(pilib.dirs.baselib,
                                       pilib.dirs.dbs.system,
                                       versiontablename='versions')
        gitupdatelib.updaterepoversion(pilib.dirs.web,
                                       pilib.dirs.dbs.system,
                                       versiontablename='versions')
    except:
        utility.log(pilib.dirs.logs.system, 'Error in git version check', 0,
                    pilib.loglevels.system)
    else:
        utility.log(pilib.dirs.logs.system, 'Git version check complete', 3,
                    pilib.loglevels.system)

    systemstatus = pilib.dbs.system.read_table_row('systemstatus')[0]

    # Get hardware info
    updatehardwareinfo()

    ## Read wireless config via iwconfig
    # this is breaking systemstatus for some reason
    # updateiwstatus()

    ## Read current netstatus
    lastnetstatus = {}
    try:
        lastnetstatus = dblib.readonedbrow(pilib.dirs.dbs.system,
                                           'netstatus')[0]
    except:
        utility.log(pilib.dirs.logs.network, 'Error reading network status. ',
                    1, pilib.loglevels.network)
    else:
        utility.log(pilib.dirs.logs.system, 'Completed network status. ', 3,
                    pilib.loglevels.network)

    # # Poll netstatus and return data
    # allnetstatus = updatenetstatus(lastnetstatus, quiet=settings['quiet'])

    # Keep reading system status?
    while systemstatus['systemstatusenabled'] or settings['force']:

        # Run notifications
        pilib.process_notifications_queue()

        try:
            data_agent.run_data_agent()
        except:
            utility.log(pilib.dirs.logs.system, 'Error running data agent. ',
                        1, pilib.loglevels.network)
        else:
            utility.log(pilib.dirs.logs.system,
                        'Data agent run successfully. ', 3,
                        pilib.loglevels.network)

        currenttime = datalib.gettimestring()
        dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemstatus',
                             'lastsystemstatuspoll', datalib.gettimestring())

        starttime = time.time()
        utility.log(pilib.dirs.logs.system,
                    'System status routine is starting. ', 3,
                    pilib.loglevels.system)
        """
        Check all network statuses. The goal here is to totally decouple status read and reconfigure
        When we need to check all status data, we'll have it either in a dict or dict array, or in a database table
        
        This sub will read config and status and give both overall and granular interface statuses.
        Then, if status is not 'ok', we will reconfigure interface.
        """

        if systemstatus['netstatusenabled']:
            utility.log(pilib.dirs.logs.system, 'Beginning network routines. ',
                        3, pilib.loglevels.system)

            # Update network interfaces statuses for all interfaces, in database tables as well
            # Check on wpa supplicant status as well. Function returns wpastatusdict
            try:
                utility.log(pilib.dirs.logs.system,
                            'Running updateifacestatus. ', 4,
                            pilib.loglevels.system)
                utility.log(pilib.dirs.logs.network,
                            'Running updateifacestatus', 4,
                            pilib.loglevels.network)
                allnetstatus = update_net_status(lastnetstatus,
                                                 quiet=settings['quiet'])
            except:
                utility.log(pilib.dirs.logs.network,
                            'Exception in updateifacestatus. ')
            else:
                utility.log(pilib.dirs.logs.network,
                            'Updateifacestatus completed. ')

            utility.log(pilib.dirs.logs.system,
                        'Completed net status update. ', 4,
                        pilib.loglevels.system)
        """
        End network configuration status
        """
        """
        Do we want to autoconfig the network? 
        
        If so, we analyze our netstatus data against what should be going on,
        and translate this into a network status. We have a list of ifaceconfigs and a list if ifacestatus
        """
        if systemstatus['netconfigenabled'] and systemstatus[
                'netstatusenabled']:

            # No need to get this fresh. We have it stored.
            netconfig_data = allnetstatus['netconfig_data']

            # We are going to hack in a jumper that sets AP configuration. This isn't the worst thing ever.
            # if netconfig_data['apoverride']:
            #     result = processapoverride(21)
            ''' Now we check network status depending on the configuration we have selected '''
            utility.log(pilib.dirs.logs.system,
                        'Running interface configuration watchdog. ', 4,
                        pilib.loglevels.system)
            utility.log(
                pilib.dirs.logs.network,
                'Running interface configuration. Mode: {}'.format(
                    netconfig_data['mode']), 4, pilib.loglevels.network)

            # print('ALL IFACE STATUS')
            # print(allnetstatus['ifaces_status'])

            result = watchdognetstatus(allnetstatus=allnetstatus)

        else:
            utility.log(pilib.dirs.logs.system,
                        'Netconfig or netstatus disabled. ', 1,
                        pilib.loglevels.system)
            dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'mode',
                                 'manual')
            dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus',
                                 'statusmsg', 'netconfig is disabled')
        """ Check Hamachi """
        if systemstatus['checkhamachistatus']:
            utility.log(pilib.dirs.logs.system, 'Hamachi watchdog is enabled',
                        3, pilib.loglevels.system)
            utility.log(pilib.dirs.logs.network,
                        'Hamachi watchdog is enabled. ', 3,
                        pilib.loglevels.network)

            # Only watchdog haamchi if we are connected to the network.
            netstatus = dblib.readonedbrow(pilib.dirs.dbs.system,
                                           'netstatus')[0]
            if netstatus['WANaccess']:
                utility.log(
                    pilib.dirs.logs.system,
                    'We appear to be online. Checking Hamachi Status. ', 3,
                    pilib.loglevels.system)
                utility.log(
                    pilib.dirs.logs.network,
                    'We appear to be online. Checking Hamachi Status. ', 3,
                    pilib.loglevels.network)

                watchdoghamachi(pingip='25.11.87.7')

                utility.log(pilib.dirs.logs.system,
                            'Completed checking Hamachi Status. ', 3,
                            pilib.loglevels.network)
                utility.log(pilib.dirs.logs.system,
                            'Completed checking Hamachi Status. ', 3,
                            pilib.loglevels.network)

            else:
                utility.log(
                    pilib.dirs.logs.system,
                    'We appear to be offline. Not checking Hamachi Status, but setting to 0. ',
                    3, pilib.loglevels.system)
                utility.log(
                    pilib.dirs.logs.network,
                    'We appear to be offline. Not checking Hamachi Status, but setting to 0. ',
                    3, pilib.loglevels.network)
                dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemstatus',
                                     'hamachistatus', 0)
        else:
            utility.log(pilib.dirs.logs.system, 'Hamachi watchdog is disabled',
                        3, pilib.loglevels.system)

        utility.log(pilib.dirs.logs.system,
                    'Finished interface configuration. ', 4,
                    pilib.loglevels.system)
        # pilib.writedatedlogmsg(pilib.dirs.logs.network, statusmsg)

        utility.log(pilib.dirs.logs.system, 'Running updateifacestatus. ', 4,
                    pilib.loglevels.system)

        update_net_status()

        utility.log(pilib.dirs.logs.system, 'Completed updateifacestatus. ', 4,
                    pilib.loglevels.system)

        utility.log(pilib.dirs.logs.system, 'Network routines complete. ', 3,
                    pilib.loglevels.system)

        utility.log(pilib.dirs.logs.system, 'Checking system flags. ', 3,
                    pilib.loglevels.system)
        processsystemflags()
        utility.log(pilib.dirs.logs.system, 'System flags complete. ', 3,
                    pilib.loglevels.system)

        # Get system status again
        systemstatus = pilib.dbs.system.read_table('systemstatus')[0]

        elapsedtime = int(time.time() - starttime)

        utility.log(
            pilib.dirs.logs.system,
            'Status routines complete. Elapsed time: {}'.format(
                str(elapsedtime)), 3, pilib.loglevels.system)

        utility.log(
            pilib.dirs.logs.system,
            'System status is sleeping for {} .'.format(
                systemstatus['systemstatusfreq']), 3, pilib.loglevels.system)

        # print('enabled: ' , systemstatus['systemstatusenabled'])
        if 'runonce' in kwargs and kwargs['runonce']:
            break

        time.sleep(systemstatus['systemstatusfreq'])

    else:
        utility.log(pilib.dirs.logs.system,
                    'System status is disabled. Exiting. ', 0,
                    pilib.loglevels.system)
def run_system_status(**kwargs):
    import pilib
    import time
    from iiutilities import utility
    from iiutilities import dblib
    from iiutilities import datalib
    from iiutilities import gitupdatelib
    from iiutilities import data_agent

    settings = {
        'debug':False,
        'quiet':False, 
        'force':True
    }
    settings.update(kwargs)

    if settings['debug']:
        print('DEBUG MODE')
        settings['quiet']=False
        pilib.set_debug()

    # This doesn't update git libraries. It checks current versions and updates the database

    try:
        utility.log(pilib.dirs.logs.system, 'Checking git versions', 3, pilib.loglevels.system)
        gitupdatelib.updaterepoversion(pilib.dirs.baselib, pilib.dirs.dbs.system, versiontablename='versions')
        gitupdatelib.updaterepoversion(pilib.dirs.web, pilib.dirs.dbs.system, versiontablename='versions')
    except:
        utility.log(pilib.dirs.logs.system, 'Error in git version check', 0, pilib.loglevels.system)
    else:
        utility.log(pilib.dirs.logs.system, 'Git version check complete', 3, pilib.loglevels.system)

    systemstatus = pilib.dbs.system.read_table_row('systemstatus')[0]

    # Get hardware info
    updatehardwareinfo()

    ## Read wireless config via iwconfig
    # this is breaking systemstatus for some reason
    # updateiwstatus()

    ## Read current netstatus
    lastnetstatus={}
    try:
        lastnetstatus = dblib.readonedbrow(pilib.dirs.dbs.system, 'netstatus')[0]
    except:
        utility.log(pilib.dirs.logs.network, 'Error reading network status. ', 1, pilib.loglevels.network)
    else:
        utility.log(pilib.dirs.logs.system, 'Completed network status. ', 3, pilib.loglevels.network)

    # # Poll netstatus and return data
    # allnetstatus = updatenetstatus(lastnetstatus, quiet=settings['quiet'])

    # Keep reading system status?
    while systemstatus['systemstatusenabled'] or settings['force']:

        # Run notifications
        pilib.process_notifications_queue()

        try:
            data_agent.run_data_agent()
        except:
            utility.log(pilib.dirs.logs.system, 'Error running data agent. ', 1, pilib.loglevels.network)
        else:
            utility.log(pilib.dirs.logs.system, 'Data agent run successfully. ', 3, pilib.loglevels.network)


        currenttime = datalib.gettimestring()
        dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemstatus', 'lastsystemstatuspoll', datalib.gettimestring())

        starttime = time.time()
        utility.log(pilib.dirs.logs.system, 'System status routine is starting. ', 3,
                      pilib.loglevels.system)

        """
        Check all network statuses. The goal here is to totally decouple status read and reconfigure
        When we need to check all status data, we'll have it either in a dict or dict array, or in a database table
        
        This sub will read config and status and give both overall and granular interface statuses.
        Then, if status is not 'ok', we will reconfigure interface.
        """

        if systemstatus['netstatusenabled']:
            utility.log(pilib.dirs.logs.system, 'Beginning network routines. ', 3, pilib.loglevels.system)

            # Update network interfaces statuses for all interfaces, in database tables as well
            # Check on wpa supplicant status as well. Function returns wpastatusdict
            try:
                utility.log(pilib.dirs.logs.system, 'Running updateifacestatus. ', 4, pilib.loglevels.system)
                utility.log(pilib.dirs.logs.network, 'Running updateifacestatus', 4, pilib.loglevels.network)
                allnetstatus = update_net_status(lastnetstatus, quiet=settings['quiet'])
            except:
                utility.log(pilib.dirs.logs.network, 'Exception in updateifacestatus. ')
            else:
                utility.log(pilib.dirs.logs.network, 'Updateifacestatus completed. ')

            utility.log(pilib.dirs.logs.system, 'Completed net status update. ', 4, pilib.loglevels.system)

        """
        End network configuration status
        """


        """
        Do we want to autoconfig the network? 
        
        If so, we analyze our netstatus data against what should be going on,
        and translate this into a network status. We have a list of ifaceconfigs and a list if ifacestatus
        """
        if systemstatus['netconfigenabled'] and systemstatus['netstatusenabled']:

            # No need to get this fresh. We have it stored.
            netconfig_data = allnetstatus['netconfig_data']

            # We are going to hack in a jumper that sets AP configuration. This isn't the worst thing ever.
            # if netconfig_data['apoverride']:
            #     result = processapoverride(21)

            ''' Now we check network status depending on the configuration we have selected '''
            utility.log(pilib.dirs.logs.system, 'Running interface configuration watchdog. ', 4,
                          pilib.loglevels.system)
            utility.log(pilib.dirs.logs.network, 'Running interface configuration. Mode: {}'.format(netconfig_data['mode']), 4,
                          pilib.loglevels.network)

            # print('ALL IFACE STATUS')
            # print(allnetstatus['ifaces_status'])

            result = watchdognetstatus(allnetstatus=allnetstatus)

        else:
            utility.log(pilib.dirs.logs.system, 'Netconfig or netstatus disabled. ', 1, pilib.loglevels.system)
            dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'mode', 'manual')
            dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'statusmsg', 'netconfig is disabled')

        """ Check Hamachi """
        if systemstatus['checkhamachistatus']:
            utility.log(pilib.dirs.logs.system, 'Hamachi watchdog is enabled', 3, pilib.loglevels.system)
            utility.log(pilib.dirs.logs.network, 'Hamachi watchdog is enabled. ', 3, pilib.loglevels.network)

            # Only watchdog haamchi if we are connected to the network.
            netstatus = dblib.readonedbrow(pilib.dirs.dbs.system, 'netstatus')[0]
            if netstatus['WANaccess']:
                utility.log(pilib.dirs.logs.system, 'We appear to be online. Checking Hamachi Status. ', 3, pilib.loglevels.system)
                utility.log(pilib.dirs.logs.network, 'We appear to be online. Checking Hamachi Status. ', 3, pilib.loglevels.network)
                
                watchdoghamachi(pingip='25.11.87.7')

                utility.log(pilib.dirs.logs.system, 'Completed checking Hamachi Status. ', 3, pilib.loglevels.network)
                utility.log(pilib.dirs.logs.system, 'Completed checking Hamachi Status. ', 3, pilib.loglevels.network)

            else:
                utility.log(pilib.dirs.logs.system, 'We appear to be offline. Not checking Hamachi Status, but setting to 0. ', 3, pilib.loglevels.system)
                utility.log(pilib.dirs.logs.network, 'We appear to be offline. Not checking Hamachi Status, but setting to 0. ', 3, pilib.loglevels.network)
                dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemstatus', 'hamachistatus', 0)
        else:
            utility.log(pilib.dirs.logs.system, 'Hamachi watchdog is disabled', 3, pilib.loglevels.system)

        utility.log(pilib.dirs.logs.system, 'Finished interface configuration. ', 4,
                      pilib.loglevels.system)
        # pilib.writedatedlogmsg(pilib.dirs.logs.network, statusmsg)

        utility.log(pilib.dirs.logs.system, 'Running updateifacestatus. ', 4, pilib.loglevels.system)

        update_net_status()

        utility.log(pilib.dirs.logs.system, 'Completed updateifacestatus. ', 4, pilib.loglevels.system)

        utility.log(pilib.dirs.logs.system, 'Network routines complete. ', 3, pilib.loglevels.system)

        utility.log(pilib.dirs.logs.system, 'Checking system flags. ', 3, pilib.loglevels.system)
        processsystemflags()
        utility.log(pilib.dirs.logs.system, 'System flags complete. ', 3, pilib.loglevels.system)

        # Get system status again
        systemstatus = pilib.dbs.system.read_table('systemstatus')[0]

        elapsedtime = int(time.time() - starttime)

        utility.log(pilib.dirs.logs.system, 'Status routines complete. Elapsed time: {}'.format(str(elapsedtime)), 3,
                      pilib.loglevels.system)

        utility.log(pilib.dirs.logs.system,
                               'System status is sleeping for {} .'.format(systemstatus['systemstatusfreq']), 3,
                      pilib.loglevels.system)

        # print('enabled: ' , systemstatus['systemstatusenabled'])
        if 'runonce' in kwargs and kwargs['runonce']:
            break

        time.sleep(systemstatus['systemstatusfreq'])

    else:
        utility.log(pilib.dirs.logs.system, 'System status is disabled. Exiting. ', 0, pilib.loglevels.system)
def update_net_status(lastnetstatus=None, quiet=True, ifaces_config=None, netconfig_data=None):

    """
    This function does two main things:

    1. Updates netstatus table. This table contains overall status information, i.e. whether we are attached to WAN,
    hamachi, etc.

    2. Updates netiface_status table (previously netifaces table). This does some contextual stuff like getting wpastate
    info if it makes sense based on mode. Trying to get wpastate data on interfaces that don't matter is not a big deal,
    except that it takes a little time. No need wasting time if the interface is not configured to use wpa.

    3. For interfaces that have a configuration, sets status in netifaces_status based on mode

    """

    import time
    from iiutilities import netfun
    from iiutilities import dblib
    from cupid import pilib
    from iiutilities import utility
    from iiutilities import datalib
    from iiutilities.netfun import getifconfigstatus, getwpaclientstatus

    if not netconfig_data:
        netconfig_data = dblib.readonedbrow(pilib.dirs.dbs.system, 'netconfig')[0]

    if not ifaces_config:

        # Get config data
        ifaces_config = pilib.dbs.system.read_table('netifaceconfig', keyed_dict=True)

        # Unpack config
        for interface_name, element in ifaces_config.items():
            element['config'] = json.loads(element['config'])

    """ 
    We get last netstatus so that we can save last online times, previous online status, etc. 
    """

    if not lastnetstatus:
        try:
            lastnetstatus = dblib.readonedbrow(pilib.dirs.dbs.system, 'netstatus')[0]
        except:
            utility.log(pilib.dirs.logs.system, 'Error reading netstatus. Attempting to recreate netstatus table with default values. ', 1, pilib.loglevels.network)
            try:
                dblib.emptyandsetdefaults(pilib.dirs.dbs.system, 'netstatus')
                lastnetstatus = dblib.readonedbrow(pilib.dirs.dbs.system, 'netstatus')[0]
            except:
                utility.log(pilib.dirs.logs.system, 'Error recreating netstatus. ', 1, pilib.loglevels.network)

    utility.log(pilib.dirs.logs.network, 'Reading ifaces with ifconfig status. ', 4, pilib.loglevels.network)

    # Returns a dictionary, config is unpacked
    ifaces_status = getifconfigstatus()

    """
    We supplement with wpa status on the wlan interfaces if station mode should be set
    Here, we need to decide which interfaces should have a proper wpa status
    """

    for interface_name, this_interface_config in ifaces_config.items():
        this_interface_status = ifaces_status[interface_name]

        # Insert mode into status
        this_interface_status['mode'] = this_interface_config['mode']

        # this_interface_status = json.loads(this_interface_status['config'])
        if this_interface_config['mode'] == 'station':
            this_interface_status['config']['wpastate'] = getwpaclientstatus(interface_name)
        else:
            this_interface_status['config']['wpastate'] = ''

        this_interface_status_result = check_interface_status(this_interface_config, this_interface_status)

        this_interface_status['status'] = this_interface_status_result['status']
        this_interface_status['status_message'] = this_interface_status_result['status_message']


    """ 
    Then write it to the table 
    TODO : Double-check no problems here with not recreating status from scratch (stale data, et.)
    """

    utility.log(pilib.dirs.logs.network, 'Sending ifaces query \n {}. '.format(ifaces_status), 5, pilib.loglevels.network)
        # print(ifacesdictarray)
    this_schema = dblib.sqliteTableSchema([
        {'name':'name', 'primary':True},
        {'name':'config'},
        {'name':'status'},
        {'name':'status_message'},
        {'name':'mode'}
    ])

    pilib.dbs.system.create_table('netifacestatus', schema=this_schema, queue=True)
    from copy import deepcopy
    # print('IFACES')
    # print(ifaces_status)
    for interface_name, interface in ifaces_status.items():
        insert = deepcopy(interface)

        # Pack up the interface configuration data
        try:
            insert['config'] = json.dumps(interface['config'])
        except:
            print('error with interface {}'.format(interface_name))
            print(interface)

        pilib.dbs.system.insert('netifacestatus', insert, queue=True)

    """ Now we check to see if we can connect to WAN """

    utility.log(pilib.dirs.logs.network, 'Checking pingtimes. ', 4, pilib.loglevels.network)
    okping = float(netconfig_data['pingthreshold'])

    pingresults = netfun.runping('8.8.8.8', quiet=quiet)

    # pingresults = [20, 20, 20]
    pingresult = sum(pingresults) / float(len(pingresults))

    if pingresult == 0:
        wanaccess = 0
        latency = 0
    else:
        latency = pingresult
        if pingresult < okping:
            wanaccess = 1
            pilib.dbs.system.set_single_value('netstatus', 'WANaccess', 1, queue=True)
            if lastnetstatus['WANaccess'] == 0 or not lastnetstatus['onlinetime']:
                lastnetstatus['onlinetime'] = datalib.gettimestring()

        else:
            wanaccess = 0

    if not wanaccess:
        dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'WANaccess', 0)
        if lastnetstatus['WANaccess'] == 1 or not lastnetstatus['offlinetime']:
            lastnetstatus['offlinetime'] = datalib.gettimestring()

    # we set all the values here, so when we retreive it we get changed and also whatever else happens to be there.
    lastnetstatus['latency'] = latency
    lastnetstatus['updatetime'] =  datalib.gettimestring()
    lastnetstatus['WANaccess'] = wanaccess

    # pilib.dbs.system.insert('netstatus', lastnetstatus, queue=True)

    utility.log(pilib.dirs.logs.network, 'Done checking pings. ', 4, pilib.loglevels.network)

    if netconfig_data['netstatslogenabled']:
        # print('going to log stuff')
        dblib.logtimevaluedata(pilib.dirs.dbs.log, 'system_WANping', time.time(), pingresult, 1000,
                               netconfig_data['netstatslogfreq'])

    #This is kinda ugly. Should be fixed.
    # netstatusdict = {'WANaccess':wanaccess, 'latency': latency, 'updatetime': updatetime}

    pilib.dbs.system.execute_queue(debug=True)
    return {'netstatusdict': lastnetstatus, 'ifaces_status': ifaces_status, 'ifaces_config':ifaces_config,
            'netconfig_data':netconfig_data}
Example #13
0
def runboot():
    import subprocess
    from time import sleep

    import pilib
    import spilights
    from iiutilities import utility, dblib, datalib

    try:
        pilib.set_all_wal(False)
    except:
        print('error setting wal mode')

    interfaces = pilib.dbs.control.read_table('interfaces')

    # Clear out status bits, if for no other reason to see the LEDs come on
    for statusvalue in ['systemstatusstatus', 'hamachistatus', 'picontrolstatus', 'updateiostatus', 'serialhandlerstatus' ]:
        dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemstatus', statusvalue, 0)

    systemstatus = dblib.readonedbrow(pilib.dirs.dbs.system, 'systemstatus')[0]


    # Queue a message indicating we are rebooting
    # TODO: Make this an actions option, or put it somewhere.
    # try:
    import socket
    hostname = socket.gethostname()

    message = 'CuPID is booting:\r\n\r\n'
    notifications_email = '*****@*****.**'
    subject = 'CuPID : ' + hostname + ' : booting'
    notification_database = pilib.cupidDatabase(pilib.dirs.dbs.notifications)
    system_database = pilib.cupidDatabase(pilib.dirs.dbs.system)

    currenttime = datalib.gettimestring()
    notification_database.insert('queued',
                                 {'type': 'email', 'message': message,
                                  'options': 'email:' + notifications_email + ',subject:' + subject,
                                  'queuedtime': currenttime})
    system_database.set_single_value('notifications', 'lastnotification', currenttime, condition="item='boot'")

    # except Exception as e:
    #     error_message = 'EXCEPTION in notification: {}'.format(e.message)
    #     print (error_message)
    #     utility.log(pilib.dirs.logs.system, error_message)
    # else:
    #     utility.log(pilib.dirs.logs.system, 'Boot notificaiton complete. ')


    # Start pigpiod

    subprocess.call(['killall','pigpiod'])
    sleep(1)
    utility.log(pilib.dirs.logs.system, 'boot: starting pigpio daemon', 3, pilib.loglevels.system)
    subprocess.call(['/usr/local/bin/pigpiod'])

    # Start webserver

    subprocess.call(['killall','nginx'])
    subprocess.call(['killall','uwsgi'])
    subprocess.call(['killall','apache2'])

    if systemstatus['webserver'] == 'apache':
        utility.log(pilib.dirs.logs.system, 'boot: starting apache', 3, pilib.loglevels.system)
        subprocess.call(['service', 'apache2', 'start'])
    elif systemstatus['webserver'] == 'nginx':
        utility.log(pilib.dirs.logs.system, 'boot: starting nginx', 3, pilib.loglevels.system)
        subprocess.call(['service', 'nginx', 'start'])

    # Run uwsgi daemon if nginx is running

    try:
        result = subprocess.check_output(['service', 'nginx', 'status']).decode('utf-8')
    except subprocess.CalledProcessError as e:
        result = ''
        # print('I AM FAILING')
        # print e.output

    if result:
        utility.log(pilib.dirs.logs.system, 'boot: starting uwsgi based on nginx call', 0)
        subprocess.call(['uwsgi', '--emperor', '/usr/lib/iicontrollibs/wsgi/', '--daemonize', '/var/log/cupid/uwsgi.log'])
    else:
        # print(' I KNOW NGINX IS NOT RUNNING')
        pass
    # Mount 1wire master

    subprocess.call(['killall','owfs'])
    subprocess.call(['killall','owserver'])
    subprocess.call(['killall','owhttpd'])

    runi2cowfs = True
    runusbowfs = False

    temp_unit = 'C'
    for interface in interfaces:
        if interface['enabled']:
            from iiutilities.datalib import parseoptions
            options_dict = parseoptions(interface['options'])
            if 'tempunit' in options_dict:
                if options_dict['tempunit'] in ['F','f','Fahrenheit','fahrenheit']:
                    temp_unit = 'F'

            if interface['interface'] == 'I2C' and interface['type'] == 'DS2483':
                runi2cowfs = True
            if interface['interface'] == 'USB' and interface['type'] == 'DS9490':
                runusbowfs = True

            if interface['interface'] == 'SPI1' and type == 'CuPIDlights':
                spilights.updatelightsfromdb(pilib.dirs.dbs.control, 'indicators', 1)
            if interface['interface'] == 'SPI0' and type == 'CuPIDlights':
                spilights.updatelightsfromdb(pilib.dirs.dbs.control, 'indicators', 0)

    if runi2cowfs or runusbowfs:
        if runi2cowfs:
            utility.log(pilib.dirs.logs.system, 'boot: Running i2c owserver', 3, pilib.loglevels.system)
            try:
                if temp_unit == 'F':
                    subprocess.call(['/opt/owfs/bin/owserver', '-F', '--i2c=/dev/i2c-1:ALL', '-p', '4304'])
                else:
                    subprocess.call(['/opt/owfs/bin/owserver', '--i2c=/dev/i2c-1:ALL', '-p', '4304'])
            except:
                utility.log(pilib.dirs.logs.system, 'boot: error running i2c owserver', 1, pilib.loglevels.system)
        if runusbowfs:
            utility.log(pilib.dirs.logs.system, 'boot: Running usb owserver', 3, pilib.loglevels.system)
            try:
                if temp_unit == 'F':
                    subprocess.call(['/opt/owfs/bin/owserver', '-F', '-u', '-p', '4304'])
                else:
                    subprocess.call(['/opt/owfs/bin/owserver', '-u', '-p', '4304'])
            except:
                utility.log(pilib.dirs.logs.system, 'error running usb owserver', 1, pilib.loglevels.system)

        utility.log(pilib.dirs.logs.system, 'boot: Running owfs/owserver mount', 3, pilib.loglevels.system)
        try:
            if temp_unit == 'F':
                subprocess.call(['/opt/owfs/bin/owfs', '-F', '-s', '4304', '/var/1wire/'])
            else:
                subprocess.call(['/opt/owfs/bin/owfs', '-s', '4304', '/var/1wire/'])
        except:
            utility.log(pilib.dirs.logs.system, 'boot: error running owfs', 1, pilib.loglevels.system)

        utility.log(pilib.dirs.logs.system, 'boot: Running owhttpd/owserver mount', 3, pilib.loglevels.system)
        try:
            if temp_unit == 'F':
                subprocess.call(['/opt/owfs/bin/owhttpd', '-F', '-s', '4304', '-p', '4305'])
            else:
                subprocess.call(['/opt/owfs/bin/owhttpd', '-s', '4304', '-p', '4305'])
        except:
            utility.log(pilib.dirs.logs.system, 'boot: error running owhttpd', 1, pilib.loglevels.system)

    else:
        utility.log(pilib.dirs.logs.system, 'boot: not running owfs', 3, pilib.loglevels.system)

    # Run netstart script if enabled
    if systemstatus['netconfigenabled']:
        from netconfig import runconfig
        utility.log(pilib.dirs.logs.system, 'boot: running boot netconfig', 2, pilib.loglevels.system)
        runconfig(onboot=True)
Example #14
0
def setsinglecontrolvalue(database, table, valuename, value, condition=None):
    from iiutilities.datalib import gettimestring
    from iiutilities import dblib
    from iiutilities import utility

    if table == 'channels':
        utility.log(dirs.logs.control, "Table: " + table + " found in keywords", 4, loglevels.control)

        if valuename in ['setpointvalue']:
            utility.log(dirs.logs.control, "Set value: " + valuename + " found in keywords", 4, loglevels.control)

            # Get the channel data
            try:
                channeldata = dblib.readonedbrow(dirs.dbs.control, 'channels', condition=condition)[0]
            except:
                utility.log(dirs.logs.control, "error retrieving channel with condition " + condition, 1, loglevels.control)
            else:
                utility.log(dirs.logs.control, "Channel retrieval went ok with " + condition, 1, loglevels.control)

                """
                This all needs to go into the picontrol section
                Set a pending value in modify channel, then picontrol processes pending setpoint

                """
                if channeldata['type'] == 'remote' and channeldata['enabled']:
                    # Process setpointvalue send for remote here to make it as fast as possible.
                    # First we need to identify the node and channel by retrieving the interface

                    channelname = channeldata['name']
                    utility.log(dirs.logs.control, "Processing remote setpoint for channel " + channelname, 1, loglevels.io)

                    # Then go to the interfaces table to get the node and channel addresses
                    address = dblib.getsinglevalue(dirs.dbs.control, 'interfaces', 'address', condition ="name='" + channelname + "'")
                    utility.log(dirs.logs.control, "Channel has address " + address, 1, loglevels.io)

                    node = address.split(':')[0]
                    channel = address.split(':')[1]

                    # If it's local, we send the command to the controller directly
                    if int(node) == 1:
                        message = '~setsv;' + channel + ';' + str(value)

                    # If not, first insert the sendmsg command to send it to the remote node
                    else:
                        message = '~sendmsg;' + node + ';;~setsv;' + channel + ';' + str(value)

                    utility.log(dirs.logs.control, "Sending message: " + message, 1, loglevels.io)


                    # Then queue up the message for dispatch

                    dblib.sqliteinsertsingle(dirs.dbs.motes, 'queued', [gettimestring(), message])

                # get existing pending entry
                pendingvaluelist = []

                pendingentry = dblib.getsinglevalue(database, table, 'pending', condition=condition)
                if pendingentry:
                    try:
                        pendingvaluelist = pendingentry.split(',')
                    except:
                        pendingvaluelist = []

                if valuename in pendingvaluelist:
                    pass
                else:
                    pendingvaluelist.append(valuename)

                pendinglistentry = ','.join(pendingvaluelist)

                dblib.setsinglevalue(database, table, 'pending', pendinglistentry, condition)
        else:
            utility.log(dirs.logs.control, "Set value: " + valuename + " not found in keywords", 4, loglevels.control)

    # carry out original query no matter what
    response = dblib.setsinglevalue(database, table, valuename, value, condition)
    return response
def application(environ, start_response):
    import cgi
    import json
    import hashlib

    # Set top folder to allow import of modules

    import os, sys, inspect

    top_folder = \
        os.path.split(os.path.realpath(os.path.abspath(os.path.split(inspect.getfile(inspect.currentframe()))[0])))[0]
    if top_folder not in sys.path:
        sys.path.insert(0, top_folder)

    import ii_netstats

    from iiutilities import dblib, datalib
    from iiutilities.utility import newunmangle
    from time import time

    # post_env = environ.copy()
    # post_env['QUERY_STRING'] = ''
    # post = cgi.FieldStorage(
    #     fp=environ['wsgi.input'],
    #     environ=post_env,
    #     keep_blank_values=True
    # )
    # formname = post.getvalue('name')
    #
    # output = {}
    #
    # d = {}
    # for k in post.keys():
    #     # print(k)
    #     d[k] = post.getvalue(k)

    try:
        request_body_size = int(environ.get('CONTENT_LENGTH', 0))
    except ValueError:
        request_body_size = 0

    request_body = environ['wsgi.input'].read(request_body_size)
    post = json.loads(request_body.decode('utf-8'))


    status = '200 OK'
    output = {'data': [], 'message': ''}

    d = post

    wsgiauth = False
    authverified = False

    if wsgiauth:
        # Verfiy that session login information is legit: hashed password, with salt and username, match
        # hash stored in database.
        import hashlib

        if 'sessionuser' in d:
            output['message'] += 'Session user is ' + d['sessionuser'] + '. '
        else:
            output['message'] += 'No session user found. '
            d['sessionuser'] = ''

        try:
            condition = "name='" + d['sessionuser'] + "'"
            userdata = dblib.readonedbrow(inventorylib.sysvars.dirs.dbs.safe, 'users', condition=condition)[0]
        except:
            output['message'] += 'error in user sqlite query for session user "' + d['sessionuser'] + '". '
            userdata = {'accesskeywords':'demo','admin':False}
        else:
            # Get session hpass to verify credentials
            hashedpassword = d['sessionhpass']
            hname = hashlib.new('sha1')
            hname.update(d['sessionuser'])
            hashedname = hname.hexdigest()
            hentry = hashlib.new('md5')
            hentry.update(hashedname + netstats.salt + hashedpassword)
            hashedentry = hentry.hexdigest()
            if hashedentry == userdata['password']:
                # successful auth
                output['message'] += 'Password verified. '
                authverified = True
    else:
        output['message'] += 'WSGI authorization not enabled. '

    if authverified or not wsgiauth:
        try:
            action = d['action']
        except KeyError:
            output['message'] = 'no action in request'
        else:
            # Stock functions
            if action == 'getnetstatsdata':
                output['message'] += 'getting netstats keyword found. '
                import datetime
                the_day = datetime.date.today()
                if 'day' in d:
                    # We will pass in a day in format yyyy-mm-dd or keywords, like 'today'
                    import datetime, time
                    today = datetime.date.today()
                    if d['day'] == 'today':
                        pass
                    elif d['day'] == 'prev_day':
                        the_day = today - datetime.timedelta(days=1)
                    elif d['day'] == 'prev_2_day':
                        the_day = today - datetime.timedelta(days=2)
                    elif d['day'] == 'prev_3_day':
                        the_day = today - datetime.timedelta(days=3)
                    elif d['day'] == 'prev_4_day':
                        the_day = today - datetime.timedelta(days=4)

                if the_day == datetime.date.today():
                    db_path = ii_netstats.netstats_dbpath
                else:
                    db_path_root = ii_netstats.netstats_dbpath.split('.db')[0]
                    date_string = '{}-{:02d}-{:02d}'.format(the_day.year, the_day.month, the_day.day)
                    db_path = '{}_{}.db'.format(db_path_root, date_string)

                print('** DBPATH: {} '.format(db_path))
                netstats_db = dblib.sqliteDatabase(db_path)

                output['message'] += 'db path {} chosen. '.format(db_path)

                wired_history =netstats_db.read_table('wired')
                if 'dataperiod' in d:
                    output['message'] += 'Limiting returned time to ' + d['dataperiod'] + '. '
                    # default 6hrs
                    period = 6 * 3600
                    if d['dataperiod'] == '6_hrs':
                        period = 6 * 3600
                    elif d['dataperiod'] == '12_hrs':
                        period = 12 * 3600
                    elif d['dataperiod'] == '24_hrs':
                        period = 24 * 3600
                    elif d['dataperiod'] == '48_hrs':
                        period = 48 * 3600
                    elif d['dataperiod'] == '7_days':
                        period = 7 * 24 * 3600

                    unmodified_length = len(wired_history)

                    # return only data within last period
                    from operator import itemgetter
                    from iiutilities.datalib import timestringtoseconds
                    new_list = sorted(wired_history, key=itemgetter('time'), reverse=True)

                    output['message'] += 'Most recent data point: ' + new_list[0]['time'] + '. '
                    new_history = []
                    most_recent_time_in_seconds = timestringtoseconds(new_list[0]['time'])
                    output['message'] += 'Most recent time in seconds ' + str(most_recent_time_in_seconds) + '. '

                    output['message'] += 'Oldest time in seconds ' + str(timestringtoseconds(new_list[-1]['time']))
                    output['message'] += 'Span of ' + str(most_recent_time_in_seconds - timestringtoseconds(new_list[-1]['time']))  + '. '
                    output['message'] += 'Period of ' + str(period) + '. '


                    for item in new_list:
                        if most_recent_time_in_seconds - timestringtoseconds(item['time']) < period:
                            new_history.append(item)
                    output['data'] = new_history
                    modified_length = len(wired_history)

                    output['message'] += 'Shortened data from ' + str(unmodified_length) + ' to ' + str(modified_length)
                else:
                    output['data'] = wired_history
                try:
                    from urllib2 import urlopen
                    my_ip = urlopen('http://ip.42.pl/raw').read()
                except:
                    my_ip = 'unknown'
                output['host'] = my_ip
            elif action == 'gettraffichistodata':
                output['message'] += 'gettraffic histo keyword found. '
                access_db = dblib.sqliteDatabase(ii_netstats.access_dbpath)

                access_db_tablenames = access_db.get_table_names()
                # output['message'] += 'Tables to search through: ' + str(access_db_tablenames) + '. '

                tables_to_fetch = []
                for tablename in access_db_tablenames:
                    if tablename.find('remotehisto') >= 0 or tablename.find('metadata') >= 0:
                        tables_to_fetch.append(tablename)
                # output['message'] += 'Fetching tables ' + str(tables_to_fetch) + '. '
                output['data'] = {}
                for table_to_fetch in tables_to_fetch:
                    output['data'][table_to_fetch] = access_db.read_table(table_to_fetch)

            elif action == 'postwirelessdata':
                output['message'] += 'postwirelessdata keyword found. '

                # nothing here yet

    if 'data' in output:
        if output['data']:
            newetag = hashlib.md5(str(output['data'])).hexdigest()
            if 'etag' in d:
                if newetag == d['etag']:
                    status = '304 Not Modified'
                    output['data'] = ''
        else:
            newetag=''
    else:
        newetag=''

    if 'datasize' in d:
        output['datasize'] = sys.getsizeof(output['data'])

    output['etag'] = newetag
    try:
        foutput = json.dumps(output, indent=1)
    except:
        import csv
        w = csv.writer(open("/usr/lib/iicontrollibs/inventory/dumperr.log", "w"))
        for key, val in output.items():
            w.writerow([key, val])

    response_headers = [('Content-type', 'application/json')]
    response_headers.append(('Etag',newetag))
    start_response(status, response_headers)

    return [foutput]