def runFunction(functionName, functionParameterValues):
    # Always assign a uuid to a function if not already
    if (functionParameterValues.has_key("functionUuid") == False):
        functionParameterValues["functionUuid"] = comDavra.generateUuid()
    # Put a file to indicate what is happening and start the function
    comDavra.provideFreshDirectory(currentFunctionDir)
    functionInfo = { 'functionName': functionName, \
        'functionParameterValues': functionParameterValues, \
        'status': 'running', \
        'startTime': comDavra.getMilliSecondsSinceEpoch() }
    with open(currentFunctionDir + '/currentFunction.json', 'w') as outfile:
        json.dump(functionInfo, outfile, indent=4)
    # Only run functions which are within capabilities
    if (comDavra.conf["capabilities"].has_key(functionName) is False):
        comDavra.logError(
            'Error: Attemping to to run a function which is not in capabilities: '
            + functionName)
        comDavra.logError('Error: Capabilities: ' +
                          str(comDavra.conf["capabilities"]))
        comDavra.upsertJsonEntry(currentFunctionJson, 'status', 'failed')
        return
    #
    comDavra.log('Running a function:' + json.dumps(functionInfo))
    flagIsFunctionRunning = True
    #
    # Is this capability something the agent knows how to do
    if (functionName in agentCapabilityFunctions):
        comDavra.log('Will run this function within the agent')
        agentCapabilityFunctions[functionName](functionParameterValues)
    else:
        # Send it onwards to the apps who may be able to do it
        comDavra.log(
            'Will run this function within an app rather than the agent')
        sendMessageFromAgentToApps(functionInfo)
    return
def sendIotDataToServer(msgFromMqtt):
    comDavra.log('Sending iotdata to server ')
    print(str(msgFromMqtt))
    dataFromAgent = json.loads(msgFromMqtt["sendIotData"])
    if (type(dataFromAgent) == type({})):
        dataFromAgent = [dataFromAgent]
    dataForServer = []
    for metric in dataFromAgent:
        if (metric.has_key("UUID") == False):
            metric["UUID"] = comDavra.conf["UUID"]
        if ("timestamp" not in metric):
            metric["timestamp"] = comDavra.getMilliSecondsSinceEpoch()
        if ("name" in metric and "value" in metric and "msg_type" in metric):
            comDavra.log('Sending data now to server ')
            print(str(metric))
            dataForServer.append(metric)
        else:
            comDavra.logError(
                'Not sending data to server as it appears incomplete: ' +
                str(metric))
    if dataForServer:
        comDavra.log('Sending data to Server: ' + str(dataForServer))
        statusCode = comDavra.sendDataToServer(dataForServer).status_code
        comDavra.log('Response after sending iotdata to server: ' +
                     str(statusCode))
def agentFunctionRunScriptBash(functionParameterValues):
    if "script" not in functionParameterValues:
        comDavra.upsertJsonEntry(currentFunctionJson, 'response',
                                 'script missing')
        comDavra.upsertJsonEntry(currentFunctionJson, 'status', 'failed')
        comDavra.logError(
            'Could not run script as function because no script to run')
        checkFunctionFinished()
        return
    # Put the script into the function dir
    scriptFile = open(currentFunctionDir + "/script.sh", "a")
    scriptFile.write(str(functionParameterValues["script"]))
    scriptFile.close()
    comDavra.logInfo('Running script ' +
                     str(functionParameterValues["script"]))
    os.system("chmod 777 " + currentFunctionDir + "/script.sh")
    time.sleep(0.5)  # Time for file flush to disk
    # Run the script with -x flag so it prints each command before ruuning it.
    # This allows the UI to show it formatted better for user on jobs page
    scriptResponse = comDavra.runCommandWithTimeout('cd ' + currentFunctionDir + \
    ' && sudo bash -x ' + currentFunctionDir + "/script.sh", comDavra.conf["scriptMaxTime"])
    # scriptResponse is a tuple of (exitStatusCode, stdout) . For exitStatusCode: 0 = success, 1 = failed )
    comDavra.log("Script response: " + str(scriptResponse[1]))
    scriptStatus = 'completed' if (scriptResponse[0] == 0) else 'failed'
    comDavra.upsertJsonEntry(currentFunctionJson, 'response',
                             str(scriptResponse[1]))
    comDavra.upsertJsonEntry(currentFunctionJson, 'status', scriptStatus)
    checkFunctionFinished()
