Exposed Cloud Service
Iotronic exposes the services of the boards Change-Id: Id88c4e6a9d5752d1bffbcfd99827eca0b9b679f7
This commit is contained in:
parent
6e9e02e9c3
commit
f450f91c70
|
@ -152,11 +152,50 @@ class InjectionCollection(collection.Collection):
|
|||
return collection
|
||||
|
||||
|
||||
class ExposedService(base.APIBase):
|
||||
service = types.uuid_or_name
|
||||
board_uuid = types.uuid_or_name
|
||||
public_port = wsme.types.IntegerType()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.fields = []
|
||||
fields = list(objects.ExposedService.fields)
|
||||
fields.remove('board_uuid')
|
||||
for k in fields:
|
||||
# Skip fields we do not expose.
|
||||
if not hasattr(self, k):
|
||||
continue
|
||||
self.fields.append(k)
|
||||
setattr(self, k, kwargs.get(k, wtypes.Unset))
|
||||
setattr(self, 'service', kwargs.get('service_uuid', wtypes.Unset))
|
||||
|
||||
|
||||
class ExposedCollection(collection.Collection):
|
||||
"""API representation of a collection of injection."""
|
||||
|
||||
exposed = [ExposedService]
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self._type = 'exposed'
|
||||
|
||||
@staticmethod
|
||||
def get_list(exposed, fields=None):
|
||||
collection = ExposedCollection()
|
||||
collection.exposed = [ExposedService(**n.as_dict())
|
||||
for n in exposed]
|
||||
return collection
|
||||
|
||||
|
||||
class PluginAction(base.APIBase):
|
||||
action = wsme.wsattr(wtypes.text)
|
||||
parameters = types.jsontype
|
||||
|
||||
|
||||
class ServiceAction(base.APIBase):
|
||||
action = wsme.wsattr(wtypes.text)
|
||||
parameters = types.jsontype
|
||||
|
||||
|
||||
class BoardPluginsController(rest.RestController):
|
||||
def __init__(self, board_ident):
|
||||
self.board_ident = board_ident
|
||||
|
@ -282,11 +321,72 @@ class BoardPluginsController(rest.RestController):
|
|||
rpc_board.uuid)
|
||||
|
||||
|
||||
class BoardServicesController(rest.RestController):
|
||||
_custom_actions = {
|
||||
'action': ['POST'],
|
||||
}
|
||||
|
||||
def __init__(self, board_ident):
|
||||
self.board_ident = board_ident
|
||||
|
||||
def _get_services_on_board_collection(self, board_uuid, fields=None):
|
||||
services = objects.ExposedService.list(pecan.request.context,
|
||||
board_uuid)
|
||||
|
||||
return ExposedCollection.get_list(services,
|
||||
fields=fields)
|
||||
|
||||
@expose.expose(ExposedCollection,
|
||||
status_code=200)
|
||||
def get_all(self):
|
||||
"""Retrieve a list of services of a board.
|
||||
|
||||
"""
|
||||
rpc_board = api_utils.get_rpc_board(self.board_ident)
|
||||
|
||||
cdict = pecan.request.context.to_policy_values()
|
||||
cdict['project_id'] = rpc_board.project
|
||||
policy.authorize('iot:service_on_board:get', cdict, cdict)
|
||||
|
||||
return self._get_services_on_board_collection(rpc_board.uuid)
|
||||
|
||||
@expose.expose(wtypes.text, types.uuid_or_name, body=ServiceAction,
|
||||
status_code=200)
|
||||
def action(self, service_ident, ServiceAction):
|
||||
|
||||
if not ServiceAction.action:
|
||||
raise exception.MissingParameterValue(
|
||||
("Action is not specified."))
|
||||
|
||||
if not ServiceAction.parameters:
|
||||
ServiceAction.parameters = {}
|
||||
|
||||
rpc_board = api_utils.get_rpc_board(self.board_ident)
|
||||
rpc_service = api_utils.get_rpc_service(service_ident)
|
||||
|
||||
try:
|
||||
cdict = pecan.request.context.to_policy_values()
|
||||
cdict['owner'] = rpc_board.owner
|
||||
policy.authorize('iot:service_action:post', cdict, cdict)
|
||||
|
||||
except exception:
|
||||
return exception
|
||||
|
||||
rpc_board.check_if_online()
|
||||
|
||||
result = pecan.request.rpcapi.action_service(pecan.request.context,
|
||||
rpc_service.uuid,
|
||||
rpc_board.uuid,
|
||||
ServiceAction.action)
|
||||
return result
|
||||
|
||||
|
||||
class BoardsController(rest.RestController):
|
||||
"""REST controller for Boards."""
|
||||
|
||||
_subcontroller_map = {
|
||||
'plugins': BoardPluginsController,
|
||||
'services': BoardServicesController,
|
||||
}
|
||||
|
||||
invalid_sort_key_list = ['extra', 'location']
|
||||
|
|
|
@ -597,3 +597,15 @@ class ErrorExecutionOnBoard(IotronicException):
|
|||
|
||||
class ServiceNotFound(NotFound):
|
||||
message = _("Service %(Service)s could not be found.")
|
||||
|
||||
|
||||
class ServiceAlreadyExists(Conflict):
|
||||
message = _("A Service with UUID %(uuid)s already exists.")
|
||||
|
||||
|
||||
class ServiceAlreadyExposed(Conflict):
|
||||
message = _("A Service with UUID %(uuid)s already exposed.")
|
||||
|
||||
|
||||
class ExposedServiceNotFound(NotFound):
|
||||
message = _("ExposedService %(uuid)s could not be found.")
|
||||
|
|
|
@ -136,6 +136,20 @@ service_policies = [
|
|||
|
||||
]
|
||||
|
||||
exposed_service_policies = [
|
||||
policy.RuleDefault('iot:service_on_board:get',
|
||||
'rule:admin_or_owner',
|
||||
description='Retrieve Service records'),
|
||||
policy.RuleDefault('iot:service_remove:delete', 'rule:admin_or_owner',
|
||||
description='Delete Service records'),
|
||||
policy.RuleDefault('iot:service_action:post',
|
||||
'rule:admin_or_owner',
|
||||
description='Create Service records'),
|
||||
policy.RuleDefault('iot:service_inject:put', 'rule:admin_or_owner',
|
||||
description='Retrieve a Service record'),
|
||||
|
||||
]
|
||||
|
||||
|
||||
def list_policies():
|
||||
policies = (default_policies
|
||||
|
@ -143,6 +157,7 @@ def list_policies():
|
|||
+ plugin_policies
|
||||
+ injection_plugin_policies
|
||||
+ service_policies
|
||||
+ exposed_service_policies
|
||||
)
|
||||
return policies
|
||||
|
||||
|
|
|
@ -39,6 +39,26 @@ def get_best_agent(ctx):
|
|||
return agent.hostname
|
||||
|
||||
|
||||
def random_public_port():
|
||||
return random.randint(6000, 7000)
|
||||
|
||||
|
||||
def manage_result(res, wamp_rpc_call, board_uuid):
|
||||
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:
|
||||
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)
|
||||
return res.message
|
||||
|
||||
|
||||
class ConductorEndpoint(object):
|
||||
def __init__(self, ragent):
|
||||
transport = oslo_messaging.get_transport(cfg.CONF)
|
||||
|
@ -119,10 +139,12 @@ class ConductorEndpoint(object):
|
|||
board_id,
|
||||
'destroyBoard',
|
||||
(p,))
|
||||
|
||||
except exception:
|
||||
return exception
|
||||
board.destroy()
|
||||
if result:
|
||||
result = manage_result(result, 'destroyBoard', board_id)
|
||||
LOG.debug(result)
|
||||
return result
|
||||
return
|
||||
|
@ -164,18 +186,7 @@ class ConductorEndpoint(object):
|
|||
data=wamp_rpc_args)
|
||||
res = wm.deserialize(res)
|
||||
|
||||
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:
|
||||
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)
|
||||
return res
|
||||
|
||||
def destroy_plugin(self, ctx, plugin_id):
|
||||
LOG.info('Destroying plugin with id %s',
|
||||
|
@ -231,7 +242,9 @@ class ConductorEndpoint(object):
|
|||
injection = objects.InjectionPlugin(ctx, **inj_data)
|
||||
injection.create()
|
||||
|
||||
result = manage_result(result, 'PluginInject', board_uuid)
|
||||
LOG.debug(result)
|
||||
|
||||
return result
|
||||
|
||||
def remove_plugin(self, ctx, plugin_uuid, board_uuid):
|
||||
|
@ -247,7 +260,7 @@ class ConductorEndpoint(object):
|
|||
(plugin.uuid,))
|
||||
except exception:
|
||||
return exception
|
||||
|
||||
result = manage_result(result, 'PluginRemove', board_uuid)
|
||||
LOG.debug(result)
|
||||
injection.destroy()
|
||||
return result
|
||||
|
@ -267,7 +280,7 @@ class ConductorEndpoint(object):
|
|||
(plugin.uuid,))
|
||||
except exception:
|
||||
return exception
|
||||
|
||||
result = manage_result(result, action, board_uuid)
|
||||
LOG.debug(result)
|
||||
return result
|
||||
|
||||
|
@ -290,3 +303,151 @@ class ConductorEndpoint(object):
|
|||
LOG.debug('Updating service %s', service.name)
|
||||
service.save()
|
||||
return serializer.serialize_entity(ctx, service)
|
||||
|
||||
def action_service(self, ctx, service_uuid, board_uuid, action):
|
||||
LOG.info('Enable service with id %s into the board %s',
|
||||
service_uuid, board_uuid)
|
||||
service = objects.Service.get(ctx, service_uuid)
|
||||
objects.service.is_valid_action(action)
|
||||
|
||||
if action == "ServiceEnable":
|
||||
try:
|
||||
objects.ExposedService.get(ctx,
|
||||
board_uuid,
|
||||
service_uuid)
|
||||
return exception.ServiceAlreadyExposed(uuid=service_uuid)
|
||||
except Exception:
|
||||
name = service.name
|
||||
public_port = random_public_port()
|
||||
port = service.port
|
||||
|
||||
res = self.execute_on_board(ctx, board_uuid, action,
|
||||
(name, public_port, port))
|
||||
|
||||
if res.result == wm.SUCCESS:
|
||||
pid = res.message[0]
|
||||
|
||||
exp_data = {
|
||||
'board_uuid': board_uuid,
|
||||
'service_uuid': service_uuid,
|
||||
'public_port': public_port,
|
||||
'pid': pid,
|
||||
}
|
||||
exposed = objects.ExposedService(ctx, **exp_data)
|
||||
exposed.create()
|
||||
|
||||
res.message = res.message[1]
|
||||
elif res.result == wm.ERROR:
|
||||
LOG.error('Error in the execution of %s on %s: %s',
|
||||
action,
|
||||
board_uuid, res.message)
|
||||
raise exception.ErrorExecutionOnBoard(call=action,
|
||||
board=board_uuid,
|
||||
error=res.message)
|
||||
LOG.debug(res.message)
|
||||
return res.message
|
||||
|
||||
elif action == "ServiceDisable":
|
||||
exposed = objects.ExposedService.get(ctx,
|
||||
board_uuid,
|
||||
service_uuid)
|
||||
|
||||
res = self.execute_on_board(ctx, board_uuid, action,
|
||||
(service.name, exposed.pid))
|
||||
|
||||
result = manage_result(res, action, board_uuid)
|
||||
LOG.debug(res.message)
|
||||
exposed.destroy()
|
||||
return result
|
||||
|
||||
elif action == "ServiceRestore":
|
||||
|
||||
exposed = objects.ExposedService.get(ctx, board_uuid,
|
||||
service_uuid)
|
||||
|
||||
print(exposed)
|
||||
|
||||
res = self.execute_on_board(ctx, board_uuid, action,
|
||||
(service.name, exposed.public_port,
|
||||
service.port, exposed.pid))
|
||||
|
||||
if res.result == wm.SUCCESS:
|
||||
pid = res.message[0]
|
||||
|
||||
exp_data = {
|
||||
'id': exposed.id,
|
||||
'board_uuid': board_uuid,
|
||||
'service_uuid': service_uuid,
|
||||
'public_port': exposed.public_port,
|
||||
'pid': pid,
|
||||
}
|
||||
|
||||
exposed = objects.ExposedService(ctx, **exp_data)
|
||||
exposed.save()
|
||||
|
||||
res.message = res.message[1]
|
||||
elif res.result == wm.ERROR:
|
||||
LOG.error('Error in the execution of %s on %s: %s',
|
||||
action,
|
||||
board_uuid, res.message)
|
||||
raise exception.ErrorExecutionOnBoard(call=action,
|
||||
board=board_uuid,
|
||||
error=res.message)
|
||||
LOG.debug(res.message)
|
||||
return res.message
|
||||
|
||||
# try:
|
||||
#
|
||||
#
|
||||
# return exception.ServiceAlreadyExposed(uuid=service_uuid)
|
||||
# except:
|
||||
# name=service.name
|
||||
# public_port=random_public_port()
|
||||
# port=service.port
|
||||
#
|
||||
# res = self.execute_on_board(ctx, board_uuid, action,
|
||||
# (name, public_port, port))
|
||||
#
|
||||
# if res.result == wm.SUCCESS:
|
||||
# pid = res.message[0]
|
||||
#
|
||||
# exp_data = {
|
||||
# 'board_uuid': board_uuid,
|
||||
# 'service_uuid': service_uuid,
|
||||
# 'public_port': public_port,
|
||||
# 'pid': pid,
|
||||
# }
|
||||
# exposed = objects.ExposedService(ctx, **exp_data)
|
||||
# exposed.create()
|
||||
#
|
||||
# res.message = res.message[1]
|
||||
# elif res.result == wm.ERROR:
|
||||
# LOG.error('Error in the execution of %s on %s: %s',
|
||||
# action,
|
||||
# board_uuid, res.message)
|
||||
# raise exception.ErrorExecutionOnBoard(call=action,
|
||||
# board=board_uuid,
|
||||
# error=res.message)
|
||||
# LOG.debug(res.message)
|
||||
# return res.message
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# exposed = objects.ExposedService.get(ctx, board_uuid,
|
||||
# service_uuid)
|
||||
#
|
||||
# res = self.execute_on_board(ctx, board_uuid, action,
|
||||
# (service.name, exposed.pid))
|
||||
#
|
||||
# result=manage_result(res,action,board_uuid)
|
||||
# LOG.debug(res.message)
|
||||
# exposed.destroy()
|
||||
# return result
|
||||
|
|
|
@ -249,3 +249,17 @@ class ConductorAPI(object):
|
|||
"""
|
||||
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
||||
return cctxt.call(context, 'update_service', service_obj=service_obj)
|
||||
|
||||
def action_service(self, context, service_uuid,
|
||||
board_uuid, action, topic=None):
|
||||
"""Action on a service into a board.
|
||||
|
||||
:param context: request context.
|
||||
:param service_uuid: service id or uuid.
|
||||
:param board_uuid: board id or uuid.
|
||||
|
||||
"""
|
||||
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
|
||||
|
||||
return cctxt.call(context, 'action_service', service_uuid=service_uuid,
|
||||
board_uuid=board_uuid, action=action)
|
||||
|
|
|
@ -473,3 +473,57 @@ class Connection(object):
|
|||
:raises: ServiceAssociated
|
||||
:raises: ServiceNotFound
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_exposed_service_by_board_uuid(self, board_uuid):
|
||||
"""get an exposed of a service using a board_uuid
|
||||
|
||||
:param board_uuid: The id or uuid of a board.
|
||||
:returns: An exposed_service.
|
||||
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_exposed_service_by_uuids(self, board_uuid, service_uuid):
|
||||
"""get an exposed of a service using a board_uuid and service_uuid
|
||||
|
||||
:param board_uuid: The id or uuid of a board.
|
||||
:param service_uuid: The id or uuid of a service.
|
||||
:returns: An exposed_service.
|
||||
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_exposed_service(self, values):
|
||||
"""Create a new exposed_service.
|
||||
|
||||
:param values: A dict containing several items used to identify
|
||||
and track the service
|
||||
:returns: An exposed service.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def destroy_exposed_service(self, exposed_service_id):
|
||||
"""Destroy an exposed service and all associated interfaces.
|
||||
|
||||
:param exposed_service_id: The id or uuid of a service.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_exposed_service(self, service_exposed_id, values):
|
||||
"""Update properties of a service.
|
||||
|
||||
:param service_id: The id or uuid of a service.
|
||||
:param values: Dict of values to update.
|
||||
:returns: A service.
|
||||
:raises: ServiceAssociated
|
||||
:raises: ServiceNotFound
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_exposed_service_list(self, board_uuid):
|
||||
"""Return a list of exposed_services.
|
||||
|
||||
:param board_uuid: The id or uuid of a service.
|
||||
:returns: A list of ExposedServices on the board.
|
||||
"""
|
||||
|
|
|
@ -761,3 +761,84 @@ class Connection(api.Connection):
|
|||
|
||||
ref.update(values)
|
||||
return ref
|
||||
|
||||
# EXPOSED SERVICE api
|
||||
|
||||
def get_exposed_service_by_board_uuid(self, board_uuid):
|
||||
query = model_query(
|
||||
models.ExposedService).filter_by(
|
||||
board_uuid=board_uuid)
|
||||
try:
|
||||
return query.one()
|
||||
except NoResultFound:
|
||||
raise exception.ExposedServiceNotFound()
|
||||
|
||||
def create_exposed_service(self, values):
|
||||
# ensure defaults are present for new services
|
||||
if 'uuid' not in values:
|
||||
values['uuid'] = uuidutils.generate_uuid()
|
||||
exp_serv = models.ExposedService()
|
||||
exp_serv.update(values)
|
||||
try:
|
||||
exp_serv.save()
|
||||
except db_exc.DBDuplicateEntry:
|
||||
raise exception.ServiceAlreadyExposed(uuid=values['uuid'])
|
||||
return exp_serv
|
||||
|
||||
def update_exposed_service(self, service_exposed_id, values):
|
||||
|
||||
if 'uuid' in values:
|
||||
msg = _("Cannot overwrite UUID for an existing Service.")
|
||||
raise exception.InvalidParameterValue(err=msg)
|
||||
try:
|
||||
return self._do_update_exposed_service(
|
||||
service_exposed_id, values)
|
||||
|
||||
except db_exc.DBDuplicateEntry as e:
|
||||
if 'name' in e.columns:
|
||||
raise exception.DuplicateName(name=values['name'])
|
||||
elif 'uuid' in e.columns:
|
||||
raise exception.ServiceAlreadyExists(uuid=values['uuid'])
|
||||
else:
|
||||
raise e
|
||||
|
||||
def get_exposed_service_by_uuids(self, board_uuid, service_uuid):
|
||||
query = model_query(
|
||||
models.ExposedService).filter_by(
|
||||
board_uuid=board_uuid).filter_by(
|
||||
service_uuid=service_uuid)
|
||||
try:
|
||||
return query.one()
|
||||
except NoResultFound:
|
||||
raise exception.ExposedServiceNotFound(uuid=service_uuid)
|
||||
|
||||
def destroy_exposed_service(self, exposed_service_id):
|
||||
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
query = model_query(models.ExposedService, session=session)
|
||||
query = add_identity_filter(query, exposed_service_id)
|
||||
try:
|
||||
query.delete()
|
||||
|
||||
except NoResultFound:
|
||||
raise exception.ExposedServiceNotFound()
|
||||
|
||||
def get_exposed_service_list(self, board_uuid):
|
||||
query = model_query(
|
||||
models.ExposedService).filter_by(
|
||||
board_uuid=board_uuid)
|
||||
return query.all()
|
||||
|
||||
def _do_update_exposed_service(self, service_id, values):
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
query = model_query(models.ExposedService, session=session)
|
||||
query = add_identity_filter(query, service_id)
|
||||
try:
|
||||
ref = query.with_lockmode('update').one()
|
||||
except NoResultFound:
|
||||
raise exception.ServiceNotFoundNotFound(uuid=service_id)
|
||||
|
||||
ref.update(values)
|
||||
return ref
|
||||
|
|
|
@ -248,3 +248,4 @@ class ExposedService(Base):
|
|||
board_uuid = Column(String(36), ForeignKey('boards.uuid'))
|
||||
service_uuid = Column(String(36), ForeignKey('services.uuid'))
|
||||
public_port = Column(Integer)
|
||||
pid = Column(Integer)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
from iotronic.objects import board
|
||||
from iotronic.objects import conductor
|
||||
from iotronic.objects import exposedservice
|
||||
from iotronic.objects import injectionplugin
|
||||
from iotronic.objects import location
|
||||
from iotronic.objects import plugin
|
||||
|
@ -26,6 +27,7 @@ Board = board.Board
|
|||
Location = location.Location
|
||||
Plugin = plugin.Plugin
|
||||
InjectionPlugin = injectionplugin.InjectionPlugin
|
||||
ExposedService = exposedservice.ExposedService
|
||||
SessionWP = sessionwp.SessionWP
|
||||
WampAgent = wampagent.WampAgent
|
||||
Service = service.Service
|
||||
|
@ -39,4 +41,5 @@ __all__ = (
|
|||
Service,
|
||||
Plugin,
|
||||
InjectionPlugin,
|
||||
ExposedService
|
||||
)
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
# coding=utf-8
|
||||
#
|
||||
#
|
||||
# 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 iotronic.db import api as db_api
|
||||
from iotronic.objects import base
|
||||
from iotronic.objects import utils as obj_utils
|
||||
|
||||
|
||||
class ExposedService(base.IotronicObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
dbapi = db_api.get_instance()
|
||||
|
||||
fields = {
|
||||
'id': int,
|
||||
'board_uuid': obj_utils.str_or_none,
|
||||
'service_uuid': obj_utils.str_or_none,
|
||||
'public_port': int,
|
||||
'pid': int
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _from_db_object(exposed_service, db_exposed_service):
|
||||
"""Converts a database entity to a formal object."""
|
||||
for field in exposed_service.fields:
|
||||
exposed_service[field] = db_exposed_service[field]
|
||||
exposed_service.obj_reset_changes()
|
||||
return exposed_service
|
||||
|
||||
@base.remotable_classmethod
|
||||
def get_by_id(cls, context, exposed_service_id):
|
||||
"""Find a exposed_service based on its integer id and return a Board object.
|
||||
|
||||
:param exposed_service_id: the id of a exposed_service.
|
||||
:returns: a :class:`exposed_service` object.
|
||||
"""
|
||||
db_exp_service = cls.dbapi.get_exposed_service_by_id(
|
||||
exposed_service_id)
|
||||
exp_service = ExposedService._from_db_object(cls(context),
|
||||
db_exp_service)
|
||||
return exp_service
|
||||
|
||||
@base.remotable_classmethod
|
||||
def get_by_board_uuid(cls, context, board_uuid):
|
||||
"""Find a exposed_service based on uuid and return a Board object.
|
||||
|
||||
:param board_uuid: the uuid of a exposed_service.
|
||||
:returns: a :class:`exposed_service` object.
|
||||
"""
|
||||
db_exp_service = cls.dbapi.get_exposed_service_by_board_uuid(
|
||||
board_uuid)
|
||||
exp_service = ExposedService._from_db_object(cls(context),
|
||||
db_exp_service)
|
||||
return exp_service
|
||||
|
||||
@base.remotable_classmethod
|
||||
def get_by_service_uuid(cls, context, service_uuid):
|
||||
"""Find a exposed_service based on uuid and return a Board object.
|
||||
|
||||
:param service_uuid: the uuid of a exposed_service.
|
||||
:returns: a :class:`exposed_service` object.
|
||||
"""
|
||||
db_exp_service = cls.dbapi.get_exposed_service_by_service_uuid(
|
||||
service_uuid)
|
||||
exp_service = ExposedService._from_db_object(cls(context),
|
||||
db_exp_service)
|
||||
return exp_service
|
||||
|
||||
@base.remotable_classmethod
|
||||
def get(cls, context, board_uuid, service_uuid):
|
||||
"""Find a exposed_service based on uuid and return a Service object.
|
||||
|
||||
:param board_uuid: the uuid of a exposed_service.
|
||||
:returns: a :class:`exposed_service` object.
|
||||
"""
|
||||
db_exp_service = cls.dbapi.get_exposed_service_by_uuids(board_uuid,
|
||||
service_uuid)
|
||||
exp_service = ExposedService._from_db_object(cls(context),
|
||||
db_exp_service)
|
||||
return exp_service
|
||||
|
||||
@base.remotable_classmethod
|
||||
def list(cls, context, board_uuid):
|
||||
"""Return a list of ExposedService 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".
|
||||
:param filters: Filters to apply.
|
||||
:returns: a list of :class:`ExposedService` object.
|
||||
|
||||
"""
|
||||
db_exps = cls.dbapi.get_exposed_service_list(board_uuid)
|
||||
return [ExposedService._from_db_object(cls(context), obj)
|
||||
for obj in db_exps]
|
||||
|
||||
@base.remotable
|
||||
def create(self, context=None):
|
||||
"""Create a ExposedService record in the DB.
|
||||
|
||||
Column-wise updates will be made based on the result of
|
||||
self.what_changed(). If target_power_state is provided,
|
||||
it will be checked against the in-database copy of the
|
||||
exposed_service before updates are made.
|
||||
|
||||
:param context: Security context. NOTE: This should only
|
||||
be used internally by the indirection_api.
|
||||
Unfortunately, RPC requires context as the first
|
||||
argument, even though we don't use it.
|
||||
A context should be set when instantiating the
|
||||
object, e.g.: ExposedService(context)
|
||||
|
||||
"""
|
||||
values = self.obj_get_changes()
|
||||
db_exposed_service = self.dbapi.create_exposed_service(values)
|
||||
self._from_db_object(self, db_exposed_service)
|
||||
|
||||
@base.remotable
|
||||
def destroy(self, context=None):
|
||||
"""Delete the ExposedService from the DB.
|
||||
|
||||
:param context: Security context. NOTE: This should only
|
||||
be used internally by the indirection_api.
|
||||
Unfortunately, RPC requires context as the first
|
||||
argument, even though we don't use it.
|
||||
A context should be set when instantiating the
|
||||
object, e.g.: ExposedService(context)
|
||||
"""
|
||||
self.dbapi.destroy_exposed_service(self.id)
|
||||
self.obj_reset_changes()
|
||||
|
||||
@base.remotable
|
||||
def save(self, context=None):
|
||||
"""Save updates to this ExposedService.
|
||||
|
||||
Column-wise updates will be made based on the result of
|
||||
self.what_changed(). If target_power_state is provided,
|
||||
it will be checked against the in-database copy of the
|
||||
exposed_service before updates are made.
|
||||
|
||||
:param context: Security context. NOTE: This should only
|
||||
be used internally by the indirection_api.
|
||||
Unfortunately, RPC requires context as the first
|
||||
argument, even though we don't use it.
|
||||
A context should be set when instantiating the
|
||||
object, e.g.: ExposedService(context)
|
||||
"""
|
||||
updates = self.obj_get_changes()
|
||||
self.dbapi.update_exposed_service(self.id, updates)
|
||||
self.obj_reset_changes()
|
|
@ -21,11 +21,8 @@ from iotronic.db import api as db_api
|
|||
from iotronic.objects import base
|
||||
from iotronic.objects import utils as obj_utils
|
||||
|
||||
"""
|
||||
ACTIONS = ['ServiceCall', 'ServiceStop', 'ServiceStart',
|
||||
'ServiceStatus', 'ServiceReboot']
|
||||
CUSTOM_PARAMS = ['ServiceCall', 'ServiceStart', 'ServiceReboot']
|
||||
NO_PARAMS = ['ServiceStatus']
|
||||
|
||||
ACTIONS = ['ServiceEnable', 'ServiceDisable', 'ServiceRestore']
|
||||
|
||||
|
||||
def is_valid_action(action):
|
||||
|
@ -34,16 +31,6 @@ 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
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class Service(base.IotronicObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
@ -154,6 +141,7 @@ class Service(base.IotronicObject):
|
|||
object, e.g.: Service(context)
|
||||
|
||||
"""
|
||||
|
||||
values = self.obj_get_changes()
|
||||
db_service = self.dbapi.create_service(values)
|
||||
self._from_db_object(self, db_service)
|
||||
|
|
|
@ -167,8 +167,11 @@ CREATE TABLE IF NOT EXISTS `iotronic`.`exposed_services` (
|
|||
`board_uuid` VARCHAR(36) NOT NULL,
|
||||
`service_uuid` VARCHAR(36) NOT NULL,
|
||||
`public_port` INT(5) NOT NULL,
|
||||
`pid` INT(5) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `board_uuid` (`board_uuid` ASC),
|
||||
CONSTRAINT unique_index
|
||||
UNIQUE (service_uuid, board_uuid, pid),
|
||||
CONSTRAINT `fk_board_uuid`
|
||||
FOREIGN KEY (`board_uuid`)
|
||||
REFERENCES `iotronic`.`boards` (`uuid`)
|
||||
|
|
Loading…
Reference in New Issue