1
0
mirror of https://github.com/dkmstr/openuds.git synced 2024-12-22 13:34:04 +03:00

BIG work on pep8 adaption (easier to read, easier to maintain, etc..)

This commit is contained in:
Adolfo Gómez 2014-02-25 03:12:00 +00:00
parent 89addaf585
commit 06ff8e32be
68 changed files with 2889 additions and 2829 deletions

View File

@ -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.
'''
@ -32,7 +32,7 @@
'''
from __future__ import unicode_literals
#from django.utils import simplejson as json
# from django.utils import simplejson as json
import ujson as json
import datetime
import time
@ -47,26 +47,26 @@ logger = logging.getLogger(__name__)
class ParametersException(Exception):
pass
class ContentProcessor(object):
mime_type = None
extensions = None
def __init__(self, request):
self._request = request
def processGetParameters(self):
if self._request.method != 'GET':
return {}
return self._request.GET.copy()
def processParameters(self):
return ''
def getResponse(self, obj):
return http.HttpResponse(content = self.render(obj), content_type=self.mime_type + "; charset=utf-8")
return http.HttpResponse(content=self.render(obj), content_type=self.mime_type + "; charset=utf-8")
def render(self, obj):
return unicode(obj)
@ -93,13 +93,14 @@ class ContentProcessor(object):
return int(time.mktime(obj.timetuple()))
return unicode(obj)
# ---------------
# Json Processor
# ---------------
class JsonProcessor(ContentProcessor):
mime_type = 'application/json'
extensions = ['json']
def processParameters(self):
try:
if len(self._request.body) == 0:
@ -111,22 +112,22 @@ class JsonProcessor(ContentProcessor):
logger.error('parsing json: {0}'.format(e))
raise ParametersException(unicode(e))
def render(self, obj):
return json.dumps( ContentProcessor.procesForRender(obj))
#return json.dumps(obj)
return json.dumps(ContentProcessor.procesForRender(obj))
# return json.dumps(obj)
# ---------------
# Json Processor
# XML Processor
# ---------------
class XMLProcessor(ContentProcessor):
mime_type = 'application/xml'
extensions = ['xml']
def processParameters(self):
return ''
processors_list = (JsonProcessor,XMLProcessor)
processors_list = (JsonProcessor, XMLProcessor)
default_processor = JsonProcessor
available_processors_mime_dict = dict((cls.mime_type, cls) for cls in processors_list)
available_processors_ext_dict = {}

View File

@ -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.
'''
@ -36,36 +36,40 @@ from django.utils.translation import ugettext as _
from uds.core.ui.UserInterface import UserInterface
from uds.core import Environmentable
from uds.core import Serializable
import base64, os.path, sys, logging
import base64
import os.path
import sys
import logging
logger = logging.getLogger(__name__)
class Module(UserInterface, Environmentable, Serializable):
'''
Base class for all modules used by UDS.
This base module provides all the needed methods that modules must implement
All modules must, at least, implement the following:
* Attributes:
* :py:attr:`.typeName`:
* :py:attr:`.typeName`:
Name for this type of module (human readable) to assign to the module (string)
This name will be used to let the administrator identify this module.
* :py:attr:`.typeType`:
* :py:attr:`.typeType`:
Name for this type of module (machine only) to assing to the module (string)
This name will be used internally to identify when a serialized module corresponds with this class.
* :py:attr:`.typeDescription`:
* :py:attr:`.typeDescription`:
Description for this type of module.
This descriptio will be used to let the administrator identify what this module provides
* :py:attr:`.iconFile`: This is an icon file, in png format, used at administration client to identify this module.
This parameter may be optionall if you override the "icon" method.
* Own Methods:
* Own Methods:
* :py:meth:`.__init__`
The default constructor. The environment value is always provided (see Environment), but the
default values provided can be None.
Remember to allow the instantiation of the module with default params, because when deserialization is done,
the process is first instatiate with an environment but no parameters and then call "unmarshal" from Serializable.
* :py:meth:`.test`
* :py:meth:`.test`
* :py:meth:`.check`
* :py:meth:`.destroy`: Optional
* :py:meth:`.icon`: Optional, if you provide an icon file, this method loads it from module folder,
@ -73,101 +77,100 @@ class Module(UserInterface, Environmentable, Serializable):
* :py:meth:`.marshal`
By default, this method serializes the values provided by user in form fields. You can override it,
but now it's not needed because you can access config vars using Form Fields.
Anyway, if you override this method, you must also override next one
* :py:meth:`.unmarshal`
By default, this method de-serializes the values provided by user in form fields. You can override it,
but now it's not needed because you can access config vars using Form Fields.
Anyway, if you override this method, you must also override previous one
* UserInterface Methods:
* :py:meth:`uds.core.ui.UserInterface.UserInterface.valuesDict`
This method, by default, provides the values contained in the form fields. If you don't override the marshal and
unmarshal, this method should be fine as is for you also.
Environmentable is a base class that provides utility method to access a separate Environment for every single
module.
'''
#: Which coded to use to encode module by default.
#: This overrides the Environmentable and Serializable Attribute, but in all cases we are using 'base64'
# : Which coded to use to encode module by default.
# : This overrides the Environmentable and Serializable Attribute, but in all cases we are using 'base64'
CODEC = 'base64' # Can be zip, hez, bzip, base64, uuencoded
#: Basic name used to provide the administrator an "huma readable" form for the module
typeName = 'Base Module'
#: Internal type name, used by system to locate this module
# : Basic name used to provide the administrator an "huma readable" form for the module
typeName = 'Base Module'
# : Internal type name, used by system to locate this module
typeType = 'BaseModule'
#: Description of this module, used at admin level
# : Description of this module, used at admin level
typeDescription = 'Base Module'
#: Icon file, relative to module folders
# : Icon file, relative to module folders
iconFile = 'base.png' # This is expected to be png, use this format always
class ValidationException(Exception):
'''
Exception used to indicate that the params assigned are invalid
'''
@classmethod
def name(cls):
'''
Returns "translated" typeName, using ugettext for transforming
Returns "translated" typeName, using ugettext for transforming
cls.typeName
Args:
cls: This is a class method, so cls is the class
Returns:
Translated type name (using ugettext)
'''
return _(cls.typeName)
@classmethod
def type(cls):
'''
Returns typeType
Args:
cls: This is a class method, so cls is the class
Returns:
the typeType of this class (or derived class)
'''
return cls.typeType
@classmethod
def description(cls):
'''
This method returns the "translated" description, that is, using
This method returns the "translated" description, that is, using
ugettext for transforming cls.typeDescription.
Args:
cls: This is a class method, so cls is the class
Returns:
Translated description (using ugettext)
Translated description (using ugettext)
'''
return _(cls.typeDescription)
@classmethod
def icon(cls, inBase64 = True):
def icon(cls, inBase64=True):
'''
Reads the file specified by iconFile at module folder, and returns it content.
This is used to obtain an icon so administration can represent it.
Args:
cls: Class
inBase64: If true, the image will be returned as base 64 encoded
Returns:
Base 64 encoded or raw image, obtained from the specified file at
Base 64 encoded or raw image, obtained from the specified file at
'iconFile' class attribute
'''
logger.debug('Loading icon for class {0} ({1})'.format(cls, cls.iconFile))
file_ = open( os.path.dirname(sys.modules[cls.__module__].__file__) + '/' + cls.iconFile, 'rb')
file_ = open(os.path.dirname(sys.modules[cls.__module__].__file__) + '/' + cls.iconFile, 'rb')
data = file_.read()
file_.close()
if inBase64 == True:
@ -179,101 +182,100 @@ class Module(UserInterface, Environmentable, Serializable):
def test(env, data):
'''
Test if the connection data is ok.
Returns an array, first value indicates "Ok" if true, "Bad" or "Error"
Returns an array, first value indicates "Ok" if true, "Bad" or "Error"
if false. Second is a string describing operation
Args:
env: environment passed for testing (temporal environment passed)
data: data passed for testing (data obtained from the form
data: data passed for testing (data obtained from the form
definition)
Returns:
Array of two elements, first is True of False, depending on test
Returns:
Array of two elements, first is True of False, depending on test
(True is all right, false is error),
second is an String with error, preferably internacionalizated..
'''
return [True, _("No connection checking method is implemented.")]
def __init__(self, environment, values = None):
def __init__(self, environment, values=None):
'''
Do not forget to invoke this in your derived class using
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.
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
cache and storage are "convenient" methods to access _env.cache() and
_env.storage()
The values param is passed directly to UserInterface base.
The environment param is passed directly to environment.
Values are passed to __initialize__ method. It this is not None,
Values are passed to __initialize__ method. It this is not None,
the values contains a dictionary of values received from administration gui,
that contains the form data requested from user.
If you override marshal, unmarshal and inherited UserInterface method
valuesDict, you must also take account of values (dict) provided at the
If you override marshal, unmarshal and inherited UserInterface method
valuesDict, you must also take account of values (dict) provided at the
__init__ method of your class.
'''
#
UserInterface.__init__(self, values)
Environmentable.__init__(self, environment)
Serializable.__init__(self)
def __str__(self):
return "Base Module"
def isDirty(self):
'''
This method informs the core if the module has changed serializable data,
This method informs the core if the module has changed serializable data,
and that must be re-serialized
Default implemetation is that on every method call, module will be dirty
Note: The implementation of this is a work in progress, so right now the module will be serialized out on every acess
'''
return True
def marshal(self):
'''
By default and if not overriden by descendants, this method, overridden
By default and if not overriden by descendants, this method, overridden
from Serializable, and returns the serialization of
form field stored values.
'''
return self.serializeForm()
def unmarshal(self, str_):
'''
By default and if not overriden by descendants, this method recovers
By default and if not overriden by descendants, this method recovers
data serialized using serializeForm
'''
self.unserializeForm(str_)
def check(self):
'''
Method that will provide the "check" capability for the module.
The return value that this method must provide is simply an string,
The return value that this method must provide is simply an string,
preferable internacionalizated.
Returns:
Internacionalized (using ugettext) string of result of the check.
'''
return _("No check method provided.")
def destroy(self):
'''
Invoked before deleting an module from database.
Do whatever needed here, as deleting associated data if needed
Do whatever needed here, as deleting associated data if needed
(no example come to my head right now... :-) )
Returns:
Nothing
'''
'''
pass

View File

@ -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.
'''
@ -35,74 +35,73 @@ from __future__ import unicode_literals
TEMP_ENV = 'temporary'
GLOBAL_ENV = 'global'
class Environment(object):
'''
Class to manipulate the associated environment with "environmentable" classes (mainly modules).
It purpose is to provide an "object owned" environment, so every db record can contain associated values
not stored with main module data.
not stored with main module data.
The environment is composed of a "cache" and a "storage". First are volatile data, while second are persistent data.
'''
def __init__(self, uniqueKey, idGenerators = {}):
def __init__(self, uniqueKey, idGenerators={}):
'''
Initialized the Environment for the specified id
@param uniqueId: Key for this environment
@param idGenerators: Hash of generators of ids for this environment. This "generators of ids" feature
is used basically at User Services to auto-create ids for macs or names, using
{'mac' : UniqueMacGenerator, 'name' : UniqueNameGenerator } as argument.
is used basically at User Services to auto-create ids for macs or names, using
{'mac' : UniqueMacGenerator, 'name' : UniqueNameGenerator } as argument.
'''
from uds.core.util.Cache import Cache
from uds.core.util.Storage import Storage
from uds.core.util.Storage import Storage
self._key = uniqueKey
self._cache = Cache(uniqueKey)
self._storage = Storage(uniqueKey)
self._idGenerators = idGenerators
def cache(self):
'''
Method to acces the cache of the environment.
@return: a referente to a Cache instance
'''
return self._cache
def storage(self):
'''
Method to acces the cache of the environment.
@return: a referente to an Storage Instance
'''
return self._storage
def idGenerators(self, generatorId):
'''
The idea of generator of id is to obtain at some moment Ids with a proper generator.
If the environment do not contains generators of id, this method will return None.
The id generator feature is used by User Services to obtain different auto-id generators, as macs or names
@param generatorId: Id of the generator to obtain
@return: Generator for that id, or None if no generator for that id is found
@return: Generator for that id, or None if no generator for that id is found
'''
if self._idGenerators.has_key(generatorId):
return self._idGenerators[generatorId]
return None
return self._idGenerators.get(generatorId, None)
def key(self):
'''
@return: the key used for this environment
'''
return self._key
def clearRelatedData(self):
'''
Removes all related information from database for this environment.
'''
from uds.core.util.Cache import Cache
from uds.core.util.Storage import Storage
from uds.core.util.Storage import Storage
Cache.delete(self._key)
Storage.delete(self._key)
for __, v in self._idGenerators.iteritems():
v.release()
@staticmethod
def getEnvForTableElement(tblName, id_, idGeneratorsTypes = {}):
def getEnvForTableElement(tblName, id_, idGeneratorsTypes={}):
'''
From a table name, and a id, tries to load the associated environment or creates a new
one if no environment exists at database. The table name and the id are used to obtain the key
@ -114,10 +113,10 @@ class Environment(object):
'''
name = 't-' + tblName + '-' + str(id_)
idGenerators = {}
for k,v in idGeneratorsTypes.iteritems():
for k, v in idGeneratorsTypes.iteritems():
idGenerators[k] = v(name)
return Environment(name, idGenerators)
@staticmethod
def getEnvForType(type_):
'''
@ -125,82 +124,82 @@ class Environment(object):
@param type_: Type
@return Associated Environment
'''
return Environment('type-'+str(type_))
return Environment('type-' + str(type_))
@staticmethod
def getTempEnv():
'''
Provides a temporary environment needed in some calls (test provider, for example)
It will not make environment persistent
It will not make environment persistent
'''
return Environment(TEMP_ENV) # TODO: In fact, we should provide a "null" cache and a "null" storage, but for now this is right
return Environment(TEMP_ENV) # TODO: In fact, we should provide a "null" cache and a "null" storage, but for now this is right
@staticmethod
def getGlobalEnv():
'''
Provides global environment
'''
return Environment(GLOBAL_ENV) # This environment is a global environment for general utility.
return Environment(GLOBAL_ENV) # This environment is a global environment for general utility.
class Environmentable(object):
'''
This is a base class provided for all objects that have an environment associated. These are mainly modules
'''
def __init__(self, environment):
'''
Initialized the element
Args:
environment: Environment to associate with
'''
self._env = environment
def setEnv(self, environment):
'''
Assigns a new environment
Args:
environment: Environment to assign
environment: Environment to assign
'''
self._env = environment
def env(self):
'''
Utility method to access the envionment contained by this object
Returns:
Environmnet for the object
'''
return self._env
def cache(self):
'''
Utility method to access the cache of the environment containe by this object
Returns:
Cache for the object
'''
return self._env.cache()
def storage(self):
'''
Utility method to access the storage of the environment containe by this object
Returns:
Storage for the object
'''
return self._env.storage()
def idGenerators(self, generatorId):
'''
Utility method to access the id generator of the environment containe by this object
Args:
generatorId: Id of the generator to obtain
generatorId: Id of the generator to obtain
Returns:
Generator for the object and the id specified
'''
return self._env.idGenerators(generatorId)

View File

@ -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.
'''
@ -36,7 +36,7 @@ from __future__ import unicode_literals
class Serializable(object):
'''
This class represents the interface that all serializable objects must provide.
Every single serializable class must implement marshall & unmarshall methods. Also, the class must allow
to be initialized without parameters, so we can:
- Initialize the object with default values
@ -44,53 +44,52 @@ class Serializable(object):
'''
# Codify codec constant
CODEC = 'base64' # Can be zip, hez, bzip, base64, uuencoded
def __init__(self):
pass
def marshal(self):
'''
This is the method that must be overriden in order to serialize an object.
This is the method that must be overriden in order to serialize an object.
The system will use in fact 'seralize' and 'deserialize' methods, but theese are
only suitable methods to "codify" serialized values
:note: This method must be overridden
'''
raise Exception('Base marshaler called!!!')
def unmarshal(self, str_):
'''
This is the method that must be overriden in order to unserialize an object.
This is the method that must be overriden in order to unserialize an object.
The system will use in fact 'seralize' and 'deserialize' methods, but theese are
only convenients methods to "codify" serialized values.
Take into account that _str can be '' (empty string), but hopefully it will never be none.
Take into account that _str can be '' (empty string), but hopefully it will never be none.
In that case, initialize the object with default values
Args:
str_ _ : String readed from persistent storage to deseralilize
:note: This method must be overridden
'''
raise Exception('Base unmarshaler called!!!')
def serialize(self):
'''
Serializes and "obfuscates' the data.
The codec used to encode the string is obtained from the instance CODEC, so derived classes can
The codec used to encode the string is obtained from the instance CODEC, so derived classes can
overwrite this attribute to set another codec
'''
return self.marshal().encode(self.CODEC)
def unserialize(self, str_):
'''
des-obfuscates the data and then de-serializes it via unmarshal method
The codec used to decode the string is obtained from the instance CODEC, so derived classes can
The codec used to decode the string is obtained from the instance CODEC, so derived classes can
overwrite this attribute to set another codec
'''
return self.unmarshal(str_.decode(self.CODEC))

View File

@ -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.
'''
@ -32,6 +32,7 @@ Core of UDS.
This package contains all core-related code for UDS
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
# Core needs tasks manager to register scheduled jobs, so we ensure of that here
from Environment import Environmentable
@ -40,4 +41,3 @@ from BaseModule import Module
import services
import auths
import transports

View File

@ -56,7 +56,7 @@ class JobsFactory(object):
return self._jobs
def insert(self, name, type_):
logger.debug('Inserting job {0} of type {1}'.format(name, type_))
logger.debug('Inserting job {0} of type_ {1}'.format(name, type_))
try:
self._jobs[name] = type_
except Exception, e:

View File

@ -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.
'''
@ -36,7 +36,8 @@ from django.conf import settings
from Crypto.PublicKey import RSA
from OpenSSL import crypto
from Crypto.Random import atfork
import hashlib, array
import hashlib
import array
import logging
@ -48,24 +49,25 @@ logger = logging.getLogger(__name__)
# import os
# RSA.generate(1024, os.urandom).exportKey()
class CryptoManager(object):
CODEC = 'base64'
CODEC = 'base64'
instance = None
def __init__(self):
self._rsa = RSA.importKey(settings.RSA_KEY)
@staticmethod
def manager():
if CryptoManager.instance is None:
CryptoManager.instance = CryptoManager()
return CryptoManager.instance
def encrypt(self, string):
atfork()
return self._rsa.encrypt(string.encode('utf-8'), '')[0].encode(CryptoManager.CODEC)
def decrypt(self, string):
try:
atfork()
@ -73,32 +75,31 @@ class CryptoManager(object):
except:
logger.exception('Decripting')
return 'decript error'
def xor(self, s1, s2):
s1, s2 = s1.encode('utf-8'), s2.encode('utf-8')
mult = (len(s1)/len(s2)) + 1
mult = (len(s1) / len(s2)) + 1
s1 = array.array(b'B', s1)
s2 = array.array(b'B', s2 * mult)
return array.array(b'B', (s1[i] ^ s2[i] for i in range(len(s1)))).tostring()
return array.array(b'B', (s1[i] ^ s2[i] for i in range(len(s1)))).tostring()
def loadPrivateKey(self, rsaKey):
try:
pk = RSA.importKey(rsaKey)
except Exception as e:
raise e
return pk
def loadCertificate(self,certificate):
def loadCertificate(self, certificate):
try:
cert = crypto.load_certificate(crypto.FILETYPE_PEM, certificate)
except crypto.Error as e:
raise Exception(e.message[0][2])
return cert
return cert
def certificateString(self, certificate):
return certificate.replace('-----BEGIN CERTIFICATE-----', '').replace('-----END CERTIFICATE-----', '').replace('\n', '')
def hash(self, string):
if string is '' or string is None:
return ''

View File

