Release 0.5.0:

- added support for wstun allowlist
- fixed nginx proxy
- added GDB management patch
- added DeviceFactoryReset RPC
- added action to force certificates renewing
- added ServicesStatus RPC
- added support Arancino device layout
- updated info API and status page: webservices list added
- fixed deploy scripts
- updated UI
- fixed rest_manager
- updated plugin_manager
- added checks in modules loader
- fixed device_bkp_rest script (restore function)
- rest submit action added
- updated info and status APIs
- Zuul Openstack CI configuration upgraded

Change-Id: I7d5398c2eb8c5d759f2488166a4016c5fcad35d1
This commit is contained in:
Nicola Peditto 2021-11-03 10:27:56 +01:00
parent f5fa5454dd
commit 47d682fff5
23 changed files with 918 additions and 177 deletions

View File

@ -77,6 +77,7 @@ class PamResp(Structure):
def __repr__(self): def __repr__(self):
return "<PamResp %i '%s'>" % (self.resp_retcode, self.resp) return "<PamResp %i '%s'>" % (self.resp_retcode, self.resp)
conv_func = CFUNCTYPE( conv_func = CFUNCTYPE(
c_int, c_int,
c_int, c_int,
@ -90,6 +91,7 @@ class PamWrapper(Structure):
"""pam_conv structure wrapper""" """pam_conv structure wrapper"""
_fields_ = [("conv", conv_func), ("appdata_ptr", c_void_p)] _fields_ = [("conv", conv_func), ("appdata_ptr", c_void_p)]
pamLib_start = libpam.pam_start pamLib_start = libpam.pam_start
pamLib_start.restype = c_int pamLib_start.restype = c_int
pamLib_start.argtypes = [ pamLib_start.argtypes = [

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 arancino
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__("arancino")
arancino.ArancinoGpio().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

@ -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 ArancinoGpio(Gpio.Gpio):
def __init__(self):
super(ArancinoGpio, self).__init__("arancino")
LOG.info("Arancino GPIO module importing...")
# Enable GPIO
def EnableGPIO(self):
result = " - GPIO not available for 'arancino' device!"
LOG.info(result)
def DisableGPIO(self):
result = " - GPIO not available for 'arancino' device!"
LOG.info(result)

View File

@ -65,8 +65,9 @@ class System(Device.Device):
""" """
LOG.info(" - readVoltage CALLED... reading pin " + Apin) LOG.info(" - readVoltage CALLED... reading pin " + Apin)
voltage = self.gpio._readVoltage(Apin) voltage = await self.gpio._readVoltage(Apin)
result = "read voltage for " + Apin + " pin: " + voltage
result = await "read voltage for " + Apin + " pin: " + voltage
LOG.info(result) LOG.info(result)
return result return result

View File

@ -26,7 +26,7 @@ from oslo_log import log as logging
import asyncio import asyncio
import inspect import inspect
import os import os
import pkg_resources # import pkg_resources
import signal import signal
import ssl import ssl
import sys import sys
@ -286,13 +286,22 @@ def iotronic_status(board_status):
wamp_singleCheck(SESSION), wamp_singleCheck(SESSION),
loop loop
) )
alive = alive.result() try:
alive = alive.result(timeout=5)
except asyncio.TimeoutError:
LOG.warning('Check Iotronic request timeout')
alive.cancel()
alive = "alive_req_canceled"
except asyncio.TimeoutError as e:
LOG.error(" - Iotronic check timeout: " + str(e))
alive = "rpc_timeout"
except Exception as e: except Exception as e:
LOG.error(" - Iotronic check: " + str(e)) LOG.error(" - Iotronic check: " + str(e))
alive = e alive = "not_connected"
else: else:
alive = "Not connected!" alive = "not_connected"
return alive return alive
@ -445,6 +454,9 @@ async def IotronicLogin(board, session, details):
# reconnection = False # reconnection = False
else: else:
LOG.warning(
" - " + str(w_msg.result) + ": " + str(w_msg.message)
)
Bye() Bye()
except exception.ApplicationError as e: except exception.ApplicationError as e:
@ -819,8 +831,10 @@ def wampConnect(wamp_conf):
async def onConnectFailure(session, fail_msg): async def onConnectFailure(session, fail_msg):
LOG.warning("WAMP Connection Failure: " + str(fail_msg)) LOG.warning("WAMP Connection Failure: " + str(fail_msg))
"""
LOG.warning(" - timeout set @ " + LOG.warning(" - timeout set @ " +
str(CONF.autobahn.connection_failure_timer)) str(CONF.autobahn.connection_failure_timer))
"""
global connFailure global connFailure
if connFailure != None: if connFailure != None:
@ -930,9 +944,9 @@ def wampConnect(wamp_conf):
LOG.error("Reconnection wrong status!") LOG.error("Reconnection wrong status!")
except IndexError as err: except IndexError as err:
LOG.error(" - Error parsing WAMP url: " + str(err)) LOG.error(" - Error parsing WAMP url: " + str(err))
LOG.error(" --> port or address not specified") LOG.error(" --> port or address not specified")
board.status = "url_wamp_error" board.status = "url_wamp_error"
except Exception as err: except Exception as err:
LOG.error(" - WAMP connection error: " + str(err)) LOG.error(" - WAMP connection error: " + str(err))
@ -1026,68 +1040,73 @@ def modulesLoader(session):
""" """
LOG.info("Available modules: ") try:
ep = [] LOG.info("Available modules: ")
for ep in pkg_resources.iter_entry_points(group='s4t.modules'): ep = []
LOG.info(" - " + str(ep))
if not ep: for ep in pkg_resources.iter_entry_points(group='s4t.modules'):
LOG.info(" - " + str(ep))
LOG.info("No modules available!") if not ep:
sys.exit()
else: LOG.info("No modules available!")
sys.exit()
modules = extension.ExtensionManager( else:
namespace='s4t.modules',
# invoke_on_load=True,
# invoke_args=(session,),
)
LOG.info('Modules to load:') modules = extension.ExtensionManager(
namespace='s4t.modules',
# invoke_on_load=True,
# invoke_args=(session,),
)
for ext in modules.extensions: LOG.info('Modules to load:')
LOG.debug(ext.name) for ext in modules.extensions:
if (ext.name == 'gpio') & (board.type == 'server'): LOG.debug(ext.name)
LOG.info("- GPIO module disabled for 'server' devices")
else: if (ext.name == 'gpio') & (board.type == 'server'):
LOG.info("- GPIO module disabled for 'server' devices")
if ext.name != "rest": else:
mod = ext.plugin(board, session) if ext.name != "rest":
global MODULES mod = ext.plugin(board, session)
MODULES[mod.name] = mod
# Methods list for each module global MODULES
meth_list = inspect.getmembers( MODULES[mod.name] = mod
mod, predicate=inspect.ismethod
)
global RPC # Methods list for each module
RPC[mod.name] = meth_list meth_list = inspect.getmembers(
mod, predicate=inspect.ismethod
)
if len(meth_list) == 3: global RPC
# there are at least two methods for each module: RPC[mod.name] = meth_list
# "__init__" and "finalize"
LOG.info(" - No RPC to register for " if len(meth_list) == 3:
+ str(ext.name) + " module!") # there are at least two methods for each module:
# "__init__" and "finalize"
else: LOG.info(" - No RPC to register for "
LOG.info(" - RPC list of " + str(mod.name) + ":") + str(ext.name) + " module!")
moduleWampRegister(SESSION, meth_list)
# Call the finalize procedure for each module else:
mod.finalize() LOG.info(" - RPC list of " + str(mod.name) + ":")
moduleWampRegister(SESSION, meth_list)
LOG.info("Lightning-rod modules loaded.") # Call the finalize procedure for each module
LOG.info("\n\nListening...") mod.finalize()
except Exception as err:
LOG.warning("Board modules loading error: " + str(err))
LOG.info("Lightning-rod modules loaded.")
LOG.info("\n\nListening...")
def moduleReloadInfo(session): def moduleReloadInfo(session):

View File

@ -21,11 +21,14 @@ import os
import subprocess import subprocess
import threading import threading
import time import time
import json
import requests
from autobahn.wamp import exception from autobahn.wamp import exception
from datetime import datetime from datetime import datetime
from iotronic_lightningrod.common import utils from iotronic_lightningrod.common import utils
# from iotronic_lightningrod.common.exception import timeout
from iotronic_lightningrod.config import package_path from iotronic_lightningrod.config import package_path
from iotronic_lightningrod.lightningrod import RPC_devices from iotronic_lightningrod.lightningrod import RPC_devices
from iotronic_lightningrod.lightningrod import wampNotify from iotronic_lightningrod.lightningrod import wampNotify
@ -495,7 +498,8 @@ class DeviceManager(Module.Module):
+ " " + str(pkg) + " " + str(pkg)
else: else:
command = command + " " + str(cmd) + " " + str(pkg) command = command + " " + str(cmd) \
+ " " + str(pkg)
if 'version' in parameters: if 'version' in parameters:
@ -682,6 +686,41 @@ class DeviceManager(Module.Module):
return w_msg.serialize() return w_msg.serialize()
# SC
async def DeviceFactoryReset(self, req, parameters=None):
req_id = req['uuid']
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED [req_id: " + str(req_id) + "]:")
if parameters is not None:
LOG.info(" - " + rpc_name + " parameters: " + str(parameters))
def FactoryReset():
message = factory_reset()
w_msg = WM.WampSuccess(msg=message, req_id=req_id)
if (req['main_request_uuid'] != None):
wampNotify(self.device_session,
self.board, w_msg.serialize(), rpc_name)
else:
return w_msg
if (req['main_request_uuid'] != None):
LOG.info(" - main request: " + str(req['main_request_uuid']))
try:
threading.Thread(target=FactoryReset).start()
w_msg = WM.WampRunning(msg=rpc_name, req_id=req_id)
except Exception as err:
message = "Error in thr_" + rpc_name + ": " + str(err)
LOG.error(message)
w_msg = WM.WampError(msg=message, req_id=req_id)
else:
w_msg = FactoryReset()
return w_msg.serialize()
# SC # SC
async def DeviceNetConfig(self, req, parameters=None): async def DeviceNetConfig(self, req, parameters=None):
req_id = req['uuid'] req_id = req['uuid']
@ -717,6 +756,136 @@ class DeviceManager(Module.Module):
return w_msg.serialize() return w_msg.serialize()
# SC
async def DeviceRestSubmit(self, req, parameters=None):
req_id = req['uuid']
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED [req_id: " + str(req_id) + "]:")
if parameters is not None:
LOG.info(" - " + rpc_name + " parameters: " + str(parameters))
def RestSubmit():
try:
if 'url' in parameters:
url = str(parameters['url'])
else:
message = "Error RestSubmit: no url specified."
LOG.error(message)
w_msg = WM.WampError(msg=message, req_id=req_id)
return w_msg
if 'method' in parameters:
method = str(parameters['method'])
else:
message = "Error RestSubmit: no REST method specified."
LOG.error(message)
w_msg = WM.WampError(msg=message, req_id=req_id)
return w_msg
response = requests.request(
method,
url,
params=json.dumps(parameters['params']) if '\
params' in parameters else None,
data=json.dumps(parameters['data']) if '\
data' in parameters else None,
json=parameters['json'] if '\
json' in parameters else None,
headers=parameters['headers'] if '\
headers' in parameters else None,
cookies=parameters['cookies'] if '\
cookies' in parameters else None,
files=parameters['files'] if '\
files' in parameters else None,
auth=parameters['auth'] if '\
auth' in parameters else None,
timeout=float(parameters['timeout']) if '\
timeout' in parameters else None,
allow_redirects=parameters['allow_redirects'] if '\
allow_redirects' in parameters else True,
proxies=parameters['proxies'] if '\
proxies' in parameters else None,
verify=parameters['verify'] if '\
verify' in parameters else True,
stream=parameters['stream'] if '\
stream' in parameters else False,
cert=parameters['cert'] if '\
cert' in parameters else None,
)
res = json.loads(response.text)
w_msg = WM.WampSuccess(msg=res, req_id=req_id)
except Exception as err:
return WM.WampError(msg=str(err), req_id=req_id)
if (req['main_request_uuid'] != None):
wampNotify(self.device_session,
self.board, w_msg.serialize(), rpc_name)
else:
return w_msg
if (req['main_request_uuid'] != None):
LOG.info(" - main request: " + str(req['main_request_uuid']))
try:
threading.Thread(target=RestSubmit).start()
w_msg = WM.WampRunning(msg=rpc_name, req_id=req_id)
except Exception as err:
message = "Error in thr_" + rpc_name + ": " + str(err)
LOG.error(message)
w_msg = WM.WampError(msg=message, req_id=req_id)
else:
w_msg = RestSubmit()
return w_msg.serialize()
def lr_install():
bashCommand = "lr_install"
process = subprocess.Popen(bashCommand.split(),
stdout=subprocess.PIPE)
output, error = process.communicate()
return
def factory_reset():
LOG.info("Lightning-rod factory reset: ")
# delete nginx conf.d files
os.system("rm /etc/nginx/conf.d/lr_*")
LOG.info("--> NGINX settings deleted.")
# delete letsencrypt
os.system("rm -r /etc/letsencrypt/*")
LOG.info("--> LetsEncrypt settings deleted.")
# delete var-iotronic
os.system("rm -r /var/lib/iotronic/*")
LOG.info("--> Iotronic data deleted.")
# delete etc-iotronic
os.system("rm -r /etc/iotronic/*")
LOG.info("--> Iotronic settings deleted.")
# exec lr_install
lr_install()
# restart LR
LOG.info("--> LR restarting in 5 seconds...")
lr_utils.LR_restart_delayed(5)
return "Device reset completed"
def getIfconfig(): def getIfconfig():

View File

@ -25,6 +25,7 @@ import queue
import shutil import shutil
import threading import threading
import time import time
import platform
from iotronic_lightningrod.common import utils from iotronic_lightningrod.common import utils
@ -149,9 +150,17 @@ class PluginManager(Module.Module):
try: try:
if (plugin_uuid in PLUGINS_THRS) and ( worker_alive = False
PLUGINS_THRS[plugin_uuid].isAlive() if (plugin_uuid in PLUGINS_THRS):
): worker = PLUGINS_THRS[plugin_uuid]
pyvers = platform.python_version_tuple()
if int(pyvers[0]) == 3 and int(pyvers[1]) >= 9:
worker_alive = worker.is_alive()
else:
worker_alive = worker.isAlive()
if (plugin_uuid in PLUGINS_THRS) and worker_alive:
LOG.warning(" - Plugin " LOG.warning(" - Plugin "
+ plugin_uuid + " already started!") + plugin_uuid + " already started!")
@ -380,10 +389,19 @@ class PluginManager(Module.Module):
plugin_name = plugins_conf['plugins'][plugin_uuid]['name'] plugin_name = plugins_conf['plugins'][plugin_uuid]['name']
worker_alive = False
if (plugin_uuid in PLUGINS_THRS):
worker = PLUGINS_THRS[plugin_uuid]
pyvers = platform.python_version_tuple()
if int(pyvers[0]) == 3 and int(pyvers[1]) >= 9:
worker_alive = worker.is_alive()
else:
worker_alive = worker.isAlive()
# Check if the plugin is already running # Check if the plugin is already running
if (plugin_uuid in PLUGINS_THRS) and ( if (plugin_uuid in PLUGINS_THRS) and worker_alive:
PLUGINS_THRS[plugin_uuid].isAlive()
):
message = "ALREADY STARTED!" message = "ALREADY STARTED!"
LOG.warning(" - Plugin " LOG.warning(" - Plugin "
@ -495,10 +513,19 @@ class PluginManager(Module.Module):
if plugin_uuid in PLUGINS_THRS: if plugin_uuid in PLUGINS_THRS:
worker = PLUGINS_THRS[plugin_uuid] worker_alive = False
LOG.debug(" - Stopping plugin " + str(worker)) if (plugin_uuid in PLUGINS_THRS):
worker = PLUGINS_THRS[plugin_uuid]
LOG.debug(" - Stopping plugin " + str(worker))
if worker.isAlive(): pyvers = platform.python_version_tuple()
if int(pyvers[0]) == 3 and int(pyvers[1]) >= 9:
worker_alive = worker.is_alive()
else:
worker_alive = worker.isAlive()
if worker_alive:
if 'delay' in parameters: if 'delay' in parameters:
time.sleep(delay) time.sleep(delay)
@ -556,9 +583,17 @@ class PluginManager(Module.Module):
try: try:
if (plugin_uuid in PLUGINS_THRS) and ( worker_alive = False
PLUGINS_THRS[plugin_uuid].isAlive() if (plugin_uuid in PLUGINS_THRS):
): worker = PLUGINS_THRS[plugin_uuid]
pyvers = platform.python_version_tuple()
if int(pyvers[0]) == 3 and int(pyvers[1]) >= 9:
worker_alive = worker.is_alive()
else:
worker_alive = worker.isAlive()
if (plugin_uuid in PLUGINS_THRS) and worker_alive:
message = "Plugin " + plugin_uuid + " already started!" message = "Plugin " + plugin_uuid + " already started!"
LOG.warning(" - " + message) LOG.warning(" - " + message)
@ -727,7 +762,14 @@ class PluginManager(Module.Module):
if plugin_uuid in PLUGINS_THRS: if plugin_uuid in PLUGINS_THRS:
worker = PLUGINS_THRS[plugin_uuid] worker = PLUGINS_THRS[plugin_uuid]
if worker.isAlive():
pyvers = platform.python_version_tuple()
if int(pyvers[0]) == 3 and int(pyvers[1]) >= 9:
worker_alive = worker.is_alive()
else:
worker_alive = worker.isAlive()
if worker_alive:
LOG.info(" - Plugin '" LOG.info(" - Plugin '"
+ plugin_name + "' is running...") + plugin_name + "' is running...")
worker.stop() worker.stop()
@ -798,17 +840,28 @@ class PluginManager(Module.Module):
worker = PLUGINS_THRS[plugin_uuid] worker = PLUGINS_THRS[plugin_uuid]
pyvers = platform.python_version_tuple()
if int(pyvers[0]) == 3 and int(pyvers[1]) >= 9:
worker_alive = worker.is_alive()
else:
worker_alive = worker.isAlive()
# STOP PLUGIN---------------------------------------------- # STOP PLUGIN----------------------------------------------
if worker.isAlive(): if worker_alive:
LOG.info(" - Thread " LOG.info(" - Thread "
+ plugin_uuid + " is running, stopping...") + plugin_uuid + " is running, stopping...")
LOG.debug(" - Stopping plugin " + str(worker)) LOG.debug(" - Stopping plugin " + str(worker))
worker.stop() worker.stop()
while worker.isAlive(): if int(pyvers[0]) == 3 and int(pyvers[1]) >= 9:
pass worker_alive = worker.is_alive()
while worker.is_alive():
pass
else:
while worker.isAlive():
pass
# Remove from plugin thread list # Remove from plugin thread list
del PLUGINS_THRS[plugin_uuid] del PLUGINS_THRS[plugin_uuid]
@ -893,7 +946,13 @@ class PluginManager(Module.Module):
worker = PLUGINS_THRS[plugin_uuid] worker = PLUGINS_THRS[plugin_uuid]
if worker.isAlive(): pyvers = platform.python_version_tuple()
if int(pyvers[0]) == 3 and int(pyvers[1]) >= 9:
worker_alive = worker.is_alive()
else:
worker_alive = worker.isAlive()
if worker_alive:
result = "ALIVE" result = "ALIVE"
else: else:
result = "DEAD" result = "DEAD"

View File

@ -24,7 +24,6 @@ LOG = logging.getLogger(__name__)
import json import json
import os import os
import shutil
import subprocess import subprocess
import time import time
@ -212,6 +211,16 @@ class ProxyManager(Proxy.Proxy):
nginx_board_conf = '''server {{ nginx_board_conf = '''server {{
listen 50000; listen 50000;
server_name {0}; server_name {0};
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";
location / {{ location / {{
proxy_pass http://127.0.0.1:1474; proxy_pass http://127.0.0.1:1474;
}} }}
@ -294,6 +303,39 @@ class ProxyManager(Proxy.Proxy):
return json.dumps(nginxMsg) return json.dumps(nginxMsg)
def _proxyRenewWebservice(self):
nginxMsg = {}
try:
command = "/usr/bin/certbot " \
"renew " \
"--force-renewal " \
"-w /var/www/html"
LOG.info("Certbot is renewing certificate:")
LOG.info(command)
certbot_result = call(command, shell=True)
LOG.info("CERTBOT RESULT: " + str(certbot_result))
if (certbot_result == 0):
nginxMsg['result'] = "SUCCESS"
nginxMsg['message'] = "Webservice certificate renewed."
else:
nginxMsg['result'] = "ERROR"
nginxMsg['message'] = "Renewing certificate failure."
LOG.info("--> " + nginxMsg['message'])
except Exception as err:
nginxMsg['log'] = "Renewing certificate error: " + str(err)
nginxMsg['code'] = ""
LOG.warning("--> " + nginxMsg['log'])
return json.dumps(nginxMsg)
def _exposeWebservice(self, board_dns, service_dns, local_port, dns_list): def _exposeWebservice(self, board_dns, service_dns, local_port, dns_list):
nginxMsg = {} nginxMsg = {}
@ -316,7 +358,7 @@ class ProxyManager(Proxy.Proxy):
proxy_set_header Connection "upgrade"; proxy_set_header Connection "upgrade";
location / {{ location / {{
proxy_pass http://localhost:{1}; proxy_pass http://127.0.0.1:{1};
}} }}
location ~ /.well-known {{ location ~ /.well-known {{
root /var/www/html; root /var/www/html;

View File

@ -34,8 +34,9 @@ from flask import request
from flask import send_file from flask import send_file
from flask import session as f_session from flask import session as f_session
from flask import url_for from flask import url_for
from flask import abort
# from flask import Response
import getpass
import os import os
import subprocess import subprocess
import threading import threading
@ -144,6 +145,18 @@ class RestManager(Module.Module):
lr_cty = sock_bundle[2] + " - " + sock_bundle[0] \ lr_cty = sock_bundle[2] + " - " + sock_bundle[0] \
+ " - " + sock_bundle[1] + " - " + sock_bundle[1]
webservice_list = []
nginx_path = "/etc/nginx/conf.d/"
if os.path.exists(nginx_path):
active_webservice_list = [f for f in os.listdir(nginx_path)
if os.path.isfile(os.path.join(nginx_path, f))]
if len(active_webservice_list) != 0:
for ws in active_webservice_list:
ws = ws.replace('.conf', '')
webservice_list.append(ws)
info = { info = {
'board_id': board.uuid, 'board_id': board.uuid,
'board_name': board.name, 'board_name': board.name,
@ -155,6 +168,7 @@ class RestManager(Module.Module):
'board_reg_status': str(board.status), 'board_reg_status': str(board.status),
'iotronic_status': str(iotronic_status(board.status)), 'iotronic_status': str(iotronic_status(board.status)),
'service_list': service_list, 'service_list': service_list,
'webservice_list': webservice_list,
'serial_dev': device_manager.getSerialDevice(), 'serial_dev': device_manager.getSerialDevice(),
'nic': lr_cty, 'nic': lr_cty,
'lr_version': str( 'lr_version': str(
@ -162,56 +176,85 @@ class RestManager(Module.Module):
) )
} }
return info return info, 200
@app.route('/status') @app.route('/status')
def status(): def status():
if ('username' in f_session): try:
f_session['status'] = str(board.status) if ('username' in f_session):
f_session['status'] = str(board.status)
wstun_status = service_manager.wstun_status()
if wstun_status == 0:
wstun_status = "Online"
else:
wstun_status = "Offline"
service_list = service_manager.services_list("html")
if service_list == "":
service_list = "no services exposed!"
webservice_list = ""
nginx_path = "/etc/nginx/conf.d/"
if os.path.exists(nginx_path):
active_webservice_list = [
f for f in os.listdir(nginx_path)
if os.path.isfile(os.path.join(nginx_path, f))
]
for ws in active_webservice_list:
ws = ws.replace('.conf', '')[3:]
webservice_list = webservice_list + "\
<li>" + ws + "</li>"
else:
webservice_list = "no webservices exposed!"
if webservice_list == "":
webservice_list = "no webservices exposed!"
lr_cty = "N/A"
from iotronic_lightningrod.lightningrod import wport
sock_bundle = lr_utils.get_socket_info(wport)
if sock_bundle != "N/A":
lr_cty = sock_bundle[2] + " - " + sock_bundle[0] \
+ " - " + sock_bundle[1]
info = {
'board_id': board.uuid,
'board_name': board.name,
'wagent': board.agent,
'session_id': board.session_id,
'timestamp': str(
datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')),
'wstun_status': wstun_status,
'board_reg_status': str(board.status),
'iotronic_status': str(iotronic_status(board.status)),
'service_list': str(service_list),
'webservice_list': str(webservice_list),
'serial_dev': device_manager.getSerialDevice(),
'nic': lr_cty,
'lr_version': str(
utils.get_version("iotronic-lightningrod")
)
}
return render_template('status.html', **info)
wstun_status = service_manager.wstun_status()
if wstun_status == 0:
wstun_status = "Online"
else: else:
wstun_status = "Offline" return redirect(url_for('login', next=request.endpoint))
service_list = service_manager.services_list("html")
if service_list == "":
service_list = "no services exposed!"
lr_cty = "N/A"
from iotronic_lightningrod.lightningrod import wport
sock_bundle = lr_utils.get_socket_info(wport)
if sock_bundle != "N/A":
lr_cty = sock_bundle[2] + " - " + sock_bundle[0] \
+ " - " + sock_bundle[1]
except Exception as err:
LOG.error(err)
info = { info = {
'board_id': board.uuid, 'messages': [str(err)]
'board_name': board.name, }
'wagent': board.agent,
'session_id': board.session_id,
'timestamp': str(
datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')),
'wstun_status': wstun_status,
'board_reg_status': str(board.status),
'iotronic_status': str(iotronic_status(board.status)),
'service_list': str(service_list),
'serial_dev': device_manager.getSerialDevice(),
'nic': lr_cty,
'lr_version': str(
utils.get_version("iotronic-lightningrod")
)
}
return render_template('status.html', **info) return render_template('status.html', **info)
else:
return redirect(url_for('login', next=request.endpoint))
@app.route('/system') @app.route('/system')
def system(): def system():
if 'username' in f_session: if 'username' in f_session:
@ -360,7 +403,7 @@ class RestManager(Module.Module):
**info, **info,
error=error error=error
) )
return redirect("/config", code=302) # return redirect("/config", code=302)
else: else:
return redirect("/", code=302) return redirect("/", code=302)
@ -370,6 +413,9 @@ class RestManager(Module.Module):
@app.route('/backup', methods=['GET']) @app.route('/backup', methods=['GET'])
def backup_download(): def backup_download():
# LOG.info(request.query_string)
# LOG.info(request.__dict__)
if 'username' in f_session: if 'username' in f_session:
print("Identity file downloading: ") print("Identity file downloading: ")
@ -433,7 +479,33 @@ class RestManager(Module.Module):
if request.method == 'POST': if request.method == 'POST':
if request.form.get('reg_btn') == 'CONFIGURE': req_body = request.get_json()
LOG.debug(req_body)
if req_body != None:
if 'action' in req_body:
if req_body['action'] == "configure":
LOG.info("API LR configuration")
ragent = req_body['urlwagent']
code = req_body['code']
lr_config(ragent, code)
if 'hostname' in req_body:
if req_body['hostname'] != "":
change_hostname(req_body['hostname'])
return {"result": "LR configured, \
authenticating..."}, 200
else:
abort(400)
elif request.form.get('reg_btn') == 'CONFIGURE':
ragent = request.form['urlwagent'] ragent = request.form['urlwagent']
code = request.form['code'] code = request.form['code']
lr_config(ragent, code) lr_config(ragent, code)
@ -633,6 +705,12 @@ class RestManager(Module.Module):
return render_template('config.html', **info) return render_template('config.html', **info)
else: else:
if request.method == 'POST':
req_body = request.get_json()
if req_body != None and str(board.status) != "first_boot":
return {"result": "LR already configured!"}, 403
return redirect(url_for('login', next=request.endpoint)) return redirect(url_for('login', next=request.endpoint))
app.run(host='0.0.0.0', port=1474, debug=False, use_reloader=False) app.run(host='0.0.0.0', port=1474, debug=False, use_reloader=False)

View File

@ -1,5 +1,4 @@
# Copyright 2017 MDSLAB - University of Messina # Copyright 2017 MDSLAB - University of Messina. All Rights Reserved.
# All Rights Reserved.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # 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 # not use this file except in compliance with the License. You may obtain
@ -24,9 +23,6 @@ import signal
import socket import socket
import subprocess import subprocess
import time import time
import threading
import copy import copy
from datetime import datetime from datetime import datetime
from random import randint from random import randint
@ -36,9 +32,7 @@ from urllib.parse import urlparse
from iotronic_lightningrod.common import utils from iotronic_lightningrod.common import utils
from iotronic_lightningrod.config import package_path from iotronic_lightningrod.config import package_path
from iotronic_lightningrod.modules import Module from iotronic_lightningrod.modules import Module
from iotronic_lightningrod import lightningrod from iotronic_lightningrod import lightningrod
import iotronic_lightningrod.wampmessage as WM import iotronic_lightningrod.wampmessage as WM
@ -101,6 +95,8 @@ class ServiceManager(Module.Module):
if wurl_list[0] == "wss": if wurl_list[0] == "wss":
is_wss = True is_wss = True
self.board_id = board.uuid
if is_wss: if is_wss:
self.wstun_url = "wss://" + self.wstun_ip + ":" + self.wstun_port self.wstun_url = "wss://" + self.wstun_ip + ":" + self.wstun_port
else: else:
@ -600,7 +596,7 @@ class ServiceManager(Module.Module):
except Exception as err: except Exception as err:
LOG.error(" --> Parsing error in " + s_conf_FILE + ": " + str(err)) LOG.error(" --> Parsing error in " + s_conf_FILE + ": " + str(err))
if os.path.isfile(s_conf_FILE): if os.path.isfile(s_conf_FILE + '.bkp '):
LOG.info(" --> restoring services.json file...") LOG.info(" --> restoring services.json file...")
@ -621,6 +617,28 @@ class ServiceManager(Module.Module):
LOG.error(" --> services.json backup file does not exist!") LOG.error(" --> services.json backup file does not exist!")
s_conf = None s_conf = None
if s_conf == None:
try:
LOG.info(" --> loading services.json template file")
template_conf = '''{
"services": {
}
}
'''
with open(s_conf_FILE, "w") as text_file:
text_file.write("%s" % template_conf)
with open(s_conf_FILE) as settings:
s_conf = json.load(settings)
except Exception as err:
LOG.error(
" --> Loading template error: \
manual check on device required!"
)
s_conf = None
return s_conf return s_conf
def _wstunMon(self, wstun, local_port): def _wstunMon(self, wstun, local_port):
@ -762,16 +780,24 @@ class ServiceManager(Module.Module):
try: try:
# subp_cmd = [CONF.services.wstun_bin, opt_reverse,
# self.wstun_url, '-u "' + str(self.board_id) + '"']
subp_cmd = [CONF.services.wstun_bin, opt_reverse,
self.wstun_url, '-u', '' + str(self.board_id) + '']
wstun = subprocess.Popen( wstun = subprocess.Popen(
[CONF.services.wstun_bin, opt_reverse, self.wstun_url], subp_cmd,
stdout=subprocess.PIPE stdout=subprocess.PIPE
) )
if (event != "boot"): if (event != "boot"):
print("WSTUN start event:") print("WSTUN start event:")
cmd_print = 'WSTUN exec: ' + str(CONF.services.wstun_bin) \ # cmd_print = 'WSTUN exec: ' + str(CONF.services.wstun_bin) \
+ " " + opt_reverse + ' ' + self.wstun_url # + " " + opt_reverse + ' ' + self.wstun_url
cmd_print = 'WSTUN exec: ' + str(subp_cmd)
print(" - " + str(cmd_print)) print(" - " + str(cmd_print))
LOG.debug(cmd_print) LOG.debug(cmd_print)
@ -845,16 +871,24 @@ class ServiceManager(Module.Module):
) )
try: try:
# subp_cmd = [CONF.services.wstun_bin, opt_reverse, self.wstun_url,
# '-u "' + str(self.board_id) + '"']
subp_cmd = [CONF.services.wstun_bin, opt_reverse, self.wstun_url,
'-u', '' + str(self.board_id) + '']
wstun = subprocess.Popen( wstun = subprocess.Popen(
[CONF.services.wstun_bin, opt_reverse, self.wstun_url], subp_cmd,
stdout=subprocess.PIPE stdout=subprocess.PIPE
) )
if (event != "boot"): if (event != "boot"):
print("WSTUN start event:") print("WSTUN start event:")
cmd_print = 'WSTUN exec: ' + str(CONF.services.wstun_bin) + " " \ # cmd_print = 'WSTUN exec: ' + str(CONF.services.wstun_bin) + " " \
+ opt_reverse + ' ' + self.wstun_url # + opt_reverse + ' ' + self.wstun_url
cmd_print = 'WSTUN exec: ' + str(subp_cmd)
print(" - " + str(cmd_print)) print(" - " + str(cmd_print))
LOG.debug(cmd_print) LOG.debug(cmd_print)
@ -926,9 +960,32 @@ class ServiceManager(Module.Module):
if parameters is not None: if parameters is not None:
LOG.info(" - " + rpc_name + " parameters: " + str(parameters)) LOG.info(" - " + rpc_name + " parameters: " + str(parameters))
thr_list = str(threading.enumerate()) tuns = {
"sockets": [],
"procs": []
}
w_msg = WM.WampSuccess(msg=thr_list, req_id=req_id) """ LSOF """
res_lsof = subprocess.Popen(
"lsof -i -n -P | grep '8080'| grep -v grep",
shell=True,
stdout=subprocess.PIPE
)
sockets = res_lsof.communicate()[0].decode("utf-8").split("\n")
tuns['sockets'] = sockets[:-1]
""" PS """
res_ps = subprocess.Popen(
"ps aux | grep 'wstun' | grep -v grep",
shell=True,
stdout=subprocess.PIPE
)
ps_s4t = res_ps.communicate()[0].decode("utf-8").split("\n")
tuns['procs'] = ps_s4t[:-1]
w_msg = WM.WampSuccess(msg=tuns, req_id=req_id)
return w_msg.serialize() return w_msg.serialize()

View File

@ -27,6 +27,8 @@ import subprocess
import sys import sys
import threading import threading
import time import time
import signal
from iotronic_lightningrod.common import utils from iotronic_lightningrod.common import utils
from iotronic_lightningrod.config import entry_points_name from iotronic_lightningrod.config import entry_points_name
@ -40,6 +42,9 @@ LOG = logging.getLogger(__name__)
global connFailureRecovery global connFailureRecovery
connFailureRecovery = None connFailureRecovery = None
global gdbPid
gdbPid = None
class Utility(Module.Module): class Utility(Module.Module):
@ -200,18 +205,35 @@ def destroyWampSocket():
LOG.warning("WAMP Connection Recovery timer: EXPIRED") LOG.warning("WAMP Connection Recovery timer: EXPIRED")
lr_utils.LR_restart() lr_utils.LR_restart()
def timeoutGDB():
LOG.warning("WAMP Connection Recovery GDB timer: EXPIRED")
global gdbPid
os.kill(gdbPid, signal.SIGKILL)
LOG.warning("WAMP Connection Recovery GDB process: KILLED")
LOG.warning("WAMP Connection Recovery GDB process: LR restarting...")
lr_utils.LR_restart()
connFailureRecovery = Timer(30, timeout) connFailureRecovery = Timer(30, timeout)
connFailureRecovery.start() connFailureRecovery.start()
LOG.warning("WAMP Connection Recovery timer: STARTED") LOG.warning("WAMP Connection Recovery timer: STARTED")
try: try:
gdbTimeoutCheck = Timer(30, timeoutGDB)
gdbTimeoutCheck.start()
LOG.debug("WAMP Connection Recovery GDB timer: STARTED")
process = subprocess.Popen( process = subprocess.Popen(
["gdb", "-p", str(LR_PID)], ["gdb", "-p", str(LR_PID)],
stdin=subprocess.PIPE, stdin=subprocess.PIPE,
stdout=subprocess.PIPE stdout=subprocess.PIPE
) )
global gdbPid
gdbPid = process.pid
proc = psutil.Process() proc = psutil.Process()
conn_list = proc.connections() conn_list = proc.connections()
@ -250,6 +272,9 @@ def destroyWampSocket():
) )
connFailureRecovery.cancel() connFailureRecovery.cancel()
gdbTimeoutCheck.cancel()
LOG.debug("WAMP Connection Recovery GDB timer: CLEANED")
if wamp_conn_set == False: if wamp_conn_set == False:
LOG.warning("WAMP CONNECTION NOT FOUND: LR restarting...") LOG.warning("WAMP CONNECTION NOT FOUND: LR restarting...")
# In conn_list there is not the WAMP connection! # In conn_list there is not the WAMP connection!

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -33,7 +33,13 @@
{% else %} {% else %}
<div align="center"> </div> <div align="center">
<br>
<img src="{{ url_for('static', filename='images/stack4thingslogo.png') }}" alt="stack4thingslogo" width="260" height="260">
</div>
{% endif %} {% endif %}

View File

@ -28,7 +28,10 @@
<div class="login-form"> <div class="login-form">
<form action="{{ url_for('login', next=request.args.get('next')) }}" method="post"> <form action="{{ url_for('login', next=request.args.get('next')) }}" method="post">
<div class="avatar"><i class="material-icons">&#xE7FF;</i></div> <!--<div class="avatar"><i class="material-icons">&#xE7FF;</i></div>-->
<center>
<img src="{{ url_for('static', filename='images/stack4thingslogo.png') }}" alt="stack4thingslogo" width="200" height="200">
</center>
<h4 class="modal-title">Login to Lightning-rod</h4> <h4 class="modal-title">Login to Lightning-rod</h4>
<div class="form-group"> <div class="form-group">
<input type="text" class="form-control" name="username" placeholder="Username" required="required" value="{{request.form.username }}"> <input type="text" class="form-control" name="username" placeholder="Username" required="required" value="{{request.form.username }}">

View File

@ -6,32 +6,65 @@
{% block content %} {% block content %}
<div class="jumbotron"> <div class="jumbotron">
<h2>Board info @ {{ timestamp }}</h2>
<br>
<h4> Iotronic </h4>
<li> Lightning-rod version: {{lr_version}}</li>
<li> Iotronic connection status: {{iotronic_status}}</li> {% if messages %}
<li>Name: {{ board_name }} </li>
<li>UUID: {{ board_id }} </li>
<li>Registartion status: {{ board_reg_status }}</li>
<li>WAMP Agent: {{ wagent }} </li>
<li>Session ID: {{ session_id }} </li>
<br>
<h4> WSTUN </h4>
<li>Status: {{ wstun_status }} </li>
<li>Services: <br>
<ul>
{% autoescape false %}
{{service_list}}
{% endautoescape %}
</ul>
</li> <h5><b>Error messages:</b></h5>
<br>
<h4> Hardware information </h4> <center>
<li>Serial device: {{ serial_dev }} </li>
<li>NIC: {{ nic }} </li> <div align="left" style="width:90%">
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
</div>
</center>
{% else %}
<br><br>
<h2>Board info @ {{ timestamp }}</h2>
<br>
<h4> Iotronic </h4>
<li> Lightning-rod version: {{lr_version}}</li>
<li> Iotronic connection status: {{iotronic_status}}</li>
<li>Name: {{ board_name }} </li>
<li>UUID: {{ board_id }} </li>
<li>Registartion status: {{ board_reg_status }}</li>
<li>WAMP Agent: {{ wagent }} </li>
<li>Session ID: {{ session_id }} </li>
<br>
<h4> WSTUN </h4>
<li>Status: {{ wstun_status }} </li>
<li>Services: <br>
<ul>
{% autoescape false %}
{{service_list}}
{% endautoescape %}
</ul>
</li>
<li>WebServices: <br>
<ul>
{% autoescape false %}
{{webservice_list}}
{% endautoescape %}
</ul>
</li>
<br>
<h4> Hardware information </h4>
<li>Serial device: {{ serial_dev }} </li>
<li>NIC: {{ nic }} </li>
<br><br>
{% endif %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,5 +1,4 @@
# Copyright 2017 MDSLAB - University of Messina # Copyright 2017 MDSLAB - University of Messina. All Rights Reserved.
# All Rights Reserved.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # 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 # not use this file except in compliance with the License. You may obtain
@ -18,10 +17,12 @@ __author__ = "Nicola Peditto <n.peditto@gmail.com>"
from iotronic_lightningrod.common import utils from iotronic_lightningrod.common import utils
from iotronic_lightningrod.config import package_path from iotronic_lightningrod.config import package_path
from iotronic_lightningrod.lightningrod import RPC_proxies from iotronic_lightningrod.lightningrod import RPC_proxies
from iotronic_lightningrod.lightningrod import wampNotify
from iotronic_lightningrod.modules import Module from iotronic_lightningrod.modules import Module
import iotronic_lightningrod.wampmessage as WM import iotronic_lightningrod.wampmessage as WM
from autobahn.wamp import exception
import threading
import importlib as imp import importlib as imp
import inspect import inspect
import json import json
@ -29,6 +30,7 @@ import OpenSSL.crypto
import os import os
import time import time
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -248,3 +250,74 @@ class WebServiceManager(Module.Module):
w_msg = WM.WampSuccess(msg=message, req_id=req_id) w_msg = WM.WampSuccess(msg=message, req_id=req_id)
return w_msg.serialize() return w_msg.serialize()
"""
# LONG
async def RenewWebservice(self, req, parameters=None):
req_id = req['uuid']
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED [req_id: " + str(req_id) + "]")
if parameters is not None:
LOG.info(" - " + rpc_name + " parameters: " + str(parameters))
message = self.board.proxy._proxyRenewWebservice()
w_msg = WM.WampSuccess(msg=message, req_id=req_id)
return w_msg.serialize()
"""
# LONG
async def RenewWebservice(self, req, parameters=None):
req_id = req['uuid']
rpc_name = utils.getFuncName()
LOG.info("RPC " + rpc_name + " CALLED [req_id: " + str(req_id) + "]")
if parameters is not None:
LOG.info(" - " + rpc_name + " parameters: " + str(parameters))
def renewing():
message = self.board.proxy._proxyRenewWebservice()
try:
message = json.loads(message)
w_msg = WM.WampMessage(
message=message['message'],
result=message['result'],
req_id=req_id
)
except Exception as e:
LOG.error(e)
w_msg = WM.WampError(
msg="Error returning message",
req_id=req_id
)
try:
wampNotify(
self.session,
self.board,
w_msg.serialize(),
rpc_name
)
except exception.ApplicationError as e:
LOG.error(
" - Notify result '" + rpc_name + "' error: " + str(e)
)
try:
threading.Thread(target=renewing).start()
except Exception as err:
LOG.error("Error in renewing thread: " + str(err))
out_msg = "LR is renewing webservice certificates..."
w_msg = WM.WampRunning(msg=out_msg, req_id=req_id)
return w_msg.serialize()

View File

@ -11,7 +11,7 @@ if [ "$1" = "backup" ]; then
else else
bkp_path="" bkp_path="."
fi fi
@ -24,13 +24,15 @@ if [ "$1" = "backup" ]; then
tar zcvf $bkp_filename /var/lib/iotronic /etc/iotronic /etc/letsencrypt /etc/nginx/conf.d &>/dev/null tar zcvf $bkp_filename /var/lib/iotronic /etc/iotronic /etc/letsencrypt /etc/nginx/conf.d &>/dev/null
elif [ "$1" = "restore" ]; then elif [ "$1" = "restore" ]; then
if [ "$#" -ne 2 ]; then if [ "$#" -ne 2 ]; then
echo "You have to specify: 'restore' <BACKUP_FILE> " echo "You have to specify: 'restore' <BACKUP_FILE_PATH> "
exit exit
fi fi
# RESTORE # RESTORE
echo "Restoring Iotronic configuration" echo "Restoring Iotronic configuration"
tar -xvzf $2 -C / #tar -xvzf $2 -C /
tar -xvf $2 -C /
service nginx restart service nginx restart
@ -39,8 +41,13 @@ elif [ "$1" = "restore" ]; then
echo -e "\nCompleted!" echo -e "\nCompleted!"
else else
echo "You have to specify:"
echo " - for backup: 'backup'" echo "You have to specify:"
echo " - for restore: 'restore' <backup-filename-to-restore>" echo " - to backup: 'backup'"
exit echo " - options:"
echo " --path: specify path where to save the backup file; e.g.: /tmp or /home/<USER>"
echo ""
echo " - to restore: 'restore' <BACKUP_FILE_PATH>"
exit
fi fi

View File

@ -18,6 +18,7 @@
import os import os
import sys import sys
if len(sys.argv) == 1: if len(sys.argv) == 1:
print('Arguments required:') print('Arguments required:')
@ -28,6 +29,13 @@ else:
if sys.argv[1] == "-c": if sys.argv[1] == "-c":
test=os.system('grep -Rq "<REGISTRATION-TOKEN>" ' + sys.argv[4] + '/settings.json')
#print(test)
if test == 0:
print("Configuration status: new")
else:
print("Configuration status: configured")
if len(sys.argv) < 5: if len(sys.argv) < 5:
print('Arguments required: ' print('Arguments required: '
+ '<REGISTRATION-TOKEN> ' + '<REGISTRATION-TOKEN> '
@ -36,20 +44,63 @@ else:
str(sys.argv) str(sys.argv)
) )
else: else:
os.system('sed -i "s|\\"code\\":.*|\\"code\\": \\"'
+ sys.argv[2] + '\\"|g" ' + sys.argv[4] + '/settings.json')
os.system('sed -i "s|\\"url\\":.*|\\"url\\": \\"' os.system('sed -i "s|\\"url\\":.*|\\"url\\": \\"'
+ sys.argv[3] + '\\",|g" ' + sys.argv[4] + '/settings.json') + sys.argv[3] + '\\",|g" ' + sys.argv[4] + '/settings.json')
os.system('sed -i "s|<IOTRONIC-REALM>|s4t|g" ' os.system('sed -i "s|<IOTRONIC-REALM>|s4t|g" '
+ sys.argv[4] + '/settings.json') + sys.argv[4] + '/settings.json')
if test == 0:
#print("Configuration status: new")
os.system('sed -i "s|\\"code\\":.*|\\"code\\": \\"'
+ sys.argv[2] + '\\"|g" ' + sys.argv[4] + '/settings.json')
print("Configuration completed")
else:
check_reg=os.system('grep -Rq "main-agent" ' + sys.argv[4] + '/settings.json')
if check_reg == 0:
#print("Configuration status: configured")
os.system('sed -i "s|\\"code\\":.*|\\"code\\": \\"'
+ sys.argv[2] + '\\",|g" ' + sys.argv[4] + '/settings.json')
else:
os.system('sed -i "s|\\"code\\":.*|\\"code\\": \\"'
+ sys.argv[2] + '\\"|g" ' + sys.argv[4] + '/settings.json')
print("Configuration overwritten")
else: else:
test=os.system('grep -Rq "<REGISTRATION-TOKEN>" /etc/iotronic/settings.json')
#print(test)
if test == 0:
print("Configuration status: new")
else:
print("Configuration status: configured")
if len(sys.argv) < 3: if len(sys.argv) < 3:
print('Arguments required: <REGISTRATION-TOKEN> <WAMP-REG-AGENT-URL>', print('Arguments required: <REGISTRATION-TOKEN> <WAMP-REG-AGENT-URL>',
str(sys.argv)) str(sys.argv))
else: else:
os.system('sed -i "s|\\"code\\":.*|\\"code\\": \\"'
+ sys.argv[1] + '\\"|g" /etc/iotronic/settings.json')
os.system('sed -i "s|\\"url\\":.*|\\"url\\": \\"' os.system('sed -i "s|\\"url\\":.*|\\"url\\": \\"'
+ sys.argv[2] + '\\",|g" /etc/iotronic/settings.json') + sys.argv[2] + '\\",|g" /etc/iotronic/settings.json')
os.system('sed -i "s|<IOTRONIC-REALM>|s4t|g" /etc/iotronic/settings.json') os.system('sed -i "s|<IOTRONIC-REALM>|s4t|g" /etc/iotronic/settings.json')
if test == 0:
#print("Configuration status: new")
os.system('sed -i "s|\\"code\\":.*|\\"code\\": \\"'
+ sys.argv[1] + '\\"|g" /etc/iotronic/settings.json')
print("Configuration completed")
else:
check_reg=os.system('grep -Rq "main-agent" /etc/iotronic/settings.json')
if check_reg == 0:
#print("Configuration status: configured")
os.system('sed -i "s|\\"code\\":.*|\\"code\\": \\"'
+ sys.argv[1] + '\\",|g" /etc/iotronic/settings.json')
else:
os.system('sed -i "s|\\"code\\":.*|\\"code\\": \\"'
+ sys.argv[1] + '\\"|g" /etc/iotronic/settings.json')
print("Configuration overwritten")

View File

@ -5,6 +5,8 @@ import requests
r = requests.get(url = "http://localhost:1474/info") r = requests.get(url = "http://localhost:1474/info")
data = r.json() try:
data = r.json()
print(json.dumps(data, indent=4, sort_keys=True)) print(json.dumps(data, indent=4, sort_keys=True))
except:
print(r.text)

View File

@ -101,7 +101,7 @@ print(' - logrotate configured.')
os.system('cp ' + py_dist_pack + '/iotronic_lightningrod/etc/systemd/system/' os.system('cp ' + py_dist_pack + '/iotronic_lightningrod/etc/systemd/system/'
+ 's4t-lightning-rod.service ' + 's4t-lightning-rod.service '
+ '/etc/systemd/system/lightning-rod.service') + '/etc/systemd/system/lightning-rod.service')
os.chmod('/etc/systemd/system/lightning-rod.service', 0o744)
print('Lightning-rod systemd script installed.') print('Lightning-rod systemd script installed.')

View File

@ -21,6 +21,7 @@ commands =
[testenv:pep8] [testenv:pep8]
basepython = python3.8 basepython = python3.8
#commands = /usr/local/bin/flake8 {posargs} #commands = /usr/local/bin/flake8 {posargs}
#commands = /usr/bin/flake8 {posargs}
commands = flake8 {posargs} commands = flake8 {posargs}
[testenv:venv] [testenv:venv]

View File

@ -15,13 +15,33 @@ RUN echo $TZ > /etc/timezone && apt-get update && apt-get install -y tzdata && r
RUN apt-get update && apt-get install -y nginx python-certbot-nginx RUN apt-get update && apt-get install -y nginx python-certbot-nginx
RUN sed -i 's/# server_names_hash_bucket_size 64;/server_names_hash_bucket_size 64;/g' /etc/nginx/nginx.conf RUN sed -i 's/# server_names_hash_bucket_size 64;/server_names_hash_bucket_size 64;/g' /etc/nginx/nginx.conf
#RUN apt-get install -y certbot
RUN rm -rf /var/lib/apt/lists/* RUN rm -rf /var/lib/apt/lists/*
ENV NODE_PATH=/usr/local/lib/node_modules
RUN apt update && apt install -y wget && wget https://deb.nodesource.com/setup_10.x
RUN chmod +x setup_10.x && ./setup_10.x
RUN apt-get install -y nodejs
RUN npm install -g --unsafe @mdslab/wstun@1.0.11 && npm cache --force clean RUN npm install -g --unsafe @mdslab/wstun@1.0.11 && npm cache --force clean
RUN pip3 install iotronic-lightningrod RUN git clone -b allowlist --depth 1 https://github.com/MDSLab/wstun.git /tmp/wstun/
RUN cp /tmp/wstun/bin/wstun.js /usr/lib/node_modules/@mdslab/wstun/bin/
RUN cp -r /tmp/wstun/lib/* /usr/lib/node_modules/@mdslab/wstun/lib/
#RUN apt update
#RUN apt install -y wget && wget https://deb.nodesource.com/setup_10.x
#RUN chmod +x setup_10.x && ./setup_10.x
#RUN apt-get install -y nodejs
#RUN npm i -g npm@latest
#RUN npm install -g --unsafe websocket@1.0.26 optimist@0.6.1 node-uuid@1.4.7 under_score log4js@1.1.1 && npm cache --force clean
#RUN cp /usr/local/lib/node_modules/@mdslab/wstun/bin/wstun.js /usr/local/bin/wstun
#RUN ln -s /usr/local/bin/wstun /usr/bin/wstun
#RUN pip3 install iotronic-lightningrod
RUN pip3 install --upgrade pip
COPY data/dist/iotronic_lightningrod-*.tar.gz /tmp/
RUN pip3 install /tmp/iotronic_lightningrod-*.tar.gz
RUN sed -i "s|listen 80 default_server;|listen 50000 default_server;|g" /etc/nginx/sites-available/default RUN sed -i "s|listen 80 default_server;|listen 50000 default_server;|g" /etc/nginx/sites-available/default
RUN sed -i "s|80 default_server;|50000 default_server;|g" /etc/nginx/sites-available/default RUN sed -i "s|80 default_server;|50000 default_server;|g" /etc/nginx/sites-available/default
@ -35,7 +55,7 @@ RUN /usr/local/bin/lr_install
VOLUME /var/lib/iotronic VOLUME /var/lib/iotronic
RUN ln -s /usr/local/bin/wstun /usr/bin/wstun #RUN ln -s /usr/local/bin/wstun /usr/bin/wstun
#CMD [ "/usr/sbin/nginx"] #CMD [ "/usr/sbin/nginx"]
#CMD [ "/usr/local/bin/lightning-rod"] #CMD [ "/usr/local/bin/lightning-rod"]