async def Remove_VIF(self, VIF_name):

        LOG.info("Removing a VIF from the board")

        try:
            LOG.info("Removing VIF")
            LOG.debug("Removing VIF :" + str(VIF_name))
            LOG.info(VIF_name[8:])

            p1 = subprocess.Popen("kill $(ps aux | grep -e '-r'" +
                                  VIF_name[8:] + " | awk '{print $2}')",
                                  shell=True,
                                  stdout=subprocess.PIPE,
                                  stderr=subprocess.STDOUT)

            p1 = subprocess.Popen("kill $(ps aux | grep -e 'dhclient " +
                                  VIF_name + "' | awk '{print $2}')",
                                  shell=True,
                                  stdout=subprocess.PIPE,
                                  stderr=subprocess.STDOUT)

            message = 'VIF removed'
            w_msg = WM.WampSuccess(message)

            LOG.info("VIF removed")
        except Exception as e:

            LOG.error(str(e))
            message = 'Error while removing the VIF'
            w_msg = WM.WampError(message)

        return w_msg.serialize()
    async def Configure_VIF(self, port_mac, ip_add, cidr):

        LOG.info("Configuration of the VIF")

        try:
            LOG.debug("Configuration of the VIF " + interface)

            p3 = subprocess.Popen("ip link set dev " + interface +
                                  " address " + str(port_mac),
                                  shell=True,
                                  stdout=subprocess.PIPE,
                                  stderr=subprocess.STDOUT)

            time.sleep(1)

            p5 = subprocess.Popen("ip address add " + str(ip_add) + "/" +
                                  str(cidr) + " dev " + interface,
                                  shell=True,
                                  stdout=subprocess.PIPE,
                                  stderr=subprocess.STDOUT)

            #p5 = subprocess.Popen("ip link set " + interface + " up" , shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

            message = 'IP address assigned'
            w_msg = WM.WampSuccess(message)

            LOG.info("Configuration succeded")

        except Exception as e:

            LOG.error(str(e))
            message = 'Error while the configuration'
            w_msg = WM.WampError(message)

        return w_msg.serialize()
Ejemplo n.º 3
0
    async def PluginStatus(self, plugin_uuid):
        """Check status thread plugin

        :param plugin_uuid:
        :return:

        """

        rpc_name = utils.getFuncName()
        LOG.info("RPC " + rpc_name + " CALLED for '"
                 + plugin_uuid + "' plugin:")

        try:

            if plugin_uuid in PLUGINS_THRS:

                worker = PLUGINS_THRS[plugin_uuid]

                if worker.isAlive():
                    result = "ALIVE"
                else:
                    result = "DEAD"

                LOG.info(" - " + worker.complete(rpc_name, result))
                w_msg = WM.WampSuccess(result)

            else:
                result = "DEAD"
                LOG.info(" - " + rpc_name + " result for "
                         + plugin_uuid + ": " + result)
                w_msg = WM.WampSuccess(result)

        except Exception as err:
            message = \
                rpc_name \
                + " - ERROR - plugin (" + plugin_uuid + ") - " + str(err)
            LOG.error(" - " + message)
            w_msg = WM.WampError(str(err))

            return w_msg.serialize()

        return w_msg.serialize()
    async def Create_VIF(self, r_tcp_port):

        LOG.info("Creation of the VIF ")

        port_socat = random.randint(10000, 20000)

        i = 0
        while i < len(Port):
            if Port[i] == port_socat:
                i = 0
                port_socat = random.randint(10000, 20000)
            i += 1
        Port.insert(0, port_socat)

        LOG.debug("Creation of the VIF iotronic" + str(r_tcp_port))

        #LOG.debug('Creating virtual interface on the board')

        try:
            p2 = subprocess.Popen(
                'socat -d -d TCP-L:' + str(port_socat) +
                ',bind=localhost,reuseaddr,forever,interval=10 TUN,tun-type=tap,tun-name=iotronic'
                + str(r_tcp_port) + ',up  ',
                shell=True,
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT)

            #ws://192.168.17.105:8080
            p1 = subprocess.Popen('wstun -r' + str(r_tcp_port) +
                                  ':localhost:' + str(port_socat) + ' ' +
                                  str(self.wagent_url),
                                  shell=True,
                                  stdout=subprocess.PIPE,
                                  stderr=subprocess.STDOUT)

            LOG.debug('Creation of the VIF succeded: iotronic')

            global interface
            interface = 'iotronic' + str(r_tcp_port)
            message = 'creation de WS tun et SOCAT'
            w_msg = WM.WampSuccess(message)

        except:

            LOG.error('Error while creating the virtual interface')
            message = 'Error while the creation'
            w_msg = WM.WampError(message)

        return w_msg.serialize()
