iotronic-lightning-rod/iotronic_lightningrod/modules/device_manager.py

393 lines
12 KiB
Python

# Copyright 2017 MDSLAB - University of Messina
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
import importlib as imp
import inspect
import os
import subprocess
import threading
import time
from autobahn.wamp import exception
from datetime import datetime
from iotronic_lightningrod.common import utils
from iotronic_lightningrod.config import package_path
from iotronic_lightningrod.lightningrod import RPC_devices
from iotronic_lightningrod.lightningrod import wampNotify
from iotronic_lightningrod.modules import Module
from iotronic_lightningrod.modules import utils as lr_utils
import iotronic_lightningrod.wampmessage as WM
from oslo_log import log as logging
LOG = logging.getLogger(__name__)
class DeviceManager(Module.Module):
def __init__(self, board, session):
# Module declaration
super(DeviceManager, self).__init__("DeviceManager", board)
self.device_session = session
device_type = board.type
path = package_path + "/devices/" + device_type + ".py"
if os.path.exists(path):
device_module = imp.import_module(
"iotronic_lightningrod.devices." + device_type
)
LOG.info(" - Device '" + device_type + "' module imported!")
device = device_module.System()
dev_meth_list = inspect.getmembers(
device,
predicate=inspect.ismethod
)
RPC_devices[device_type] = dev_meth_list
self._deviceWampRegister(dev_meth_list, board)
board.device = device
else:
LOG.warning("Device '" + device_type + "' not supported!")
def finalize(self):
pass
def restore(self):
pass
def _deviceWampRegister(self, dev_meth_list, board):
LOG.info(" - " + str(board.type).capitalize()
+ " device registering RPCs:")
for meth in dev_meth_list:
if (meth[0] != "__init__") & (meth[0] != "finalize"):
LOG.info(" - " + str(meth[0]))
# rpc_addr = u'iotronic.' + board.uuid + '.' + meth[0]
rpc_addr = u'iotronic.' + str(board.session_id) + '.' + \
board.uuid + '.' + meth[0]
# LOG.debug(" --> " + str(rpc_addr))
self.device_session.register(meth[1], rpc_addr)
LOG.info(" --> " + str(meth[0]) + " registered!")
async def DevicePing(self, req_id, parameters=None):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED [req_id: " + str(req_id) + "]")
LOG.info("--> Parameters: " + str(parameters))
command = "hostname"
try:
out = subprocess.Popen(
command,
shell=True,
stdout=subprocess.PIPE
)
output = out.communicate()[0].decode('utf-8').strip()
except Exception as err:
LOG.error("Error in parameters: " + str(err))
output = "N/A"
message = str(output) + " @ " + \
str(datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f'))
w_msg = WM.WampSuccess(message)
return w_msg.serialize()
async def DeviceReboot(self, req_id, parameters=None):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED [req_id: " + str(req_id) + "]")
LOG.info("--> Parameters: " + str(parameters))
delay = 3 # default delay
try:
if parameters['delay'] > 3:
delay = parameters['delay']
except Exception as err:
LOG.error("Error in 'delay' parameter: " + str(err))
LOG.warning("--> default 'delay' parameter set: " + str(delay))
LOG.info("--> delay: " + str(delay))
def delayBoardReboot():
time.sleep(delay)
subprocess.call("reboot", shell=True)
threading.Thread(target=delayBoardReboot).start()
if parameters == None:
message = "Rebooting board in few seconds @" + \
str(datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f'))
else:
message = "Rebooting board in " + str(delay) + " seconds (" \
+ datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f') \
+ ")..."
w_msg = WM.WampSuccess(message)
return w_msg.serialize()
async def DeviceRestartLR(self, req_id, parameters=None):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED [req_id: " + str(req_id) + "]")
LOG.info("--> Parameters: " + str(parameters))
delay = 3 # default delay
try:
if parameters['delay'] > 3:
delay = parameters['delay']
except Exception as err:
LOG.error("Error in 'delay' parameter: " + str(err))
LOG.warning("--> default 'delay' parameter set: " + str(delay))
LOG.info("--> delay: " + str(delay))
# LR restarting
lr_utils.LR_restart_delayed(delay)
message = "Restarting LR in " + str(delay) \
+ " seconds (" \
+ datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f') + ")..."
w_msg = WM.WampSuccess(message)
return w_msg.serialize()
async def DeviceUpgradeLR(self, req_id, parameters=None):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED [req_id: " + str(req_id) + "]")
LOG.info("--> Parameters: " + str(parameters))
try:
version = parameters['version']
except Exception as err:
LOG.info("--> version not specified: set 'latest'")
version = None # latest
if (version != None) and (version != "latest"):
command = "pip3 install iotronic-lightningrod==" + str(version)
else:
command = "pip3 install --upgrade iotronic-lightningrod"
def upgradingLR():
out = subprocess.Popen(
command,
shell=True,
stdout=subprocess.PIPE
)
output = out.communicate()[0].decode('utf-8').strip()
LOG.info("\n" + str(output))
try:
w_msg = WM.WampSuccess(
msg="LR upgraded", req_id=req_id
).serialize()
except Exception as e:
LOG.error(" - Wamp Message error in '"
+ rpc_name + "': " + str(e))
try:
notify = wampNotify(self.device_session, self.board, w_msg)
LOG.info(
" - Notify result '" + rpc_name + "': "
+ str(notify.result) + " - " + str(notify.message)
)
except exception.ApplicationError as e:
LOG.error(" - Notify result '"
+ rpc_name + "' error: " + str(e))
# Restart LR to start new version
lr_utils.LR_restart_delayed(2)
try:
threading.Thread(target=upgradingLR).start()
except Exception as err:
LOG.error("Error in parameters: " + str(err))
w_msg = WM.WampRunning("LR upgrading...")
return w_msg.serialize()
async def DevicePackageAction(self, req_id, parameters=None):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED [req_id: " + str(req_id) + "]")
LOG.info("--> Parameters: " + str(parameters))
try:
mng = parameters['manager'] # apt | apt-get | pip | pip3 | npm
opt = parameters['options'] # -f| --upgrade | etc
cmd = parameters['command'] # install | update | remove
pkg = parameters['package']
version = parameters['version']
command = str(mng)
if opt == None:
command = command + " " + str(cmd) + " " + str(pkg)
else:
command = command + " " + str(opt) + " " + str(cmd) \
+ " " + str(pkg)
if version != None:
if (mng == "pip") or (mng == "pip3"):
command = command + "==" + str(version)
elif (mng == "apt") or (mng == "apt-get"):
command = command + "=" + str(version)
elif mng == "npm":
command = command + "@" + str(version)
else:
command = command + " " + str(pkg)
except Exception as err:
LOG.warning(err)
def actionOnPackage():
out = subprocess.Popen(
command,
shell=True,
stdout=subprocess.PIPE
)
output = out.communicate()[0].decode('utf-8').strip()
LOG.info(str(output))
try:
w_msg = WM.WampSuccess(
msg="Package Action completed", req_id=req_id
).serialize()
except Exception as e:
LOG.error(" - Wamp Message error in '"
+ rpc_name + "': " + str(e))
try:
notify = wampNotify(self.device_session, self.board, w_msg)
LOG.info(
" - Notify result '" + rpc_name + "': "
+ str(notify.result) + " - " + str(notify.message)
)
except exception.ApplicationError as e:
LOG.error(" - Notify result '"
+ rpc_name + "' error: " + str(e))
try:
threading.Thread(target=actionOnPackage).start()
except Exception as err:
LOG.error("Error in parameters: " + str(err))
w_msg = WM.WampSuccess("LR upgrading...")
return w_msg.serialize()
async def DeviceEcho(self, req_id, parameters=None):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED [req_id: " + str(req_id) + "]")
LOG.info("--> Parameters: " + str(parameters))
try:
message = str(parameters['say']) + " @ " + \
str(datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f'))
LOG.info("--> Echo: " + str(message))
except Exception as err:
LOG.warning("Error in parameters: " + str(err))
message = str(datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f'))
LOG.info("--> Echo (no-params): " + str(message))
w_msg = WM.WampSuccess(message)
return w_msg.serialize()
async def DeviceNetConfig(self, req_id, parameters=None):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED [req_id: " + str(req_id) + "]")
LOG.info("--> Parameters: " + str(parameters))
message = getIfconfig()
w_msg = WM.WampSuccess(message)
return w_msg.serialize()
def getIfconfig():
try:
command = "ifconfig"
out = subprocess.Popen(
command,
shell=True,
stdout=subprocess.PIPE
)
output = str(out.communicate()[0].decode('utf-8').strip())
except Exception as err:
LOG.error("Error in 'ifconfig' command: " + str(err))
output = "N/A"
return output