fixing up sample service

This commit is contained in:
Adolfo Gómez García 2019-10-01 14:01:52 +02:00
parent 76a17b19df
commit d48e71cfd3
8 changed files with 154 additions and 113 deletions

View File

@ -64,49 +64,50 @@ class Transports(ModelHandler):
return transports.factory().providers().values() return transports.factory().providers().values()
def getGui(self, type_: str) -> typing.List[typing.Any]: def getGui(self, type_: str) -> typing.List[typing.Any]:
try: transport = transports.factory().lookup(type_)
field = self.addDefaultFields(transports.actory().lookup(type_).guiDescription(), ['name', 'comments', 'tags', 'priority'])
field = self.addField(field, {
'name': 'nets_positive',
'value': True,
'label': ugettext('Network access'),
'tooltip': ugettext('If checked, the transport will be enabled for the selected networks. If unchecked, transport will be disabled for selected networks'),
'type': 'checkbox',
'order': 100, # At end
})
field = self.addField(field, {
'name': 'networks',
'value': [],
'values': sorted([{'id': x.id, 'text': x.name} for x in Network.objects.all()], key=lambda x: x['text'].lower()),
'label': ugettext('Networks'),
'tooltip': ugettext('Networks associated with this transport. If No network selected, will mean "all networks"'),
'type': 'multichoice',
'order': 101
})
field = self.addField(field, {
'name': 'allowed_oss',
'value': [],
'values': sorted([{'id': x, 'text': x} for x in OsDetector.knownOss], key=lambda x: x['text'].lower()),
'label': ugettext('Allowed Devices'),
'tooltip': ugettext('If empty, any kind of device compatible with this transport will be allowed. Else, only devices compatible with selected values will be allowed'),
'type': 'multichoice',
'order': 102
})
field = self.addField(field, {
'name': 'pools',
'value': [],
'values': [{'id': x.id, 'text': x.name} for x in ServicePool.objects.all().order_by('name')],
'label': ugettext('Service Pools'),
'tooltip': ugettext('Currently assigned services pools'),
'type': 'multichoice',
'order': 103
})
return field if not transport:
except Exception:
raise self.invalidItemException() raise self.invalidItemException()
field = self.addDefaultFields(transport.guiDescription(), ['name', 'comments', 'tags', 'priority'])
field = self.addField(field, {
'name': 'nets_positive',
'value': True,
'label': ugettext('Network access'),
'tooltip': ugettext('If checked, the transport will be enabled for the selected networks. If unchecked, transport will be disabled for selected networks'),
'type': 'checkbox',
'order': 100, # At end
})
field = self.addField(field, {
'name': 'networks',
'value': [],
'values': sorted([{'id': x.id, 'text': x.name} for x in Network.objects.all()], key=lambda x: x['text'].lower()),
'label': ugettext('Networks'),
'tooltip': ugettext('Networks associated with this transport. If No network selected, will mean "all networks"'),
'type': 'multichoice',
'order': 101
})
field = self.addField(field, {
'name': 'allowed_oss',
'value': [],
'values': sorted([{'id': x, 'text': x} for x in OsDetector.knownOss], key=lambda x: x['text'].lower()),
'label': ugettext('Allowed Devices'),
'tooltip': ugettext('If empty, any kind of device compatible with this transport will be allowed. Else, only devices compatible with selected values will be allowed'),
'type': 'multichoice',
'order': 102
})
field = self.addField(field, {
'name': 'pools',
'value': [],
'values': [{'id': x.id, 'text': x.name} for x in ServicePool.objects.all().order_by('name')],
'label': ugettext('Service Pools'),
'tooltip': ugettext('Currently assigned services pools'),
'type': 'multichoice',
'order': 103
})
return field
def item_as_dict(self, item: Transport) -> typing.Dict[str, typing.Any]: def item_as_dict(self, item: Transport) -> typing.Dict[str, typing.Any]:
type_ = item.getType() type_ = item.getType()
return { return {

View File

@ -34,11 +34,12 @@ UDS Service modules interfaces and classes.
""" """
from .transport import Transport from .transport import Transport
from .transport import DIRECT_GROUP, TUNNELED_GROUP from .transport import DIRECT_GROUP, TUNNELED_GROUP
from .transport_factory import TransportsFactory
from . import protocols from . import protocols
def factory():
def factory() -> TransportsFactory:
""" """
Returns factory for register/access to service providers Returns factory for register/access to service providers
""" """
from .transport_factory import TransportsFactory
return TransportsFactory.factory() return TransportsFactory.factory()

View File

@ -40,5 +40,4 @@ For this, we must simply import the class at __init__, UDS will take care
of the rest of the rest
""" """
from .SampleProvider import Provider from .provider import Provider

View File

@ -30,15 +30,22 @@
""" """
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com .. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
""" """
from uds.core.services import UserDeployment
from uds.core.util.state import State
import logging import logging
import typing
from uds.core import services
from uds.core.util.state import State
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
from uds import models
from .service import ServiceOne
from .publication import SamplePublication
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class SampleUserDeploymentOne(UserDeployment): class SampleUserDeploymentOne(services.UserDeployment):
""" """
This class generates the user consumable elements of the service tree. This class generates the user consumable elements of the service tree.
@ -72,17 +79,16 @@ class SampleUserDeploymentOne(UserDeployment):
suggestedTime = 5 suggestedTime = 5
# Serializable needed methods # Serializable needed methods
def marshal(self): def marshal(self) -> bytes:
""" """
Does nothing right here, we will use environment storage in this sample Does nothing right here, we will use environment storage in this sample
""" """
return b'' return b''
def unmarshal(self, str_): def unmarshal(self, data: bytes) -> None:
""" """
Does nothing here also, all data are kept at environment storage Does nothing here also, all data are kept at environment storage
""" """
pass
def getName(self): def getName(self):
""" """

View File

@ -30,16 +30,23 @@
""" """
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com .. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
""" """
from uds.core.services import UserDeployment
from uds.core.util.state import State
import logging
import codecs import codecs
import logging
import typing
from uds.core import services
from uds.core.util.state import State
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
from uds import models
from .service import ServiceOne
from .publication import SamplePublication
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class SampleUserDeploymentTwo(UserDeployment): class SampleUserDeploymentTwo(services.UserDeployment):
""" """
This class generates the user consumable elements of the service tree. This class generates the user consumable elements of the service tree.

View File

@ -32,18 +32,24 @@ Created on Jun 22, 2012
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com .. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
""" """
import logging
import typing
from django.utils.translation import ugettext_noop as _ from django.utils.translation import ugettext_noop as _
from uds.core.services import ServiceProvider from uds.core import services
from .SampleService import ServiceOne, ServiceTwo
from uds.core.ui import gui from uds.core.ui import gui
from .service import ServiceOne, ServiceTwo
import logging # Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
from uds.core import Module
from uds.core.environment import Environment
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class Provider(ServiceProvider): class Provider(services.ServiceProvider):
""" """
This class represents the sample services provider This class represents the sample services provider
@ -87,14 +93,16 @@ class Provider(ServiceProvider):
# : Remote host. Here core will translate label and tooltip, remember to # : Remote host. Here core will translate label and tooltip, remember to
# : mark them as _ using ugettext_noop. # : mark them as _ using ugettext_noop.
remoteHost = gui.TextField(oder=1, remoteHost = gui.TextField(
oder=1,
length=64, length=64,
label=_('Remote host'), label=_('Remote host'),
tooltip=_('This fields contains a remote host'), tooltip=_('This fields contains a remote host'),
required=True, required=True,
) )
# : Name of your pet (sample, not really needed :-) ) # : Name of your pet (sample, not really needed :-) )
petName = gui.TextField(order=2, petName = gui.TextField(
order=2,
length=32, length=32,
label=_('Your pet\'s name'), label=_('Your pet\'s name'),
tooltip=_('If you like, write the name of your pet'), tooltip=_('If you like, write the name of your pet'),
@ -104,7 +112,8 @@ class Provider(ServiceProvider):
# : Age of Methuselah (matusalén in spanish) # : Age of Methuselah (matusalén in spanish)
# : in Spain there is a well-known to say that something is very old, # : in Spain there is a well-known to say that something is very old,
# : "Tiene mas años que matusalén"(is older than Methuselah) # : "Tiene mas años que matusalén"(is older than Methuselah)
methAge = gui.NumericField(order=3, methAge = gui.NumericField(
order=3,
length=4, # That is, max allowed value is 9999 length=4, # That is, max allowed value is 9999
label=_('Age of Methuselah'), label=_('Age of Methuselah'),
tooltip=_('If you know it, please, tell me!!!'), tooltip=_('If you know it, please, tell me!!!'),
@ -113,14 +122,16 @@ class Provider(ServiceProvider):
) )
# : Is Methuselah istill alive? # : Is Methuselah istill alive?
methAlive = gui.CheckBoxField(order=4, methAlive = gui.CheckBoxField(
order=4,
label=_('Is Methuselah still alive?'), label=_('Is Methuselah still alive?'),
tooltip=_('If you fail, this will not get saved :-)'), tooltip=_('If you fail, this will not get saved :-)'),
required=True, # : Also means nothing. Check boxes has always a value required=True, # : Also means nothing. Check boxes has always a value
defvalue=gui.TRUE # : By default, at new item, check this defvalue=gui.TRUE # : By default, at new item, check this
) )
methText = gui.TextField(order=5, methText = gui.TextField(
order=5,
length=512, length=512,
multiline=5, multiline=5,
label=_('Text area'), label=_('Text area'),
@ -130,7 +141,7 @@ class Provider(ServiceProvider):
) )
# There is more fields type, but not here the best place to cover it # There is more fields type, but not here the best place to cover it
def initialize(self, values=None): def initialize(self, values: 'Module.ValuesType') -> None:
""" """
We will use the "autosave" feature for form fields, that is more than We will use the "autosave" feature for form fields, that is more than
enought for most providers. (We simply need to store data provided by user enought for most providers. (We simply need to store data provided by user
@ -143,8 +154,8 @@ class Provider(ServiceProvider):
# If you say meth is alive, you are wrong!!! (i guess..) # If you say meth is alive, you are wrong!!! (i guess..)
# values are only passed from administration client. Internals # values are only passed from administration client. Internals
# instantiations are always empty. # instantiations are always empty.
if values is not None and self.methAlive.isTrue(): if values and self.methAlive.isTrue():
raise ServiceProvider.ValidationException(_('Methuselah is not alive!!! :-)')) raise services.ServiceProvider.ValidationException(_('Methuselah is not alive!!! :-)'))
# Marshal and unmarshal are defaults ones, also enought # Marshal and unmarshal are defaults ones, also enought
@ -152,7 +163,7 @@ class Provider(ServiceProvider):
# base class so we don't have to mess with all those things... # base class so we don't have to mess with all those things...
@staticmethod @staticmethod
def test(env, data): def test(env: 'Environment', data: typing.Dict[str, str]) -> typing.List[typing.Any]:
""" """
Create your test method here so the admin can push the "check" button Create your test method here so the admin can push the "check" button
and this gets executed. and this gets executed.
@ -176,9 +187,8 @@ class Provider(ServiceProvider):
try: try:
# We instantiate the provider, but this may fail... # We instantiate the provider, but this may fail...
instance = Provider(env, data) instance = Provider(env, data)
logger.debug('Methuselah has {0} years and is {1} :-)' logger.debug('Methuselah has %s years and is %s :-)', instance.methAge.value, instance.methAlive.value)
.format(instance.methAge.value, instance.methAlive.value)) except services.ServiceProvider.ValidationException as e:
except ServiceProvider.ValidationException as e:
# If we say that meth is alive, instantiation will # If we say that meth is alive, instantiation will
return [False, str(e)] return [False, str(e)]
except Exception as e: except Exception as e:
@ -191,15 +201,15 @@ class Provider(ServiceProvider):
# #
# From now onwards, we implement our own methods, that will be used by, # From now onwards, we implement our own methods, that will be used by,
# for example, services derived from this provider # for example, services derived from this provider
def host(self): def host(self) -> str:
""" """
Sample method, in fact in this we just return Sample method, in fact in this we just return
the value of host field, that is an string the value of host field, that is an string
""" """
return self.remoteHost.value return self.remoteHost.value
def methYears(self): def methYears(self) -> int:
""" """
Another sample return, it will in fact return the Methuselah years Another sample return, it will in fact return the Methuselah years
""" """
return self.methAge.value() return self.methAge.num()

View File

@ -30,15 +30,19 @@
""" """
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com .. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
""" """
import logging
import typing
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from uds.core.services import Publication from uds.core.services import Publication
from uds.core.util.state import State from uds.core.util.state import State
from datetime import datetime
import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
from .service import ServiceOne, ServiceTwo
class SamplePublication(Publication): class SamplePublication(Publication):
""" """
@ -79,6 +83,9 @@ class SamplePublication(Publication):
""" """
suggestedTime = 5 # : Suggested recheck time if publication is unfinished in seconds suggestedTime = 5 # : Suggested recheck time if publication is unfinished in seconds
_name: str = ''
_reason: str = ''
_number: int = -1
def initialize(self): def initialize(self):
""" """
@ -104,9 +111,9 @@ class SamplePublication(Publication):
""" """
deserializes the data and loads it inside instance. deserializes the data and loads it inside instance.
""" """
logger.debug('Data: {0}'.format(data)) logger.debug('Data: %s', data)
vals = data.decode('utf8').split('\t') vals = data.decode('utf8').split('\t')
logger.debug('Values: {0}'.format(vals)) logger.debug('Values: %s', vals)
self._name = vals[0] self._name = vals[0]
self._reason = vals[1] self._reason = vals[1]
self._number = int(vals[2]) self._number = int(vals[2])

View File

@ -30,20 +30,26 @@
""" """
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com .. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
""" """
import logging
import typing
from django.utils.translation import ugettext_noop as _ from django.utils.translation import ugettext_noop as _
from uds.core.services import Service from uds.core import services
from .SamplePublication import SamplePublication
from .SampleUserDeploymentOne import SampleUserDeploymentOne
from .SampleUserDeploymentTwo import SampleUserDeploymentTwo
from uds.core.ui import gui from uds.core.ui import gui
import logging from .publication import SamplePublication
from .deployment_one import SampleUserDeploymentOne
from .deployment_two import SampleUserDeploymentTwo
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
from uds.core import Module
from uds.core.environment import Environment
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class ServiceOne(Service): class ServiceOne(services.Service):
""" """
Basic service, the first part (variables) include the description of the service. Basic service, the first part (variables) include the description of the service.
@ -114,33 +120,37 @@ class ServiceOne(Service):
# If we don't indicate an order, the output order of fields will be # If we don't indicate an order, the output order of fields will be
# "random" # "random"
colour = gui.ChoiceField(order=1, colour = gui.ChoiceField(
label=_('Colour'), order=1,
tooltip=_('Colour of the field'), label=_('Colour'),
# In this case, the choice can have none value selected by default tooltip=_('Colour of the field'),
required=True, # In this case, the choice can have none value selected by default
values=[ gui.choiceItem('red', 'Red'), required=True,
gui.choiceItem('green', 'Green'), values=[
gui.choiceItem('blue', 'Blue'), gui.choiceItem('red', 'Red'),
gui.choiceItem('nonsense', 'Blagenta') gui.choiceItem('green', 'Green'),
], gui.choiceItem('blue', 'Blue'),
defvalue='1' # Default value is the ID of the choicefield gui.choiceItem('nonsense', 'Blagenta')
) ],
defvalue='1' # Default value is the ID of the choicefield
)
passw = gui.PasswordField(order=2, passw = gui.PasswordField(
label=_('Password'), order=2,
tooltip=_('Password for testing purposes'), label=_('Password'),
required=True, tooltip=_('Password for testing purposes'),
defvalue='1234' # : Default password are nonsense?? :-) required=True,
) defvalue='1234' # : Default password are nonsense?? :-)
)
baseName = gui.TextField(order=3, baseName = gui.TextField(
label=_('Services names'), order=3,
tooltip=_('Base name for this user services'), label=_('Services names'),
# In this case, the choice can have none value selected by default tooltip=_('Base name for this user services'),
required=True, # In this case, the choice can have none value selected by default
defvalue='' # Default value is the ID of the choicefield required=True,
) defvalue='' # Default value is the ID of the choicefield
)
def initialize(self, values): def initialize(self, values):
""" """
@ -155,7 +165,7 @@ class ServiceOne(Service):
# so we only need to validate params if values is not None # so we only need to validate params if values is not None
if values is not None: if values is not None:
if self.colour.value == 'nonsense': if self.colour.value == 'nonsense':
raise Service.ValidationException('The selected colour is invalid!!!') raise services.Service.ValidationException('The selected colour is invalid!!!')
# Services itself are non testeable right now, so we don't even have # Services itself are non testeable right now, so we don't even have
@ -189,7 +199,7 @@ class ServiceOne(Service):
class ServiceTwo(Service): class ServiceTwo(services.Service):
""" """
Just a second service, no comments here (almost same that ServiceOne Just a second service, no comments here (almost same that ServiceOne
""" """