def runDavraJob(jobObject):
    # Catch situation where a job is already running
    if (os.path.isfile(currentJobJson) == True):
        comDavra.logWarning(
            'A job is already running. Will not start another job. ' +
            jobObject["UUID"])
        return
    comDavra.log('Start Run of job ' + jobObject["UUID"])
    try:
        flagIsJobRunning = True
        # Write this job to disk as the current job
        jobObject['devices'][0][
            'startTime'] = comDavra.getMilliSecondsSinceEpoch()
        jobObject['devices'][0]['status'] = 'running'
        comDavra.provideFreshDirectory(currentJobDir)
        with open(currentJobJson, 'w') as outfile:
            json.dump(jobObject, outfile, indent=4)
        if (jobObject.has_key('jobConfig')
                and jobObject['jobConfig']['type'].lower() == 'runfunction'):
            comDavra.logInfo('Job Run: type is runFunction. ' +
                             jobObject['jobConfig']['functionName'])
            runFunction(jobObject['jobConfig']['functionName'],
                        jobObject['jobConfig']['functionParameterValues'])
            return
        # Reaching here means the job type was not recognised so that is a failed situation
        updateJobWithResult('failed', 'Unknown job type')
        checkCurrentJob()
        return
    except Exception as e:
        # Reaching here means the job type was not recognised so that is a failed situation
        comDavra.logError('Job Error ' + str(e))
        updateJobWithResult('failed', 'Unknown job type')
        checkCurrentJob()
        return
def mqttOnMessageDevice(client, userdata, msg):
    payload = str(msg.payload)
    if (comDavra.isJson(payload)):
        processMessageFromAppToAgent(json.loads(payload))
    else:
        comDavra.logError(
            'ERROR: Mqtt Device Broker: Received NON json Mqtt message: ' +
            payload)
    return
def checkFunctionFinished():
    currentFunctionInfo = None
    if (os.path.isfile(currentFunctionJson) == True):
        with open(currentFunctionJson) as data_file:
            currentFunctionInfo = json.load(data_file)
        if (currentFunctionInfo.has_key("status")):
            if (currentFunctionInfo["status"] == 'completed'
                    or currentFunctionInfo["status"] == 'failed'):
                # Function has finished, report back if part of a currently running job
                functionResponse = currentFunctionInfo[
                    "response"] if currentFunctionInfo.has_key(
                        "response") else ""
                reportFunctionFinishedAsEventToServer(currentFunctionInfo)
                updateJobWithResult(currentFunctionInfo["status"],
                                    functionResponse)
                comDavra.provideFreshDirectory(
                    currentFunctionDir
                )  # Wipe the currently running function files
                flagIsFunctionRunning = False
                comDavra.log('Function finished ' +
                             json.dumps(currentFunctionInfo))
            else:
                # Has the function been running for too long. If so, declare it as failed
                if (currentFunctionInfo.has_key("startTime") is True):
                    if(comDavra.getMilliSecondsSinceEpoch() - int(currentFunctionInfo["startTime"]) \
                    > int(comDavra.conf["scriptMaxTime"]) * 1000):
                        comDavra.logWarning(
                            'Function has been running for too long - declare it failed'
                        )
                        currentFunctionInfo["status"] = "failed"
                        currentFunctionInfo[
                            "endTime"] = comDavra.getMilliSecondsSinceEpoch()
                        with open(currentFunctionDir + '/currentFunction.json',
                                  'w') as outfile:
                            json.dump(currentFunctionInfo, outfile, indent=4)
                        reportFunctionFinishedAsEventToServer(
                            currentFunctionInfo)
                        flagIsFunctionRunning = False
                        comDavra.logWarning(
                            'Function finished due to timeout ' +
                            json.dumps(currentFunctionInfo))
            # If a function has finished, it may have been part of a job. Check if that is finished
            checkCurrentJob()
            return
        else:
            comDavra.logError(
                'Error situation. Function has no status. Should not occur.')
    return
