NEW WebService module; Device Manager improved; installation procedures updated.

Change-Id: I40a70948b830edc387cef6032f6f9fea036ec66f
This commit is contained in:
Nicola Peditto 2018-10-23 13:00:53 +02:00
parent 1b20493251
commit 76f9b5372b
40 changed files with 899 additions and 91 deletions

3
.gitignore vendored
View File

@ -12,4 +12,5 @@ ChangeLog
*.md
.eggs
dist
__pycache__
iotronic_lightningrod/modules/test.py
iotronic_lightningrod/modules/vfs_*

View File

@ -6,6 +6,8 @@ include etc/systemd/system/s4t-lightning-rod.service
include etc/logrotate.d/lightning-rod.log
include scripts/lr_install
include scripts/lr_configure
include scripts/device_bkp_rest
include iotronic_lightningrod/proxies/configs/*
include AUTHORS
include ChangeLog

View File

@ -1,3 +1,6 @@
[DEFAULT]
lightningrod_home = /var/lib/iotronic
skip_cert_verify = True
debug = True
log_file = /var/log/iotronic/lightning-rod.log
proxy = nginx
log_file = /var/log/iotronic/lightning-rod.log

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
from datetime import datetime
import json
@ -48,6 +48,7 @@ class Board(object):
self.location = {}
self.device = None
self.proxy = None
self.wamp_config = None
self.extra = {}
@ -77,9 +78,6 @@ class Board(object):
'''
LOG.info("Lightning-rod home:")
LOG.info(" - " + CONF.lightningrod_home)
# Load all settings.json file
self.iotronic_config = self.loadConf()

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
import os
import signal
@ -33,13 +33,17 @@ def manageTimeout(error_message, action):
os._exit(1)
class NginxError(Exception):
def __init__(self, message):
super(NginxError, self).__init__(message)
class TimeoutError(Exception):
def __init__(self, message, action):
# Call the base class constructor with the parameters it needs
super(TimeoutError, self).__init__(message)
# Now for your custom code...
self.action = action

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
import os
import pkg_resources

View File

@ -13,13 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
import abc
import six
from oslo_log import log as logging
LOG = logging.getLogger(__name__)

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
import abc
import six

View File

@ -0,0 +1,37 @@
# Copyright 2011 OpenStack Foundation
# 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>"
from oslo_log import log as logging
from iotronic_lightningrod.devices.gpio import Gpio
LOG = logging.getLogger(__name__)
class RaspberryGpio(Gpio.Gpio):
def __init__(self):
super(RaspberryGpio, self).__init__("raspberry")
LOG.info("Raspberry GPIO module importing...")
# Enable GPIO
def EnableGPIO(self):
result = " - GPIO not available for 'raspberry' device!"
LOG.info(result)
def DisableGPIO(self):
result = " - GPIO not available for 'raspberry' device!"
LOG.info(result)

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
from oslo_log import log as logging
@ -29,9 +29,9 @@ class ServerGpio(Gpio.Gpio):
# Enable GPIO
def EnableGPIO(self):
result = ' - GPIO not available for server device!'
result = " - GPIO not available for 'server' device!"
LOG.info(result)
def DisableGPIO(self):
result = ' - GPIO not available for server device!'
result = " - GPIO not available for 'server' device!"
LOG.info(result)

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
import os
import time

View File

@ -0,0 +1,56 @@
# Copyright 2011 OpenStack Foundation
# 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 inspect
from iotronic_lightningrod.devices import Device
from iotronic_lightningrod.devices.gpio import raspberry
from oslo_log import log as logging
LOG = logging.getLogger(__name__)
def whoami():
return inspect.stack()[1][3]
def makeNothing():
pass
class System(Device.Device):
def __init__(self):
super(System, self).__init__("raspberry")
raspberry.RaspberryGpio().EnableGPIO()
def finalize(self):
"""Function called at the end of module loading (after RPC registration).
:return:
"""
pass
async def testRPC(self):
rpc_name = whoami()
LOG.info("RPC " + rpc_name + " CALLED...")
await makeNothing()
result = " - " + rpc_name + " result: testRPC is working!!!\n"
LOG.info(result)
return result

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
import inspect

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
from iotronic_lightningrod.devices import Device
from iotronic_lightningrod.devices.gpio import yun

View File

@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
# Autobahn imports
import asyncio
@ -47,16 +47,25 @@ LOG = logging.getLogger(__name__)
lr_opts = [
cfg.StrOpt('lightningrod_home',
default='/var/lib/iotronic',
help=('Lightning Home Data')),
help=('Lightning-rod Home Data')),
cfg.BoolOpt('skip_cert_verify',
default=True,
help=('Flag for skipping the verification of the server cert '
'(for the auto-signed ones)')),
]
proxy_opts = [
cfg.StrOpt(
'proxy',
choices=[('nginx', ('nginx proxy')), ],
help=('Proxy for WebServices Manager')
),
]
CONF = cfg.CONF
CONF.register_opts(lr_opts)
CONF.register_opts(proxy_opts)
SESSION = None
global board
@ -64,6 +73,7 @@ board = None
reconnection = False
RPC = {}
RPC_devices = {}
RPC_proxies = {}
# ASYNCIO
loop = None
@ -168,7 +178,7 @@ def modulesLoader(session):
# LOG.debug(ext.name)
if (ext.name == 'gpio') & (board.type == 'server'):
LOG.info('- GPIO module disabled for laptop devices')
LOG.info("- GPIO module disabled for 'server' devices")
else:
mod = ext.plugin(board, session)
@ -448,7 +458,7 @@ def wampConnect(wamp_conf):
LOG.info("\n\n\nBoard is becoming operative...\n\n\n")
board.updateStatus("operative")
board.loadSettings()
LOG.info("WAMP status @ firt connection:" +
LOG.info("WAMP status @ first connection:" +
"\n- board = " + str(board.status) +
"\n- reconnection = " + str(reconnection) +
"\n- connected = " + str(connected)
@ -674,39 +684,63 @@ def Bye():
def LogoLR():
LOG.info('')
LOG.info('##############################')
LOG.info(' Stack4Things Lightning-rod')
LOG.info('##############################')
def checkIotronicConf(lr_CONF):
try:
if(lr_CONF.log_file == None):
LOG.warning("'log_file' is not specified!")
return False
else:
print("View logs in " + lr_CONF.log_file)
return True
except Exception as err:
print(err)
return False
class LightningRod(object):
def __init__(self):
LogoLR()
LOG.info("LR available modules: ")
for ep in pkg_resources.iter_entry_points(group='s4t.modules'):
LOG.info(" - " + str(ep))
logging.register_options(CONF)
DOMAIN = "s4t-lightning-rod"
CONF(project='iotronic')
logging.setup(CONF, DOMAIN)
if CONF.debug:
txaio.start_logging(level="debug")
if (checkIotronicConf(CONF)):
signal.signal(signal.SIGINT, self.stop_handler)
if CONF.debug:
txaio.start_logging(level="debug")
LogoLR()
signal.signal(signal.SIGINT, self.stop_handler)
global board
board = Board()
LogoLR()
LOG.info('Info:')
LOG.info(' - Logs: /var/log/s4t-lightning-rod.log')
current_time = board.getTimestamp()
LOG.info(" - Current time: " + current_time)
global board
board = Board()
self.w = WampManager(board.wamp_config)
LOG.info('Lightning-rod configurations:')
LOG.info(' - Logs: ' + CONF.log_file)
LOG.info(" - Current time: " + board.getTimestamp())
LOG.info(" - Home: " + CONF.lightningrod_home)
LOG.info(" - WebServices Proxy: " + CONF.proxy)
self.w.start()
self.w = WampManager(board.wamp_config)
self.w.start()
else:
Bye()
def stop_handler(self, signum, frame):
LOG.info("LR is shutting down...")

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
import abc
import six

View File

@ -13,16 +13,20 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
import imp
import importlib as imp
import inspect
import os
import subprocess
from datetime import datetime
from iotronic_lightningrod.config import package_path
from iotronic_lightningrod.lightningrod import RPC_devices
from iotronic_lightningrod.lightningrod import SESSION
from iotronic_lightningrod.modules import Module
from iotronic_lightningrod.modules import utils
from oslo_log import log as logging
@ -36,15 +40,19 @@ class DeviceManager(Module.Module):
# 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.load_source("device", path)
device_module = imp.import_module(
"iotronic_lightningrod.devices." + device_type
)
LOG.info(" - Device " + device_type + " module imported!")
LOG.info(" - Device '" + device_type + "' module imported!")
device = device_module.System()
@ -60,7 +68,7 @@ class DeviceManager(Module.Module):
board.device = device
else:
LOG.warning("Device " + device_type + " not supported!")
LOG.warning("Device '" + device_type + "' not supported!")
def finalize(self):
pass
@ -82,3 +90,52 @@ class DeviceManager(Module.Module):
SESSION.register(meth[1], rpc_addr)
LOG.info(" --> " + str(meth[0]) + " registered!")
async def DevicePing(self):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED")
return datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')
async def DeviceReboot(self):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED")
command = "reboot"
subprocess.call(command, shell=True)
return datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')
async def DeviceHostname(self):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED")
command = "hostname"
# subprocess.call(command, shell=True)
out = subprocess.Popen(
command,
shell=True,
stdout=subprocess.PIPE
)
output = out.communicate()[0].decode('utf-8').strip()
print(output)
return str(output) + "@" + \
str(datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f'))
"""
async def DeviceWampDisconnect(self):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED")
import threading, time
def delayDisconnection():
time.sleep(5)
SESSION.disconnect()
threading.Thread(target=delayDisconnection).start()
return "Device disconnection in 5 seconds..."
"""

View File

@ -14,10 +14,10 @@
# under the License.
from __future__ import absolute_import
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
from datetime import datetime
import imp
import importlib as imp
import json
import os
import queue
@ -166,7 +166,11 @@ class PluginManager(Module.Module):
if os.path.exists(plugin_filename):
task = imp.load_source("plugin", plugin_filename)
# task = imp.load_source("plugin", plugin_filename)
task = imp.machinery.SourceFileLoader(
"plugin",
plugin_filename
).load_module()
if os.path.exists(plugin_params_file):
@ -362,7 +366,10 @@ class PluginManager(Module.Module):
# Import plugin (as python module)
if os.path.exists(plugin_filename):
task = imp.load_source("plugin", plugin_filename)
task = imp.machinery.SourceFileLoader(
"plugin",
plugin_filename
).load_module()
LOG.info(" - Plugin '" + plugin_uuid + "' imported!")
@ -527,7 +534,11 @@ class PluginManager(Module.Module):
try:
task = imp.load_source("plugin", plugin_filename)
# task = imp.load_source("plugin", plugin_filename)
task = imp.machinery.SourceFileLoader(
"plugin",
plugin_filename
).load_module()
LOG.info(" - Plugin " + plugin_uuid + " imported!")
@ -751,7 +762,11 @@ class PluginManager(Module.Module):
if os.path.exists(plugin_filename):
# Import plugin python module
task = imp.load_source("plugin", plugin_filename)
# task = imp.load_source("plugin", plugin_filename)
task = imp.machinery.SourceFileLoader(
"plugin",
plugin_filename
).load_module()
if parameters is None:

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
from datetime import datetime
import errno

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
import asyncio
@ -38,6 +38,6 @@ class Test(Module.Module):
return result
async def add(self, x, y):
c = await x + y
c = x + y
LOG.info("DEVICE add result: " + str(c))
return c

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
import asyncio
import inspect

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
import errno
from fuse import FuseOSError

View File

@ -14,7 +14,7 @@
# under the License.
from __future__ import with_statement
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
import errno
import os

View File

@ -0,0 +1,151 @@
# 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>"
from iotronic_lightningrod.modules import Module
from oslo_config import cfg
from oslo_log import log as logging
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
import importlib as imp
import inspect
import json
import os
from iotronic_lightningrod.config import package_path
from iotronic_lightningrod.lightningrod import RPC_proxies
from iotronic_lightningrod.lightningrod import SESSION
from iotronic_lightningrod.modules import utils
import iotronic_lightningrod.wampmessage as WM
class WebServiceManager(Module.Module):
def __init__(self, board, session):
super(WebServiceManager, self).__init__("WebServiceManager", board)
LOG.info(" - Proxy used: " + CONF.proxy.upper())
proxy_type = CONF.proxy
path = package_path + "/proxies/" + proxy_type + ".py"
if os.path.exists(path):
proxy_module = imp.import_module("iotronic_lightningrod.proxies."
+ proxy_type)
LOG.info(" --> " + proxy_type.upper() + " module imported!")
proxy = proxy_module.ProxyManager()
proxy_meth_list = inspect.getmembers(
proxy,
predicate=inspect.ismethod
)
RPC_proxies[proxy_type] = proxy_meth_list
board.proxy = proxy
self._proxyWampRegister(proxy_meth_list, board)
else:
LOG.warning("Proxy '" + proxy_type + "' not supported!")
def finalize(self):
proxy_status = json.loads(self.board.proxy._proxyInfo())
LOG.info("--> Proxy " + self.board.proxy.type.upper()
+ " status:\n Active: " + str(proxy_status['status'])
+ "\n Info: " + str(proxy_status['log']))
LOG.info("Webservice exposed on device:")
active_webservice_list = self.board.proxy._webserviceList()
if len(active_webservice_list) != 0:
for ws in active_webservice_list:
LOG.info("-> " + ws)
else:
LOG.info("-> NO WebService!")
LOG.info("WebService Manager initialized!")
def restore(self):
LOG.info("WebService Manager restored.")
def _proxyWampRegister(self, proxy_meth_list, board):
LOG.info(" - " + str(board.proxy.type).upper()
+ " proxy registering RPCs:")
for meth in proxy_meth_list:
if (meth[0] != "__init__") & (meth[0] != "finalize") \
& (meth[0] != "restore"):
# LOG.info(" - " + str(meth[0]))
rpc_addr = u'iotronic.' + board.uuid + '.' + meth[0]
# LOG.debug(" --> " + str(rpc_addr))
if not meth[0].startswith('_'):
SESSION.register(meth[1], rpc_addr)
LOG.info(" --> " + str(meth[0]))
async def ExposeWebservice(self, service_name, local_port):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED")
response = self.board.proxy._exposeWebservice(service_name, local_port)
response = json.loads(response)
if(response['result'] == "SUCCESS"):
message = "Webservice '" + service_name + "' successfully exposed!"
LOG.info("--> " + str(message))
w_msg = WM.WampSuccess(response)
else:
message = "Error exposing webservice '" + service_name + "'"
LOG.warning("--> " + str(response['message']))
w_msg = WM.WampWarning(response)
return w_msg.serialize()
async def UnexposeWebservice(self, service_name):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED")
response = self.board.proxy._disableWebservice(service_name)
response = json.loads(response)
if (response['result'] == "SUCCESS"):
LOG.info("--> " + str(response['message']))
w_msg = WM.WampSuccess(response)
else:
LOG.warning("--> " + str(response['message']))
w_msg = WM.WampWarning(response)
return w_msg.serialize()
async def BoardDnsCertsSetup(self, board_dns, owner_email):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED")
message = self.board.proxy._proxyBoardDnsSetup(board_dns, owner_email)
w_msg = WM.WampSuccess(message)
return w_msg.serialize()

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
import abc
import six
@ -23,19 +23,6 @@ from oslo_log import log as logging
LOG = logging.getLogger(__name__)
"""
from twisted.internet.defer import inlineCallbacks
@inlineCallbacks
def sendNotification(msg=None):
try:
res = yield SESSION.call(u'agent.stack4things.echo', msg)
LOG.info("NOTIFICATION " + str(res))
except Exception as e:
LOG.warning("NOTIFICATION error: {0}".format(e))
"""
@six.add_metaclass(abc.ABCMeta)
class Plugin(threading.Thread):
@ -63,13 +50,6 @@ class Plugin(threading.Thread):
def stop(self):
self._is_running = False
"""
def Done(self):
self.setStatus("COMPLETED")
sendNotification(msg="hello!")
self.checkStatus()
"""
def checkStatus(self):
# LOG.debug("Plugin " + self.name + " check status: " + self.status)
return self.status

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
import _pickle as pickle

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
import httplib2
import json

View File

@ -0,0 +1 @@
{"name":"LR"}

View File

@ -27,6 +27,6 @@ class Worker(Plugin.Plugin):
super(Worker, self).__init__(uuid, name, q_result, params)
def run(self):
LOG.info("Input parameters: " + str(self.params))
LOG.info("Input parameters: " + str(self.params['name']))
LOG.info("Plugin " + self.name + " process completed!")
self.q_result.put("ZERO RESULT")
self.q_result.put("ECHO RESULT: "+str(self.params['name']))

View File

@ -0,0 +1,35 @@
# Copyright 2011 OpenStack Foundation
# 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 abc
import six
from oslo_log import log as logging
LOG = logging.getLogger(__name__)
@six.add_metaclass(abc.ABCMeta)
class Proxy(object):
"""Base class for proxies supported by Iotornic.
"""
def __init__(self, proxy_type):
self.type = proxy_type
def finalize(self):
pass

View File

@ -0,0 +1,7 @@
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

View File

@ -0,0 +1,7 @@
server {
listen 80;
listen [::]:80;
server_name BOARD_DNS;
include conf.d/iotronic/*;
}

View File

@ -0,0 +1,374 @@
# Copyright 2011 OpenStack Foundation
# 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>"
from iotronic_lightningrod.proxies import Proxy
from oslo_log import log as logging
LOG = logging.getLogger(__name__)
import json
import os
import site
import subprocess
import time
from iotronic_lightningrod.common.exception import NginxError
from iotronic_lightningrod.modules import utils
import iotronic_lightningrod.wampmessage as WM
from subprocess import call
class ProxyManager(Proxy.Proxy):
def __init__(self):
super(ProxyManager, self).__init__("nginx")
def finalize(self):
"""Function called at the end of module loading (after RPC registration).
:return:
"""
pass
def _proxyInfo(self):
nginxMsg = {}
try:
stat = subprocess.Popen('systemctl status nginx.service',
shell=True, stdout=subprocess.PIPE)
stdout_list = str(stat.communicate()[0]).split('\n')
for line in stdout_list:
if 'Active:' in line:
nginxMsg['log'] = line.split('\\n')[2].replace(" ", "")
if '(running)' in line:
nginxMsg['status'] = True
else:
nginxMsg['status'] = False
nginxMsg = json.dumps(nginxMsg)
return nginxMsg
except Exception as err:
LOG.error("Error check NGINX status: " + str(err))
nginxMsg['log'] = str(err)
nginxMsg['status'] = False
nginxMsg = json.dumps(nginxMsg)
return nginxMsg
def _proxyStatus(self):
nginxMsg = {}
try:
stat = subprocess.Popen(
'systemctl status nginx.service',
shell=True,
stdout=subprocess.PIPE
)
stdout_list = str(stat.communicate()[0]).split('\n')
for line in stdout_list:
if 'Active:' in line:
if '(running)' in line:
nginxMsg['log'] = "NGINX is running"
nginxMsg['status'] = True
# LOG.info("--> " + nginxMsg['log'])
else:
nginxMsg['log'] = "NGINX is not running"
nginxMsg['status'] = False
# LOG.warning("--> " + nginxMsg['log'])
except Exception as err:
nginxMsg['log'] = "Error check NGINX status: " + str(err)
nginxMsg['status'] = True
# LOG.error("--> " + nginxMsg['log'])
return json.dumps(nginxMsg)
def _proxyReload(self):
nginxMsg = {}
try:
stat = subprocess.call('service nginx reload', shell=True)
if stat != 0:
raise NginxError(str(stat))
else:
nginxMsg['log'] = "NGINX successfully reloaded"
nginxMsg['code'] = stat
LOG.info("--> " + nginxMsg['log'])
except NginxError:
nginxMsg['log'] = "NGINX reloading error"
nginxMsg['code'] = stat
LOG.warning("--> " + nginxMsg['log'])
except Exception as err:
nginxMsg['log'] = "NGINX Generic error: " + str(err)
nginxMsg['code'] = stat
LOG.warning("--> " + nginxMsg['log'])
nginxMsg = json.dumps(nginxMsg)
return nginxMsg
def _proxyRestart(self):
nginxMsg = {}
try:
stat = os.system('systemctl restart nginx')
if stat != 0:
raise NginxError(str(stat))
else:
nginxMsg['log'] = "NGINX successfully restart"
nginxMsg['code'] = stat
LOG.info("--> " + nginxMsg['log'])
except NginxError:
nginxMsg['log'] = "NGINX restarting error"
nginxMsg['code'] = stat
LOG.warning("--> " + nginxMsg['log'])
except Exception as err:
nginxMsg['log'] = "NGINX generic error: " + str(err)
nginxMsg['code'] = stat
LOG.warning("--> " + nginxMsg['log'])
return json.dumps(nginxMsg)
def _proxyBoardDnsSetup(self, board_dns, owner_email):
nginxMsg = {}
try:
py_dist_pack = site.getsitepackages()[0]
iotronic_nginx_path = "/etc/nginx/conf.d/iotronic"
iotronic_nginx_default = "/etc/nginx/conf.d/iotronic/default"
if not os.path.exists(iotronic_nginx_path):
os.makedirs(iotronic_nginx_path)
nginx_default = '''proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";'''
with open(iotronic_nginx_default, "w") as text_file:
text_file.write("%s" % nginx_default)
iotronic_nginx_avl_path = "/etc/nginx/sites-available/iotronic"
string = '''server {{
listen 80;
server_name {0};
include conf.d/iotronic/*;
}}'''.format(board_dns)
with open(iotronic_nginx_avl_path, "w") as text_file:
text_file.write("%s" % string)
os.system(
'ln -s '
'/etc/nginx/sites-available/iotronic '
'/etc/nginx/sites-enabled/'
)
time.sleep(3)
self._proxyReload()
time.sleep(3)
command = '/usr/bin/certbot -n ' \
'--redirect --authenticator webroot ' \
'--installer nginx -w /var/www/html/ ' \
'--domain ' + board_dns + ' --agree-tos ' \
'--email ' + owner_email
LOG.debug(command)
call(command, shell=True)
except Exception as err:
nginxMsg['log'] = "NGINX DNS setup error: " + str(err)
nginxMsg['code'] = ""
LOG.warning("--> " + nginxMsg['log'])
return json.dumps(nginxMsg)
def _exposeWebservice(self, service_name, local_port):
nginxMsg = {}
try:
nginx_path = "/etc/nginx/conf.d/iotronic"
if not os.path.exists(nginx_path):
os.makedirs(nginx_path)
fp = nginx_path + "/" + service_name
string = '''location /{0}/ {{
proxy_pass http://localhost:{1}/;
include conf.d/iotronic/default;
}}
location /{0} {{
rewrite ^ $scheme://$http_host/{0}/ redirect;
}}
'''.format(service_name, local_port)
with open(fp, "w") as ws_nginx_conf:
ws_nginx_conf.write("%s" % string)
time.sleep(3)
nginxMsg['message'] = "Webservice '" + service_name + \
"' configuration injected in NGINX."
nginxMsg['result'] = "SUCCESS"
LOG.info("--> " + nginxMsg['message'])
self._proxyReload()
time.sleep(3)
except Exception as e:
nginxMsg['message'] = "Error exposing Webservice '" + \
service_name + \
"' configuration in NGINX: {}".format(e)
nginxMsg['result'] = "ERROR"
LOG.warning("--> " + nginxMsg['message'])
return json.dumps(nginxMsg)
def _disableWebservice(self, service_name):
nginxMsg = {}
try:
nginx_path = "/etc/nginx/conf.d/iotronic"
service_path = nginx_path + "/" + service_name
if os.path.exists(service_path):
os.remove(service_path)
time.sleep(3)
nginxMsg['message'] = "webservice '" \
+ service_name + "' disabled."
nginxMsg['result'] = "SUCCESS"
# LOG.info("--> " + nginxMsg['message'])
self._proxyReload()
time.sleep(3)
else:
nginxMsg['message'] = "webservice file " \
+ service_path + " does not exist"
nginxMsg['result'] = "ERROR"
# LOG.info("--> " + nginxMsg['message'])
except Exception as e:
nginxMsg['message'] = "Error disabling Webservice '" + \
service_name + "': {}".format(e)
nginxMsg['result'] = "ERROR"
# LOG.warning("--> " + nginxMsg['message'])
return json.dumps(nginxMsg)
def _webserviceList(self):
nginx_path = "/etc/nginx/conf.d/iotronic"
if os.path.exists(nginx_path):
service_list = [f for f in os.listdir(nginx_path)
if os.path.isfile(os.path.join(nginx_path, f))]
service_list.remove('default')
else:
service_list = []
return service_list
async def NginxInfo(self):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED")
message = self._proxyInfo()
w_msg = WM.WampSuccess(message)
return w_msg.serialize()
async def NginxStatus(self):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED")
message = self._proxyStatus()
w_msg = WM.WampSuccess(message)
return w_msg.serialize()
async def NginxReload(self):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED")
message = self._proxyReload()
w_msg = WM.WampSuccess(message)
return w_msg.serialize()
async def NginxRestart(self):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED")
message = self._proxyRestart()
w_msg = WM.WampSuccess(message)
return w_msg.serialize()
async def NginxIotronicConf(self):
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED")
message = self._proxyIotronicConf()
w_msg = WM.WampSuccess(message)
return w_msg.serialize()

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = "Nicola Peditto <npeditto@unime.it"
__author__ = "Nicola Peditto <n.peditto@gmail.com>"
import json

39
scripts/device_bkp_rest Executable file
View File

@ -0,0 +1,39 @@
#!/bin/bash
echo "Option chosen: "$1 $2
if [ "$1" = "backup" ]; then
if [ "$#" -ne 1 ]; then
echo "You have to specify: 'restore' <BACKUP_FILE> "
exit
fi
# BACKUP
echo "Backing up Iotronic configuration"
now_date=`date '+%Y%m%d%H%M%S'`
device=`cat /etc/iotronic/settings.json | grep name | awk '{print $2}' | tr -d \" | tr -d ,`
bkp_filename="bkp_"$device"_"$now_date".tar.gz"
echo "-> backup filename: " $bkp_filename
tar zcvf $bkp_filename /var/lib/iotronic /etc/iotronic /etc/letsencrypt /etc/nginx > /dev/null
elif [ "$1" = "restore" ]; then
if [ "$#" -ne 2 ]; then
echo "You have to specify: 'restore' <BACKUP_FILE> "
exit
fi
# RESTORE
echo "Restoring Iotronic configuration"
tar -xvzf $2 -C /
service nginx restart
sleep 3
echo -e "\nCompleted!"
else
echo "You have to specify:"
echo " - for backup: 'backup'"
echo " - for restore: 'restore' <backup-filename-to-restore>"
exit
fi

View File

@ -22,8 +22,8 @@ if len(sys.argv) < 3:
print('Arguments required: "<REGISTRATION-TOKEN> <WAMP-REG-AGENT-URL>',
str(sys.argv))
else:
os.system('sed -i "s|<REGISTRATION-TOKEN>|'
+ sys.argv[1] + '|g" /etc/iotronic/settings.json')
os.system('sed -i "s|ws://<WAMP-SERVER>:<WAMP-PORT>/|'
+ sys.argv[2] + '|g" /etc/iotronic/settings.json')
os.system('sed -i "s|\\"code\\":.*|\\"code\\": \\"'
+ sys.argv[1] + '\\"|g" /etc/iotronic/settings.json')
os.system('sed -i "s|\\"url\\":.*|\\"url\\": \\"'
+ sys.argv[2] + '\\",|g" /etc/iotronic/settings.json')
os.system('sed -i "s|<IOTRONIC-REALM>|s4t|g" /etc/iotronic/settings.json')

View File

@ -18,10 +18,18 @@
import os
import site
if os.path.exists('/iotronic_lightningrod/'):
print("Cleaning install folders...")
os.system('rm -rf ' + site.getsitepackages()[0]
+ '/iotronic_lightningrod/etc')
os.system('rm -rf ' + site.getsitepackages()[0]
+ '/iotronic_lightningrod/templates')
print("Moving installation folders...")
os.system('mv -f /iotronic_lightningrod/* '
+ site.getsitepackages()[0] + '/iotronic_lightningrod/')
py_dist_pack = site.getsitepackages()[0]
print(py_dist_pack)
print("Python packages folder: " + py_dist_pack)
print('Iotronic environment creation:')
if not os.path.exists('/etc/iotronic/'):

View File

@ -4,7 +4,7 @@ summary = Implementation of the Lightning-rod, the Stack4Things board-side probe
description-file =
README.rst
author = Nicola Peditto, Fabio Verboso
author-email = unime.mdslab@gmail.com
author-email = n.peditto@gmail.com
home-page = http://stack4things.unime.it/
classifier =
Environment :: OpenStack
@ -21,7 +21,7 @@ classifier =
[files]
packages =
iotronic_lightningrod
data_files =
data-files =
bin/ = scripts/*
/iotronic_lightningrod/templates = templates/*
/iotronic_lightningrod/etc/iotronic = etc/iotronic/iotronic.conf
@ -65,8 +65,9 @@ s4t.modules =
plugin = iotronic_lightningrod.modules.plugin_manager:PluginManager
device = iotronic_lightningrod.modules.device_manager:DeviceManager
service = iotronic_lightningrod.modules.service_manager:ServiceManager
network = iotronic_lightningrod.modules.network_manager:NetworkManager
# vfs = iotronic_lightningrod.modules.vfs_manager:VfsManager
# network = iotronic_lightningrod.modules.network_manager:NetworkManager
webservice = iotronic_lightningrod.modules.webservice_manager:WebServiceManager
# vfs = iotronic_lightningrod.modules.vfs_manager:VfsManager
[options]
build_scripts =