forked from shaba/openuds
* New Clients Versions
* Refactoring * Minor fixes
This commit is contained in:
parent
8934d978fe
commit
7af7d11c8a
@ -207,8 +207,8 @@ class Module(UserInterface, Environmentable, Serializable):
|
||||
We want to use the env, cache and storage methods outside class.
|
||||
If not called, you must implement your own methods.
|
||||
|
||||
cache and storage are "convenient" methods to access _env.cache() and
|
||||
_env.storage()
|
||||
cache and storage are "convenient" methods to access _env.cache and
|
||||
_env.storage
|
||||
|
||||
The values param is passed directly to UserInterface base.
|
||||
|
||||
|
@ -59,6 +59,7 @@ class Environment(object):
|
||||
self._storage = Storage(uniqueKey)
|
||||
self._idGenerators = idGenerators
|
||||
|
||||
@property
|
||||
def cache(self):
|
||||
'''
|
||||
Method to acces the cache of the environment.
|
||||
@ -66,6 +67,7 @@ class Environment(object):
|
||||
'''
|
||||
return self._cache
|
||||
|
||||
@property
|
||||
def storage(self):
|
||||
'''
|
||||
Method to acces the cache of the environment.
|
||||
@ -83,6 +85,7 @@ class Environment(object):
|
||||
'''
|
||||
return self._idGenerators.get(generatorId, None)
|
||||
|
||||
@property
|
||||
def key(self):
|
||||
'''
|
||||
@return: the key used for this environment
|
||||
@ -156,15 +159,7 @@ class Environmentable(object):
|
||||
'''
|
||||
self._env = environment
|
||||
|
||||
def setEnv(self, environment):
|
||||
'''
|
||||
Assigns a new environment
|
||||
|
||||
Args:
|
||||
environment: Environment to assign
|
||||
'''
|
||||
self._env = environment
|
||||
|
||||
@property
|
||||
def env(self):
|
||||
'''
|
||||
Utility method to access the envionment contained by this object
|
||||
@ -174,6 +169,18 @@ class Environmentable(object):
|
||||
'''
|
||||
return self._env
|
||||
|
||||
@env.setter
|
||||
def env(self, environment):
|
||||
'''
|
||||
Assigns a new environment
|
||||
|
||||
Args:
|
||||
environment: Environment to assign
|
||||
'''
|
||||
self._env = environment
|
||||
|
||||
|
||||
@property
|
||||
def cache(self):
|
||||
'''
|
||||
Utility method to access the cache of the environment containe by this object
|
||||
@ -181,8 +188,9 @@ class Environmentable(object):
|
||||
Returns:
|
||||
Cache for the object
|
||||
'''
|
||||
return self._env.cache()
|
||||
return self._env.cache
|
||||
|
||||
@property
|
||||
def storage(self):
|
||||
'''
|
||||
Utility method to access the storage of the environment containe by this object
|
||||
@ -190,7 +198,7 @@ class Environmentable(object):
|
||||
Returns:
|
||||
Storage for the object
|
||||
'''
|
||||
return self._env.storage()
|
||||
return self._env.storage
|
||||
|
||||
def idGenerators(self, generatorId):
|
||||
'''
|
||||
|
@ -36,7 +36,7 @@ from uds.core import Environmentable
|
||||
from uds.core import Serializable
|
||||
from uds.core.util.State import State
|
||||
|
||||
__updated__ = '2015-05-12'
|
||||
__updated__ = '2016-02-26'
|
||||
|
||||
|
||||
class UserDeployment(Environmentable, Serializable):
|
||||
@ -118,7 +118,7 @@ class UserDeployment(Environmentable, Serializable):
|
||||
'''
|
||||
Do not forget to invoke this in your derived class using "super(self.__class__, self).__init__(environment, **kwargs)"
|
||||
We want to use the env, service and storage methods outside class. If not called, you must implement your own methods
|
||||
service and storage are "convenient" methods to access _env.service() and _env.storage()
|
||||
service and storage are "convenient" methods to access _env.service() and _env.storage
|
||||
|
||||
Invoking this from derived classes is a MUST, again, do not forget it or your
|
||||
module will probable never work.
|
||||
|
@ -35,7 +35,7 @@ from __future__ import unicode_literals
|
||||
from uds.core import Environmentable
|
||||
from uds.core import Serializable
|
||||
|
||||
__updated__ = '2014-03-22'
|
||||
__updated__ = '2016-02-26'
|
||||
|
||||
|
||||
class Publication(Environmentable, Serializable):
|
||||
@ -81,7 +81,7 @@ class Publication(Environmentable, Serializable):
|
||||
'''
|
||||
Do not forget to invoke this in your derived class using "super(self.__class__, self).__init__(environment, values)"
|
||||
We want to use the env, cache and storage methods outside class. If not called, you must implement your own methods
|
||||
cache and storage are "convenient" methods to access _env.cache() and _env.storage()
|
||||
cache and storage are "convenient" methods to access _env.cache and _env.storage
|
||||
@param environment: Environment assigned to this publication
|
||||
'''
|
||||
Environmentable.__init__(self, environment)
|
||||
|
@ -37,7 +37,7 @@ from uds.core import Module
|
||||
from uds.core.transports import protocols
|
||||
from . import types
|
||||
|
||||
__updated__ = '2016-02-08'
|
||||
__updated__ = '2016-02-26'
|
||||
|
||||
|
||||
class Service(Module):
|
||||
@ -179,7 +179,7 @@ class Service(Module):
|
||||
'''
|
||||
Do not forget to invoke this in your derived class using "super(self.__class__, self).__init__(environment, parent, values)".
|
||||
We want to use the env, parent methods outside class. If not called, you must implement your own methods
|
||||
cache and storage are "convenient" methods to access _env.cache() and _env.storage()
|
||||
cache and storage are "convenient" methods to access _env.cache and _env.storage
|
||||
'''
|
||||
super(Service, self).__init__(environment, values)
|
||||
self._provider = parent
|
||||
|
@ -37,7 +37,7 @@ from uds.core.util.Config import GlobalConfig
|
||||
|
||||
import logging
|
||||
|
||||
__updated__ = '2014-11-11'
|
||||
__updated__ = '2016-02-26'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -62,7 +62,7 @@ class ClusteredServiceProvider(ServiceProvider):
|
||||
|
||||
# This methods do not need to be overriden
|
||||
def clusterStats(self):
|
||||
stats = self.storage().getPickle('ClusterStats')
|
||||
stats = self.storage.getPickle('ClusterStats')
|
||||
if stats is None:
|
||||
stats = {}
|
||||
return stats
|
||||
|
@ -80,7 +80,7 @@ class ClusterUpdateStatsTask(DelayedTask):
|
||||
'freeMemory': s.get('freeMemory', None),
|
||||
'totalMemory': s.get('totalMemory')
|
||||
}
|
||||
cluster.storage().putPickle('ClusterStats', stats)
|
||||
cluster.storage.putPickle('ClusterStats', stats)
|
||||
except:
|
||||
logger.exception('Update Stats Task')
|
||||
# Removed provider, no problem at all, no update is done
|
||||
|
@ -48,7 +48,7 @@ import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
__updated__ = '2016-02-10'
|
||||
__updated__ = '2016-02-26'
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Authenticator(ManagedObjectModel, TaggingMixin):
|
||||
@ -194,7 +194,7 @@ class Authenticator(ManagedObjectModel, TaggingMixin):
|
||||
if toDelete.data != '':
|
||||
s = toDelete.getInstance()
|
||||
s.destroy()
|
||||
s.env().clearRelatedData()
|
||||
s.env.clearRelatedData()
|
||||
|
||||
# Clears related logs
|
||||
log.clearLogs(toDelete)
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
__updated__ = '2016-02-10'
|
||||
__updated__ = '2016-02-26'
|
||||
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.db import IntegrityError
|
||||
@ -112,7 +112,7 @@ class OSManager(ManagedObjectModel, TaggingMixin):
|
||||
if toDelete.data != '':
|
||||
s = toDelete.getInstance()
|
||||
s.destroy()
|
||||
s.env().clearRelatedData()
|
||||
s.env.clearRelatedData()
|
||||
|
||||
logger.debug('Before delete os manager {}'.format(toDelete))
|
||||
|
||||
|
@ -44,7 +44,7 @@ from uds.models.Tag import TaggingMixin
|
||||
import logging
|
||||
|
||||
|
||||
__updated__ = '2016-02-10'
|
||||
__updated__ = '2016-02-26'
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -103,7 +103,7 @@ class Provider(ManagedObjectModel, TaggingMixin):
|
||||
if toDelete.data != '':
|
||||
s = toDelete.getInstance()
|
||||
s.destroy()
|
||||
s.env().clearRelatedData()
|
||||
s.env.clearRelatedData()
|
||||
|
||||
# Clears related logs
|
||||
log.clearLogs(toDelete)
|
||||
|
@ -48,7 +48,7 @@ from uds.models.Provider import Provider
|
||||
import logging
|
||||
|
||||
|
||||
__updated__ = '2016-02-10'
|
||||
__updated__ = '2016-02-26'
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -147,7 +147,7 @@ class Service(ManagedObjectModel, TaggingMixin):
|
||||
if toDelete.data != '':
|
||||
s = toDelete.getInstance()
|
||||
s.destroy()
|
||||
s.env().clearRelatedData()
|
||||
s.env.clearRelatedData()
|
||||
|
||||
# Clears related logs
|
||||
log.clearLogs(toDelete)
|
||||
|
@ -60,7 +60,7 @@ from uds.core.util.calendar import CalendarChecker
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
__updated__ = '2016-02-19'
|
||||
__updated__ = '2016-02-26'
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -215,7 +215,7 @@ class DeployedService(UUIDModel, TaggingMixin):
|
||||
name: Name of the value to store
|
||||
value: Value of the value to store
|
||||
'''
|
||||
self.getEnvironment().storage().put(name, value)
|
||||
self.getEnvironment().storage.put(name, value)
|
||||
|
||||
def recoverValue(self, name):
|
||||
'''
|
||||
@ -227,7 +227,7 @@ class DeployedService(UUIDModel, TaggingMixin):
|
||||
Returns:
|
||||
Stored value, None if no value was stored
|
||||
'''
|
||||
return self.getEnvironment().storage().get(name)
|
||||
return self.getEnvironment().storage.get(name)
|
||||
|
||||
def setState(self, state, save=True):
|
||||
'''
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
__updated__ = '2016-02-10'
|
||||
__updated__ = '2016-02-26'
|
||||
|
||||
from django.db import models
|
||||
from django.db.models import signals
|
||||
@ -134,7 +134,7 @@ class Transport(ManagedObjectModel, TaggingMixin):
|
||||
if toDelete.data != '':
|
||||
s = toDelete.getInstance()
|
||||
s.destroy()
|
||||
s.env().clearRelatedData()
|
||||
s.env.clearRelatedData()
|
||||
|
||||
# Clears related permissions
|
||||
clean(toDelete)
|
||||
|
@ -55,7 +55,7 @@ from uds.models.Util import getSqlDatetime
|
||||
|
||||
import logging
|
||||
|
||||
__updated__ = '2016-02-08'
|
||||
__updated__ = '2016-02-26'
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -230,7 +230,7 @@ class UserService(UUIDModel):
|
||||
# To transition between old stor at storage table and new properties table
|
||||
# If value is found on property, use it, else, try to recover it from storage
|
||||
if val is None:
|
||||
val = self.getEnvironment().storage().get(name)
|
||||
val = self.getEnvironment().storage.get(name)
|
||||
return val
|
||||
|
||||
def setConnectionSource(self, ip, hostname=''):
|
||||
|
@ -37,7 +37,7 @@ from uds.core.util import log
|
||||
import pickle
|
||||
import logging
|
||||
|
||||
__updated__ = '2015-09-07'
|
||||
__updated__ = '2016-02-26'
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -168,7 +168,7 @@ class OVirtLinkedDeployment(UserDeployment):
|
||||
The method is invoked whenever a machine is provided to an user, right
|
||||
before presenting it (via transport rendering) to the user.
|
||||
'''
|
||||
if self.cache().get('ready') == '1':
|
||||
if self.cache.get('ready') == '1':
|
||||
return State.FINISHED
|
||||
|
||||
state = self.service().getMachineState(self._vmid)
|
||||
@ -180,7 +180,7 @@ class OVirtLinkedDeployment(UserDeployment):
|
||||
self._queue = [opStart, opFinish]
|
||||
return self.__executeQueue()
|
||||
|
||||
self.cache().put('ready', '1')
|
||||
self.cache.put('ready', '1')
|
||||
return State.FINISHED
|
||||
|
||||
def getConsoleConnection(self):
|
||||
|
@ -41,7 +41,7 @@ from uds.core.ui import gui
|
||||
|
||||
import logging
|
||||
|
||||
__updated__ = '2015-07-24'
|
||||
__updated__ = '2016-02-26'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -197,7 +197,7 @@ class OVirtLinkedService(Service):
|
||||
self.memoryGuaranteed.value = self.memory.value
|
||||
|
||||
self.ov.value = self.parent().serialize()
|
||||
self.ev.value = self.parent().env().key()
|
||||
self.ev.value = self.parent().env.key
|
||||
|
||||
def initGui(self):
|
||||
'''
|
||||
@ -208,7 +208,7 @@ class OVirtLinkedService(Service):
|
||||
# This is that value is always '', so if we want to change something, we have to do it
|
||||
# at defValue
|
||||
self.ov.defValue = self.parent().serialize()
|
||||
self.ev.defValue = self.parent().env().key()
|
||||
self.ev.defValue = self.parent().env.key
|
||||
|
||||
machines = self.parent().getMachines()
|
||||
vals = []
|
||||
|
@ -45,7 +45,7 @@ from .client import oVirtClient
|
||||
|
||||
import logging
|
||||
|
||||
__updated__ = '2015-09-22'
|
||||
__updated__ = '2016-02-26'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -112,7 +112,7 @@ class Provider(ServiceProvider):
|
||||
Returns the connection API object for oVirt (using ovirtsdk)
|
||||
'''
|
||||
if self._api is None:
|
||||
self._api = oVirtClient.Client(self.host.value, self.username.value, self.password.value, self.timeout.value, self.cache())
|
||||
self._api = oVirtClient.Client(self.host.value, self.username.value, self.password.value, self.timeout.value, self.cache)
|
||||
return self._api
|
||||
|
||||
# There is more fields type, but not here the best place to cover it
|
||||
|
@ -39,7 +39,7 @@ from . import on
|
||||
import pickle
|
||||
import logging
|
||||
|
||||
__updated__ = '2016-02-09'
|
||||
__updated__ = '2016-02-26'
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -168,7 +168,7 @@ class LiveDeployment(UserDeployment):
|
||||
The method is invoked whenever a machine is provided to an user, right
|
||||
before presenting it (via transport rendering) to the user.
|
||||
'''
|
||||
if self.cache().get('ready') == '1':
|
||||
if self.cache.get('ready') == '1':
|
||||
return State.FINISHED
|
||||
|
||||
state = self.service().getMachineState(self._vmid)
|
||||
@ -178,7 +178,7 @@ class LiveDeployment(UserDeployment):
|
||||
|
||||
self.service().startMachine()
|
||||
|
||||
self.cache().put('ready', '1')
|
||||
self.cache.put('ready', '1')
|
||||
return State.FINISHED
|
||||
|
||||
def getConsoleConnection(self):
|
||||
|
@ -43,7 +43,7 @@ from defusedxml import minidom
|
||||
# Python bindings for OpenNebula
|
||||
import oca
|
||||
|
||||
__updated__ = '2016-02-09'
|
||||
__updated__ = '2016-02-25'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -56,8 +56,8 @@ for i in enumerate(['INIT', 'PENDING', 'HOLD', 'ACTIVE', 'STOPPED', 'SUSPENDED',
|
||||
|
||||
|
||||
# Import submodules
|
||||
from common import *
|
||||
import template
|
||||
import vm
|
||||
import storage
|
||||
from .common import *
|
||||
from . import template
|
||||
from . import vm
|
||||
from . import storage
|
||||
|
||||
|
@ -78,33 +78,33 @@ class IPMachinesService(services.Service):
|
||||
return {'ipList': gui.convertToList(ips)}
|
||||
|
||||
def marshal(self):
|
||||
self.storage().saveData('ips', pickle.dumps(self._ips))
|
||||
self.storage.saveData('ips', pickle.dumps(self._ips))
|
||||
return 'v1'
|
||||
|
||||
def unmarshal(self, vals):
|
||||
if vals == 'v1':
|
||||
self._ips = pickle.loads(str(self.storage().readData('ips')))
|
||||
self._ips = pickle.loads(str(self.storage.readData('ips')))
|
||||
|
||||
def getUnassignedMachine(self):
|
||||
# Search first unassigned machine
|
||||
try:
|
||||
self.storage().lock()
|
||||
self.storage.lock()
|
||||
for ip in self._ips:
|
||||
if self.storage().readData(ip) == None:
|
||||
self.storage().saveData(ip, ip)
|
||||
if self.storage.readData(ip) == None:
|
||||
self.storage.saveData(ip, ip)
|
||||
return ip
|
||||
return None
|
||||
except Exception:
|
||||
logger.exception("Exception at getUnassignedMachine")
|
||||
return None
|
||||
finally:
|
||||
self.storage().unlock()
|
||||
self.storage.unlock()
|
||||
|
||||
def unassignMachine(self, ip):
|
||||
try:
|
||||
self.storage().lock()
|
||||
self.storage().remove(ip)
|
||||
self.storage.lock()
|
||||
self.storage.remove(ip)
|
||||
except Exception:
|
||||
logger.exception("Exception at getUnassignedMachine")
|
||||
finally:
|
||||
self.storage().unlock()
|
||||
self.storage.unlock()
|
||||
|
@ -4,27 +4,27 @@
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@ -40,85 +40,85 @@ logger = logging.getLogger(__name__)
|
||||
class SampleUserDeploymentOne(UserDeployment):
|
||||
'''
|
||||
This class generates the user consumable elements of the service tree.
|
||||
|
||||
|
||||
After creating at administration interface an Deployed Service, UDS will
|
||||
create consumable services for users using UserDeployment class as
|
||||
provider of this elements.
|
||||
|
||||
|
||||
|
||||
|
||||
At class instantiation, this will receive an environment with"generator",
|
||||
that are classes that provides a way to generate unique items.
|
||||
|
||||
|
||||
The generators provided right now are 'mac' and 'name'. To get more info
|
||||
about this, look at py:class:`uds.core.util.UniqueMacGenerator.UniqueNameGenerator`
|
||||
and py:class:`uds.core.util.UniqueNameGenerator.UniqueNameGenerator`
|
||||
|
||||
|
||||
This first sample do not uses cache. To see one with cache, see
|
||||
SampleUserDeploymentTwo. The main difference are the "...Cache".." methods,
|
||||
that here are not needed.
|
||||
|
||||
|
||||
As sample also of environment storage usage, wi will use here the provider
|
||||
storage to keep all our needed info, leaving marshal and unmarshal (needed
|
||||
by Serializble classes, like this) empty (that is, returns '' first and does
|
||||
nothing the second one)
|
||||
|
||||
|
||||
Also Remember, if you don't include this class as the deployedType of the
|
||||
SampleServiceOne, or whenever you trie to access a service of SampleServiceOne,
|
||||
you will get an excetion that says that you havent included the deployedType.
|
||||
you will get an excetion that says that you havent included the deployedType.
|
||||
'''
|
||||
|
||||
#: Recheck every five seconds by default (for task methods)
|
||||
|
||||
# : Recheck every five seconds by default (for task methods)
|
||||
suggestedTime = 5
|
||||
|
||||
# Serializable needed methods
|
||||
# Serializable needed methods
|
||||
def marshal(self):
|
||||
'''
|
||||
Does nothing right here, we will use envoronment storage in this sample
|
||||
'''
|
||||
return ''
|
||||
|
||||
|
||||
def unmarshal(self, str_):
|
||||
'''
|
||||
Does nothing here also, all data are keeped at environment storage
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def getName(self):
|
||||
'''
|
||||
We override this to return a name to display. Default inplementation
|
||||
We override this to return a name to display. Default inplementation
|
||||
(in base class), returns getUniqueIde() value
|
||||
This name will help user to identify elements, and is only used
|
||||
at administration interface.
|
||||
|
||||
|
||||
We will use here the environment name provided generator to generate
|
||||
a name for this element.
|
||||
|
||||
The namaGenerator need two params, the base name and a length for a
|
||||
|
||||
The namaGenerator need two params, the base name and a length for a
|
||||
numeric incremental part for generating unique names. This are unique for
|
||||
all UDS names generations, that is, UDS will not generate this name again
|
||||
until this name is freed, or object is removed, what makes its environment
|
||||
to also get removed, that makes all uniques ids (names and macs right now)
|
||||
to also get released.
|
||||
|
||||
|
||||
Every time get method of a generator gets called, the generator creates
|
||||
a new unique name, so we keep the first generated name cached and don't
|
||||
generate more names. (Generator are simple utility classes)
|
||||
'''
|
||||
name = self.storage().readData('name')
|
||||
if name is None:
|
||||
name = self.nameGenerator().get( self.service().getBaseName()
|
||||
+ '-' + self.service().getColour(), 3 )
|
||||
name = self.storage.readData('name')
|
||||
if name is None:
|
||||
name = self.nameGenerator().get(self.service().getBaseName()
|
||||
+ '-' + self.service().getColour(), 3)
|
||||
# Store value for persistence
|
||||
self.storage().saveData('name', name)
|
||||
|
||||
self.storage.saveData('name', name)
|
||||
|
||||
return name
|
||||
|
||||
|
||||
def setIp(self, ip):
|
||||
'''
|
||||
In our case, there is no OS manager associated with this, so this method
|
||||
will never get called, but we put here as sample.
|
||||
|
||||
|
||||
Whenever an os manager actor notifies the broker the state of the service
|
||||
(mainly machines), the implementation of that os manager can (an probably will)
|
||||
need to notify the IP of the deployed service. Remember that UDS treats with
|
||||
@ -126,248 +126,247 @@ class SampleUserDeploymentOne(UserDeployment):
|
||||
:note: This IP is the IP of the "consumed service", so the transport can
|
||||
access it.
|
||||
'''
|
||||
self.storage().saveData('ip', str(ip))
|
||||
|
||||
self.storage.saveData('ip', str(ip))
|
||||
|
||||
def getUniqueId(self):
|
||||
'''
|
||||
Return and unique identifier for this service.
|
||||
In our case, we will generate a mac name, that can be also as sample
|
||||
of 'mac' generator use, and probably will get used something like this
|
||||
at some services.
|
||||
|
||||
|
||||
The get method of a mac generator takes one param, that is the mac range
|
||||
to use to get an unused mac.
|
||||
'''
|
||||
mac = self.storage().readData('mac')
|
||||
mac = self.storage.readData('mac')
|
||||
if mac is None:
|
||||
mac = self.macGenerator().get( '00:00:00:00:00:00-00:FF:FF:FF:FF:FF' )
|
||||
self.storage().saveData('mac', mac)
|
||||
mac = self.macGenerator().get('00:00:00:00:00:00-00:FF:FF:FF:FF:FF')
|
||||
self.storage.saveData('mac', mac)
|
||||
return mac
|
||||
|
||||
|
||||
def getIp(self):
|
||||
'''
|
||||
We need to implement this method, so we can return the IP for transports
|
||||
use. If no IP is known for this service, this must return None
|
||||
|
||||
|
||||
If our sample do not returns an IP, IP transport will never work with
|
||||
this service. Remember in real cases to return a valid IP address if
|
||||
the service is accesible and you alredy know that (for example, because
|
||||
the IP has been assigend via setIp by an os manager) or because
|
||||
you get it for some other method.
|
||||
|
||||
you get it for some other method.
|
||||
|
||||
Storage returns None if key is not stored.
|
||||
|
||||
|
||||
:note: Keeping the IP address is responsibility of the User Deployment.
|
||||
Every time the core needs to provide the service to the user, or
|
||||
show the IP to the administrator, this method will get called
|
||||
|
||||
|
||||
'''
|
||||
ip = self.storage().readData('ip')
|
||||
ip = self.storage.readData('ip')
|
||||
if ip is None:
|
||||
ip = '192.168.0.34' # Sample IP for testing purposses only
|
||||
ip = '192.168.0.34' # Sample IP for testing purposses only
|
||||
return ip
|
||||
|
||||
def setReady(self):
|
||||
'''
|
||||
This is a task method. As that, the expected return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
|
||||
The method is invoked whenever a machine is provided to an user, right
|
||||
before presenting it (via transport rendering) to the user.
|
||||
|
||||
This method exist for this kind of situations (i will explain it with a
|
||||
|
||||
This method exist for this kind of situations (i will explain it with a
|
||||
sample)
|
||||
|
||||
|
||||
Imagine a Service tree (Provider, Service, ...) for virtual machines.
|
||||
This machines will get created by the UserDeployment implementation, but,
|
||||
at some time, the machine can be put at in an state (suspend, shut down)
|
||||
that will make the transport impossible to connect with it.
|
||||
|
||||
|
||||
This method, in this case, will check the state of the machine, and if
|
||||
it is "ready", that is, powered on and accesible, it will return
|
||||
it is "ready", that is, powered on and accesible, it will return
|
||||
"State.FINISHED". If the machine is not accesible (has ben erased, for
|
||||
example), it will return "State.ERROR" and store a reason of error so UDS
|
||||
can ask for it and present this information to the Administrator.
|
||||
|
||||
|
||||
If the machine powered off, or suspended, or any other state that is not
|
||||
directly usable but can be put in an usable state, it will return
|
||||
"State.RUNNING", and core will use checkState to see when the operation
|
||||
has finished.
|
||||
|
||||
|
||||
I hope this sample is enough to explain the use of this method..
|
||||
'''
|
||||
|
||||
|
||||
# In our case, the service is always ready
|
||||
return State.FINISHED
|
||||
|
||||
|
||||
def deployForUser(self, user):
|
||||
'''
|
||||
Deploys an service instance for an user.
|
||||
|
||||
This is a task method. As that, the excepted return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
|
||||
The user parameter is not realy neded, but provided. It indicates the
|
||||
Database User Object (see py:mod:`uds.modules`) to which this deployed
|
||||
user service will be assigned to.
|
||||
|
||||
|
||||
This method will get called whenever a new deployed service for an user
|
||||
is needed. This will give this class the oportunity to create
|
||||
a service that is assigned to an user.
|
||||
|
||||
|
||||
The way of using this method is as follows:
|
||||
|
||||
|
||||
If the service gets created in "one step", that is, before the return
|
||||
of this method, the consumable service for the user gets created, it
|
||||
will return "State.FINISH".
|
||||
If the service needs more steps (as in this case), we will return
|
||||
If the service needs more steps (as in this case), we will return
|
||||
"State.RUNNING", and if it has an error, it wil return "State.ERROR" and
|
||||
store an error string so administration interface can show it.
|
||||
|
||||
|
||||
We do not use user for anything, as in most cases will be.
|
||||
'''
|
||||
import random
|
||||
|
||||
self.storage().saveData('count', '0')
|
||||
|
||||
self.storage.saveData('count', '0')
|
||||
|
||||
# random fail
|
||||
if random.randint(0, 9) == 9:
|
||||
self.storage().saveData('error', 'Random error at deployForUser :-)')
|
||||
self.storage.saveData('error', 'Random error at deployForUser :-)')
|
||||
return State.ERROR
|
||||
|
||||
|
||||
return State.RUNNING
|
||||
|
||||
|
||||
|
||||
|
||||
def checkState(self):
|
||||
'''
|
||||
Our deployForUser method will initiate the consumable service deployment,
|
||||
Our deployForUser method will initiate the consumable service deployment,
|
||||
but will not finish it.
|
||||
|
||||
|
||||
So in our sample, we will only check if a number reaches 5, and if so
|
||||
return that we have finished, else we will return that we are working
|
||||
on it.
|
||||
|
||||
|
||||
One deployForUser returns State.RUNNING, this task will get called until
|
||||
checkState returns State.FINISHED.
|
||||
|
||||
|
||||
Also, we will make the publication fail one of every 10 calls to this
|
||||
method.
|
||||
|
||||
Note: Destroying, canceling and deploying for cache also makes use of
|
||||
|
||||
Note: Destroying, canceling and deploying for cache also makes use of
|
||||
this method, so you must keep the info of that you are checking if you
|
||||
need it.
|
||||
need it.
|
||||
In our case, destroy is 1-step action so this will no get called while
|
||||
destroying, and cancel will simply invoke destroy
|
||||
'''
|
||||
import random
|
||||
|
||||
count = int(self.storage().readData('count')) + 1
|
||||
|
||||
count = int(self.storage.readData('count')) + 1
|
||||
# Count is always a valid value, because this method will never get
|
||||
# called before deployForUser, deployForCache, destroy or cancel.
|
||||
# In our sample, we only use checkState in case of deployForUser,
|
||||
# so at first call count will be 0.
|
||||
if count >= 5:
|
||||
return State.FINISHED
|
||||
|
||||
|
||||
# random fail
|
||||
if random.randint(0, 9) == 9:
|
||||
self.storage().saveData('error', 'Random error at checkState :-)')
|
||||
self.storage.saveData('error', 'Random error at checkState :-)')
|
||||
return State.ERROR
|
||||
|
||||
self.storage().saveData('count', str(count))
|
||||
|
||||
self.storage.saveData('count', str(count))
|
||||
return State.RUNNING
|
||||
|
||||
|
||||
def finish(self):
|
||||
'''
|
||||
Invoked when the core notices that the deployment of a service has finished.
|
||||
(No matter wether it is for cache or for an user)
|
||||
|
||||
|
||||
This gives the oportunity to make something at that moment.
|
||||
:note: You can also make these operations at checkState, this is really
|
||||
not needed, but can be provided (default implementation of base class does
|
||||
nothing)
|
||||
nothing)
|
||||
'''
|
||||
# Note that this is not really needed, is just a sample of storage use
|
||||
self.storage().remove('count')
|
||||
|
||||
self.storage.remove('count')
|
||||
|
||||
def assignToUser(self, user):
|
||||
'''
|
||||
This method is invoked whenever a cache item gets assigned to an user.
|
||||
This gives the User Deployment an oportunity to do whatever actions
|
||||
are required so the service puts at a correct state for using by a service.
|
||||
|
||||
|
||||
In our sample, the service is always ready, so this does nothing.
|
||||
|
||||
|
||||
This is not a task method. All level 1 cache items can be diretly
|
||||
assigned to an user with no more work needed, but, if something is needed,
|
||||
here you can do whatever you need
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
def userLoggedIn(self, user):
|
||||
'''
|
||||
This method must be available so os managers can invoke it whenever
|
||||
an user get logged into a service.
|
||||
|
||||
|
||||
Default implementation does nothing, so if you are going to do nothing,
|
||||
you don't need to implement it.
|
||||
|
||||
The responability of notifying it is of os manager actor, and it's
|
||||
|
||||
The responability of notifying it is of os manager actor, and it's
|
||||
directly invoked by os managers (right now, linux os manager and windows
|
||||
os manager)
|
||||
|
||||
|
||||
The user provided is just an string, that is provided by actor.
|
||||
'''
|
||||
# We store the value at storage, but never get used, just an example
|
||||
self.storage().saveData('user', user)
|
||||
|
||||
self.storage.saveData('user', user)
|
||||
|
||||
def userLoggedOut(self, user):
|
||||
'''
|
||||
This method must be available so os managers can invoke it whenever
|
||||
an user get logged out if a service.
|
||||
|
||||
|
||||
Default implementation does nothing, so if you are going to do nothing,
|
||||
you don't need to implement it.
|
||||
|
||||
The responability of notifying it is of os manager actor, and it's
|
||||
|
||||
The responability of notifying it is of os manager actor, and it's
|
||||
directly invoked by os managers (right now, linux os manager and windows
|
||||
os manager)
|
||||
|
||||
|
||||
The user provided is just an string, that is provided by actor.
|
||||
'''
|
||||
# We do nothing more that remove the user
|
||||
self.storage().remove('user')
|
||||
|
||||
self.storage.remove('user')
|
||||
|
||||
def reasonOfError(self):
|
||||
'''
|
||||
Returns the reason of the error.
|
||||
|
||||
|
||||
Remember that the class is responsible of returning this whenever asked
|
||||
for it, and it will be asked everytime it's needed to be shown to the
|
||||
user (when the administation asks for it).
|
||||
'''
|
||||
return self.storage().readData('error') or 'No error'
|
||||
|
||||
return self.storage.readData('error') or 'No error'
|
||||
|
||||
def destroy(self):
|
||||
'''
|
||||
This is a task method. As that, the excepted return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
|
||||
Invoked for destroying a deployed service
|
||||
Do whatever needed here, as deleting associated data if needed (i.e. a copy of the machine, snapshots, etc...)
|
||||
@return: State.FINISHED if no more checks/steps for deployment are needed, State.RUNNING if more steps are needed (steps checked using checkState)
|
||||
'''
|
||||
'''
|
||||
return State.FINISHED
|
||||
|
||||
def cancel(self):
|
||||
'''
|
||||
This is a task method. As that, the excepted return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
|
||||
This can be invoked directly by an administration or by the clean up
|
||||
of the deployed service (indirectly).
|
||||
When administrator requests it, the cancel is "delayed" and not
|
||||
invoked directly.
|
||||
'''
|
||||
return State.FINISHED
|
||||
|
@ -4,27 +4,27 @@
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@ -40,32 +40,32 @@ logger = logging.getLogger(__name__)
|
||||
class SampleUserDeploymentTwo(UserDeployment):
|
||||
'''
|
||||
This class generates the user consumable elements of the service tree.
|
||||
|
||||
|
||||
This is almost the same as SampleUserDeploymentOne, but differs that this one
|
||||
uses the publication to get data from it, in a very basic way.
|
||||
|
||||
|
||||
After creating at administration interface an Deployed Service, UDS will
|
||||
create consumable services for users using UserDeployment class as
|
||||
provider of this elements.
|
||||
|
||||
|
||||
At class instantiation, this will receive an environment with"generator",
|
||||
that are classes that provides a way to generate unique items.
|
||||
|
||||
|
||||
The generators provided right now are 'mac' and 'name'. To get more info
|
||||
about this, look at py:class:`uds.core.util.UniqueMacGenerator.UniqueNameGenerator`
|
||||
and py:class:`uds.core.util.UniqueNameGenerator.UniqueNameGenerator`
|
||||
|
||||
|
||||
As sample also of environment storage usage, wi will use here the provider
|
||||
storage to keep all our needed info, leaving marshal and unmarshal (needed
|
||||
by Serializable classes, like this) empty (that is, returns '' first and does
|
||||
nothing the second one)
|
||||
|
||||
|
||||
Also Remember, if you don't include this class as the deployedType of the
|
||||
SampleServiceTwo, or whenever you try to access a service of SampleServiceTwo,
|
||||
you will get an exception that says that you haven't included the deployedType.
|
||||
you will get an exception that says that you haven't included the deployedType.
|
||||
'''
|
||||
|
||||
#: Recheck every five seconds by default (for task methods)
|
||||
|
||||
# : Recheck every five seconds by default (for task methods)
|
||||
suggestedTime = 2
|
||||
|
||||
def initialize(self):
|
||||
@ -78,18 +78,18 @@ class SampleUserDeploymentTwo(UserDeployment):
|
||||
self._mac = ''
|
||||
self._error = ''
|
||||
self._count = 0
|
||||
|
||||
# Serializable needed methods
|
||||
|
||||
# Serializable needed methods
|
||||
def marshal(self):
|
||||
'''
|
||||
Marshal own data, in this sample we will marshal internal needed
|
||||
attributes.
|
||||
|
||||
|
||||
In this case, the data will be store with the database record. To
|
||||
minimize database storage usage, we will "zip" data before returning it.
|
||||
Anyway, we should keep this data as low as possible, we also have an
|
||||
storage for loading larger data.
|
||||
|
||||
|
||||
:note: It's a good idea when providing marshalers, to store a 'version'
|
||||
beside the values, so we can, at a later stage, treat with old
|
||||
data for current modules.
|
||||
@ -97,10 +97,10 @@ class SampleUserDeploymentTwo(UserDeployment):
|
||||
data = '\t'.join(['v1', self._name, self._ip, self._mac, self._error,
|
||||
str(self._count)])
|
||||
return data.encode('zip')
|
||||
|
||||
|
||||
def unmarshal(self, str_):
|
||||
'''
|
||||
We unmarshal the content.
|
||||
We unmarshal the content.
|
||||
'''
|
||||
data = str_.decode('zip').split('\t')
|
||||
# Data Version check
|
||||
@ -112,36 +112,36 @@ class SampleUserDeploymentTwo(UserDeployment):
|
||||
|
||||
def getName(self):
|
||||
'''
|
||||
We override this to return a name to display. Default implementation
|
||||
We override this to return a name to display. Default implementation
|
||||
(in base class), returns getUniqueIde() value
|
||||
This name will help user to identify elements, and is only used
|
||||
at administration interface.
|
||||
|
||||
|
||||
We will use here the environment name provided generator to generate
|
||||
a name for this element.
|
||||
|
||||
The namaGenerator need two params, the base name and a length for a
|
||||
|
||||
The namaGenerator need two params, the base name and a length for a
|
||||
numeric incremental part for generating unique names. This are unique for
|
||||
all UDS names generations, that is, UDS will not generate this name again
|
||||
until this name is freed, or object is removed, what makes its environment
|
||||
to also get removed, that makes all unique ids (names and macs right now)
|
||||
to also get released.
|
||||
|
||||
|
||||
Every time get method of a generator gets called, the generator creates
|
||||
a new unique name, so we keep the first generated name cached and don't
|
||||
generate more names. (Generator are simple utility classes)
|
||||
'''
|
||||
if self._name == '':
|
||||
self._name = self.nameGenerator().get( self.publication().getBaseName(),
|
||||
3 )
|
||||
self._name = self.nameGenerator().get(self.publication().getBaseName(),
|
||||
3)
|
||||
# self._name will be stored when object is marshaled
|
||||
return self._name
|
||||
|
||||
|
||||
def setIp(self, ip):
|
||||
'''
|
||||
In our case, there is no OS manager associated with this, so this method
|
||||
will never get called, but we put here as sample.
|
||||
|
||||
|
||||
Whenever an os manager actor notifies the broker the state of the service
|
||||
(mainly machines), the implementation of that os manager can (an probably will)
|
||||
need to notify the IP of the deployed service. Remember that UDS treats with
|
||||
@ -150,17 +150,17 @@ class SampleUserDeploymentTwo(UserDeployment):
|
||||
access it.
|
||||
'''
|
||||
self._ip = ip
|
||||
|
||||
|
||||
def getUniqueId(self):
|
||||
'''
|
||||
Return and unique identifier for this service.
|
||||
In our case, we will generate a mac name, that can be also as sample
|
||||
of 'mac' generator use, and probably will get used something like this
|
||||
at some services.
|
||||
|
||||
|
||||
The get method of a mac generator takes one param, that is the mac range
|
||||
to use to get an unused mac.
|
||||
|
||||
|
||||
The mac generated is not used by anyone, it will not depend on
|
||||
the range, the generator will take care that this mac is unique
|
||||
and in the range provided, or it will return None. The ranges
|
||||
@ -172,119 +172,119 @@ class SampleUserDeploymentTwo(UserDeployment):
|
||||
that id can change with time. (In fact, it's not unique at database level,
|
||||
it's unique in the sense that you must return an unique id that can, for
|
||||
example, be used by os managers to identify this element).
|
||||
|
||||
|
||||
:note: Normally, getting out of macs in the mac pool is a bad thing... :-)
|
||||
'''
|
||||
if self._mac == '':
|
||||
self._mac = self.macGenerator().get( '00:00:00:00:00:00-00:FF:FF:FF:FF:FF' )
|
||||
self._mac = self.macGenerator().get('00:00:00:00:00:00-00:FF:FF:FF:FF:FF')
|
||||
return self._mac
|
||||
|
||||
|
||||
def getIp(self):
|
||||
'''
|
||||
We need to implement this method, so we can return the IP for transports
|
||||
use. If no IP is known for this service, this must return None
|
||||
|
||||
|
||||
If our sample do not returns an IP, IP transport will never work with
|
||||
this service. Remember in real cases to return a valid IP address if
|
||||
the service is accesible and you alredy know that (for example, because
|
||||
the IP has been assigend via setIp by an os manager) or because
|
||||
you get it for some other method.
|
||||
|
||||
you get it for some other method.
|
||||
|
||||
Storage returns None if key is not stored.
|
||||
|
||||
|
||||
:note: Keeping the IP address is responsibility of the User Deployment.
|
||||
Every time the core needs to provide the service to the user, or
|
||||
show the IP to the administrator, this method will get called
|
||||
|
||||
|
||||
'''
|
||||
if self._ip == '':
|
||||
return '192.168.0.34' # Sample IP for testing purposes only
|
||||
return '192.168.0.34' # Sample IP for testing purposes only
|
||||
return self._ip
|
||||
|
||||
def setReady(self):
|
||||
'''
|
||||
This is a task method. As that, the excepted return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
|
||||
The method is invoked whenever a machine is provided to an user, right
|
||||
before presenting it (via transport rendering) to the user.
|
||||
|
||||
This method exist for this kind of situations (i will explain it with a
|
||||
|
||||
This method exist for this kind of situations (i will explain it with a
|
||||
sample)
|
||||
|
||||
|
||||
Imagine a Service tree (Provider, Service, ...) for virtual machines.
|
||||
This machines will get created by the UserDeployment implementation, but,
|
||||
at some time, the machine can be put at in an state (suspend, shut down)
|
||||
that will make the transport impossible to connect with it.
|
||||
|
||||
|
||||
This method, in this case, will check the state of the machine, and if
|
||||
it is "ready", that is, powered on and accessible, it will return
|
||||
it is "ready", that is, powered on and accessible, it will return
|
||||
"State.FINISHED". If the machine is not accessible (has been erased, for
|
||||
example), it will return "State.ERROR" and store a reason of error so UDS
|
||||
can ask for it and present this information to the Administrator.
|
||||
|
||||
|
||||
If the machine powered off, or suspended, or any other state that is not
|
||||
directly usable but can be put in an usable state, it will return
|
||||
"State.RUNNING", and core will use checkState to see when the operation
|
||||
has finished.
|
||||
|
||||
|
||||
I hope this sample is enough to explain the use of this method..
|
||||
'''
|
||||
|
||||
|
||||
# In our case, the service is always ready
|
||||
return State.FINISHED
|
||||
|
||||
|
||||
def deployForUser(self, user):
|
||||
'''
|
||||
Deploys an service instance for an user.
|
||||
|
||||
This is a task method. As that, the excepted return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
|
||||
The user parameter is not realy neded, but provided. It indicates the
|
||||
Database User Object (see py:mod:`uds.modules`) to which this deployed
|
||||
user service will be assigned to.
|
||||
|
||||
|
||||
This method will get called whenever a new deployed service for an user
|
||||
is needed. This will give this class the oportunity to create
|
||||
a service that is assigned to an user.
|
||||
|
||||
|
||||
The way of using this method is as follows:
|
||||
|
||||
|
||||
If the service gets created in "one step", that is, before the return
|
||||
of this method, the consumable service for the user gets created, it
|
||||
will return "State.FINISH".
|
||||
If the service needs more steps (as in this case), we will return
|
||||
If the service needs more steps (as in this case), we will return
|
||||
"State.RUNNING", and if it has an error, it wil return "State.ERROR" and
|
||||
store an error string so administration interface can show it.
|
||||
|
||||
|
||||
We do not use user for anything, as in most cases will be.
|
||||
'''
|
||||
import random
|
||||
|
||||
self._count = 0
|
||||
|
||||
|
||||
# random fail
|
||||
if random.randint(0, 9) == 9:
|
||||
# Note that we can mark this string as translatable, and return
|
||||
# it translated at reasonOfError method
|
||||
self._error = 'Random error at deployForUser :-)'
|
||||
return State.ERROR
|
||||
|
||||
|
||||
return State.RUNNING
|
||||
|
||||
|
||||
def deployForCache(self, cacheLevel):
|
||||
'''
|
||||
Deploys a user deployment as cache.
|
||||
|
||||
This is a task method. As that, the expected return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
|
||||
In our sample, this will do exactly the same as deploy for user,
|
||||
except that it will never will give an error.
|
||||
|
||||
|
||||
See deployForUser for a description of what this method should do.
|
||||
|
||||
|
||||
:note: deployForCache is invoked whenever a new cache element is needed
|
||||
for an specific user deployment. It will also indicate for what
|
||||
cache level (L1, L2) is the deployment
|
||||
@ -296,58 +296,58 @@ class SampleUserDeploymentTwo(UserDeployment):
|
||||
'''
|
||||
This method is invoked whenever the core needs to move from the current
|
||||
cache level to a new cache level an user deployment.
|
||||
|
||||
|
||||
This is a task method. As that, the expected return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
|
||||
We only provide newLevel, because there is only two cache levels, so if
|
||||
newLevel is L1, the actual is L2, and if it is L2, the actual is L1.
|
||||
|
||||
|
||||
Actually there is no possibility to move assigned services again back to
|
||||
cache. If some service needs that kind of functionallity, this must be
|
||||
provided at service level (for example, when doing publishing creating
|
||||
a number of services that will be used, released and reused by users).
|
||||
|
||||
|
||||
Also, user deployments that are at cache level 2 will never get directly
|
||||
assigned to user. First, it will pass to L1 and then it will get assigned.
|
||||
|
||||
|
||||
A good sample of a real implementation of this is moving a virtual machine
|
||||
from a "suspended" state to "running" state to assign it to an user.
|
||||
|
||||
|
||||
In this sample, there is L2 cache also, but moving from L1 to L2 and
|
||||
from L2 to L1 is doing really nothing, so this method will do nothing.
|
||||
|
||||
|
||||
In a real scenario, we will, for example, suspend or resume virtual machine
|
||||
and, return State.RUNNING and at checkState check if this task is completed.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
def checkState(self):
|
||||
'''
|
||||
Our deployForUser method will initiate the consumable service deployment,
|
||||
Our deployForUser method will initiate the consumable service deployment,
|
||||
but will not finish it.
|
||||
|
||||
|
||||
So in our sample, we will only check if a number reaches 5, and if so
|
||||
return that we have finished, else we will return that we are working
|
||||
on it.
|
||||
|
||||
|
||||
One deployForUser returns State.RUNNING, this task will get called until
|
||||
checkState returns State.FINISHED.
|
||||
|
||||
|
||||
Also, we will make the user deployment fail one of every 10 calls to this
|
||||
method.
|
||||
|
||||
Note: Destroying, canceling and deploying for cache also makes use of
|
||||
|
||||
Note: Destroying, canceling and deploying for cache also makes use of
|
||||
this method, so you must keep the info of that you are checking if you
|
||||
need it.
|
||||
|
||||
need it.
|
||||
|
||||
In our case, destroy is 1-step action so this will no get called while
|
||||
destroying, and cancel will simply invoke destroy. Cache deployment is
|
||||
exactly as user deployment, except that the core will not assign it to
|
||||
anyone, and cache moving operations is
|
||||
anyone, and cache moving operations is
|
||||
'''
|
||||
import random
|
||||
|
||||
|
||||
self._count += 1
|
||||
# Count is always a valid value, because this method will never get
|
||||
# called before deployForUser, deployForCache, destroy or cancel.
|
||||
@ -355,112 +355,112 @@ class SampleUserDeploymentTwo(UserDeployment):
|
||||
# so at first call count will be 0.
|
||||
if self._count >= 5:
|
||||
return State.FINISHED
|
||||
|
||||
|
||||
# random fail
|
||||
if random.randint(0, 9) == 9:
|
||||
self._error = 'Random error at checkState :-)'
|
||||
return State.ERROR
|
||||
|
||||
|
||||
return State.RUNNING
|
||||
|
||||
|
||||
def finish(self):
|
||||
'''
|
||||
Invoked when the core notices that the deployment of a service has finished.
|
||||
(No matter whether it is for cache or for an user)
|
||||
|
||||
|
||||
This gives the opportunity to make something at that moment.
|
||||
|
||||
|
||||
:note: You can also make these operations at checkState, this is really
|
||||
not needed, but can be provided (default implementation of base class does
|
||||
nothing)
|
||||
nothing)
|
||||
'''
|
||||
# We set count to 0, not needed but for sample purposes
|
||||
self._count = 0
|
||||
|
||||
|
||||
def assignToUser(self, user):
|
||||
'''
|
||||
This method is invoked whenever a cache item gets assigned to an user.
|
||||
This is not a task method right now, simply a notification. This means
|
||||
that L1 cache items must be directly usable (except for the readyness part)
|
||||
by users in a single step operation.
|
||||
|
||||
|
||||
Note that there will be an setReady call before letting the user consume
|
||||
this user deployment, so this is more informational (so, if you keep at
|
||||
what cache level is this instance, you can update it) than anything else.
|
||||
|
||||
|
||||
This is not a task method. All level 1 cache items can be dircetly
|
||||
assigned to an user with no more work needed, but, if something is needed,
|
||||
here you can do whatever you need.
|
||||
|
||||
|
||||
user is a Database user object.
|
||||
'''
|
||||
logger.debug('Assigned to user {0}'.format(user))
|
||||
|
||||
|
||||
def userLoggedIn(self, user):
|
||||
'''
|
||||
This method must be available so os managers can invoke it whenever
|
||||
an user get logged into a service.
|
||||
|
||||
|
||||
Default implementation does nothing, so if you are going to do nothing,
|
||||
you don't need to implement it.
|
||||
|
||||
The responsibility of notifying it is of os manager actor, and it's
|
||||
|
||||
The responsibility of notifying it is of os manager actor, and it's
|
||||
directly invoked by os managers (right now, linux os manager and windows
|
||||
os manager)
|
||||
|
||||
|
||||
The user provided is just an string, that is provided by actors.
|
||||
'''
|
||||
# We store the value at storage, but never get used, just an example
|
||||
self.storage().saveData('user', user)
|
||||
|
||||
self.storage.saveData('user', user)
|
||||
|
||||
def userLoggedOut(self, user):
|
||||
'''
|
||||
This method must be available so os managers can invoke it whenever
|
||||
an user get logged out if a service.
|
||||
|
||||
|
||||
Default implementation does nothing, so if you are going to do nothing,
|
||||
you don't need to implement it.
|
||||
|
||||
The responability of notifying it is of os manager actor, and it's
|
||||
|
||||
The responability of notifying it is of os manager actor, and it's
|
||||
directly invoked by os managers (right now, linux os manager and windows
|
||||
os manager)
|
||||
|
||||
|
||||
The user provided is just an string, that is provided by actor.
|
||||
'''
|
||||
# We do nothing more that remove the user
|
||||
self.storage().remove('user')
|
||||
|
||||
self.storage.remove('user')
|
||||
|
||||
def reasonOfError(self):
|
||||
'''
|
||||
Returns the reason of the error.
|
||||
|
||||
|
||||
Remember that the class is responsible of returning this whenever asked
|
||||
for it, and it will be asked everytime it's needed to be shown to the
|
||||
user (when the administation asks for it).
|
||||
|
||||
|
||||
:note: Remember that you can use ugettext to translate this error to
|
||||
user language whenever it is possible. (This one will get invoked
|
||||
directly from admin interface and, as so, will have translation
|
||||
environment correctly set up.
|
||||
'''
|
||||
return self._error
|
||||
|
||||
|
||||
def destroy(self):
|
||||
'''
|
||||
This is a task method. As that, the excepted return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
|
||||
Invoked for destroying a deployed service
|
||||
Do whatever needed here, as deleting associated data if needed (i.e. a copy of the machine, snapshots, etc...)
|
||||
@return: State.FINISHED if no more checks/steps for deployment are needed, State.RUNNING if more steps are needed (steps checked using checkState)
|
||||
'''
|
||||
'''
|
||||
return State.FINISHED
|
||||
|
||||
def cancel(self):
|
||||
'''
|
||||
This is a task method. As that, the excepted return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
|
||||
This can be invoked directly by an administration or by the clean up
|
||||
of the deployed service (indirectly).
|
||||
When administrator requests it, the cancel is "delayed" and not
|
||||
|
@ -1,6 +1,6 @@
|
||||
{% extends "uds/admin/tmpl/fld/form-group.html" %}
|
||||
{% block field %}
|
||||
{% verbatim %}
|
||||
<input type="{% endverbatim %}{% block type %}text{% endblock %}{% verbatim %}" class="form-control {{ css }}" name="{{ name }}" id="{{ name }}_field" placeholder="{{ tooltip }}" value="{{ value }}"{{# if readonly }} readonly{{/ if }} {{# if required }} required {{/ if }} data-minval="{{ minValue }}" data-maxVal="{{ maxValue }}" tabindex="{{ index }}">
|
||||
<input type="{% endverbatim %}{% block type %}text{% endblock %}{% verbatim %}" class="form-control {{ css }}" name="{{ name }}" id="{{ name }}_field" placeholder="{{ tooltip }}" value="{{ value }}"{{# if readonly }} readonly{{/ if }} {{# if required }} required {{/ if }} data-minval="{{ minValue }}" data-maxVal="{{ maxValue }}" {{# unless readonly }}tabindex="{{ index }}"{{/ unless }}>
|
||||
{% endverbatim %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
@ -2,13 +2,13 @@
|
||||
{% load i18n %}
|
||||
{% block field %}
|
||||
{% verbatim %}
|
||||
<input type="checkbox"
|
||||
data-on-text="{% endverbatim %}{% trans 'Yes' %}{% verbatim %}"
|
||||
<input type="checkbox"
|
||||
data-on-text="{% endverbatim %}{% trans 'Yes' %}{% verbatim %}"
|
||||
data-off-text="{% endverbatim %}{% trans 'No' %}{% verbatim %}"
|
||||
class="{{ css }}"
|
||||
name="{{ name }}"
|
||||
id="{{ name }}_field"{{# ifequals value true }} checked{{/ ifequals }}{{# if readonly }} disabled{{/ if }}
|
||||
tabindex="{{ index }}">
|
||||
{{# unless readonly }}tabindex="{{ index }}"{{/ unless }}>
|
||||
|
||||
{% endverbatim %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
@ -3,7 +3,7 @@
|
||||
{% block field %}
|
||||
{% verbatim %}
|
||||
<div class="input-group date">
|
||||
<input type="date" class="form-control {{ css }}" name="{{ name }}" id="{{ name }}_field" placeholder="{{ tooltip }}" value="{{ value }}"{{# if readonly }} readonly{{/ if }} {{# if required }} required {{/ if }} data-minval="{{ minValue }}" tabindex="{{ index }}"><span class="input-group-addon"><i class="glyphicon glyphicon-th"></i></span>
|
||||
<input type="date" class="form-control {{ css }}" name="{{ name }}" id="{{ name }}_field" placeholder="{{ tooltip }}" value="{{ value }}"{{# if readonly }} readonly{{/ if }} {{# if required }} required {{/ if }} data-minval="{{ minValue }}" {{# unless readonly }}tabindex="{{ index }}"{{/ unless }}><span class="input-group-addon"><i class="glyphicon glyphicon-th"></i></span>
|
||||
</div>
|
||||
|
||||
{% endverbatim %}
|
||||
|
@ -87,14 +87,14 @@ class HTML5RDPTransport(Transport):
|
||||
Override this in yours transports
|
||||
'''
|
||||
logger.debug('Checking availability for {0}'.format(ip))
|
||||
ready = self.cache().get(ip)
|
||||
ready = self.cache.get(ip)
|
||||
if ready is None:
|
||||
# Check again for readyness
|
||||
if connection.testServer(ip, '3389') is True:
|
||||
self.cache().put(ip, 'Y', READY_CACHE_TIMEOUT)
|
||||
self.cache.put(ip, 'Y', READY_CACHE_TIMEOUT)
|
||||
return True
|
||||
else:
|
||||
self.cache().put(ip, 'N', READY_CACHE_TIMEOUT)
|
||||
self.cache.put(ip, 'N', READY_CACHE_TIMEOUT)
|
||||
return ready == 'Y'
|
||||
|
||||
def processedUser(self, userService, userName):
|
||||
|
@ -151,14 +151,14 @@ class NXTransport(Transport):
|
||||
Override this in yours transports
|
||||
'''
|
||||
logger.debug('Checking availability for {0}'.format(ip))
|
||||
ready = self.cache().get(ip)
|
||||
ready = self.cache.get(ip)
|
||||
if ready is None:
|
||||
# Check again for readyness
|
||||
if connection.testServer(ip, self._listenPort) is True:
|
||||
self.cache().put(ip, 'Y', READY_CACHE_TIMEOUT)
|
||||
self.cache.put(ip, 'Y', READY_CACHE_TIMEOUT)
|
||||
return True
|
||||
else:
|
||||
self.cache().put(ip, 'N', READY_CACHE_TIMEOUT)
|
||||
self.cache.put(ip, 'N', READY_CACHE_TIMEOUT)
|
||||
return ready == 'Y'
|
||||
|
||||
def getScript(self, script):
|
||||
|
@ -166,14 +166,14 @@ class TSNXTransport(Transport):
|
||||
Override this in yours transports
|
||||
'''
|
||||
logger.debug('Checking availability for {0}'.format(ip))
|
||||
ready = self.cache().get(ip)
|
||||
ready = self.cache.get(ip)
|
||||
if ready is None:
|
||||
# Check again for readyness
|
||||
if connection.testServer(ip, self._listenPort) is True:
|
||||
self.cache().put(ip, 'Y', READY_CACHE_TIMEOUT)
|
||||
self.cache.put(ip, 'Y', READY_CACHE_TIMEOUT)
|
||||
return True
|
||||
else:
|
||||
self.cache().put(ip, 'N', READY_CACHE_TIMEOUT)
|
||||
self.cache.put(ip, 'N', READY_CACHE_TIMEOUT)
|
||||
return ready == 'Y'
|
||||
|
||||
def getScript(self, script):
|
||||
|
@ -42,7 +42,7 @@ from uds.core.util import connection
|
||||
import logging
|
||||
import os
|
||||
|
||||
__updated__ = '2015-05-14'
|
||||
__updated__ = '2016-02-26'
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -77,14 +77,14 @@ class BaseRDPTransport(Transport):
|
||||
Override this in yours transports
|
||||
'''
|
||||
logger.debug('Checking availability for {0}'.format(ip))
|
||||
ready = self.cache().get(ip)
|
||||
ready = self.cache.get(ip)
|
||||
if ready is None:
|
||||
# Check again for ready
|
||||
if connection.testServer(ip, '3389') is True:
|
||||
self.cache().put(ip, 'Y', READY_CACHE_TIMEOUT)
|
||||
self.cache.put(ip, 'Y', READY_CACHE_TIMEOUT)
|
||||
return True
|
||||
else:
|
||||
self.cache().put(ip, 'N', READY_CACHE_TIMEOUT)
|
||||
self.cache.put(ip, 'N', READY_CACHE_TIMEOUT)
|
||||
return ready == 'Y'
|
||||
|
||||
def processedUser(self, userService, userName):
|
||||
|
Loading…
x
Reference in New Issue
Block a user