general fixes and checks

Change-Id: I72de75a264ebd92bca35c52746cb2987d8f94902
This commit is contained in:
Fabio Verboso 2017-04-03 19:03:02 +02:00
parent 063e62ee3d
commit 0b57956164
16 changed files with 261 additions and 167 deletions

3
.gitignore vendored
View File

@ -3,3 +3,6 @@
iotronic.egg-info
build
*.pyc
AUTHORS
Authors
ChangeLog

View File

@ -174,41 +174,47 @@ class BoardPluginsController(rest.RestController):
"""Retrieve a list of plugins of a board.
"""
# cdict = pecan.request.context.to_policy_values()
# policy.authorize('iot:plugins_on_board:get', cdict, cdict)
rpc_board = api_utils.get_rpc_board(self.board_ident)
cdict = pecan.request.context.to_policy_values()
cdict['owner'] = rpc_board.owner
policy.authorize('iot:plugin_on_board:get', cdict, cdict)
return self._get_plugins_on_board_collection(rpc_board.uuid)
@expose.expose(InjectionPlugin, types.uuid_or_name)
def get_one(self, plugin_ident):
"""Retrieve information about the given board.
:param plugin_ident: UUID or logical name of a board.
:param fields: Optional, a list with a specified set of fields
of the resource to be returned.
"""
# cdict = pecan.request.context.to_policy_values()
# policy.authorize('iot:plugins_on_board:get', cdict, cdict)
rpc_board = api_utils.get_rpc_board(self.board_ident)
rpc_plugin = api_utils.get_rpc_plugin(plugin_ident)
inj_plug = objects.InjectionPlugin.get(pecan.request.context,
rpc_board.uuid,
rpc_plugin.uuid)
return InjectionPlugin(**inj_plug.as_dict())
@expose.expose(wtypes.text, types.uuid_or_name, body=PluginAction,
status_code=200)
def post(self, plugin_ident, PluginAction):
# cdict = pecan.request.context.to_policy_values()
# policy.authorize('iot:plugin_action:post', cdict, cdict)
rpc_plugin = api_utils.get_rpc_plugin(plugin_ident)
if not PluginAction.action:
raise exception.MissingParameterValue(
("Action is not specified."))
if not PluginAction.parameters:
PluginAction.parameters = {}
rpc_board = api_utils.get_rpc_board(self.board_ident)
rpc_plugin = api_utils.get_rpc_plugin(plugin_ident)
try:
cdict = pecan.request.context.to_policy_values()
cdict['owner'] = rpc_board.owner
policy.authorize('iot:plugin_action:post', cdict, cdict)
if not rpc_plugin.public:
cdict = pecan.request.context.to_policy_values()
cdict['owner'] = rpc_plugin.owner
policy.authorize('iot:plugin_action:post', cdict, cdict)
except exception:
return exception
rpc_board.check_if_online()
if objects.plugin.want_customs_params(PluginAction.action):
valid_keys = list(rpc_plugin.parameters.keys())
if not all(k in PluginAction.parameters for k in valid_keys):
raise exception.InvalidParameterValue(
"Parameters are different from the valid ones")
result = pecan.request.rpcapi.action_plugin(pecan.request.context,
rpc_plugin.uuid,
@ -226,11 +232,29 @@ class BoardPluginsController(rest.RestController):
:param board_ident: UUID or logical name of a board.
"""
# cdict = context.to_policy_values()
# policy.authorize('iot:plugin:inject', cdict, cdict)
if not Injection.plugin:
raise exception.MissingParameterValue(
("Plugin is not specified."))
if not Injection.onboot:
Injection.onboot = False
rpc_plugin = api_utils.get_rpc_plugin(Injection.plugin)
rpc_board = api_utils.get_rpc_board(self.board_ident)
rpc_plugin = api_utils.get_rpc_plugin(Injection.plugin)
try:
cdict = pecan.request.context.to_policy_values()
cdict['owner'] = rpc_board.owner
policy.authorize('iot:plugin_inject:put', cdict, cdict)
if not rpc_plugin.public:
cdict = pecan.request.context.to_policy_values()
cdict['owner'] = rpc_plugin.owner
policy.authorize('iot:plugin_inject:put', cdict, cdict)
except exception:
return exception
rpc_board.check_if_online()
result = pecan.request.rpcapi.inject_plugin(pecan.request.context,
rpc_plugin.uuid,
rpc_board.uuid,
@ -245,11 +269,12 @@ class BoardPluginsController(rest.RestController):
:param plugin_ident: UUID or logical name of a plugin.
:param board_ident: UUID or logical name of a board.
"""
# cdict = context.to_policy_values()
# policy.authorize('iot:plugin:remove', cdict, cdict)
rpc_board = api_utils.get_rpc_board(self.board_ident)
cdict = pecan.request.context.to_policy_values()
cdict['owner'] = rpc_board.owner
policy.authorize('iot:plugin_remove:delete', cdict, cdict)
rpc_board.check_if_online()
rpc_plugin = api_utils.get_rpc_plugin(plugin_uuid)
return pecan.request.rpcapi.remove_plugin(pecan.request.context,

View File

@ -39,6 +39,7 @@ class Plugin(base.APIBase):
public = types.boolean
owner = types.uuid
callable = types.boolean
parameters = types.jsontype
links = wsme.wsattr([link.Link], readonly=True)
extra = types.jsontype
@ -105,7 +106,7 @@ class PluginsController(rest.RestController):
def _get_plugins_collection(self, marker, limit,
sort_key, sort_dir,
fields=None, with_publics=False,
fields=None, with_public=False,
all_plugins=False):
limit = api_utils.validate_limit(limit)
@ -130,8 +131,8 @@ class PluginsController(rest.RestController):
else:
if not all_plugins:
filters['owner'] = pecan.request.context.user_id
if with_publics:
filters['public'] = with_publics
if with_public:
filters['public'] = with_public
plugins = objects.Plugin.list(pecan.request.context, limit, marker_obj,
sort_key=sort_key, sort_dir=sort_dir,
@ -153,18 +154,18 @@ class PluginsController(rest.RestController):
"""
rpc_plugin = api_utils.get_rpc_plugin(plugin_ident)
cdict = pecan.request.context.to_policy_values()
cdict['owner'] = rpc_plugin.owner
policy.authorize('iot:plugin:get_one', cdict, cdict)
if not rpc_plugin.public:
cdict = pecan.request.context.to_policy_values()
cdict['owner'] = rpc_plugin.owner
policy.authorize('iot:plugin:get_one', cdict, cdict)
return Plugin.convert_with_links(rpc_plugin, fields=fields)
@expose.expose(PluginCollection, types.uuid, int, wtypes.text,
wtypes.text, types.listtype)
wtypes.text, types.listtype, types.boolean, types.boolean)
def get_all(self, marker=None,
limit=None, sort_key='id', sort_dir='asc',
fields=None):
fields=None, with_public=False, all_plugins=False):
"""Retrieve a list of plugins.
:param marker: pagination marker for large data sets.
@ -174,6 +175,9 @@ class PluginsController(rest.RestController):
max_limit resources will be returned.
:param sort_key: column to sort results by. Default: id.
:param sort_dir: direction to sort. "asc" or "desc". Default: asc.
:param with_public: Optional boolean to get also public pluings.
:param all_plugins: Optional boolean to get all the pluings.
Only for the admin
:param fields: Optional, a list with a specified set of fields
of the resource to be returned.
"""
@ -184,6 +188,8 @@ class PluginsController(rest.RestController):
fields = _DEFAULT_RETURN_FIELDS
return self._get_plugins_collection(marker,
limit, sort_key, sort_dir,
with_public=with_public,
all_plugins=all_plugins,
fields=fields)
@expose.expose(Plugin, body=Plugin, status_code=201)
@ -210,7 +216,6 @@ class PluginsController(rest.RestController):
**Plugin.as_dict())
new_Plugin.owner = cdict['user']
new_Plugin = pecan.request.rpcapi.create_plugin(pecan.request.context,
new_Plugin)
@ -239,27 +244,27 @@ class PluginsController(rest.RestController):
:return updated_plugin: updated_plugin
"""
context = pecan.request.context
cdict = context.to_policy_values()
rpc_plugin = api_utils.get_rpc_plugin(plugin_ident)
cdict = pecan.request.context.to_policy_values()
cdict['owner'] = rpc_plugin.owner
policy.authorize('iot:plugin:update', cdict, cdict)
plugin = api_utils.get_rpc_plugin(plugin_ident)
val_Plugin = val_Plugin.as_dict()
for key in val_Plugin:
try:
plugin[key] = val_Plugin[key]
rpc_plugin[key] = val_Plugin[key]
except Exception:
pass
updated_plugin = pecan.request.rpcapi.update_plugin(
pecan.request.context, plugin)
pecan.request.context, rpc_plugin)
return Plugin.convert_with_links(updated_plugin)
@expose.expose(PluginCollection, types.uuid, int, wtypes.text,
wtypes.text, types.listtype, types.boolean, types.boolean)
def detail(self, marker=None,
limit=None, sort_key='id', sort_dir='asc',
fields=None, with_publics=False, all_plugins=False):
fields=None, with_public=False, all_plugins=False):
"""Retrieve a list of plugins.
:param marker: pagination marker for large data sets.
@ -269,7 +274,7 @@ class PluginsController(rest.RestController):
max_limit resources will be returned.
:param sort_key: column to sort results by. Default: id.
:param sort_dir: direction to sort. "asc" or "desc". Default: asc.
:param with_publics: Optional boolean to get also public pluings.
:param with_public: Optional boolean to get also public pluings.
:param all_plugins: Optional boolean to get all the pluings.
Only for the admin
:param fields: Optional, a list with a specified set of fields
@ -286,6 +291,6 @@ class PluginsController(rest.RestController):
return self._get_plugins_collection(marker,
limit, sort_key, sort_dir,
with_publics=with_publics,
with_public=with_public,
all_plugins=all_plugins,
fields=fields)

View File

@ -415,8 +415,8 @@ class CommunicationError(IotronicException):
message = _("Unable to communicate with the server.")
class HTTPForbidden(Forbidden):
pass
class HTTPForbidden(NotAuthorized):
message = _("Access was denied to the following resource: %(resource)s")
class Unauthorized(IotronicException):
@ -589,3 +589,7 @@ class InvalidPluginAction(Invalid):
class NeedParams(Invalid):
message = _("Action %(action)s needs parameters.")
class ErrorExecutionOnBoard(IotronicException):
message = _("Error in the execution of %(call)s on %(board)s: %(error)s")

View File

@ -101,10 +101,22 @@ plugin_policies = [
description='Delete Plugin records'),
policy.RuleDefault('iot:plugin:update', 'rule:admin_or_owner',
description='Update Plugin records'),
policy.RuleDefault('iot:plugin:inject',
'rule:is_admin or rule:is_admin_iot_project '
'or rule:is_manager_iot_project',
description='Inject Plugin records'),
]
injection_plugin_policies = [
policy.RuleDefault('iot:plugin_on_board:get',
'rule:admin_or_owner',
description='Retrieve Plugin records'),
policy.RuleDefault('iot:plugin_remove:delete', 'rule:admin_or_owner',
description='Delete Plugin records'),
policy.RuleDefault('iot:plugin_action:post',
'rule:admin_or_owner',
description='Create Plugin records'),
policy.RuleDefault('iot:plugin_inject:put', 'rule:admin_or_owner',
description='Retrieve a Plugin record'),
]
@ -113,6 +125,7 @@ def list_policies():
policies = (default_policies
+ board_policies
+ plugin_policies
+ injection_plugin_policies
)
return policies

View File

@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
# from oslo_log import log as logging
# LOG = logging.getLogger(__name__)

View File

@ -51,36 +51,6 @@ class ConductorEndpoint(object):
LOG.info("ECHO: %s" % data)
return data
def connection(self, ctx, uuid, session_num):
LOG.debug('Received registration from %s with session %s',
uuid, session_num)
try:
board = objects.Board.get_by_uuid(ctx, uuid)
except Exception as exc:
msg = exc.message % {'board': uuid}
LOG.error(msg)
return wm.WampError(msg).serialize()
try:
old_ses = objects.SessionWP(ctx)
old_ses = old_ses.get_session_by_board_uuid(ctx, board.uuid,
valid=True)
old_ses.valid = False
old_ses.save()
except Exception:
LOG.debug('valid session for %s not found', board.uuid)
session_data = {'board_id': board.id,
'board_uuid': board.uuid,
'session_id': session_num}
session = objects.SessionWP(ctx, **session_data)
session.create()
board.status = states.ONLINE
board.save()
LOG.debug('Board %s is now %s', board.uuid, states.ONLINE)
return wm.WampSuccess('').serialize()
def registration(self, ctx, code, session_num):
LOG.debug('Received registration from %s with session %s',
code, session_num)
@ -92,6 +62,12 @@ class ConductorEndpoint(object):
LOG.error(msg)
return wm.WampError(msg).serialize()
if not board.status == states.REGISTERED:
msg = "board with code %(board)s cannot " \
"be registered again." % {'board': code}
LOG.error(msg)
return wm.WampError(msg).serialize()
try:
old_ses = objects.SessionWP(ctx)
old_ses = old_ses.get_session_by_board_uuid(ctx, board.uuid,
@ -131,17 +107,19 @@ class ConductorEndpoint(object):
LOG.info('Destroying board with id %s',
board_id)
board = objects.Board.get_by_uuid(ctx, board_id)
prov = Provisioner()
prov.conf_clean()
p = prov.get_config()
LOG.debug('sending this conf %s', p)
try:
result = self.execute_on_board(ctx, board_id, 'destroyBoard', (p,))
except Exception:
LOG.error('cannot execute remote destroyboard on %s. '
'Maybe it is OFFLINE', board_id)
result = None
if board.is_online():
prov = Provisioner()
prov.conf_clean()
p = prov.get_config()
LOG.debug('sending this conf %s', p)
try:
result = self.execute_on_board(ctx,
board_id,
'destroyBoard',
(p,))
except exception:
return exception
board.destroy()
if result:
LOG.debug(result)
@ -187,8 +165,16 @@ class ConductorEndpoint(object):
if res.result == wm.SUCCESS:
return res.message
elif res.result == wm.WARNING:
LOG.warning('Warning in the execution of %s on %s', wamp_rpc_call,
board_uuid)
return res.message
elif res.result == wm.ERROR:
raise Exception
LOG.error('Error in the execution of %s on %s: %s', wamp_rpc_call,
board_uuid, res.message)
raise exception.ErrorExecutionOnBoard(call=wamp_rpc_call,
board=board.uuid,
error=res.message)
def destroy_plugin(self, ctx, plugin_id):
LOG.info('Destroying plugin with id %s',
@ -216,11 +202,13 @@ class ConductorEndpoint(object):
plugin_uuid, board_uuid)
plugin = objects.Plugin.get(ctx, plugin_uuid)
result = self.execute_on_board(ctx,
board_uuid,
'PluginInject',
(plugin, onboot))
try:
result = self.execute_on_board(ctx,
board_uuid,
'PluginInject',
(plugin, onboot))
except exception:
return exception
injection = None
try:
@ -256,17 +244,16 @@ class ConductorEndpoint(object):
try:
result = self.execute_on_board(ctx, board_uuid, 'PluginRemove',
(plugin.uuid,))
except Exception:
LOG.error('cannot execute a plugin remove on %s. ', Exception)
return Exception
except exception:
return exception
LOG.debug(result)
injection.destroy()
return result
def action_plugin(self, ctx, plugin_uuid, board_uuid, action, params):
LOG.info('Calling plugin with id %s into the board %s',
plugin_uuid, board_uuid)
LOG.info('Calling plugin with id %s into the board %s with params %s',
plugin_uuid, board_uuid, params)
plugin = objects.Plugin.get(ctx, plugin_uuid)
objects.plugin.is_valid_action(action)
@ -277,9 +264,8 @@ class ConductorEndpoint(object):
else:
result = self.execute_on_board(ctx, board_uuid, action,
(plugin.uuid,))
except Exception:
LOG.error('cannot execute a plugin remove on %s. ', Exception)
return Exception
except exception:
return exception
LOG.debug(result)
return result

View File

@ -196,7 +196,7 @@ class ConductorAPI(object):
board_uuid=board_uuid)
def action_plugin(self, context, plugin_uuid,
board_uuid, action, params=None, topic=None):
board_uuid, action, params, topic=None):
"""Action on a plugin into a board.
:param context: request context.

View File

@ -267,6 +267,10 @@ class Connection(object):
:returns: A list of locations.
"""
@abc.abstractmethod
def get_valid_wpsessions_list(self):
"""Return a list of wpsession."""
@abc.abstractmethod
def get_wampagent(self, hostname):
"""Retrieve a wampagent's service record from the database.

View File

@ -448,6 +448,10 @@ class Connection(api.Connection):
except NoResultFound:
return None
def get_valid_wpsessions_list(self):
query = model_query(models.SessionWP).filter_by(valid=1)
return query.all()
# WAMPAGENT api
def register_wampagent(self, values, update_existing=False):

View File

@ -207,6 +207,7 @@ class Plugin(Base):
public = Column(Boolean, default=False)
code = Column(TEXT)
callable = Column(Boolean)
parameters = Column(JSONEncodedDict)
extra = Column(JSONEncodedDict)

View File

@ -23,6 +23,7 @@ from iotronic.objects import utils as obj_utils
ACTIONS = ['PluginCall', 'PluginStop', 'PluginStart',
'PluginStatus', 'PluginReboot']
CUSTOM_PARAMS = ['PluginCall', 'PluginStart']
NO_PARAMS = ['PluginStatus', 'PluginReboot']
@ -32,6 +33,10 @@ def is_valid_action(action):
return True
def want_customs_params(action):
return True if action in CUSTOM_PARAMS else False
def want_params(action):
return False if action in NO_PARAMS else True
@ -50,6 +55,7 @@ class Plugin(base.IotronicObject):
'public': bool,
'code': obj_utils.str_or_none,
'callable': bool,
'parameters': obj_utils.dict_or_none,
'extra': obj_utils.dict_or_none,
}

