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:
parent
89addaf585
commit
06ff8e32be
@ -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 = {}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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 ''
|
||||
|
@ -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
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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')),
|
||||
)
|
||||
)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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"
|
||||
|
@ -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]
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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!')
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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
@ -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)
|
||||
|
@ -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_ + '>'
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 = []
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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):]))
|
||||
|
@ -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.
|
||||
|
||||
'''
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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')
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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')
|
||||
|
@ -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)
|
||||
|
@ -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__()
|
||||
|
@ -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)
|
||||
|
@ -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 ]
|
||||
|
@ -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')
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user