Ejemplo n.º 5
0
    def PluginReboot(self, plugin_uuid):
        """To reboot an asynchronous plugin (callable = false) into the board.

        :return: return a response to RPC request

        """

        rpc_name = getFuncName()

        LOG.info("RPC " + rpc_name + " CALLED for '" + plugin_uuid +
                 "' plugin:")

        try:

            plugin_home = iotronic_home + "/plugins/" + plugin_uuid
            plugin_filename = plugin_home + "/" + plugin_uuid + ".py"
            plugin_params_file = plugin_home + "/" + plugin_uuid + ".json"

            plugins_conf = loadPluginsConf()
            plugin_name = plugins_conf['plugins'][plugin_uuid]['name']
            callable = plugins_conf['plugins'][plugin_uuid]['callable']

            if callable is False:

                if plugin_uuid in PLUGINS_THRS:

                    worker = PLUGINS_THRS[plugin_uuid]

                    if worker.isAlive():
                        # STOP PLUGIN------------------------------------------
                        LOG.info(" - Thread " + plugin_uuid +
                                 " is running, stopping...")
                        LOG.debug(" - Stopping plugin " + str(worker))
                        worker.stop()

                    # Remove from plugin thread list
                    del PLUGINS_THRS[plugin_uuid]

                # START PLUGIN-------------------------------------------------
                if os.path.exists(plugin_filename):

                    # Import plugin python module
                    task = imp.load_source("plugin", plugin_filename)

                    if os.path.exists(plugin_params_file):

                        with open(plugin_params_file) as conf:
                            plugin_params = json.load(conf)

                    else:
                        plugin_params = None

                    worker = task.Worker(plugin_uuid,
                                         plugin_name,
                                         params=plugin_params)

                    PLUGINS_THRS[plugin_uuid] = worker
                    LOG.info("   - Starting plugin " + str(worker))

                    worker.start()

                    message = "REBOOTED"
                    LOG.info(" - " + worker.complete(rpc_name, message))
                    w_msg = yield WM.WampSuccess(message)

                else:
                    message = "ERROR '" + plugin_filename + "' does not exist!"
                    LOG.error(" - " + message)
                    w_msg = yield WM.WampError(message)

        except Exception as err:
            message = "Error rebooting plugin '" \
                      + plugin_uuid + "': " + str(err)
            LOG.error(" - " + message)
            w_msg = yield WM.WampError(str(err))
            returnValue(w_msg.serialize())

        returnValue(w_msg.serialize())
Ejemplo n.º 6
0
    def PluginRemove(self, plugin_uuid):
        """To remove a plugin from the board

        :param plugin_uuid:
        :return: return a response to RPC request

        """

        rpc_name = getFuncName()

        LOG.info("RPC " + rpc_name + " for plugin " + plugin_uuid)

        plugin_path = iotronic_home + "/plugins/" + plugin_uuid + "/"

        if os.path.exists(plugin_path) is False \
                or os.path.exists(PLUGINS_CONF_FILE) is False:

            message = "Plugin paths or files do not exist!"
            LOG.error(message)
            w_msg = yield WM.WampError(message)
            returnValue(w_msg.serialize())

        else:

            LOG.info(" - Removing plugin...")

            try:

                try:

                    shutil.rmtree(plugin_path,
                                  ignore_errors=False,
                                  onerror=None)

                except Exception as err:
                    message = "Removing plugin's files error in " \
                              + plugin_path + ": " + str(err)
                    LOG.error(" - " + message)
                    w_msg = yield WM.WampError(str(err))
                    returnValue(w_msg.serialize())

                # Remove from plugins.json file its configuration
                try:

                    plugins_conf = loadPluginsConf()

                    if plugin_uuid in plugins_conf['plugins']:

                        plugin_name = \
                            plugins_conf['plugins'][plugin_uuid]['name']

                        del plugins_conf['plugins'][plugin_uuid]

                        with open(PLUGINS_CONF_FILE, 'w') as f:
                            json.dump(plugins_conf, f, indent=4)

                        if plugin_uuid in PLUGINS_THRS:
                            worker = PLUGINS_THRS[plugin_uuid]
                            if worker.isAlive():
                                LOG.info(" - Plugin " + plugin_name +
                                         " is running...")
                                worker.stop()
                                LOG.info("   ...stopped!")

                            del PLUGINS_THRS[plugin_uuid]

                        message = "PluginRemove result: " \
                                  + plugin_uuid + " removed!"
                        LOG.info(" - " + message)

                    else:
                        message = "PluginRemove result:  " \
                                  + plugin_uuid + " already removed!"
                        LOG.warning(" - " + message)

                    w_msg = yield WM.WampSuccess(message)
                    returnValue(w_msg.serialize())

                except Exception as err:
                    message = "Updating plugins.json error: " + str(err)
                    LOG.error(" - " + message)
                    w_msg = yield WM.WampError(str(err))
                    returnValue(w_msg.serialize())

            except Exception as err:
                message = "Plugin removing error: {0}".format(err)
                LOG.error(" - " + message)
                w_msg = yield WM.WampError(str(err))
                returnValue(w_msg.serialize())
