general fixes and checks
Change-Id: I72de75a264ebd92bca35c52746cb2987d8f94902
This commit is contained in:
parent
063e62ee3d
commit
0b57956164
3
.gitignore
vendored
3
.gitignore
vendored
@ -3,3 +3,6 @@
|
||||
iotronic.egg-info
|
||||
build
|
||||
*.pyc
|
||||
AUTHORS
|
||||
Authors
|
||||
ChangeLog
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
||||
|
@ -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__)
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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):
|
||||
|
@ -207,6 +207,7 @@ class Plugin(Base):
|
||||
public = Column(Boolean, default=False)
|
||||
code = Column(TEXT)
|
||||
callable = Column(Boolean)
|
||||
parameters = Column(JSONEncodedDict)
|
||||
extra = Column(JSONEncodedDict)
|
||||
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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');
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user