View File

@ -43,14 +43,6 @@ class SessionWP(base.IotronicObject):
session.obj_reset_changes()
return session
@staticmethod
def _from_db_object_list(db_objects, cls, context):
"""Converts a list of database entities to a list of formal objects."""
return [
SessionWP._from_db_object(
cls(context),
obj) for obj in db_objects]
@base.remotable_classmethod
def get(cls, context, session_or_board_uuid):
"""Find a session based on its id or uuid and return a SessionWP object.
@ -90,24 +82,15 @@ class SessionWP(base.IotronicObject):
return session
@base.remotable_classmethod
def list(cls, context, limit=None, marker=None,
sort_key=None, sort_dir=None):
def valid_list(cls, context):
"""Return a list of SessionWP objects.
:param context: Security context.
:param limit: maximum number of resources to return in a single result.
:param marker: pagination marker for large data sets.
:param sort_key: column to sort results by.
:param sort_dir: direction to sort. "asc" or "desc".
:returns: a list of :class:`SessionWP` object.
:returns: a list of valid session_id
"""
db_sessions = cls.dbapi.get_session_list(limit=limit,
marker=marker,
sort_key=sort_key,
sort_dir=sort_dir)
return SessionWP._from_db_object_list(db_sessions, cls, context)
db_list = cls.dbapi.get_valid_wpsessions_list()
return [SessionWP._from_db_object(cls(context), x) for x in db_list]
@base.remotable
def create(self, context=None):
@ -178,4 +161,4 @@ class SessionWP(base.IotronicObject):
if (hasattr(
self, base.get_attrname(field))
and self[field] != current[field]):
self[field] = current[field]
self[field] = current[field]

View File

@ -16,6 +16,8 @@
from autobahn.twisted import wamp
from autobahn.twisted import websocket
from autobahn.wamp import types
from twisted.internet.defer import inlineCallbacks
from iotronic.common import exception
from iotronic.common.i18n import _LI
from iotronic.common.i18n import _LW
@ -43,6 +45,13 @@ wamp_opts = [
cfg.BoolOpt('register_agent',
default=False,
help=('Flag for se a registration agent')),
cfg.IntOpt('autoPingInterval',
default=2,
help=('autoPingInterval parameter for wamp')),
cfg.IntOpt('autoPingTimeout',
default=2,
help=('autoPingInterval parameter for wamp')),
]
CONF = cfg.CONF
@ -100,6 +109,7 @@ class WampEndpoint(object):
class WampFrontend(wamp.ApplicationSession):
@inlineCallbacks
def onJoin(self, details):
global wamp_session_caller, AGENT_HOST
wamp_session_caller = self
@ -108,7 +118,6 @@ class WampFrontend(wamp.ApplicationSession):
self.subscribe(fun.board_on_leave, 'wamp.session.on_leave')
self.subscribe(fun.board_on_join, 'wamp.session.on_join')
# self.subscribe(fun.on_board_connect, 'board.connection')
try:
if CONF.wamp.register_agent:
@ -124,6 +133,10 @@ class WampFrontend(wamp.ApplicationSession):
LOG.info("WAMP session ready.")
session_l = yield self.call(u'wamp.session.list')
session_l.remove(details.session)
fun.update_sessions(session_l)
def onDisconnect(self):
LOG.info("disconnected")
@ -184,6 +197,9 @@ class WampManager(object):
transport_factory = WampClientFactory(session_factory,
url=CONF.wamp.wamp_transport_url)
transport_factory.autoPingInterval = CONF.wamp.autoPingInterval
transport_factory.autoPingTimeout = CONF.wamp.autoPingTimeout
LOG.debug("wamp url: %s wamp realm: %s",
CONF.wamp.wamp_transport_url, CONF.wamp.wamp_realm)
websocket.connectWS(transport_factory)

View File

@ -17,6 +17,7 @@ from iotronic.common import rpc
from iotronic.common import states
from iotronic.conductor import rpcapi
from iotronic import objects
from iotronic.wamp import wampmessage as wm
from oslo_config import cfg
from oslo_log import log
@ -44,6 +45,34 @@ def echo(data):
return data
def update_sessions(session_list):
session_list = set(session_list)
list_from_db = objects.SessionWP.valid_list(ctxt)
list_db = set([int(elem.session_id) for elem in list_from_db])
if session_list == list_db:
LOG.debug('Sessions on the database are updated.')
return
old_connected = list_db.difference(session_list)
for elem in old_connected:
old_session = objects.SessionWP.get(ctxt, elem)
old_session.valid = False
old_session.save()
LOG.debug('%s has been put offline.', old_session.board_uuid)
if old_connected:
LOG.warning('Some boards have been updated: status offline')
keep_connected = list_db.intersection(session_list)
for elem in keep_connected:
for x in list_from_db:
if x.session_id == str(elem):
LOG.debug('%s need to be restored.', x.board_uuid)
break
if keep_connected:
LOG.warning('Some boards need to be restored.')
def board_on_leave(session_id):
LOG.debug('A board with %s disconnectd', session_id)
@ -61,24 +90,36 @@ def board_on_leave(session_id):
LOG.debug('Board %s is now %s', old_session.uuid, states.OFFLINE)
def on_board_connect(board_uuid, session_id, msg):
if msg == 'connection':
try:
board = objects.Board.get_by_uuid(ctxt, board_uuid)
board.status = states.ONLINE
session_data = {'board_id': board.id,
'board_uuid': board.uuid,
'session_id': session_id}
session = objects.SessionWP(ctxt, **session_data)
session.create()
board.save()
LOG.debug('Board %s is now %s', board_uuid, states.ONLINE)
except Exception:
LOG.debug(Exception.message)
def connection(uuid, session):
return c.connection(ctxt, uuid, session)
LOG.debug('Received registration from %s with session %s',
uuid, session)
try:
board = objects.Board.get_by_uuid(ctxt, uuid)
except Exception as exc:
msg = exc.message % {'board': uuid}
LOG.error(msg)
return wm.WampError(msg).serialize()
try:
old_ses = objects.SessionWP(ctxt)
old_ses = old_ses.get_session_by_board_uuid(ctxt, board.uuid,
valid=True)
old_ses.valid = False
old_ses.save()
except Exception:
LOG.debug('valid session for %s not found', board.uuid)
session_data = {'board_id': board.id,
'board_uuid': board.uuid,
'session_id': session}
session = objects.SessionWP(ctxt, **session_data)
session.create()
board.status = states.ONLINE
board.save()
LOG.info('Board %s (%s) is now %s', board.uuid,
board.name, states.ONLINE)
return wm.WampSuccess('').serialize()
def registration(code, session):

View File

@ -147,6 +147,7 @@ CREATE TABLE IF NOT EXISTS `iotronic`.`plugins` (
`public` TINYINT(1) NOT NULL DEFAULT '0',
`code` TEXT NULL DEFAULT NULL,
`callable` TINYINT(1) NOT NULL,
`parameters` TEXT NULL DEFAULT NULL,
`extra` TEXT NULL DEFAULT NULL,
`owner` VARCHAR(36) NOT NULL,
PRIMARY KEY (`id`),
@ -193,17 +194,20 @@ SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
-- insert testing boards
INSERT INTO `boards` VALUES
('2017-02-20 10:38:26',NULL,132,'f3961f7a-c937-4359-8848-fb64aa8eeaaa','12345','registered','laptop-14','server',NULL,'eee383360cc14c44b9bf21e1e003a4f3','4adfe95d49ad41398e00ecda80257d21',0,'{}','{}'),
('2017-02-20 10:38:45',NULL,133,'e9bee8d9-7270-5323-d3e9-9875ba9c5753','yunyun','registered','yun22','yun',NULL,'eee383360cc14c44b9bf21e1e003a4f3','4adfe95d49ad41398e00ecda80257d21',0,'{}','{}'),
('2017-02-20 10:39:08',NULL,134,'65f9db36-9786-4803-b66f-51dcdb60066e','test','registered','test','server',NULL,'eee383360cc14c44b9bf21e1e003a4f3','4adfe95d49ad41398e00ecda80257d21',0,'{}','{}');
('2017-02-20 10:38:26',NULL,'','f3961f7a-c937-4359-8848-fb64aa8eeaaa','12345','registered','laptop-14','server',NULL,'eee383360cc14c44b9bf21e1e003a4f3','4adfe95d49ad41398e00ecda80257d21',0,'{}','{}'),
('2017-02-20 10:38:45',NULL,'','e9bee8d9-7270-5323-d3e9-9875ba9c5753','yunyun','registered','yun-22','yun',NULL,'13ae14174aa1424688a75253ef814261','3c1e2e2c4bac40da9b4b1d694da6e2a1',0,'{}','{}'),
('2017-02-20 10:38:45',NULL,'','96b69f1f-0188-48cc-abdc-d10674144c68','567','registered','yun-30','yun',NULL,'13ae14174aa1424688a75253ef814261','3c1e2e2c4bac40da9b4b1d694da6e2a1',0,'{}','{}'),
('2017-02-20 10:39:08',NULL,'','65f9db36-9786-4803-b66f-51dcdb60066e','test','registered','test','server',NULL,'eee383360cc14c44b9bf21e1e003a4f3','4adfe95d49ad41398e00ecda80257d21',0,'{}','{}');
INSERT INTO `locations` VALUES
('2017-02-20 10:38:26',NULL,6,'2','1','3',132),
('2017-02-20 10:38:45',NULL,7,'2','1','3',133),
('2017-02-20 10:39:08',NULL,8,'2','1','3',134);
INSERT INTO `plugins` VALUES
('2017-02-20 10:38:26',NULL,132,'edff22cd-9148-4ad8-b35b-51dcdb60066e','runner','0','V# Copyright 2017 MDSLAB - University of Messina\u000a# All Rights Reserved.\u000a#\u000a# Licensed under the Apache License, Version 2.0 (the "License"); you may\u000a# not use this file except in compliance with the License. You may obtain\u000a# a copy of the License at\u000a#\u000a# http://www.apache.org/licenses/LICENSE-2.0\u000a#\u000a# Unless required by applicable law or agreed to in writing, software\u000a# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\u000a# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\u000a# License for the specific language governing permissions and limitations\u000a# under the License.\u000a\u000afrom iotronic_lightningrod.plugins import Plugin\u000a\u000afrom oslo_log import log as logging\u000aLOG = logging.getLogger(__name__)\u000a\u000a# User imports\u000aimport time\u000a\u000a\u000a\u000aclass Worker(Plugin.Plugin):\u000a def __init__(self, name, th_result, plugin_conf=None):\u000a super(Worker, self).__init__(name, th_result, plugin_conf)\u000a\u000a def run(self):\u000a LOG.info("Plugin " + self.name + " starting...")\u000a while(self._is_running):\u000a print(self.plugin_conf[''message''])\u000a time.sleep(1) \u000a
p1
.',0,'{}','eee383360cc14c44b9bf21e1e003a4f3')
('2017-02-20 10:38:26',NULL,133,'edff22cd-9148-4ad8-b35b-c0c80abf1e8a','zero','0','Vfrom iotronic_lightningrod.plugins import Plugin\u000a\u000afrom oslo_log import log as logging\u000a\u000aLOG = logging.getLogger(__name__)\u000a\u000a\u000a# User imports\u000a\u000a\u000aclass Worker(Plugin.Plugin):\u000a def __init__(self, name, is_running):\u000a super(Worker, self).__init__(name, is_running)\u000a\u000a def run(self):\u000a LOG.info("Plugin process completed!")\u000a #self.Done()
p1
.',1,'{}','eee383360cc14c44b9bf21e1e003a4f3');
('2017-02-20 10:38:26',NULL,'','2','1','3',132),
('2017-02-20 10:38:45',NULL,'','15.5966863','38.2597708','70',133),
('2017-02-20 10:38:45',NULL,'','15.5948288','38.259486','18',134),
('2017-02-20 10:39:08',NULL,'','2','1','3',135);
# INSERT INTO `plugins` VALUES
# ('2017-02-20 10:38:26',NULL,132,'edff22cd-9148-4ad8-b35b-51dcdb60066e','runner','0','V# Copyright 2017 MDSLAB - University of Messina\u000a# All Rights Reserved.\u000a#\u000a# Licensed under the Apache License, Version 2.0 (the "License"); you may\u000a# not use this file except in compliance with the License. You may obtain\u000a# a copy of the License at\u000a#\u000a# http://www.apache.org/licenses/LICENSE-2.0\u000a#\u000a# Unless required by applicable law or agreed to in writing, software\u000a# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\u000a# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\u000a# License for the specific language governing permissions and limitations\u000a# under the License.\u000a\u000afrom iotronic_lightningrod.plugins import Plugin\u000a\u000afrom oslo_log import log as logging\u000aLOG = logging.getLogger(__name__)\u000a\u000a# User imports\u000aimport time\u000a\u000a\u000a\u000aclass Worker(Plugin.Plugin):\u000a def __init__(self, name, th_result, plugin_conf=None):\u000a super(Worker, self).__init__(name, th_result, plugin_conf)\u000a\u000a def run(self):\u000a LOG.info("Plugin " + self.name + " starting...")\u000a while(self._is_running):\u000a print(self.plugin_conf[''message''])\u000a time.sleep(1) \u000a
# p1
# .',0,'{}','eee383360cc14c44b9bf21e1e003a4f3')
# ('2017-02-20 10:38:26',NULL,133,'edff22cd-9148-4ad8-b35b-c0c80abf1e8a','zero','0','Vfrom iotronic_lightningrod.plugins import Plugin\u000a\u000afrom oslo_log import log as logging\u000a\u000aLOG = logging.getLogger(__name__)\u000a\u000a\u000a# User imports\u000a\u000a\u000aclass Worker(Plugin.Plugin):\u000a def __init__(self, name, is_running):\u000a super(Worker, self).__init__(name, is_running)\u000a\u000a def run(self):\u000a LOG.info("Plugin process completed!")\u000a #self.Done()
# p1
# .',1,'{}','eee383360cc14c44b9bf21e1e003a4f3');