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

This commit is contained in:
Adolfo Gómez 2014-02-25 03:57:29 +00:00
parent 06ff8e32be
commit ddbcc5aec4
50 changed files with 1201 additions and 1118 deletions

View File

@ -150,8 +150,11 @@ encoding//src/uds/management/commands/taskManager.py=utf-8
encoding//src/uds/management/commands/taskManager_enterprise.py=utf-8
encoding//src/uds/migrations/0001_initial.py=utf-8
encoding//src/uds/migrations/0002_auto__del_unique_userpreference_name_module.py=utf-8
encoding//src/uds/migrations/0003_auto__del_field_deployedservice_authenticator.py=utf-8
encoding//src/uds/migrations/0004_auto__add_field_deployedservice_state_date.py=utf-8
encoding//src/uds/migrations/0005_auto__add_field_config_crypt.py=utf-8
encoding//src/uds/migrations/0006_auto__chg_field_storage_data.py=utf-8
encoding//src/uds/migrations/0007_auto__add_field_config_long.py=utf-8
encoding//src/uds/migrations/0008_auto__add_userservicelog__add_field_userservice_src_hostname__add_fiel.py=utf-8
encoding//src/uds/migrations/0009_auto__del_userservicelog__add_log.py=utf-8
encoding//src/uds/migrations/0010_auto__add_field_log_owner_type.py=utf-8
@ -159,6 +162,7 @@ encoding//src/uds/migrations/0011_auto__add_statscounters__add_statsevents__chg_
encoding//src/uds/migrations/0012_auto__add_field_authenticator_small_name.py=utf-8
encoding//src/uds/migrations/0013_auto__add_field_group_is_meta__add_field_uniqueid_stamp.py=utf-8
encoding//src/uds/migrations/0014_auto__add_field_network_net_string.py=utf-8
encoding//src/uds/migrations/0015_auto__add_field_user_parent.py=utf-8
encoding//src/uds/migrations/0016_auto__add_field_userservice_cluster_node.py=utf-8
encoding//src/uds/migrations/0017_change_tables.py=utf-8
encoding//src/uds/migrations/0018_security_config.py=utf-8

View File