def agentFunctionPushAppWithInstaller(functionParameterValues):
    comDavra.logInfo(
        'Function: Pushing Application onto device to run as a service ' +
        str(functionParameterValues))
    if (functionParameterValues["Installation File"]):
        installationFile = functionParameterValues["Installation File"]
        # Download the app tarball
        try:
            tmpPath = '/tmp/' + str(comDavra.getMilliSecondsSinceEpoch())
            comDavra.ensureDirectoryExists(tmpPath)
            comDavra.runCommandWithTimeout(
                'cd ' + tmpPath + ' && /usr/bin/curl -LO ' + installationFile,
                300)
            comDavra.runCommandWithTimeout(
                'cd ' + tmpPath + ' && /bin/tar -xvf ./* ', 300)
            comDavra.runCommandWithTimeout(
                'cd ' + tmpPath + ' && chmod 777 ./* ', 300)
            # Ensure the install.sh is unix format
            comDavra.runCommandWithTimeout(
                "cd " + tmpPath + " &&  sed -i $'s/\r$//' install.sh ", 30)
            installedAppPath = comDavra.installationDir + '/apps/' + str(
                comDavra.getMilliSecondsSinceEpoch())
            comDavra.ensureDirectoryExists(installedAppPath)
            comDavra.runCommandWithTimeout(
                'cd ' + tmpPath + ' && cp -r * ' + installedAppPath, 300)
            installResponse = comDavra.runCommandWithTimeout(
                'cd ' + installedAppPath + ' && bash ./install.sh ',
                comDavra.conf["scriptMaxTime"])
            comDavra.log('Installation response: ' + str(installResponse[1]))
            scriptStatus = 'completed' if (installResponse[0]
                                           == 0) else 'failed'
            comDavra.upsertJsonEntry(currentFunctionJson, 'response',
                                     str(installResponse[1]))
            comDavra.upsertJsonEntry(currentFunctionJson, 'status',
                                     scriptStatus)
        except Exception as e:
            comDavra.logError('Failed to download application:' +
                              installationFile + " : Error: " + str(e))
            comDavra.upsertJsonEntry(currentFunctionJson, 'status', 'failed')
            checkFunctionFinished()
        comDavra.log('Finished agentFunctionPushAppWithInstaller')
        checkFunctionFinished()
    else:
        comDavra.logWarning('Action parameters missing, nothing to do')
    # TODO
    return
def reportJobStatus():
    comDavra.log('Current job is finished so reporting it to server now')
    jobObject = None
    with open(currentJobJson) as data_file:
        jobObject = json.load(data_file)
    deviceJobObject = jobObject['devices'][0]
    headers = comDavra.getHeadersForRequests()
    apiEndPoint = comDavra.conf['server'] + '/api/v1/jobs/' + jobObject[
        'UUID'] + '/' + deviceJobObject['UUID']
    comDavra.logInfo('Reporting job update to server: ' + apiEndPoint + ' : ' +
                     json.dumps(deviceJobObject))
    r = comDavra.httpPut(apiEndPoint, deviceJobObject)
    if (r.status_code == 200):
        comDavra.log("Updated server after running job.")
        # The job has completed and been reflected at the server so delete the currentJobJson file
        os.remove(currentJobJson)
    else:
        comDavra.log("Issue while updating server after running job. " +
                     str(r.status_code))
        comDavra.log(r.content)
    # Report job event to server as an iotdata event
    eventToSend = {
        "UUID": deviceJobObject['UUID'],
        "name": "davra.job.finished",
        "msg_type": "event",
        "value": deviceJobObject,
        "tags": {
            "status": deviceJobObject["status"]
        }
    }
    apiEndPoint = comDavra.conf['server'] + '/api/v1/iotdata'
    r = comDavra.httpPut(apiEndPoint, eventToSend)
    if (r.status_code == 200):
        comDavra.log("Sent event to server after running job.")
    else:
        comDavra.logError(
            "Issue while sending event to server after running job. " +
            str(r.status_code))
        comDavra.logError(r.content)
    comDavra.provideFreshDirectory(
        currentJobDir)  # Remove the file and dir on disk
    flagIsJobRunning = False
    return
def mqttConnectToServer():
    if(comDavra.conf.has_key("mqttBrokerServerHost") and len(comDavra.conf["mqttBrokerServerHost"]) > 3) \
    and comDavra.conf.has_key("apiToken"):
        clientOfServer = mqtt.Client()
        clientOfServer.on_connect = mqttOnConnectServer
        clientOfServer.on_message = mqttOnMessageServer
        comDavra.log(
            'Starting to connect to MQTT broker running on Davra server ' +
            comDavra.conf["mqttBrokerServerHost"])
        apiTokenForDevice = comDavra.conf["apiToken"]
        clientOfServer.username_pw_set(username=comDavra.conf["UUID"],
                                       password=apiTokenForDevice)
        try:
            clientOfServer.connect(comDavra.conf["mqttBrokerServerHost"])
            clientOfServer.loop_start(
            )  # Starts another thread to monitor incoming messages
        except Exception as e:
            comDavra.logError('Experienced error connecting to mqtt at ' +
                              comDavra.conf["mqttBrokerServerHost"] + ":" +
                              str(e))
    else:
        comDavra.logError('No MQTT broker configured for Davra server')