Ejemplo n.º 7
0
    def PluginCall(self, plugin_uuid, parameters=None):
        """To execute a synchronous plugin into the board

        :param plugin_uuid:
        :param parameters:
        :return: return a response to RPC request

        """

        rpc_name = getFuncName()
        LOG.info("RPC " + rpc_name + " CALLED for " + plugin_uuid + " plugin:")

        try:

            if (plugin_uuid
                    in PLUGINS_THRS) and (PLUGINS_THRS[plugin_uuid].isAlive()):

                message = "Plugin " + plugin_uuid + " already started!"
                LOG.warning(" - " + message)
                w_msg = yield WM.WampWarning(message)

            else:

                plugin_home = iotronic_home + "/plugins/" + plugin_uuid
                plugin_filename = plugin_home + "/" + plugin_uuid + ".py"
                plugin_params_file = plugin_home + "/" + plugin_uuid + ".json"

                plugins_conf = loadPluginsConf()
                plugin_name = plugins_conf['plugins'][plugin_uuid]['name']

                # Import plugin (as python module)
                if os.path.exists(plugin_filename):

                    try:

                        task = imp.load_source("plugin", plugin_filename)

                        LOG.info(" - Plugin " + plugin_uuid + " imported!")

                        q_result = Queue()

                    except Exception as err:
                        message = "Error importing plugin " \
                                  + plugin_filename + ": " + str(err)
                        LOG.error(" - " + message)
                        w_msg = yield WM.WampError(str(err))
                        returnValue(w_msg.serialize())

                    try:

                        # Store input parameters of the plugin
                        if parameters is not None:
                            with open(plugin_params_file, 'w') as f:
                                json.dump(parameters, f, indent=4)

                            with open(plugin_params_file) as conf:
                                plugin_params = json.load(conf)

                            LOG.info(" - Plugin configuration:\n" +
                                     str(plugin_params))

                        else:
                            plugin_params = None

                        worker = task.Worker(plugin_uuid,
                                             plugin_name,
                                             q_result=q_result,
                                             params=plugin_params)

                        PLUGINS_THRS[plugin_uuid] = worker
                        LOG.debug(" - Executing plugin " + str(worker))

                        worker.start()

                        while q_result.empty():
                            pass

                        response = q_result.get()

                        LOG.info(" - " + worker.complete(rpc_name, response))
                        w_msg = yield WM.WampSuccess(response)

                    except Exception as err:
                        message = "Error spawning plugin " \
                                  + plugin_filename + ": " + str(err)
                        LOG.error(" - " + message)
                        w_msg = yield WM.WampError(str(err))
                        returnValue(w_msg.serialize())

                else:
                    message = \
                        rpc_name \
                        + " - ERROR " + plugin_filename + " does not exist!"
                    LOG.error(" - " + message)
                    w_msg = yield WM.WampError(message)

        except Exception as err:
            message = \
                rpc_name \
                + " - ERROR - plugin (" + plugin_uuid + ") - " + str(err)
            LOG.error(" - " + message)
            w_msg = yield WM.WampError(str(err))
            returnValue(w_msg.serialize())

        returnValue(w_msg.serialize())