@ -4,92 +4,92 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
import os, tempfile, zipfile, uuid
import os
import uuid
from django.http import HttpResponse, Http404
from django.core.servers.basehttp import FileWrapper
import logging
logger = logging.getLogger(__name__)
class DownloadsManager(object):
'''
Manager so connectors can register their own downloadables
For registering, use at __init__.py of the conecto something like this:
from uds.core.managers.DownloadsManager import DownloadsManager
import os.path, sys
DownloadsManager.manager().registerDownloadable('test.exe',
DownloadsManager.manager().registerDownloadable('test.exe',
_('comments for test'),
os.path.dirname(sys.modules[__package__].__file__) + '/files/test.exe',
'application/x-msdos-program')
os.path.dirname(sys.modules[__package__].__file__) + '/files/test.exe',
'application/x-msdos-program')
'''
_manager = None
def __init__(self):
self._downloadables = {}
self._namespace = uuid.UUID('627a37a5-e8db-431a-b783-73f7d20b4934')
@staticmethod
def manager():
if DownloadsManager._manager == None:
DownloadsManager._manager = DownloadsManager()
return DownloadsManager._manager
def registerDownloadable(self, name, comment, path, mime = 'application/octet-stream'):
def registerDownloadable(self, name, comment, path, mime='application/octet-stream'):
'''
Registers a downloadable file.
@param name: name shown
@param path: path to file
@params zip: If download as zip
@params zip: If download as zip
'''
_id = str(uuid.uuid5(self._namespace, name))
self._downloadables[_id] = { 'name': name, 'comment' : comment, 'path' : path, 'mime' : mime }
self._downloadables[_id] = {'name': name, 'comment': comment, 'path': path, 'mime': mime}
def getDownloadables(self):
return self._downloadables
def send(self, request, _id):
if self._downloadables.has_key(_id) is False:
if _id not in self._downloadables:
return Http404()
return self.__send_file(request, self._downloadables[_id]['name'], self._downloadables[_id]['path'], self._downloadables[_id]['mime']);
return self.__send_file(request, self._downloadables[_id]['name'], self._downloadables[_id]['path'], self._downloadables[_id]['mime'])
def __send_file(self, request, name, filename, mime):
"""
Send a file through Django without loading the whole file into
memory at once. The FileWrapper will turn the file object into an
iterator for chunks of 8KB.
"""
Send a file through Django without loading the whole file into
memory at once. The FileWrapper will turn the file object into an
iterator for chunks of 8KB.
"""
wrapper = FileWrapper(file(filename))
response = HttpResponse(wrapper, content_type=mime)
response['Content-Length'] = os.path.getsize(filename)
response['Content-Disposition'] = 'attachment; filename=' + name
return response

View File

@ -3,33 +3,33 @@
# Copyright (c) 2013 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from uds.models import UserService
from uds.models import DeployedServicePublication
@ -52,25 +52,26 @@ OT_USERSERVICE, OT_PUBLICATION, OT_DEPLOYED_SERVICE, OT_SERVICE, OT_PROVIDER, OT
# Dict for translations
transDict = {
UserService : OT_USERSERVICE,
DeployedServicePublication : OT_PUBLICATION,
DeployedService : OT_DEPLOYED_SERVICE,
Service : OT_SERVICE,
Provider : OT_PROVIDER,
User : OT_USER,
Group : OT_GROUP,
Authenticator : OT_AUTHENTICATOR
UserService: OT_USERSERVICE,
DeployedServicePublication: OT_PUBLICATION,
DeployedService: OT_DEPLOYED_SERVICE,
Service: OT_SERVICE,
Provider: OT_PROVIDER,
User: OT_USER,
Group: OT_GROUP,
Authenticator: OT_AUTHENTICATOR
}
class LogManager(object):
'''
Manager for logging (at database) events
'''
_manager = None
def __init__(self):
pass
@staticmethod
def manager():
if LogManager._manager == None:
@ -83,87 +84,83 @@ class LogManager(object):
'''
from uds.models import getSqlDatetime
from uds.models import Log
qs = Log.objects.filter(owner_id = owner_id, owner_type = owner_type)
qs = Log.objects.filter(owner_id=owner_id, owner_type=owner_type)
# First, ensure we do not have more than requested logs, and we can put one more log item
if qs.count() >= GlobalConfig.MAX_LOGS_PER_ELEMENT.getInt():
for i in qs.order_by('-created',)[GlobalConfig.MAX_LOGS_PER_ELEMENT.getInt()-1:]:
for i in qs.order_by('-created',)[GlobalConfig.MAX_LOGS_PER_ELEMENT.getInt() - 1:]:
i.delete()
if avoidDuplicates is True:
try:
lg = Log.objects.filter(owner_id = owner_id, owner_type = owner_type, level = level, source = source).order_by('-created', '-id')[0]
lg = Log.objects.filter(owner_id=owner_id, owner_type=owner_type, level=level, source=source).order_by('-created', '-id')[0]
if lg.message == message:
# Do not log again, already logged
return
except: # Do not exists log
except: # Do not exists log
pass
# now, we add new log
try:
Log.objects.create(owner_type = owner_type, owner_id = owner_id, created = getSqlDatetime(), source = source, level = level, data = message)
Log.objects.create(owner_type=owner_type, owner_id=owner_id, created=getSqlDatetime(), source=source, level=level, data=message)
except:
# Some objects will not get logged, such as System administrator objects
pass
def __getLogs(self, owner_type, owner_id, limit):
'''
Get all logs associated with an user service, ordered by date
'''
from uds.models import Log
qs = Log.objects.filter(owner_id = owner_id, owner_type = owner_type)
qs = Log.objects.filter(owner_id=owner_id, owner_type=owner_type)
return [{'date': x.created, 'level': x.level, 'source': x.source, 'message': x.data} for x in reversed(qs.order_by('-created', '-id')[:limit])]
def __clearLogs(self, owner_type, owner_id):
'''
Clears all logs related to user service
'''
from uds.models import Log
Log.objects.filter(owner_id = owner_id, owner_type = owner_type).delete()
def doLog(self, wichObject, level, message, source, avoidDuplicates = True):
Log.objects.filter(owner_id=owner_id, owner_type=owner_type).delete()
def doLog(self, wichObject, level, message, source, avoidDuplicates=True):
'''
Do the logging for the requested object.
If the object provided do not accepts associated loggin, it simply ignores the request
'''
if type(level) is not int:
level = log.logLevelFromStr(level)
owner_type = transDict.get(type(wichObject), None)
if owner_type is not None:
if owner_type is not None:
self.__log(owner_type, wichObject.id, level, message, source, avoidDuplicates)
else:
logger.debug('Requested doLog for a type of object not covered: {0}'.format(wichObject))
def getLogs(self, wichObject, limit):
'''
Get the logs associated with "wichObject", limiting to "limit" (default is GlobalConfig.MAX_LOGS_PER_ELEMENT)
Get the logs associated with "wichObject", limiting to "limit" (default is GlobalConfig.MAX_LOGS_PER_ELEMENT)
'''
owner_type = transDict.get(type(wichObject), None)
if owner_type is not None:
if owner_type is not None:
return self.__getLogs(owner_type, wichObject.id, limit)
else:
logger.debug('Requested getLogs for a type of object not covered: {0}'.format(wichObject))
return []
def clearLogs(self, wichObject):
'''
Clears all logs related to wichObject
Used mainly at object database removal (parent object)
'''
owner_type = transDict.get(type(wichObject), None)
if owner_type is not None:
if owner_type is not None:
self.__clearLogs(owner_type, wichObject.id)
else:
logger.debug('Requested clearLogs for a type of object not covered: {0}'.format(wichObject))

View File

@ -3,27 +3,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.
'''
@ -44,18 +44,19 @@ logger = logging.getLogger(__name__)
PUBTAG = 'pm-'
class PublicationOldMachinesCleaner(DelayedTask):
def __init__(self, publicationId):
super(PublicationOldMachinesCleaner,self).__init__()
super(PublicationOldMachinesCleaner, self).__init__()
self._id = publicationId
@transaction.atomic
def run(self):
try:
dsp = DeployedServicePublication.objects.get(pk=self._id)
if (dsp.state!=State.REMOVABLE):
if (dsp.state != State.REMOVABLE):
logger.info('Already removed')
now = getSqlDatetime()
activePub = dsp.deployed_service.activePublication()
dsp.deployed_service.userServices.filter(in_use=True).update(in_use=False, state_date=now)
@ -65,17 +66,18 @@ class PublicationOldMachinesCleaner(DelayedTask):
# Removed provider, no problem at all, no update is done
pass
class PublicationLauncher(DelayedTask):
def __init__(self, publish):
super(PublicationLauncher,self).__init__()
super(PublicationLauncher, self).__init__()
self._publishId = publish.id
def run(self):
logger.debug('Publishing')
try:
with transaction.atomic():
dsp = DeployedServicePublication.objects.select_for_update().get(pk=self._publishId)
if dsp.state != State.LAUNCHING: # If not preparing (may has been canceled by user) just return
if dsp.state != State.LAUNCHING: # If not preparing (may has been canceled by user) just return
return
dsp.state = State.PREPARING
dsp.save()
@ -85,16 +87,16 @@ class PublicationLauncher(DelayedTask):
deployedService.current_pub_revision += 1
deployedService.save()
PublicationFinishChecker.checkAndUpdateState(dsp, pi, state)
except Exception as e:
except Exception:
logger.exception("Exception launching publication")
dsp.state = State.ERROR
dsp.save()
# Delayed Task that checks if a publication is done
class PublicationFinishChecker(DelayedTask):
def __init__(self, publish):
super(PublicationFinishChecker,self).__init__()
super(PublicationFinishChecker, self).__init__()
self._publishId = publish.id
self._state = publish.state
@ -111,48 +113,48 @@ class PublicationFinishChecker(DelayedTask):
# Now we mark, if it exists, the previous usable publication as "Removable"
if State.isPreparing(prevState):
for old in dsp.deployed_service.publications.filter(state=State.USABLE):
old.state=State.REMOVABLE
old.state = State.REMOVABLE
old.save()
pc = PublicationOldMachinesCleaner(old.id)
pc.register(GlobalConfig.SESSION_EXPIRE_TIME.getInt(True)*3600, 'pclean-'+str(old.id), True)
pc.register(GlobalConfig.SESSION_EXPIRE_TIME.getInt(True) * 3600, 'pclean-' + str(old.id), True)
dsp.setState(State.USABLE)
dsp.deployed_service.markOldUserServicesAsRemovables(dsp)
elif State.isRemoving(prevState):
dsp.setState(State.REMOVED)
else: # State is canceling
else: # State is canceling
dsp.setState(State.CANCELED)
# Mark all previous publications deployed services as removables
# and make this usable
pi.finish()
dsp.updateData(pi)
dsp.updateData(pi)
elif State.isErrored(state):
dsp.updateData(pi)
dsp.state = State.ERROR
else:
checkLater = True # The task is running
dsp.updateData(pi)
dsp.save()
if checkLater:
PublicationFinishChecker.checkLater(dsp, pi)
except:
logger.exception('At checkAndUpdate for publication')
PublicationFinishChecker.checkLater(dsp, pi)
@staticmethod
def checkLater(dsp, pi):
'''
Inserts a task in the delayedTaskRunner so we can check the state of this publication
@param dps: Database object for DeployedServicePublication
@param pi: Instance of Publication manager for the object
@param pi: Instance of Publication manager for the object
'''
DelayedTaskRunner.runner().insert(PublicationFinishChecker(dsp), pi.suggestedTime, PUBTAG + str(dsp.id))
@transaction.atomic
def run(self):
logger.debug('Checking publication finished {0}'.format(self._publishId))
try :
try:
dsp = DeployedServicePublication.objects.select_for_update().get(pk=self._publishId)
if dsp.state != self._state:
logger.debug('Task overrided by another task (state of item changed)')
@ -164,42 +166,42 @@ class PublicationFinishChecker(DelayedTask):
except Exception, e:
logger.debug('Deployed service not found (erased from database) {0} : {1}'.format(e.__class__, e))
class PublicationManager(object):
_manager = None
def __init__(self):
pass
@staticmethod
def manager():
if PublicationManager._manager == None:
PublicationManager._manager = PublicationManager()
return PublicationManager._manager
def publish(self, deployedService):
with transaction.atomic():
if deployedService.publications.select_for_update().filter(state__in=State.PUBLISH_STATES).count() > 0:
raise PublishException(_('Already publishing. Wait for previous publication to finish and try again'))
try:
now = getSqlDatetime()
dsp = deployedService.publications.create(state = State.LAUNCHING, state_date = now, publish_date = now, revision = deployedService.current_pub_revision)
dsp = deployedService.publications.create(state=State.LAUNCHING, state_date=now, publish_date=now, revision=deployedService.current_pub_revision)
DelayedTaskRunner.runner().insert(PublicationLauncher(dsp), 4, PUBTAG + str(dsp.id))
except Exception as e:
logger.debug('Caught exception at publish: {0}'.format(e))
raise PublishException(str(e))
@transaction.atomic
def cancel(self,dsp):
def cancel(self, dsp):
dsp = DeployedServicePublication.objects.select_for_update().get(id=dsp.id)
if dsp.state not in State.PUBLISH_STATES:
raise PublishException(_('Can\'t cancel non running publication'))
if dsp.state == State.LAUNCHING:
dsp.state = State.CANCELED
dsp.save()
return dsp
try:
pi = dsp.getInstance()
state = pi.cancel()
@ -208,7 +210,7 @@ class PublicationManager(object):
return dsp
except Exception, e:
raise PublishException(str(e))
@transaction.atomic
def unpublish(self, dsp):
if State.isUsable(dsp.state) == False and State.isRemovable(dsp.state) == False:
@ -223,4 +225,3 @@ class PublicationManager(object):
PublicationFinishChecker.checkAndUpdateState(dsp, pi, state)
except Exception, e:
raise PublishException(str(e))

View File

@ -3,34 +3,35 @@
# Copyright (c) 2013 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from uds.core.util.Config import GlobalConfig
from uds.core.util.Config import GlobalConfig
import logging
@ -40,33 +41,32 @@ logger = logging.getLogger(__name__)
class StatsManager(object):
'''
Manager for loggins statistics, so we can provide usefull info about platform usage
Right now, we are going to provide an interface to "counter stats", that is, statistics
that has counters (such as how many users is at a time active at platform, how many services
are assigned, are in use, in cache, etc...
'''
_manager = None
def __init__(self):
pass
@staticmethod
def manager():
if StatsManager._manager == None:
StatsManager._manager = StatsManager()
return StatsManager._manager
def __doCleanup(self, dbTable):
from uds.models import getSqlDatetime, optimizeTable
from django.db import connection, transaction
from django.db import connection
import datetime
import time
minTime = time.mktime( (getSqlDatetime() - datetime.timedelta(days = GlobalConfig.STATS_DURATION.getInt())).timetuple() )
minTime = time.mktime((getSqlDatetime() - datetime.timedelta(days=GlobalConfig.STATS_DURATION.getInt())).timetuple())
# Don't like how django executes this (recovers all IDS and lauches "DELETE .. WHERE id IN ...)
#StatsCounters.objects.filter(stamp__lt=minTime).delete()
# StatsCounters.objects.filter(stamp__lt=minTime).delete()
# Used dict, cause environment says _meta is not known :-)
query = 'DELETE FROM {0} where STAMP < {1}'.format(dbTable, minTime)
cursor = connection.cursor()
@ -74,15 +74,14 @@ class StatsManager(object):
# This table will hold a big amount of data, and mayby we erase a a big number of records also.
# This will ensure table is in "good" shape (testing right now, will see at future)
optimizeTable(dbTable)
# Counter stats
def addCounter(self, owner_type, owner_id, counterType, counterValue, stamp = None):
def addCounter(self, owner_type, owner_id, counterType, counterValue, stamp=None):
'''
Adds a new counter stats to database.
Args:
owner_type: type of owner (integer, from internal tables)
owner_id: id of the owner
counterType: The type of counter that will receive the value (look at uds.core.util.stats.counters module)
@ -91,115 +90,111 @@ class StatsManager(object):
(this has a granurality of seconds)
Returns:
Nothing
Nothing
'''
from uds.models import getSqlDatetime, StatsCounters
import time
if stamp is None:
stamp = getSqlDatetime()
# To Unix epoch
stamp = int(time.mktime(stamp.timetuple()))
try:
StatsCounters.objects.create(owner_type=owner_type, owner_id=owner_id, counter_type=counterType, value=counterValue, stamp=stamp)
return True
except:
logger.error('Exception handling counter stats saving (maybe database is full?)')
return False
def getCounters(self, ownerType, counterType, ownerIds, since, to, limit, use_max = False):
def getCounters(self, ownerType, counterType, ownerIds, since, to, limit, use_max=False):
'''
Retrieves counters from item
Args:
counterTye: Type of counter to get values
counterId: (optional), if specified, limit counter to only this id, all ids for specidied type if not
maxElements: (optional) Maximum number of elements to retrieve, all if nothing specified
from: date from what to obtain counters. Unlimited if not specified
to: date until obtain counters. Unlimited if not specified
Returns:
Iterator, containing (date, counter) each element
'''
from uds.models import StatsCounters
import time
# To Unix epoch
since = int(time.mktime(since.timetuple()))
to = int(time.mktime(to.timetuple()))
return StatsCounters.get_grouped(ownerType, counterType, owner_id = ownerIds, since = since, to = to, limit = limit, use_max = use_max)
return StatsCounters.get_grouped(ownerType, counterType, owner_id=ownerIds, since=since, to=to, limit=limit, use_max=use_max)
def cleanupCounters(self):
'''
Removes all counters previous to configured max keep time for stat information from database.
'''
from uds.models import StatsCounters
self.__doCleanup(StatsCounters.__dict__['_meta'].db_table)
# Event stats
# Counter stats
def addEvent(self, owner_type, owner_id, eventType, stamp = None):
def addEvent(self, owner_type, owner_id, eventType, stamp=None):
'''
Adds a new event stat to database.
Args:
toWhat: if of the counter
stamp: if not None, this will be used as date for cuounter, else current date/time will be get
(this has a granurality of seconds)
Returns:
Nothing
Nothing
'''
from uds.models import getSqlDatetime, StatsEvents
import time
if stamp is None:
stamp = getSqlDatetime()
# To Unix epoch
stamp = int(time.mktime(stamp.timetuple()))
try:
StatsEvents.objects.create(owner_type=owner_type, owner_id=owner_id, event_type=eventType, stamp=stamp)
return True
except:
logger.error('Exception handling event stats saving (maybe database is full?)')
return False
def getEvents(self, fromWhat, **kwargs):
'''
Retrieves counters from item
Args:
fromWhat: From what object to get counters
maxElements: (optional) Maximum number of elements to retrieve
Returns:
Array of lists, containing (date, counter)
'''
def cleanupEvents(self):
'''
Removes all events previous to configured max keep time for stat information from database.
'''
from uds.models import StatsEvents
self.__doCleanup(StatsEvents.__dict__['_meta'].db_table)
self.__doCleanup(StatsEvents.__dict__['_meta'].db_table)

View File

@ -4,48 +4,54 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from uds.core.jobs.Scheduler import Scheduler
from uds.core.jobs.DelayedTaskRunner import DelayedTaskRunner
from uds.core import jobs
from uds.core.util.Config import GlobalConfig
import threading, time, signal
import threading
import time
import signal
import logging
logger = logging.getLogger(__name__)
class SchedulerThread(threading.Thread):
def run(self):
Scheduler.scheduler().run()
def notifyTermination(self):
Scheduler.scheduler().notifyTermination()
class DelayedTaskThread(threading.Thread):
def run(self):
DelayedTaskRunner.runner().run()
@ -56,7 +62,7 @@ class DelayedTaskThread(threading.Thread):
class TaskManager(object):
keepRunning = True
@staticmethod
def sigTerm(sigNum, frame):
'''
@ -69,59 +75,56 @@ class TaskManager(object):
'''
logger.info("Caught term signal, finishing task manager")
TaskManager.keepRunning = False
@staticmethod
def registerJob(jobType):
jobName = jobType.friendly_name
jobs.factory().insert(jobName, jobType)
@staticmethod
def registerScheduledTasks():
logger.info("Registering sheduled tasks")
from uds.core import workers
# Simply import this to make workers "auto import"
from uds.core import workers # @UnusedImport
@staticmethod
def run():
TaskManager.keepRunning = True
# Runs Scheduler in a separate thread and DelayedTasks here
TaskManager.registerScheduledTasks()
noSchedulers = GlobalConfig.SCHEDULER_THREADS.getInt()
noDelayedTasks = GlobalConfig.DELAYED_TASKS_THREADS.getInt()
logger.info('Starting {0} schedulers and {1} task executors'.format(noSchedulers, noDelayedTasks))
threads = []
for n in range(noSchedulers):
for _ in range(noSchedulers):
thread = SchedulerThread()
thread.start()
threads.append(thread)
time.sleep(0.5)
for n in range(noDelayedTasks):
for _ in range(noDelayedTasks):
thread = DelayedTaskThread()
thread.start()
threads.append(thread)
time.sleep(1)
signal.signal(signal.SIGTERM, TaskManager.sigTerm)
# Debugging stuff
#import guppy
#from guppy.heapy import Remote
#Remote.on()
#gc.set_debug(gc.DEBUG_LEAK)
while( TaskManager.keepRunning ):
signal.signal(signal.SIGTERM, TaskManager.sigTerm)
# Debugging stuff
# import guppy
# from guppy.heapy import Remote
# Remote.on()
# gc.set_debug(gc.DEBUG_LEAK)
while(TaskManager.keepRunning):
time.sleep(1)
for thread in threads:
thread.notifyTermination()
# The join of threads will happen before termination, so its fine to just return here

View File

@ -4,32 +4,33 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from django import forms
from django.utils.translation import ugettext as _, ugettext_lazy
@ -39,27 +40,28 @@ import logging
logger = logging.getLogger(__name__)
class UserPrefsManager(object):
_manager = None
def __init__(self):
self._prefs = {}
@staticmethod
def manager():
if UserPrefsManager._manager == None:
UserPrefsManager._manager = UserPrefsManager()
return UserPrefsManager._manager
def __nameFor(self, module, name):
return module + "_" + name
def registerPrefs(self, modName, friendlyModName, prefs):
'''
Register an array of preferences for a module
'''
self._prefs[modName] = { 'friendlyName' : friendlyModName, 'prefs' : prefs }
self._prefs[modName] = {'friendlyName': friendlyModName, 'prefs': prefs}
def getPreferencesForUser(self, modName, user):
'''
Gets the preferences for an specified module for the user
@ -68,10 +70,10 @@ class UserPrefsManager(object):
for up in user.preferences.filter(module=modName):
prefs[up.name] = up.value
for p in self._prefs[modName]['prefs']:
if prefs.has_key(p.getName()) is False:
if p.getName() not in prefs:
prefs[p.getName()] = p.getDefValue()
return prefs
def getHtmlForUserPreferences(self, user):
# First fill data for all preferences
data = {}
@ -82,11 +84,11 @@ class UserPrefsManager(object):
form = forms.Form()
for p in v['prefs']:
name = self.__nameFor(mod, p.getName())
val = data[name] if data.has_key(name) else p.getDefValue()
form.fields[ name ] = p.formField(val)
res += '<fieldset class="prefset"><legend>' + v['friendlyName'] + '</legend>' + form.as_p() + '</fieldset>'
val = data[name] if name in data else p.getDefValue()
form.fields[name] = p.formField(val)
res += '<fieldset class="prefset"><legend>' + v['friendlyName'] + '</legend>' + form.as_p() + '</fieldset>'
return res
def getGuiForUserPreferences(self, user=None):
data = {}
if user is not None:
@ -97,12 +99,11 @@ class UserPrefsManager(object):
grp = []
for p in v['prefs']:
name = self.__nameFor(mod, p.getName())
val = data[name] if data.has_key(name) else p.getDefValue()
grp.append( { 'name' : name, 'gui' : p.guiField(val).guiDescription(), 'value' : val } )
res.append( {'moduleLabel': v['friendlyName'], 'prefs': grp} )
val = data[name] if name in data else p.getDefValue()
grp.append({'name': name, 'gui': p.guiField(val).guiDescription(), 'value': val})
res.append({'moduleLabel': v['friendlyName'], 'prefs': grp})
return res
def processRequestForUserPreferences(self, user, data):
'''
Returns a list of errors in case of error, else return None
@ -122,12 +123,12 @@ class UserPrefsManager(object):
for p in v['prefs']:
name = self.__nameFor(mod, p.getName())
logger.debug(name)
prefs.append({ 'module': mod, 'name': p.getName(), 'value': form.cleaned_data[name] } )
prefs.append({'module': mod, 'name': p.getName(), 'value': form.cleaned_data[name]})
user.preferences.all().delete()
for p in prefs:
user.preferences.create(module=p['module'], name=p['name'], value=p['value'])
return None
def processGuiForUserPreferences(self, user, data):
'''
'''
@ -137,85 +138,91 @@ class UserPrefsManager(object):
logger.debug(mod)
for p in v['prefs']:
name = self.__nameFor(mod, p.getName())
if data.has_key(name):
prefs.append( { 'module': mod, 'name': p.getName(), 'value': data[name] } )
if name in data:
prefs.append({'module': mod, 'name': p.getName(), 'value': data[name]})
user.preferences.all().delete()
for p in prefs:
user.preferences.create(module=p['module'], name=p['name'], value=p['value'])
class UserPreference(object):
TYPE = 'abstract'
def __init__(self, **kwargs):
self._name = kwargs['name']
self._label = kwargs['label']
self._defValue = kwargs['defvalue'] if kwargs.has_key('defvalue') else None
self._defValue = kwargs.get('defvalue', None)
self._css = 'form-control'
def getName(self):
return self._name
def getDefValue(self):
return self._defValue
def formField(self, value):
'''
Returns a form field to add to the preferences form
'''
raise NameError('Can\'t create an abstract preference!!!')
def guiField(self):
'''
'''
raise NameError('Can\'t create an abstract preference!!!')
class UserTextPreference(UserPreference):
TYPE = 'text'
def __init__(self, **kwargs):
super(self.__class__,self).__init__(**kwargs)
self._length = kwargs['length'] if kwargs.has_key('length') else None
def formField(self, value):
return forms.CharField(label = _(self._label), initial = value, attrs = {'class': self._css})
class UserNumericPreference(UserPreference):
TYPE = 'numeric'
def __init__(self, **kwargs):
super(self.__class__,self).__init__(**kwargs)
self._min = kwargs['minvalue'] if kwargs.has_key('minvalue') else None
self._max = kwargs['maxvalue'] if kwargs.has_key('maxvalue') else None
super(self.__class__, self).__init__(**kwargs)
self._length = kwargs.get('length', None)
def formField(self, value):
return forms.IntegerField(label = _(self._label), initial = value, min_value = self._min, max_value = self._max,
widget = forms.TextInput(attrs = {'class': self._css}))
return forms.CharField(label=_(self._label), initial=value, attrs={'class': self._css})
class UserNumericPreference(UserPreference):
TYPE = 'numeric'
def __init__(self, **kwargs):
super(self.__class__, self).__init__(**kwargs)
self._min = kwargs.get('minvalue', None)
self._max = kwargs.get('maxvalue', None)
def formField(self, value):
return forms.IntegerField(label=_(self._label), initial=value, min_value=self._min, max_value=self._max,
widget=forms.TextInput(attrs={'class': self._css}))
class UserChoicePreference(UserPreference):
TYPE = 'choice'
def __init__(self, **kwargs):
super(self.__class__,self).__init__(**kwargs)
super(self.__class__, self).__init__(**kwargs)
'''
Values are a tuple of
Values are a tuple of
'''
self._values = kwargs['values']
def formField(self, value):
return forms.ChoiceField(label = _(self._label), initial = value, choices = self._values,
widget = forms.Select(attrs = {'class': self._css}))
return forms.ChoiceField(label=_(self._label), initial=value, choices=self._values,
widget=forms.Select(attrs={'class': self._css}))
def guiField(self, value):
vals = []
for v in self._values:
vals.append( { 'id': v[0], 'text': _(v[1]) } )
return gui.ChoiceField(label = _(self._label), rdonly = False, values = vals, defvalue=value, tooltip = _(self._label))
vals.append({'id': v[0], 'text': _(v[1])})
return gui.ChoiceField(label=_(self._label), rdonly=False, values=vals, defvalue=value, tooltip=_(self._label))
class UserCheckboxPreference(UserPreference):
TYPE = 'checkbox'
TYPE = 'checkbox'
def __init__(self, **kwargs):
super(self.__class__,self).__init__(**kwargs)
super(self.__class__, self).__init__(**kwargs)
class CommonPrefs(object):
SZ_PREF = 'screenSize'
@ -223,49 +230,51 @@ class CommonPrefs(object):
SZ_800x600 = '2'
SZ_1024x768 = '3'
SZ_FULLSCREEN = 'F'
DEPTH_PREF = 'screenDepth'
DEPTH_8 = '1'
DEPTH_16 = '2'
DEPTH_24 = '3'
DEPTH_32 = '4'
@staticmethod
def getWidthHeight(prefsDict):
'''
Get width based on screenSizePref value
'''
return { CommonPrefs.SZ_640x480 : (640, 480),
CommonPrefs.SZ_800x600 : (800, 600),
CommonPrefs.SZ_1024x768 : (1024, 768),
CommonPrefs.SZ_FULLSCREEN : (-1, -1)
}[prefsDict[CommonPrefs.SZ_PREF]]
return {
CommonPrefs.SZ_640x480: (640, 480),
CommonPrefs.SZ_800x600: (800, 600),
CommonPrefs.SZ_1024x768: (1024, 768),
CommonPrefs.SZ_FULLSCREEN: (-1, -1)
}[prefsDict[CommonPrefs.SZ_PREF]]
@staticmethod
def getDepth(prefsDict):
'''
Get depth based on depthPref value
'''
return { CommonPrefs.DEPTH_8 : 8,
CommonPrefs.DEPTH_16 : 16,
CommonPrefs.DEPTH_24 : 24,
CommonPrefs.DEPTH_32 : 32 }[ prefsDict[CommonPrefs.DEPTH_PREF] ]
screenSizePref = UserChoicePreference(name = SZ_PREF, label = ugettext_lazy('Screen Size'), defvalue = SZ_FULLSCREEN, values = (
(SZ_640x480, '640x480'),
(SZ_800x600, '800x600'),
(SZ_1024x768, '1024x768'),
(SZ_FULLSCREEN, ugettext_lazy('Full Screen'))
)
return {
CommonPrefs.DEPTH_8: 8,
CommonPrefs.DEPTH_16: 16,
CommonPrefs.DEPTH_24: 24,
CommonPrefs.DEPTH_32: 32
}[prefsDict[CommonPrefs.DEPTH_PREF]]
screenSizePref = UserChoicePreference(name=SZ_PREF,
label=ugettext_lazy('Screen Size'),
defvalue=SZ_FULLSCREEN,
values=(
(SZ_640x480, '640x480'),
(SZ_800x600, '800x600'),
(SZ_1024x768, '1024x768'),
(SZ_FULLSCREEN, ugettext_lazy('Full Screen'))
)
)
depthPref = UserChoicePreference(name=DEPTH_PREF, label=ugettext_lazy('Screen colors'), defvalue=DEPTH_24, values=(
(DEPTH_8, ugettext_lazy('8 bits')),
(DEPTH_16, ugettext_lazy('16 bits')),
(DEPTH_24, ugettext_lazy('24 bits')),
(DEPTH_32, ugettext_lazy('32 bits')),
)
)
depthPref = UserChoicePreference(name = DEPTH_PREF, label = ugettext_lazy('Screen colors'), defvalue = DEPTH_24, values = (
(DEPTH_8, ugettext_lazy('8 bits')),
(DEPTH_16, ugettext_lazy('16 bits')),
(DEPTH_24, ugettext_lazy('24 bits')),
(DEPTH_32, ugettext_lazy('32 bits')),
)
)

View File

@ -4,32 +4,33 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from django.utils.translation import ugettext as _
from django.db.models import Q
@ -50,9 +51,10 @@ logger = logging.getLogger(__name__)
USERSERVICE_TAG = 'cm-'
class UserServiceOpChecker(DelayedTask):
def __init__(self, service):
super(UserServiceOpChecker,self).__init__()
super(UserServiceOpChecker, self).__init__()
self._svrId = service.id
self._state = service.state
@ -60,10 +62,10 @@ class UserServiceOpChecker(DelayedTask):
def makeUnique(userService, userServiceInstance, state):
'''
This method makes sure that there will be only one delayedtask related to the userService indicated
'''
'''
DelayedTaskRunner.runner().remove(USERSERVICE_TAG + str(userService.id))
UserServiceOpChecker.checkAndUpdateState(userService, userServiceInstance, state)
@staticmethod
def checkAndUpdateState(userService, userServiceInstance, state):
'''
@ -81,7 +83,7 @@ class UserServiceOpChecker(DelayedTask):
if userServiceInstance.service().publicationType is None or userService.publication == userService.deployed_service.activePublication():
userService.setState(State.USABLE)
# and make this usable if os manager says that it is usable, else it pass to configuring state
if userServiceInstance.osmanager() is not None and userService.os_state == State.PREPARING: # If state is already "Usable", do not recheck it
if userServiceInstance.osmanager() is not None and userService.os_state == State.PREPARING: # If state is already "Usable", do not recheck it
stateOs = userServiceInstance.osmanager().checkState(userService)
# If state is finish, we need to notify the userService again that os has finished
if State.isFinished(stateOs):
@ -89,7 +91,7 @@ class UserServiceOpChecker(DelayedTask):
userService.updateData(userServiceInstance)
else:
stateOs = State.FINISHED
if State.isRuning(stateOs):
userService.setOsState(State.PREPARING)
else:
@ -118,17 +120,17 @@ class UserServiceOpChecker(DelayedTask):
if checkLater:
UserServiceOpChecker.checkLater(userService, userServiceInstance)
except Exception as e:
logger.exception('Checkin service state')
logger.exception('Checking service state')
log.doLog(userService, log.ERROR, 'Exception: {0}'.format(e), log.INTERNAL)
userService.setState(State.ERROR)
userService.save()
@staticmethod
def checkLater(userService, ci):
'''
Inserts a task in the delayedTaskRunner so we can check the state of this publication
@param dps: Database object for DeployedServicePublication
@param pi: Instance of Publication manager for the object
@param pi: Instance of Publication manager for the object
'''
# Do not add task if already exists one that updates this service
if DelayedTaskRunner.runner().checkExists(USERSERVICE_TAG + str(userService.id)):
@ -164,17 +166,17 @@ class UserServiceOpChecker(DelayedTask):
class UserServiceManager(object):
_manager = None
def __init__(self):
pass
@staticmethod
def manager():
if UserServiceManager._manager == None:
UserServiceManager._manager = UserServiceManager()
return UserServiceManager._manager
@staticmethod
@staticmethod
def getCacheStateFilter(level):
return Q(cache_level=level) & UserServiceManager.getStateFilter()
@ -191,15 +193,13 @@ class UserServiceManager(object):
# Early return, so no database count is needed
if serviceInstance.maxDeployed == Service.UNLIMITED:
return
numberOfServices = deployedService.userServices.select_for_update().filter(
state__in=[State.PREPARING, State.USABLE]).count()
if serviceInstance.maxDeployed <= numberOfServices:
raise MaxServicesReachedException(
'Max number of allowed deployments for service reached'
)
raise MaxServicesReachedException('Max number of allowed deployments for service reached')
def __createCacheAtDb(self, deployedServicePublication, cacheLevel):
'''
Private method to instatiate a cache element at database with default states
@ -207,10 +207,10 @@ class UserServiceManager(object):
# Checks if maxDeployed has been reached and if so, raises an exception
self.__checkMaxDeployedReached(deployedServicePublication.deployed_service)
now = getSqlDatetime()
return deployedServicePublication.userServices.create(cache_level = cacheLevel, state = State.PREPARING, os_state = State.PREPARING,
state_date=now, creation_date=now, data = '', deployed_service = deployedServicePublication.deployed_service,
user = None, in_use = False )
return deployedServicePublication.userServices.create(cache_level=cacheLevel, state=State.PREPARING, os_state=State.PREPARING,
state_date=now, creation_date=now, data='', deployed_service=deployedServicePublication.deployed_service,
user=None, in_use=False)
def __createAssignedAtDb(self, deployedServicePublication, user):
'''
Private method to instatiate an assigned element at database with default state
@ -219,7 +219,7 @@ class UserServiceManager(object):
now = getSqlDatetime()
return deployedServicePublication.userServices.create(cache_level=0, state=State.PREPARING, os_state=State.PREPARING,
state_date=now, creation_date=now, data='', deployed_service=deployedServicePublication.deployed_service, user=user, in_use=False)
def __createAssignedAtDbForNoPublication(self, deployedService, user):
'''
__createCacheAtDb and __createAssignedAtDb uses a publication for create the UserService.
@ -230,8 +230,7 @@ class UserServiceManager(object):
now = getSqlDatetime()
return deployedService.userServices.create(cache_level=0, state=State.PREPARING, os_state=State.PREPARING,
state_date=now, creation_date=now, data='', publication=None, user=user, in_use=False)
def createCacheFor(self, deployedServicePublication, cacheLevel):
'''
Creates a new cache for the deployed service publication at level indicated
@ -240,10 +239,10 @@ class UserServiceManager(object):
cache = self.__createCacheAtDb(deployedServicePublication, cacheLevel)
ci = cache.getInstance()
state = ci.deployForCache(cacheLevel)
UserServiceOpChecker.checkAndUpdateState(cache, ci, state)
return cache
def createAssignedFor(self, ds, user):
'''
Creates a new assigned deployed service for the publication and user indicated
@ -254,15 +253,15 @@ class UserServiceManager(object):
assigned = self.__createAssignedAtDb(dsp, user)
else:
logger.debug('Creating a new assigned element for user {0}'.format(user))
assigned = self.__createAssignedAtDbForNoPublication(ds, user)
assigned = self.__createAssignedAtDbForNoPublication(ds, user)
ai = assigned.getInstance()
state = ai.deployForUser(user)
UserServiceOpChecker.makeUnique(assigned, ai, state)
return assigned
def createAssignable(self, ds, deployed, user):
'''
Creates an assignable service
@ -277,9 +276,7 @@ class UserServiceManager(object):
logger.exception("Exception {0}".format(e))
logger.debug("Assignable: {0}".format(assignable))
return assignable
def moveToLevel(self, cache, cacheLevel):
'''
Moves a cache element from one level to another
@ -293,9 +290,9 @@ class UserServiceManager(object):
logger.debug('Service State: {0} {1} {2}'.format(State.toString(state), State.toString(cache.state), State.toString(cache.os_state)))
if State.isRuning(state) and cache.isUsable():
cache.setState(State.PREPARING)
UserServiceOpChecker.makeUnique(cache, ci, state)
def cancel(self, uService):
'''
Cancels a user service creation
@ -306,7 +303,7 @@ class UserServiceManager(object):
if uService.isPreparing() == False:
logger.INFO(_('Cancel requested for a non running operation, doing remove instead'))
return self.remove(uService)
ui = uService.getInstance()
# We simply notify service that it should cancel operation
state = ui.cancel()
@ -315,7 +312,6 @@ class UserServiceManager(object):
UserServiceOpChecker.makeUnique(uService, ui, state)
return uService
def remove(self, uService):
'''
Removes a uService element
@ -325,12 +321,12 @@ class UserServiceManager(object):
logger.debug('Removing uService {0}'.format(uService))
if uService.isUsable() == False and State.isRemovable(uService.state) == False:
raise OperationException(_('Can\'t remove a non active element'))
ci = uService.getInstance()
state = ci.destroy()
uService.setState(State.REMOVING)
UserServiceOpChecker.makeUnique(uService, ci, state)
def removeOrCancel(self, uService):
if uService.isUsable() or State.isRemovable(uService.state):
return self.remove(uService)
@ -338,38 +334,37 @@ class UserServiceManager(object):
return self.cancel(uService)
else:
raise OperationException(_('Can\'t remove nor cancel {0} cause its states doesn\'t allows it'))
def removeInfoItems(self, dsp):
dsp.cachedDeployedService.select_for_update().filter(state__in=State.INFO_STATES).delete()
def getAssignationForUser(self, ds, user):
# First, we try to locate an already assigned service
existing = ds.assignedUserServices().filter(user=user,state__in=State.VALID_STATES)
existing = ds.assignedUserServices().filter(user=user, state__in=State.VALID_STATES)
lenExisting = existing.count()
if lenExisting > 0: # Already has 1 assigned
if lenExisting > 0: # Already has 1 assigned
logger.debug('Found assigned service from {0} to user {1}'.format(ds, user.name))
return existing[0]
#if existing[0].state == State.ERROR:
# if existing[0].state == State.ERROR:
# if lenExisting > 1:
# return existing[1]
#else:
# else:
# return existing[0]
# Now try to locate 1 from cache already "ready" (must be usable and at level 1)
cache = ds.cachedUserServices().select_for_update().filter(cache_level = services.UserDeployment.L1_CACHE, state = State.USABLE)[:1]
cache = ds.cachedUserServices().select_for_update().filter(cache_level=services.UserDeployment.L1_CACHE, state=State.USABLE)[:1]
if len(cache) > 0:
cache = cache[0] # Database object
cache = cache[0] # Database object
cache.assignToUser(user)
cache.save() # Store assigned ASAP, we do not know how long assignToUser method of instance will take
cache.save() # Store assigned ASAP, we do not know how long assignToUser method of instance will take
logger.debug('Found a cached-ready service from {0} for user {1}, item {2}'.format(ds, user, cache))
ci = cache.getInstance() # User Deployment instance
ci = cache.getInstance() # User Deployment instance
ci.assignToUser(user)
cache.updateData(ci)
cache.save()
return cache
# Now find if there is a preparing one
cache = ds.cachedUserServices().select_for_update().filter(cache_level = services.UserDeployment.L1_CACHE, state = State.PREPARING)[:1]
cache = ds.cachedUserServices().select_for_update().filter(cache_level=services.UserDeployment.L1_CACHE, state=State.PREPARING)[:1]
if len(cache) > 0:
cache = cache[0]
cache.assignToUser(user)
@ -387,13 +382,13 @@ class UserServiceManager(object):
raise MaxServicesReachedException()
# Can create new service, create it
return self.createAssignedFor(ds, user)
def getServicesInStateForProvider(self, provider_id, state):
'''
Returns the number of services of a service provider in the state indicated
'''
return UserService.objects.filter(deployed_service__service__provider__id=provider_id, state=state).count()
def canRemoveServiceFromDeployedService(self, ds):
'''
checks if we can do a "remove" from a deployed service
@ -411,7 +406,7 @@ class UserServiceManager(object):
if preparing >= GlobalConfig.MAX_PREPARING_SERVICES.getInt() and GlobalConfig.IGNORE_LIMITS.getBool() == False:
return False
return True
def isReady(self, uService):
UserService.objects.update()
uService = UserService.objects.select_for_update().get(id=uService.id)
@ -436,14 +431,13 @@ class UserServiceManager(object):
This method is used by UserService when a request for setInUse(False) is made
This checks that the service can continue existing or not
'''
#uService = UserService.objects.select_for_update().get(id=uService.id)
# uService = UserService.objects.select_for_update().get(id=uService.id)
if uService.publication == None:
return
if uService.publication.id != uService.deployed_service.activePublication().id:
logger.debug('Old revision of user service, marking as removable: {0}'.format(uService))
uService.remove()
def notifyReadyFromOsManager(self, uService, data):
ui = uService.getInstance()
logger.debug('Notifying user service ready state')
@ -452,7 +446,6 @@ class UserServiceManager(object):
uService.updateData(ui)
if state == State.FINISHED:
uService.save()
elif uService.state in (State.USABLE, State.PREPARING): # We don't want to get active deleting or deleted machines...
elif uService.state in (State.USABLE, State.PREPARING): # We don't want to get active deleting or deleted machines...
uService.setState(State.PREPARING)
UserServiceOpChecker.makeUnique(uService, ui, state)

View File

@ -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.
'''
@ -32,10 +32,14 @@ UDS managers (downloads, users preferences, publications, ...)
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
__updated__ = '2014-02-19'
def cryptoManager():
from CryptoManager import CryptoManager
return CryptoManager.manager()
return CryptoManager.manager()
def taskManager():
@ -47,10 +51,12 @@ def downloadsManager():
from DownloadsManager import DownloadsManager
return DownloadsManager.manager()
def logManager():
from LogManager import LogManager
return LogManager.manager()
def statsManager():
from StatsManager import StatsManager
return StatsManager.manager()
return StatsManager.manager()

View File

@ -4,32 +4,33 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from django.utils.translation import ugettext_noop as _
from uds.core.util.State import State
@ -37,45 +38,46 @@ from uds.core import Module
STORAGE_KEY = 'osmk'
class OSManager(Module):
'''
An OS Manager is responsible for communication the service the different actions to take (i.e. adding a windows machine to a domain)
The Service (i.e. virtual machine) communicates with the OSManager via a published web method, that must include the unique ID.
In order to make easier to agents identify themselfs, the Unique ID can be a list with various Ids (i.e. the macs of the virtual machine).
In order to make easier to agents identify themselfs, the Unique ID can be a list with various Ids (i.e. the macs of the virtual machine).
Server will iterate thought them and look for an identifier associated with the service. This list is a comma separated values (i.e. AA:BB:CC:DD:EE:FF,00:11:22:...)
Remember also that we inherit the test and check methods from BaseModule
'''
# Service informational related data
typeName = _('Base OS Manager')
# Service informational related data
typeName = _('Base OS Manager')
typeType = 'BaseOSManager'
typeDescription = _('Base Manager')
iconFile = 'osmanager.png'
# If true, this os manager will be invoked with every user service assigned, but not used from time to time
# Time is defined as a global config
# Time is defined as a global config
processUnusedMachines = False
def __init__(self,environment, values):
def __init__(self, environment, values):
super(OSManager, self).__init__(environment, values)
self.initialize(values)
def initialize(self, values):
'''
This method will be invoked from __init__ constructor.
This is provided so you don't have to provide your own __init__ method,
and invoke base methods.
This will get invoked when all initialization stuff is done
Args:
Values: If values is not none, this object is being initialized
from administration interface, and not unmarshal will be done.
If it's None, this is initialized internally, and unmarshal will
be called after this.
Default implementation does nothing
'''
pass
def release(self, service):
'''
Called by a service that is in Usable state before destroying it so osmanager can release data associated with it
@ -83,70 +85,68 @@ class OSManager(Module):
@return nothing
'''
pass
# These methods must be overriden
def process(self,service, message, data):
def process(self, service, message, data):
'''
This method must be overriden so your so manager can manage requests and responses from agent.
@param service: Service that sends the request (virtual machine or whatever)
@param message: message to process (os manager dependent)
@param data: Data for this message
@param data: Data for this message
'''
pass
def checkState(self,service):
def checkState(self, service):
'''
This method must be overriden so your os manager can respond to requests from system to the current state of the service
This method will be invoked when:
* After service creation has finished, with the service wanting to see if it has to wait for os manager process finalization
* After call to process method, to check if the state has changed
* Before assigning a service to an user (maybe this is not needed)?
* Before assigning a service to an user (maybe this is not needed)?
Notice that the service could be in any state. In fact, what we want with this is return FINISHED if nothing is expected from os o RUNING else
The state will be updated by actors inside oss, so no more direct checking is needed
The state will be updated by actors inside oss, so no more direct checking is needed
@return: RUNNING, FINISHED
We do not expect any exception from this method
'''
return State.FINISHED
def processUnused(self, userService):
'''
This will be invoked for every assigned and unused user service that has been in this state at least 1/2 of Globalconfig.CHECK_UNUSED_TIME
This function can update userService values. Normal operation will be remove machines if this state is not valid
'''
pass
@classmethod
def transformsUserOrPasswordForService(cls):
'''
Helper method that informs if the os manager transforms the username and/or the password.
This is used from DeployedService
This is used from DeployedService
'''
return cls.processUserPassword != OSManager.processUserPassword
def processUserPassword(self, service, username, password):
'''
This will be invoked prior to passsing username/password to Transport.
This method allows us to "change" username and/or password "on the fly".
One example of use of this is an OS Manager that creates a random password for an user.
One example of use of this is an OS Manager that creates a random password for an user.
In that case, this method, if the username passed in is the same as the os manager changes the password for, return the changed password.
MUST Return:
An array with 2 elements, [newUserName, newPassword].
Default method simplt does nothing with in parameters, just returns it. (So, if your os manager does not need this,
simply do not implement it)
Note: This method is, right now, invoked by Transports directly. So if you implement a Transport, remember to invoke this
'''
return [username, password]
def destroy(self):
'''
Invoked when OS Manager is deleted
'''
pass
def __str__(self):
return "Base OS Manager"
return "Base OS Manager"

View File

@ -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.
'''
@ -36,25 +36,26 @@ import logging
logger = logging.getLogger(__name__)
class OSManagersFactory(object):
_factory = None
def __init__(self):
self._jobs = {}
@staticmethod
@staticmethod
def factory():
if OSManagersFactory._factory == None:
if OSManagersFactory._factory == None:
OSManagersFactory._factory = OSManagersFactory()
return OSManagersFactory._factory
def providers(self):
return self._jobs
def insert(self, type_):
logger.debug('Adding OS Manager {0} as {1}'.format(type_.type(), type_))
self._jobs[type_.type()] = type_
def lookup(self, typeName):
try:
return self._jobs[typeName]

View File

@ -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.
'''
@ -32,12 +32,13 @@ UDS os managers related interfaces and classes
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from BaseOsManager import OSManager
def factory():
'''
Returns factory for register/access to authenticators
'''
from OSManagersFactory import OSManagersFactory
return OSManagersFactory.factory()

View File

@ -4,147 +4,141 @@
# 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.
'''
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from uds.core import Environmentable
from uds.core import Serializable
from uds.core.util.State import State
class UserDeployment(Environmentable, Serializable):
'''
Interface for deployed services.
This class provides the needed logic for implementing an "consumable user service",
that are the elements that the user will interact with.
A good way to understand this class is to look at the sample services provided
with the documentation.
As with all modules interfaces, if you override __init__ method,
As with all modules interfaces, if you override __init__ method,
do not forget to invoke this class __init__ method as this::
super(self.__class__, self).__init__(environment, **kwargs)
This is a MUST (if you override __init___), so internal structured gets filled correctly, so don't forget it!.
The preferred way of initializing, is to provide :py:meth:`.initialize`, that
will be invoked just after all initialization stuff is done at __init__.
Normally objects of classes deriving from this one, will be serialized, called,
deserialized. This means that all that you want to ensure that is keeped inside
the class must be serialized and unserialized, because there is no warantee that
the object will get two methods invoked without haven't been remoded from memory
and loaded again, this means, IMPLEMENT marshal and unmarshal with all attributes
that you want to keep.
Things to know about this class:
* Once a deployment is done, it will never be called again for same instance
object
* The method getUniqueId will be invoked after call to deploys and check.
You can change it on the fly, but remember that uniqueId is the "keyword"
used inside services to communicate with os managers (os manager will
receive an instance of UserDeployment, and this will be located via that
* The method getUniqueId will be invoked after call to deploys and check.
You can change it on the fly, but remember that uniqueId is the "keyword"
used inside services to communicate with os managers (os manager will
receive an instance of UserDeployment, and this will be located via that
uniqueId)
Uniques ids can be repeated at database level, to let it come at a later
Uniques ids can be repeated at database level, to let it come at a later
deployment stage, but if two services has same uniqueid at a time,
os manager will simply not work.
* suggestedTime is always accessed through instance objects, and used after
deployForCache, deployForUser and moveToCache it these methods returns
* suggestedTime is always accessed through instance objects, and used after
deployForCache, deployForUser and moveToCache it these methods returns
RUNNING
* Checks (if a deployment has finished, or the cache movement is finished)
are always done using checkState(). It is secuential, i mean, will only
be called when a deployment,a cache movement or a cancel operation is
* Checks (if a deployment has finished, or the cache movement is finished)
are always done using checkState(). It is secuential, i mean, will only
be called when a deployment,a cache movement or a cancel operation is
running
* If the service that supports this deployeds do not use L2 cache, the
* If the service that supports this deployeds do not use L2 cache, the
moveCache method will never be invoked
* The L1 cache should be a fast access cache (i.e. running service but
not assigned to an user), while L2 cache should be non consuming or
almost-non-consuming service. This means that if we cannont make an
slower an less resources consumable form for a service, this should
not have an L2 cache (slower is not a must,
but probably it will be slower to recover from L2 cache than from L1,
* The L1 cache should be a fast access cache (i.e. running service but
not assigned to an user), while L2 cache should be non consuming or
almost-non-consuming service. This means that if we cannont make an
slower an less resources consumable form for a service, this should
not have an L2 cache (slower is not a must,
but probably it will be slower to recover from L2 cache than from L1,
but faster than creating a new service)
Ofc, if a service has an "Instant" creation, it don't needs cache...
* We do not expect any exception from these methods, but if there is an
error, the method can return "ERROR". To show the reason of error, the
method reasonOfError can be called multiple times, including
* We do not expect any exception from these methods, but if there is an
error, the method can return "ERROR". To show the reason of error, the
method reasonOfError can be called multiple times, including
serializations in middle, so remember to include reason of error in serializations
'''
L1_CACHE = 1 #: Constant for Cache of level 1
L2_CACHE = 2 #: Constant for Cache of level 2
#: Suggested time for deployment finishing, in seconds
#: This allows the manager to, if deployment is no done in 1 step, re-check
#: the deployment once this time has passed, i.e. KVM COW deployment takes
#: low time, so we suggest to check at short intervals, but full copys takes
#: a bit more so we can use longer interval checks
#: This attribute is accessed always through an instance object,
#: so u can modify it at your own implementation.
L1_CACHE = 1 # : Constant for Cache of level 1
L2_CACHE = 2 # : Constant for Cache of level 2
# : Suggested time for deployment finishing, in seconds
# : This allows the manager to, if deployment is no done in 1 step, re-check
# : the deployment once this time has passed, i.e. KVM COW deployment takes
# : low time, so we suggest to check at short intervals, but full copys takes
# : a bit more so we can use longer interval checks
# : This attribute is accessed always through an instance object,
# : so u can modify it at your own implementation.
suggestedTime = 10
def __init__(self, environment, **kwargs):
'''
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()
Invoking this from derived classes is a MUST, again, do not forget it or your
module will probable never work.
Args:
environment: Environment assigned to this publication
kwargs: List of arguments that will receive:
service: Parent service (derived from Service) of this deployment (this is an instance, not database object)
service: Parent service (derived from Service) of this deployment (this is an instance, not database object)
publication: Parent publication (derived from Publication) of this deployment (optional)(this is an instance, not database object)
osmanager: Parent osmanager (derived from :py:class:`uds.core.osmanagersOSManager`) of this deployment (optional)(this is an instance, not database object)
dbservice: Database object for this service
'''
Environmentable.__init__(self, environment)
Serializable.__init__(self)
self._service = kwargs['service'] # Raises an exception if service is not included. Parent
if kwargs.has_key('publication'):
self._publication = kwargs['publication']
else:
self._publication = None
if kwargs.has_key('osmanager'):
self._osmanager = kwargs['osmanager']
else:
self._osmanager = None
if kwargs.has_key('dbservice'): # Reference to database service, will be there most time :-)
self._dbService = kwargs['dbservice']
else:
self._dbService = None
self._service = kwargs['service'] # Raises an exception if service is not included. Parent
self._publication = kwargs.get('publication', None)
self._osmanager = kwargs.get('osmanager', None)
self._dbService = kwargs.get('dbservice', None)
self.initialize()
def initialize(self):
'''
This method will be invoked from __init__ constructor.
@ -155,17 +149,16 @@ class UserDeployment(Environmentable, Serializable):
'''
pass
def getName(self):
'''
Override this to return a name to display under some circustances
Returns:
name, default implementation returns unique id
name, default implementation returns unique id
'''
return self.getUniqueId()
def service(self):
'''
Utility method to access parent service. This doesn't need to be override.
@ -174,154 +167,154 @@ class UserDeployment(Environmentable, Serializable):
consumable to the user.
Returns:
Parent service of this User Deployment
'''
return self._service
def publication(self):
'''
Utility method to access publication. This doesn't need to be overriden.
Returns:
publication for this user deployment, or None if this deployment has
no publication at all.
'''
return self._publication
def osmanager(self):
'''
Utility method to access os manager. This doesn't need to be overriden.
Returns:
os manager for this user deployment, or None if this deployment has
no os manager.
'''
return self._osmanager
def dbservice(self):
'''
Utility method to access database object for the object this represents.
Returns:
Database object that got unserialized to obtain this object.
'''
return self._dbService
def doLog(self, level, message):
'''
Logs a message with requested level associated with this service
'''
from uds.core.util import log
log.doLog(self._dbService, level, message, log.SERVICE)
def macGenerator(self):
'''
Utility method to access provided macs generator (inside environment)
Returns the environment unique mac addresses generator
'''
return self.idGenerators('mac')
def nameGenerator(self):
'''
Utility method to access provided names generator (inside environment)
Returns the environment unique name generator
'''
return self.idGenerators('name')
def getUniqueId(self):
'''
Obtains an unique id for this deployed service, you MUST override this
Returns:
An unique identifier for this object, that is an string and must be
unique.
'''
raise Exception('Base getUniqueId for User Deployment called!!!')
def notifyReadyFromOsManager(self, data):
'''
This is a task method. As that, the excepted return values are
State values RUNNING, FINISHED or ERROR.
This method provides a mechanism to let os managers notify readyness
This method provides a mechanism to let os managers notify readyness
to deployed services.
Args:
Data: Data sent by os manager.
Data is os manager dependant, so check if this data is known by you
Data is os manager dependant, so check if this data is known by you
(normally, it will be None, but is os manager dependad as i say)
This is a task-initiating method, so if there is something to do,
This is a task-initiating method, so if there is something to do,
just return State.RUNNING. If not, return State.FINISHED. In case of
error, return State.ERROR and be ready to provide error message when
if State.RUNNING is returned, the :py:meth:.checkState method will be
if State.RUNNING is returned, the :py:meth:.checkState method will be
used to check when this process has finished.
:note: All task methods, like this one, are expected to handle
:note: All task methods, like this one, are expected to handle
all exceptions, and never raise an exception from these methods
to the core. Take that into account and handle exceptions inside
this method.
this method.
'''
return State.FINISHED
def getIp(self):
'''
All services are "IP" services, so this method is a MUST
All services are "IP" services, so this method is a MUST
Returns:
The needed ip to let the user connect to the his deployed service.
This ip will be managed by transports, without IP there is no connection
'''
raise Exception('Base getIp for User Deployment got called!!!')
def setIp(self, ip):
'''
This is an utility method, invoked by some os manager to notify what they thinks is the ip for this service.
If you assign the service IP by your own methods, do not override this
'''
pass
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.
:note: All task methods, like this one, are expected to handle
:note: All task methods, like this one, are expected to handle
all exceptions, and never raise an exception from these methods
to the core. Take that into account and handle exceptions inside
this method.
this method.
'''
return State.FINISHED
@ -331,13 +324,13 @@ class UserDeployment(Environmentable, Serializable):
This is a task method. As that, the expected return values are
State values RUNNING, FINISHED or ERROR.
The objective of this method is providing a cache copy of an user consumable,
and will be invoked whenever the core need to create a new copy for cache
of the service this UserDeployment manages.
Things to take care with this method are:
* cacheLevel can be L1 or L2 (class constants)
* If a deploy for cache is asked for a L1 cache, the generated
element is expected to be all-done for user consume. L1 cache items
@ -351,55 +344,54 @@ class UserDeployment(Environmentable, Serializable):
If your L2 cache consumes the same that L1 cache, L2 cache is in fact not
needed.
* This works as :py:meth:.deployForUser, meaning that you can take a look
also to that method for more info
also to that method for more info
:note: If your service uses caching, this method MUST be provided. If it
do not uses cache, this method will never get called, so you can
skip it implementation
skip it implementation
:note: All task methods, like this one, are expected to handle
:note: All task methods, like this one, are expected to handle
all exceptions, and never raise an exception from these methods
to the core. Take that into account and handle exceptions inside
this method.
this method.
'''
raise Exception('Base deploy for cache invoked! for class {0}'.format(self.__class__.__name__))
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.
:note: override ALWAYS this method, or an exception will be raised
:note: All task methods, like this one, are expected to handle
:note: All task methods, like this one, are expected to handle
all exceptions, and never raise an exception from these methods
to the core. Take that into account and handle exceptions inside
this method.
this method.
'''
raise Exception('Base deploy for user invoked! for class {0}'.format(self.__class__.__name__))
def checkState(self):
'''
This is a task method. As that, the expected return values are
@ -408,35 +400,35 @@ class UserDeployment(Environmentable, Serializable):
If some of the initiating action tasks returns State.RUNNING. this method
will get called until it returns State.FINISH or State.ERROR.
In other words, whenever a multi step operation is initiated, this method
will get the responsability to check that the operation has finished or
failed. If the operation continues, but haven't finished yet, it must
return State.RUNNING. If has finished must return State.FINISH and if it
has some kind of error, State.ERROR and also store somewhere the info
that will be requested using :py:meth:.reasonOfError
that will be requested using :py:meth:.reasonOfError
:note: override ALWAYS this method, or an exception will be raised
:note: All task methods, like this one, are expected to handle
:note: All task methods, like this one, are expected to handle
all exceptions, and never raise an exception from these methods
to the core. Take that into account and handle exceptions inside
this method.
this method.
'''
raise Exception('Base check state invoked! for class {0}'.format(self.__class__.__name__))
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.
Default implementation does nothing at all.
: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)
'''
pass
@ -446,76 +438,76 @@ class UserDeployment(Environmentable, Serializable):
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.
'''
pass
def moveToCache(self, newLevel):
'''
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.
:note: All task methods, like this one, are expected to handle
:note: All task methods, like this one, are expected to handle
all exceptions, and never raise an exception from these methods
to the core. Take that into account and handle exceptions inside
this method.
this method.
'''
return State.FINISHED
def userLoggedIn(self, username):
'''
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.
'''
pass
def userLoggedOut(self, username):
'''
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.
'''
pass
@ -523,11 +515,11 @@ class UserDeployment(Environmentable, Serializable):
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
@ -539,18 +531,18 @@ class UserDeployment(Environmentable, Serializable):
'''
This is a task method. As that, the excepted return values are
State values RUNNING, FINISHED or ERROR.
This method gives the oportunity to remove associated data (virtual machine,
...) for the user consumable this instance represents.
If return value is State.RUNNING, :py:meth:.checkState will be used to
check if the destroy operation has finished.
:note: All task methods, like this one, are expected to handle
:note: All task methods, like this one, are expected to handle
all exceptions, and never raise an exception from these methods
to the core. Take that into account and handle exceptions inside
this method.
'''
this method.
'''
raise Exception('destroy method for class {0} not provided!'.format(self.__class__.__name__))
def cancel(self):
@ -561,14 +553,14 @@ class UserDeployment(Environmentable, Serializable):
Cancel represents a canceling of the current running operation, and
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.
:note: All task methods, like this one, are expected to handle
:note: All task methods, like this one, are expected to handle
all exceptions, and never raise an exception from these methods
to the core. Take that into account and handle exceptions inside
this method.
this method.
'''
raise Exception('cancel method for class {0} not provided!'.format(self.__class__.__name__))
@ -576,4 +568,4 @@ class UserDeployment(Environmentable, Serializable):
'''
Mainly used for debugging purposses
'''
return "Base Deployed Service"
return "Base Deployed Service"

View File

@ -4,53 +4,56 @@
# 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.
'''
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from uds.core import Environmentable
from uds.core import Serializable
class Publication(Environmentable, Serializable):
'''
This class is in fact an interface, and defines the logic of a publication
This class is in fact an interface, and defines the logic of a publication
for a Service.
A publication is the preparation of the needs of a service before it can
be provided to users. One good sample of this is, in case of virtual machines,
to copy a machine to provide COWS of this copy to users.
As always, do not forget to invoke base class __init__ if you override it as this::
super(self.__class__, self).__init__(environment, **kwargs)
This is a MUST, so internal structured gets filled correctly, so don't forget it!.
The preferred method is not to override init, but provide the :py:meth:`.initialize`,
that will be invoked just after all internal initialization is completed.
Normally objects of classes deriving from this one, will be serialized, called,
deserialized. This means that all that you want to ensure that is keeped inside
the class must be serialized and unserialized, because there is no warantee that
@ -58,20 +61,20 @@ class Publication(Environmentable, Serializable):
and loaded again, this means, IMPLEMENT marshal and unmarshal with all attributes
that you want to keep.
'''
# Constants for publications
# Description of the publication
#:Suggested time for publication finishing, in seconds
#: This allows the manager to, if publication is no done in 1 step,
#: re-check the publication once this time has passed, i.e. KVM COW publication
#: takes low time, so we suggest to check at short intervals,
#: but full clone takes a lot, so we suggest that checks are done more steady.
#: This attribute is always accessed using an instance object, so you can
#: change suggestedTime in your implementation.
# :Suggested time for publication finishing, in seconds
# : This allows the manager to, if publication is no done in 1 step,
# : re-check the publication once this time has passed, i.e. KVM COW publication
# : takes low time, so we suggest to check at short intervals,
# : but full clone takes a lot, so we suggest that checks are done more steady.
# : This attribute is always accessed using an instance object, so you can
# : change suggestedTime in your implementation.
suggestedTime = 10
def __init__(self, environment, **kwargs):
'''
Do not forget to invoke this in your derived class using "super(self.__class__, self).__init__(environment, values)"
@ -82,12 +85,12 @@ class Publication(Environmentable, Serializable):
Environmentable.__init__(self, environment)
Serializable.__init__(self)
self._osManager = kwargs.get('osManager', None)
self._service = kwargs['service'] # Raises an exception if service is not included
self._service = kwargs['service'] # Raises an exception if service is not included
self._revision = kwargs.get('revision', -1)
self._dsName = kwargs.get('dsName', 'Unknown')
self.initialize()
def initialize(self):
'''
This method will be invoked from __init__ constructor.
@ -97,13 +100,13 @@ class Publication(Environmentable, Serializable):
you can here access service, osManager, ...
'''
pass
def service(self):
'''
Utility method to access parent service of this publication
Returns
Parent service instance object (not database object)
'''
return self._service
@ -111,48 +114,48 @@ class Publication(Environmentable, Serializable):
def osManager(self):
'''
Utility method to access os manager for this publication.
Returns
Parent service instance object (not database object)
The returned value can be None if no Os manager is needed by
the service owner of this publication.
'''
return self._osManager
def revision(self):
'''
Utility method to access the revision of this publication
This is a numeric value, and is set by core
'''
return self._revision
def dsName(self):
'''
Utility method to access the declared deployed service name.
This name is set by core, using the administrator provided data
at administration interface.
'''
return self._dsName
def publish(self):
'''
This method is invoked whenever the administrator requests a new publication.
The method is not invoked directly (i mean, that the administration request
do no makes a call to this method), but a DelayedTask is saved witch will
initiate all publication stuff (and, of course, call this method).
You MUST implement it, so the publication do really something.
All publications can be synchronous or asynchronous.
The main difference between both is that first do whatever needed, (the
action must be fast enough to do not block core), returning State.FINISHED.
The second (asynchronous) are publications that could block the core, so
it have to be done in more than one step.
An example publication could be a copy of a virtual machine, where:
* First we invoke the copy operation to virtualization provider
* Second, we kept needed values inside instance so we can serialize
@ -161,59 +164,59 @@ class Publication(Environmentable, Serializable):
has started but has to finish sometime later. (We do no check
again the state and keep waiting here, because we will block the
core untill this operation is finished).
:note: This method MUST be provided, an exception is raised if not.
:note: All task methods, like this one, are expected to handle
:note: All task methods, like this one, are expected to handle
all exceptions, and never raise an exception from these methods
to the core. Take that into account and handle exceptions inside
this method.
this method.
'''
raise Exception('publish method for class {0} not provided! '.format(self.__class__.__name__))
def checkState(self):
'''
This is a task method. As that, the expected return values are
State values RUNNING, FINISHED or ERROR.
This method will be invoked whenever a publication is started, but it
do not finish in 1 step.
The idea behind this is simple, we can initiate an operation of publishing,
that will be done at :py:meth:.publish method.
If this method returns that the operation has been initiated, but not finished
(State.RUNNING), the core will keep calling this method until checkState
returns State.FINISHED (or State.error).
You MUST always provide this method if you expect the publication no to be
done in 1 step (meaning this that if publish can return State.RUNNING, this
will get called)
will get called)
:note: All task methods, like this one, are expected to handle
:note: All task methods, like this one, are expected to handle
all exceptions, and never raise an exception from these methods
to the core. Take that into account and handle exceptions inside
this method.
this method.
'''
raise Exception('checkState method for class {0} not provided!!!'.format(self.__class__.__name__))
def finish(self):
'''
Invoked when Publication manager noticed that the publication has finished.
Invoked when Publication manager noticed that the publication has finished.
This give us the opportunity of cleaning up things (as stored vars, etc..)
Returned value, if any, is ignored
Default implementation does nothing. You can leave default method if you
are going to do nothing.
'''
pass
def reasonOfError(self):
'''
If a publication produces an error, here we must return the reason why
it happened. This will be called just after publish or checkPublishingState
If a publication produces an error, here we must return the reason why
it happened. This will be called just after publish or checkPublishingState
if they return State.ERROR
The returned value, an string, will be used always by administration interface,
meaning this that the translation environment will be ready, and that you
can use ugettext to return a version that can be translated to administration
@ -227,18 +230,18 @@ class Publication(Environmentable, Serializable):
State values RUNNING, FINISHED or ERROR.
Invoked for destroying a deployed service
Do whatever needed here, as deleting associated data if needed
Do whatever needed here, as deleting associated data if needed
(i.e. a copy of the machine, snapshots, etc...)
This method MUST be provided, even if you do nothing here (in that case,
simply return State.FINISHED). Default implementation will raise an
exception if it gets called
:note: All task methods, like this one, are expected to handle
:note: All task methods, like this one, are expected to handle
all exceptions, and never raise an exception from these methods
to the core. Take that into account and handle exceptions inside
this method.
'''
this method.
'''
raise Exception('destroy method for class {0} not provided!'.format(self.__class__.__name__))
def cancel(self):
@ -249,21 +252,20 @@ class Publication(Environmentable, Serializable):
This method is invoked whenever the core needs a cancelation of current
operation. This will happen if we are, for example, preparing the
service for users, but the administration request to stop doing this.
This method MUST be provided, even if you do nothing here (in that case,
simply return State.FINISHED). Default implementation will raise an
exception if it gets called
:note: All task methods, like this one, are expected to handle
:note: All task methods, like this one, are expected to handle
all exceptions, and never raise an exception from these methods
to the core. Take that into account and handle exceptions inside
this method.
this method.
'''
raise Exception('cancel method for class {0} not provided!'.format(self.__class__.__name__))
def __str__(self):
'''
String method, mainly used for debugging purposes
'''
return "Base Publication"
return "Base Publication"

View File

@ -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.
'''
@ -35,29 +35,30 @@ from __future__ import unicode_literals
from django.utils.translation import ugettext_noop as _
from uds.core import Module
class Service(Module):
'''
This class is in fact an interface, and represents a service, that is the
This class is in fact an interface, and represents a service, that is the
definition of an offering for consumers (users).
Class derived from this one declares the behavior of the service, as well
Class derived from this one declares the behavior of the service, as well
as custom parameter that will be needed to provide final consumable elements
to users.
The behavior attributes must be declared always, although they have default
values, this can change in a future and declaring all needed is a good way
to avoid future problems. Of course, if you declare that do no do something
(i.e. do not uses cache), you will not have to declare related attributes
(i.e. cacheTooltip, usesCache_L2 and cacheTooltip_L2)
(i.e. cacheTooltip, usesCache_L2 and cacheTooltip_L2)
As you derive from this class, if you provide __init__ in your own class,
remember to call ALWAYS at base class __init__ as this:
super(self.__class__, self).__init__(dbAuth, environment, values)
This is a MUST (if you override __init__), so internal structured gets
This is a MUST (if you override __init__), so internal structured gets
filled correctly, so don't forget it!.
The preferred method of provide initialization is to provide the :py:meth:`.initialize`,
and do not override __init__ method. This (initialize) will be invoked after
all internal initialization, so there will be available parent, environment and storage.
@ -70,90 +71,90 @@ class Service(Module):
default implementation marshals and unmashals them, so if your case is that you
only need data that is keeped at form fields, marshal and unmarshal and in fact
not needed.
'''
#: Constant for indicating that max elements this service can deploy is unlimited.
UNLIMITED = -1
#: Name of type, used at administration interface to identify this
#: service (i.e. Xen server, oVirt Server, ...)
#: This string will be translated when provided to admin interface
#: using ugettext, so you can mark it as "_" at derived classes (using ugettext_noop)
#: if you want so it can be translated.
typeName = _('Base Service')
#: Name of type used by Managers to identify this type of service
#: We could have used here the Class name, but we decided that the
#: module implementator will be the one that will provide a name that
#: will relation the class (type) and that name.
'''
# : Constant for indicating that max elements this service can deploy is unlimited.
UNLIMITED = -1
# : Name of type, used at administration interface to identify this
# : service (i.e. Xen server, oVirt Server, ...)
# : This string will be translated when provided to admin interface
# : using ugettext, so you can mark it as "_" at derived classes (using ugettext_noop)
# : if you want so it can be translated.
typeName = _('Base Service')
# : Name of type used by Managers to identify this type of service
# : We could have used here the Class name, but we decided that the
# : module implementator will be the one that will provide a name that
# : will relation the class (type) and that name.
typeType = 'BaseService'
#: Description shown at administration level for this service.
#: This string will be translated when provided to admin interface
#: using ugettext, so you can mark it as "_" at derived classes (using ugettext_noop)
#: if you want so it can be translated.
# : Description shown at administration level for this service.
# : This string will be translated when provided to admin interface
# : using ugettext, so you can mark it as "_" at derived classes (using ugettext_noop)
# : if you want so it can be translated.
typeDescription = _('Base Service')
#: Icon file, used to represent this service at administration interface
#: This file should be at same folder as this class is, except if you provide
#: your own :py:meth:uds.core.BaseModule.BaseModule.icon method.
iconFile = 'service.png'
# Functional related data
#: Normally set to UNLIMITED. This attribute indicates if the service has some "limitation"
#: for providing deployed services to users. This attribute can be set here or
#: modified at instance level, core will access always to it using an instance object.
maxDeployed = UNLIMITED #: If the service provides more than 1 "provided service" (-1 = no limit, 0 = ???? (do not use it!!!), N = max number to deploy
#: If this class uses cache or not. If uses cache is true, means that the
#: service can "prepare" some user deployments to allow quicker user access
#: to services if he already do not have one.
#: If you set this to True, please, provide a _ :py:attr:.cacheToolTip
usesCache = False
#: Tooltip to be used if services uses cache at administration interface, indicated by :py:attr:.usesCache
cacheTooltip = _('None') #: Tooltip shown to user when this item is pointed at admin interface
#: If user deployments can be cached (see :py:attr:.usesCache), may he also can provide a secondary cache,
#: that is no more that user deployments that are "almost ready" to be used, but preperably consumes less
#: resources than L1 cache. This can give a boost to cache L1 recovering in case of peaks
#: in demand. If you set this to True, please, provide also a _ :py:attr:.cacheTooltip_L2
usesCache_L2 = False #: If we need to generate a "Level 2" cache for this service (i.e., L1 could be running machines and L2 suspended machines)
#: Tooltip to be used if services uses L2 cache at administration interface, indicated by :py:attr:.usesCache_L2
cacheTooltip_L2 = _('None') #: Tooltip shown to user when this item is pointed at admin interface
#: If the service needs a o.s. manager (see os managers section)
needsManager = False
#: If the service can be autoassigned or needs to be assigned by administrator
#: Not all services are for assigning it. Thing, i.e., a Service that manages
#: a number of Server. The desired behavior will be to let administrator
#: the service to a user in the administration interface, an not the system
#: to assign the service automatically. If this is true, the core will not
#: assign the service automatically, so if the user do not have a consumable
#: assigned, the user will never get one (of this kind, of course)
mustAssignManually = False
#: Types of publications (preparated data for deploys)
#: If you provide this, UDS will assume that the service needs a preparation.
#: If not provided (it is None), UDS will assume that service do not needs
#: preparation. Take care, if you mark a service as it uses cache, you MUST
#: provide a publication type
#: This refers to class that provides the logic for publication, you can see
#: :py:class:uds.core.services.Publication
# : Icon file, used to represent this service at administration interface
# : This file should be at same folder as this class is, except if you provide
# : your own :py:meth:uds.core.BaseModule.BaseModule.icon method.
iconFile = 'service.png'
# Functional related data
# : Normally set to UNLIMITED. This attribute indicates if the service has some "limitation"
# : for providing deployed services to users. This attribute can be set here or
# : modified at instance level, core will access always to it using an instance object.
maxDeployed = UNLIMITED # : If the service provides more than 1 "provided service" (-1 = no limit, 0 = ???? (do not use it!!!), N = max number to deploy
# : If this class uses cache or not. If uses cache is true, means that the
# : service can "prepare" some user deployments to allow quicker user access
# : to services if he already do not have one.
# : If you set this to True, please, provide a _ :py:attr:.cacheToolTip
usesCache = False
# : Tooltip to be used if services uses cache at administration interface, indicated by :py:attr:.usesCache
cacheTooltip = _('None') # : Tooltip shown to user when this item is pointed at admin interface
# : If user deployments can be cached (see :py:attr:.usesCache), may he also can provide a secondary cache,
# : that is no more that user deployments that are "almost ready" to be used, but preperably consumes less
# : resources than L1 cache. This can give a boost to cache L1 recovering in case of peaks
# : in demand. If you set this to True, please, provide also a _ :py:attr:.cacheTooltip_L2
usesCache_L2 = False # : If we need to generate a "Level 2" cache for this service (i.e., L1 could be running machines and L2 suspended machines)
# : Tooltip to be used if services uses L2 cache at administration interface, indicated by :py:attr:.usesCache_L2
cacheTooltip_L2 = _('None') # : Tooltip shown to user when this item is pointed at admin interface
# : If the service needs a o.s. manager (see os managers section)
needsManager = False
# : If the service can be autoassigned or needs to be assigned by administrator
# : Not all services are for assigning it. Thing, i.e., a Service that manages
# : a number of Server. The desired behavior will be to let administrator
# : the service to a user in the administration interface, an not the system
# : to assign the service automatically. If this is true, the core will not
# : assign the service automatically, so if the user do not have a consumable
# : assigned, the user will never get one (of this kind, of course)
mustAssignManually = False
# : Types of publications (preparated data for deploys)
# : If you provide this, UDS will assume that the service needs a preparation.
# : If not provided (it is None), UDS will assume that service do not needs
# : preparation. Take care, if you mark a service as it uses cache, you MUST
# : provide a publication type
# : This refers to class that provides the logic for publication, you can see
# : :py:class:uds.core.services.Publication
publicationType = None
#: Types of deploys (services in cache and/or assigned to users)
#: This is ALWAYS a MUST. You mast indicate the class responsible
#: for managing the user deployments (user consumable services generated
#: from this one). If this attribute is not set, the service will never work
#: (core will not know how to handle the user deployments)
# : Types of deploys (services in cache and/or assigned to users)
# : This is ALWAYS a MUST. You mast indicate the class responsible
# : for managing the user deployments (user consumable services generated
# : from this one). If this attribute is not set, the service will never work
# : (core will not know how to handle the user deployments)
deployedType = None
def __init__(self, environment, parent, values = None):
def __init__(self, environment, parent, values=None):
'''
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
@ -162,64 +163,62 @@ class Service(Module):
super(Service, self).__init__(environment, values)
self._provider = parent
self.initialize(values)
def initialize(self, values):
'''
This method will be invoked from __init__ constructor.
This is provided so you don't have to provide your own __init__ method,
and invoke base methods.
This will get invoked when all initialization stuff is done
Args:
Values: If values is not none, this object is being initialized
from administration interface, and not unmarshal will be done.
If it's None, this is initialized internally, and unmarshal will
be called after this.
Default implementation does nothing
'''
pass
def parent(self):
'''
Utility method to access parent provider for this service
Returns
Parent provider instance object (not database object)
'''
return self._provider
def requestServicesForAssignation(self, **kwargs):
'''
override this if mustAssignManualy is True
@params kwargs: Named arguments
@params kwargs: Named arguments
@return an array with the services that we can assign (they must be of type deployedType)
We will access the returned array in "name" basis. This means that the service will be assigned by "name", so be care that every single service
returned are not repeated... :-)
'''
raise Exception('The class {0} has been marked as manually asignable but no requestServicesForAssignetion provided!!!'.format(self.__class__.__name__))
def macGenerator(self):
'''
Utility method to access provided macs generator (inside environment)
Returns the environment unique mac addresses generator
'''
return self.idGenerators('mac')
def nameGenerator(self):
'''
Utility method to access provided names generator (inside environment)
Returns the environment unique name generator
'''
return self.idGenerators('name')
def __str__(self):
'''
String method, mainly used for debugging purposes
'''
return "Base Service Provider"
return "Base Service Provider"

View File

@ -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.
'''
@ -41,21 +41,21 @@ logger = logging.getLogger(__name__)
class ServiceProvider(Module):
'''
Base Service Provider Class.
All classes that will represent a service provider will need to be derived
from this class.
The preferred way of using this class is by its alias name, provided
at uds.core.services module, ServiceProvider.
This is a very basic class, intended to be the root class of services.
This is a very basic class, intended to be the root class of services.
This means that services are childs of this class, declared at "offers" attribute.
As you derive from this class, if you provide __init__ in your own class,
remember to call ALWAYS at base class __init__ as this:
super(...., self).__init__(environment, values)
The preferred method of provide initialization is to provide the :py:meth:`.initialize`,
and do not overrie __init__ method. This (initialize) will be invoked after
all internal initialization.
@ -71,50 +71,50 @@ class ServiceProvider(Module):
only need data that is keeped at form fields, marshal and unmarshal and in fact
not needed.
'''
#: Services that we offers. Here is a list of service types (python types) that
#: this class will provide. This types are the python clases, derived from
#: Service, that are childs of this provider
offers = []
#: Name of type, used at administration interface to identify this
#: provider (i.e. Xen server, oVirt Server, ...)
#: This string will be translated when provided to admin interface
#: using ugettext, so you can mark it as "translatable" at derived classes (using ugettext_noop)
#: if you want so it can be translated.
typeName = 'Base Provider'
#: Name of type used by Managers to identify this tipe of service
#: We could have used here the Class name, but we decided that the
#: module implementator will be the one that will provide a name that
#: will relation the class (type) and that name.
# : Services that we offers. Here is a list of service types (python types) that
# : this class will provide. This types are the python clases, derived from
# : Service, that are childs of this provider
offers = []
# : Name of type, used at administration interface to identify this
# : provider (i.e. Xen server, oVirt Server, ...)
# : This string will be translated when provided to admin interface
# : using ugettext, so you can mark it as "translatable" at derived classes (using ugettext_noop)
# : if you want so it can be translated.
typeName = 'Base Provider'
# : Name of type used by Managers to identify this tipe of service
# : We could have used here the Class name, but we decided that the
# : module implementator will be the one that will provide a name that
# : will relation the class (type) and that name.
typeType = 'BaseServiceProvider'
#: Description shown at administration level for this provider.
#: This string will be translated when provided to admin interface
#: using ugettext, so you can mark it as "translatable" at derived classes (using ugettext_noop)
#: if you want so it can be translated.
# : Description shown at administration level for this provider.
# : This string will be translated when provided to admin interface
# : using ugettext, so you can mark it as "translatable" at derived classes (using ugettext_noop)
# : if you want so it can be translated.
typeDescription = 'Base Service Provider'
#: Icon file, used to represent this provider at administration interface
#: This file should be at same folder as this class is, except if you provide
#: your own py:meth:`uds.core.BaseModule.BaseModule.icon` method.
iconFile = 'provider.png'
# : Icon file, used to represent this provider at administration interface
# : This file should be at same folder as this class is, except if you provide
# : your own py:meth:`uds.core.BaseModule.BaseModule.icon` method.
iconFile = 'provider.png'
@classmethod
def getServicesTypes(cls):
'''
Returns what type of services this provider offers
'''
return cls.offers
@classmethod
def getServiceByType(cls, typeName):
'''
Tries to locate a child service which type corresponds with the
one provided.
Returns None if can't find one.
:note: The type that this method looks for is not the class, but
the typeType that Service has.
'''
@ -125,8 +125,7 @@ class ServiceProvider(Module):
break
return res
def __init__(self, environment, values = None):
def __init__(self, environment, values=None):
'''
Do not forget to invoke this in your derived class using "super(self.__class__, self).__init__(environment, values)"
if you override this method. Better is to provide an "__initialize__" method, that will be invoked
@ -136,7 +135,6 @@ class ServiceProvider(Module):
'''
super(ServiceProvider, self).__init__(environment, values)
self.initialize(values)
def initialize(self, values):
'''
@ -144,21 +142,20 @@ class ServiceProvider(Module):
This is provided so you don't have to provide your own __init__ method,
and invoke base methods.
This will get invoked when all initialization stuff is done
Args:
Values: If values is not none, this object is being initialized
from administration interface, and not unmarshal will be done.
If it's None, this is initialized internally, and unmarshal will
be called after this.
Default implementation does nothing
'''
pass
def __str__(self):
'''
Basic implementation, mostly used for debuging and testing, never used
at user or admin interfaces.
'''
return "Base Service Provider"
return "Base Service Provider"

View File

@ -4,41 +4,43 @@
# 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.
'''
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from BasePublication import Publication
class ClusteredPublication(Publication):
def __str__(self):
'''
String method, mainly used for debugging purposes
'''
return "Base Clustered Publication"
return "Base Clustered Publication"
# These methods must be overriden
def getNode(self):
@ -46,4 +48,3 @@ class ClusteredPublication(Publication):
Returns on wich node this publication has been deployed
'''
raise Exception('getNode method of ClusteredPublication must be overriden!')

View File

@ -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.
'''
@ -35,12 +35,13 @@ from __future__ import unicode_literals
from django.utils.translation import ugettext_noop as _
from BaseService import Service
class ClusteredService(Service):
typeName = _('Base Clustered Service')
typeName = _('Base Clustered Service')
typeType = 'BaseClusteredService'
typeDescription = _('Base Clustered Service')
iconFile = 'service.png'
iconFile = 'service.png'
# Utility methods
def getClusterBestNodeForDeploy(self):
return self.parent().getClusterBestNodeForDeploy()
return self.parent().getClusterBestNodeForDeploy()

View File

@ -4,34 +4,33 @@
# 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.
'''
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
#from __future__ import with_statement
from BaseServiceProvider import ServiceProvider
from uds.core.util.Config import GlobalConfig
@ -42,207 +41,203 @@ logger = logging.getLogger(__name__)
HEIGHT_OF_CPU = 5
class ClusteredServiceProvider(ServiceProvider):
'''
This class represents a Clustered Service Provider, that is, a Service provider that forms a Cluster and needs
"organization".
It adds the needed methods to keep cluster "in good shape"
'''
typeName = 'Base Clustered Provider'
typeName = 'Base Clustered Provider'
typeType = 'BaseClusteredServiceProvider'
typeDescription = 'Base Clustered Service Provider'
iconFile = 'provider.png'
balanceNodes = False # If false, clustered provider will not try to balance nodes (only tries to distribute services on best node on creation)
allowInUseMigration = False # If True, means that we can migrate a service while it is being used
canRegisterServiceOnNodeFailure = False # If can register a service on another node without accesing original node
balanceNodes = False # If false, clustered provider will not try to balance nodes (only tries to distribute services on best node on creation)
allowInUseMigration = False # If True, means that we can migrate a service while it is being used
canRegisterServiceOnNodeFailure = False # If can register a service on another node without accesing original node
# This methods do not need to be overriden
def clusterStats(self):
stats = self.storage().getPickle('ClusterStats')
if stats is None:
stats = {}
return stats
# This method do not need to be overriden, but can be if it is needed (taking care ofc :-) )
def getClusterOverloadedNodes(self):
'''
Checks if a migration is desired, based on nodes load
This method will return:
Array of NodeName, preferably sorted by priority, with nodes that are "Overloaded".
This array, ofc, can be "empty"
'''
if self.balanceNodes is False:
return []
overloadedNodes = []
nodesStats = self.clusterStats()
maxCpuLoad = GlobalConfig.CLUSTER_MIGRATE_CPULOAD.getInt(True)
minFreeMemPercent = GlobalConfig.CLUSTER_MIGRATE_MEMORYLOAD.getInt(True)
for nodeName, nodeStats in nodesStats.iteritems():
if nodeStats['freeMemory'] is None or nodeStats['totalMemory'] is None or nodeStats['cpuLoad'] is None:
continue
freeMemPercent = (nodeStats['freeMemory'] * 100) / nodeStats['totalMemory']
if nodeStats['cpuLoad'] > maxCpuLoad or freeMemPercent < minFreeMemPercent:
overloadedNodes.append(nodeName)
# Helper to sort array
def getNodeStatsKey(name):
val = 0
if nodesStats[name]['cpuLoad']>maxCpuLoad:
if nodesStats[name]['cpuLoad'] > maxCpuLoad:
val += HEIGHT_OF_CPU + nodesStats[name]['cpuLoad']
val += 100 - (nodeStats['freeMemory'] * 100) / nodeStats['totalMemory']
return val
# Here we sort nodes so most overloaded servers are migrated first
return sorted(overloadedNodes, key=getNodeStatsKey)
# Same as before, this method do not need to be overriden,
def getClusterUnderloadedNodes(self):
'''
Checks which nodes of the cluster are elegible for destination of machines
This method is very similar to getClusterOverloadedNodes, but this returns
a list of nodes where we can migrate the services.
a list of nodes where we can migrate the services.
This method will return:
Array of NodeName, preferably sorted by priority, with nodes that are "Underloaded"
This array, ofc, can be "empty"
'''
if self.balanceNodes is False:
return []
underloadedNodes = []
nodesStats = self.clusterStats()
maxCpuLoad = GlobalConfig.CLUSTER_ELEGIBLE_CPULOAD.getInt(True)
minFreeMemPercent = GlobalConfig.CLUSTER_ELEGIBLE_MEMORYLOAD.getInt(True)
for nodeName, nodeStats in nodesStats.iteritems():
if nodeStats['freeMemory'] is None or nodeStats['totalMemory'] is None or nodeStats['cpuLoad'] is None:
continue
freeMemPercent = (nodeStats['freeMemory'] * 100) / nodeStats['totalMemory']
if nodeStats['cpuLoad'] < maxCpuLoad and freeMemPercent > minFreeMemPercent:
underloadedNodes.append(nodeName)
# Helper to sort array
def getNodeStatsKey(name):
ns = nodesStats[name]
memUsePercent = (ns['freeMemory'] * 100) / ns['totalMemory']
# Percents of cpu is weighted over memory
val = (maxCpuLoad - ns['cpuLoad']) * HEIGHT_OF_CPU + (minFreeMemPercent - memUsePercent)
# Percents of cpu is weighted over memory
val = (maxCpuLoad - ns['cpuLoad']) * HEIGHT_OF_CPU + (minFreeMemPercent - memUsePercent)
return -val
# Here we sort nodes so most overloaded servers are migrated first
return sorted(underloadedNodes, key=getNodeStatsKey)
def getClusterBestNodeForDeploy(self):
nodesStats = self.clusterStats()
nodes = [name for name in nodesStats.iterkeys()]
def getNodeStatsKey(name):
ns = nodesStats[name]
if ns['freeMemory'] is None or ns['totalMemory'] is None or ns['cpuLoad'] is None:
return 0 # We will put last if do not knwo anything about a node
return 0 # We will put last if do not knwo anything about a node
memUsePercent = (ns['freeMemory'] * 100) / ns['totalMemory']
val = (100-ns['cpuLoad']) * HEIGHT_OF_CPU + (100-memUsePercent)
val = (100 - ns['cpuLoad']) * HEIGHT_OF_CPU + (100 - memUsePercent)
return -val
return sorted(nodes, key=getNodeStatsKey)
def getServicesForBalancing(self, clusterNode):
'''
Select machines from the specified nodes that can be "migrated"
Select machines from the specified nodes that can be "migrated"
so we can balance nodes.
This method returns a generator
If load balancing is not enabled for this cluster, this method will return an empty generator
If load balancing is not enabled for this cluster, this method will return an empty generator
If allowInUseMigration is not enabled, this method will only return services not in use
Only service "fully ready" (in State "active") are eligible for mitrations
This method will return an array of services, db Objects, that are on the specified nodes
and are "ready" for migration. The calling method MUST lock for update the record and
update the state so it's not assigned while in migration (balancing operation)
'''
from uds.models import UserService
from uds.core.util.State import State
if self.balanceNodes is False:
return []
fltr = UserService.objects.filter(cluster_node=clusterNode, state=State.USABLE)
if self.allowInUseMigration is False:
fltr = fltr.filter(in_use=False)
res = []
for srvc in fltr:
res.append(srvc)
return res
def locateClusterService(self, serviceInstance):
'''
This method tries to locate a service instance on every node
To make this, tries to connect to all nodes and look for service.
To make this, tries to connect to all nodes and look for service.
This method can be a bit "slow", because it has to ask so we will probably redesign it using ThreadPool
'''
from uds.core.util.ThreadPool import ThreadPool
node = None
def isInNode(n):
if serviceInstance.ensureExistsOnNode(n) is True:
node = n
pool = ThreadPool(10)
for n in self.getClusterNodes():
pool.add_task(isInNode, n)
pool.wait_completion()
return node
# This methods must be overriden
def getClusterNodes(self):
'''
This method must be overriden.
returns the nodes of this clusters as an array dictionaries, with the id of nodes and the is the node is "active".
Active means that it is ready to process services, inactive means that services are not available
Active means that it is ready to process services, inactive means that services are not available
This ids must be recognized later by nodes methods of ClusteredServiceProvider
Example:
[ { 'id': 'node1', 'active': True }, { 'id': 'node2', 'active': False }]
'''
return []
def getClusterNodeLoad(self, nodeId):
'''
This method must be overriden
Returns the load of a node of the cluster, as a dictionary, with 3 informations used right now:
{ 'cpuLoad':, 'freeMemory'}
If any value is not known or can't be obtained, this can be not included in resulting dictionary, or
it's value can be None
The units for elements are:
* cpuLoad: Load of cpu of Node (use) in %. If server has more than one CPU, average can be used (Integer)
* freeMemory: Unused memory (or usable memory) of node, expressed in Kb (Integer)
* totalMemory: Total memory of node, expressed in Kb (Integer)
'''
return {'cpuLoad': None, 'freeMemory': None, 'totalMemory': None} # We could have used return {}, but i prefer this "sample template"
return {'cpuLoad': None, 'freeMemory': None, 'totalMemory': None} # We could have used return {}, but i prefer this "sample template"

View File

@ -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.
'''
@ -35,11 +35,12 @@ from __future__ import unicode_literals
from BaseDeployed import UserDeployment
from uds.core.util.State import State
class ClusteredUserDeployment(UserDeployment):
def startMigration(self, dstNode):
return State.FINISHED
def ensureExistsOnNode(self, node):
'''
Ensure that this method is reentrant, because it can be asked for existence in parallel
@ -50,4 +51,4 @@ class ClusteredUserDeployment(UserDeployment):
'''
Mainly used for debugging purposses
'''
return "Base Deployed Service"
return "Base Deployed Service"

View File

@ -4,71 +4,78 @@
# 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.
'''
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
'''
class UnsupportedException(Exception):
'''
Reflects that we request an operation that is not supported, i.e. Cancel a publication with snapshots
'''
pass
class OperationException(Exception):
'''
Reflects that the operation requested can't be acomplished, i.e. remove an snapshot without snapshot reference, cancel non running operation, etc...
'''
pass
class PublishException(Exception):
'''
Reflects thate the publication can't be done for causes we don't know in advance
'''
pass
class DeploymentException(Exception):
'''
Reflects that a deployment of a service (at cache, or assigned to user) can't be done for causes we don't know in advance
'''
pass
pass
class CancelException(Exception):
'''
Reflects that a "cancel" operation can't be done for some reason
'''
class InvalidServiceException(Exception):
'''
Invalid service specified. The service is not ready
'''
pass
class MaxServicesReachedException(Exception):
'''
Number of maximum services has been reached, and no more services
can be created for users.
'''
pass
pass

View File

@ -4,66 +4,69 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
import logging
logger = logging.getLogger(__name__)
class ServiceProviderFactory(object):
'''
This class holds the register of all known service provider modules
inside UDS.
It provides a way to register and recover providers providers.
'''
_factory = None
def __init__(self):
'''
Initializes internal dictionary for service providers registration
'''
self._providers = {}
@staticmethod
@staticmethod
def factory():
'''
Returns the factory that keeps the register of service providers.
'''
if ServiceProviderFactory._factory == None:
if ServiceProviderFactory._factory == None:
ServiceProviderFactory._factory = ServiceProviderFactory()
return ServiceProviderFactory._factory
def providers(self):
'''
Returns the list of service providers already registered.
'''
return self._providers
def insert(self, type_):
'''
Inserts type_ as a service provider
@ -72,12 +75,12 @@ class ServiceProviderFactory(object):
# We could also check if it provides at least a service, but
# for debugging purposes, it's better to not check that
# We will check that if service provided by "provider" needs
# cache, but service do not provides publicationType,
# cache, but service do not provides publicationType,
# that service will not be registered and it will be informed
if self._providers.get(type_.type(), None) is not None:
logger.debug('{0} already registered as Service Provider'.format(type_))
return
offers = []
for s in type_.offers:
if s.usesCache_L2 is True:
@ -87,20 +90,20 @@ class ServiceProviderFactory(object):
type_, s))
continue
offers.append(s)
# Only offers valid services
type_.offers = offers
logger.debug('Adding provider {0} as {1}'.format(type_.type(), type_))
self._providers[type_.type()] = type_
def lookup(self, typeName):
'''
Tries to locate a server provider and by its name, and, if
not found, returns None
'''
return self._providers.get(typeName, None)
def servicesThatDoNotNeedPublication(self):
'''
Returns a list of all service providers registered that do not need

View File

@ -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.
'''
@ -42,9 +42,10 @@ from ClusteredServiceProvider import ClusteredServiceProvider
from ClusteredService import ClusteredService
from ClusteredPublication import ClusteredPublication
from ClusteredUserDeployment import ClusteredUserDeployment
import Exceptions
def factory():
'''
Returns factory for register/access to service providers

View File

@ -4,32 +4,33 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from django.utils.translation import ugettext as _
from uds.core.util import OsDetector
@ -45,12 +46,12 @@ class Transport(Module):
'''
An OS Manager is responsible for communication the service the different actions to take (i.e. adding a windows machine to a domain)
The Service (i.e. virtual machine) communicates with the OSManager via a published web method, that must include the unique ID.
In order to make easier to agents identify themselfs, the Unique ID can be a list with various Ids (i.e. the macs of the virtual machine).
In order to make easier to agents identify themselfs, the Unique ID can be a list with various Ids (i.e. the macs of the virtual machine).
Server will iterate thought them and look for an identifier associated with the service. This list is a comma separated values (i.e. AA:BB:CC:DD:EE:FF,00:11:22:...)
Remember also that we inherit the test and check methods from BaseModule
'''
# Transport informational related data, inherited from BaseModule
typeName = 'Base Transport Manager'
# Transport informational related data, inherited from BaseModule
typeName = 'Base Transport Manager'
typeType = 'Base Transport'
typeDescription = 'Base Transport'
iconFile = 'transport.png'
@ -59,46 +60,46 @@ class Transport(Module):
# Windows
# Macintosh
# Linux
supportedOss = OsDetector.desktopOss # Supported operating systems
supportedOss = OsDetector.desktopOss # Supported operating systems
# If this transport is visible via Web, via Thick Client or both
webTransport = False
tcTransport = False
def __init__(self,environment, values):
def __init__(self, environment, values):
super(Transport, self).__init__(environment, values)
self.initialize(values)
def initialize(self, values):
'''
This method will be invoked from __init__ constructor.
This is provided so you don't have to provide your own __init__ method,
and invoke base methods.
This will get invoked when all initialization stuff is done
Args:
Values: If values is not none, this object is being initialized
from administration interface, and not unmarshal will be done.
If it's None, this is initialized internally, and unmarshal will
be called after this.
Default implementation does nothing
'''
pass
def destroy(self):
'''
Invoked when Transport is deleted
'''
pass
def isAvailableFor(self, ip):
'''
Checks if the transport is available for the requested destination ip
Override this in yours transports
'''
return False
@classmethod
def supportsOs(cls, osName):
'''
@ -107,17 +108,17 @@ class Transport(Module):
'''
logger.debug('Checking suported os {0} against {1}'.format(osName, cls.supportedOss))
return cls.supportedOss.count(osName) > 0
@classmethod
def providesConnetionInfo(cls):
'''
Helper method to check if transport provides information about connection
'''
return cls.getConnectionInfo != Transport.getConnectionInfo
def getConnectionInfo(self, service, user, password):
'''
This method must provide information about connection.
This method must provide information about connection.
We don't have to implement it, but if we wont to allow some types of connections
(such as Client applications, some kinds of TC, etc... we must provide it or those
kind of terminals/application will not work
@ -126,20 +127,20 @@ class Transport(Module):
userService: DeployedUserService for witch we are rendering the connection (db model), or DeployedService (db model)
user: user (dbUser) logged in
pass: password used in authentication
The expected result from this method is a dictionary, containing at least:
'protocol': protocol to use, (there are a few standard defined in 'protocols.py', if yours does not fit those, use your own name
'username': username (transformed if needed to) used to login to service
'password': password (transformed if needed to) used to login to service
'domain': domain (extracted from username or wherever) that will be used. (Not necesarily an AD domain)
:note: The provided service can be an user service or an deployed service (parent of user services).
I have implemented processUserPassword in both so in most cases we do not need if the service is
DeployedService or UserService. In case of processUserPassword for an DeployedService, no transformation
is done, because there is no relation at that level between user and service.
'''
return {'protocol': protocols.NONE, 'username': '', 'password': '', 'domain': ''}
def renderForHtml(self, userService, idUserService, idTransport, ip, os, user, password):
'''
Requests the html rendering of connector for the destination ip, (dbUser) and password
@ -151,16 +152,15 @@ class Transport(Module):
@param pass: password used in authentication
'''
return _('Transport empty')
def getHtmlComponent(self, id, os, componentId):
def getHtmlComponent(self, id, os, componentId): # @ReservedAssignment
'''
This is a method to let the transport add own components (images, applets, or whatever) to the rendered html
The reference to object will be the access to the uds.web.views.transcomp, with parameters transportId = ourTransportId and
The reference to object will be the access to the uds.web.views.transcomp, with parameters transportId = ourTransportId and
componentId = one id recognized by this method
We expect an return array, with first parameter as mime/type and second the content to return
'''
return ['text/plain', '']
def __str__(self):
return "Base OS Manager"
return "Base OS Manager"

View File

@ -4,55 +4,58 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
import logging
logger = logging.getLogger(__name__)
class TransportsFactory(object):
_factory = None
def __init__(self):
self._jobs = {}
@staticmethod
@staticmethod
def factory():
if TransportsFactory._factory == None:
if TransportsFactory._factory == None:
TransportsFactory._factory = TransportsFactory()
return TransportsFactory._factory
def providers(self):
return self._jobs
def insert(self, type):
logger.debug('Adding transport {0} as {1}'.format(type.type(), type))
self._jobs[type.type()] = type
def insert(self, type_):
logger.debug('Adding transport {0} as {1}'.format(type_.type(), type_))
self._jobs[type_.type()] = type_
def lookup(self, typeName):
try:
return self._jobs[typeName]

View File

@ -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.
'''
@ -32,8 +32,11 @@ UDS Service modules interfaces and classes.
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from BaseTransport import Transport
def factory():
'''
Returns factory for register/access to service providers

View File

@ -4,32 +4,33 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
NONE = ''
RDP = 'rdp'
@ -42,4 +43,4 @@ HDX = 'hdx'
ICA = 'ica'
NX = 'nx'
X11 = 'x11'
OTHER = 'other'
OTHER = 'other'

File diff suppressed because it is too large Load Diff

View File

@ -4,27 +4,27 @@
# Copyright (c) 2014 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.
'''
@ -34,11 +34,12 @@ from __future__ import unicode_literals
from uds.core.util.Config import GlobalConfig
def template(template_name):
theme_path = GlobalConfig.UDS_THEME.get(True)
if theme_path == 'default':
theme_path = ''
else:
theme_path += '/'
return 'uds/{0}{1}'.format(theme_path, template_name)
return 'uds/{0}{1}'.format(theme_path, template_name)

View File

@ -4,58 +4,61 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from uds.core.Serializable import Serializable
import cPickle
import timeit
class Attribute(object):
def __init__(self, theType, value = None):
def __init__(self, theType, value=None):
self._type = theType
self.setValue(value)
def getType(self):
return self._type
def getValue(self):
return self._value
def getStrValue(self):
return str(self._value)
def setValue(self, value):
if value is None:
self._value = self._type()
else:
self._value = self._type(value)
class AutoAttributes(Serializable):
'''
Easy creation of attributes to marshal & unmarshal at modules
@ -64,45 +67,45 @@ class AutoAttributes(Serializable):
or with declare(attr1=type,attr2=type,..)
Access attrs as "self._attr1, self._attr2"
'''
#: This codec is not intended to override Serializable codec
#: Serializable codec is for encoding marshaled data,
#: while this codec is for encoding pickled data from autoattributes
# : This codec is not intended to override Serializable codec
# : Serializable codec is for encoding marshaled data,
# : while this codec is for encoding pickled data from autoattributes
ACODEC = 'zip'
def __init__(self, **kwargs):
self.declare(**kwargs)
def __getattribute__(self, name):
if name.startswith('_') and self.dict.has_key(name[1:]):
return self.dict[name[1:]].getValue()
return object.__getattribute__(self, name)
def __setattr__(self, name, value):
if name.startswith('_') and self.dict.has_key(name[1:]):
self.dict[name[1:]].setValue(value)
else:
object.__setattr__(self, name, value)
def declare(self, **kwargs):
d = {}
for key,typ in kwargs.iteritems():
for key, typ in kwargs.iteritems():
d[key] = Attribute(typ)
self.dict = d
def marshal(self):
return '\2'.join( [ '%s\1%s' % (k, cPickle.dumps(v)) for k, v in self.dict.iteritems() ] ).encode(AutoAttributes.ACODEC)
return '\2'.join(['%s\1%s' % (k, cPickle.dumps(v)) for k, v in self.dict.iteritems()]).encode(AutoAttributes.ACODEC)
def unmarshal(self, data):
if data == '': # Can be empty
if data == '': # Can be empty
return
# We keep original data (maybe incomplete)
for pair in data.decode(AutoAttributes.ACODEC).split('\2'):
k, v = pair.split('\1')
self.dict[k] = cPickle.loads(v)
def __str__(self):
str = '<AutoAttribute '
str_ = '<AutoAttribute '
for k, v in self.dict.iteritems():
str += "%s (%s) = %s" % (k, v.getType(), v.getStrValue())
return str + '>'
str_ += "%s (%s) = %s" % (k, v.getType(), v.getStrValue())
return str_ + '>'

View File

@ -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,27 +40,26 @@ import cPickle
logger = logging.getLogger(__name__)
class Cache(object):
DEFAULT_VALIDITY = 60
CODEC = 'base64' # Can be zip, hez, bzip, base64, uuencoded
def __init__(self, owner):
self._owner = owner
def __getKey(self, key):
import os
h = hashlib.md5()
h.update(self._owner + key)
return h.hexdigest()
def get(self,skey, defValue = None):
def get(self, skey, defValue=None):
now = getSqlDatetime()
#logger.debug('Requesting key "%s" for cache "%s"' % (skey, self._owner,))
# logger.debug('Requesting key "%s" for cache "%s"' % (skey, self._owner,))
try:
key = self.__getKey(skey)
c = dbCache.objects.get(pk=key)
expired = now > c.created + timedelta(seconds = c.validity)
expired = now > c.created + timedelta(seconds=c.validity)
if expired:
return defValue
val = cPickle.loads(c.value.decode(Cache.CODEC))
@ -68,27 +67,27 @@ class Cache(object):
except dbCache.DoesNotExist:
logger.debug('key not found')
return defValue
def remove(self,skey):
#logger.debug('Removing key "%s" for uService "%s"' % (skey, self._owner))
def remove(self, skey):
# logger.debug('Removing key "%s" for uService "%s"' % (skey, self._owner))
try:
key = self.__getKey(skey)
dbCache.objects.get(pk=key).delete()
except dbCache.DoesNotExist:
logger.debug('key not found')
def clean(self):
Cache.delete(self._owner)
def put(self, skey, value, validity = None):
#logger.debug('Saving key "%s" for cache "%s"' % (skey, self._owner,))
def put(self, skey, value, validity=None):
# logger.debug('Saving key "%s" for cache "%s"' % (skey, self._owner,))
if validity == None:
validity = Cache.DEFAULT_VALIDITY
key = self.__getKey(skey)
value = cPickle.dumps(value).encode(Cache.CODEC)
now = getSqlDatetime()
try:
dbCache.objects.create( owner = self._owner, key = key, value = value, created = now, validity = validity )
dbCache.objects.create(owner=self._owner, key=key, value=value, created=now, validity=validity)
except Exception:
# Already exists, modify it
c = dbCache.objects.get(pk=key)
@ -98,9 +97,9 @@ class Cache(object):
c.created = datetime.now()
c.validity = validity
c.save()
def refresh(self, skey):
#logger.debug('Refreshing key "%s" for cache "%s"' % (skey, self._owner,))
# logger.debug('Refreshing key "%s" for cache "%s"' % (skey, self._owner,))
try:
key = self.__getKey(skey)
c = dbCache.objects.get(pk=key)
@ -109,21 +108,20 @@ class Cache(object):
except dbCache.DoesNotExist:
logger.debug('Can\'t refresh cache key %s because it don\'t exists' % skey)
return
@staticmethod
def purge():
dbCache.objects.all().delete()
@staticmethod
def cleanUp():
dbCache.cleanUp()
@staticmethod
def delete(owner = None):
#logger.info("Deleting cache items")
def delete(owner=None):
# logger.info("Deleting cache items")
if owner == None:
objects = dbCache.objects.all()
else:
objects = dbCache.objects.filter(owner=owner)
objects.delete()

View File

@ -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.
'''
@ -43,13 +43,14 @@ GLOBAL_SECTION = 'UDS'
SECURITY_SECTION = 'Security'
CLUSTER_SECTION = 'Cluster'
class Config(object):
'''
Keeps persistend configuration data
'''
class _Value(object):
def __init__(self, section, key, default = '', crypt = False, longText = False):
def __init__(self, section, key, default='', crypt=False, longText=False):
self._section = section
self._key = key
self._crypt = crypt
@ -59,19 +60,19 @@ class Config(object):
else:
self._default = CryptoManager.manager().encrypt(default)
self._data = None
def get(self, force = False):
def get(self, force=False):
try:
if force or self._data is None:
#logger.debug('Accessing db config {0}.{1}'.format(self._section.name(), self._key))
# logger.debug('Accessing db config {0}.{1}'.format(self._section.name(), self._key))
readed = dbConfig.objects.filter(section=self._section.name(), key=self._key)[0]
self._data = readed.value
self._crypt = [self._crypt, True][readed.crypt] # True has "higher" precedende than False
self._crypt = [self._crypt, True][readed.crypt] # True has "higher" precedende than False
self._longText = readed.long
except Exception:
# Not found
if self._default != '' and self._crypt:
self.set( CryptoManager.manager().decrypt(self._default) )
self.set(CryptoManager.manager().decrypt(self._default))
elif not self._crypt:
self.set(self._default)
self._data = self._default
@ -80,7 +81,7 @@ class Config(object):
else:
return self._data
def getInt(self, force = False):
def getInt(self, force=False):
try:
return int(self.get(force))
except Exception:
@ -90,21 +91,21 @@ class Config(object):
except:
logger.error('Default value for {0}.{1} is also invalid (integer expected)'.format(self._section, self._key))
return -1
def getBool(self, force = False):
def getBool(self, force=False):
if self.get(force) == '0':
return False
return True
def key(self):
return self._key
def section(self):
return self._section.name()
def isCrypted(self):
return self._crypt
def isLongText(self):
return self._longText
@ -117,46 +118,44 @@ class Config(object):
logger.debug('Saving config {0}.{1} as {2}'.format(self._section.name(), self._key, value))
try:
if dbConfig.objects.filter(section=self._section.name(), key=self._key).update(value=value, crypt=self._crypt, long=self._longText) == 0:
raise Exception() # Do not exists, create a new one
raise Exception() # Do not exists, create a new one
except Exception:
try:
dbConfig.objects.create(section=self._section.name(), key=self._key, value=value, crypt=self._crypt, long=self._longText)
except Exception:
# Probably a migration issue, just ignore it
logger.info("Could not save configuration key {0}.{1}".format(self._section.name(), self._key))
class _Section:
def __init__(self, sectionName):
self._sectionName = sectionName
def value(self, key, default = ''):
def value(self, key, default=''):
return Config._Value(self, key, default)
def valueCrypt(self, key, default = ''):
def valueCrypt(self, key, default=''):
return Config._Value(self, key, default, True)
def valueLong(self, key, default = ''):
def valueLong(self, key, default=''):
return Config._Value(self, key, default, False, True)
def name(self):
return self._sectionName
@staticmethod
def section(sectionName):
return Config._Section(sectionName)
@staticmethod
def enumerate():
for cfg in dbConfig.objects.all():
for cfg in dbConfig.objects.all().order_by('key'):
logger.debug('{0}.{1}:{2}'.format(cfg.section, cfg.key, cfg.value))
if cfg.crypt is True:
val = Config.section(cfg.section).valueCrypt(cfg.key)
else:
val = Config.section(cfg.section).value(cfg.key)
val = Config.section(cfg.section).value(cfg.key)
yield val
@staticmethod
def update(section, key, value):
# If cfg value does not exists, simply ignore request
@ -169,14 +168,15 @@ class Config(object):
logger.debug('Updated value for {0}.{1} to {2}'.format(section, key, value))
except Exception:
pass
class GlobalConfig(object):
'''
Simple helper to keep track of global configuration
'''
SESSION_EXPIRE_TIME = Config.section(GLOBAL_SECTION).value('sessionExpireTime', '24') # Max session duration (in use) after a new publishment has been made
# Delay between cache checks. reducing this number will increase cache generation speed but also will load service providers
CACHE_CHECK_DELAY = Config.section(GLOBAL_SECTION).value('cacheCheckDelay', '19')
CACHE_CHECK_DELAY = Config.section(GLOBAL_SECTION).value('cacheCheckDelay', '19')
# Delayed task number of threads PER SERVER, with higher number of threads, deplayed task will complete sooner, but it will give more load to overall system
DELAYED_TASKS_THREADS = Config.section(GLOBAL_SECTION).value('delayedTasksThreads', '4')
# Number of scheduler threads running PER SERVER, with higher number of threads, deplayed task will complete sooner, but it will give more load to overall system
@ -184,33 +184,33 @@ class GlobalConfig(object):
# Waiting time before removing "errored" and "removed" publications, cache, and user assigned machines. Time is in seconds
CLEANUP_CHECK = Config.section(GLOBAL_SECTION).value('cleanupCheck', '3607')
# Time to maintaing "info state" items before removing it, in seconds
KEEP_INFO_TIME = Config.section(GLOBAL_SECTION).value('keepInfoTime', '14401') # Defaults to 2 days 172800?? better 4 hours xd
KEEP_INFO_TIME = Config.section(GLOBAL_SECTION).value('keepInfoTime', '14401') # Defaults to 2 days 172800?? better 4 hours xd
# Max number of services to be "preparing" at same time
MAX_PREPARING_SERVICES = Config.section(GLOBAL_SECTION).value('maxPreparingServices', '15') # Defaults to 15 services at once (per service provider)
MAX_PREPARING_SERVICES = Config.section(GLOBAL_SECTION).value('maxPreparingServices', '15') # Defaults to 15 services at once (per service provider)
# Max number of service to be at "removal" state at same time
MAX_REMOVING_SERVICES = Config.section(GLOBAL_SECTION).value('maxRemovingServices', '15') # Defaults to 15 services at once (per service provider)
MAX_REMOVING_SERVICES = Config.section(GLOBAL_SECTION).value('maxRemovingServices', '15') # Defaults to 15 services at once (per service provider)
# If we ignore limits (max....)
IGNORE_LIMITS = Config.section(GLOBAL_SECTION).value('ignoreLimits', '0')
# Number of services to initiate removal per run of CacheCleaner
USER_SERVICE_CLEAN_NUMBER = Config.section(GLOBAL_SECTION).value('userServiceCleanNumber', '3') # Defaults to 3 per wun
USER_SERVICE_CLEAN_NUMBER = Config.section(GLOBAL_SECTION).value('userServiceCleanNumber', '3') # Defaults to 3 per wun
# Removal Check time for cache, publications and deployed services
REMOVAL_CHECK = Config.section(GLOBAL_SECTION).value('removalCheck', '31') # Defaults to 30 seconds
REMOVAL_CHECK = Config.section(GLOBAL_SECTION).value('removalCheck', '31') # Defaults to 30 seconds
# Login URL
LOGIN_URL = Config.section(GLOBAL_SECTION).value('loginUrl', '/login') # Defaults to /login
LOGIN_URL = Config.section(GLOBAL_SECTION).value('loginUrl', '/login') # Defaults to /login
# Session duration
USER_SESSION_LENGTH = Config.section(SECURITY_SECTION).value('userSessionLength', '14400') # Defaults to 4 hours
USER_SESSION_LENGTH = Config.section(SECURITY_SECTION).value('userSessionLength', '14400') # Defaults to 4 hours
# Superuser (do not need to be at database!!!)
SUPER_USER_LOGIN = Config.section(SECURITY_SECTION).value('superUser', 'root') # Defaults to 4 hours
SUPER_USER_LOGIN = Config.section(SECURITY_SECTION).value('superUser', 'root') # Defaults to 4 hours
# Superuser password (do not need to be at database!!!)
SUPER_USER_PASS = Config.section(SECURITY_SECTION).valueCrypt('rootPass', 'udsmam0')
# Idle time before closing session on admin
SUPER_USER_ALLOW_WEBACCESS = Config.section(SECURITY_SECTION).value('allowRootWebAccess', '1')
# Time an admi session can be idle before being "logged out"
ADMIN_IDLE_TIME = Config.section(SECURITY_SECTION).value('adminIdleTime', '14400') # Defaults to 4 hous
ADMIN_IDLE_TIME = Config.section(SECURITY_SECTION).value('adminIdleTime', '14400') # Defaults to 4 hous
# Time betwen checks of unused services by os managers
# Unused services will be invoked for every machine assigned but not in use AND that has been assigned at least this time
# (only if os manager asks for this characteristic)
CHECK_UNUSED_TIME = Config.section(GLOBAL_SECTION).value('checkUnusedTime', '631') # Defaults to 10 minutes
CHECK_UNUSED_TIME = Config.section(GLOBAL_SECTION).value('checkUnusedTime', '631') # Defaults to 10 minutes
# Default CSS Used
CSS = Config.section(GLOBAL_SECTION).value('css', settings.STATIC_URL + 'css/uds.css')
# Max logins before blocking an account
@ -239,12 +239,12 @@ class GlobalConfig(object):
STATS_DURATION = Config.section(GLOBAL_SECTION).value('statsDuration', '365')
# If disallow login using /login url, and must go to an authenticator
DISALLOW_GLOBAL_LOGIN = Config.section(GLOBAL_SECTION).value('disallowGlobalLogin', '0')
# Allowed "trusted sources" for request
TRUSTED_SOURCES = Config.section(SECURITY_SECTION).value('Trusted Hosts', '*')
# Clusters related vars
# Maximum desired CPU Load. If cpu is over this value, a migration of a service is "desirable"
CLUSTER_MIGRATE_CPULOAD = Config.section(CLUSTER_SECTION).value('Migration CPU Load', '80')
# Maximum CPU Load for a node to be elegible for destination of a migration
@ -254,17 +254,17 @@ class GlobalConfig(object):
CLUSTER_MIGRATE_MEMORYLOAD = Config.section(CLUSTER_SECTION).value('Migration Free Memory', '20')
# Minimum Free memory for a node to be elegible for a destination of a migration
CLUSTER_ELEGIBLE_MEMORYLOAD = Config.section(CLUSTER_SECTION).value('Migration Free Memory', '40')
# Gui vars
UDS_THEME = Config.section(GLOBAL_SECTION).value('UDS Theme', 'html5')
initDone = False
@staticmethod
def initialize():
try:
if GlobalConfig.initDone is False:
# All configurations are upper case
# All configurations are upper case
# Tries to initialize database data for global config so it is stored asap and get cached for use
for v in GlobalConfig.__dict__.itervalues():
if type(v) is Config._Value:
@ -272,10 +272,11 @@ class GlobalConfig(object):
GlobalConfig.initDone = True
except:
logger.debug('Config table do not exists!!!, maybe we are installing? :-)')
# Context processor
def context_processor(request):
return { 'css_path' : GlobalConfig.CSS.get() }
return {'css_path': GlobalConfig.CSS.get()}
# Initialization of global configurations
GlobalConfig.initialize()
# Initialization of global configurations
GlobalConfig.initialize()

View File

@ -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.
'''
@ -39,17 +39,18 @@ from uds.web import errors
from time import sleep
from functools import wraps
# Have to test these decorators before using them
def retryOnException(retries=3, delay = 0):
def retryOnException(retries=3, delay=0):
'''
Decorator to retry
Decorator to retry
'''
def decorator(func):
@wraps(func)
def _wrapped_func(*args, **kwargs):
while retries > 0:
retries -= 1
try:
try:
return func(*args, **kwargs)
except Exception:
if retries == 0:
@ -62,10 +63,10 @@ def retryOnException(retries=3, delay = 0):
# Decorator that protects pages that needs at least a browser version
# Default is to deny IE < 9
def denyBrowsers(browsers=['ie<9'], errorResponse=lambda request:errors.errorView(request,errors.BROWSER_NOT_SUPPORTED)):
def denyBrowsers(browsers=['ie<9'], errorResponse=lambda request: errors.errorView(request, errors.BROWSER_NOT_SUPPORTED)):
'''
Decorator to set protection to access page
Look for samples at uds.core.web.views
Look for samples at uds.core.web.views
'''
def wrap(view_func):
@wraps(view_func)
@ -76,7 +77,7 @@ def denyBrowsers(browsers=['ie<9'], errorResponse=lambda request:errors.errorVie
for b in browsers:
if checkBrowser(request.META['HTTP_USER_AGENT'], b):
return errorResponse(request)
return view_func(request, *args, **kwargs)
return _wrapped_view
return wrap

View File

@ -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.
'''
@ -42,17 +42,18 @@ Android = 'Android'
iPad = 'iPad'
iPhone = 'iPhone'
knownOss = [ WindowsPhone, Android, Linux, Windows, Macintosh, iPad, iPhone ] # Android is linux also, so it is cheched on first place
knownOss = [WindowsPhone, Android, Linux, Windows, Macintosh, iPad, iPhone] # Android is linux also, so it is cheched on first place
allOss = list(knownOss)
desktopOss = [Linux, Windows, Macintosh]
mobilesODD = list(set(allOss)-set(desktopOss))
mobilesODD = list(set(allOss) - set(desktopOss))
def getOsFromUA(ua):
'''
Basic OS Client detector (very basic indeed :-))
'''
res = {'OS' : 'Unknown', 'Version' : 'unused' }
res = {'OS': 'Unknown', 'Version': 'unused'}
for os in knownOss:
try:
ua.index(os)
@ -63,4 +64,3 @@ def getOsFromUA(ua):
logger.debug('User-Agent: {0}'.format(ua))
logger.debug('Detected OS: {0}'.format(res))
return res

View File

@ -4,36 +4,37 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from django.utils.translation import ugettext_noop as _, ugettext
# States for different objects. Not all objects supports all States
class State(object):
'''
@ -42,32 +43,45 @@ class State(object):
'''
ACTIVE = 'A'
BLOCKED = 'B'
CANCELED = 'C'
CANCELED = 'C'
ERROR = 'E'
FINISHED = 'F'
BALANCING = 'H'
INACTIVE = 'I'
CANCELING = 'K'
LAUNCHING = 'L'
REMOVING = 'M'
PREPARING = 'P'
REMOVABLE = 'R'
REMOVING = 'M'
PREPARING = 'P'
REMOVABLE = 'R'
REMOVED = 'S'
USABLE = 'U'
USABLE = 'U'
RUNNING = 'W'
FOR_EXECUTE = 'X'
string = { ACTIVE: _('Active'), INACTIVE: _('Inactive'), BLOCKED: _('Blocked'), LAUNCHING: _('Waiting publication'),
PREPARING: _('In preparation'), USABLE: _('Valid'),
REMOVABLE: _('Waiting for removal'), REMOVING: _('Removing'), REMOVED: _('Removed'), CANCELED: _('Canceled'),
CANCELING: _('Canceling'), ERROR: _('Error'), RUNNING: _('Running'), FINISHED: _('Finished'), FOR_EXECUTE: _('Waiting execution'),
BALANCING: _('Balancing') }
string = {
ACTIVE: _('Active'),
INACTIVE: _('Inactive'),
BLOCKED: _('Blocked'),
LAUNCHING: _('Waiting publication'),
PREPARING: _('In preparation'),
USABLE: _('Valid'),
REMOVABLE: _('Waiting for removal'),
REMOVING: _('Removing'),
REMOVED: _('Removed'),
CANCELED: _('Canceled'),
CANCELING: _('Canceling'),
ERROR: _('Error'),
RUNNING: _('Running'),
FINISHED: _('Finished'),
FOR_EXECUTE: _('Waiting execution'),
BALANCING: _('Balancing')
}
# States that are merely for "information" to the user. They don't contain any usable instance
INFO_STATES = [REMOVED, CANCELED, ERROR]
# States that indicates that the service is "Valid" for a user
VALID_STATES = [USABLE,PREPARING]
VALID_STATES = [USABLE, PREPARING]
# Publication States
PUBLISH_STATES = [LAUNCHING, PREPARING]
@ -79,31 +93,31 @@ class State(object):
@staticmethod
def isInactive(state):
return state == State.INACTIVE
@staticmethod
def isBlocked(state):
return state == State.BLOCKED
@staticmethod
def isPreparing(state):
return state == State.PREPARING
@staticmethod
def isUsable(state):
return state == State.USABLE
@staticmethod
def isRemovable(state):
return state == State.REMOVABLE
@staticmethod
def isRemoving(state):
return state == State.REMOVING
@staticmethod
def isRemoved(state):
return state == State.REMOVED
@staticmethod
def isCanceling(state):
return state == State.CANCELING
@ -115,7 +129,7 @@ class State(object):
@staticmethod
def isErrored(state):
return state == State.ERROR
@staticmethod
def isFinished(state):
return state == State.FINISHED
@ -123,18 +137,18 @@ class State(object):
@staticmethod
def isRuning(state):
return state == State.RUNNING
@staticmethod
def isForExecute(state):
return state == State.FOR_EXECUTE
@staticmethod
def toString(state):
try:
return State.string[state]
except Exception:
return ''
@staticmethod
def dictionary():
'''
@ -144,4 +158,3 @@ class State(object):
for k, v in State.string.iteritems():
res[k] = ugettext(v)
return res

View File

@ -4,76 +4,78 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
class StateQueue(object):
def __init__(self):
def __init__(self):
self.reset()
def __str__(self):
res = '<StateQueue Current: %s, Queue: (%s)>' % (self._current , ','.join( state for state in self._queue ))
res = '<StateQueue Current: %s, Queue: (%s)>' % (self._current, ','.join(state for state in self._queue))
return res
def clearQueue(self):
self._queue = []
def reset(self):
self._queue = []
self._current = None
def getCurrent(self):
return self._current
def setCurrent(self, newState):
self._current = newState
return self._current
def contains(self, state):
#if self._queue.co
# if self._queue.co
for s in self._queue:
if s == state:
return True
return False
def push_back(self, state):
self._queue.append(state)
def push_front(self, state):
self._queue.insert(0, state)
def pop_front(self):
if len(self._queue) > 0:
return self._queue.pop(0)
return None
def remove(self, state):
try:
self._queue.remove(state)
except Exception:
pass # If state not in queue, nothing happens
pass # If state not in queue, nothing happens

View File

@ -4,32 +4,33 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from django.db import transaction
from uds.models import Storage as dbStorage
@ -39,39 +40,40 @@ import cPickle
logger = logging.getLogger(__name__)
class Storage(object):
CODEC = 'base64' # Can be zip, hez, bzip, base64, uuencoded
def __init__(self, owner):
self._owner = owner
def __getKey(self, key):
h = hashlib.md5()
h.update(self._owner)
h.update(str(key))
return h.hexdigest()
def saveData(self, skey, data, attr1 = None):
def saveData(self, skey, data, attr1=None):
key = self.__getKey(skey)
data = data.encode(Storage.CODEC)
attr1 = '' if attr1 == None else attr1
try:
with transaction.atomic():
dbStorage.objects.create(owner = self._owner, key = key, data = data, attr1 = attr1 )
dbStorage.objects.create(owner=self._owner, key=key, data=data, attr1=attr1)
except Exception:
with transaction.atomic():
dbStorage.objects.filter(key=key).update(owner = self._owner, data = data, attr1 = attr1)
dbStorage.objects.filter(key=key).update(owner=self._owner, data=data, attr1=attr1)
logger.debug('Key saved')
def put(self, skey, data):
return self.saveData(skey, data)
def putPickle(self, skey, data):
return self.saveData(skey, cPickle.dumps(data))
def updateData(self, skey, data, attr1 = None):
def updateData(self, skey, data, attr1=None):
self.saveData(skey, data, attr1)
def readData(self, skey):
try:
key = self.__getKey(skey)
@ -81,26 +83,26 @@ class Storage(object):
except dbStorage.DoesNotExist:
logger.debug('key not found')
return None
def get(self, skey):
return self.readData(skey)
def getPickle(self, skey):
return cPickle.loads(self.readData(skey))
def remove(self, skey):
try:
key = self.__getKey(skey)
dbStorage.objects.filter(key=key).delete()
except Exception:
pass
def lock(self):
'''
Use with care. If locked, it must be unlocked before returning
'''
dbStorage.objects.lock()
def unlock(self):
'''
Must be used to unlock table
@ -108,7 +110,7 @@ class Storage(object):
dbStorage.objects.unlock()
@staticmethod
def delete(owner = None):
def delete(owner=None):
logger.info("Deleting storage items")
if owner == None:
objects = dbStorage.objects.all()
@ -118,6 +120,6 @@ class Storage(object):
def locateByAttr1(self, attr1):
res = []
for v in dbStorage.objects.filter( attr1 = attr1 ):
res.append( v.data.decode(Storage.CODEC) )
for v in dbStorage.objects.filter(attr1=attr1):
res.append(v.data.decode(Storage.CODEC))
return res

View File

@ -4,27 +4,27 @@
# Copyright (c) 2013 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.
from __future__ import unicode_literals
@ -36,7 +36,8 @@ import logging
logger = logging.getLogger(__name__)
DEFAULT_QUEUE_SIZE=32
DEFAULT_QUEUE_SIZE = 32
class Worker(Thread):
def __init__(self, tasks):
@ -44,24 +45,25 @@ class Worker(Thread):
self._tasks = tasks
self._stop = False
self.start()
def notifyStop(self):
self._stop = True
def run(self):
while self._stop is False:
try:
func, args, kargs = self._tasks.get(block=True, timeout=1)
except Queue.Empty:
continue
try:
try:
func(*args, **kargs)
except Exception:
except Exception:
logger.exception('ThreadPool Worker')
self._tasks.task_done()
class ThreadPool:
def __init__(self, num_threads, queueSize=DEFAULT_QUEUE_SIZE):
self._tasks = Queue.Queue(queueSize)
@ -73,7 +75,7 @@ class ThreadPool:
Add a task to the queue
'''
if len(self._threads) == 0:
for _ in range(self._numThreads):
for _ in range(self._numThreads):
self._threads.append(Worker(self._tasks))
self._tasks.put((func, args, kargs))
@ -83,14 +85,14 @@ class ThreadPool:
Wait for completion of all the tasks in the queue
'''
self._tasks.join()
# Now we will close all running tasks
# In case new tasks are inserted after using this, new threads will be created
# to handle tasks
for n in self._threads:
n.notifyStop()
n.notifyStop()
for n in self._threads:
n.join()
self._threads = []
self._threads = []

View File

@ -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,42 +40,43 @@ logger = logging.getLogger(__name__)
MAX_SEQ = 1000000000000000
class UniqueIDGenerator(object):
def __init__(self, typeName, owner, baseName = 'uds'):
def __init__(self, typeName, owner, baseName='uds'):
self._owner = owner + typeName
self._baseName = baseName
def setBaseName(self, newBaseName):
self._baseName = newBaseName
def __filter(self, rangeStart, rangeEnd=MAX_SEQ):
return dbUniqueId.objects.filter( basename = self._baseName, seq__gte=rangeStart, seq__lte=rangeEnd )
return dbUniqueId.objects.filter(basename=self._baseName, seq__gte=rangeStart, seq__lte=rangeEnd)
def get(self, rangeStart=0, rangeEnd=MAX_SEQ):
'''
Tries to generate a new unique id in the range provided. This unique id
is global to "unique ids' database
'''
# First look for a name in the range defined
stamp = getSqlDatetime(True)
stamp = getSqlDatetime(True)
try:
dbUniqueId.objects.lock()
flt = self.__filter(rangeStart, rangeEnd)
try:
item = flt.filter(assigned=False).order_by('seq')[0]
dbUniqueId.objects.filter(id=item.id).update( owner = self._owner, assigned = True, stamp = stamp )
dbUniqueId.objects.filter(id=item.id).update(owner=self._owner, assigned=True, stamp=stamp)
seq = item.seq
except Exception, e: # No free element found
except Exception: # No free element found
try:
last = flt.filter(assigned = True)[0] # DB Returns correct order so the 0 item is the last
last = flt.filter(assigned=True)[0] # DB Returns correct order so the 0 item is the last
seq = last.seq + 1
except Exception: # If there is no assigned at database
except Exception: # If there is no assigned at database
seq = rangeStart
logger.debug('Found seq {0}'.format(seq))
if seq > rangeEnd:
return -1 # No ids free in range
dbUniqueId.objects.create( owner = self._owner, basename = self._baseName, seq = seq, assigned = True, stamp = stamp)
return -1 # No ids free in range
dbUniqueId.objects.create(owner=self._owner, basename=self._baseName, seq=seq, assigned=True, stamp=stamp)
return seq
except Exception:
logger.exception('Generating unique id sequence')
@ -86,55 +87,51 @@ class UniqueIDGenerator(object):
def transfer(self, seq, toUidGen):
try:
dbUniqueId.objects.lock()
obj = dbUniqueId.objects.get( owner=self._owner, seq=seq)
obj = dbUniqueId.objects.get(owner=self._owner, seq=seq)
obj.owner = toUidGen._owner
obj.basename = toUidGen._baseName
obj.stamp = getSqlDatetime(True)
obj.save()
return True
except:
logger.exception('EXCEPTION AT transfer')
return False
finally:
dbUniqueId.objects.unlock()
def free(self, seq):
try:
logger.debug('Freeing seq {0} from {1} ({2})'.format(seq, self._owner, self._baseName))
dbUniqueId.objects.lock()
flt = self.__filter(0).filter(owner = self._owner, seq=seq).update(owner='', assigned=False, stamp = getSqlDatetime(True))
flt = self.__filter(0).filter(owner=self._owner, seq=seq).update(owner='', assigned=False, stamp=getSqlDatetime(True))
if flt > 0:
self.__purge()
finally:
dbUniqueId.objects.unlock()
def __purge(self):
try:
last = self.__filter(0).filter(assigned=True)[0]
seq = last.seq+1
seq = last.seq + 1
except:
seq = 0
self.__filter(seq).delete() # Clean ups all unassigned after last assigned in this range
self.__filter(seq).delete() # Clean ups all unassigned after last assigned in this range
def release(self):
try:
dbUniqueId.objects.lock()
dbUniqueId.objects.filter(owner=self._owner).update(assigned=False, owner='', stamp = getSqlDatetime(True))
dbUniqueId.objects.filter(owner=self._owner).update(assigned=False, owner='', stamp=getSqlDatetime(True))
self.__purge()
finally:
dbUniqueId.objects.unlock()
def releaseOlderThan(self, stamp):
stamp = getSqlDatetime(True)
try:
dbUniqueId.objects.lock()
dbUniqueId.objects.filter(owner=self._owner, stamp__lt=stamp).update(assigned=False, owner='', stamp = stamp)
dbUniqueId.objects.filter(owner=self._owner, stamp__lt=stamp).update(assigned=False, owner='', stamp=stamp)
self.__purge()
finally:
dbUniqueId.objects.unlock()

View File

@ -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.
'''
@ -32,33 +32,34 @@
'''
from __future__ import unicode_literals
from UniqueIDGenerator import UniqueIDGenerator
import logging, re
import logging
import re
logger = logging.getLogger(__name__)
class UniqueMacGenerator(UniqueIDGenerator):
def __init__(self, owner):
super(UniqueMacGenerator, self).__init__('mac', owner, '\tmac')
def __toInt(self, mac):
return int(mac.replace(':', ''), 16)
def __toMac(self, seq):
return re.sub(r"(..)", r"\1:", "%0*X" % (12, seq))[:-1]
def get(self, macRange):
firstMac, lastMac = macRange.split('-')
firstMac = self.__toInt(firstMac)
lastMac = self.__toInt(lastMac)
return self.__toMac(super(UniqueMacGenerator, self).get(firstMac, lastMac))
def transfer(self, mac, toUMgen):
super(UniqueMacGenerator, self).transfer( self.__toInt(mac), toUMgen )
super(UniqueMacGenerator, self).transfer(self.__toInt(mac), toUMgen)
def free(self, mac):
super(UniqueMacGenerator, self).free( self.__toInt(mac) )
# Release is inherited, no mod needed
super(UniqueMacGenerator, self).free(self.__toInt(mac))
# Release is inherited, no mod needed

View File

@ -4,58 +4,60 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from UniqueIDGenerator import UniqueIDGenerator
import logging
logger = logging.getLogger(__name__)
class UniqueNameGenerator(UniqueIDGenerator):
def __init__(self, owner):
super(UniqueNameGenerator, self).__init__('name', owner, )
super(UniqueNameGenerator, self).__init__('name', owner,)
def __toName(self, seq, length):
if seq == -1:
raise KeyError('No more names available. Please, increase service digits.')
return "%s%0*d" % (self._baseName, length, seq)
raise KeyError('No more names available. Please, increase service digits.')
return "%s%0*d" % (self._baseName, length, seq)
def get(self, baseName, length=5):
self.setBaseName(baseName)
minVal = 0
maxVal = 10**length - 1
maxVal = 10 ** length - 1
return self.__toName(super(UniqueNameGenerator, self).get(minVal, maxVal), length)
def transfer(self, baseName, name, toUNGen):
self.setBaseName(baseName)
super(UniqueNameGenerator, self).transfer(int(name[len(self._baseName):]), toUNGen)
def free(self, baseName, name):
self.setBaseName(baseName)
super(UniqueNameGenerator, self).free(int(name[len(self._baseName):]))
super(UniqueNameGenerator, self).free(int(name[len(self._baseName):]))

View File

@ -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.
'''

View File

@ -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.
'''
@ -37,7 +37,8 @@ import socket
logger = logging.getLogger(__name__)
def testServer(host, port, timeOut = 4):
def testServer(host, port, timeOut=4):
try:
logger.debug('Checking connection to {0}:{1} with {2} seconds timeout'.format(host, port, timeOut))
sock = socket.create_connection((host, int(port)), timeOut)
@ -46,5 +47,3 @@ def testServer(host, port, timeOut = 4):
logger.debug('Exception checking {0}:{1} with {2} timeout: {3}'.format(host, port, timeOut, e))
return False
return True

View File

@ -4,27 +4,27 @@
# Copyright (c) 2014 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.
'''
@ -42,14 +42,15 @@ def parseDate(dateToParse):
import datetime
from django.utils.translation import get_language
from django.utils import formats
if get_language() == 'fr':
date_format = '%d/%m/%Y'
else:
date_format = formats.get_format('SHORT_DATE_FORMAT').replace('Y', '%Y').replace('m','%m').replace('d','%d')
date_format = formats.get_format('SHORT_DATE_FORMAT').replace('Y', '%Y').replace('m', '%m').replace('d', '%d')
return datetime.datetime.strptime(dateToParse, date_format).date()
def dateToLiteral(date):
from django.utils.translation import get_language
from django.utils import formats
@ -58,16 +59,17 @@ def dateToLiteral(date):
if get_language() == 'fr':
date = date.strftime('%d/%m/%Y')
else:
date = formats.date_format(date, 'SHORT_DATE_FORMAT')
date = formats.date_format(date, 'SHORT_DATE_FORMAT')
return date
def extractKey(dictionary, key, **kwargs):
format_ = kwargs.get('format', '{0}')
default = kwargs.get('default', '')
if dictionary.has_key(key):
default = kwargs.get('default', '')
if key in dictionary:
value = format_.format(dictionary[key])
del dictionary[key]
else:
@ -88,13 +90,14 @@ _chrome = re.compile('Chrome/([0-9]+)\.([0-9]+)')
_webkit = re.compile('AppleWebKit/([0-9]+)\.([0-9]+)')
_browsers = {
'ie' : [_trident, _msie],
'ie': [_trident, _msie],
'opera': [_opera],
'firefox': [_firefox],
'chrome': [_chrome],
'webkit': [_webkit],
}
def checkBrowser(user_agent, browser):
'''
Known browsers right now:
@ -102,23 +105,22 @@ def checkBrowser(user_agent, browser):
ie<[version]
'''
# Split brwosers we look for
needs_browser = None
needs_version = 0
needs = ''
regexs = None
for b, res in _browsers.iteritems():
if browser.startswith(b):
logger.debug('Found: {0}'.format(b))
regexs = res
browser = browser[len(b):]
if regexs is None:
return False
browser += ' ' # So we ensure we have at least beowser 0
browser += ' ' # So we ensure we have at least beowser 0
if browser[0] == '<' or browser[0] == '>' or browser[0] == '=':
needs = browser[0]
needs_version = int(browser[1:])
@ -129,7 +131,7 @@ def checkBrowser(user_agent, browser):
except:
needs = ''
needs_version = 0
try:
matches = None
for r in regexs:
@ -138,7 +140,7 @@ def checkBrowser(user_agent, browser):
break
if matches is None:
return False
version = int(matches.groups()[0])
if needs == '<':
return version < needs_version
@ -146,12 +148,12 @@ def checkBrowser(user_agent, browser):
return version > needs_version
elif needs == '=':
return version == needs_version
return True
except:
return False
# debug setting in context
def context(request):
from django.conf import settings

View File

@ -4,39 +4,40 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
import logging
logger = logging.getLogger(__name__)
useLogger = logging.getLogger('useLog')
# Logging levels
OTHER,DEBUG,INFO,WARN,ERROR,FATAL = (10000*(x+1) for x in xrange(6))
OTHER, DEBUG, INFO, WARN, ERROR, FATAL = (10000 * (x + 1) for x in xrange(6))
# Logging sources
INTERNAL, ACTOR, TRANSPORT, OSMANAGER, UNKNOWN, WEB, ADMIN, SERVICE = ('internal', 'actor', 'transport', 'osmanager', 'unknown', 'web', 'admin', 'service')
@ -54,7 +55,8 @@ __nameLevels = {
}
# Reverse dict of names
__valueLevels = dict((v,k) for k, v in __nameLevels.iteritems())
__valueLevels = dict((v, k) for k, v in __nameLevels.iteritems())
def logLevelFromStr(str_):
'''
@ -62,31 +64,33 @@ def logLevelFromStr(str_):
'''
return __nameLevels.get(str_.upper(), OTHER)
def logStrFromLevel(level):
return __valueLevels.get(level, 'OTHER')
def useLog(type_, serviceUniqueId, serviceIp, username):
useLogger.info('|'.join([type_, serviceUniqueId, serviceIp, username]))
def doLog(wichObject, level, message, source = UNKNOWN, avoidDuplicates = True):
def doLog(wichObject, level, message, source=UNKNOWN, avoidDuplicates=True):
from uds.core.managers import logManager
logManager().doLog(wichObject, level, message, source, avoidDuplicates)
def getLogs(wichObject, limit = None):
def getLogs(wichObject, limit=None):
'''
Get the logs associated with "wichObject", limiting to "limit" (default is GlobalConfig.MAX_LOGS_PER_ELEMENT)
Get the logs associated with "wichObject", limiting to "limit" (default is GlobalConfig.MAX_LOGS_PER_ELEMENT)
'''
from uds.core.managers import logManager
from uds.core.util.Config import GlobalConfig
if limit is None:
limit = GlobalConfig.MAX_LOGS_PER_ELEMENT.getInt()
return logManager().getLogs(wichObject, limit)
def clearLogs(wichObject):
'''
Clears the logs associated with the object using the logManager

View File

@ -4,43 +4,46 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
import os.path, pkgutil
import sys, imp
import os.path
import pkgutil
import sys
import imp
import logging
import uds.dispatchers
import uds.dispatchers # @UnusedImport
logger = logging.getLogger(__name__)
patterns = []
def loadModulesUrls():
logger.debug('Looking for dispatching modules')
global patterns
@ -54,10 +57,9 @@ def loadModulesUrls():
try:
patterns += mod.urlpatterns
except:
logger.info( 'Module {0} has no url patterns'.format(mod))
logger.info('Module {0} has no url patterns'.format(mod))
except Exception, e:
logger.debug(e)
pass
return patterns

View File

@ -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.
'''
@ -44,6 +44,7 @@ re3Asterisk = re.compile('^([0-9]{1,3})\.\*\.?\*?\.?\*?$')
reRange = re.compile('^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})-([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$')
reHost = re.compile('^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$')
def ipToLong(ip):
'''
convert decimal dotted quad string to long integer
@ -52,8 +53,9 @@ def ipToLong(ip):
hexn = ''.join(["%02X" % long(i) for i in ip.split('.')])
return long(hexn, 16)
except:
return 0 # Invalid values will map to "0.0.0.0" --> 0
return 0 # Invalid values will map to "0.0.0.0" --> 0
def longToIp(n):
'''
convert long int to dotted quad string
@ -62,19 +64,19 @@ def longToIp(n):
d = 256 * 256 * 256
q = []
while d > 0:
m,n = divmod(n,d)
m, n = divmod(n, d)
q.append(str(m))
d = d/256
d = d / 256
return '.'.join(q)
except:
return '0.0.0.0' # Invalid values will map to "0.0.0.0"
return '0.0.0.0' # Invalid values will map to "0.0.0.0"
def networksFromString(strNets, allowMultipleNetworks = True):
def networksFromString(strNets, allowMultipleNetworks=True):
'''
Parses the network from strings in this forms:
- A.* (or A.*.* or A.*.*.*)
- A.* (or A.*.* or A.*.*.*)
- A.B.* (or A.B.*.* )
- A.B.C.* (i.e. 192.168.0.*)
- A.B.C.D/N (i.e. 192.168.0.0/24)
@ -84,28 +86,28 @@ def networksFromString(strNets, allowMultipleNetworks = True):
If allowMultipleNetworks is True, it allows ',' and ';' separators (and, ofc, more than 1 network)
Returns a list of networks tuples in the form [(start1, end1), (start2, end2) ...]
'''
inputString = strNets
def check(*args):
for n in args:
if int(n) < 0 or int(n) > 255:
raise Exception()
def toNum(*args):
start = 256*256*256
start = 256 * 256 * 256
val = 0
for n in args:
val += start*int(n)
val += start * int(n)
start /= 256
return val
def maskFromBits(nBits):
v = 0
for n in xrange(nBits):
v |= 1<<(31-n)
v |= 1 << (31 - n)
return v
if allowMultipleNetworks is True:
res = []
for strNet in re.split('[;,]', strNets):
@ -114,11 +116,11 @@ def networksFromString(strNets, allowMultipleNetworks = True):
return res
strNets = strNets.replace(' ', '')
if strNets == '*':
return (0, 4294967295)
try:
try:
# Test patterns
m = reCIDR.match(strNets)
if m is not None:
@ -129,16 +131,16 @@ def networksFromString(strNets, allowMultipleNetworks = True):
val = toNum(*m.groups())
bits = maskFromBits(bits)
noBits = ~bits & 0xffffffff
return (val&bits, val|noBits)
return (val & bits, val | noBits)
m = reMask.match(strNets)
if m is not None:
check(*m.groups())
val = toNum(*(m.groups()[0:4]))
bits = toNum(*(m.groups()[4:8]))
noBits = ~bits & 0xffffffff
return (val&bits, val|noBits)
return (val & bits, val | noBits)
m = reRange.match(strNets)
if m is not None:
check(*m.groups())
@ -147,7 +149,7 @@ def networksFromString(strNets, allowMultipleNetworks = True):
if val2 < val:
raise Exception()
return (val, val2)
m = reHost.match(strNets)
if m is not None:
check(*m.groups())
@ -155,26 +157,26 @@ def networksFromString(strNets, allowMultipleNetworks = True):
return (val, val)
for v in ((re1Asterisk, 3), (re2Asterisk, 2), (re3Asterisk, 1)):
m = v[0].match(strNets)
m = v[0].match(strNets)
if m is not None:
check(*m.groups())
val = toNum(*(m.groups()[0:v[1]+1]))
bits = maskFromBits(v[1]*8)
val = toNum(*(m.groups()[0:v[1] + 1]))
bits = maskFromBits(v[1] * 8)
noBits = ~bits & 0xffffffff
return (val&bits, val|noBits)
return (val & bits, val | noBits)
# No pattern recognized, invalid network
raise Exception()
except:
raise ValueError(inputString)
def ipInNetwork(ip, network):
if isinstance(ip,unicode) or isinstance(ip,str):
if isinstance(ip, unicode) or isinstance(ip, str):
ip = ipToLong(ip)
if isinstance(network,unicode) or isinstance(network,str):
if isinstance(network, unicode) or isinstance(network, str):
network = networksFromString(network)
for net in network:
if ip >= net[0] and ip <= net[1]:
return True

View File

@ -4,41 +4,43 @@
# 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.
'''
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
import threading
_requests = {}
def getRequest():
return _requests[threading._get_ident()]
class GlobalRequestMiddleware(object):
def process_request(self, request):
_requests[threading._get_ident()] = request
return None

View File

@ -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.
'''
@ -43,15 +43,16 @@ import logging
logger = logging.getLogger(__name__)
class AssignedAndUnused(Job):
class AssignedAndUnused(Job):
frecuency = GlobalConfig.CHECK_UNUSED_TIME.getInt()
friendly_name = 'Unused services checker'
def __init__(self, environment):
super(AssignedAndUnused,self).__init__(environment)
super(AssignedAndUnused, self).__init__(environment)
def run(self):
since_state = getSqlDatetime() - timedelta( seconds = GlobalConfig.CHECK_UNUSED_TIME.getInt() )
since_state = getSqlDatetime() - timedelta(seconds=GlobalConfig.CHECK_UNUSED_TIME.getInt())
for ds in DeployedService.objects.all():
# If do not needs os manager, this is
with transaction.atomic():
@ -59,11 +60,10 @@ class AssignedAndUnused(Job):
osm = ds.osmanager.getInstance()
if osm.processUnusedMachines is True:
logger.debug('Processing unused services for {0}'.format(osm))
for us in ds.assignedUserServices().select_for_update().filter(in_use=False,state_date__lt=since_state, state=State.USABLE, os_state=State.USABLE):
for us in ds.assignedUserServices().select_for_update().filter(in_use=False, state_date__lt=since_state, state=State.USABLE, os_state=State.USABLE):
logger.debug('Found unused assigned service {0}'.format(us))
osm.processUnused(us)
else: # No os manager, simply remove unused services in specified time
for us in ds.assignedUserServices().select_for_update().filter(in_use=False,state_date__lt=since_state, state=State.USABLE, os_state=State.USABLE):
else: # No os manager, simply remove unused services in specified time
for us in ds.assignedUserServices().select_for_update().filter(in_use=False, state_date__lt=since_state, state=State.USABLE, os_state=State.USABLE):
logger.debug('Found unused assigned service {0}'.format(us))
us.remove()

View File

@ -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.
'''
@ -38,17 +38,16 @@ import logging
logger = logging.getLogger(__name__)
class CacheCleaner(Job):
frecuency = 3600*24 # Once a day
frecuency = 3600 * 24 # Once a day
friendly_name = 'Utility Cache Cleaner'
def __init__(self, environment):
super(CacheCleaner,self).__init__(environment)
super(CacheCleaner, self).__init__(environment)
def run(self):
logger.debug('Starting cache cleanup')
Cache.cleanUp()
logger.debug('Done cache cleanup')

View File

@ -4,27 +4,27 @@
# Copyright (c) 2013 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.
'''
@ -47,23 +47,25 @@ GETCLUSTERSTATS_TAG = 'ClstrStats'
BALANCECLUSTER_TAG = 'ClstrBalance'
MIGRATETASK_TAG = 'ClstrMigrate'
# Utility to get all providers that are derived from
# Utility to get all providers that are derived from
def getClusteredProvidersFromDB():
#services.ClusteredServiceProvider.
# services.ClusteredServiceProvider.
from uds.core import services
p = services.ClusteredServiceProvider
for prov in Provider.objects.all():
for cls in p.__subclasses__():
if prov.isOfType(cls.typeType):
yield prov
class ClusterUpdateStatsTask(DelayedTask):
def __init__(self, providerId):
super(ClusterUpdateStatsTask,self).__init__()
super(ClusterUpdateStatsTask, self).__init__()
self._id = providerId
def run(self):
try:
provider = Provider.objects.get(pk=self._id)
@ -73,37 +75,41 @@ class ClusterUpdateStatsTask(DelayedTask):
stats = {}
for node in nodes:
s = cluster.getClusterNodeLoad(node['id'])
stats[node['id']] = { 'cpuLoad': s.get('cpuLoad', None), 'freeMemory': s.get('freeMemory', None),
'totalMemory': s.get('totalMemory') }
stats[node['id']] = {
'cpuLoad': s.get('cpuLoad', None),
'freeMemory': s.get('freeMemory', None),
'totalMemory': s.get('totalMemory')
}
cluster.storage().putPickle('ClusterStats', stats)
except:
logger.exception('Update Stats Task')
# Removed provider, no problem at all, no update is done
pass
# Job for managing ClusteredServiceProvider
class ClusterUpdateStats(Job):
frecuency = 60 # Once every 60 seconds
frecuency = 60 # Once every 60 seconds
friendly_name = 'Clustered Providers Statistics Updater'
def __init__(self, environment):
super(ClusterUpdateStats,self).__init__(environment)
super(ClusterUpdateStats, self).__init__(environment)
def run(self):
logger.debug('Clustered Service manager started')
for p in getClusteredProvidersFromDB():
logger.debug('Getting stats for clustered provider {0}'.format(p.name))
ct = ClusterUpdateStatsTask(p.id)
ct.register(0, '{0}_{1}'.format(GETCLUSTERSTATS_TAG, p.id), True)
# Balancing nodes related
class ClusterMigrationTask(DelayedTask):
def __init__(self, service):
super(ClusterMigrationTask, self).__init__()
self._serviceId = service.id
self._state = service.state
@staticmethod
@transaction.atomic
def checkAndUpdateState(userService, userServiceInstance, state):
@ -116,7 +122,7 @@ class ClusterMigrationTask(DelayedTask):
checkLater = False
userServiceInstance.finish()
userService.updateData(userServiceInstance)
userService.setState(State.USABLE) # Wi will only migrate fully functional services
userService.setState(State.USABLE) # Wi will only migrate fully functional services
elif State.isErrored(state):
checkLater = False
userService.updateData(userServiceInstance)
@ -132,22 +138,20 @@ class ClusterMigrationTask(DelayedTask):
log.doLog(userService, log.ERROR, 'Exception: {0}'.format(e), log.INTERNAL)
userService.setState(State.ERROR)
userService.save()
@staticmethod
def checkLater(userService, userServiceInstance):
'''
Inserts a task in the delayedTaskRunner so we can check the state of this migration
@param userService: Database object for DeployedServicePublication
@param userServiceInstance: Instance of Publication manager for the object
@param userServiceInstance: Instance of Publication manager for the object
'''
from uds.core.jobs.DelayedTaskRunner import DelayedTaskRunner
# Do not add task if already exists one that updates this service
if DelayedTaskRunner.runner().checkExists(MIGRATETASK_TAG + str(userService.id)):
return
DelayedTaskRunner.runner().insert(ClusterUpdateStats(userService), userServiceInstance.suggestedTime, ClusterUpdateStats + str(userService.id))
@transaction.atomic
def run(self):
logger.debug('Checking user service finished migrating {0}'.format(self._serviceId))
uService = None
@ -157,7 +161,7 @@ class ClusterMigrationTask(DelayedTask):
logger.debug('Task overrided by another task (state of item changed)')
# This item is no longer valid, returning will not check it again (no checkLater called)
return
ci = uService.getInstance()
logger.debug("uService instance class: {0}".format(ci.__class__))
state = ci.checkState()
@ -174,24 +178,25 @@ class ClusterMigrationTask(DelayedTask):
uService.save()
except Exception:
logger.error('Can\'t update state of uService object')
class ClusterBalancingTask(DelayedTask):
def __init__(self, providerId):
super(ClusterBalancingTask, self).__init__()
self._id = providerId
@staticmethod
@transaction.atomic
def migrate(serviceId, toNode):
try:
service = UserService.objects.select_for_update().get(pk=serviceId)
service.setState(State.BALANCING)
serviceInstance = service.getInstance()
# Now we will start a new task, similar to those of deploying
state = serviceInstance.startMigration(toNode)
ClusterMigrationTask.checkAndUpdateState(service, serviceInstance, state)
except Exception as e:
logger.exception('Initializing migration')
@ -202,7 +207,7 @@ class ClusterBalancingTask(DelayedTask):
service.save()
except:
logger.exception('Setting error state at migration init')
def run(self):
try:
provider = Provider.objects.get(pk=self._id)
@ -221,7 +226,7 @@ class ClusterBalancingTask(DelayedTask):
if node is not None:
s.cluster_node = node
s.save()
if serviceForBalancing is None:
return
@ -230,18 +235,18 @@ class ClusterBalancingTask(DelayedTask):
logger.debug('Cluster is overloaded, but no underloaded nodes for receiving migration')
underloadedNode = nodesForDestination[0]
ClusterBalancingTask.migrate(serviceForBalancing, underloadedNode)
except:
logger.exception('Cluster Balancing Task')
class ClusterBalancingJob(Job):
frecuency = 90
friendly_name = 'Clustered Providers Balancing job'
def __init__(self, environment):
super(ClusterBalancingJob,self).__init__(environment)
super(ClusterBalancingJob, self).__init__(environment)
def run(self):
'''
@ -252,4 +257,3 @@ class ClusterBalancingJob(Job):
logger.debug('Checking balancing on {0}'.format(p.name))
cb = ClusterBalancingTask(p.id)
cb.register(0, '{0}_{1}'.format(BALANCECLUSTER_TAG, p.id), True)

View File

@ -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.
'''
@ -42,30 +42,31 @@ import logging
logger = logging.getLogger(__name__)
class DeployedServiceInfoItemsCleaner(Job):
frecuency = GlobalConfig.CLEANUP_CHECK.getInt() # Request run cache "info" cleaner every configured seconds. If config value is changed, it will be used at next reload
frecuency = GlobalConfig.CLEANUP_CHECK.getInt() # Request run cache "info" cleaner every configured seconds. If config value is changed, it will be used at next reload
friendly_name = 'Deployed Service Info Cleaner'
def __init__(self, environment):
super(DeployedServiceInfoItemsCleaner,self).__init__(environment)
super(DeployedServiceInfoItemsCleaner, self).__init__(environment)
def run(self):
removeFrom = getSqlDatetime() - timedelta(seconds = GlobalConfig.KEEP_INFO_TIME.getInt())
removeFrom = getSqlDatetime() - timedelta(seconds=GlobalConfig.KEEP_INFO_TIME.getInt())
DeployedService.objects.filter(state__in=State.INFO_STATES, state_date__lt=removeFrom).delete()
class DeployedServiceRemover(Job):
frecuency = GlobalConfig.REMOVAL_CHECK.getInt() # Request run publication "removal" every configued seconds. If config value is changed, it will be used at next reload
frecuency = GlobalConfig.REMOVAL_CHECK.getInt() # Request run publication "removal" every configued seconds. If config value is changed, it will be used at next reload
friendly_name = 'Deployed Service Cleaner'
def __init__(self, environment):
super(DeployedServiceRemover,self).__init__(environment)
super(DeployedServiceRemover, self).__init__(environment)
@transaction.atomic
def startRemovalOf(self, ds):
# Get publications in course...., can be at most 1!!!
logger.debug('Removal process of {0}'.format(ds))
publishing = ds.publications.filter(state=State.PREPARING)
for p in publishing:
p.cancel()
@ -78,17 +79,16 @@ class DeployedServiceRemover(Job):
ds.state = State.REMOVING
ds.name = ds.name + ' (removed)'
ds.save()
@transaction.atomic
@transaction.atomic
def continueRemovalOf(self, ds):
# First, we remove all publications and user services in "info_state"
ds.userServices.select_for_update().filter(state__in=State.INFO_STATES).delete()
# Mark usable user services as removable
now = getSqlDatetime()
ds.userServices.select_for_update().filter(state=State.USABLE).update(state=State.REMOVABLE, state_date=now)
# When no service is at database, we start with publications
# When no service is at database, we start with publications
if ds.userServices.all().count() == 0:
try:
logger.debug('All services removed, checking active publication')
@ -99,10 +99,10 @@ class DeployedServiceRemover(Job):
logger.debug('No active publication found, removing info states and checking if removal is done')
ds.publications.filter(state__in=State.INFO_STATES).delete()
if ds.publications.count() is 0:
ds.removed() # Mark it as removed, clean later from database
except Exception as e:
ds.removed() # Mark it as removed, clean later from database
except Exception:
logger.exception('Cought unexpected exception at continueRemovalOf: ')
def run(self):
# First check if there is someone in "removable" estate
rems = DeployedService.objects.filter(state=State.REMOVABLE)[:10]
@ -115,5 +115,3 @@ class DeployedServiceRemover(Job):
logger.debug('Found a deployed service in removing state, continuing removal of {0}'.format(rems))
for rem in rems:
self.continueRemovalOf(rem)

View File

@ -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.
'''
@ -43,18 +43,19 @@ import logging
logger = logging.getLogger(__name__)
class HangedCleaner(Job):
class HangedCleaner(Job):
frecuency = GlobalConfig.MAX_INITIALIZING_TIME.getInt()
friendly_name = 'Hanged services checker'
def __init__(self, environment):
super(HangedCleaner,self).__init__(environment)
super(HangedCleaner, self).__init__(environment)
def run(self):
since_state = getSqlDatetime() - timedelta( seconds = GlobalConfig.MAX_INITIALIZING_TIME.getInt() )
since_state = getSqlDatetime() - timedelta(seconds=GlobalConfig.MAX_INITIALIZING_TIME.getInt())
# Filter for locating machine not ready
flt = Q(state_date__lt=since_state, state=State.PREPARING) | Q(state_date__lt=since_state, state=State.USABLE, os_state=State.PREPARING)
for ds in DeployedService.objects.exclude(osmanager=None, state__in=State.VALID_STATES):
logger.debug('Searching for hanged services for {0}'.format(ds))
for us in ds.userServices.filter(flt):
@ -62,4 +63,3 @@ class HangedCleaner(Job):
log.doLog(us, log.ERROR, 'User Service seems to be hanged. Removing it.', log.INTERNAL)
log.doLog(ds, log.ERROR, 'Removing user service {0} because it seems to be hanged'.format(us.friendly_name))
us.removeOrCancel()

View File

@ -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.
'''
@ -45,28 +45,29 @@ logger = logging.getLogger(__name__)
class PublicationInfoItemsCleaner(Job):
frecuency = GlobalConfig.CLEANUP_CHECK.getInt() # Request run cache "info" cleaner every configured seconds. If config value is changed, it will be used at next reload
frecuency = GlobalConfig.CLEANUP_CHECK.getInt() # Request run cache "info" cleaner every configured seconds. If config value is changed, it will be used at next reload
friendly_name = 'Publications Info Cleaner'
now = getSqlDatetime()
def __init__(self, environment):
super(PublicationInfoItemsCleaner,self).__init__(environment)
super(PublicationInfoItemsCleaner, self).__init__(environment)
def run(self):
removeFrom = getSqlDatetime() - timedelta(seconds = GlobalConfig.KEEP_INFO_TIME.getInt(True))
removeFrom = getSqlDatetime() - timedelta(seconds=GlobalConfig.KEEP_INFO_TIME.getInt(True))
DeployedServicePublication.objects.filter(state__in=State.INFO_STATES, state_date__lt=removeFrom).delete()
class PublicationCleaner(Job):
frecuency = GlobalConfig.REMOVAL_CHECK.getInt() # Request run publication "removal" every configued seconds. If config value is changed, it will be used at next reload
frecuency = GlobalConfig.REMOVAL_CHECK.getInt() # Request run publication "removal" every configued seconds. If config value is changed, it will be used at next reload
friendly_name = 'Publication Cleaner'
def __init__(self, environment):
super(PublicationCleaner,self).__init__(environment)
super(PublicationCleaner, self).__init__(environment)
def run(self):
removables = DeployedServicePublication.objects.filter(state=State.REMOVABLE)
for removable in removables:
try:
PublicationManager.manager().unpublish(removable)
except PublishException: # Can say that it cant be removed right now
except PublishException: # Can say that it cant be removed right now
logger.debug('Delaying removal')
pass

View File

@ -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.
'''
@ -46,7 +46,7 @@ import logging
logger = logging.getLogger(__name__)
class ServiceCacheUpdater(Job):
'''
Cache updater is responsible of keeping up to date the cache for different deployed services configurations requested
@ -54,37 +54,37 @@ class ServiceCacheUpdater(Job):
if cache is not needed.
This is included as a scheduled task that will run every X seconds, and scheduler will keep it so it will be only executed by one backend at a time
'''
frecuency = GlobalConfig.CACHE_CHECK_DELAY.getInt() # Request run cache manager every configured seconds (defaults to 20 seconds).
frecuency = GlobalConfig.CACHE_CHECK_DELAY.getInt() # Request run cache manager every configured seconds (defaults to 20 seconds).
# If config value is changed, it will be used at next reload
friendly_name = 'Service Cache Updater'
def __init__(self, environment):
super(ServiceCacheUpdater,self).__init__(environment)
super(ServiceCacheUpdater, self).__init__(environment)
@staticmethod
def calcProportion(max, actual):
return actual * 10000 / max
def calcProportion(max_, actual):
return actual * 10000 / (max_ or 1)
@staticmethod
def __notifyRestrain(deployedService):
log.doLog(deployedService, log.WARN, 'Deployed service is restrained due to errors', log.INTERNAL)
logger.info('Deployed service {0} is restrained, will check this later'.format(deployedService.name))
@transaction.atomic
@transaction.atomic
def bestDeployedServiceNeedingCacheUpdate(self):
# State filter for cached and inAssigned objects
# First we get all deployed services that could need cache generation
DeployedService.objects.update()
# We start filtering out the deployed services that do not need caching at all.
whichNeedsCaching = DeployedService.objects.filter(Q(initial_srvs__gt=0) | Q(cache_l1_srvs__gt=0)).filter(max_srvs__gt=0,state=State.ACTIVE)
whichNeedsCaching = DeployedService.objects.filter(Q(initial_srvs__gt=0) | Q(cache_l1_srvs__gt=0)).filter(max_srvs__gt=0, state=State.ACTIVE)
# We will get the one that proportionally needs more cache
selected = None
cachedL1, cachedL2, assigned = 0,0,0
toCacheL1 = False # Mark for prefering update L1 cache before L2 cache
prop = ServiceCacheUpdater.calcProportion(1,1)
cachedL1, cachedL2, assigned = 0, 0, 0
toCacheL1 = False # Mark for prefering update L1 cache before L2 cache
prop = ServiceCacheUpdater.calcProportion(1, 1)
for ds in whichNeedsCaching:
ds.userServices.update() # Cleans cached queries
ds.userServices.update() # Cleans cached queries
# If this deployedService don't have a publication active and needs it, ignore it
if ds.activePublication() == None and ds.service.getInstance().publicationType is not None:
logger.debug('Needs publication but do not have one, cache test ignored')
@ -93,11 +93,11 @@ class ServiceCacheUpdater(Job):
if ds.publications.filter(state=State.PREPARING).count() > 0:
logger.debug('Stopped cache generation for deployed service with publication running: {0}'.format(ds))
continue
if ds.isRestrained():
ServiceCacheUpdater.__notifyRestrain(ds)
continue
# Get data related to actual state of cache
inCacheL1 = ds.cachedUserServices().filter(UserServiceManager.getCacheStateFilter(services.UserDeployment.L1_CACHE)).count()
inCacheL2 = ds.cachedUserServices().filter(UserServiceManager.getCacheStateFilter(services.UserDeployment.L2_CACHE)).count()
@ -118,15 +118,15 @@ class ServiceCacheUpdater(Job):
cachedL1, cachedL2, assigned = inCacheL1, inCacheL2, inAssigned
selected = ds
break
# If we have more in L2 cache than needed, decrease L2 cache, but int this case, we continue checking cause L2 cache removal
# has less priority than l1 creations or removals, but higher. In this case, we will simply take last l2 oversized found and reduce it
# If we have more in L2 cache than needed, decrease L2 cache, but int this case, we continue checking cause L2 cache removal
# has less priority than l1 creations or removals, but higher. In this case, we will simply take last l2 oversized found and reduce it
if inCacheL2 > ds.cache_l2_srvs:
if toCacheL1 == False:
logger.debug('We have more services in L2 cache than configured, decreasing it')
cachedL1, cachedL2, assigned = inCacheL1, inCacheL2, inAssigned
selected = ds
prop = ServiceCacheUpdater.calcProportion(1,0)
prop = ServiceCacheUpdater.calcProportion(1, 0)
# If this service don't allows more starting user services, continue
if UserServiceManager.manager().canInitiateServiceFromDeployedService(ds) is False:
@ -143,11 +143,11 @@ class ServiceCacheUpdater(Job):
cachedL1, cachedL2, assigned = inCacheL1, inCacheL2, inAssigned
selected = ds
prop = p
# We skip it if already at max
if totalL1Assigned == ds.max_srvs:
continue;
continue
if totalL1Assigned < ds.initial_srvs:
p = ServiceCacheUpdater.calcProportion(ds.initial_srvs, totalL1Assigned)
if p < prop or toCacheL1 == False:
@ -164,14 +164,14 @@ class ServiceCacheUpdater(Job):
selected = ds
cachedL1, cachedL2, assigned = inCacheL1, inCacheL2, inAssigned
prop = p
# We also return calculated values so we can reuse then
return selected, cachedL1, cachedL2, assigned
def growL1Cache(self, ds, cacheL1, cacheL2, assigned):
'''
This method tries to enlarge L1 cache.
If for some reason the number of deployed services (Counting all, ACTIVE
and PREPARING, assigned, L1 and L2) is over max allowed service deployments,
this method will not grow the L1 cache
@ -189,7 +189,7 @@ class ServiceCacheUpdater(Job):
else:
valid = n
break
if valid is not None:
valid.moveToLevel(services.UserDeployment.L1_CACHE)
return
@ -200,11 +200,11 @@ class ServiceCacheUpdater(Job):
# TODO: When alerts are ready, notify this
except:
logger.exception('Exception')
def growL2Cache(self, ds, cacheL1, cacheL2, assigned):
'''
Tries to grow L2 cache of service.
If for some reason the number of deployed services (Counting all, ACTIVE
and PREPARING, assigned, L1 and L2) is over max allowed service deployments,
this method will not grow the L1 cache
@ -215,7 +215,7 @@ class ServiceCacheUpdater(Job):
except MaxServicesReachedException as e:
logger.error(str(e))
# TODO: When alerts are ready, notify this
def reduceL1Cache(self, ds, cacheL1, cacheL2, assigned):
logger.debug("Reducing L1 cache erasing a service in cache for {0}".format(ds))
# We will try to destroy the newest cacheL1 element that is USABLE if the deployer can't cancel a new service creation
@ -223,7 +223,7 @@ class ServiceCacheUpdater(Job):
if len(cacheItems) == 0:
logger.debug('There is more services than configured, but could not reduce cache cause its already empty')
return
if cacheL2 < ds.cache_l2_srvs:
valid = None
for n in cacheItems:
@ -234,14 +234,14 @@ class ServiceCacheUpdater(Job):
else:
valid = n
break
if valid is not None:
valid.moveToLevel(services.UserDeployment.L2_CACHE)
return
cache = cacheItems[0]
cache.removeOrCancel()
def reduceL2Cache(self, ds, cacheL1, cacheL2, assigned):
logger.debug("Reducing L2 cache erasing a service in cache for {0}".format(ds))
if cacheL2 > 0:
@ -249,7 +249,7 @@ class ServiceCacheUpdater(Job):
# TODO: Look first for non finished cache items and cancel them
cache = cacheItems[0]
cache.removeOrCancel()
def run(self):
logger.debug('Starting cache checking')
# We need to get
@ -257,10 +257,10 @@ class ServiceCacheUpdater(Job):
# We have cache to update??
if ds == None:
logger.debug('Cache up to date')
return
return
logger.debug("Updating cache for {0}".format(ds))
totalL1Assigned = cacheL1 + assigned
# We try first to reduce cache before tring to increase it.
# This means that if there is excesive number of user deployments
# for L1 or L2 cache, this will be reduced untill they have good numbers.
@ -271,11 +271,11 @@ class ServiceCacheUpdater(Job):
self.reduceL1Cache(ds, cacheL1, cacheL2, assigned)
elif totalL1Assigned > ds.initial_srvs and cacheL1 > ds.cache_l1_srvs:
self.reduceL1Cache(ds, cacheL1, cacheL2, assigned)
elif cacheL2 > ds.cache_l2_srvs: # We have excesives L2 items
elif cacheL2 > ds.cache_l2_srvs: # We have excesives L2 items
self.reduceL2Cache(ds, cacheL1, cacheL2, assigned)
elif totalL1Assigned < ds.max_srvs and (totalL1Assigned < ds.initial_srvs or cacheL1 < ds.cache_l1_srvs): # We need more services
self.growL1Cache(ds, cacheL1, cacheL2, assigned)
elif cacheL2 < ds.cache_l2_srvs: # We need more L2 items
elif totalL1Assigned < ds.max_srvs and (totalL1Assigned < ds.initial_srvs or cacheL1 < ds.cache_l1_srvs): # We need more services
self.growL1Cache(ds, cacheL1, cacheL2, assigned)
elif cacheL2 < ds.cache_l2_srvs: # We need more L2 items
self.growL2Cache(ds, cacheL1, cacheL2, assigned)
else:
logger.info("We have more services than max requested for {0}, but can't erase any of then cause all of them are already assigned".format(ds))

View File

@ -3,27 +3,27 @@
# Copyright (c) 2013 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.
'''
@ -41,22 +41,22 @@ import logging
logger = logging.getLogger(__name__)
class DeployedServiceStatsCollector(Job):
'''
This Job is responsible for collecting stats for every deployed service every ten minutes
'''
frecuency = 599 # Once every ten minutes, 601 is prime, 599 also is prime
frecuency = 599 # Once every ten minutes, 601 is prime, 599 also is prime
friendly_name = 'Deployed Service Stats'
def __init__(self, environment):
super(DeployedServiceStatsCollector,self).__init__(environment)
super(DeployedServiceStatsCollector, self).__init__(environment)
def run(self):
logger.debug('Starting Deployed service stats collector')
for ds in DeployedService.objects.filter(state = State.ACTIVE):
for ds in DeployedService.objects.filter(state=State.ACTIVE):
try:
fltr = ds.assignedUserServices().exclude(state__in=State.INFO_STATES)
assigned = fltr.count()
@ -65,32 +65,31 @@ class DeployedServiceStatsCollector(Job):
counters.addCounter(ds, counters.CT_INUSE, inUse)
except:
logger.exception('Getting counters for deployed service {0}'.format(ds))
logger.debug('Done Deployed service stats collector')
class StatsCleaner(Job):
'''
This Job is responsible of housekeeping of stats tables.
This Job is responsible of housekeeping of stats tables.
This is done by:
* Deleting all records
* Optimize table
'''
frecuency = 3600*24*15 # Ejecuted just once every 15 days
frecuency = 3600 * 24 * 15 # Ejecuted just once every 15 days
friendly_name = 'Statistic housekeeping'
def run(self):
logger.debug('Starting statistics cleanup')
try:
statsManager().cleanupCounters()
except:
logger.exception('Cleaning up counters')
try:
statsManager().cleanupEvents()
except:
logger.exception('Cleaning up events')
logger.debug('Donde statistics cleanup')

View File

@ -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.
'''
@ -48,31 +48,30 @@ logger = logging.getLogger(__name__)
# Look for non current cache items and mark them as removables.
class UserServiceInfoItemsCleaner(Job):
frecuency = GlobalConfig.CLEANUP_CHECK.getInt() # Request run cache "info" cleaner every configured seconds. If config value is changed, it will be used at next reload
frecuency = GlobalConfig.CLEANUP_CHECK.getInt() # Request run cache "info" cleaner every configured seconds. If config value is changed, it will be used at next reload
friendly_name = 'User Service Info Cleaner'
def __init__(self, environment):
super(UserServiceInfoItemsCleaner,self).__init__(environment)
super(UserServiceInfoItemsCleaner, self).__init__(environment)
def run(self):
removeFrom = getSqlDatetime() - timedelta(seconds = GlobalConfig.KEEP_INFO_TIME.getInt(True))
removeFrom = getSqlDatetime() - timedelta(seconds=GlobalConfig.KEEP_INFO_TIME.getInt(True))
logger.debug('Removing information user services from {0}'.format(removeFrom))
UserService.objects.select_for_update().filter(state__in=State.INFO_STATES, state_date__lt=removeFrom).delete()
class UserServiceRemover(Job):
frecuency = GlobalConfig.REMOVAL_CHECK.getInt() # Request run cache "info" cleaner every configued seconds. If config value is changed, it will be used at next reload
frecuency = GlobalConfig.REMOVAL_CHECK.getInt() # Request run cache "info" cleaner every configued seconds. If config value is changed, it will be used at next reload
friendly_name = 'User Service Cleaner'
removeAtOnce = GlobalConfig.USER_SERVICE_CLEAN_NUMBER.getInt() # Same, it will work at reload
removeAtOnce = GlobalConfig.USER_SERVICE_CLEAN_NUMBER.getInt() # Same, it will work at reload
def __init__(self, environment):
super(UserServiceRemover,self).__init__(environment)
super(UserServiceRemover, self).__init__(environment)
def run(self):
removeFrom = getSqlDatetime() - timedelta(seconds=10) # We keep at least 30 seconds the machine before removing it, so we avoid connections errors
removeFrom = getSqlDatetime() - timedelta(seconds=10) # We keep at least 30 seconds the machine before removing it, so we avoid connections errors
removables = UserService.objects.filter(state=State.REMOVABLE, state_date__lt=removeFrom)[0:UserServiceRemover.removeAtOnce]
for us in removables:
UserServiceManager.manager().remove(us)

View File

@ -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.
'''
@ -32,26 +32,28 @@
'''
from __future__ import unicode_literals
def __init__():
'''
This imports all packages that are descendant of this package, and, after that,
it register all subclases of service provider as
it register all subclases of service provider as
'''
import os.path, pkgutil
import os.path
import pkgutil
import sys
from uds.core import jobs
from uds.core.managers.TaskManager import TaskManager
# Dinamycally import children of this package.
pkgpath = os.path.dirname(sys.modules[__name__].__file__)
for _, name, _ in pkgutil.iter_modules([pkgpath]):
__import__(name, globals(), locals(), [], -1)
p = jobs.Job
# This is marked as error in IDE, but it's not (__subclasses__)
for cls in p.__subclasses__():
# Limit to autoregister just workers jobs inside this module
if cls.__module__[0:16] == 'uds.core.workers':
TaskManager.registerJob(cls)
__init__()

View File

@ -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.
@ -55,48 +55,48 @@ class TSNXTransport(Transport):
typeName = _('NX Transport (tunneled)')
typeType = 'TSNXTransport'
typeDescription = _('NX Transport for tunneled connection')
iconFile = 'nx.png'
iconFile = 'nx.png'
needsJava = True # If this transport needs java for rendering
supportedOss = ['Windows', 'Macintosh', 'Linux']
tunnelServer = gui.TextField(label=_('Tunnel server'), order = 1, tooltip = _('IP or Hostname of tunnel server send to client device ("public" ip) and port. (use HOST:PORT format)'))
tunnelCheckServer = gui.TextField(label=_('Tunnel host check'), order = 2, tooltip = _('If not empty, this server will be used to check if service is running before assigning it to user. (use HOST:PORT format)'))
tunnelServer = gui.TextField(label=_('Tunnel server'), order=1, tooltip=_('IP or Hostname of tunnel server send to client device ("public" ip) and port. (use HOST:PORT format)'))
tunnelCheckServer = gui.TextField(label=_('Tunnel host check'), order=2, tooltip=_('If not empty, this server will be used to check if service is running before assigning it to user. (use HOST:PORT format)'))
useEmptyCreds = gui.CheckBoxField(label = _('Empty creds'), order = 3, tooltip = _('If checked, the credentials used to connect will be emtpy'))
fixedName = gui.TextField(label=_('Username'), order = 4, tooltip = _('If not empty, this username will be always used as credential'))
fixedPassword = gui.PasswordField(label=_('Password'), order = 5, tooltip = _('If not empty, this password will be always used as credential'))
listenPort = gui.NumericField(label=_('Listen port'), length = 5, order = 6, tooltip = _('Listening port of NX (ssh) at client machine'), defvalue = '22')
connection = gui.ChoiceField(label=_('Connection'), order = 7, tooltip = _('Connection speed for this transport (quality)'), values = [
useEmptyCreds = gui.CheckBoxField(label=_('Empty creds'), order=3, tooltip=_('If checked, the credentials used to connect will be emtpy'))
fixedName = gui.TextField(label=_('Username'), order=4, tooltip=_('If not empty, this username will be always used as credential'))
fixedPassword = gui.PasswordField(label=_('Password'), order=5, tooltip=_('If not empty, this password will be always used as credential'))
listenPort = gui.NumericField(label=_('Listen port'), length=5, order=6, tooltip=_('Listening port of NX (ssh) at client machine'), defvalue='22')
connection = gui.ChoiceField(label=_('Connection'), order=7, tooltip=_('Connection speed for this transport (quality)'), values=[
{'id' : 'modem', 'text' : 'modem'},
{'id' : 'isdn', 'text' : 'isdn'},
{'id' : 'adsl', 'text' : 'adsl'},
{'id' : 'wan', 'text' : 'wan'},
{'id' : 'lan', 'text' : 'lan'},
] )
session = gui.ChoiceField(label=_('Session'), order = 8, tooltip = _('Desktop session'), values = [
])
session = gui.ChoiceField(label=_('Session'), order=8, tooltip=_('Desktop session'), values=[
{'id' : 'gnome', 'text' : 'gnome'},
{'id' : 'kde', 'text' : 'kde'},
{'id' : 'cde', 'text' : 'cde'},
] )
cacheDisk = gui.ChoiceField(label=_('Disk Cache'), order = 9, tooltip = _('Cache size en Mb stored at disk'), values = [
])
cacheDisk = gui.ChoiceField(label=_('Disk Cache'), order=9, tooltip=_('Cache size en Mb stored at disk'), values=[
{'id' : '0', 'text' : '0 Mb'},
{'id' : '32', 'text' : '32 Mb'},
{'id' : '64', 'text' : '64 Mb'},
{'id' : '128', 'text' : '128 Mb'},
{'id' : '256', 'text' : '256 Mb'},
{'id' : '512', 'text' : '512 Mb'},
] )
cacheMem = gui.ChoiceField(label=_('Memory Cache'), order = 10, tooltip = _('Cache size en Mb keept at memory'), values = [
])
cacheMem = gui.ChoiceField(label=_('Memory Cache'), order=10, tooltip=_('Cache size en Mb keept at memory'), values=[
{'id' : '4', 'text' : '4 Mb'},
{'id' : '8', 'text' : '8 Mb'},
{'id' : '16', 'text' : '16 Mb'},
{'id' : '32', 'text' : '32 Mb'},
{'id' : '64', 'text' : '64 Mb'},
{'id' : '128', 'text' : '128 Mb'},
] )
def __init__(self, environment, values = None):
])
def __init__(self, environment, values=None):
super(TSNXTransport, self).__init__(environment, values)
if values != None:
if values['tunnelServer'].find(':') == -1:
@ -122,26 +122,26 @@ class TSNXTransport(Transport):
self._session = ''
self._cacheDisk = ''
self._cacheMem = ''
def marshal(self):
'''
Serializes the transport data so we can store it in database
'''
return str.join( '\t', [ 'v1', gui.boolToStr(self._useEmptyCreds), self._fixedName, self._fixedPassword, self._listenPort,
self._connection, self._session, self._cacheDisk, self._cacheMem, self._tunnelServer, self._tunnelCheckServer ] )
return str.join('\t', [ 'v1', gui.boolToStr(self._useEmptyCreds), self._fixedName, self._fixedPassword, self._listenPort,
self._connection, self._session, self._cacheDisk, self._cacheMem, self._tunnelServer, self._tunnelCheckServer ])
def unmarshal(self, string):
data = string.split('\t')
if data[0] == 'v1':
self._useEmptyCreds = gui.strToBool(data[1])
self._fixedName, self._fixedPassword, self._listenPort, self._connection, self._session, self._cacheDisk, self._cacheMem, self._tunnelServer, self._tunnelCheckServer = data[2:]
def valuesDict(self):
return { 'useEmptyCreds' : gui.boolToStr(self._useEmptyCreds), 'fixedName' : self._fixedName,
return { 'useEmptyCreds' : gui.boolToStr(self._useEmptyCreds), 'fixedName' : self._fixedName,
'fixedPassword' : self._fixedPassword, 'listenPort': self._listenPort,
'connection' : self._connection, 'session' : self._session, 'cacheDisk' : self._cacheDisk,
'cacheMem' : self._cacheMem, 'tunnelServer' : self._tunnelServer,
'cacheMem' : self._cacheMem, 'tunnelServer' : self._tunnelServer,
'tunnelCheckServer' : self._tunnelCheckServer }
def isAvailableFor(self, ip):
@ -159,11 +159,11 @@ class TSNXTransport(Transport):
else:
self.cache().put(ip, 'N', READY_CACHE_TIMEOUT)
return ready == 'Y'
def renderForHtml(self, userService, idUserService, idTransport, ip, os, user, password):
prefs = user.prefs('nx')
username = user.getUsernameForAuth()
proc = username.split('@')
username = proc[0]
@ -172,33 +172,32 @@ class TSNXTransport(Transport):
if self._fixedPassword is not '':
password = self._fixedPassword
if self._useEmptyCreds is True:
username, password = '',''
username, password = '', ''
width, height = CommonPrefs.getWidthHeight(prefs)
cache = Cache('pam')
tunuser = ''.join(random.choice(string.letters + string.digits) for i in xrange(12)) + ("%f" % time.time()).split('.')[1]
tunpass = ''.join(random.choice(string.letters + string.digits) for i in xrange(12))
cache.put(tunuser, tunpass, 60*10) # Credential valid for ten minutes, and for 1 use only
cache.put(tunuser, tunpass, 60 * 10) # Credential valid for ten minutes, and for 1 use only
sshHost, sshPort = self._tunnelServer.split(':')
logger.debug('Username generated: {0}, password: {1}'.format(tunuser, tunpass))
tun = "{0} {1} {2} {3} {4} {5} {6}".format(tunuser, tunpass, sshHost, sshPort, ip, self._listenPort, '9')
# Extra data
extra = { 'width': width, 'height' : height,
'connection' : self._connection,
'session' : self._session, 'cacheDisk': self._cacheDisk,
'cacheMem' : self._cacheMem, 'tun' : tun }
# Fix username/password acording to os manager
username, password = userService.processUserPassword(username, password)
return generateHtmlForNX(self, idUserService, idTransport, os, username, password, extra)
def getHtmlComponent(self, theId, os, componentId):
# We use helper to keep this clean
return getHtmlComponent(self.__module__, componentId)

View File

@ -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.
'''
@ -32,6 +32,8 @@
'''
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext as _
from uds.core.util.Config import Config
from uds.core.util import OsDetector
@ -48,16 +50,15 @@ def simpleScrambler(data):
n = ord('M')
pos = 0
for c in data:
res.append( chr(ord(c) ^ n) )
res.append(chr(ord(c) ^ n))
n = n ^ pos
pos = pos + 1
return "".join(res).encode('hex')
def generateHtmlForNX(transport, idUserService, idTransport, os, user, password, extra):
isMac = os['OS'] == OsDetector.Macintosh
applet = reverse('uds.web.views.transcomp', kwargs = { 'idTransport' : idTransport, 'componentId' : '1' })
applet = reverse('uds.web.views.transcomp', kwargs={'idTransport': idTransport, 'componentId': '1'})
# Gets the codebase, simply remove last char from applet
codebase = applet[:-1]
# We generate the "data" parameter
@ -74,22 +75,22 @@ def generateHtmlForNX(transport, idUserService, idTransport, os, user, password,
'tun:' + extra['tun'],
'is:' + idUserService
]
data = simpleScrambler( '\t'.join(data))
data = simpleScrambler('\t'.join(data))
if isMac is True:
msg = '<p>' + _('In order to use this transport, you need to install first OpenNX Client for mac') + '</p>'
msg += '<p>' + _('You can oibtain it from ') + '<a href="{0}">'.format(Config.section('NX').value('downloadUrlMACOS').get()) + _('OpenNx Website') + '</a></p>'
else:
msg = '<p>' + _('In order to use this transport, you need to install first Nomachine Nx Client version 3.5.x') + '</p>'
msg +='<p>' + _('you can obtain it for your platform from') + '<a href="{0}">'.format(Config.section('NX').value('downloadUrl').get()) + _('nochamine web site') + '</a></p>'
res = '<div idTransport="applet"><applet code="NxTunTransportApplet.class" codebase="%s" archive="%s" width="165" height="22"><param name="data" value="%s"/><param name="permissions" value="all-permissions"/></applet></div>' % (codebase, '1', data )
msg += '<p>' + _('you can obtain it for your platform from') + '<a href="{0}">'.format(Config.section('NX').value('downloadUrl').get()) + _('nochamine web site') + '</a></p>'
res = '<div idTransport="applet"><applet code="NxTunTransportApplet.class" codebase="%s" archive="%s" width="165" height="22"><param name="data" value="%s"/><param name="permissions" value="all-permissions"/></applet></div>' % (codebase, '1', data)
res += '<div>' + msg + '</div>'
return res
def getHtmlComponent(module, componentId):
dict = { '1' : ['nxtuntransport.jar', 'application/java-archive' ], '2' : ['launcher.jar', 'application/java-archive']}
if dict.has_key(componentId) == False:
return ['text/plain', 'no component']
fname = os.path.dirname(sys.modules[module].__file__) + '/applet/' + dict[componentId][0]
@ -98,4 +99,4 @@ def getHtmlComponent(module, componentId):
f = open(fname, 'rb')
data = f.read()
f.close()
return [ dict[componentId][1], data ]
return [ dict[componentId][1], data ]

View File

@ -4,33 +4,34 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from django.utils.translation import ugettext as _
from uds.models import DeployedService, Service, OSManager, Transport, State, Group
from ..auths.AdminAuth import needs_credentials
from django.db import IntegrityError
@ -105,17 +106,17 @@ def getDeployedServices(credentials, all_):
@needs_credentials
def getDeployedService(credentials, id):
def getDeployedService(credentials, id_):
'''
Returns the available deployed services
'''
logger.debug('Returning list of deployed services')
ds = DeployedService.objects.get(pk=id)
ds = DeployedService.objects.get(pk=id_)
if ds.state == State.ACTIVE:
return dictFromDeployedService(ds)
raise InsertException(_('Deployed Service does not exists'))
@needs_credentials
def createDeployedService(credentials, deployedService):
'''
@ -134,9 +135,9 @@ def createDeployedService(credentials, deployedService):
osManager = None
if serviceInstance.needsManager:
osManager = OSManager.objects.get(pk=deployedService['idOsManager'])
dps = DeployedService.objects.create(name = deployedService['name'], comments = deployedService['comments'], service = service,
osmanager = osManager, state = State.ACTIVE, initial_srvs = initialServices, cache_l1_srvs = cacheL1,
cache_l2_srvs = cacheL2, max_srvs = maxServices, current_pub_revision = 1)
dps = DeployedService.objects.create(name=deployedService['name'], comments=deployedService['comments'], service=service,
osmanager=osManager, state=State.ACTIVE, initial_srvs=initialServices, cache_l1_srvs=cacheL1,
cache_l2_srvs=cacheL2, max_srvs=maxServices, current_pub_revision=1)
# Now we add transports
addTransportsToDeployedService(dps, deployedService['transports'])
except IntegrityError as e:
@ -146,7 +147,8 @@ def createDeployedService(credentials, deployedService):
logger.error("Exception adding deployed service {0}".format(deployedService))
raise InsertException(str(e))
return str(dps.id)
@needs_credentials
def modifyDeployedService(credentials, deployedService):
'''
@ -162,7 +164,7 @@ def modifyDeployedService(credentials, deployedService):
maxServices = deployedService['maxServices']
if serviceInstance.usesCache == False:
initialServices = cacheL1 = cacheL2 = maxServices = 0
dps.name = deployedService['name']
dps.comments = deployedService['comments']
dps.initial_srvs = initialServices
@ -183,6 +185,7 @@ def modifyDeployedService(credentials, deployedService):
raise InsertException(str(e))
return True
@needs_credentials
def getGroupsAssignedToDeployedService(credentials, deployedServiceId):
'''
@ -199,6 +202,7 @@ def getGroupsAssignedToDeployedService(credentials, deployedServiceId):
raise InsertException(_('Deployed Service does not exists'))
return grps
@needs_credentials
def assignGroupToDeployedService(credentials, deployedServiceId, groupId):
'''
@ -215,6 +219,7 @@ def assignGroupToDeployedService(credentials, deployedServiceId, groupId):
raise InsertException(_('Deployed Service does not exists'))
return True
@needs_credentials
def removeGroupsFromDeployedService(credentials, deployedServiceId, groupIds):
'''
@ -229,6 +234,7 @@ def removeGroupsFromDeployedService(credentials, deployedServiceId, groupIds):
raise InsertException(_('Deployed Service does not exists'))
return True
@needs_credentials
def getTransportsAssignedToDeployedService(credentias, idDS):
'''
@ -236,13 +242,14 @@ def getTransportsAssignedToDeployedService(credentias, idDS):
'''
try:
ds = DeployedService.objects.get(id=idDS)
return [ dictFromTransport(t) for t in ds.transports.all() ]
return [dictFromTransport(t) for t in ds.transports.all()]
except DeployedService.DoesNotExist:
raise FindException(_('Can\'t find deployed service'))
except Exception as e:
logger.exception("getTransportsForDeployedService: ")
raise FindException(str(e))
@needs_credentials
def assignTransportToDeployedService(credentials, deployedServiceId, transportId):
logger.debug('Assigning transport {0} to service {1}'.format(transportId, deployedServiceId))
@ -254,9 +261,10 @@ def assignTransportToDeployedService(credentials, deployedServiceId, transportId
raise InsertException(_('Transport does not exists'))
except DeployedService.DoesNotExist:
raise InsertException(_('Deployed Service does not exists'))
return True
@needs_credentials
def removeTransportFromDeployedService(credentials, deployedServiceId, transportIds):
'''
@ -270,7 +278,7 @@ def removeTransportFromDeployedService(credentials, deployedServiceId, transport
raise InsertException(_('Deployed Service does not exists'))
return True
@needs_credentials
def removeDeployedService(credentials, deployedServiceId):
'''
@ -285,6 +293,7 @@ def removeDeployedService(credentials, deployedServiceId):
raise InsertException(_('Deployed service does not exists'))
return True
# Registers XML RPC Methods
def registerDeployedServicesFunctions(dispatcher):
dispatcher.register_function(getDeployedServices, 'getDeployedServices')

View File

@ -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.
'''
@ -32,7 +32,7 @@
'''
from django.utils.translation import ugettext as _
from django.db import IntegrityError
from django.db import IntegrityError
from uds.models import Provider, Service
from uds.xmlrpc.util.Helpers import dictFromData
from uds.xmlrpc.auths.AdminAuth import needs_credentials
@ -43,13 +43,14 @@ import logging
logger = logging.getLogger(__name__)
def infoDictFromServiceInstance(service):
if service is not None:
needsPublication = service.publicationType is not None
maxDeployed = service.maxDeployed
usesCache = service.usesCache
usesCache_L2 = service.usesCache_L2
cacheTooltip = _(service.cacheTooltip)
cacheTooltip = _(service.cacheTooltip)
cacheTooltip_L2 = _(service.cacheTooltip_L2)
needsManager = service.needsManager
mustAssignManually = service.mustAssignManually
@ -59,26 +60,28 @@ def infoDictFromServiceInstance(service):
maxDeployed = 0
usesCache = False
usesCache_L2 = False
cacheTooltip = ''
cacheTooltip = ''
cacheTooltip_L2 = ''
needsManager = False
mustAssignManually = False
typeName = ''
return { 'needsPublication' : needsPublication, 'maxDeployed' : maxDeployed,
'usesCache' : usesCache, 'usesCacheL2' : usesCache_L2,
'cacheTooltip' : cacheTooltip, 'cacheTooltipL2' : cacheTooltip_L2,
return { 'needsPublication' : needsPublication, 'maxDeployed' : maxDeployed,
'usesCache' : usesCache, 'usesCacheL2' : usesCache_L2,
'cacheTooltip' : cacheTooltip, 'cacheTooltipL2' : cacheTooltip_L2,
'needsManager' : needsManager, 'mustAssignManually' : mustAssignManually,
'typeName' : typeName
'typeName' : typeName
}
def dictFromService(serv):
service = serv.getInstance()
return { 'idParent' : str(serv.provider_id), 'id' : str(serv.id), 'name' : serv.name,
return { 'idParent' : str(serv.provider_id), 'id' : str(serv.id), 'name' : serv.name,
'comments' : serv.comments, 'type' : serv.data_type, 'typeName' : _(service.name()), 'info' : infoDictFromServiceInstance(service)
}
@needs_credentials
def getServices(credentials, idParent):
'''
@ -94,6 +97,7 @@ def getServices(credentials, idParent):
logger.debug(e)
return res
@needs_credentials
def getAllServices(credentials):
'''
@ -109,6 +113,7 @@ def getAllServices(credentials):
logger.exception('getAllServices')
return res
@needs_credentials
def getServiceGui(credentials, idParent, type):
'''
@ -118,12 +123,13 @@ def getServiceGui(credentials, idParent, type):
logger.debug('getServiceGui parameters: {0}, {1}'.format(idParent, type))
provider = Provider.objects.get(id=idParent).getInstance()
serviceType = provider.getServiceByType(type)
service = serviceType( Environment.getTempEnv(), provider) # Instantiate it so it has the opportunity to alter gui description based on parent
service = serviceType(Environment.getTempEnv(), provider) # Instantiate it so it has the opportunity to alter gui description based on parent
return service.guiDescription(service)
except:
logger.exception('Exception at getServiceGui')
raise
@needs_credentials
def getService(credentials, id):
'''
@ -131,7 +137,7 @@ def getService(credentials, id):
'''
logger.debug('getService parameters: {0}'.format(id))
srv = Service.objects.get(id=id)
res = [
res = [
{ 'name' : 'name', 'value' : srv.name },
{ 'name' : 'comments', 'value' : srv.comments },
]
@ -144,6 +150,7 @@ def getService(credentials, id):
logger.debug('getService res: {0}'.format(res))
return res
@needs_credentials
def createService(credentials, idParent, type, data):
'''
@ -154,14 +161,14 @@ def createService(credentials, idParent, type, data):
provider = Provider.objects.get(id=idParent)
dic = dictFromData(data)
try:
srv = provider.services.create(name = dic['name'], comments = dic['comments'], data_type = type)
srv = provider.services.create(name=dic['name'], comments=dic['comments'], data_type=type)
# Invoque serialization with correct environment
srv.data = srv.getInstance(dic).serialize()
srv.save()
except services.Service.ValidationException as e:
srv.delete()
raise ValidationException(str(e))
except IntegrityError: # Must be exception at creation
except IntegrityError: # Must be exception at creation
raise InsertException(_('Name %s already exists') % (dic['name']))
except Exception as e:
logger.exception('Unexpected exception')
@ -185,12 +192,12 @@ def modifyService(credentials, id, data):
serv.save()
except services.Service.ValidationException as e:
raise ValidationException(str(e))
except IntegrityError: # Must be exception at creation
except IntegrityError: # Must be exception at creation
raise InsertException(_('Name %s already exists') % (dic['name']))
except Exception as e:
logger.exception('Unexpected exception')
raise ValidationException(str(e))
return True
@needs_credentials