Esempio n. 10
0
def checkForPendingJob():
    headers = comDavra.getHeadersForRequests()
    dataToSend = {
        "deviceUUID": comDavra.conf['UUID'],
        "deviceStatus": "pending",
        "jobStatus": "active",
        "oldest": True
    }
    r = comDavra.httpPut(comDavra.conf['server'] + '/api/v1/jobs', dataToSend)
    if (r.status_code == 200):
        pendingJobs = json.loads(r.content) if comDavra.isJson(
            r.content) else []
        if (pendingJobs != [] and len(pendingJobs) > 0):
            comDavra.log('Pending job to run: ' + str(pendingJobs[0]))
            runDavraJob(pendingJobs[0])
        else:
            comDavra.log('No pending job to run.')
        return
    else:
        comDavra.logError("Issue while checking for pending job. " +
                          str(r.status_code))
        comDavra.logError(r.content)
        return (r.status_code)
Esempio n. 11
0
    if(r.status_code == 200):
        jsonContent = json.loads(r.content)
        latitude = jsonContent['lat']
        longitude = jsonContent['lon']
        return (latitude, longitude)
    else:
        comDavra.logWarning("Cannot reach GeoIp server. " + str(r.status_code))
        return (0,0)

(piLatitude, piLongitude) = getLatLong()
comDavra.log('Latitude/Longitude estimated as ' + str(piLatitude) + ", " + str(piLongitude))


# Confirm MQTT Broker on agent
if(comDavra.checkIsAgentMqttBrokerInstalled() == False):
    comDavra.logError('MQTT Broker not installed')
    comDavra.upsertConfigurationItem("mqttBrokerAgentHost", '')
else:
    comDavra.log('MQTT Broker installed and running')
    comDavra.upsertConfigurationItem("mqttBrokerAgentHost", '127.0.0.1')
    # To enable advanced security on mqtt requiring usernames for connections
    #comDavra.upsertConfigurationItem("mqttRestrictions", 'localhost,username')
    # To enable basic security which is only localhost connections to mqtt
    comDavra.upsertConfigurationItem("mqttRestrictions", 'localhost')
    setDeviceMqttBrokerSecurity()
    
    

# Send an event to the server to inform it of the installation
dataToSend = { 
    "UUID": comDavra.conf['UUID'],
Esempio n. 12
0
clientOfDevice = None
if (comDavra.conf.has_key("mqttBrokerAgentHost")
        and len(comDavra.conf["mqttBrokerAgentHost"]) > 3):
    clientOfDevice = mqtt.Client()
    clientOfDevice.on_connect = mqttOnConnectDevice
    clientOfDevice.on_message = mqttOnMessageDevice
    clientOfDevice.username_pw_set(username=comDavra.conf["UUID"],
                                   password=comDavra.conf["apiToken"])
    comDavra.logInfo('Starting to connect to MQTT broker running on device ' +
                     comDavra.conf["mqttBrokerAgentHost"])
    try:
        clientOfDevice.connect(comDavra.conf["mqttBrokerAgentHost"])
        clientOfDevice.loop_start(
        )  # Starts another thread to monitor incoming messages
    except Exception as e:
        comDavra.logError('Experienced error connecting to mqtt at ' +
                          comDavra.conf["mqttBrokerServerHost"] + ":" + str(e))
else:
    comDavra.logError('No MQTT broker configured on device')

###########################   Process Messages from Device Application to Device Agent


# These messages may arrive by mqtt from app to agent or api calls or flat file comms
# msg should be a json object
def processMessageFromAppToAgent(msg):
    # Ignore any messages this agent published
    if (msg.has_key("fromAgent")):
        return
    comDavra.log('processMessageFromAppToAgent: incoming msg: ' + str(msg))
    if (msg.has_key("registerCapability")):
        capabilityName = msg["registerCapability"]