Ejemplo n.º 8
0
    def PluginStop(self, plugin_uuid, parameters=None):
        """To stop an asynchronous plugin

        :param plugin_uuid: ID of plufin to stop
        :param parameters: JSON OPTIONAL stop parameters; 'delay' in seconds
        :return: return a response to RPC request

        """
        rpc_name = getFuncName()
        LOG.info("RPC " + rpc_name + " CALLED for '" + plugin_uuid +
                 "' plugin:")

        if parameters is not None:
            LOG.info(" - " + rpc_name + " parameters: " + str(parameters))
            if 'delay' in parameters:
                delay = parameters['delay']
                LOG.info(" --> stop delay: " + str(delay))

        try:

            if plugin_uuid in PLUGINS_THRS:

                worker = PLUGINS_THRS[plugin_uuid]
                LOG.debug(" - Stopping plugin " + str(worker))

                if worker.isAlive():

                    if 'delay' in parameters:
                        time.sleep(delay)

                    yield worker.stop()

                    del PLUGINS_THRS[plugin_uuid]

                    message = "STOPPED"
                    LOG.info(" - " + worker.complete(rpc_name, message))
                    w_msg = yield WM.WampSuccess(message)

                else:
                    message = \
                        rpc_name \
                        + " - ERROR - plugin (" + plugin_uuid \
                        + ") is instantiated but is not running anymore!"
                    LOG.error(" - " + message)
                    w_msg = yield WM.WampError(message)

            else:
                message = \
                    rpc_name + " - WARNING " \
                    + plugin_uuid + "  is not running!"
                LOG.warning(" - " + message)
                w_msg = yield WM.WampWarning(message)

        except Exception as err:
            message = \
                rpc_name \
                + " - ERROR - plugin (" + plugin_uuid + ") - " + str(err)
            LOG.error(" - " + message)
            w_msg = yield WM.WampError(str(err))
            returnValue(w_msg.serialize())

        returnValue(w_msg.serialize())
Ejemplo n.º 9
0
    def PluginStart(self, plugin_uuid, parameters=None):
        """To start an asynchronous plugin;

        the plugin will run until the PluginStop is called.

        :param plugin_uuid:
        :param parameters:
        :return: return a response to RPC request

        """

        try:

            rpc_name = getFuncName()
            LOG.info("RPC " + rpc_name + " called for '" + plugin_uuid +
                     "' plugin:")

            plugins_conf = loadPluginsConf()

            if plugin_uuid in plugins_conf['plugins']:

                plugin_name = plugins_conf['plugins'][plugin_uuid]['name']

                # Check if the plugin is already running
                if (plugin_uuid in PLUGINS_THRS) and (
                        PLUGINS_THRS[plugin_uuid].isAlive()):

                    message = "ALREADY STARTED!"
                    LOG.warning(" - Plugin " + plugin_uuid +
                                " already started!")
                    w_msg = yield WM.WampError(message)

                else:

                    plugin_home = \
                        iotronic_home + "/plugins/" + plugin_uuid
                    plugin_filename = \
                        plugin_home + "/" + plugin_uuid + ".py"
                    plugin_params_file = \
                        plugin_home + "/" + plugin_uuid + ".json"

                    # Import plugin (as python module)
                    if os.path.exists(plugin_filename):

                        task = imp.load_source("plugin", plugin_filename)

                        LOG.info(" - Plugin '" + plugin_uuid + "' imported!")

                        # Store input parameters of the plugin
                        if parameters is not None:

                            with open(plugin_params_file, 'w') as f:
                                json.dump(parameters, f, indent=4)

                            with open(plugin_params_file) as conf:
                                plugin_params = json.load(conf)

                            LOG.info(" - plugin with parameters:")
                            LOG.info("   " + str(plugin_params))

                        else:
                            plugin_params = None

                        worker = task.Worker(plugin_uuid,
                                             plugin_name,
                                             params=plugin_params)

                        PLUGINS_THRS[plugin_uuid] = worker
                        LOG.debug(" - Starting plugin " + str(worker))

                        worker.start()

                        # Apply the changes to plugins.json
                        with open(PLUGINS_CONF_FILE, 'w') as f:
                            plugins_conf['plugins'][plugin_uuid]['status'] = \
                                'operative'
                            json.dump(plugins_conf, f, indent=4)

                        response = "STARTED"
                        LOG.info(" - " + worker.complete(rpc_name, response))
                        w_msg = yield WM.WampSuccess(response)

                    else:
                        message = \
                            rpc_name + " - ERROR " \
                            + plugin_filename + " does not exist!"
                        LOG.error(" - " + message)
                        w_msg = yield WM.WampError(message)

            else:
                message = "Plugin " + plugin_uuid \
                          + " does not exist in this board!"
                LOG.warning(" - " + message)
                w_msg = yield WM.WampError(message)

        except Exception as err:
            message = \
                rpc_name + " - ERROR - plugin (" + plugin_uuid + ") - " \
                + str(err)
            LOG.error(" - " + message)
            w_msg = yield WM.WampError(str(err))
            returnValue(w_msg.serialize())

        returnValue(w_msg.serialize())