@ -3,27 +3,27 @@
# Copyright (c) 2012 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@ -44,28 +44,29 @@ import logging
logger = logging.getLogger(__name__)
__all__ = [ str(v) for v in ['Handler', 'Dispatcher'] ]
__all__ = [str(v) for v in ['Handler', 'Dispatcher']]
AUTH_TOKEN_HEADER = 'X-Auth-Token'
class Dispatcher(View):
services = { '' : None } # Will include a default /rest handler, but rigth now this will be fine
services = {'': None} # Will include a default /rest handler, but rigth now this will be fine
@method_decorator(csrf_exempt)
def dispatch(self, request, **kwargs):
import processors
# Remove session, so response middelwares do nothing with this
del request.session
# Now we extract method and posible variables from path
path = kwargs['arguments'].split('/')
del kwargs['arguments']
# Transverse service nodes too look for path
service = Dispatcher.services
full_path = []
# Last element will be
do_break = False
do_break = False
cls = None
while len(path) > 0 and not do_break:
# .json, .xml, ... will break path recursion
@ -84,8 +85,7 @@ class Dispatcher(View):
cls = service['']
if cls is None:
return http.HttpResponseNotFound('method not found')
# Guess content type from content type header (post) or ".xxx" to method
try:
p = full_path.split('.')
@ -93,13 +93,12 @@ class Dispatcher(View):
except:
# TODO: Extract processor from accept and/or content type?
processor = processors.available_processors_mime_dict.get(request.META.get('CONTENT_TYPE', 'json'), processors.default_processor)(request)
# Obtain method to be invoked
http_method = request.method.lower()
args = path
# Inspect
lang = None
if len(args) > 0:
@ -113,12 +112,12 @@ class Dispatcher(View):
# Instantiate method handler and locate http_method dispatcher
try:
handler = cls(request, full_path, http_method, processor.processParameters(), *args, **kwargs)
# If no lang on request, try to get the one from
# If no lang on request, try to get the one from
if lang is None:
activate(handler.getValue('locale'))
else:
handler.setValue('locale', lang) # Update Locale if request had one
handler.setValue('locale', lang) # Update Locale if request had one
operation = getattr(handler, http_method)
except processors.ParametersException as e:
return http.HttpResponseServerError('Invalid parameters invoking {0}: {1}'.format(path[0], e))
@ -134,15 +133,14 @@ class Dispatcher(View):
logger.exception('error accessing attribute')
logger.debug('Getting attribute {0} for {1}'.format(http_method, full_path))
return http.HttpResponseServerError('Unexcepected error')
# Invokes the handler's operation, add headers to response and returns
try:
start = time.time();
start = time.time()
response = operation()
logger.debug('Execution time for method: {0}'.format(time.time() - start))
if not handler.raw: # Raw handlers will return an HttpResponse Object
if not handler.raw: # Raw handlers will return an HttpResponse Object
start = time.time()
response = processor.getResponse(response)
logger.debug('Execution time for encoding: {0}'.format(time.time() - start))
@ -165,8 +163,8 @@ class Dispatcher(View):
@staticmethod
def registerSubclasses(classes):
for cls in classes:
if len(cls.__subclasses__()) == 0: # Only classes that has not been inherited will be registered as Handlers
for cls in classes:
if len(cls.__subclasses__()) == 0: # Only classes that has not been inherited will be registered as Handlers
logger.debug('Found class {0}'.format(cls))
if cls.name is None:
name = cls.__name__.lower()
@ -177,15 +175,15 @@ class Dispatcher(View):
if cls.path is not None:
for k in cls.path.split('/'):
if service_node.get(k) is None:
service_node[k] = { '' : None }
service_node[k] = {'': None}
service_node = service_node[k]
if service_node.get(name) is None:
service_node[name] = { '' : None }
service_node[name] = {'': None}
service_node[name][''] = cls
else:
Dispatcher.registerSubclasses(cls.__subclasses__())
# Initializes the dispatchers
@staticmethod
def initialize():
@ -193,18 +191,19 @@ class Dispatcher(View):
This imports all packages that are descendant of this package, and, after that,
it register all subclases of Handler. (In fact, it looks for packages inside "methods" package, child of this)
'''
import os.path, pkgutil
import os.path
import pkgutil
import sys
logger.debug('Loading Handlers')
# Dinamycally import children of this package. The __init__.py files must register, if needed, inside ServiceProviderFactory
package = 'methods'
pkgpath = os.path.join(os.path.dirname(sys.modules[__name__].__file__), package)
for _, name, _ in pkgutil.iter_modules([pkgpath]):
__import__(__name__ + '.' + package + '.' + name, globals(), locals(), [], -1)
__import__(__name__ + '.' + package + '.' + name, globals(), locals(), [], -1)
Dispatcher.registerSubclasses(Handler.__subclasses__()) # @UndefinedVariable
Dispatcher.initialize()

View File

@ -4,33 +4,34 @@
# Copyright (c) 2012 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from django.contrib.sessions.backends.db import SessionStore
from django.conf import settings
@ -42,38 +43,44 @@ logger = logging.getLogger(__name__)
AUTH_TOKEN_HEADER = 'HTTP_X_AUTH_TOKEN'
class HandlerError(Exception):
pass
class NotFound(HandlerError):
pass
class AccessDenied(HandlerError):
pass
class RequestError(HandlerError):
pass
class ResponseError(HandlerError):
pass
class Handler(object):
raw = False # If true, Handler will return directly an HttpResponse Object
name = None # If name is not used, name will be the class name in lower case
path = None # Path for this method, so we can do /auth/login, /auth/logout, /auth/auths in a simple way
authenticated = True # By default, all handlers needs authentication
needs_admin = False # By default, the methods will be accessible by anyone if nothine else indicated
needs_staff = False # By default, staff
raw = False # If true, Handler will return directly an HttpResponse Object
name = None # If name is not used, name will be the class name in lower case
path = None # Path for this method, so we can do /auth/login, /auth/logout, /auth/auths in a simple way
authenticated = True # By default, all handlers needs authentication
needs_admin = False # By default, the methods will be accessible by anyone if nothine else indicated
needs_staff = False # By default, staff
# method names: 'get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'
def __init__(self, request, path, operation, params, *args, **kwargs):
if self.needs_admin:
self.authenticated = True # If needs_admin, must also be authenticated
self.authenticated = True # If needs_admin, must also be authenticated
if self.needs_staff:
self.authenticated = True # Same for staff members
self.authenticated = True # Same for staff members
self._request = request
self._path = path
self._operation = operation
@ -82,54 +89,57 @@ class Handler(object):
self._kwargs = kwargs
self._headers = {}
self._authToken = None
if self.authenticated: # Only retrieve auth related data on authenticated handlers
if self.authenticated: # Only retrieve auth related data on authenticated handlers
try:
self._authToken = self._request.META.get(AUTH_TOKEN_HEADER, '')
self._session = SessionStore(session_key = self._authToken)
if not self._session.has_key('REST'):
raise Exception() # No valid session, so auth_token is also invalid
self._session = SessionStore(session_key=self._authToken)
if 'REST' not in self._session:
raise Exception() # No valid session, so auth_token is also invalid
except:
self._authToken = None
self._session = None
if self._authToken is None:
raise AccessDenied()
if self.needs_admin and not self.getValue('is_admin'):
raise AccessDenied()
if self.needs_staff and not self.getValue('staff_member'):
raise AccessDenied()
def headers(self):
return self._headers
def header(self, header_):
return self._headers.get(header_)
def addHeader(self, header, value):
self._headers[header] = value
def removeHeader(self, header):
try:
del self._headers[header]
except:
pass
# Auth related
def getAuthToken(self):
return self._authToken
@staticmethod
def storeSessionAuthdata(session, id_auth, username, locale, is_admin, staff_member):
if is_admin:
staff_member = True # Make admins also staff members :-)
session['REST'] = { 'auth': id_auth, 'username': username,
'locale': locale, 'is_admin': is_admin,
'staff_member': staff_member }
staff_member = True # Make admins also staff members :-)
session['REST'] = {
'auth': id_auth,
'username': username,
'locale': locale,
'is_admin': is_admin,
'staff_member': staff_member
}
def genAuthToken(self, id_auth, username, locale, is_admin, staf_member):
session = SessionStore()
session.set_expiry(GlobalConfig.ADMIN_IDLE_TIME.getInt())
@ -138,20 +148,20 @@ class Handler(object):
self._authToken = session.session_key
self._session = session
return self._authToken
def cleanAuthToken(self):
self._authToken = None
if self._session:
self._session.delete()
self._session = None
# Session related (from auth token)
def getValue(self, key):
try:
return self._session['REST'].get(key)
except:
return None
def setValue(self, key, value):
try:
self._session['REST'][key] = value
@ -159,9 +169,9 @@ class Handler(object):
self._session.save()
except:
pass
def is_admin(self):
return self.getValue('is_admin') and True or False
def is_staff_member(self):
return self.getValue('staff_member') and True or False

View File

@ -4,27 +4,27 @@
# Copyright (c) 2014 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@ -41,10 +41,11 @@ logger = logging.getLogger(__name__)
# Enclosed methods under /auth path
class Cache(Handler):
authenticated = True # Public method
needs_staff = True #
authenticated = True
needs_staff = True
def get(self):
'''
This login uses parameters to generate auth token
@ -61,14 +62,14 @@ class Cache(Handler):
on success: { 'result': 'ok', 'auth': [auth_code] }
on error: { 'result: 'error', 'error': [error string] }
'''
logger.debug('Params: {0}'.format(self._params))
if len(self._args) == 0:
return {}
if len(self._args) != 1:
raise RequestError('Invalid Request')
uCache.purge()
return 'done'

View File

@ -4,27 +4,27 @@
# Copyright (c) 2014 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@ -42,26 +42,30 @@ logger = logging.getLogger(__name__)
# Enclosed methods under /auth path
class Config(Handler):
needs_admin = True # By default, staff is lower level needed
needs_admin = True # By default, staff is lower level needed
def get(self):
res = {}
addCrypt = self.is_admin()
for cfg in cfgConfig.enumerate():
if cfg.isCrypted() is True and addCrypt is False:
continue
# add section if it do not exists
if res.has_key(cfg.section()) is False:
if cfg.section() not in res:
res[cfg.section()] = {}
res[cfg.section()][cfg.key()] = { 'value' : cfg.get(), 'crypt': cfg.isCrypted(), 'longText': cfg.isLongText() }
res[cfg.section()][cfg.key()] = {
'value': cfg.get(),
'crypt': cfg.isCrypted(),
'longText': cfg.isLongText()
}
logger.debug('Configuration: {0}'.format(res))
return res
def put(self):
for section, secDict in self._params.iteritems():
for key, vals in secDict.iteritems():
cfgConfig.update( section, key, vals['value'] )
cfgConfig.update(section, key, vals['value'])
return 'done'

View File

@ -4,27 +4,27 @@
# Copyright (c) 2014 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@ -41,17 +41,17 @@ logger = logging.getLogger(__name__)
# Enclosed methods under /auth path
class Callback(Handler):
path = 'gui'
authenticated = True # Public method
needs_staff = True #
path = 'gui'
authenticated = True
needs_staff = True
def get(self):
if len(self._args) != 1:
raise RequestError('Invalid Request')
if gui.callbacks.has_key(self._args[0]):
if self._args[0] in gui.callbacks:
return gui.callbacks[self._args[0]](self._params)
raise NotFound('callback {0} not found'.format(self._args[0]))

View File

@ -4,27 +4,27 @@
# Copyright (c) 2014 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@ -43,10 +43,11 @@ logger = logging.getLogger(__name__)
# Enclosed methods under /auth path
class Login(Handler):
path = 'auth'
authenticated = False # Public method
path = 'auth'
authenticated = False # Public method
def post(self):
'''
This login uses parameters to generate auth token
@ -76,35 +77,40 @@ class Login(Handler):
except Exception as e:
logger.exception('exception')
return {'result': 'error', 'error': unicode(e)}
class Logout(Handler):
path = 'auth'
authenticated = True # By default, all handlers needs authentication
authenticated = True # By default, all handlers needs authentication
def get(self):
# Remove auth token
self.cleanAuthToken()
return 'done'
return 'done'
def post(self):
return self.get()
class Auths(Handler):
path = 'auth'
authenticated = False # By default, all handlers needs authentication
authenticated = False # By default, all handlers needs authentication
def auths(self):
for a in Authenticator.all():
if a.getType().isCustom() is False:
yield { 'auth' : str(a.small_name), 'name' : a.name }
yield {
'auth': str(a.small_name),
'name': a.name
}
def get(self):
return list(self.auths())
class Locale(Handler):
authenticated = True
def get(self):
if len(self._args) > 0:
self.setValue('locale', self._args[1])

View File

@ -4,27 +4,27 @@
# Copyright (c) 2014 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@ -45,17 +45,18 @@ logger = logging.getLogger(__name__)
# Enclosed methods under /item path
class Networks(ModelHandler):
model = Network
save_fields = ['name', 'net_string']
table_title = _('Current Networks')
table_title = _('Current Networks')
table_fields = [
{ 'name': {'title': _('Name'), 'visible': True, 'type': 'icon', 'icon': 'fa fa-globe text-success' } },
{ 'net_string': {'title': _('Range')}},
{ 'networks_count': {'title': _('Used by'), 'type': 'numeric', 'width': '8em'}}
{'name': {'title': _('Name'), 'visible': True, 'type': 'icon', 'icon': 'fa fa-globe text-success'}},
{'net_string': {'title': _('Range')}},
{'networks_count': {'title': _('Used by'), 'type': 'numeric', 'width': '8em'}}
]
def beforeSave(self, fields):
logger.debug('Before {0}'.format(fields))
try:
@ -65,21 +66,21 @@ class Networks(ModelHandler):
except Exception as e:
raise SaveException(ugettext('Invalid network: ') + unicode(e))
logger.debug('Processed {0}'.format(fields))
def getGui(self, type_):
return self.addField(self.addDefaultFields([], ['name']),{
return self.addField(self.addDefaultFields([], ['name']), {
'name': 'net_string',
'value': '',
'label': ugettext('Network range'),
'tooltip': ugettext('Network range. Accepts most network definitions formats (range, subnet, host, etc...'),
'type': gui.InputField.TEXT_TYPE,
'order': 100, # At end
'order': 100, # At end
})
def item_as_dict(self, item):
return { 'id': item.id,
'name': item.name,
'net_string': item.net_string,
'networks_count': item.transports.count(),
return {
'id': item.id,
'name': item.name,
'net_string': item.net_string,
'networks_count': item.transports.count(),
}

View File

@ -4,27 +4,27 @@
# Copyright (c) 2014 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@ -34,7 +34,7 @@ from __future__ import unicode_literals
from django.utils.translation import ugettext, ugettext_lazy as _
from uds.models import Provider, Service, UserService
from services import Services as DetailServices
from services import Services as DetailServices
from uds.core import services
from uds.REST import NotFound, RequestError
@ -47,55 +47,55 @@ logger = logging.getLogger(__name__)
class Providers(ModelHandler):
model = Provider
detail = { 'services': DetailServices }
detail = {'services': DetailServices}
custom_methods = [('allservices', False), ('service', False)]
save_fields = ['name', 'comments']
table_title = _('Service providers')
# Table info fields
table_fields = [
{ 'name': {'title': _('Name'), 'type': 'iconType' } },
{ 'comments': {'title': _('Comments')}},
{ 'services_count': {'title': _('Services'), 'type': 'numeric', 'width': '5em'}},
{ 'user_services_count': {'title': _('User Services'), 'type': 'numeric', 'width': '8em'}},
{'name': {'title': _('Name'), 'type': 'iconType'}},
{'comments': {'title': _('Comments')}},
{'services_count': {'title': _('Services'), 'type': 'numeric', 'width': '5em'}},
{'user_services_count': {'title': _('User Services'), 'type': 'numeric', 'width': '8em'}},
]
def item_as_dict(self, provider):
type_ = provider.getType()
# Icon can have a lot of data (1-2 Kbytes), but it's not expected to have a lot of services providers, and even so, this will work fine
offers = [{
'name' : ugettext(t.name()),
'type' : t.type(),
'description' : ugettext(t.description()),
'icon' : t.icon().replace('\n', '') } for t in type_.getServicesTypes()]
return { 'id': provider.id,
'name': provider.name,
'services_count': provider.services.count(),
'user_services_count': UserService.objects.filter(deployed_service__service__provider=provider).count(),
'offers': offers,
'type': type_.type(),
'comments': provider.comments,
offers = [{
'name': ugettext(t.name()),
'type': t.type(),
'description': ugettext(t.description()),
'icon': t.icon().replace('\n', '')} for t in type_.getServicesTypes()]
return {
'id': provider.id,
'name': provider.name,
'services_count': provider.services.count(),
'user_services_count': UserService.objects.filter(deployed_service__service__provider=provider).count(),
'offers': offers,
'type': type_.type(),
'comments': provider.comments,
}
def checkDelete(self, item):
if item.services.count() > 0:
raise RequestError('Can\'t delete providers with services already associated')
# Types related
def enum_types(self):
return services.factory().providers().values()
# Gui related
def getGui(self, type_):
try:
return self.addDefaultFields(services.factory().lookup(type_).guiDescription(), ['name', 'comments'])
except:
raise NotFound('type not found')
def allservices(self):
for s in Service.objects.all():
@ -103,7 +103,7 @@ class Providers(ModelHandler):
yield DetailServices.serviceToDict(s, True)
except:
logger.exception('Passed service cause type is unknown')
def service(self):
try:
return DetailServices.serviceToDict(Service.objects.get(pk=self._args[1]), True)

View File

@ -4,27 +4,27 @@
# Copyright (c) 2014 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@ -49,16 +49,16 @@ logger = logging.getLogger(__name__)
class Services(DetailHandler):
@staticmethod
def serviceToDict(item, full=False):
retVal = {
'id':item.id,
'name': item.name,
'comments': item.comments,
'type': item.data_type,
'type_name' : _(item.getType().name()),
'deployed_services_count' : item.deployedServices.count(),
retVal = {
'id': item.id,
'name': item.name,
'comments': item.comments,
'type': item.data_type,
'type_name': _(item.getType().name()),
'deployed_services_count': item.deployedServices.count(),
'user_services_count': UserService.objects.filter(deployed_service__service=item).count(),
}
if full:
@ -74,14 +74,14 @@ class Services(DetailHandler):
'needs_manager': info.needsManager,
'must_assign_manually': info.mustAssignManually,
}
return retVal
def getItems(self, parent, item):
# Extract provider
try:
if item is None:
return [Services.serviceToDict(k) for k in parent.services.all() ]
return [Services.serviceToDict(k) for k in parent.services.all()]
else:
k = parent.services.get(pk=item)
val = Services.serviceToDict(k)
@ -89,85 +89,85 @@ class Services(DetailHandler):
except:
logger.exception('getItems')
self.invalidItemException()
def saveItem(self, parent, item):
# Extract item db fields
# We need this fields for all
logger.debug('Saving service {0} / {1}'.format(parent, item))
fields = self.readFieldsFromParams(['name', 'comments', 'data_type'])
try:
if item is None: # Create new
if item is None: # Create new
service = parent.services.create(**fields)
else:
service = parent.services.get(pk=item)
service.__dict__.update(fields)
service.data = service.getInstance(self._params).serialize()
service.save()
except Service.DoesNotExist:
except Service.DoesNotExist:
self.invalidItemException()
except IntegrityError: # Duplicate key probably
except IntegrityError: # Duplicate key probably
raise RequestError('Element already exists (duplicate key error)')
except Exception:
logger.exception('Saving Service')
raise RequestError('incorrect invocation to PUT')
return self.getItems(parent, service.id)
def deleteItem(self, parent, item):
try:
service = parent.services.get(pk=item)
if service.deployedServices.count() != 0:
raise RequestError('Item has associated deployed services')
service.delete()
except:
self.invalidItemException()
return 'deleted'
def getTitle(self, parent):
try:
return _('Services of {0}').format(parent.name)
except:
return _('Current services')
def getFields(self, parent):
return [
{ 'name': {'title': _('Service name'), 'visible': True, 'type': 'iconType' } },
{ 'comments': { 'title': _('Comments') } },
{ 'type_name': {'title': _('Type') } },
{ 'deployed_services_count': {'title': _('Deployed services'), 'type': 'numeric', 'width': '7em'}},
{ 'user_services_count': {'title': _('User services'), 'type': 'numeric', 'width': '7em'}},
{'name': {'title': _('Service name'), 'visible': True, 'type': 'iconType'}},
{'comments': {'title': _('Comments')}},
{'type_name': {'title': _('Type')}},
{'deployed_services_count': {'title': _('Deployed services'), 'type': 'numeric', 'width': '7em'}},
{'user_services_count': {'title': _('User services'), 'type': 'numeric', 'width': '7em'}},
]
def getTypes(self, parent, forType):
logger.debug('getTypes parameters: {0}, {1}'.format(parent, forType))
if forType is None:
offers = [{
'name' : _(t.name()),
'type' : t.type(),
'description' : _(t.description()),
'icon' : t.icon().replace('\n', '') } for t in parent.getType().getServicesTypes()]
offers = [{
'name': _(t.name()),
'type': t.type(),
'description': _(t.description()),
'icon': t.icon().replace('\n', '')} for t in parent.getType().getServicesTypes()]
else:
offers = None # Do we really need to get one specific type?
offers = None # Do we really need to get one specific type?
for t in parent.getType().getServicesTypes():
if forType == t.type():
offers = t
break
if offers is None:
raise NotFound('type not found')
return offers # Default is that details do not have types
return offers # Default is that details do not have types
def getGui(self, parent, forType):
try:
logger.debug('getGui parameters: {0}, {1}'.format(parent, forType))
parentInstance = parent.getInstance()
serviceType = parentInstance.getServiceByType(forType)
service = serviceType( Environment.getTempEnv(), parentInstance) # Instantiate it so it has the opportunity to alter gui description based on parent
return self.addDefaultFields( service.guiDescription(service), ['name', 'comments'])
service = serviceType(Environment.getTempEnv(), parentInstance) # Instantiate it so it has the opportunity to alter gui description based on parent
return self.addDefaultFields(service.guiDescription(service), ['name', 'comments'])
except Exception as e:
logger.exception('getGui')
raise ResponseError(unicode(e))
@ -179,4 +179,3 @@ class Services(DetailHandler):
return log.getLogs(item)
except:
self.invalidItemException()

View File

@ -4,27 +4,27 @@
# Copyright (c) 2014 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@ -48,105 +48,107 @@ import logging
logger = logging.getLogger(__name__)
class ServicesPools(ModelHandler):
model = DeployedService
detail = {
'services': AssignedService,
detail = {
'services': AssignedService,
'cache': CachedService,
'groups': Groups,
'groups': Groups,
'transports': Transports,
'publications': Publications,
}
save_fields = ['name', 'comments', 'service_id', 'osmanager_id', 'initial_srvs', 'cache_l1_srvs', 'cache_l2_srvs', 'max_srvs']
table_title = _('Deployed services')
table_title = _('Deployed services')
table_fields = [
{ 'name': {'title': _('Name') } },
{ 'parent': {'title': _('Parent Service') } }, # Will process this field on client in fact, not sent by server
{ 'state': { 'title': _('state'), 'type': 'dict', 'dict': State.dictionary() } },
{ 'comments': {'title': _('Comments')}},
{'name': {'title': _('Name')}},
{'parent': {'title': _('Parent Service')}}, # Will process this field on client in fact, not sent by server
{'state': {'title': _('state'), 'type': 'dict', 'dict': State.dictionary()}},
{'comments': {'title': _('Comments')}},
]
# Field from where to get "class" and prefix for that class, so this will generate "row-state-A, row-state-X, ....
table_row_style = { 'field': 'state', 'prefix': 'row-state-' }
table_row_style = {'field': 'state', 'prefix': 'row-state-'}
def item_as_dict(self, item):
val = { 'id': item.id,
'name': item.name,
val = {
'id': item.id,
'name': item.name,
'comments': item.comments,
'state' : item.state,
'state': item.state,
'service_id': item.service_id,
'initial_srvs' : item.initial_srvs,
'cache_l1_srvs' : item.cache_l1_srvs,
'cache_l2_srvs' : item.cache_l2_srvs,
'max_srvs' : item.max_srvs,
'initial_srvs': item.initial_srvs,
'cache_l1_srvs': item.cache_l1_srvs,
'cache_l2_srvs': item.cache_l2_srvs,
'max_srvs': item.max_srvs,
'user_services_count': item.userServices.count(),
'restrained': item.isRestrained(),
}
if item.osmanager is not None:
val['osmanager_id'] = item.osmanager.id
return val
# Gui related
def getGui(self, type_):
if OSManager.objects.count() < 1: # No os managers, can't create db
if OSManager.objects.count() < 1: # No os managers, can't create db
raise ResponseError(ugettext('Create at least one OS Manager before creating a new service pool'))
if Service.objects.count() < 1:
raise ResponseError(ugettext('Create at least a service before creating a new service pool'))
g = self.addDefaultFields([], ['name', 'comments'])
for f in [{
'name': 'service_id',
'values': [gui.choiceItem(-1, '')] + [ gui.choiceItem(v.id, v.name) for v in Service.objects.all() ],
'values': [gui.choiceItem(-1, '')] + [gui.choiceItem(v.id, v.name) for v in Service.objects.all()],
'label': ugettext('Base service'),
'tooltip': ugettext('Service used as base of this service pool'),
'type': gui.InputField.CHOICE_TYPE,
'rdonly' : True,
'order': 100, # At end
},{
'rdonly': True,
'order': 100, # At end
}, {
'name': 'osmanager_id',
'values': [gui.choiceItem(-1, '')] + [ gui.choiceItem(v.id, v.name) for v in OSManager.objects.all() ],
'values': [gui.choiceItem(-1, '')] + [gui.choiceItem(v.id, v.name) for v in OSManager.objects.all()],
'label': ugettext('OS Manager'),
'tooltip': ugettext('OS Manager used as base of this service pool'),
'type': gui.InputField.CHOICE_TYPE,
'rdonly' : True,
'order': 101, # At end
},{
'rdonly': True,
'order': 101, # At end
}, {
'name': 'initial_srvs',
'value': '0',
'label': ugettext('Initial available services'),
'tooltip': ugettext('Services created initially for this service pool'),
'type': gui.InputField.NUMERIC_TYPE,
'order': 102, # At end
},{
'order': 102, # At end
}, {
'name': 'cache_l1_srvs',
'value': '0',
'label': ugettext('Services to keep in cache'),
'tooltip': ugettext('Services keeped in cache for improved user service assignation'),
'type': gui.InputField.NUMERIC_TYPE,
'order': 103, # At end
},{
'order': 103, # At end
}, {
'name': 'cache_l2_srvs',
'value': '0',
'label': ugettext('Services to keep in L2 cache'),
'tooltip': ugettext('Services keeped in cache of level2 for improved service generation'),
'type': gui.InputField.NUMERIC_TYPE,
'order': 104, # At end
},{
'order': 104, # At end
}, {
'name': 'max_srvs',
'value': '0',
'label': ugettext('Maximum number of services to provide'),
'tooltip': ugettext('Maximum number of service (assigned and L1 cache) that can be created for this service'),
'type': gui.InputField.NUMERIC_TYPE,
'order': 105, # At end
'order': 105, # At end
}]:
self.addField(g, f)
return g
def beforeSave(self, fields):
logger.debug('Before {0}'.format(fields))
logger.debug(self._args)
@ -157,7 +159,7 @@ class ServicesPools(ModelHandler):
fields['service'] = service
except:
raise RequestError(ugettext('Base service does not exists anymore'))
try:
serviceType = service.getType()
if serviceType.needsManager is True:
@ -166,16 +168,15 @@ class ServicesPools(ModelHandler):
del fields['osmanager_id']
except:
raise RequestError(ugettext('This service requires an os manager'))
except (RequestError, ResponseError):
raise
except Exception as e:
raise RequestError(str(e))
def deleteItem(self, item):
item.remove() # This will mark it for deletion, but in fact will not delete it directly
item.remove() # This will mark it for deletion, but in fact will not delete it directly
# Logs
def getLogs(self, item):
return log.getLogs(item)

View File

@ -4,27 +4,27 @@
# Copyright (c) 2014 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@ -49,7 +49,7 @@ cache = Cache('StatsDispatcher')
# Enclosed methods under /syatem path
POINTS = 365
SINCE = 365 # Days
SINCE = 365 # Days
USE_MAX = True
@ -57,39 +57,38 @@ def getServicesPoolsCounters(servicePool, counter_type):
try:
cacheKey = (servicePool and servicePool.id or 'all') + str(counter_type) + str(POINTS) + str(SINCE)
to = getSqlDatetime()
since = to - timedelta(days=SINCE)
since = to - timedelta(days=SINCE)
val = cache.get(cacheKey)
if val is None:
if servicePool is None:
us = DeployedService()
complete = True # Get all deployed services stats
complete = True # Get all deployed services stats
else:
us = servicePool
complete = False
val = []
for x in counters.getCounters(us, counter_type, since=since, to=to, limit=POINTS, use_max=USE_MAX, all=complete):
val.append({ 'stamp': x[0], 'value': int(x[1]) })
val.append({'stamp': x[0], 'value': int(x[1])})
if len(val) > 2:
cache.put(cacheKey, cPickle.dumps(val).encode('zip'), 600)
else:
val = [{'stamp':since, 'value':0 }, {'stamp':to, 'value':0}]
val = [{'stamp':since, 'value': 0}, {'stamp':to, 'value':0}]
else:
val = cPickle.loads(val.decode('zip'))
return val
except:
logger.exception('exception')
raise ResponseError('can\'t create stats for objects!!!')
class System(Handler):
needs_admin = True # By default, staff is lower level needed
needs_admin = True # By default, staff is lower level needed
def get(self):
logger.debug('args: {0}'.format(self._args))
if len(self._args) == 1:
if self._args[0] == 'overview': # System overview
if self._args[0] == 'overview': # System overview
users = User.objects.count()
services = Service.objects.count()
user_services = UserService.objects.count()
@ -100,16 +99,15 @@ class System(Handler):
'user_services': user_services,
'restrained_services_pools': restrained_services_pools,
}
if len(self._args) == 2:
if self._args[0] == 'stats':
if self._args[1] == 'assigned':
return getServicesPoolsCounters(None, counters.CT_ASSIGNED)
if self._args[1] == 'inuse':
return getServicesPoolsCounters(None, counters.CT_INUSE)
raise RequestError('invalid request')
def put(self):
raise RequestError('todo')

View File

@ -4,27 +4,27 @@
# Copyright (c) 2014 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@ -36,7 +36,6 @@ from django.utils.translation import ugettext_lazy as _, ugettext
from uds.models import Transport, Network
from uds.core.transports import factory
from uds.REST import Handler, NotFound
from uds.REST.model import ModelHandler
import logging
@ -45,21 +44,22 @@ logger = logging.getLogger(__name__)
# Enclosed methods under /item path
class Transports(ModelHandler):
model = Transport
save_fields = ['name', 'comments', 'priority', 'nets_positive']
table_title = _('Current Transports')
table_title = _('Current Transports')
table_fields = [
{ 'priority': {'title': _('Priority'), 'type': 'numeric', 'width': '6em' }},
{ 'name': {'title': _('Name'), 'visible': True, 'type': 'iconType' } },
{ 'comments': {'title': _('Comments')}},
{ 'deployed_count': {'title': _('Used by'), 'type': 'numeric', 'width': '8em'}}
{'priority': {'title': _('Priority'), 'type': 'numeric', 'width': '6em'}},
{'name': {'title': _('Name'), 'visible': True, 'type': 'iconType'}},
{'comments': {'title': _('Comments')}},
{'deployed_count': {'title': _('Used by'), 'type': 'numeric', 'width': '8em'}}
]
def enum_types(self):
return factory().providers().values()
def getGui(self, type_):
try:
return self.addField(self.addField(self.addDefaultFields(factory().lookup(type_).guiDescription(), ['name', 'comments', 'priority']), {
@ -68,11 +68,11 @@ class Transports(ModelHandler):
'label': ugettext('Network access'),
'tooltip': ugettext('If ACTIVE, the transport will be enabled for the selected networks.If INACTIVE, trans port will be disabled for selected networks'),
'type': 'checkbox',
'order': 100, # At end
'order': 100, # At end
}), {
'name': 'networks',
'value': [],
'values': sorted([{'id': x.id, 'text': x.name} for x in Network.objects.all()], key=lambda x: x['text'].lower()), # TODO: We will fix this behavior after current admin client is fully removed
'values': sorted([{'id': x.id, 'text': x.name} for x in Network.objects.all()], key=lambda x: x['text'].lower()), # TODO: We will fix this behavior after current admin client is fully removed
'label': ugettext('Networks'),
'tooltip': ugettext('Networks associated with this transport. If No network selected, will mean "all networks"'),
'type': 'multichoice',
@ -80,24 +80,25 @@ class Transports(ModelHandler):
})
except:
self.invalidItemException()
def item_as_dict(self, item):
type_ = item.getType()
return { 'id': item.id,
'name': item.name,
'comments': item.comments,
'priority': item.priority,
'nets_positive': item.nets_positive,
'networks': [ { 'id': n.id } for n in item.networks.all() ],
'deployed_count': item.deployedServices.count(),
'type': type_.type(),
return {
'id': item.id,
'name': item.name,
'comments': item.comments,
'priority': item.priority,
'nets_positive': item.nets_positive,
'networks': [{'id': n.id} for n in item.networks.all()],
'deployed_count': item.deployedServices.count(),
'type': type_.type(),
}
def afterSave(self, item):
try:
networks = self._params['networks']
except: # No networks passed in, this is ok
except: # No networks passed in, this is ok
return
logger.debug('Params: {0}'.format(networks))
item.networks = Network.objects.filter(id__in=networks)

View File

@ -4,27 +4,27 @@
# Copyright (c) 2012 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@ -45,34 +45,35 @@ import logging
logger = logging.getLogger(__name__)
class AssignedService(DetailHandler):
@staticmethod
def itemToDict(item, is_cache=False):
val = {
'id' : item.id,
'id_deployed_service' : item.deployed_service_id,
'unique_id' : item.unique_id,
'friendly_name' : item.friendly_name,
'state' : item.state,
'os_state': item.os_state,
'state_date' : item.state_date,
'creation_date' : item.creation_date,
'revision' : item.publication and item.publication.revision or '',
'id': item.id,
'id_deployed_service': item.deployed_service_id,
'unique_id': item.unique_id,
'friendly_name': item.friendly_name,
'state': item.state,
'os_state': item.os_state,
'state_date': item.state_date,
'creation_date': item.creation_date,
'revision': item.publication and item.publication.revision or '',
}
if is_cache:
val['cache_level'] = item.cache_level
else:
val.update({
'owner': item.user.manager.name + "-" + item.user.name,
'in_use': item.in_use,
val.update({
'owner': item.user.manager.name + "-" + item.user.name,
'in_use': item.in_use,
'in_use_date': item.in_use_date,
'source_host' : item.src_hostname,
'source_ip': item.src_ip
'source_host': item.src_hostname,
'source_ip': item.src_ip
})
return val
def getItems(self, parent, item):
# Extract provider
try:
@ -83,20 +84,20 @@ class AssignedService(DetailHandler):
except:
logger.exception('getItems')
self.invalidItemException()
def getTitle(self, parent):
return _('Assigned services')
def getFields(self, parent):
return [
{ 'creation_date': { 'title': _('Creation date'), 'type': 'datetime' } },
{ 'revision': { 'title': _('Revision') } },
{ 'unique_id': { 'title': 'Unique ID'} },
{ 'friendly_name': {'title': _('Friendly name')} },
{ 'state': { 'title': _('State'), 'type': 'dict', 'dict': State.dictionary() } },
{ 'owner': { 'title': _('Owner') } },
{'creation_date': {'title': _('Creation date'), 'type': 'datetime'}},
{'revision': {'title': _('Revision')}},
{'unique_id': {'title': 'Unique ID'}},
{'friendly_name': {'title': _('Friendly name')}},
{'state': {'title': _('State'), 'type': 'dict', 'dict': State.dictionary()}},
{'owner': {'title': _('Owner')}},
]
def getLogs(self, parent, item):
try:
item = parent.assignedUserServices().get(pk=item)
@ -104,15 +105,15 @@ class AssignedService(DetailHandler):
return log.getLogs(item)
except:
self.invalidItemException()
class CachedService(AssignedService):
def getItems(self, parent, item):
# Extract provider
try:
if item is None:
return [AssignedService.itemToDict(k, True) for k in parent.cachedUserServices().all() ]
return [AssignedService.itemToDict(k, True) for k in parent.cachedUserServices().all()]
else:
k = parent.cachedUserServices().get(pk=item)
return AssignedService.itemToDict(k, True)
@ -125,12 +126,12 @@ class CachedService(AssignedService):
def getFields(self, parent):
return [
{ 'creation_date': { 'title': _('Creation date'), 'type': 'datetime' } },
{ 'revision': { 'title': _('Revision') } },
{ 'unique_id': { 'title': 'Unique ID'} },
{ 'friendly_name': {'title': _('Friendly name')} },
{ 'state': { 'title': _('State'), 'type': 'dict', 'dict': State.dictionary() } },
{ 'cache_level': { 'title': _('Cache level') } },
{'creation_date': {'title': _('Creation date'), 'type': 'datetime'}},
{'revision': {'title': _('Revision')}},
{'unique_id': {'title': 'Unique ID'}},
{'friendly_name': {'title': _('Friendly name')}},
{'state': {'title': _('State'), 'type': 'dict', 'dict': State.dictionary()}},
{'cache_level': {'title': _('Cache level')}},
]
def getLogs(self, parent, item):
@ -151,25 +152,26 @@ class Groups(DetailHandler):
'type': i.is_meta and 'meta' or 'group',
'auth_name': i.manager.name,
} for i in parent.assignedGroups.all()]
def getTitle(self, parent):
return _('Assigned groups')
def getFields(self, parent):
return [
# Note that this field is "self generated" on client table
{ 'group_name': { 'title': _('Name'), 'type': 'icon_dict', 'icon_dict': {'group' : 'fa fa-group text-success', 'meta' : 'fa fa-gears text-info' } } },
{ 'comments': { 'title': _('comments') } },
{ 'state': { 'title': _('State'), 'type': 'dict', 'dict': State.dictionary() } },
{'group_name': {'title': _('Name'), 'type': 'icon_dict', 'icon_dict': {'group': 'fa fa-group text-success', 'meta': 'fa fa-gears text-info'}}},
{'comments': {'title': _('comments')}},
{'state': {'title': _('State'), 'type': 'dict', 'dict': State.dictionary()}},
]
def saveItem(self, parent, item):
parent.assignedGroups.add(Group.objects.get(pk=self._params['id']))
return self.success()
def deleteItem(self, parent, item):
parent.assignedGroups.remove(Group.objects.get(pk=self._args[0]))
class Transports(DetailHandler):
def getItems(self, parent, item):
return [{
@ -179,42 +181,43 @@ class Transports(DetailHandler):
'comments': i.comments,
'priority': i.priority,
} for i in parent.transports.all()]
def getTitle(self, parent):
return _('Assigned transports')
def getFields(self, parent):
return [
{ 'priority': {'title': _('Priority'), 'type': 'numeric', 'width': '6em' } },
{ 'name': {'title': _('Name')} },
{ 'trans_type': {'title': _('Type') } },
{ 'comments': {'title': _('Comments')}},
{'priority': {'title': _('Priority'), 'type': 'numeric', 'width': '6em'}},
{'name': {'title': _('Name')}},
{'trans_type': {'title': _('Type')}},
{'comments': {'title': _('Comments')}},
]
def saveItem(self, parent, item):
parent.transports.add(Transport.objects.get(pk=self._params['id']))
return self.success()
def deleteItem(self, parent, item):
parent.transports.remove(Transport.objects.get(pk=self._args[0]))
class Publications(DetailHandler):
custom_methods=['publish', 'cancel']
custom_methods = ['publish', 'cancel']
def publish(self, parent):
logger.debug('Custom "publish" invoked')
parent.publish()
return self.success()
def cancel(self, parent, id):
def cancel(self, parent, pk):
try:
ds = DeployedServicePublication.objects.get(pk=id)
ds = DeployedServicePublication.objects.get(pk=pk)
ds.cancel()
except Exception as e:
raise ResponseError(unicode(e))
return self.success()
def getItems(self, parent, item):
return [{
'id': i.id,
@ -224,18 +227,20 @@ class Publications(DetailHandler):
'reason': State.isErrored(i.state) and i.getInstance().reasonOfError() or '',
'state_date': i.state_date,
} for i in parent.publications.all()]
def getTitle(self, parent):
return _('Publications')
def getFields(self, parent):
return [
{ 'revision': {'title': _('Revision'), 'type': 'numeric', 'width': '6em' } },
{ 'publish_date': { 'title': _('Publish date'), 'type': 'datetime' } },
{ 'state': { 'title': _('State'), 'type': 'dict', 'dict': State.dictionary() } },
{ 'reason': {'title': _('Reason')}},
{'revision': {'title': _('Revision'), 'type': 'numeric', 'width': '6em'}},
{'publish_date': {'title': _('Publish date'), 'type': 'datetime'}},
{'state': {'title': _('State'), 'type': 'dict', 'dict': State.dictionary()}},
{'reason': {'title': _('Reason')}},
]
def getRowStyle(self, parent):
return { 'field': 'state', 'prefix': 'row-state-' }
return {
'field': 'state',
'prefix': 'row-state-'
}

View File

@ -3,27 +3,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.
'''
@ -31,7 +31,7 @@
'''
from __future__ import unicode_literals
#import time
# import time
from django.utils.translation import ugettext as _
from django.forms.models import model_to_dict
from uds.core.util.State import State
@ -52,16 +52,17 @@ logger = logging.getLogger(__name__)
# Details of /auth
class Users(DetailHandler):
def getItems(self, parent, item):
# Extract authenticator
try:
if item is None:
return list(parent.users.all().values('id','name','real_name','comments','state','staff_member','is_admin','last_access','parent'))
return list(parent.users.all().values('id', 'name', 'real_name', 'comments', 'state', 'staff_member', 'is_admin', 'last_access', 'parent'))
else:
u = parent.users.get(pk=item)
res = model_to_dict(u, fields = ('id','name','real_name','comments','state','staff_member','is_admin','last_access','parent'))
res = model_to_dict(u, fields=('id', 'name', 'real_name', 'comments', 'state', 'staff_member', 'is_admin', 'last_access', 'parent'))
usr = aUser(u)
res['groups'] = [g.dbGroup().id for g in usr.groups()]
logger.debug('Item: {0}'.format(res))
@ -69,87 +70,88 @@ class Users(DetailHandler):
except:
logger.exception('En users')
self.invalidItemException()
def getTitle(self, parent):
try:
return _('Users of {0}').format(Authenticator.objects.get(pk=self._kwargs['parent_id']).name)
except:
return _('Current users')
def getFields(self, parent):
return [
{ 'name': {'title': _('Username'), 'visible': True, 'type': 'icon', 'icon': 'fa fa-user text-success' } },
{ 'real_name': { 'title': _('Name') } },
{ 'comments': { 'title': _('Comments') } },
{ 'state': { 'title': _('state'), 'type': 'dict', 'dict': State.dictionary() } },
{ 'last_access': { 'title': _('Last access'), 'type': 'datetime' } },
{'name': {'title': _('Username'), 'visible': True, 'type': 'icon', 'icon': 'fa fa-user text-success'}},
{'real_name': {'title': _('Name')}},
{'comments': {'title': _('Comments')}},
{'state': {'title': _('state'), 'type': 'dict', 'dict': State.dictionary()}},
{'last_access': {'title': _('Last access'), 'type': 'datetime'}},
]
def getRowStyle(self, parent):
return { 'field': 'state', 'prefix': 'row-state-' }
return {'field': 'state', 'prefix': 'row-state-'}
def getLogs(self, parent, item):
try:
user = parent.users.get(pk=item)
except:
self.invalidItemException()
return log.getLogs(user)
def saveItem(self, parent, item):
logger.debug('Saving user {0} / {1}'.format(parent, item))
valid_fields = ['name', 'real_name', 'comments', 'state', 'staff_member', 'is_admin']
if self._params.has_key('password'):
if 'password' in self._params:
valid_fields.append('password')
self._params['password'] = cryptoManager().hash(self._params['password'])
fields = self.readFieldsFromParams(valid_fields)
try:
auth = parent.getInstance()
if item is None: # Create new
auth.createUser(fields) # this throws an exception if there is an error (for example, this auth can't create users)
if item is None: # Create new
auth.createUser(fields) # this throws an exception if there is an error (for example, this auth can't create users)
toSave = {}
for k in valid_fields:
toSave[k] = fields[k]
user = parent.users.create(**toSave)
else:
auth.modifyUser(fields) # Notifies authenticator
auth.modifyUser(fields) # Notifies authenticator
toSave = {}
for k in valid_fields:
toSave[k] = fields[k]
user = parent.users.get(pk=item)
user.__dict__.update(toSave)
if auth.isExternalSource == False and user.parent == -1:
groups = self.readFieldsFromParams(['groups'])['groups']
user.groups = Group.objects.filter(id__in=groups)
user.save()
except User.DoesNotExist:
except User.DoesNotExist:
self.invalidItemException()
except IntegrityError: # Duplicate key probably
except IntegrityError: # Duplicate key probably
raise RequestError(_('User already exists (duplicate key error)'))
except AuthenticatorException as e:
raise RequestError(unicode(e))
except Exception:
logger.exception('Saving user')
self.invalidRequestException()
return self.getItems(parent, user.id)
def deleteItem(self, parent, item):
try:
user = parent.users.get(pk=item)
user.delete()
except:
self.invalidItemException()
return 'deleted'
class Groups(DetailHandler):
def getItems(self, parent, item):
# Extract authenticator
try:
@ -177,30 +179,31 @@ class Groups(DetailHandler):
except:
logger.exception('REST groups')
self.invalidItemException()
def getTitle(self, parent):
try:
return _('Groups of {0}').format(Authenticator.objects.get(pk=self._kwargs['parent_id']).name)
except:
return _('Current groups')
def getFields(self, parent):
return [
{ 'name': {'title': _('Group'), 'visible': True, 'type': 'icon_dict', 'icon_dict': {'group' : 'fa fa-group text-success', 'meta' : 'fa fa-gears text-info' } } },
{ 'comments': { 'title': _('Comments') } },
{ 'state': { 'title': _('state'), 'type': 'dict', 'dict': State.dictionary() } },
]
{'name': {'title': _('Group'), 'visible': True, 'type': 'icon_dict', 'icon_dict': {'group': 'fa fa-group text-success', 'meta': 'fa fa-gears text-info'}}},
{'comments': {'title': _('Comments')}},
{'state': {'title': _('state'), 'type': 'dict', 'dict': State.dictionary()}},
]
def getTypes(self, parent, forType):
tDct = {
'group': { 'name': _('Group'), 'description': _('UDS Group') },
'meta' : { 'name': _('Meta group'), 'description': _('UDS Meta Group') },
'group': {'name': _('Group'), 'description': _('UDS Group')},
'meta': {'name': _('Meta group'), 'description': _('UDS Meta Group')},
}
types = [{
'name' : tDct[t]['name'],
'type' : t,
'description' : tDct[t]['description'],
'icon' : '' } for t in tDct.keys()]
types = [{
'name': tDct[t]['name'],
'type': t,
'description': tDct[t]['description'],
'icon': ''
} for t in tDct.keys()]
if forType is None:
return types
else:
@ -216,9 +219,9 @@ class Groups(DetailHandler):
valid_fields = ['name', 'comments', 'state']
fields = self.readFieldsFromParams(valid_fields)
auth = parent.getInstance()
if item is None: # Create new
if item is None: # Create new
if not is_meta:
auth.createGroup(fields) # this throws an exception if there is an error (for example, this auth can't create users)
auth.createGroup(fields) # this throws an exception if there is an error (for example, this auth can't create users)
toSave = {}
for k in valid_fields:
toSave[k] = fields[k]
@ -230,32 +233,32 @@ class Groups(DetailHandler):
toSave = {}
for k in valid_fields:
toSave[k] = fields[k]
del toSave['name'] # Name can't be changed
del toSave['name'] # Name can't be changed
group = parent.groups.get(pk=item)
group.__dict__.update(toSave)
if is_meta:
group.groups = self._params['groups']
group.save()
except Group.DoesNotExist:
except Group.DoesNotExist:
self.invalidItemException()
except IntegrityError: # Duplicate key probably
except IntegrityError: # Duplicate key probably
raise RequestError(_('User already exists (duplicate key error)'))
except AuthenticatorException as e:
raise RequestError(unicode(e))
except Exception:
logger.exception('Saving group')
self.invalidRequestException()
return self.getItems(parent, group.id)
def deleteItem(self, parent, item):
try:
group = parent.groups.get(pk=item)
group.delete()
except:
self.invalidItemException()
return 'deleted'

View File

@ -4,27 +4,27 @@
# Copyright (c) 2014 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@ -37,7 +37,7 @@ from django.utils.translation import ugettext as _
from django.db import IntegrityError
from uds.core.ui.UserInterface import gui as uiGui
from uds.REST.handlers import Handler
from uds.REST.handlers import Handler
from uds.core.util import log
import logging
@ -51,13 +51,15 @@ TABLEINFO = 'tableinfo'
GUI = 'gui'
LOG = 'log'
# Exception to "rethrow" on save error
class SaveException(Exception):
pass
# Base for Gui Related mixins
class BaseModelHandler(Handler):
def addField(self, gui, field):
gui.append({
'name': field.get('name', ''),
@ -77,7 +79,7 @@ class BaseModelHandler(Handler):
}
})
return gui
def addDefaultFields(self, gui, flds):
if 'name' in flds:
self.addField(gui, {
@ -85,38 +87,38 @@ class BaseModelHandler(Handler):
'required': True,
'label': _('Name'),
'tooltip': _('Name of this element'),
'order': -100,
'order':-100,
})
if 'comments' in flds:
self.addField(gui, {
'name': 'comments',
'name': 'comments',
'label': _('Comments'),
'tooltip': _('Comments for this element'),
'length': 256,
'order': -99,
'order':-99,
})
if 'priority' in flds:
self.addField(gui, {
'name': 'priority',
'type': 'numeric',
'type': 'numeric',
'label': _('Priority'),
'tooltip': _('Selects the priority of this element (lower number means higher priority)'),
'required': True,
'value': 1,
'length': 4,
'order': -98,
'order':-98,
})
if 'small_name' in flds:
self.addField(gui, {
'name': 'small_name',
'type': 'text',
'type': 'text',
'label': _('Short name'),
'tooltip': _('Short name of this element'),
'required': True,
'length': 128,
'order': -97,
'order':-97,
})
return gui
def typeInfo(self, type_):
@ -124,16 +126,21 @@ class BaseModelHandler(Handler):
def type_as_dict(self, type_):
res = self.typeInfo(type_)
res.update( { 'name' : _(type_.name()),
'type' : type_.type(),
'description' : _(type_.description()),
'icon' : type_.icon().replace('\n', '')
res.update({
'name': _(type_.name()),
'type': type_.type(),
'description': _(type_.description()),
'icon': type_.icon().replace('\n', '')
})
return res
def processTableFields(self, title, fields, row_style):
return { 'title': unicode(title), 'fields': fields, 'row-style': row_style };
return {
'title': unicode(title),
'fields': fields,
'row-style': row_style
}
def readFieldsFromParams(self, fldList):
args = {}
try:
@ -142,32 +149,33 @@ class BaseModelHandler(Handler):
del self._params[key]
except KeyError as e:
raise RequestError('needed parameter not found in data {0}'.format(unicode(e)))
return args
def fillIntanceFields(self, item, res):
if hasattr(item, 'getInstance'):
for key, value in item.getInstance().valuesDict().iteritems():
if type(value) in (unicode, str):
value = {"true":True, "false":False}.get(value, value) # Translate "true" & "false" to True & False (booleans)
value = {"true": True, "false": False}.get(value, value) # Translate "true" & "false" to True & False (booleans)
logger.debug('{0} = {1}'.format(key, value))
res[key] = value
return res
# Exceptions
def invalidRequestException(self):
raise RequestError(_('Invalid Request'))
def invalidMethodException(self):
raise NotFound(_('Method not found'))
def invalidItemException(self):
raise NotFound(_('Item not found'))
# Success methods
def success(self):
return 'done'
# Details do not have types at all
# so, right now, we only process details petitions for Handling & tables info
class DetailHandler(BaseModelHandler):
@ -177,7 +185,7 @@ class DetailHandler(BaseModelHandler):
Urls recognized for GET are:
[path] --> get Items (all hopefully, this call is delegated to getItems)
[path]/overview
[path]/ID
[path]/ID
[path]/gui
[path]/gui/TYPE
[path]/types
@ -188,17 +196,17 @@ class DetailHandler(BaseModelHandler):
[path]/ID --> Modify existing item
For DELETE:
[path]/ID
Also accepts GET methods for "custom" methods
Also accepts GET methods for "custom" methods
'''
def __init__(self, parentHandler, path, params, *args, **kwargs):
self._parent = parentHandler
self._path = path
self._params = params
self._args = args
self._kwargs = kwargs
def __checkCustom(self, check, parent, arg=None):
logger.debug('Checking custom method {0}'.format(check))
for cm in self.custom_methods:
@ -207,7 +215,7 @@ class DetailHandler(BaseModelHandler):
operation = getattr(self, cm)
except:
self.invalidMethodException()
if arg is None:
return operation(parent)
else:
@ -220,12 +228,12 @@ class DetailHandler(BaseModelHandler):
nArgs = len(self._args)
parent = self._kwargs['parent']
if nArgs == 0:
return self.getItems(parent, None)
return self.getItems(parent, None)
# if has custom methods, look for if this request matches any of them
r = self.__checkCustom(self._args[0], parent)
if r is not None:
return r
return r
if nArgs == 1:
if self._args[0] == OVERVIEW:
@ -237,14 +245,14 @@ class DetailHandler(BaseModelHandler):
return self.getTypes(parent, None)
elif self._args[0] == TABLEINFO:
return self.processTableFields(self.getTitle(parent), self.getFields(parent), self.getRowStyle(parent))
# try to get id
return self.getItems(parent, self._args[0])
if nArgs == 2:
if self._args[0] == GUI:
gui = self.getGui(parent, self._args[1])
return sorted(gui, key=lambda f: f['gui']['order'])
return sorted(gui, key=lambda f: f['gui']['order'])
elif self._args[0] == TYPES:
return self.getTypes(parent, self._args[1])
elif self._args[1] == LOG:
@ -252,19 +260,18 @@ class DetailHandler(BaseModelHandler):
else:
r = self.__checkCustom(self._args[1], parent, self._args[0])
if r is not None:
return r
return r
return self.fallbackGet()
def put(self):
'''
Put is delegated to specific implementation
'''
logger.debug("Detail args for PUT: {0}, {1}".format(self._args, self._params))
parent = self._kwargs['parent']
if len(self._args) == 0:
# Create new
item = None
@ -272,80 +279,81 @@ class DetailHandler(BaseModelHandler):
item = self._args[0]
else:
self.invalidRequestException()
return self.saveItem(parent, item)
def post(self):
'''
Post will be used for, for example, testing
Post will be used for, for example, testing
'''
raise NotFound('TODO: do it :-)')
def delete(self):
'''
Put is delegated to specific implementation
'''
logger.debug("Detail args for DELETE: {0}".format(self._args))
parent = self._kwargs['parent']
if len(self._args) != 1:
self.invalidRequestException()
return self.deleteItem(parent, self._args[0])
# Invoked if default get can't process request
def fallbackGet(self):
raise self.invalidRequestException()
# Override this to provide functionality
# Default (as sample) getItems
def getItems(self, parent, item):
if item is None: # Returns ALL detail items
if item is None: # Returns ALL detail items
return []
return {} # Returns one item
return {} # Returns one item
# Default save
def saveItem(self, parent, item):
logger.debug('Default saveItem handler caller for {0}'.format(self._path))
self.invalidRequestException()
# Default delete
def deleteItem(self, parent, item):
self.invalidRequestException()
# A detail handler must also return title & fields for tables
def getTitle(self, parent):
return ''
def getFields(self, parent):
return []
def getRowStyle(self, parent):
return {}
def getGui(self, parent, forType):
raise RequestError('Gui not provided for this type of object')
def getTypes(self, parent, forType):
return [] # Default is that details do not have types
return [] # Default is that details do not have types
def getLogs(self, parent, item):
self.invalidMethodException()
class ModelHandler(BaseModelHandler):
'''
Basic Handler for a model
Basically we will need same operations for all models, so we can
take advantage of this fact to not repeat same code again and again...
Urls treated are:
[path] --> Returns all elements for this path (including INSTANCE variables if it has it). (example: .../providers)
[path]/overview --> Returns all elements for this path, not including INSTANCE variables. (example: .../providers/overview)
[path]/ID --> Returns an exact element for this path. (example: .../providers/4)
[path/ID/DETAIL --> Delegates to Detail, if it has details. (example: .../providers/4/services/overview, .../providers/5/services/9/gui, ....
Note: Instance variables are the variables declared and serialized by modules.
[path/ID/DETAIL --> Delegates to Detail, if it has details. (example: .../providers/4/services/overview, .../providers/5/services/9/gui, ....
Note: Instance variables are the variables declared and serialized by modules.
The only detail that has types within is "Service", child of "Provider"
'''
# Authentication related
@ -353,75 +361,75 @@ class ModelHandler(BaseModelHandler):
needs_staff = True
# Which model does this manage
model = None
custom_methods = [] # If this model respond to "custom" methods, we will declare them here
custom_methods = [] # If this model respond to "custom" methods, we will declare them here
# This is an array of tuples of two items, where first is method and second inticates if method needs parent id
# For example ('services', True) -- > .../id_parent/services
# ('services', False) --> ..../services
# ('services', False) --> ..../services
# If this model has details, which ones
detail = None # Dictionary containing detail routing
detail = None # Dictionary containing detail routing
# Put needed fields
save_fields = []
# Table info needed fields and title
table_fields = []
table_row_style = {}
table_title = ''
# This methods must be override, depending on what is provided
# Data related
def item_as_dict(self, item):
pass
# types related
def enum_types(self): # override this
def enum_types(self): # override this
return []
def getTypes(self, *args, **kwargs):
for type_ in self.enum_types():
yield self.type_as_dict(type_)
def getType(self, type_):
found = None
for v in self.getTypes():
if v['type'] == type_:
found = v
break
if found is None:
raise NotFound('type not found')
logger.debug('Found type {0}'.format(v))
return found
# log related
def getLogs(self, item):
logger.debug('Default getLogs invoked')
return log.getLogs(item)
# gui related
def getGui(self, type_):
self.invalidRequestException()
# Delete related, checks if the item can be deleted
# If it can't be so, raises an exception
def checkDelete(self, item):
pass
# Save related, checks if the item can be saved
# If it can't be saved, raises an exception
def checkSave(self, item):
pass
# Invoked to possibily fix fields (or add new one, or check
def beforeSave(self, fields):
pass
# Invoked right after saved an item (no matter if new or edition)
def afterSave(self, item):
pass
# End overridable
# End overridable
# Helper to process detail
def processDetail(self):
logger.debug('Processing detail {0}'.format(self._path))
@ -430,22 +438,22 @@ class ModelHandler(BaseModelHandler):
detailCls = self.detail[self._args[1]]
args = list(self._args[2:])
path = self._path + '/'.join(args[:2])
detail = detailCls(self, path, self._params, *args, parent = item)
detail = detailCls(self, path, self._params, *args, parent=item)
method = getattr(detail, self._operation)
except KeyError:
self.invalidMethodException()
except AttributeError:
self.invalidMethodException()
return method()
def getItems(self, *args, **kwargs):
for item in self.model.objects.filter(*args, **kwargs):
try:
try:
yield self.item_as_dict(item)
except:
logger.exception('Exception getting item from {0}'.format(self.model))
def get(self):
logger.debug('method GET for {0}, {1}'.format(self.__class__.__name__, self._args))
nArgs = len(self._args)
@ -456,26 +464,26 @@ class ModelHandler(BaseModelHandler):
self.fillIntanceFields(val, res)
result.append(res)
return result
# if has custom methods, look for if this request matches any of them
for cm in self.custom_methods:
if nArgs > 1 and cm[1] is True: # Method needs parent (existing item)
if self._args[1] == cm[0]:
if nArgs > 1 and cm[1] is True: # Method needs parent (existing item)
if self._args[1] == cm[0]:
try:
operation = getattr(self, self._args[1])
item = self.model.objects.get(pk=self._args[0])
except:
self.invalidMethodException()
return operation(item)
elif self._args[0] == cm[0]:
try:
operation = getattr(self, self._args[0])
except:
self.invalidMethodException()
return operation()
if nArgs == 1:
if self._args[0] == OVERVIEW:
return list(self.getItems())
@ -485,7 +493,7 @@ class ModelHandler(BaseModelHandler):
return self.processTableFields(self.table_title, self.table_fields, self.table_row_style)
elif self._args[0] == GUI:
return self.getGui(None)
# get item ID
try:
val = self.model.objects.get(pk=self._args[0])
@ -494,9 +502,9 @@ class ModelHandler(BaseModelHandler):
return res
except:
self.invalidItemException()
# nArgs > 1
# Request type info or gui, or detail
# Request type info or gui, or detail
if self._args[0] == TYPES:
if nArgs != 2:
self.invalidRequestException()
@ -504,7 +512,7 @@ class ModelHandler(BaseModelHandler):
elif self._args[0] == GUI:
if nArgs != 2:
self.invalidRequestException()
gui = self.getGui(self._args[1])
gui = self.getGui(self._args[1])
return sorted(gui, key=lambda f: f['gui']['order'])
elif self._args[1] == LOG:
if nArgs != 2:
@ -515,41 +523,41 @@ class ModelHandler(BaseModelHandler):
self.invalidItemException()
return self.getLogs(item)
# If has detail and is requesting detail
# If has detail and is requesting detail
if self.detail is not None:
return self.processDetail()
self.invalidRequestException()
def post(self):
# right now
# right now
logger.debug('method POST for {0}, {1}'.format(self.__class__.__name__, self._args))
if len(self._args) == 2:
if self._args[0] == 'test':
return 'tested'
self.invalidMethodException()
def put(self):
logger.debug('method PUT for {0}, {1}'.format(self.__class__.__name__, self._args))
if len(self._args) > 1: # Detail?
if len(self._args) > 1: # Detail?
return self.processDetail()
try:
# Extract fields
args = self.readFieldsFromParams(self.save_fields)
self.beforeSave(args)
deleteOnError = False
if len(self._args) == 0: # create new
if len(self._args) == 0: # create new
item = self.model.objects.create(**args)
deleteOnError = True
else: # Must have 1 arg
else: # Must have 1 arg
# We have to take care with this case, update will efectively update records on db
item = self.model.objects.get(pk=self._args[0]);
item.__dict__.update(args) # Update fields from args
except self.model.DoesNotExist:
item = self.model.objects.get(pk=self._args[0])
item.__dict__.update(args) # Update fields from args
except self.model.DoesNotExist:
raise NotFound('Item not found')
except IntegrityError: # Duplicate key probably
except IntegrityError: # Duplicate key probably
raise RequestError('Element already exists (duplicate key error)')
except SaveException as e:
raise RequestError(unicode(e))
@ -559,44 +567,43 @@ class ModelHandler(BaseModelHandler):
logger.exception('Exception on put')
raise RequestError('incorrect invocation to PUT')
if not deleteOnError:
self.checkSave(item) # Will raise an exception if item can't be saved (only for modify operations..)
if not deleteOnError:
self.checkSave(item) # Will raise an exception if item can't be saved (only for modify operations..)
# Store associated object if needed
try:
if self._params.has_key('data_type'): # Needs to store instance
if 'data_type' in self._params: # Needs to store instance
item.data_type = self._params['data_type']
item.data = item.getInstance(self._params).serialize()
item.save()
res = self.item_as_dict(item)
self.fillIntanceFields(item, res)
except:
if deleteOnError:
item.delete()
raise
self.afterSave(item)
return res
return res
def delete(self):
logger.debug('method DELETE for {0}, {1}'.format(self.__class__.__name__, self._args))
if len(self._args) > 1:
if len(self._args) > 1:
return self.processDetail()
if len(self._args) != 1:
raise RequestError('Delete need one and only one argument')
try:
item = self.model.objects.get(pk=self._args[0]);
item = self.model.objects.get(pk=self._args[0])
self.checkDelete(item)
self.deleteItem(item)
except self.model.DoesNotExist:
raise NotFound('Element do not exists')
return 'deleted'
def deleteItem(self, item):
item.delete()

View File

@ -193,7 +193,7 @@ class PublicationManager(object):
@transaction.atomic
def cancel(self, dsp):
dsp = DeployedServicePublication.objects.select_for_update().get(id=dsp.id)
dsp = DeployedServicePublication.objects.select_for_update().get(pk=dsp.id)
if dsp.state not in State.PUBLISH_STATES:
raise PublishException(_('Can\'t cancel non running publication'))

View File

@ -298,7 +298,7 @@ class UserServiceManager(object):
Cancels a user service creation
@return: the Uservice canceling
'''
uService = UserService.objects.select_for_update().get(id=uService.id)
uService = UserService.objects.select_for_update().get(pk=uService.id)
logger.debug('Canceling uService {0} creation'.format(uService))
if uService.isPreparing() == False:
logger.INFO(_('Cancel requested for a non running operation, doing remove instead'))

View File

@ -8,6 +8,7 @@
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
import logging
@ -17,29 +18,30 @@ Service modules for uds are contained inside this package.
To create a new service module, you will need to follow this steps:
1.- Create the service module, probably based on an existing one
2.- Insert the module package as child of this package
3.- Import the class of your service module at __init__. For example::
from Service import SimpleService
3.- Import the class of your service module at __init__. For example::
from Service import SimpleService
4.- Done. At Server restart, the module will be recognized, loaded and treated
The registration of modules is done locating subclases of :py:class:`uds.core.auths.Authentication`
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
'''
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
# Dinamycally import children of this package. The __init__.py files must register, if needed, inside ServiceProviderFactory
pkgpath = os.path.dirname(sys.modules[__name__].__file__)
for _, name, _ in pkgutil.iter_modules([pkgpath]):
__import__(name, globals(), locals(), [], -1)
logger.debug('Dispatchers initialized')
__init__()

View File

@ -4,30 +4,29 @@
# 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
'''

View File

@ -4,35 +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.conf.urls import patterns
urlpatterns = patterns(__package__,
(r'^guacamole/(?P<tunnelId>.+)$', 'views.guacamole'),
)

View File

@ -4,33 +4,32 @@
# 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 django.http import HttpResponse
@ -46,26 +45,28 @@ CONTENT_TYPE = 'text/plain'
# We will use the cache to "hold" the tickets valid for users
def dict2resp(dct):
return '\r'.join(( k + '\t' + v for k, v in dct.iteritems()))
return '\r'.join((k + '\t' + v for k, v in dct.iteritems()))
@auth.trustedSourceRequired
def guacamole(request, tunnelId):
logger.debug('Received credentials request for tunnel id {0}'.format(tunnelId))
try:
try:
cache = Cache('guacamole')
val = cache.get(tunnelId, None)
# Remove key from cache, just 1 use
# Cache has a limit lifetime, so we will allow to "reload" the page
# cache.remove(tunnelId)
#response = 'protocol\trdp\rhostname\tw7adolfo\rusername\tadmin\rpassword\ttemporal'
# Cache has a limit lifetime, so we will allow to "reload" the page
# cache.remove(tunnelId)
# response = 'protocol\trdp\rhostname\tw7adolfo\rusername\tadmin\rpassword\ttemporal'
response = dict2resp(val)
except:
return HttpResponse(ERROR, content_type=CONTENT_TYPE)
return HttpResponse(response, content_type=CONTENT_TYPE)

View File

@ -4,36 +4,36 @@
# 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.conf.urls import patterns
urlpatterns = patterns(__package__,
(r'^pam$', 'views.pam'),
)

View File

@ -4,32 +4,33 @@
# Copyright (c) 2012 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from django.http import HttpResponseNotAllowed, HttpResponse
from uds.core.util.Cache import Cache
@ -40,27 +41,28 @@ logger = logging.getLogger(__name__)
# We will use the cache to "hold" the tickets valid for users
@auth.trustedSourceRequired
def pam(request):
response = ''
cache = Cache('pam')
if request.method == 'POST':
return HttpResponseNotAllowed(['GET'])
if request.GET.has_key('id') & request.GET.has_key('pass'):
if 'id' in request.GET and 'pass' in request.GET:
# This is an "auth" request
logger.debug("Auth request for user [{0}] and pass [{1}]".format(request.GET['id'], request.GET['pass']))
password = cache.get(request.GET['id'])
response = '0'
if password == request.GET['pass']:
response = '1'
cache.remove(request.GET['id']) # Ticket valid for just 1 login
elif request.GET.has_key('uid'):
cache.remove(request.GET['id']) # Ticket valid for just 1 login
elif 'uid' in request.GET:
# This is an "get name for id" call
logger.debug("NSS Request for id [{0}]".format(request.GET['uid']))
response = '10000 udstmp'
elif request.GET.has_key('name'):
elif 'name' in request.GET:
logger.debug("NSS Request for username [{0}]".format(request.GET['name']))
response = '10000 udstmp'
return HttpResponse(response, content_type='text/plain')

View File

@ -4,32 +4,33 @@
# Copyright (c) 2012 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from django.core.management.base import BaseCommand
from uds.core.util.Config import Config, GLOBAL_SECTION
@ -37,6 +38,7 @@ import logging
logger = logging.getLogger(__name__)
class Command(BaseCommand):
args = "<mod.name=value mod.name=value mod.name=value...>"
help = "Updates configuration values. If mod is omitted, UDS will be used. Omit whitespaces betwen name, =, and value (they must be a single param)"
@ -55,4 +57,3 @@ class Command(BaseCommand):
Config.update(mod, name, value)
except Exception:
logger.exception("Error")

View File

@ -4,51 +4,59 @@
# 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.core.management.base import BaseCommand, CommandError
from optparse import make_option
from server.settings import SITE_ROOT, LOGDIR
from django.conf import settings
from django.utils.daemonize import become_daemon
from uds.core.managers.TaskManager import TaskManager
import logging, sys, os, signal, time
import logging
import sys
import os
import signal
import time
logger = logging.getLogger(__name__)
PID_FILE = 'taskmanager.pid'
def getPidFile():
return SITE_ROOT + '/' + PID_FILE
return settings.SITE_ROOT + '/' + PID_FILE
class Command(BaseCommand):
args = "None"
help = "Executes the task manager as a daemon. No parameter show current status of task manager"
option_list = BaseCommand.option_list + (
make_option('--start',
action='store_true',
@ -61,35 +69,35 @@ class Command(BaseCommand):
default=False,
help='Stop any running daemon'),
)
def handle(self, *args, **options):
logger.info("Running task manager command")
start = options['start'] and True or False
stop = options['stop'] and True or False
pid = None
try:
pid = int(file(getPidFile(), 'r').readline())
except Exception:
pid = None
if stop is True and pid is not None:
try:
logger.info('Stopping task manager. pid: {0}'.format(pid))
os.kill( pid, signal.SIGTERM )
os.kill(pid, signal.SIGTERM)
time.sleep(1) # Wait a bit before running new one
os.unlink(getPidFile())
except Exception:
logger.error("Could not stop task manager (maybe it's not runing?)")
os.unlink(getPidFile())
if start is True:
logger.info('Starting task manager.')
become_daemon(SITE_ROOT, LOGDIR + '/taskManagerStdout.log', LOGDIR + '/taskManagerStderr.log')
become_daemon(settings.SITE_ROOT, settings.LOGDIR + '/taskManagerStdout.log', settings.LOGDIR + '/taskManagerStderr.log')
pid = str(os.getpid())
file(getPidFile() ,'w+').write("%s\n" % pid)
file(getPidFile(), 'w+').write("%s\n" % pid)
manager = TaskManager()
manager.run()
@ -98,4 +106,3 @@ class Command(BaseCommand):
sys.stdout.write("Task manager found running (pid file exists: {0})\n".format(pid))
else:
sys.stdout.write("Task manager not foud (pid file do not exits)\n")

View File

@ -1,23 +1,24 @@
# encoding: utf-8
# @PydevCodeAnalysisIgnore
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Removing unique constraint on 'UserPreference', fields ['name', 'module']
db.delete_unique('uds_userpreference', ['name', 'module'])
def backwards(self, orm):
# Adding unique constraint on 'UserPreference', fields ['name', 'module']
db.create_unique('uds_userpreference', ['name', 'module'])
models = {
'uds.authenticator': {
'Meta': {'object_name': 'Authenticator'},
@ -196,5 +197,5 @@ class Migration(SchemaMigration):
'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'userServices'", 'null': 'True', 'blank': 'True', 'to': "orm['uds.User']"})
}
}
complete_apps = ['uds']

View File

@ -1,23 +1,24 @@
# encoding: utf-8
# @PydevCodeAnalysisIgnore
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Deleting field 'DeployedService.authenticator'
db.delete_column('uds__deployed_service', 'authenticator_id')
def backwards(self, orm):
# Adding field 'DeployedService.authenticator'
db.add_column('uds__deployed_service', 'authenticator', self.gf('django.db.models.fields.related.ForeignKey')(related_name='deployedServices', null=True, to=orm['uds.Authenticator'], blank=True), keep_default=False)
models = {
'uds.authenticator': {
'Meta': {'object_name': 'Authenticator'},
@ -195,5 +196,5 @@ class Migration(SchemaMigration):
'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'userServices'", 'null': 'True', 'blank': 'True', 'to': "orm['uds.User']"})
}
}
complete_apps = ['uds']

View File

@ -1,23 +1,24 @@
# encoding: utf-8
# @PydevCodeAnalysisIgnore
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'DeployedService.state_date'
db.add_column('uds__deployed_service', 'state_date', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(1972, 7, 1, 0, 0)), keep_default=False)
def backwards(self, orm):
# Deleting field 'DeployedService.state_date'
db.delete_column('uds__deployed_service', 'state_date')
models = {
'uds.authenticator': {
'Meta': {'object_name': 'Authenticator'},
@ -196,5 +197,5 @@ class Migration(SchemaMigration):
'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'userServices'", 'null': 'True', 'blank': 'True', 'to': "orm['uds.User']"})
}
}
complete_apps = ['uds']

View File

@ -1,23 +1,24 @@
# encoding: utf-8
# @PydevCodeAnalysisIgnore
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Config.crypt'
db.add_column('uds_configuration', 'crypt', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)
def backwards(self, orm):
# Deleting field 'Config.crypt'
db.delete_column('uds_configuration', 'crypt')
models = {
'uds.authenticator': {
'Meta': {'object_name': 'Authenticator'},
@ -197,5 +198,5 @@ class Migration(SchemaMigration):
'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'userServices'", 'null': 'True', 'blank': 'True', 'to': "orm['uds.User']"})
}
}
complete_apps = ['uds']

View File

@ -1,23 +1,24 @@
# encoding: utf-8
# @PydevCodeAnalysisIgnore
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'Storage.data'
db.alter_column('uds_storage', 'data', self.gf('django.db.models.fields.TextField')())
def backwards(self, orm):
# Changing field 'Storage.data'
db.alter_column('uds_storage', 'data', self.gf('django.db.models.fields.CharField')(max_length=1024))
models = {
'uds.authenticator': {
'Meta': {'object_name': 'Authenticator'},
@ -197,5 +198,5 @@ class Migration(SchemaMigration):
'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'userServices'", 'null': 'True', 'blank': 'True', 'to': "orm['uds.User']"})
}
}
complete_apps = ['uds']

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# @PydevCodeAnalysisIgnore
import datetime
from south.db import db
from south.v2 import SchemaMigration
@ -200,4 +201,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['uds']
complete_apps = ['uds']

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# @PydevCodeAnalysisIgnore
import datetime
from south.db import db
from south.v2 import SchemaMigration
@ -233,4 +234,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['uds']
complete_apps = ['uds']

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# @PydevCodeAnalysisIgnore
import datetime
from south.db import db
from south.v2 import SchemaMigration
@ -215,4 +216,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['uds']
complete_apps = ['uds']

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# @PydevCodeAnalysisIgnore
import datetime
from south.db import db
from south.v2 import SchemaMigration
@ -212,4 +213,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['uds']
complete_apps = ['uds']

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# @PydevCodeAnalysisIgnore
import datetime
from south.db import db
from south.v2 import SchemaMigration
@ -43,7 +44,7 @@ class Migration(SchemaMigration):
# Adding index on 'Config', fields ['key']
db.create_index('uds_configuration', ['key'])
from uds.models import Config
try:
Config.objects.get(section='UDS', key='maxRemovinggServices').delete()
@ -284,4 +285,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['uds']
complete_apps = ['uds']

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# @PydevCodeAnalysisIgnore
import datetime
from south.db import db
from south.v2 import SchemaMigration
@ -235,4 +236,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['uds']
complete_apps = ['uds']

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# @PydevCodeAnalysisIgnore
import datetime
from south.db import db
from south.v2 import SchemaMigration
@ -255,4 +256,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['uds']
complete_apps = ['uds']

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# @PydevCodeAnalysisIgnore
import datetime
from south.db import db
from south.v2 import SchemaMigration
@ -240,4 +241,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['uds']
complete_apps = ['uds']

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# @PydevCodeAnalysisIgnore
import datetime
from south.db import db
from south.v2 import SchemaMigration
@ -235,4 +236,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['uds']
complete_apps = ['uds']

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# @PydevCodeAnalysisIgnore
import datetime
from south.db import db
from south.v2 import SchemaMigration
@ -236,4 +237,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['uds']
complete_apps = ['uds']

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# @PydevCodeAnalysisIgnore
import datetime
from south.db import db
from south.v2 import SchemaMigration
@ -232,4 +233,4 @@ class Migration(SchemaMigration):
}
}
complete_apps = ['uds']
complete_apps = ['uds']

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# @PydevCodeAnalysisIgnore
import datetime
from south.db import db
from south.v2 import DataMigration
@ -12,15 +13,15 @@ class Migration(DataMigration):
def forwards(self, orm):
"Write your forwards methods here."
# Note: Don't use "from appname.models import ModelName".
# Note: Don't use "from appname.models import ModelName".
# Use orm.ModelName to refer to models in this application,
# and orm['appname.ModelName'] for models in other applications.
if not db.dry_run:
# Remove existing secirity values if they exists before "migrating" global ones
for k in configKeys:
try:
o = orm.Config.objects.get(section=GLOBAL_SECTION,key=k)
orm.Config.objects.filter(section=SECURITY_SECTION,key=k).delete()
o = orm.Config.objects.get(section=GLOBAL_SECTION, key=k)
orm.Config.objects.filter(section=SECURITY_SECTION, key=k).delete()
o.section = SECURITY_SECTION
o.save()
except:
@ -31,8 +32,8 @@ class Migration(DataMigration):
if not db.dry_run:
for k in configKeys:
try:
o = orm.Config.objects.get(section=SECURITY_SECTION,key=k)
orm.Config.objects.filter(section=GLOBAL_SECTION,key=k).delete()
o = orm.Config.objects.get(section=SECURITY_SECTION, key=k)
orm.Config.objects.filter(section=GLOBAL_SECTION, key=k).delete()
o.section = GLOBAL_SECTION
o.save()
except:

View File

@ -7,21 +7,22 @@ import logging
logger = logging.getLogger(__name__)
# Ensure tables that needs to be in InnoDB are so
def modify_MySQL_storage(*args, **kwargs):
from django.db import connection
cursor = connection.cursor()
logger.info('Converting tables')
innoDbTables = ( models.UserService, models.DeployedService, models.DeployedServicePublication,
innoDbTables = (models.UserService, models.DeployedService, models.DeployedServicePublication,
models.Scheduler, models.DelayedTask, models.User, models.Group, models.Authenticator,
models.Service, models.Provider, models.Storage)
for model in innoDbTables:
db_table=model._meta.db_table
stmt = 'ALTER TABLE %s ENGINE=%s' % (db_table,'InnoDB')
db_table = model._meta.db_table
stmt = 'ALTER TABLE %s ENGINE=%s' % (db_table, 'InnoDB')
cursor.execute(stmt)
# sets charset to utf8
stmt = 'ALTER TABLE %s CHARACTER SET \'utf8\' COLLATE \'utf8_general_ci\'' % db_table
cursor.execute(stmt)
#signals.post_migrate.connect(modify_MySQL_storage)
# signals.post_migrate.connect(modify_MySQL_storage)

View File

@ -4,32 +4,33 @@
# Copyright (c) 2012 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from django.utils.translation import ugettext_noop as _
from uds.core.ui.UserInterface import gui
@ -41,46 +42,51 @@ from uds.core.managers.UserServiceManager import UserServiceManager
logger = logging.getLogger(__name__)
class LinuxOsManager(osmanagers.OSManager):
typeName = _('Linux OS Manager')
typeType = 'LinuxManager'
typeDescription = _('Os Manager to control linux virtual machines (basically renames machine and notify state)')
iconFile = 'losmanager.png'
onLogout = gui.ChoiceField( label = _('On Logout'), order = 10, rdonly = False, tooltip = _('What to do when user logout from service'),
values = [ {'id' : 'keep', 'text' : _('Keep service assigned') },
{'id' : 'remove', 'text' : _('Remove service') }
], defvalue = 'keep' )
onLogout = gui.ChoiceField(
label=_('On Logout'),
order=10,
rdonly=False,
tooltip=_('What to do when user logout from service'),
values=[
{'id': 'keep', 'text': _('Keep service assigned')},
{'id': 'remove', 'text': _('Remove service')}
],
defvalue='keep')
def __setProcessUnusedMachines(self):
self.processUnusedMachines = self._onLogout == 'remove'
def __init__(self,environment, values):
def __init__(self, environment, values):
super(LinuxOsManager, self).__init__(environment, values)
if values is not None:
self._onLogout = values['onLogout']
else:
self._onLogout = ''
self.__setProcessUnusedMachines()
self.__setProcessUnusedMachines()
def release(self, service):
pass
def getName(self, service):
'''
gets name from deployed
'''
return service.getName()
def infoVal(self,service):
def infoVal(self, service):
return 'rename:' + self.getName(service)
def infoValue(self,service):
def infoValue(self, service):
return 'rename\r' + self.getName(service)
def notifyIp(self, uid, si, data):
# Notifies IP to deployed
pairs = data.split(',')
@ -89,14 +95,14 @@ class LinuxOsManager(osmanagers.OSManager):
if key.lower() == uid.lower():
si.setIp(val)
break
def process(self,service,msg, data):
def process(self, service, msg, data):
'''
We understand this messages:
* msg = info, data = None. Get information about name of machine (or domain, in derived WinDomainOsManager class), old method
* msg = information, data = None. Get information about name of machine (or domain, in derived WinDomainOsManager class), new method
* msg = logon, data = Username, Informs that the username has logged in inside the machine
* msg = logoff, data = Username, Informs that the username has logged out of the machine
* msg = logoff, data = Username, Informs that the username has logged out of the machine
* msg = ready, data = None, Informs machine ready to be used
'''
logger.info("Invoked LinuxOsManager for {0} with params: {1},{2}".format(service, msg, data))
@ -106,7 +112,7 @@ class LinuxOsManager(osmanagers.OSManager):
notifyReady = False
doRemove = False
state = service.os_state
# Old "info" state, will be removed in a near future
if msg == "info":
ret = self.infoVal(service)
@ -137,10 +143,10 @@ class LinuxOsManager(osmanagers.OSManager):
notifyReady = True
self.notifyIp(service.unique_id, si, data)
service.updateData(si)
service.setInUse(inUse)
service.setOsState(state)
# If notifyReady is not true, save state, let UserServiceManager do it for us else
if doRemove is True:
service.remove()
@ -151,7 +157,7 @@ class LinuxOsManager(osmanagers.OSManager):
UserServiceManager.manager().notifyReadyFromOsManager(service, '')
logger.debug('Returning {0}'.format(ret))
return ret
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
@ -159,9 +165,8 @@ class LinuxOsManager(osmanagers.OSManager):
'''
if self._onLogout == 'remove':
userService.remove()
def checkState(self,service):
def checkState(self, service):
logger.debug('Checking state for service {0}'.format(service))
return State.RUNNING
@ -169,13 +174,13 @@ class LinuxOsManager(osmanagers.OSManager):
'''
Serializes the os manager data so we can store it in database
'''
return str.join( '\t', [ 'v1', self._onLogout ] )
return str.join('\t', ['v1', self._onLogout])
def unmarshal(self, s):
data = s.split('\t')
if data[0] == 'v1':
self._onLogout = data[1]
self.__setProcessUnusedMachines()
self.__setProcessUnusedMachines()
def valuesDict(self):
return { 'onLogout' : self._onLogout }
return {'onLogout': self._onLogout}

View File

@ -4,42 +4,44 @@
# 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.osmanagers.OSManagersFactory import OSManagersFactory
from uds.core.managers.DownloadsManager import DownloadsManager
from uds.osmanagers.LinuxOsManager.LinuxOsManager import LinuxOsManager
import os.path, sys
import os.path
import sys
OSManagersFactory.factory().insert(LinuxOsManager)
DownloadsManager.manager().registerDownloadable('udsactor_1.0_all.deb',
DownloadsManager.manager().registerDownloadable('udsactor_1.0_all.deb',
_('UDS Actor for linux machines <b>(Requires python 2.6 or greater)'),
os.path.dirname(sys.modules[__package__].__file__) + '/files/udsactor_1.0_all.deb',
os.path.dirname(sys.modules[__package__].__file__) + '/files/udsactor_1.0_all.deb',
'application/x-debian-package')

View File

@ -8,6 +8,7 @@
'''
@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.ui.UserInterface import gui
@ -22,21 +23,22 @@ import logging
logger = logging.getLogger(__name__)
class WinDomainOsManager(WindowsOsManager):
typeName = _('Windows Domain OS Manager')
typeType = 'WinDomainManager'
typeDescription = _('Os Manager to control windows machines with domain. (Basically renames machine)')
iconFile = 'wosmanager.png'
iconFile = 'wosmanager.png'
# Apart form data from windows os manager, we need also domain and credentials
domain = gui.TextField(length=64, label = _('Domain'), order = 1, tooltip = _('Domain to join machines to (use FQDN form, netbios name not allowed)'), required = True)
account = gui.TextField(length=64, label = _('Account'), order = 2, tooltip = _('Account with rights to add machines to domain'), required = True)
password = gui.PasswordField(length=64, label = _('Password'), order = 3, tooltip = _('Password of the account'), required = True)
ou = gui.TextField(length=64, label = _('OU'), order = 4, tooltip = _('Organizational unit where to add machines in domain (check it before using it)'))
domain = gui.TextField(length=64, label=_('Domain'), order=1, tooltip=_('Domain to join machines to (use FQDN form, netbios name not allowed)'), required=True)
account = gui.TextField(length=64, label=_('Account'), order=2, tooltip=_('Account with rights to add machines to domain'), required=True)
password = gui.PasswordField(length=64, label=_('Password'), order=3, tooltip=_('Password of the account'), required=True)
ou = gui.TextField(length=64, label=_('OU'), order=4, tooltip=_('Organizational unit where to add machines in domain (check it before using it)'))
# Inherits base "onLogout"
onLogout = WindowsOsManager.onLogout
def __init__(self,environment, values):
def __init__(self, environment, values):
super(WinDomainOsManager, self).__init__(environment, values)
if values != None:
if values['domain'] == '':
@ -58,20 +60,20 @@ class WinDomainOsManager(WindowsOsManager):
self._ou = ""
self._account = ""
self._password = ""
self._ou = self._ou.replace(' ', '')
if self._domain != '' and self._ou != '':
lpath = 'dc=' + ',dc='.join(self._domain.split('.'))
if self._ou.find(lpath) == -1:
self._ou += ',' + lpath
def __getLdapError(self, e):
logger.debug('Ldap Error: {0} {1}'.format(e, e.message))
_str = ''
if type(e.message) == dict:
#_str += e.message.has_key('info') and e.message['info'] + ',' or ''
_str += e.message.has_key('desc') and e.message['desc'] or ''
else :
# _str += e.message.has_key('info') and e.message['info'] + ',' or ''
_str += e.message.get('desc', '')
else:
_str += str(e)
return _str
@ -82,61 +84,59 @@ class WinDomainOsManager(WindowsOsManager):
dns.resolver.NXDOMAIN
ldap.LDAPError
'''
servers = reversed(sorted(dns.resolver.query('_ldap._tcp.'+self._domain, 'SRV'), key=lambda i: i.priority * 10000 + i.weight))
servers = reversed(sorted(dns.resolver.query('_ldap._tcp.' + self._domain, 'SRV'), key=lambda i: i.priority * 10000 + i.weight))
for server in servers:
_str = ''
try:
uri = "%s://%s:%d" % ('ldap', str(server.target)[:-1], server.port)
logger.debug('URI: {0}'.format(uri))
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) # Disable certificate check
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) # Disable certificate check
l = ldap.initialize(uri=uri)
l.set_option(ldap.OPT_REFERRALS, 0)
l.network_timeout = l.timeout = 5
l.protocol_version = ldap.VERSION3
account = self._account
if account.find('@') == -1:
account += '@' + self._domain
logger.debug('Account data: {0}, {1}, {2}, {3}'.format(self._account, self._domain, account, self._password))
l.simple_bind_s(who = account, cred = self._password)
l.simple_bind_s(who=account, cred=self._password)
return l
except ldap.LDAPError as e:
_str = self.__getLdapError(e)
raise ldap.LDAPError(_str)
def release(self, service):
'''
service is a db user service object
'''
super(WinDomainOsManager,self).release(service)
try:
l = self.__connectLdap()
except dns.resolver.NXDOMAIN: # No domain found, log it and pass
logger.warn('Could not find _ldap._tcp.'+self._domain)
log.doLog(service, log.WARN, "Could not remove machine from domain (_ldap._tcp.{0} not found)".format(self._domain), log.OSMANAGER);
except ldap.LDAPError:
logger.exception('Ldap Exception caught')
log.doLog(service, log.WARN, "Could not remove machine from domain (invalid credentials for {0})".format(self._account), log.OSMANAGER);
#_filter = '(&(objectClass=computer)(sAMAccountName=%s$))' % service.friendly_name
super(WinDomainOsManager, self).release(service)
try:
# res = l.search_ext_s(base = self._ou, scope = ldap.SCOPE_SUBTREE,
l = self.__connectLdap()
except dns.resolver.NXDOMAIN: # No domain found, log it and pass
logger.warn('Could not find _ldap._tcp.' + self._domain)
log.doLog(service, log.WARN, "Could not remove machine from domain (_ldap._tcp.{0} not found)".format(self._domain), log.OSMANAGER)
except ldap.LDAPError:
logger.exception('Ldap Exception caught')
log.doLog(service, log.WARN, "Could not remove machine from domain (invalid credentials for {0})".format(self._account), log.OSMANAGER)
# _filter = '(&(objectClass=computer)(sAMAccountName=%s$))' % service.friendly_name
try:
# res = l.search_ext_s(base = self._ou, scope = ldap.SCOPE_SUBTREE,
# filterstr = _filter)[0]
l.delete('cn={0},{1}'.format(service.friendly_name, self._ou))
except:
logger.exception('Not found: ')
def check(self):
try:
@ -152,10 +152,8 @@ class WinDomainOsManager(WindowsOsManager):
l.search_st(self._ou, ldap.SCOPE_BASE)
except ldap.LDAPError as e:
return _('Check error: {0}').format(self.__getLdapError(e))
return _('Server check was successful')
@staticmethod
def test(env, data):
@ -167,15 +165,15 @@ class WinDomainOsManager(WindowsOsManager):
l = wd.__connectLdap()
except ldap.LDAPError as e:
return [False, _('Could not access AD using LDAP ({0})').format(wd.__getLdapError(e))]
ou = wd._ou
if ou == '':
ou = 'cn=Computers,dc='+',dc='.join(wd._domain.split('.'))
logger.debug('Checking {0} with ou {1}'.format(wd._domain,ou))
ou = 'cn=Computers,dc=' + ',dc='.join(wd._domain.split('.'))
logger.debug('Checking {0} with ou {1}'.format(wd._domain, ou))
r = l.search_st(ou, ldap.SCOPE_BASE)
logger.debug('Result of search: {0}'.format(r))
except ldap.LDAPError:
if wd._ou == '':
return [False, _('The default path {0} for computers was not found!!!').format(ou)]
@ -186,23 +184,22 @@ class WinDomainOsManager(WindowsOsManager):
except Exception as e:
logger.exception('Exception ')
return [False, str(e)]
return [True, _("All parameters seems to work fine.")]
def infoVal(self, service):
return 'domain:{0}\t{1}\t{2}\t{3}\t{4}'.format( self.getName(service), self._domain, self._ou, self._account, self._password)
return 'domain:{0}\t{1}\t{2}\t{3}\t{4}'.format(self.getName(service), self._domain, self._ou, self._account, self._password)
def infoValue(self, service):
return 'domain\r{0}\t{1}\t{2}\t{3}\t{4}'.format( self.getName(service), self._domain, self._ou, self._account, self._password)
return 'domain\r{0}\t{1}\t{2}\t{3}\t{4}'.format(self.getName(service), self._domain, self._ou, self._account, self._password)
def marshal(self):
base = super(WinDomainOsManager,self).marshal()
base = super(WinDomainOsManager, self).marshal()
'''
Serializes the os manager data so we can store it in database
'''
return str.join( '\t', [ 'v1', self._domain, self._ou, self._account, CryptoManager.manager().encrypt(self._password), base.encode('hex') ] )
return str.join('\t', ['v1', self._domain, self._ou, self._account, CryptoManager.manager().encrypt(self._password), base.encode('hex')])
def unmarshal(self, s):
data = s.split('\t')
if data[0] == 'v1':
@ -211,12 +208,11 @@ class WinDomainOsManager(WindowsOsManager):
self._account = data[3]
self._password = CryptoManager.manager().decrypt(data[4])
super(WinDomainOsManager, self).unmarshal(data[5].decode('hex'))
def valuesDict(self):
dct = super(WinDomainOsManager,self).valuesDict()
dct = super(WinDomainOsManager, self).valuesDict()
dct['domain'] = self._domain
dct['ou'] = self._ou
dct['account'] = self._account
dct['password'] = self._password
return dct

View File

@ -8,6 +8,7 @@
'''
@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.ui.UserInterface import gui
@ -19,20 +20,21 @@ import logging
logger = logging.getLogger(__name__)
class WinRandomPassManager(WindowsOsManager):
typeName = _('Windows Random Password OS Manager')
typeType = 'WinRandomPasswordManager'
typeDescription = _('Os Manager to control windows machines, with user password set randomly.')
iconFile = 'wosmanager.png'
iconFile = 'wosmanager.png'
# Apart form data from windows os manager, we need also domain and credentials
userAccount = gui.TextField(length=64, label = _('Account'), order = 2, tooltip = _('User account to change password'), required = True)
password = gui.PasswordField(length=64, label = _('Password'), order = 3, tooltip = _('Current (template) password of the user account'), required = True)
userAccount = gui.TextField(length=64, label=_('Account'), order=2, tooltip=_('User account to change password'), required=True)
password = gui.PasswordField(length=64, label=_('Password'), order=3, tooltip=_('Current (template) password of the user account'), required=True)
# Inherits base "onLogout"
onLogout = WindowsOsManager.onLogout
def __init__(self,environment, values):
def __init__(self, environment, values):
super(WinRandomPassManager, self).__init__(environment, values)
if values != None:
if values['userAccount'] == '':
@ -44,15 +46,15 @@ class WinRandomPassManager(WindowsOsManager):
else:
self._userAccount = ''
self._password = ""
def release(self, service):
super(WinRandomPassManager,self).release(service)
super(WinRandomPassManager, self).release(service)
def processUserPassword(self, service, username, password):
if username == self._userAccount:
return [username, service.recoverValue('winOsRandomPass')]
return [username, password]
def genPassword(self, service):
import random
import string
@ -61,30 +63,29 @@ class WinRandomPassManager(WindowsOsManager):
randomPass = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(16))
service.storeValue('winOsRandomPass', randomPass)
return randomPass
def infoVal(self, service):
return 'rename:{0}\t{1}\t{2}\t{3}'.format( self.getName(service), self._userAccount, self._password, self.genPassword(service))
return 'rename:{0}\t{1}\t{2}\t{3}'.format(self.getName(service), self._userAccount, self._password, self.genPassword(service))
def infoValue(self, service):
return 'rename\r{0}\t{1}\t{2}\t{3}'.format( self.getName(service), self._userAccount, self._password, self.genPassword(service))
return 'rename\r{0}\t{1}\t{2}\t{3}'.format(self.getName(service), self._userAccount, self._password, self.genPassword(service))
def marshal(self):
base = super(WinRandomPassManager,self).marshal()
base = super(WinRandomPassManager, self).marshal()
'''
Serializes the os manager data so we can store it in database
'''
return str.join( '\t', [ 'v1', self._userAccount, CryptoManager.manager().encrypt(self._password), base.encode('hex') ] )
return str.join('\t', ['v1', self._userAccount, CryptoManager.manager().encrypt(self._password), base.encode('hex')])
def unmarshal(self, s):
data = s.split('\t')
if data[0] == 'v1':
self._userAccount = data[1]
self._password = CryptoManager.manager().decrypt(data[2])
super(WinRandomPassManager, self).unmarshal(data[3].decode('hex'))
def valuesDict(self):
dic = super(WinRandomPassManager,self).valuesDict()
dic = super(WinRandomPassManager, self).valuesDict()
dic['userAccount'] = self._userAccount
dic['password'] = self._password
return dic

View File

@ -8,6 +8,7 @@
'''
@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.ui.UserInterface import gui
@ -28,7 +29,7 @@ def scrambleMsg(data):
res = []
n = 0x32
for c in data[::-1]:
res.append( chr(ord(c) ^ n) )
res.append(chr(ord(c) ^ n))
n = (n + ord(c)) & 0xFF
return "".join(res).encode('hex')
@ -37,14 +38,21 @@ class WindowsOsManager(osmanagers.OSManager):
typeName = _('Windows Basic OS Manager')
typeType = 'WindowsManager'
typeDescription = _('Os Manager to control windows machines without domain. (Basically renames machine)')
iconFile = 'wosmanager.png'
onLogout = gui.ChoiceField( label = _('On Logout'), order = 10, rdonly = False, tooltip = _('What to do when user logout from service'),
values = [ {'id' : 'keep', 'text' : _('Keep service assigned') },
{'id' : 'remove', 'text' : _('Remove service') }
], defvalue = 'keep' )
iconFile = 'wosmanager.png'
onLogout = gui.ChoiceField(
label=_('On Logout'),
order=10,
rdonly=False,
tooltip=_('What to do when user logout from service'),
values=[
{'id': 'keep', 'text': _('Keep service assigned')},
{'id': 'remove', 'text': _('Remove service')}
],
defvalue='keep'
)
@staticmethod
def validateLen(len):
try:
@ -54,11 +62,11 @@ class WindowsOsManager(osmanagers.OSManager):
if len > 6 or len < 1:
raise osmanagers.OSManager.ValidationException(_('Length must be betwen 1 and six'))
return len
def __setProcessUnusedMachines(self):
self.processUnusedMachines = self._onLogout == 'remove'
def __init__(self,environment, values):
def __init__(self, environment, values):
super(WindowsOsManager, self).__init__(environment, values)
if values is not None:
self._onLogout = values['onLogout']
@ -66,22 +74,22 @@ class WindowsOsManager(osmanagers.OSManager):
self._onLogout = ''
self.__setProcessUnusedMachines()
def release(self, service):
pass
def getName(self, service):
'''
gets name from deployed
'''
return service.getName()
def infoVal(self,service):
def infoVal(self, service):
return 'rename:' + self.getName(service)
def infoValue(self,service):
def infoValue(self, service):
return 'rename\r' + self.getName(service)
def notifyIp(self, uid, si, data):
# Notifies IP to deployed
pairs = data.split(',')
@ -90,24 +98,24 @@ class WindowsOsManager(osmanagers.OSManager):
if key.lower() == uid.lower():
si.setIp(val)
break
def doLog(self, service, data, origin = log.OSMANAGER):
def doLog(self, service, data, origin=log.OSMANAGER):
# Stores a log associated with this service
try:
msg, level = data.split('\t')
log.doLog(service, level, msg, origin)
except:
log.doLog(service, log.ERROR, "do not understand {0}".format(data), origin)
def process(self,service,msg, data):
def process(self, service, msg, data):
'''
We understand this messages:
* msg = info, data = None. Get information about name of machine (or domain, in derived WinDomainOsManager class) (old method)
* msg = information, data = None. Get information about name of machine (or domain, in derived WinDomainOsManager class) (new method)
* msg = logon, data = Username, Informs that the username has logged in inside the machine
* msg = logoff, data = Username, Informs that the username has logged out of the machine
* msg = logoff, data = Username, Informs that the username has logged out of the machine
* msg = ready, data = None, Informs machine ready to be used
'''
logger.info("Invoked WindowsOsManager for {0} with params: {1},{2}".format(service, msg, data))
@ -153,10 +161,10 @@ class WindowsOsManager(osmanagers.OSManager):
notifyReady = True
self.notifyIp(service.unique_id, si, data)
service.updateData(si)
service.setInUse(inUse)
service.setOsState(state)
# If notifyReady is not true, save state, let UserServiceManager do it for us else
if doRemove is True:
service.remove()
@ -167,7 +175,7 @@ class WindowsOsManager(osmanagers.OSManager):
UserServiceManager.manager().notifyReadyFromOsManager(service, '')
logger.debug('Returning {0}'.format(ret))
return scrambleMsg(ret)
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
@ -175,8 +183,8 @@ class WindowsOsManager(osmanagers.OSManager):
'''
if self._onLogout == 'remove':
userService.remove()
def checkState(self,service):
def checkState(self, service):
logger.debug('Checking state for service {0}'.format(service))
return State.RUNNING
@ -184,15 +192,14 @@ class WindowsOsManager(osmanagers.OSManager):
'''
Serializes the os manager data so we can store it in database
'''
return str.join( '\t', [ 'v1', self._onLogout ] )
return str.join('\t', [ 'v1', self._onLogout ])
def unmarshal(self, s):
data = s.split('\t')
if data[0] == 'v1':
self._onLogout = data[1]
self.__setProcessUnusedMachines()
def valuesDict(self):
return { 'onLogout' : self._onLogout }

View File

@ -4,27 +4,27 @@
# Copyright (c) 2012 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@ -32,32 +32,33 @@ OS Manager modules for uds are contained inside this package.
To create a new OS manager module, you will need to follow this steps:
1.- Create the os manager module, probably based on an existing one
2.- Insert the module package as child of this package
3.- Import the class of your os manager module at __init__. For example::
from OSManager import SimpleOSManager
3.- Import the class of your os manager module at __init__. For example::
from OSManager import SimpleOSManager
4.- Done. At Server restart, the module will be recognized, loaded and treated
The registration of modules is done locating subclases of :py:class:`uds.core.auths.Authentication`
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
'''
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 sys
from uds.core import osmanagers
# Dinamycally import children of this package. The __init__.py files must register, if needed, inside ServiceProviderFactory
pkgpath = os.path.dirname(sys.modules[__name__].__file__)
for _, name, _ in pkgutil.iter_modules([pkgpath]):
__import__(name, globals(), locals(), [], -1)
p = osmanagers.OSManager
# This is marked as error in IDE, but it's not (__subclasses__)
for cls in p.__subclasses__():
osmanagers.factory().insert(cls)
__init__()