def processapoverride(pin): from iiutilities import utility from iiutilities.dblib import setsinglevalue import pilib utility.log(pilib.dirs.logs.network, "Reading GPIO override on pin " + str(pin) + '. ', 3, pilib.loglevels.network) utility.log(pilib.dirs.logs.system, "Reading GPIO override on pin " + str(pin) + '. ', 2, pilib.loglevels.system) import RPi.GPIO as GPIO import pilib try: GPIO.set_mode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) except: utility.log(pilib.dirs.logs.network, "Error reading GPIO", 3, pilib.loglevels.network) else: # jumper in place = input off, --> AP mode if not GPIO.input(pin): utility.log(pilib.dirs.logs.network, "GPIO On. Setting AP Mode.", 3, pilib.loglevels.network) setsinglevalue(pilib.dirs.dbs.system, 'netconfig', 'mode', 'ap')
def processsystemflags(systemflags=None): from cupid import pilib from iiutilities import dblib from iiutilities import utility if not systemflags: systemflags = pilib.dbs.system.read_table('systemflags') flagnames = [] flagvalues = [] for flag in systemflags: flagnames.append(flag['name']) flagvalues.append(flag['value']) stop = False if 'reboot' in flagnames: if flagvalues[flagnames.index('reboot')]: stop = True dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemflags', 'value', 0, "name='reboot'") import subprocess utility.log(pilib.dirs.logs.system, 'Rebooting for system flag', 0, pilib.loglevels.system) subprocess.call(['/sbin/reboot']) if 'netconfig' in flagnames: if flagvalues[flagnames.index('netconfig')]: stop = True dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemflags', 'value', 0, "name='netconfig'") from netconfig import runconfig utility.log(pilib.dirs.logs.system, 'Restarting network configuration', 0, pilib.loglevels.system) runconfig() if 'updateiicontrollibs' in flagnames and not stop: if flagvalues[flagnames.index('updateiicontrollibs')]: stop = True dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemflags', 'value', 0, 'name=\'updateiicontrollibs\'') from iiutilities.gitupdatelib import updateiicontrollibs utility.log(pilib.dirs.logs.system, 'Updating iicontrollibs', 0, pilib.loglevels.system) updateiicontrollibs(True) if 'updatecupidweblib' in flagnames and not stop: if flagvalues[flagnames.index('updatecupidweblib')]: stop = True dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemflags', 'value', 0, 'name=\'updatecupidweblib\'') from iiutilities.gitupdatelib import updatecupidweblib utility.log(pilib.dirs.logs.system, 'Updating cupidweblib', 0, pilib.loglevels.system) updatecupidweblib(True)
def processapoverride(pin): from iiutilities import utility from iiutilities.dblib import setsinglevalue import pilib utility.log(pilib.dirs.logs.network, "Reading GPIO override on pin " + str(pin) + '. ', 3, pilib.loglevels.network) utility.log(pilib.dirs.logs.system, "Reading GPIO override on pin " + str(pin) + '. ', 2, pilib.loglevels.system) import RPi.GPIO as GPIO import pilib try: GPIO.set_mode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) except: utility.log(pilib.dirs.logs.network, "Error reading GPIO", 3, pilib.loglevels.network) else: # jumper in place = input off, --> AP mode if not GPIO.input(pin): utility.log(pilib.dirs.logs.network, "GPIO On. Setting AP Mode.", 3, pilib.loglevels.network) setsinglevalue(pilib.dirs.dbs.system, 'netconfig', 'mode', 'ap')
def processsystemflags(systemflags=None): from cupid import pilib from iiutilities import dblib from iiutilities import utility if not systemflags: systemflags = pilib.dbs.system.read_table('systemflags') flagnames = [] flagvalues = [] for flag in systemflags: flagnames.append(flag['name']) flagvalues.append(flag['value']) stop = False if 'reboot' in flagnames: if flagvalues[flagnames.index('reboot')]: stop = True dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemflags', 'value', 0, "name='reboot'") import subprocess utility.log(pilib.dirs.logs.system, 'Rebooting for system flag', 0, pilib.loglevels.system) subprocess.call(['/sbin/reboot']) if 'netconfig' in flagnames: if flagvalues[flagnames.index('netconfig')]: stop = True dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemflags', 'value', 0, "name='netconfig'") from netconfig import runconfig utility.log(pilib.dirs.logs.system, 'Restarting network configuration', 0, pilib.loglevels.system) runconfig() if 'updateiicontrollibs' in flagnames and not stop: if flagvalues[flagnames.index('updateiicontrollibs')]: stop = True dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemflags', 'value', 0, 'name=\'updateiicontrollibs\'') from iiutilities.gitupdatelib import updateiicontrollibs utility.log(pilib.dirs.logs.system, 'Updating iicontrollibs', 0, pilib.loglevels.system) updateiicontrollibs(True) if 'updatecupidweblib' in flagnames and not stop: if flagvalues[flagnames.index('updatecupidweblib')]: stop = True dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemflags', 'value', 0, 'name=\'updatecupidweblib\'') from iiutilities.gitupdatelib import updatecupidweblib utility.log(pilib.dirs.logs.system, 'Updating cupidweblib', 0, pilib.loglevels.system) updatecupidweblib(True)
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 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 watchdoghamachi(pingip='self', threshold=3000, debug=False, restart=True): from iiutilities.netfun import runping, restarthamachi, killhamachi, gethamachistatusdata from iiutilities import utility from iiutilities import dblib from cupid import pilib if debug: pilib.set_debug() try: # if this throws an error, it means that there is not a valid status hamachistatusdata = gethamachistatusdata() except: import traceback error_message = traceback.format_exc() print(error_message) utility.log( pilib.dirs.logs.network, 'Error checking Hamachi via gethamachistatusdata with message: {}' .format(error_message), 1, pilib.loglevels.network) hamachistatusdata = {} # We are having some issue with return on hamachi status check. This is not always a reason to restart hamachi # We will carry on below and try to ping. if we can ping, we are good. if we need to self ping, this will still # Throw errors. BUT, main point is that if we can ping our chosen hamachi address, we are good. numpings = 10 try: print('I am here, doing the pings') utility.log( pilib.dirs.logs.network, 'Trying to ping hamachi gateway ({} pings) ... '.format(numpings), 1, pilib.loglevels.network) # So instead, we are going to test with a ping to another member on the network that # should always be online. This of course means that we have to make sure that it is, in fact, always # online if pingip in ['self', 'Self']: pingip = hamachistatusdata['address'] pingtimes = runping(pingip, numpings=numpings, quiet=False) pingmax = max(pingtimes) pingmin = min(pingtimes) pingave = sum(pingtimes) / len(pingtimes) # if hamachistatusdata['status'] not in ['logged in']: if pingave <= 0 or pingave > threshold: utility.log(pilib.dirs.logs.network, 'Pingtime unacceptable: ' + str(pingave) + '. ', 1, pilib.loglevels.network) dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemstatus', 'hamachistatus', 0) utility.log(pilib.dirs.logs.network, 'Restarting Hamachi. ', 1, pilib.loglevels.network) killhamachi() restarthamachi() utility.log(pilib.dirs.logs.network, 'Completed restarting Hamachi. ', 1, pilib.loglevels.network) else: if pingmax > threshold or pingmin <= 0: utility.log(pilib.dirs.logs.system, 'Hamachi lives, with issues: ' + str(pingtimes), 3, pilib.loglevels.system) else: dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemstatus', 'hamachistatus', 1) utility.log(pilib.dirs.logs.network, 'Hamachi appears fine. ', 3, pilib.loglevels.network) except: import traceback error_message = traceback.format_exc() utility.log( pilib.dirs.logs.network, 'Error checking Hamachi (second stage, pings) with message: {}'. format(error_message), 1, pilib.loglevels.network) if restart: utility.log(pilib.dirs.logs.network, 'Restarting hamachi: {}'.format(error_message), 1, pilib.loglevels.network) killhamachi() restarthamachi()
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)
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)
def application(environ, start_response): import cgi import json import os, sys, inspect # Set top folder to allow import of modules 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) from cupid import pilib, controllib from iiutilities import dblib, utility, datalib # 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 = {} # output['message'] = 'Output Message: ' # for k in post.keys(): # 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')) output = {} output['message'] = '' status = '200 OK' wsgiauth = True authverified = False if wsgiauth: # Verfiy that session login information is legit: hashed password, with salt and username, match # hash stored in database. import hashlib safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.users) if 'username' in post and post['username']: output['message'] += 'Session user is ' + post['username'] + '. ' else: output['message'] += 'No session user found. ' post['username'] = '' if post['username']: try: condition = "name='" + post['username'] + "'" user_data = safe_database.read_table_row( 'users', condition=condition)[0] except: output[ 'message'] += 'Error in user sqlite query for session user "' + post[ 'username'] + '". ' output[ 'message'] += 'Condition: ' + condition + '. Path: ' + pilib.dirs.dbs.safe user_data = {'accesskeywords': 'demo', 'admin': False} else: # Get session hpass to verify credentials hashedpassword = post['hpass'] hname = hashlib.new('sha1') hname.update(post['username']) hashedname = hname.hexdigest() hentry = hashlib.new('md5') hentry.update(hashedname + pilib.salt + hashedpassword) hashedentry = hentry.hexdigest() if hashedentry == user_data['password']: # successful auth output['message'] += 'Password verified. ' authverified = True # TODO: implement usermeta else: # Demo status authverified = True user_data = {'authlevel': 0} else: output['message'] += 'WSGI authorization not enabled. ' if authverified or not wsgiauth: output['authorized'] = True try: action = post['action'] except KeyError: output['message'] = 'no action in request' action = '' else: output['message'] += '{} action keyword found'.format(action) if output['authorized'] and action: output['action_allowed'] = pilib.check_action_auths( action, user_data['authlevel']) else: output['action_allowed'] = False if output['authorized'] and output['action_allowed']: output['message'] += 'Found action. ' if action == 'testdbvn': from iiutilities.dblib import dbvntovalue try: output['data'] = dbvntovalue(post['dbvn']) except: output['message'] += 'Error in dbvn evaluation. ' output['data'] = 'error' else: output['message'] += 'Seems to have worked out. ' elif action == 'testlogical': from iiutilities.datalib import evaldbvnformula try: output['data'] = evaldbvnformula(post['logical']) except: output['message'] += 'Error in logical evaluation. ' output['data'] = 'error' else: output['message'] += 'Seems to have worked out. ' elif action == 'testmodule': output['message'] += 'Testing module: ' if 'modulename' in post: import cupid.cupidunittests output['message'] += post['modulename'] output['data'] = cupid.cupidunittests.testmodule( post['modulename']) else: output['message'] += 'Modulename not found. ' elif action == 'testfunction': output['message'] += 'Testing function: ' if 'testname' in post: import cupid.cupidunittests output['message'] += post['testname'] # output['data'] = cupid.tests.testfunction(d['testname']) output['data'] = cupid.cupidunittests.testfunction( post['testname']) # output['data'] = str(cupid.tests.testfunction('systemstatus')) else: output['message'] += 'Testname not found. ' elif action == 'modifychannelalarm': controllib.handle_modify_channel_alarm(post, output) from cupid.actions import processactions # process only this action. processactions(name=post['actionname']) elif action == 'modifychannel': controllib.handle_modify_channel(post, output) elif action == 'getalarmscount': control_db = dblib.sqliteDatabase(pilib.dirs.dbs.control) actions = control_db.read_table('actions') output['data'] = { 'totalalarms': len(actions), 'channelalarms': 0, 'activealarms': 0, 'activechannelalarms': 0 } for action in actions: if action['conditiontype'] == 'channel': output['data']['channelalarms'] += 1 if action['active']: output['data']['activechannelalarms'] += 1 if action['active']: output['data']['activealarms'] += 1 elif action == 'copy_log_to_archive': pilib.app_copy_log_to_archive(post, output) elif action == 'getlogscount': logtablenames = dblib.sqliteDatabase( pilib.dirs.dbs.log).get_table_names() output['data'] = {'logscount': len(logtablenames)} elif action == 'test_action': output['message'] += 'Testing action. ' controldb = dblib.sqliteDatabase(pilib.dirs.dbs.control) actiondict = controldb.read_table('actions', condition='"name"=\'' + post['actionname'] + "'")[0] from cupid.actions import action test_action = action(actiondict) test_action.test() elif action == 'update_network': safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe) safe_database.set_single_value('wireless', 'password', post['password'], "SSID='" + post['ssid'] + "'") elif action == 'add_network': safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe) insert = {'SSID': post['ssid'], 'auto': 1, 'priority': 1} if 'password' in post: insert['password'] = post['password'] safe_database.insert('wireless', insert) elif action == 'delete_network': safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe) safe_database.delete('wireless', "SSID='" + post['ssid'] + "'") # elif action == 'dump': # # this has to go. # if 'database' in d: # dbpath = pilib.dbnametopath(d['database']) # if dbpath: # if 'tablelist' in d and 'outputfile' in d: # dbpath = pilib.dbnametopath(d['database']) # dblib.sqlitedatadump(dbpath, d['tablelist'], d['outputfile']) # output['message'] = 'data dumped' # elif 'tablename' in d and 'outputfile' in d: # dblib.sqlitedatadump(dbpath, [d['tablename']], d['outputfile']) # output['message'] = 'data dumped. ' # else: # output['message'] += 'keys not present for dump. ' # else: # output['message'] += 'keys not present for dump. ' # else: # output['message'] += 'keys not present for dump. ' elif action in ['userdelete', 'useradd', 'usermodify']: """ This needs to be consolidate with the other useradd, modify algorithm written already. Probably do this when we update the user permissions interface. """ # Ensure that we are authorized for this action if action == 'userdelete': try: dblib.sqlitequery( pilib.dirs.dbs.users, "delete from users where name='" + post['usertodelete'] + "'") except: output['message'] += 'Error in delete query. ' else: output['message'] += 'Successful delete query. ' elif action == 'usermodify': if 'usertomodify' in post: querylist = [] if 'newpass' in post: from pilib import salt # Get session hpass to verify credentials hashedpassword = post['newpass'] hname = hashlib.new('sha1') hname.update(post['usertomodify']) hashedname = hname.hexdigest() hentry = hashlib.new('md5') hentry.update(hashedname + salt + hashedpassword) hashedentry = hentry.hexdigest() querylist.append('update users set password='******'" + post['usertomodify'] + "'") if 'newemail' in post: querylist.append("update users set email='" + post['newemail'] + "' where name='" + post['usertomodify'] + "'") if 'newauthlevel' in post: querylist.append("update users set authlevel='" + post['newauthlevel'] + "' where name='" + post['usertomodify'] + "'") try: dblib.sqlitemultquery(pilib.dirs.dbs.users, querylist) except: output[ 'message'] += 'Error in modify/add query: ' + ",".join( querylist) else: output[ 'message'] += 'Successful modify/add query. ' + ",".join( querylist) else: output['message'] += 'Need usertomodify in query. ' elif action == 'useradd': try: username = post['newusername'] except: username = '******' try: newemail = post['newemail'] except: newemail = '*****@*****.**' try: newauthlevel = post['newauthlevel'] except: newauthlevel = 0 query = "insert into users values(NULL,'" + username + "','','" + newemail + "',''," + str( newauthlevel) + ")" try: dblib.sqlitequery(pilib.dirs.dbs.users, query) except: output[ 'message'] += "Error in useradd sqlite query: " + query + ' . ' else: output['message'] += "Successful query: " + query + ' . ' elif action == 'getfiletext': try: filepath = post['filepath'] if 'numlines' in post: numlines = int(post['numlines']) else: numlines = 9999 output['message'] += 'Using numlines: ' + str( numlines) + ' for read action. ' if 'startposition' in post: startposition = post['startposition'] else: startposition = 'end' output[ 'message'] += 'Reading from position ' + startposition + '. ' except KeyError: output[ 'message'] += 'Sufficient keys for action getfile text do not exist. ' except: output['message'] += 'Uncaught error in getfiletext. ' else: try: file = open(filepath) lines = file.readlines() except: output[ 'message'] += 'Error reading file in getfiletext action. ' else: output['data'] = [] if startposition == 'end': try: output['data'] = datalib.tail(file, numlines)[0] except: output['message'] += 'Error in tail read. ' else: linecount = 0 for line in lines: linecount += 1 if linecount > numlines: break else: output['data'].append(line) elif action == 'getmbtcpdata': try: clientIP = post['clientIP'] register = post['register'] length = post['length'] except KeyError: output[ 'message'] += 'Sufficient keys do not exist for the command. Requires clientIP, register, and length. ' else: from iiutilities.netfun import readMBcodedaddresses # try: output['response'] = readMBcodedaddresses( clientIP, int(register), int(length)) elif action == 'queuemessage': output['message'] += 'Queue message. ' if 'message' in post: try: dblib.sqliteinsertsingle( pilib.dirs.dbs.motes, 'queuedmessages', [datalib.gettimestring(), post['message']]) except: import traceback exc_type, exc_value, exc_traceback = sys.exc_info() output[ 'message'] += 'Error in queue insert query: {}. '.format( traceback.format_exc()) else: output['message'] += 'Message insert successful' else: output['message'] += 'No message present. ' elif action == 'setsystemflag' and 'systemflag' in post: database = pilib.dirs.dbs.system dblib.setsinglevalue(database, 'systemflags', 'value', 1, "name=\'" + post['systemflag'] + "'") elif action == 'rundaemon': from cupiddaemon import rundaemon rundaemon() # TODO: Eliminate this scary thing. elif action == 'setvalue': utility.log(pilib.dirs.logs.control, "Setting value in wsgi", 1, 1) # we use the auxiliary 'setsinglecontrolvalue' to add additional actions to update if all(k in post for k in ('database', 'table', 'valuename', 'value')): dbpath = pilib.dbnametopath(post['database']) if dbpath: output[ 'message'] += 'Carrying out setvalue for value ' + post[ 'valuename'] + ' on ' + post[ 'table'] + ' in ' + dbpath if 'condition' in post: pilib.setsinglecontrolvalue(dbpath, post['table'], post['valuename'], post['value'], post['condition']) elif 'index' in post: condition = 'rowid= ' + post['index'] pilib.setsinglecontrolvalue(dbpath, post['table'], post['valuename'], post['value'], condition) else: pilib.setsinglecontrolvalue(dbpath, post['table'], post['valuename'], post['value']) else: output[ 'message'] += 'Problem translating dbpath from friendly name: ' + post[ 'database'] else: output['message'] += 'Insufficient data for setvalue ' elif action == 'updateioinfo': if all(k in post for k in ['database', 'ioid', 'value']): query = dblib.makesqliteinsert('ioinfo', [post['ioid'], post['value']], ['id', 'name']) try: dblib.sqlitequery(pilib.dirs.dbs.control, query) except: output[ 'message'] += 'Error in updateioinfo query execution: ' + query + '. into database: ' + pilib.dirs.dbs.control output['message'] += 'ioid: ' + post['ioid'] + ' . ' else: output['message'] += 'Executed updateioinfo query. ' else: output[ 'message'] += 'Insufficient data for updateioinfo query ! ' # TODO: properly incorporate and test channel class functions here, and then sub it. elif action == 'modify_channel': controllib.app_modify_channel(post, output) elif action == 'deletechannelbyname' and 'database' in post and 'channelname' in post: dbpath = pilib.dbnametopath(post['database']) dblib.sqlitequery( dbpath, 'delete channelname from channels where name=\"' + post['channelname'] + '\"') elif action == 'updatecameraimage': output['message'] += 'Take camera image keyword. ' import cupid.camera if 'width' in post: width = post['width'] else: width = 800 try: values = cupid.camera.takesnap(width=width) except: output['message'] += 'Error taking image. ' else: output['message'] += 'Appears successful. Path : ' + values[ 'imagepath'] + '. Timestamp : ' + values['timestamp'] + '. ' output['data'] = values elif action == 'getcurrentcamtimestamp': output['message'] += 'getcurrentcamtimestamp keyword found. ' try: with open('/var/www/webcam/images/current.jpg.timestamp') as f: data = f.read() except: output['message'] += 'Error reading file as requested. ' else: output['data'] = data else: output[ 'message'] += 'Action keyword present(' + action + '), but not handled. ' else: output[ 'message'] += 'Authentication unsuccessful or action not authorized.' status = '401 Not Authorized' foutput = json.dumps(output, indent=1) response_headers = [('Content-type', 'application/json')] start_response(status, response_headers) return [foutput]
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 watchdoghamachi(pingip='self', threshold=3000, debug=False, restart=True): from iiutilities.netfun import runping, restarthamachi, killhamachi, gethamachistatusdata from iiutilities import utility from iiutilities import dblib from cupid import pilib if debug: pilib.set_debug() try: # if this throws an error, it means that there is not a valid status hamachistatusdata = gethamachistatusdata() except: import traceback error_message = traceback.format_exc() print(error_message) utility.log(pilib.dirs.logs.network, 'Error checking Hamachi via gethamachistatusdata with message: {}'.format(error_message), 1, pilib.loglevels.network) hamachistatusdata = {} # We are having some issue with return on hamachi status check. This is not always a reason to restart hamachi # We will carry on below and try to ping. if we can ping, we are good. if we need to self ping, this will still # Throw errors. BUT, main point is that if we can ping our chosen hamachi address, we are good. numpings = 10 try: print('I am here, doing the pings') utility.log(pilib.dirs.logs.network, 'Trying to ping hamachi gateway ({} pings) ... '.format(numpings), 1, pilib.loglevels.network) # So instead, we are going to test with a ping to another member on the network that # should always be online. This of course means that we have to make sure that it is, in fact, always # online if pingip in ['self', 'Self']: pingip = hamachistatusdata['address'] pingtimes = runping(pingip, numpings=numpings, quiet=False) pingmax = max(pingtimes) pingmin = min(pingtimes) pingave = sum(pingtimes)/len(pingtimes) # if hamachistatusdata['status'] not in ['logged in']: if pingave <= 0 or pingave > threshold: utility.log(pilib.dirs.logs.network, 'Pingtime unacceptable: ' + str(pingave) + '. ', 1, pilib.loglevels.network) dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemstatus', 'hamachistatus', 0) utility.log(pilib.dirs.logs.network, 'Restarting Hamachi. ', 1, pilib.loglevels.network) killhamachi() restarthamachi() utility.log(pilib.dirs.logs.network, 'Completed restarting Hamachi. ', 1, pilib.loglevels.network) else: if pingmax > threshold or pingmin <= 0: utility.log(pilib.dirs.logs.system, 'Hamachi lives, with issues: ' + str(pingtimes), 3, pilib.loglevels.system) else: dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemstatus', 'hamachistatus', 1) utility.log(pilib.dirs.logs.network, 'Hamachi appears fine. ', 3, pilib.loglevels.network) except: import traceback error_message = traceback.format_exc() utility.log(pilib.dirs.logs.network, 'Error checking Hamachi (second stage, pings) with message: {}'.format(error_message), 1, pilib.loglevels.network) if restart: utility.log(pilib.dirs.logs.network, 'Restarting hamachi: {}'.format(error_message), 1, pilib.loglevels.network) killhamachi() restarthamachi()
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}
def watchdognetstatus(allnetstatus={}): from iiutilities import utility from cupid import pilib from iiutilities import datalib from cupid import netconfig from iiutilities import dblib """ And now comes the checking of configuration specific statuses and restarting them if enabled and necessary We are getting updated status information for each interface. We have configuration info for interfaces. We compare the two based on mode and decide if we need to run a netconfig on each interface. We do this by running through, interface by interface on netconfigstatus, and comparing. We then add the name to interfaces we need to reconfig and pass to netconfig(). We ignore interfaces we don't have a config for so we ignore things like hamachi interfaces, loopback, GSM, etc. """ if 'ifaces_config' not in allnetstatus or 'ifaces_status' not in allnetstatus: allnetstatus = update_net_status() netconfig_data = allnetstatus['netconfig_data'] netstatus = allnetstatus['netstatusdict'] ifaces_config = allnetstatus['ifaces_config'] ifaces_status = allnetstatus['ifaces_status'] statusmsg = '' currenttime = datalib.gettimestring() reconfig_interfaces = [] for iface_name, iface_status in ifaces_status.items(): utility.log(pilib.dirs.logs.network, 'Checking status of interface {}. '.format(iface_name, 3, pilib.loglevels.network)) if iface_status['status'] == 'fail': reconfig_interfaces.append(iface_name) utility.log(pilib.dirs.logs.network, 'Interface has fail status. Setting reconfig for {}. '.format(iface_name, 1, pilib.loglevels.network)) # Now do some sleuthing if we are being stringent about WAN access. Have to be careful about this if we are on a # private network run_WAN_reconfig = False if netconfig_data['requireWANaccess']: utility.log(pilib.dirs.logs.network, 'Requiring WAN access. Checking status and times. ', 3, pilib.loglevels.network) # print('NETSTATUS') # print(netstatus) if not netstatus['WANaccess']: utility.log(pilib.dirs.logs.network, 'No WANaccess. Checking offline time. ', 2, pilib.loglevels.network) try: offlinetime = netstatus['offlinetime'] except: # print('netstatus ERROR') utility.log(pilib.dirs.logs.network, 'Error getting offlinetime. ', 2, pilib.loglevels.network) offlineperiod = datalib.timestringtoseconds(datalib.gettimestring()) - datalib.timestringtoseconds(offlinetime) utility.log(pilib.dirs.logs.network, 'We have been offline for ' + str(offlineperiod)) # When did we last restart the network config? Is it time to again? timesincelastnetrestart = datalib.timestringtoseconds( datalib.gettimestring()) - datalib.timestringtoseconds(netstatus['lastnetreconfig']) utility.log(pilib.dirs.logs.network, 'It has been ' + str(timesincelastnetrestart) + ' seconds since we last restarted the network configuration. ') # Require that offline time is greater than WANretrytime if timesincelastnetrestart > int(netconfig_data['WANretrytime']) and offlineperiod > int(netconfig_data['WANretrytime']): utility.log(pilib.dirs.logs.network, 'We are not online, and it has been long enough, exceeding retry time of ' + str(int(netconfig_data['WANretrytime']))) dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'lastnetreconfig', datalib.gettimestring()) # We do reset the WAN offline time in the reboot sequence, hwoever. restarts = int(dblib.getsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'WANaccessrestarts')) restarts += 1 dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'WANaccessrestarts', restarts) utility.log(pilib.dirs.logs.network, 'Going to run netconfig to correct WAN access.') run_WAN_reconfig = True else: utility.log(pilib.dirs.logs.network, 'Not yet time to run netconfig to correct WAN access. Retry time set at ' + str(netconfig_data['WANretrytime'])) else: utility.log(pilib.dirs.logs.network, 'WANAccess is fine. ') if run_WAN_reconfig: # Set bad status in netstatus dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'netstate', 0) # Set ok time to '' to trigger rewrite next time status is ok lastoktime = dblib.getsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'netstateoktime') if not lastoktime: dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'netstateoktime', datalib.gettimestring()) else: if netconfig_data['rebootonfail']: offlinetime = datalib.timestringtoseconds(datalib.gettimestring()) - datalib.timestringtoseconds(lastoktime) if offlinetime > int(netconfig_data['rebootonfailperiod']): # Set to '' so we get another full fail period before rebooting again dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'netstateoktime', '') # Same thing for WAN offline time dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'offlinetime', '') bootcounts = int(dblib.getsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'netrebootcounter')) bootcounts += 1 dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'netrebootcounter', str(bootcounts)) # Set system flag to reboot utility.log(pilib.dirs.logs.system, 'REBOOTING to try to fix network', 0, pilib.loglevels.system) dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemflags', 'reboot', 1) # Figure out which interfaces to restart to fix WAN issues for interface_name, interface in ifaces_config.items(): utility.log(pilib.dirs.logs.network, 'Adding interface {} to reconfig list'.format(interface_name), 1, pilib.loglevels.network) if interface['mode'] in ['status', 'station', 'dhcp']: reconfig_interfaces.append(interface_name) else: # Clear bad status in netstatus and set netoktime dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'statusmsg', 'Mode appears to be set.') dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'netstate', 1) dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'netstateoktime', datalib.gettimestring()) dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'statusmsg', statusmsg) if reconfig_interfaces: utility.log(pilib.dirs.logs.network, 'Running netreconfig on list: {}'.format(reconfig_interfaces), 1, pilib.loglevels.network) netconfig.runconfig(ifaces_to_configure=reconfig_interfaces, config=ifaces_config, config_all=False)
def application(environ, start_response): import cgi import json import os, sys, inspect # Set top folder to allow import of modules 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) from cupid import pilib, controllib from iiutilities import dblib, utility, datalib # 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 = {} # output['message'] = 'Output Message: ' # for k in post.keys(): # 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')) output = {} output['message'] = '' status = '200 OK' wsgiauth = True authverified = False if wsgiauth: # Verfiy that session login information is legit: hashed password, with salt and username, match # hash stored in database. import hashlib safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.users) if 'username' in post and post['username']: output['message'] += 'Session user is ' + post['username'] + '. ' else: output['message'] += 'No session user found. ' post['username'] = '' if post['username']: try: condition = "name='" + post['username'] + "'" user_data = safe_database.read_table_row('users', condition=condition)[0] except: output['message'] += 'Error in user sqlite query for session user "' + post['username'] + '". ' output['message'] += 'Condition: ' + condition + '. Path: ' + pilib.dirs.dbs.safe user_data = {'accesskeywords': 'demo', 'admin': False} else: # Get session hpass to verify credentials hashedpassword = post['hpass'] hname = hashlib.new('sha1') hname.update(post['username']) hashedname = hname.hexdigest() hentry = hashlib.new('md5') hentry.update(hashedname + pilib.salt + hashedpassword) hashedentry = hentry.hexdigest() if hashedentry == user_data['password']: # successful auth output['message'] += 'Password verified. ' authverified = True # TODO: implement usermeta else: # Demo status authverified = True user_data = {'authlevel':0} else: output['message'] += 'WSGI authorization not enabled. ' if authverified or not wsgiauth: output['authorized'] = True try: action = post['action'] except KeyError: output['message'] = 'no action in request' action = '' else: output['message'] += '{} action keyword found'.format(action) if output['authorized'] and action: output['action_allowed'] = pilib.check_action_auths(action, user_data['authlevel']) else: output['action_allowed'] = False if output['authorized'] and output['action_allowed']: output['message'] += 'Found action. ' if action == 'testdbvn': from iiutilities.dblib import dbvntovalue try: output['data'] = dbvntovalue(post['dbvn']) except: output['message'] += 'Error in dbvn evaluation. ' output['data'] = 'error' else: output['message'] += 'Seems to have worked out. ' elif action == 'testlogical': from iiutilities.datalib import evaldbvnformula try: output['data'] = evaldbvnformula(post['logical']) except: output['message'] += 'Error in logical evaluation. ' output['data'] = 'error' else: output['message'] += 'Seems to have worked out. ' elif action == 'testmodule': output['message'] += 'Testing module: ' if 'modulename' in post: import cupid.cupidunittests output['message'] += post['modulename'] output['data'] = cupid.cupidunittests.testmodule(post['modulename']) else: output['message'] += 'Modulename not found. ' elif action == 'testfunction': output['message'] += 'Testing function: ' if 'testname' in post: import cupid.cupidunittests output['message'] += post['testname'] # output['data'] = cupid.tests.testfunction(d['testname']) output['data'] = cupid.cupidunittests.testfunction(post['testname']) # output['data'] = str(cupid.tests.testfunction('systemstatus')) else: output['message'] += 'Testname not found. ' elif action == 'modifychannelalarm': controllib.handle_modify_channel_alarm(post, output) from cupid.actions import processactions # process only this action. processactions(name=post['actionname']) elif action == 'modifychannel': controllib.handle_modify_channel(post, output) elif action == 'getalarmscount': control_db = dblib.sqliteDatabase(pilib.dirs.dbs.control) actions = control_db.read_table('actions') output['data'] = {'totalalarms':len(actions),'channelalarms':0, 'activealarms':0, 'activechannelalarms':0} for action in actions: if action['conditiontype'] == 'channel': output['data']['channelalarms'] += 1 if action['active']: output['data']['activechannelalarms'] += 1 if action['active']: output['data']['activealarms'] += 1 elif action == 'copy_log_to_archive': pilib.app_copy_log_to_archive(post, output) elif action == 'getlogscount': logtablenames = dblib.sqliteDatabase(pilib.dirs.dbs.log).get_table_names() output['data'] = {'logscount':len(logtablenames)} elif action == 'test_action': output['message'] += 'Testing action. ' controldb = dblib.sqliteDatabase(pilib.dirs.dbs.control) actiondict = controldb.read_table('actions',condition='"name"=\'' + post['actionname'] + "'")[0] from cupid.actions import action test_action = action(actiondict) test_action.test() elif action == 'update_network': safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe) safe_database.set_single_value('wireless', 'password', post['password'], "SSID='" + post['ssid'] + "'") elif action == 'add_network': safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe) insert = {'SSID':post['ssid'], 'auto':1, 'priority':1} if 'password' in post: insert['password'] = post['password'] safe_database.insert('wireless',insert) elif action == 'delete_network': safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe) safe_database.delete('wireless', "SSID='" + post['ssid'] + "'") # elif action == 'dump': # # this has to go. # if 'database' in d: # dbpath = pilib.dbnametopath(d['database']) # if dbpath: # if 'tablelist' in d and 'outputfile' in d: # dbpath = pilib.dbnametopath(d['database']) # dblib.sqlitedatadump(dbpath, d['tablelist'], d['outputfile']) # output['message'] = 'data dumped' # elif 'tablename' in d and 'outputfile' in d: # dblib.sqlitedatadump(dbpath, [d['tablename']], d['outputfile']) # output['message'] = 'data dumped. ' # else: # output['message'] += 'keys not present for dump. ' # else: # output['message'] += 'keys not present for dump. ' # else: # output['message'] += 'keys not present for dump. ' elif action in ['userdelete', 'useradd', 'usermodify']: """ This needs to be consolidate with the other useradd, modify algorithm written already. Probably do this when we update the user permissions interface. """ # Ensure that we are authorized for this action if action == 'userdelete': try: dblib.sqlitequery(pilib.dirs.dbs.users, "delete from users where name='" + post['usertodelete'] + "'") except: output['message'] += 'Error in delete query. ' else: output['message'] += 'Successful delete query. ' elif action == 'usermodify': if 'usertomodify' in post: querylist=[] if 'newpass' in post: from pilib import salt # Get session hpass to verify credentials hashedpassword = post['newpass'] hname = hashlib.new('sha1') hname.update(post['usertomodify']) hashedname = hname.hexdigest() hentry = hashlib.new('md5') hentry.update(hashedname + salt + hashedpassword) hashedentry = hentry.hexdigest() querylist.append('update users set password='******'" + post['usertomodify'] + "'") if 'newemail' in post: querylist.append("update users set email='" + post['newemail'] + "' where name='" + post['usertomodify'] + "'") if 'newauthlevel' in post: querylist.append("update users set authlevel='" + post['newauthlevel'] + "' where name='" + post['usertomodify'] + "'") try: dblib.sqlitemultquery(pilib.dirs.dbs.users, querylist) except: output['message'] += 'Error in modify/add query: ' + ",".join(querylist) else: output['message'] += 'Successful modify/add query. ' + ",".join(querylist) else: output['message'] += 'Need usertomodify in query. ' elif action == 'useradd': try: username = post['newusername'] except: username = '******' try: newemail = post['newemail'] except: newemail = '*****@*****.**' try: newauthlevel = post['newauthlevel'] except: newauthlevel = 0 query = "insert into users values(NULL,'" + username + "','','" + newemail + "',''," + str(newauthlevel) + ")" try: dblib.sqlitequery(pilib.dirs.dbs.users, query) except: output['message'] += "Error in useradd sqlite query: " + query + ' . ' else: output['message'] += "Successful query: " + query + ' . ' elif action == 'getfiletext': try: filepath = post['filepath'] if 'numlines' in post: numlines = int(post['numlines']) else: numlines = 9999 output['message'] += 'Using numlines: ' + str(numlines) + ' for read action. ' if 'startposition' in post: startposition = post['startposition'] else: startposition = 'end' output['message'] += 'Reading from position ' + startposition + '. ' except KeyError: output['message'] += 'Sufficient keys for action getfile text do not exist. ' except: output['message'] += 'Uncaught error in getfiletext. ' else: try: file = open(filepath) lines = file.readlines() except: output['message'] += 'Error reading file in getfiletext action. ' else: output['data'] = [] if startposition == 'end': try: output['data'] = datalib.tail(file, numlines)[0] except: output['message'] += 'Error in tail read. ' else: linecount = 0 for line in lines: linecount += 1 if linecount > numlines: break else: output['data'].append(line) elif action == 'getmbtcpdata': try: clientIP = post['clientIP'] register = post['register'] length = post['length'] except KeyError: output['message'] += 'Sufficient keys do not exist for the command. Requires clientIP, register, and length. ' else: from iiutilities.netfun import readMBcodedaddresses # try: output['response'] = readMBcodedaddresses(clientIP, int(register), int(length)) elif action == 'queuemessage': output['message'] += 'Queue message. ' if 'message' in post: try: dblib.sqliteinsertsingle(pilib.dirs.dbs.motes, 'queuedmessages', [datalib.gettimestring(), post['message']]) except: import traceback exc_type, exc_value, exc_traceback = sys.exc_info() output['message'] += 'Error in queue insert query: {}. '.format(traceback.format_exc()) else: output['message'] += 'Message insert successful' else: output['message'] += 'No message present. ' elif action == 'setsystemflag' and 'systemflag' in post: database = pilib.dirs.dbs.system dblib.setsinglevalue(database, 'systemflags', 'value', 1, "name=\'" + post['systemflag'] + "'") elif action == 'rundaemon': from cupiddaemon import rundaemon rundaemon() # TODO: Eliminate this scary thing. elif action == 'setvalue': utility.log(pilib.dirs.logs.control, "Setting value in wsgi", 1, 1) # we use the auxiliary 'setsinglecontrolvalue' to add additional actions to update if all(k in post for k in ('database', 'table', 'valuename', 'value')): dbpath = pilib.dbnametopath(post['database']) if dbpath: output['message'] += 'Carrying out setvalue for value ' + post['valuename'] + ' on ' + post['table'] + ' in ' + dbpath if 'condition' in post: pilib.setsinglecontrolvalue(dbpath, post['table'], post['valuename'], post['value'], post['condition']) elif 'index' in post: condition = 'rowid= ' + post['index'] pilib.setsinglecontrolvalue(dbpath, post['table'], post['valuename'], post['value'], condition) else: pilib.setsinglecontrolvalue(dbpath, post['table'], post['valuename'], post['value']) else: output['message'] += 'Problem translating dbpath from friendly name: ' + post['database'] else: output['message'] += 'Insufficient data for setvalue ' elif action == 'updateioinfo': if all(k in post for k in ['database', 'ioid', 'value']): query = dblib.makesqliteinsert('ioinfo', [post['ioid'], post['value']], ['id', 'name']) try: dblib.sqlitequery(pilib.dirs.dbs.control, query) except: output['message'] += 'Error in updateioinfo query execution: ' + query +'. into database: ' + pilib.dirs.dbs.control output['message'] += 'ioid: ' + post['ioid'] + ' . ' else: output['message'] += 'Executed updateioinfo query. ' else: output['message'] += 'Insufficient data for updateioinfo query ! ' # TODO: properly incorporate and test channel class functions here, and then sub it. elif action == 'modify_channel': controllib.app_modify_channel(post, output) elif action == 'deletechannelbyname' and 'database' in post and 'channelname' in post: dbpath = pilib.dbnametopath(post['database']) dblib.sqlitequery(dbpath, 'delete channelname from channels where name=\"' + post['channelname'] + '\"') elif action == 'updatecameraimage': output['message'] += 'Take camera image keyword. ' import cupid.camera if 'width' in post: width = post['width'] else: width = 800 try: values = cupid.camera.takesnap(width=width) except: output['message'] += 'Error taking image. ' else: output['message'] += 'Appears successful. Path : ' + values['imagepath'] + '. Timestamp : ' + values['timestamp'] + '. ' output['data'] = values elif action == 'getcurrentcamtimestamp': output['message'] += 'getcurrentcamtimestamp keyword found. ' try: with open('/var/www/webcam/images/current.jpg.timestamp') as f: data = f.read() except: output['message'] += 'Error reading file as requested. ' else: output['data'] = data else: output['message'] += 'Action keyword present(' + action + '), but not handled. ' else: output['message'] += 'Authentication unsuccessful or action not authorized.' status = '401 Not Authorized' foutput = json.dumps(output, indent=1) response_headers = [('Content-type', 'application/json')] start_response(status, response_headers) return [foutput]
def onact(self): from iiutilities import dblib, datalib, utility from cupid import pilib if self.actiontype == 'email': # process email action self.statusmsg += 'Processing email alert. ' email = self.actiondetail # Special messages if self.conditiontype == 'channel': message = 'Channel alarm for ' + self.name + ' is active with value of ' + str(self.value) + '. ' if 'PV_low' in self.actiondatadict: message += 'Low alarm: ' + str(self.actiondatadict['PV_low'] + '. ') if 'PV_high' in self.actiondatadict: message += 'High alarm: ' + str(self.actiondatadict['PV_high'] + '. ') elif self.conditiontype == 'value': # message = 'Alert is active for ' + self.name + '. Criterion ' + self.variablename + ' in ' + self.tablename + ' has value ' + str(self.variablevalue) + ' with a criterion of ' + str(self.criterion) + ' with an operator of ' + self.operator + '. This alarm status has been on since ' + self.ontime + '.' message = 'Alert for alarm ' + self.name + ' . On time of ' + self.ontime + '. Current time of ' \ + datalib.gettimestring() message += ' Value: ' + str(self.value) + self.actiondatadict['operator'] + str(self.actiondatadict['criterion']) else: # message = 'Alert is active for ' + self.name + '. Criterion ' + self.variablename + ' in ' + self.tablename + ' has value ' + str(self.variablevalue) + ' with a criterion of ' + str(self.criterion) + ' with an operator of ' + self.operator + '. This alarm status has been on since ' + self.ontime + '.' message = 'Alert for alarm ' + self.name + ' . On time of ' + self.ontime + '. Current time of ' \ + datalib.gettimestring() import socket hostname = socket.gethostname() subject = 'CuPID ' + hostname + ' Alert : Alarm On - ' + self.name try: actionmail = utility.gmail(message=message, subject=subject, recipient=email) actionmail.send() except: self.statusmsg += 'Error sending email. ' else: self.statusmsg += 'Mail sent. ' elif self.actiontype == 'indicator': # process indicator action self.statusmsg += 'Processing indicator on action. ' indicatorname = self.actiondetail dblib.sqlitequery(pilib.dirs.dbs.control, 'update indicators set status=1 where name = \'' + indicatorname + '\'') elif self.actiontype == 'output': self.statusmsg += 'Processing output on action. ' dblib.setsinglevalue(pilib.dirs.dbs.control, 'outputs', 'value', '1', condition='"id"=\'' + self.actiondetail + "'") elif self.actiontype == 'mote_command': settings = { 'no_duplicates':True, 'retries':5 } settings.update(self.actiondatadict) self.statusmsg += 'Processing command on action. ' destination = self.actiondatadict['destination'] message = self.actiondatadict['message'] command_id = '{}_{}'.format(destination, message) command = {'queuedtime': datalib.gettimestring(), 'destination': destination, 'status': 'new', 'message': message, 'commandid':command_id, } command['options'] = json.dumps({'retries':settings['retries']}) insert = True if settings['no_duplicates']: # Check to see if commands exist with our command id. condition = "commandid='{}'".format(command_id) matching_commands = pilib.dbs.motes.read_table('commands',condition=condition) if matching_commands: self.statusmsg += '{} matching commands are already queued. Not inserting. '.format(len(matching_commands)) insert = False if insert: self.statusmsg += 'Inserting command. ' pilib.dbs.motes.settings['quiet'] = False pilib.dbs.motes.insert('commands',command) # This should be the generic handler that we migrate to elif self.actiontype == 'setvalue': # to set a value, we need at minimum: # dbname, tablename, valuename, setmethod and either: # setmethod = increment, incrementvalue=1 # setmethod = value dbvndict = datalib.parsedbvn(self.actiondetail) dbpath = pilib.dbnametopath(dbvndict['dbname']) # Special set formula? if 'setvalueformula' in self.actiondatadict: # Stuff that we don't know yet. dblib.setsinglevalue(dbpath, dbvndict['tablename'], dbvndict['valuename'], 'formulastuff here', dbvndict['condition']) else: """ TODO: Fix this hack. We cannot currently single quote in the database entry because it breaks the reinsert. So for now, we have to add quotes on either side of the string literal before executing the sqlite query. """ if dbvndict['condition']: querycondition = dbvndict['condition'].split('=')[0] + "='" + dbvndict['condition'].split('=')[1] + "'" # print('FIXED CONDITION') # print(querycondition) else: querycondition = None dblib.setsinglevalue(dbpath, dbvndict['tablename'], dbvndict['valuename'], '1', querycondition)
def offact(self): from iiutilities import dblib, datalib, utility from cupid import pilib if self.actiontype == 'email': # process email action # TODO: This really needs to queue the email action in case we are not online. self.statusmsg +='Processing email alert.' email = self.actiondetail # message = 'Alert has gone inactive for ' + self.name + '. Criterion ' + self.variablename + ' in ' + self.tablename + ' has value ' + str(self.variablevalue) + ' with a criterion of ' + str(self.criterion) + ' with an operator of ' + self.operator + '. This alarm status has been of since ' + self.offtime + '.' message = 'Alert for alarm ' + self.name + ' . Off time of ' + self.offtime + '. Current time of ' \ + datalib.gettimestring() if self.conditiontype == 'value': message += ' Value: ' + str(self.value) + self.actiondatadict['operator'] + str( self.actiondatadict['criterion']) import socket hostname = socket.gethostname() subject = 'CuPID ' + hostname + ' Alert : Alarm Off - ' + self.name try: actionmail = utility.gmail(message=message, subject=subject, recipient=email) actionmail.send() except: self.statusmsg += 'Error sending email. ' else: self.statusmsg += 'Mail sent. ' elif self.actiontype == 'indicator': # process indicator action self.statusmsg +='Processing indicator off action.' indicatorname = self.actiondetail dblib.setsinglevalue(pilib.dirs.dbs.control, 'indicators', 'status', 0, 'name=\'' + indicatorname+ '\'') print('INDICATORNAME = "' + indicatorname + '"') # dblib.sqlitequery(pilib.dirs.dbs.control, 'update indicators set status=0 where name = ' + indicatorname) elif self.actiontype == 'output': self.statusmsg += 'Processing output off action. ' dblib.setsinglevalue(pilib.dirs.dbs.control, 'outputs', 'value', '0', condition='"id"=\'' + self.actiondetail + "'") # This should be the generic handler that we migrate to elif self.actiontype == 'setvalue': # to set a value, we need at minimum: # dbname, tablename, valuename, setmethod and either: # setmethod = increment, incrementvalue=1 # setmethod = value dbvndict = datalib.parsedbvn(self.actiondetail) dbpath = pilib.dbnametopath(dbvndict['dbname']) # Special set formula? if 'setvalueformula' in self.actiondatadict: # Stuff that we don't know yet. dblib.setsinglevalue(dbpath, dbvndict['tablename'], dbvndict['valuename'], 'formulastuff here', dbvndict['condition']) else: """ TODO: Fix this hack. We cannot currently single quote in the database entry because it breaks the reinsert. So for now, we have to add quotes on either side of the string literal before executing the sqlite query. """ if dbvndict['condition']: querycondition = dbvndict['condition'].split('=')[0] + "='" + dbvndict['condition'].split('=')[1] + "'" # print('FIXED CONDITION') # print(querycondition) else: querycondition = None dblib.setsinglevalue(dbpath, dbvndict['tablename'], dbvndict['valuename'], '0', querycondition)
def watchdognetstatus(allnetstatus={}): from iiutilities import utility from cupid import pilib from iiutilities import datalib from cupid import netconfig from iiutilities import dblib """ And now comes the checking of configuration specific statuses and restarting them if enabled and necessary We are getting updated status information for each interface. We have configuration info for interfaces. We compare the two based on mode and decide if we need to run a netconfig on each interface. We do this by running through, interface by interface on netconfigstatus, and comparing. We then add the name to interfaces we need to reconfig and pass to netconfig(). We ignore interfaces we don't have a config for so we ignore things like hamachi interfaces, loopback, GSM, etc. """ if 'ifaces_config' not in allnetstatus or 'ifaces_status' not in allnetstatus: allnetstatus = update_net_status() netconfig_data = allnetstatus['netconfig_data'] netstatus = allnetstatus['netstatusdict'] ifaces_config = allnetstatus['ifaces_config'] ifaces_status = allnetstatus['ifaces_status'] statusmsg = '' currenttime = datalib.gettimestring() reconfig_interfaces = [] for iface_name, iface_status in ifaces_status.items(): utility.log( pilib.dirs.logs.network, 'Checking status of interface {}. '.format( iface_name, 3, pilib.loglevels.network)) if iface_status['status'] == 'fail': reconfig_interfaces.append(iface_name) utility.log( pilib.dirs.logs.network, 'Interface has fail status. Setting reconfig for {}. '.format( iface_name, 1, pilib.loglevels.network)) # Now do some sleuthing if we are being stringent about WAN access. Have to be careful about this if we are on a # private network run_WAN_reconfig = False if netconfig_data['requireWANaccess']: utility.log(pilib.dirs.logs.network, 'Requiring WAN access. Checking status and times. ', 3, pilib.loglevels.network) # print('NETSTATUS') # print(netstatus) if not netstatus['WANaccess']: utility.log(pilib.dirs.logs.network, 'No WANaccess. Checking offline time. ', 2, pilib.loglevels.network) try: offlinetime = netstatus['offlinetime'] except: # print('netstatus ERROR') utility.log(pilib.dirs.logs.network, 'Error getting offlinetime. ', 2, pilib.loglevels.network) offlineperiod = datalib.timestringtoseconds(datalib.gettimestring( )) - datalib.timestringtoseconds(offlinetime) utility.log(pilib.dirs.logs.network, 'We have been offline for ' + str(offlineperiod)) # When did we last restart the network config? Is it time to again? timesincelastnetrestart = datalib.timestringtoseconds( datalib.gettimestring()) - datalib.timestringtoseconds( netstatus['lastnetreconfig']) utility.log( pilib.dirs.logs.network, 'It has been ' + str(timesincelastnetrestart) + ' seconds since we last restarted the network configuration. ') # Require that offline time is greater than WANretrytime if timesincelastnetrestart > int( netconfig_data['WANretrytime']) and offlineperiod > int( netconfig_data['WANretrytime']): utility.log( pilib.dirs.logs.network, 'We are not online, and it has been long enough, exceeding retry time of ' + str(int(netconfig_data['WANretrytime']))) dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'lastnetreconfig', datalib.gettimestring()) # We do reset the WAN offline time in the reboot sequence, hwoever. restarts = int( dblib.getsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'WANaccessrestarts')) restarts += 1 dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'WANaccessrestarts', restarts) utility.log(pilib.dirs.logs.network, 'Going to run netconfig to correct WAN access.') run_WAN_reconfig = True else: utility.log( pilib.dirs.logs.network, 'Not yet time to run netconfig to correct WAN access. Retry time set at ' + str(netconfig_data['WANretrytime'])) else: utility.log(pilib.dirs.logs.network, 'WANAccess is fine. ') if run_WAN_reconfig: # Set bad status in netstatus dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'netstate', 0) # Set ok time to '' to trigger rewrite next time status is ok lastoktime = dblib.getsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'netstateoktime') if not lastoktime: dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'netstateoktime', datalib.gettimestring()) else: if netconfig_data['rebootonfail']: offlinetime = datalib.timestringtoseconds( datalib.gettimestring()) - datalib.timestringtoseconds( lastoktime) if offlinetime > int(netconfig_data['rebootonfailperiod']): # Set to '' so we get another full fail period before rebooting again dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'netstateoktime', '') # Same thing for WAN offline time dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'offlinetime', '') bootcounts = int( dblib.getsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'netrebootcounter')) bootcounts += 1 dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'netrebootcounter', str(bootcounts)) # Set system flag to reboot utility.log(pilib.dirs.logs.system, 'REBOOTING to try to fix network', 0, pilib.loglevels.system) dblib.setsinglevalue(pilib.dirs.dbs.system, 'systemflags', 'reboot', 1) # Figure out which interfaces to restart to fix WAN issues for interface_name, interface in ifaces_config.items(): utility.log( pilib.dirs.logs.network, 'Adding interface {} to reconfig list'.format(interface_name), 1, pilib.loglevels.network) if interface['mode'] in ['status', 'station', 'dhcp']: reconfig_interfaces.append(interface_name) else: # Clear bad status in netstatus and set netoktime dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'statusmsg', 'Mode appears to be set.') dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'netstate', 1) dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'netstateoktime', datalib.gettimestring()) dblib.setsinglevalue(pilib.dirs.dbs.system, 'netstatus', 'statusmsg', statusmsg) if reconfig_interfaces: utility.log( pilib.dirs.logs.network, 'Running netreconfig on list: {}'.format(reconfig_interfaces), 1, pilib.loglevels.network) netconfig.runconfig(ifaces_to_configure=reconfig_interfaces, config=ifaces_config, config_all=False)
def updatewpasupplicant(**kwargs): from cupid import pilib from iiutilities import dblib from iiutilities import utility settings = { 'station_interface': 'wlan0', # 'network_select':['name','strongest'], 'network_select': ['strongest'], 'network_ssid': 'leHouse', 'path': '/etc/wpa_supplicant/wpa_supplicant.conf', 'debug': False } settings.update(kwargs) # Update networks to see what is available to attach to # try: networks = updatewirelessnetworks(settings['station_interface']) if settings['debug']: network_dict = {} for network in networks: network_dict[network['ssid']] = network print('all networks by strength: ') networks_with_strength = [{ 'ssid': network['ssid'], 'signallevel': int(network['signallevel'].split('dB')[0].strip()) } for network_name, network in network_dict.items()] from operator import itemgetter networks_by_strength = sorted(networks_with_strength, key=itemgetter('signallevel'), reverse=True) print(networks_by_strength) # except: # utility.log(pilib.dirs.logs.network, 'Error finding network interface. Is interface down?', 0, pilib.loglevels.network) # availablessids = [] # for network in networks: # availablessids.append(network['ssid']) # At first pass, this could be as simple as checking the last SSID and trying the other one try: wirelessauth_list = pilib.dbs.safe.read_table('wireless') except: utility.log(pilib.dirs.logs.network, 'Error reading wireless data. ', 0, pilib.loglevels.network) else: utility.log(pilib.dirs.logs.network, 'Read wireless data. ', 4, pilib.loglevels.network) auths = {} for auth_element in wirelessauth_list: auths[auth_element['SSID']] = auth_element # Get paired lists of networks and auths that match matchnetworks = {} for network in networks: this_ssid = network['ssid'] if this_ssid in auths: matchnetworks[this_ssid] = network matchnetworks[this_ssid]['auths'] = auths[this_ssid] # So now the matchnetworks are available and we have credentials for them print('*** AVAILABLE NETWORKS ***') print(matchnetworks) newnetwork = {} if len(matchnetworks.items()) > 0: # matchnetwork_names = [matchnetwork['name'] for matchnetwork in matchnetworks] utility.log(pilib.dirs.logs.network, str(len(matchnetworks)) + ' matching networks found. ', 1, pilib.loglevels.network) """ Choose network This is written such that if you have 'name' selected and not 'by strength' as secondary choice, no network will be selected. This is potentially a valid option. """ # TODO: Add in possibility of sorting by priority as stored in credentials. for network_method in settings['network_select']: if network_method == 'name': utility.log(pilib.dirs.logs.network, 'Using method name with name {}. ', 2, pilib.loglevels.network) if settings['network_ssid'] in matchnetworks: utility.log(pilib.dirs.logs.network, 'Selected network {} found. ', 2, pilib.loglevels.network) newnetwork = matchnetworks[settings['network_ssid']] break else: utility.log(pilib.dirs.logs.network, 'Selected network {} NOT found. ', 2, pilib.loglevels.network) elif network_method == 'strongest': utility.log(pilib.dirs.logs.network, 'Using method strongest. ', 2, pilib.loglevels.network) networks_with_strength = [{ 'ssid': network['ssid'], 'signallevel': int(network['signallevel'].split('dB')[0].strip()), 'network': network } for network_name, network in matchnetworks.items()] print(networks_with_strength) from operator import itemgetter networks_by_strength = sorted(networks_with_strength, key=itemgetter('signallevel'), reverse=True) newnetwork = networks_by_strength[0]['network'] print(networks_by_strength) break if newnetwork: print('NEW NETWORK') print(newnetwork) dblib.setsinglevalue(pilib.dirs.dbs.system, 'netconfig', 'SSID', newnetwork['ssid']) utility.log(pilib.dirs.logs.network, 'Network "' + newnetwork['ssid'] + '" selected', 1, pilib.loglevels.network) myfile = open(settings['path'], 'w') filestring = 'ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\n\n' filestring += 'network={\n' filestring += 'psk="' + newnetwork['auths']['password'] + '"\n' filestring += 'ssid="' + newnetwork['ssid'] + '"\n' filestring += 'proto=RSN\nauth_alg=OPEN\npairwise=CCMP\nkey_mgmt=WPA-PSK\n}' myfile.write(filestring) myfile.close() else: dblib.setsinglevalue(pilib.dirs.dbs.system, 'netconfig', 'SSID', '') utility.log( pilib.dirs.logs.network, 'No network found with method selected and auths/ssids available. ', 1, pilib.loglevels.network) else: utility.log(pilib.dirs.logs.network, 'No available ssids found with saved auths.', 1, pilib.loglevels.network)
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 }
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)
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