Ejemplo n.º 10
0
    def PluginInject(self, plugin, onboot):
        """Plugin injection procedure into the board:

         1. get Plugin files
         2. deserialize files
         3. store files

        :param plugin:
        :param onboot:
        :return:

        """

        rpc_name = getFuncName()

        try:

            plugin_uuid = plugin['uuid']
            plugin_name = plugin['name']
            code = plugin['code']
            callable = plugin['callable']

            LOG.info("RPC " + rpc_name + " for plugin '" + plugin_name +
                     "' (" + plugin_uuid + ")")

            # Deserialize the plugin code received
            ser = PluginSerializer.ObjectSerializer()
            loaded = ser.deserialize_entity(code)
            # LOG.debug("- plugin loaded code:\n" + loaded)

            plugin_path = iotronic_home + "/plugins/" + plugin_uuid + "/"
            plugin_filename = plugin_path + plugin_uuid + ".py"

            # Plugin folder creation if does not exist
            if not os.path.exists(plugin_path):
                os.makedirs(plugin_path)

            # Plugin code file creation
            with open(plugin_filename, "w") as pluginfile:
                pluginfile.write(loaded)

            # Load plugins.json configuration file
            plugins_conf = loadPluginsConf()

            # LOG.debug("Plugin setup:\n"
            #          + json.dumps(plugin, indent=4, sort_keys=True))

            # Save plugin settings in plugins.json
            if plugin_uuid not in plugins_conf['plugins']:

                # It is a new plugin
                plugins_conf['plugins'][plugin_uuid] = {}
                plugins_conf['plugins'][plugin_uuid]['name'] = plugin_name
                plugins_conf['plugins'][plugin_uuid]['onboot'] = onboot
                plugins_conf['plugins'][plugin_uuid]['callable'] = callable
                plugins_conf['plugins'][plugin_uuid]['injected_at'] = \
                    datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')
                plugins_conf['plugins'][plugin_uuid]['updated_at'] = ""
                plugins_conf['plugins'][plugin_uuid]['status'] = "injected"

                LOG.info("Plugin " + plugin_name + " created!")
                message = rpc_name + " result: INJECTED"

            else:
                # The plugin was already injected and we are updating it
                plugins_conf['plugins'][plugin_uuid]['name'] = plugin_name
                plugins_conf['plugins'][plugin_uuid]['onboot'] = onboot
                plugins_conf['plugins'][plugin_uuid]['callable'] = callable
                plugins_conf['plugins'][plugin_uuid]['updated_at'] = \
                    datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')
                plugins_conf['plugins'][plugin_uuid]['status'] = "updated"

                LOG.info("Plugin " + plugin_name + " (" + str(plugin_uuid) +
                         ") updated!")
                message = rpc_name + " result: UPDATED"

            LOG.info("Plugin setup:\n" + json.dumps(
                plugins_conf['plugins'][plugin_uuid], indent=4, sort_keys=True)
                     )

            # Apply the changes to plugins.json
            with open(PLUGINS_CONF_FILE, 'w') as f:
                json.dump(plugins_conf, f, indent=4)

            LOG.info(" - " + message)
            w_msg = yield WM.WampSuccess(message)

        except Exception as err:
            message = "Plugin injection error: " + str(err)
            LOG.error(" - " + message)
            w_msg = yield WM.WampError(str(err))
            returnValue(w_msg.serialize())

        returnValue(w_msg.serialize())
    async def ServiceRestore(self, service, public_port):

        rpc_name = utils.getFuncName()

        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']

            try:

                # 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...")

                # 2. Create the reverse tunnel
                wstun = self._startWstun(public_port, local_port)

                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()
    async def ServiceDisable(self, 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:

            # Load services.json configuration file
            services_conf = self._loadServicesConf()

            if service_uuid in services_conf['services']:

                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 = "Updating services.json error: " + str(err)
            LOG.error(" - " + message)
            w_msg = WM.WampError(message)

        return w_msg.serialize()
    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(service_name) \
                      + " service: " + str(err)
            LOG.error(" - " + message)
            w_msg = WM.WampError(message)

        return w_msg.serialize()