diff --git a/README.rst b/README.rst index b2213e5..df656db 100644 --- a/README.rst +++ b/README.rst @@ -15,9 +15,8 @@ board-side probe. Installation guides ------------------- -* `Arduino YUN `_. +* `Raspberry Pi 3 `_. * `Ubuntu 16.04 `_. -* `Raspberry Pi 3 `_. - +* `Arduino YUN `_. diff --git a/doc/installation/arduino_yun.rst b/doc/installation/arduino_yun.rst index 8448621..ace8ce4 100644 --- a/doc/installation/arduino_yun.rst +++ b/doc/installation/arduino_yun.rst @@ -1,8 +1,7 @@ IoTronic Lightning-rod installation guide for Arduino YUN ========================================================= -We tested this procedure on a Arduino YUN board with OpenWRT LininoIO -image. +We tested this procedure on a Arduino YUN board with OpenWRT LininoIO image. Install from source code ------------------------ @@ -25,28 +24,13 @@ Install dependencies :: opkg install git bzip2 python-netifaces - pip install --no-cache-dir zope.interface pyserial Babel oslo.config oslo.log + pip install --no-cache-dir zope.interface pyserial Babel oslo.config + oslo.log easy_install httplib2 Install Autobahn: ''''''''''''''''' -:: - - # Install Twisted: - wget --no-check-certificate https://pypi.python.org/packages/source/T/Twisted/Twisted-14.0.2.tar.bz2 - bzip2 -d Twisted-14.0.2.tar.bz2 - tar -xvf Twisted-14.0.2.tar - cd Twisted-14.0.2/ - vi setup.py - - comment line 63: - #conditionalExtensions=getExtensions(), - - python setup.py install - cd /opt/ - rm -rf /opt/Twisted-14.0.2* - :: easy_install autobahn @@ -82,6 +66,7 @@ Deployment cp etc/iotronic/iotronic.conf /etc/iotronic/ cp settings.example.json /var/lib/iotronic/settings.json cp plugins.example.json /var/lib/iotronic/plugins.json + cp services.example.json /var/lib/iotronic/services.json cp etc/init.d/lightning-rod /etc/init.d/lightning-rod chmod +x /etc/init.d/lightning-rod touch /var/log/iotronic/lightning-rod.log diff --git a/doc/installation/raspberry_pi_3.rst b/doc/installation/raspberry_pi_3.rst index 593051c..fe7420c 100644 --- a/doc/installation/raspberry_pi_3.rst +++ b/doc/installation/raspberry_pi_3.rst @@ -11,7 +11,7 @@ Install requirements :: - pip install oslo-config oslo_log twisted autobahn httplib2 + pip install oslo.config oslo.log asyncio autobahn httplib2 psutil six Set up environment: ~~~~~~~~~~~~~~~~~~~ @@ -44,6 +44,7 @@ Deployment cp etc/iotronic/iotronic.conf /etc/iotronic/ cp settings.example.json /var/lib/iotronic/settings.json cp plugins.example.json /var/lib/iotronic/plugins.json + cp services.example.json /var/lib/iotronic/services.json cp etc/systemd/system/s4t-lightning-rod.service /etc/systemd/system/lightning-rod.service chmod +x /etc/systemd/system/lightning-rod.service systemctl daemon-reload diff --git a/doc/installation/ubuntu1604.rst b/doc/installation/ubuntu1604.rst index 5a5a82b..55874da 100644 --- a/doc/installation/ubuntu1604.rst +++ b/doc/installation/ubuntu1604.rst @@ -12,7 +12,7 @@ Install requirements :: - pip install oslo-config oslo_log twisted autobahn httplib2 + pip install oslo.config oslo.log asyncio autobahn httplib2 psutil six Set up environment: ~~~~~~~~~~~~~~~~~~~ @@ -45,6 +45,7 @@ Deployment cp etc/iotronic/iotronic.conf /etc/iotronic/ cp settings.example.json /var/lib/iotronic/settings.json cp plugins.example.json /var/lib/iotronic/plugins.json + cp services.example.json /var/lib/iotronic/services.json cp etc/systemd/system/s4t-lightning-rod.service /etc/systemd/system/lightning-rod.service chmod +x /etc/systemd/system/lightning-rod.service systemctl daemon-reload diff --git a/etc/iotronic/iotronic.conf b/etc/iotronic/iotronic.conf index 94e4ef1..4355926 100644 --- a/etc/iotronic/iotronic.conf +++ b/etc/iotronic/iotronic.conf @@ -1,4 +1,4 @@ [DEFAULT] debug = True log_file = /var/log/iotronic/lightning-rod.log -lightningrod_home = /var/lib/iotronic +lightningrod_home = /var/lib/iotronic \ No newline at end of file diff --git a/iotronic_lightningrod/lightningrod.py b/iotronic_lightningrod/lightningrod.py index f41b4bb..2d740bd 100644 --- a/iotronic_lightningrod/lightningrod.py +++ b/iotronic_lightningrod/lightningrod.py @@ -66,6 +66,9 @@ txaio.start_logging(level="info") RUNNER = None connected = False +global MODULES +MODULES = {} + def moduleReloadInfo(session): """This function is used in the reconnection stage to register @@ -76,18 +79,22 @@ def moduleReloadInfo(session): """ - LOG.info("Modules reloading after WAMP recovery...") + LOG.info("\n\nModules reloading after WAMP recovery...\n\n") try: - # Register RPCs for each Lightning-rod module - for mod in RPC: - LOG.info("- Reloading module RPcs for " + str(mod)) - moduleWampRegister(session, RPC[mod]) + # Call module restore procedures and + # register RPCs for each Lightning-rod module + for mod_name in MODULES: + LOG.info("- Registering RPCs for module " + str(mod_name)) + moduleWampRegister(session, RPC[mod_name]) + + LOG.info("- Restoring module " + str(mod_name)) + MODULES[mod_name].restore() # Register RPCs for the device for dev in RPC_devices: - LOG.info("- Reloading device RPCs for " + str(dev)) + LOG.info("- Registering RPCs for device " + str(dev)) moduleWampRegister(session, RPC_devices[dev]) except Exception as err: @@ -110,13 +117,15 @@ def moduleWampRegister(session, meth_list): else: for meth in meth_list: - # We don't considere the __init__ and finalize methods - if (meth[0] != "__init__") & (meth[0] != "finalize"): + # We don't considere the "__init__", "finalize" and + # "restore" methods + if (meth[0] != "__init__") & (meth[0] != "finalize") \ + & (meth[0] != "restore"): rpc_addr = u'iotronic.' + board.uuid + '.' + meth[0] - session.register(meth[1], rpc_addr) - - LOG.info(" --> " + str(meth[0])) + if not meth[0].startswith('_'): + session.register(meth[1], rpc_addr) + LOG.info(" --> " + str(meth[0])) def modulesLoader(session): @@ -158,13 +167,16 @@ def modulesLoader(session): else: mod = ext.plugin(board, session) + global MODULES + MODULES[mod.name] = mod + # Methods list for each module meth_list = inspect.getmembers(mod, predicate=inspect.ismethod) global RPC RPC[mod.name] = meth_list - if len(meth_list) == 2: + if len(meth_list) == 3: # there are at least two methods for each module: # "__init__" and "finalize" @@ -222,8 +234,7 @@ async def IotronicLogin(board, session, details): modulesLoader(session) except Exception as e: - LOG.warning("WARNING - Could not register procedures: " - + str(e)) + LOG.warning("WARNING - Could not load modules: " + str(e)) # Reset flag to False # reconnection = False @@ -257,10 +268,10 @@ def wampConnect(wamp_conf): try: - LOG.info("WAMP status:" + + LOG.info("WAMP status @ boot:" + "\n- board = " + str(board.status) + "\n- reconnection = " + str(reconnection) + - "\n- connection = " + str(connected) + "\n- connected = " + str(connected) ) # LR creates the Autobahn Asyncio Component that points to the @@ -406,10 +417,10 @@ def wampConnect(wamp_conf): LOG.info("\n\n\nBoard is becoming operative...\n\n\n") board.updateStatus("operative") board.loadSettings() - LOG.info("WAMP status:" + + LOG.info("WAMP status @ firt connection:" + "\n- board = " + str(board.status) + "\n- reconnection = " + str(reconnection) + - "\n- connection = " + str(connected) + "\n- connected = " + str(connected) ) await IotronicLogin(board, session, details) @@ -471,7 +482,7 @@ def wampConnect(wamp_conf): except Exception as e: LOG.warning( - "WARNING - Could not register procedures: " + "WARNING - Could not reload modules: " + str(e)) Bye() @@ -481,7 +492,7 @@ def wampConnect(wamp_conf): Bye() except exception.ApplicationError as e: - LOG.error("IoTronic connection error: " + str(e)) + LOG.error("IoTronic connection error:\n" + str(e)) # Iotronic is offline the board can not call # the "stack4things.connection" RPC. # The board will disconnect from WAMP agent and retry later @@ -517,10 +528,10 @@ def wampConnect(wamp_conf): global reconnection - LOG.info("WAMP status:" + + LOG.info("WAMP status on disconnect:" + "\n- board = " + str(board.status) + "\n- reconnection = " + str(reconnection) + - "\n- connection = " + str(connected) + "\n- connected = " + str(connected) ) if board.status == "operative" and reconnection is False: @@ -579,7 +590,7 @@ def wampConnect(wamp_conf): LOG.error("Reconnection wrong status!") except Exception as err: - LOG.error(" - URI validation error: " + str(err)) + LOG.error(" - WAMP connection error: " + str(err)) Bye() diff --git a/iotronic_lightningrod/modules/Module.py b/iotronic_lightningrod/modules/Module.py index ca57c9a..dc02211 100644 --- a/iotronic_lightningrod/modules/Module.py +++ b/iotronic_lightningrod/modules/Module.py @@ -28,8 +28,6 @@ class Module(object): """ - # __metaclass__ = abc.ABCMeta - def __init__(self, name, board): self.name = name @@ -40,3 +38,7 @@ class Module(object): @abc.abstractmethod def finalize(self): pass + + @abc.abstractmethod + def restore(self): + pass diff --git a/iotronic_lightningrod/modules/device_manager.py b/iotronic_lightningrod/modules/device_manager.py index 13476d0..76b9442 100644 --- a/iotronic_lightningrod/modules/device_manager.py +++ b/iotronic_lightningrod/modules/device_manager.py @@ -29,22 +29,6 @@ from oslo_log import log as logging LOG = logging.getLogger(__name__) -def deviceWampRegister(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] - # LOG.debug(" --> " + str(rpc_addr)) - SESSION.register(meth[1], rpc_addr) - - LOG.info(" --> " + str(meth[0]) + " registered!") - - class DeviceManager(Module.Module): def __init__(self, board, session): @@ -71,7 +55,7 @@ class DeviceManager(Module.Module): RPC_devices[device_type] = dev_meth_list - deviceWampRegister(dev_meth_list, board) + self._deviceWampRegister(dev_meth_list, board) board.device = device @@ -80,3 +64,21 @@ class DeviceManager(Module.Module): 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] + # LOG.debug(" --> " + str(rpc_addr)) + SESSION.register(meth[1], rpc_addr) + + LOG.info(" --> " + str(meth[0]) + " registered!") diff --git a/iotronic_lightningrod/modules/plugin_manager.py b/iotronic_lightningrod/modules/plugin_manager.py index 582ea3e..e4b230f 100644 --- a/iotronic_lightningrod/modules/plugin_manager.py +++ b/iotronic_lightningrod/modules/plugin_manager.py @@ -18,7 +18,6 @@ __author__ = "Nicola Peditto the tunnel for '" + service_name + + "' already exists; killing...") + + # 1. Kill wstun process (if exists) + try: + os.kill(service_pid, signal.SIGKILL) + LOG.info(" --> service '" + service_name + + "' with PID " + str(service_pid) + + " was killed; creating new one...") + except OSError: + LOG.warning(" - WSTUN process already killed, " + "creating new one...") + + break + + # 2. Create the reverse tunnel + public_port = \ + services_conf['services'][service_uuid]['public_port'] + local_port = \ + services_conf['services'][service_uuid]['local_port'] + + wstun = self._startWstun(public_port, local_port) + + if wstun != None: + service_pid = wstun.pid + + # 3. Update services.json file + services_conf['services'][service_uuid]['pid'] = \ + service_pid + services_conf['services'][service_uuid]['updated_at'] = \ + datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f') + + self._updateServiceConf(services_conf, service_uuid, + output=True) + + LOG.info(" --> Cloud service '" + service_name + + "' tunnel established.") + else: + message = "Error spawning " + str(service_name) \ + + " service tunnel!" + LOG.error(" - " + message) + + else: + LOG.info(" --> No service tunnels to establish.") + + def restore(self): + LOG.info("Cloud service tunnels to restore:") + + # Load services.json configuration file + services_conf = self._loadServicesConf() + + if len(services_conf['services']) != 0: + + wstun_process_list = [] + + # Collect all alive WSTUN proccesses + for p in psutil.process_iter(): + if len(p.cmdline()) != 0: + if (p.name() == "node") and ("wstun" in p.cmdline()[1]): + wstun_process_list.append(p) + + for service_uuid in services_conf['services']: + + service_name = services_conf['services'][service_uuid]['name'] + service_pid = services_conf['services'][service_uuid]['pid'] + LOG.info(" - " + service_name) + + s_alive = False + + # WSTUN is still alive + if len(wstun_process_list) != 0: + + for wp in wstun_process_list: + + if service_pid == wp.pid: + LOG.warning(" --> the tunnel for '" + service_name + + "' is still established.") + s_alive = True + break + + if not s_alive: + # Create the reverse tunnel again + public_port = services_conf['services'][service_uuid] + ['public_port'] + local_port = services_conf['services'][service_uuid] + ['local_port'] + + wstun = self._startWstun(public_port, local_port) + + if wstun != None: + service_pid = wstun.pid + + # 3. Update services.json file + services_conf['services'][service_uuid]['pid'] = \ + service_pid + services_conf['services'][service_uuid]['updated_at'] = \ + datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f') + + self._updateServiceConf(services_conf, + service_uuid, output=True) + + LOG.info(" --> Cloud service '" + service_name + + "' tunnel restored.") + else: + message = "Error spawning " + str(service_name) \ + + " service tunnel!" + LOG.error(" - " + message) + + else: + LOG.info(" --> No service tunnels to restore.") + + def _loadServicesConf(self): + """Load services.json JSON configuration. + + :return: JSON Services configuration + + """ try: - url_ip = urlparse(self.board.wamp_config["url"])[1].split(':')[0] + with open(SERVICES_CONF_FILE) as settings: + services_conf = json.load(settings) - # "wstun -r6030:127.0.0.1:22 ws://192.168.17.103:8080" - opt_reverse = "-r" + str(public_port) + ":127.0.0.1:" \ - + str(local_port) - wagent_url = "ws://" + url_ip + ":8080" + except Exception as err: + LOG.error( + "Parsing error in " + SERVICES_CONF_FILE + ": " + str(err)) + services_conf = None + return services_conf + + def _startWstun(self, public_port, local_port): + + opt_reverse = "-r" + str( + public_port) + ":127.0.0.1:" + str(local_port) + + try: wstun = subprocess.Popen( - ['/usr/bin/wstun', opt_reverse, wagent_url], + ['/usr/bin/wstun', opt_reverse, self.wagent_url], stdout=subprocess.PIPE ) + except Exception as err: + LOG.error("Error spawning WSTUN process: " + str(err)) + wstun = None - LOG.debug(" - WSTUN stdout: " + str(wstun.stdout)) + return wstun - message = "Cloud service " + str(name) + " exposed on port " \ - + str(public_port) + " on " + url_ip + def _updateServiceConf(self, services_conf, service_uuid, output=True): + # Apply the changes to services.json + with open(SERVICES_CONF_FILE, 'w') as f: + json.dump(services_conf, f, indent=4) - LOG.info(" - " + message + " with PID " + str(wstun.pid)) + if output: + LOG.info(" - service updated:\n" + json.dumps( + services_conf['services'][service_uuid], + indent=4, + sort_keys=True + )) + else: + LOG.info(" - services.json file updated!") - w_msg = WM.WampSuccess([wstun.pid, message]) + async def ServiceEnable(self, service, public_port): + + rpc_name = utils.getFuncName() + + service_name = service['name'] + service_uuid = service['uuid'] + local_port = service['port'] + + LOG.info("RPC " + rpc_name + " CALLED for '" + service_name + + "' (" + service_uuid + ") service:") + + try: + + wstun = self._startWstun(public_port, local_port) + + if wstun != None: + + service_pid = wstun.pid + + LOG.debug(" - WSTUN stdout: " + str(wstun.stdout)) + + # Update services.json file + # Load services.json configuration file + services_conf = self._loadServicesConf() + + # Save plugin settings in services.json + if service_uuid not in services_conf['services']: + + # It is a new plugin + services_conf['services'][service_uuid] = {} + services_conf['services'][service_uuid]['name'] = \ + service_name + services_conf['services'][service_uuid]['public_port'] = \ + public_port + services_conf['services'][service_uuid]['local_port'] = \ + local_port + services_conf['services'][service_uuid]['pid'] = \ + service_pid + services_conf['services'][service_uuid]['enabled_at'] = \ + datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f') + services_conf['services'][service_uuid]['updated_at'] = "" + + else: + # The service was already added and we are updating it + services_conf['services'][service_uuid]['updated_at'] = \ + datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f') + LOG.info(" - services.json file updated!") + + # Apply the changes to services.json + self._updateServiceConf(services_conf, service_uuid, + output=True) + + message = "Cloud service '" + str(service_name) \ + + "' exposed on port " \ + + str(public_port) + " on " + self.url_ip + + LOG.info(" - " + message + " with PID " + str(service_pid)) + + w_msg = WM.WampSuccess(message) + + else: + message = "Error spawning " + str(service_name) \ + + " service tunnel!" + LOG.error(" - " + message) + w_msg = WM.WampError(message) except Exception as err: - message = "Error exposing " + str(name) + " service: " + str(err) + message = "Error exposing " + str(service_name) \ + + " service: " + str(err) LOG.error(" - " + message) w_msg = WM.WampError(message) return w_msg.serialize() - async def ServiceDisable(self, name, pid): + async def ServiceDisable(self, service): - LOG.info("RPC " + utils.getFuncName() + " CALLED for " - + name + " service:") + rpc_name = utils.getFuncName() + service_name = service['name'] + service_uuid = service['uuid'] + + LOG.info("RPC " + rpc_name + + " CALLED for '" + service_name + + "' (" + service_uuid + ") service:") + + # Remove from services.json file try: - os.kill(pid, signal.SIGKILL) + # Load services.json configuration file + services_conf = self._loadServicesConf() - message = "Cloud service " + str(name) + " disabled." + if service_uuid in services_conf['services']: - LOG.info(" - " + message) - w_msg = WM.WampSuccess(message) + service_pid = services_conf['services'][service_uuid]['pid'] + + try: + + os.kill(service_pid, signal.SIGKILL) + + message = "Cloud service '" \ + + str(service_name) + "' tunnel disabled." + + del services_conf['services'][service_uuid] + + self._updateServiceConf(services_conf, service_uuid, + output=False) + + LOG.info(" - " + message) + w_msg = WM.WampSuccess(message) + + except Exception as err: + if err.errno == errno.ESRCH: # ESRCH == No such process + message = "Service '" + str( + service_name) + "' WSTUN process is not running!" + LOG.warning(" - " + message) + + del services_conf['services'][service_uuid] + + self._updateServiceConf(services_conf, service_uuid, + output=False) + + w_msg = WM.WampWarning(message) + + else: + + message = "Error disabling '" + str( + service_name) + "' service tunnel: " + str(err) + LOG.error(" - " + message) + w_msg = WM.WampError(message) + + else: + message = rpc_name + " result: " + service_uuid \ + + " already removed!" + LOG.error(" - " + message) + w_msg = WM.WampError(message) except Exception as err: - message = "Error disabling " + str(name) + " service: " + str(err) + message = "Updating services.json error: " + str(err) LOG.error(" - " + message) w_msg = WM.WampError(message) return w_msg.serialize() - async def ServiceRestore(self, name, public_port, local_port, pid): + async def ServiceRestore(self, service, public_port): - LOG.info("RPC " + utils.getFuncName() + " CALLED for " - + name + " service:") + rpc_name = utils.getFuncName() - try: + service_name = service['name'] + service_uuid = service['uuid'] + + LOG.info("RPC " + rpc_name + + " CALLED for '" + service_name + + "' (" + service_uuid + ") service:") + + # Load services.json configuration file + services_conf = self._loadServicesConf() + + if service_uuid in services_conf['services']: + + local_port = \ + services_conf['services'][service_uuid]['local_port'] + service_pid = \ + services_conf['services'][service_uuid]['pid'] - # 1. Kill wstun process (if exists) try: - os.kill(pid, signal.SIGKILL) - LOG.info(" - service " + name + " with PID " + str(pid) - + " killed.") - except OSError: - LOG.warning(" - WSTUN process already killed: " - "creating new one...") - # 2. Create the reverse tunnel - url_ip = urlparse(self.board.wamp_config["url"])[1].split(':')[0] - opt_reverse = "-r" + str(public_port) + ":127.0.0.1:" + str( - local_port) - wagent_url = "ws://" + url_ip + ":8080" - wstun = subprocess.Popen( - ['/usr/bin/wstun', opt_reverse, wagent_url], - stdout=subprocess.PIPE - ) + # 1. Kill wstun process (if exists) + try: + os.kill(service_pid, signal.SIGKILL) + LOG.info(" - service '" + service_name + + "' with PID " + str(service_pid) + + " was killed.") + except OSError: + LOG.warning(" - WSTUN process already killed: " + "creating new one...") - message = "service " + str(name) + " restored on port " \ - + str(public_port) + " on " + url_ip - LOG.info(" - " + message + " with PID " + str(wstun.pid)) - w_msg = WM.WampSuccess([wstun.pid, message]) + # 2. Create the reverse tunnel + wstun = self._startWstun(public_port, local_port) - except Exception as err: - message = "Error restoring " + str(name) + " service: " + str(err) - LOG.error(" - " + message) - w_msg = WM.WampError(message) + if wstun != None: + service_pid = wstun.pid + + # UPDATE services.json file + services_conf['services'][service_uuid]['pid'] = \ + service_pid + services_conf['services'][service_uuid]['updated_at'] = \ + datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f') + + self._updateServiceConf(services_conf, service_uuid, + output=True) + + message = "service " + str(service_name) \ + + " restored on port " \ + + str(public_port) + " on " + self.url_ip + LOG.info(" - " + message + " with PID " + str(service_pid)) + + w_msg = WM.WampSuccess(message) + + else: + message = "Error spawning " + str(service_name) \ + + " service tunnel!" + LOG.error(" - " + message) + w_msg = WM.WampError(message) + + except Exception as err: + message = "Error restoring '" + str(service_name) \ + + "' service tunnel: " + str(err) + LOG.error(" - " + message) + w_msg = WM.WampError(message) + + else: + + local_port = service['port'] + + wstun = self._startWstun(public_port, local_port) + + if wstun != None: + + service_pid = wstun.pid + + services_conf['services'][service_uuid] = {} + services_conf['services'][service_uuid]['name'] = \ + service_name + services_conf['services'][service_uuid]['public_port'] = \ + public_port + services_conf['services'][service_uuid]['local_port'] = \ + local_port + services_conf['services'][service_uuid]['pid'] = \ + service_pid + services_conf['services'][service_uuid]['enabled_at'] = \ + datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f') + services_conf['services'][service_uuid]['updated_at'] = "" + + self._updateServiceConf(services_conf, service_uuid, + output=True) + + message = "service " + str(service_name) \ + + " restored on port " \ + + str(public_port) + " on " + self.url_ip + LOG.info(" - " + message + " with PID " + str(service_pid)) + + w_msg = WM.WampSuccess(message) + + else: + message = "Error spawning " + str(service_name) \ + + " service tunnel!" + LOG.error(" - " + message) + w_msg = WM.WampError(message) return w_msg.serialize() diff --git a/iotronic_lightningrod/modules/utils.py b/iotronic_lightningrod/modules/utils.py index acc827e..f70c054 100644 --- a/iotronic_lightningrod/modules/utils.py +++ b/iotronic_lightningrod/modules/utils.py @@ -67,6 +67,9 @@ class Utility(Module.Module): def finalize(self): pass + def restore(self): + pass + async def hello(self, client_name, message): import random s = random.uniform(0.5, 3.0) diff --git a/iotronic_lightningrod/modules/vfs_manager.py b/iotronic_lightningrod/modules/vfs_manager.py index 93b6ef9..185cab8 100644 --- a/iotronic_lightningrod/modules/vfs_manager.py +++ b/iotronic_lightningrod/modules/vfs_manager.py @@ -57,6 +57,9 @@ class VfsManager(Module.Module): def finalize(self): pass + def restore(self): + pass + def mountLocal(self, mountSource, mountPoint): try: diff --git a/services.example.json b/services.example.json new file mode 100644 index 0000000..1b3131a --- /dev/null +++ b/services.example.json @@ -0,0 +1,5 @@ +{ + "services": { + + } +}