text: # Copyright 2017 MDSLAB - University of Messina
  # All Rights Reserved.
  #
  #    Licensed under the Apache License, Version 2.0 (the "License"); you may
  #    not use this file except in compliance with the License. You may obtain
  #    a copy of the License at
  #
  #         http://www.apache.org/licenses/LICENSE-2.0
  #
  #    Unless required by applicable law or agreed to in writing, software
  #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  #    License for the specific language governing permissions and limitations
  #    under the License.
  from __future__ import absolute_import
  
  __author__ = "Nicola Peditto <n.peditto@gmail.com>"
  
  from datetime import datetime
  import importlib as imp
  import json
  import os
  import queue
  import shutil
  import time
  
  
  from iotronic_lightningrod.modules import Module
  from iotronic_lightningrod.modules.plugins import PluginSerializer
  from iotronic_lightningrod.modules import utils
  import iotronic_lightningrod.wampmessage as WM
  
  
  from oslo_config import cfg
  from oslo_log import log as logging
  LOG = logging.getLogger(__name__)
  
  CONF = cfg.CONF
  PLUGINS_THRS = {}
  PLUGINS_CONF_FILE = CONF.lightningrod_home + "/plugins.json"
  
  
  class PluginManager(Module.Module):
  
      """Plugin module to manage board plugins.
  
      """
  
      def __init__(self, board, session):
          """Init function for PluginManager module.
  
          :param board:
          :param session:
  
          """
  
          # Module declaration
          super(PluginManager, self).__init__("PluginManager", board)
  
          # Creation of plugins.json configuration file
          self._createPluginsConf()
  
      def finalize(self):
          """Function called at the end of module loading.
  
          This function in this module reloads
          the enabled (asynchronous) plugins at boot.
  
          """
  
          # Reboot boot enabled plugins
          self._rebootOnBootPlugins()
  
      def restore(self):
          pass
  
      def _loadPluginsConf(self):
          """Load plugins.json JSON configuration.
  
          :return: JSON Plugins configuration
  
          """
  
          try:
  
              with open(PLUGINS_CONF_FILE) as settings:
                  plugins_conf = json.load(settings)
  
          except Exception as err:
              LOG.error(
                  "Parsing error in " + PLUGINS_CONF_FILE + ": " + str(err))
              plugins_conf = None
  
          return plugins_conf
  
      def _getEnabledPlugins(self):
          """This function gets the list of all asynchronous plugins.
  
          We considered only those plugins with 'callable' flag set to False
          and 'onboot' flag set to True.
  
          :return: enabledPlugins List
  
          """
          enabledPlugins = []
          plugins_conf = self._loadPluginsConf()
  
          for plugin in plugins_conf['plugins']:
  
              if plugins_conf['plugins'][plugin]['callable'] is False:
  
                  if plugins_conf['plugins'][plugin]['onboot'] is True:
  
                      if plugins_conf['plugins'][plugin]['status'] == \
                              "operative":
                          enabledPlugins.append(plugin)
  
          if len(enabledPlugins) != 0:
              LOG.info(" - Enabled plugins list: " + str(enabledPlugins))
  
          return enabledPlugins
  
      def _rebootOnBootPlugins(self):
          """Reboot at boot each enabled asynchronous plugin
  
          :return:
  
          """
  
          f_name = utils.getFuncName()
          LOG.info("Rebooting enabled plugins:")
  
          enabledPlugins = self._getEnabledPlugins()
  
          if enabledPlugins.__len__() == 0:
  
              message = "No plugin to reboot!"
              LOG.info(" - " + message)
  
          else:
  
              for plugin_uuid in enabledPlugins:
  
                  plugins_conf = self._loadPluginsConf()
                  plugin_name = plugins_conf['plugins'][plugin_uuid]['name']
  
                  try:
  
                      if (plugin_uuid in PLUGINS_THRS) and (
                              PLUGINS_THRS[plugin_uuid].isAlive()
                      ):
  
                          LOG.warning(" - Plugin "
                                      + plugin_uuid + " already started!")
  
                      else:
  
                          LOG.info(" - Rebooting plugin " + plugin_uuid)
  
                          plugin_home = \
                              CONF.lightningrod_home + "/plugins/" + plugin_uuid
                          plugin_filename = \
                              plugin_home + "/" + plugin_uuid + ".py"
                          plugin_params_file = \
                              plugin_home + "/" + plugin_uuid + ".json"
  
                          if os.path.exists(plugin_filename):
  
                              # task = imp.load_source("plugin", plugin_filename)
                              task = imp.machinery.SourceFileLoader(
                                  "plugin",
                                  plugin_filename
                              ).load_module()
  
                              if os.path.exists(plugin_params_file):
  
                                  with open(plugin_params_file) as conf:
                                      plugin_params = json.load(conf)
  
                                  worker = task.Worker(
                                      plugin_uuid,
                                      plugin_name,
                                      q_result=None,
                                      params=plugin_params
                                  )
  
                                  PLUGINS_THRS[plugin_uuid] = worker
                                  LOG.info("   - Starting plugin " + str(worker))
  
                                  worker.start()
  
                              else:
                                  message = "ERROR " + plugin_params_file \
                                            + " does not exist!"
  
                                  LOG.error("   - "
                                            + worker.complete(f_name, message))
  
                          else:
                              message = "ERROR " \
                                        + plugin_filename + " does not exist!"
  
                              LOG.error(
                                  "   - " + worker.complete(f_name, message))
  
                      message = "rebooted!"
  
                      LOG.info("   - " + worker.complete(f_name, message))
  
                  except Exception as err:
                      message = "Error rebooting plugin " \
                                + plugin_uuid + ": " + str(err)
                      LOG.error(" - " + message)
  
      def _createPluginsConf(self):
          """Create plugins.json file if it does not exist.
  
          """
          if not os.path.exists(PLUGINS_CONF_FILE):
              LOG.debug("plugins.json does not exist: creating...")
              plugins_conf = {'plugins': {}}
              with open(PLUGINS_CONF_FILE, 'w') as f:
                  json.dump(plugins_conf, f, indent=4)
  
      async 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 = utils.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 = CONF.lightningrod_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 = self._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 = WM.WampSuccess(message)
  
          except Exception as err:
              message = "Plugin injection error: " + str(err)
              LOG.error(" - " + message)
              w_msg = WM.WampError(str(err))
  
              return w_msg.serialize()
  
          return w_msg.serialize()
  
      async 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 = utils.getFuncName()
              LOG.info("RPC " + rpc_name + " called for '"
                       + plugin_uuid + "' plugin:")
  
              plugins_conf = self._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 = WM.WampError(message)
  
                  else:
  
                      plugin_home = \
                          CONF.lightningrod_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.machinery.SourceFileLoader(
                              "plugin",
                              plugin_filename
                          ).load_module()
  
                          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 = WM.WampSuccess(response)
  
                      else:
                          message = \
                              rpc_name + " - ERROR " \
                              + plugin_filename + " does not exist!"
                          LOG.error(" - " + message)
                          w_msg = WM.WampError(message)
  
              else:
                  message = "Plugin " + plugin_uuid \
                            + " does not exist in this board!"
                  LOG.warning(" - " + message)
                  w_msg = WM.WampError(message)
  
          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 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 = utils.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)
  
                      worker.stop()
  
                      del PLUGINS_THRS[plugin_uuid]
  
                      message = "STOPPED"
                      LOG.info(" - " + worker.complete(rpc_name, message))
                      w_msg = WM.WampSuccess(message)
  
                  else:
                      message = \
                          rpc_name \
                          + " - ERROR - plugin (" + plugin_uuid \
                          + ") is instantiated but is not running anymore!"
                      LOG.error(" - " + message)
                      w_msg = WM.WampError(message)
  
              else:
                  message = \
                      rpc_name + " - WARNING " \
                      + plugin_uuid + "  is not running!"
                  LOG.warning(" - " + message)
                  w_msg = WM.WampWarning(message)
  
          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 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 = utils.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 = WM.WampWarning(message)
  
              else:
  
                  plugin_home = CONF.lightningrod_home \
                      + "/plugins/" + plugin_uuid
                  plugin_filename = plugin_home + "/" + plugin_uuid + ".py"
                  plugin_params_file = plugin_home + "/" + plugin_uuid + ".json"
  
                  plugins_conf = self._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)
                          task = imp.machinery.SourceFileLoader(
                              "plugin",
                              plugin_filename
                          ).load_module()
  
                          LOG.info(" - Plugin " + plugin_uuid + " imported!")
  
                          q_result = queue.Queue()
  
                      except Exception as err:
                          message = "Error importing plugin " \
                                    + plugin_filename + ": " + str(err)
                          LOG.error(" - " + message)
                          w_msg = WM.WampError(str(err))
  
                          return 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 = WM.WampSuccess(response)
  
                      except Exception as err:
                          message = "Error spawning plugin " \
                                    + plugin_filename + ": " + str(err)
                          LOG.error(" - " + message)
                          w_msg = WM.WampError(str(err))
  
                          return w_msg.serialize()
  
                  else:
                      message = \
                          rpc_name \
                          + " - ERROR " + plugin_filename + " does not exist!"
                      LOG.error(" - " + message)
                      w_msg = WM.WampError(message)
  
          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 PluginRemove(self, plugin_uuid):
          """To remove a plugin from the board
  
          :param plugin_uuid:
          :return: return a response to RPC request
  
          """
  
          rpc_name = utils.getFuncName()
  
          LOG.info("RPC " + rpc_name + " for plugin " + plugin_uuid)
  
          plugin_path = CONF.lightningrod_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 = WM.WampError(message)
  
              return 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 = WM.WampError(str(err))
  
                      return w_msg.serialize()
  
                  # Remove from plugins.json file its configuration
                  try:
  
                      plugins_conf = self._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 = WM.WampSuccess(message)
  
                      return w_msg.serialize()
  
                  except Exception as err:
                      message = "Updating plugins.json error: " + str(err)
                      LOG.error(" - " + message)
                      w_msg = WM.WampError(str(err))
  
                      return w_msg.serialize()
  
              except Exception as err:
                  message = "Plugin removing error: {0}".format(err)
                  LOG.error(" - " + message)
                  w_msg = WM.WampError(str(err))
  
                  return w_msg.serialize()
  
      async def PluginReboot(self, plugin_uuid, parameters=None):
          """To reboot an asynchronous plugin (callable = false) into the board.
  
          :return: return a response to RPC request
  
          """
  
          rpc_name = utils.getFuncName()
  
          LOG.info("RPC " + rpc_name + " CALLED for '"
                   + plugin_uuid + "' plugin:")
  
          LOG.info(" - plugin restarting with parameters:")
          LOG.info("   " + str(parameters))
  
          try:
  
              plugin_home = CONF.lightningrod_home + "/plugins/" + plugin_uuid
              plugin_filename = plugin_home + "/" + plugin_uuid + ".py"
              plugin_params_file = plugin_home + "/" + plugin_uuid + ".json"
  
              plugins_conf = self._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]
  
                      # STOP PLUGIN----------------------------------------------
  
                      if worker.isAlive():
  
                          LOG.info(" - Thread "
                                   + plugin_uuid + " is running, stopping...")
                          LOG.debug(" - Stopping plugin " + str(worker))
                          worker.stop()
  
                      while worker.isAlive():
                          pass
  
                      # Remove from plugin thread list
                      del PLUGINS_THRS[plugin_uuid]
                      LOG.debug(" - plugin data structure cleaned!")
  
                  # START PLUGIN-------------------------------------------------
                  if os.path.exists(plugin_filename):
  
                      # Import plugin python module
                      # task = imp.load_source("plugin", plugin_filename)
                      task = imp.machinery.SourceFileLoader(
                          "plugin",
                          plugin_filename
                      ).load_module()
  
                      if parameters is None:
  
                          if os.path.exists(plugin_params_file):
  
                              with open(plugin_params_file) as conf:
                                  plugin_params = json.load(conf)
  
                          else:
                              plugin_params = None
  
                      else:
                          plugin_params = parameters
                          LOG.info(" - plugin restarting with parameters:")
                          LOG.info("   " + str(plugin_params))
  
                      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 = WM.WampSuccess(message)
  
                  else:
                      message = "ERROR '" + plugin_filename + "' does not exist!"
                      LOG.error(" - " + message)
                      w_msg = WM.WampError(message)
  
          except Exception as err:
              message = "Error rebooting plugin '" \
                        + plugin_uuid + "': " + str(err)
              LOG.error(" - " + message)
              w_msg = WM.WampError(str(err))
  
              return w_msg.serialize()
  
          return w_msg.serialize()
  
      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()
  