1
0
mirror of https://github.com/dkmstr/openuds.git synced 2025-01-08 21:18:00 +03:00

Merged changes to 2.1

This commit is contained in:
Adolfo Gómez García 2017-06-01 11:36:07 +02:00
commit e8ecf3d057
28 changed files with 504 additions and 52 deletions

View File

@ -32,10 +32,12 @@
'''
from __future__ import unicode_literals
from PyQt4 import QtCore, QtGui # @UnresolvedImport
import sys
from PyQt4 import QtCore, QtGui
import six
from uds.rest import RestRequest
from uds.forward import forward # @UnusedImport
from uds.forward import forward
from uds.log import logger
from uds import tools
from uds import VERSION
@ -308,7 +310,7 @@ if __name__ == "__main__":
# Setup REST api endpoint
RestRequest.restApiUrl = '{}://{}/rest/client'.format(['http', 'https'][ssl], host)
logger.debug('Setting requert URL to {}'.format(RestRequest.restApiUrl))
logger.debug('Setting request URL to {}'.format(RestRequest.restApiUrl))
# RestRequest.restApiUrl = 'https://172.27.0.1/rest/client'
try:

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2015 Virtual Cable S.L.
# Copyright (c) 2017 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2015 Virtual Cable S.L.
# Copyright (c) 2017 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,

View File

@ -0,0 +1,140 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 Virtual Cable S.L.
# All rights reserved.
#
# 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,
# 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
# 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
# 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
# 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
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from uds import ui
from uds import browser
from uds.rest import RestRequest, RetryException
from uds.forward import forward
from uds import VERSION
from uds.log import logger # @UnresolvedImport
from uds import tools
import six
import sys
import webbrowser
import pickle
def approveHost(host):
from os.path import expanduser
hostsFile = expanduser('~/.udsclient.hosts')
try:
with open(hostsFile, 'r') as f:
approvedHosts = f.read().splitlines()
except Exception:
approvedHosts = []
host = host.lower()
if host in approvedHosts:
return True
errorString = 'The server {} must be approved:\n'.format(host)
errorString += 'Only approve UDS servers that you trust to avoid security issues.'
approved = ui.question("ACCESS Warning", errorString)
if approved:
approvedHosts.append(host)
logger.debug('Host was approved, saving to approvedHosts file')
try:
with open(hostsFile, 'w') as f:
f.write('\n'.join(approvedHosts))
except Exception:
logger.warn('Got exception writing to {}'.format(hostsFile))
return approved
def getWithRetry(rest, url):
while True:
try:
res = rest.get(url)
return res
except RetryException as e:
if ui.question('Service not available', '{}\nPlease, wait a minute and press "OK" to retry, or CANCEL to abort') is True:
continue
raise Exception('Cancelled by user')
if __name__ == "__main__":
logger.debug('Initializing connector')
if six.PY3 is False:
logger.debug('Fixing threaded execution of commands')
import threading
threading._DummyThread._Thread__stop = lambda x: 42
# First parameter must be url
try:
uri = sys.argv[1]
if uri == '--test':
sys.exit(0)
logger.debug('URI: {}'.format(uri))
if uri[:6] != 'uds://' and uri[:7] != 'udss://':
raise Exception()
ssl = uri[3] == 's'
host, ticket, scrambler = uri.split('//')[1].split('/')
logger.debug('ssl: {}, host:{}, ticket:{}, scrambler:{}'.format(ssl, host, ticket, scrambler))
except Exception:
logger.debug('Detected execution without valid URI, exiting')
ui.message('UDS Client', 'UDS Client Version {}'.format(VERSION))
sys.exit(1)
rest = RestRequest('{}://{}/rest/client'.format(['http', 'https'][ssl], host))
logger.debug('Setting request URL to {}'.format(rest.restApiUrl))
# Main requests part
# First, get version
try:
res = getWithRetry(rest, '')
if res['requiredVersion'] > VERSION:
ui.message("New UDS Client available", "A new uds version is needed in order to access this version of UDS. A browser will be openend for this download.")
webbrowser.open(res['downloadUrl'])
sys.exit(1)
# Now get ticket
res = getWithRetry(rest, '/{}/{}'.format(ticket, scrambler), params={'hostname': tools.getHostName(), 'version': VERSION})
except Exception as e:
error = 'ERROR: {}'.format(e)
logger.error(error)
ui.message('Error', error)
sys.exit(2)

View File

@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 Virtual Cable S.L.
# All rights reserved.
#
# 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,
# 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
# 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
# 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
# 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
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
import random
import os
import tempfile
import string
import webbrowser
TEMPLATE = '''<html>
<head>
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>
<p>{message}<P>
</body>
</html>
'''
def _htmlFilename():
return os.path.join(tempfile.gettempdir(), ''.join([random.choice(string.ascii_lowercase) for i in range(22)]) + '.html')
def message(title, message):
filename = _htmlFilename()
with open(filename, 'w') as f:
f.write(TEMPLATE.format(title=title, message=message))
webbrowser.open('file://' + filename, new=0, autoraise=False)

1
client/thin/src/uds/log.py Symbolic link
View File

@ -0,0 +1 @@
../../../full/src/uds/log.py

View File

@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2015 Virtual Cable S.L.
# All rights reserved.
#
# 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,
# 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
# 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
# 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
# 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
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
import requests
from . import VERSION
import json
import six
import urllib
from .log import logger
class RetryException(Exception):
pass
class RestRequest(object):
restApiUrl = ''
def __init__(self, restURL): # parent not used
super(RestRequest, self).__init__()
self.restApiUrl = restURL
def get(self, url, params=None):
url = self.restApiUrl + url
if params is not None:
url += '?' + '&'.join('{}={}'.format(k, urllib.quote(six.text_type(v).encode('utf8'))) for k, v in params.iteritems())
logger.debug('Requesting {}'.format(url))
try:
r = requests.get(url, headers={'Content-type': 'application/json'})
except requests.exceptions.ConnectionError as e:
raise Exception('Error connecting to UDS Server at {}'.format(self.restApiUrl[0:-11]))
if r.ok:
logger.debug('Request was OK. {}'.format(r.text))
data = json.loads(r.text)
if not 'error' in data:
return data['result']
# Has error
if data.get('retryable', '0') == '1':
raise RetryException(data['error'])
raise Exception(data['error'])
else:
logger.error('Error requesting {}: {}, {}'.format(url, r.code. r.text))
raise Exception('Error {}: {}'.format(r.code, r.text))
return data

View File

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 Virtual Cable S.L.
# All rights reserved.
#
# 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,
# 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
# 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
# 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
# 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
# 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
try:
import gtkui as theUI
except Exception:
import consoleui as theUI
def message(title, message):
theUI.message(title, message)
def question(title, message):
return theUI.question(title, message)

View File

@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 Virtual Cable S.L.
# All rights reserved.
#
# 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,
# 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
# 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
# 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
# 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
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
import sys
from uds.log import logger
def message(title, message):
sys.stderr.write("** {} **\n {}\n".format(title, message))
def question(title, message):
sys.stderr.write("** {} **\n{}\nReturned YES\n".format(title, message))
return True

View File

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 Virtual Cable S.L.
# All rights reserved.
#
# 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,
# 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
# 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
# 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
# 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
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
import pygtk
pygtk.require('2.0')
import gtk
raise Exception('not available')

View File

@ -1,3 +1,5 @@
base
#add your own dependancies to this file, base should always be included.
python
pygtk
freerdp

View File

@ -23,7 +23,7 @@ BASE_DIR = '/'.join(os.path.dirname(os.path.abspath(__file__)).split('/')[:-1])
DEBUG = True
# USE_X_FORWARDED_HOST = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https') # For testing behind a reverse proxy
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') # For testing begind a reverse proxy
DATABASES = {
'default': {
@ -246,6 +246,9 @@ TRACEFILE = 'trace.log'
LOGLEVEL = DEBUG and 'DEBUG' or 'INFO'
ROTATINGSIZE = 32 * 1024 * 1024 # 32 Megabytes before rotating files
# Tests runner is default tests runner
TEST_RUNNER = 'django.test.runner.DiscoverRunner'
LOGGING = {
'version': 1,
'disable_existing_loggers': True,

View File

@ -51,7 +51,7 @@ import requests
import json
import logging
__updated__ = '2017-05-18'
__updated__ = '2017-05-19'
logger = logging.getLogger(__name__)
traceLogger = logging.getLogger('traceLog')
@ -213,17 +213,19 @@ class UserServiceManager(object):
@return: the uService removed (marked for removal)
'''
with transaction.atomic():
uService = UserService.objects.get(id=uService.id)
uService = UserService.objects.select_for_update().get(id=uService.id)
logger.debug('Removing uService {0}'.format(uService))
if uService.isUsable() is False and State.isRemovable(uService.state) is False:
raise OperationException(_('Can\'t remove a non active element'))
ci = uService.getInstance()
state = ci.destroy()
uService.setState(State.REMOVING)
logger.debug("**** The state now is {}".format(uService.state))
logger.debug("***** The state now is {}".format(State.toString(uService.state)))
uService.setInUse(False) # For accounting, ensure that it is not in use right now
UserServiceOpChecker.makeUnique(uService, ci, state)
uService.save()
ci = uService.getInstance()
state = ci.destroy()
UserServiceOpChecker.makeUnique(uService, ci, state)
def removeOrCancel(self, uService):
if uService.isUsable() or State.isRemovable(uService.state):
@ -466,14 +468,18 @@ class UserServiceManager(object):
This method is used by UserService when a request for setInUse(False) is made
This checks that the service can continue existing or not
'''
remove = False
# uService = UserService.objects.get(id=uService.id)
with transaction.atomic():
uService = UserService.objects.get(id=uService.id)
uService = UserService.objects.select_for_update().get(id=uService.id)
if uService.publication is None:
return
if uService.publication.id != uService.deployed_service.activePublication().id:
logger.debug('Old revision of user service, marking as removable: {0}'.format(uService))
uService.remove()
remove = True
if remove:
uService.remove()
def notifyReadyFromOsManager(self, uService, data):
try:

View File

@ -34,6 +34,7 @@
from uds.core.Serializable import Serializable
import pickle
import timeit
import six
class Attribute(object):
@ -88,12 +89,12 @@ class AutoAttributes(Serializable):
def declare(self, **kwargs):
d = {}
for key, typ in kwargs.iteritems():
for key, typ in six.iteritems(kwargs):
d[key] = Attribute(typ)
self.dict = d
def marshal(self):
return '\2'.join(['%s\1%s' % (k, pickle.dumps(v)) for k, v in self.dict.iteritems()]).encode(AutoAttributes.ACODEC)
return '\2'.join(['%s\1%s' % (k, pickle.dumps(v)) for k, v in six.iteritems(self.dict)]).encode(AutoAttributes.ACODEC)
def unmarshal(self, data):
if data == '': # Can be empty
@ -105,6 +106,6 @@ class AutoAttributes(Serializable):
def __str__(self):
str_ = '<AutoAttribute '
for k, v in self.dict.iteritems():
for k, v in six.iteritems(self.dict):
str_ += "%s (%s) = %s" % (k, v.getType(), v.getStrValue())
return str_ + '>'

View File

@ -102,14 +102,17 @@ class Cache(object):
try:
uds.models.Cache.objects.create(owner=self._owner, key=key, value=value, created=now, validity=validity) # @UndefinedVariable
except Exception:
# Already exists, modify it
c = uds.models.Cache.objects.get(pk=key) # @UndefinedVariable
c.owner = self._owner
c.key = key
c.value = value
c.created = datetime.now()
c.validity = validity
c.save()
try:
# Already exists, modify it
c = uds.models.Cache.objects.get(pk=key) # @UndefinedVariable
c.owner = self._owner
c.key = key
c.value = value
c.created = datetime.now()
c.validity = validity
c.save()
except transaction.TransactionManagementError:
logger.debug('Transaction in course, cannot store value')
def refresh(self, skey):
# logger.debug('Refreshing key "%s" for cache "%s"' % (skey, self._owner,))

View File

@ -322,6 +322,9 @@ class GlobalConfig(object):
# Custom message for error when limiting by calendar
LIMITED_BY_CALENDAR_TEXT = Config.section(GLOBAL_SECTION).value('Calendar access denied text', '', type=Config.TEXT_FIELD) # Defaults to Nothing
# This is used so templates can change "styles" from admin interface
LOWERCASE_USERNAME = Config.section(SECURITY_SECTION).value('Convert username to lowercase', '1', type=Config.BOOLEAN_FIELD)
initDone = False
@staticmethod

View File

@ -65,7 +65,8 @@ class UserServiceInfoItemsCleaner(Job):
class UserServiceRemover(Job):
frecuency = GlobalConfig.REMOVAL_CHECK.getInt() # Request run cache "info" cleaner every configued seconds. If config value is changed, it will be used at next reload
frecuency = 31
frecuency_cfg = GlobalConfig.REMOVAL_CHECK # Request run cache "info" cleaner every configued seconds. If config value is changed, it will be used at next reload
friendly_name = 'User Service Cleaner'
removeAtOnce = GlobalConfig.USER_SERVICE_CLEAN_NUMBER.getInt() # Same, it will work at reload
@ -74,10 +75,12 @@ class UserServiceRemover(Job):
super(UserServiceRemover, self).__init__(environment)
def run(self):
removeFrom = getSqlDatetime() - timedelta(seconds=10) # We keep at least 10 seconds the machine before removing it, so we avoid connections errors
removables = UserService.objects.filter(state=State.REMOVABLE, state_date__lt=removeFrom,
deployed_service__service__provider__maintenance_mode=False)[0:UserServiceRemover.removeAtOnce]
with transaction.atomic():
removeFrom = getSqlDatetime() - timedelta(seconds=10) # We keep at least 10 seconds the machine before removing it, so we avoid connections errors
removables = UserService.objects.filter(state=State.REMOVABLE, state_date__lt=removeFrom,
deployed_service__service__provider__maintenance_mode=False)[0:UserServiceRemover.removeAtOnce]
for us in removables:
logger.debug('Checking removal of {}'.format(us))
try:
if managers.userServiceManager().canRemoveServiceFromDeployedService(us.deployed_service) is True:
managers.userServiceManager().remove(us)

View File

@ -33,7 +33,7 @@
from __future__ import unicode_literals
from django.db import models
from django.db import models, transaction
from django.db.models import signals
from django.utils.encoding import python_2_unicode_compatible
@ -62,7 +62,7 @@ from datetime import datetime, timedelta
import logging
import pickle
__updated__ = '2017-05-10'
__updated__ = '2017-05-19'
logger = logging.getLogger(__name__)
@ -335,6 +335,7 @@ class DeployedService(UUIDModel, TaggingMixin):
Args:
activePub: Active publication used as "current" publication to make checks
'''
logger.debug('Marking old user services as removable...')
now = getSqlDatetime()
if activePub is None:
logger.error('No active publication, don\'t know what to erase!!! (ds = {0})'.format(self))
@ -342,8 +343,9 @@ class DeployedService(UUIDModel, TaggingMixin):
for ap in self.publications.exclude(id=activePub.id):
for u in ap.userServices.filter(state=states.userService.PREPARING):
u.cancel()
ap.userServices.exclude(cache_level=0).filter(state=states.userService.USABLE).update(state=states.userService.REMOVABLE, state_date=now)
ap.userServices.filter(cache_level=0, state=states.userService.USABLE, in_use=False).update(state=states.userService.REMOVABLE, state_date=now)
with transaction.atomic():
ap.userServices.exclude(cache_level=0).filter(state=states.userService.USABLE).update(state=states.userService.REMOVABLE, state_date=now)
ap.userServices.filter(cache_level=0, state=states.userService.USABLE, in_use=False).update(state=states.userService.REMOVABLE, state_date=now)
def validateGroups(self, grps):
'''

View File

@ -57,7 +57,7 @@ import six
import pickle
import logging
__updated__ = '2017-05-18'
__updated__ = '2017-05-19'
logger = logging.getLogger(__name__)
@ -319,7 +319,8 @@ class UserService(UUIDModel):
save: Defaults to true. If false, record will not be saved to db, just modified
'''
logger.debug(' *** Setting state to {} from {} for {}--{}'.format(state, self.state, self.id, self.friendly_name))
logger.debug(' *** Setting state to {} from {} for {}'.format(State.toString(state), State.toString(self.state), self))
if state != self.state:
self.state_date = getSqlDatetime()
self.state = state
@ -362,7 +363,7 @@ class UserService(UUIDModel):
self.in_use = state
self.in_use_date = getSqlDatetime()
# Start/stop accouting
# Start/stop accounting
if state is True:
self.startUsageAccounting()
else:

View File

@ -43,7 +43,7 @@ import six
import pickle
import logging
__updated__ = '2017-05-18'
__updated__ = '2017-05-19'
logger = logging.getLogger(__name__)
@ -149,7 +149,7 @@ class OGDeployment(UserDeployment):
return self.__error('Error checking machine: {}'.format(e))
# possible status are ("off", "oglive", "busy", "linux", "windows", "macos" o "unknown").
if status['status'] != 'off':
if status['status'] in ("linux", "windows", "macos"):
return State.FINISHED
return State.RUNNING

View File

@ -48,7 +48,7 @@ import logging
import six
__updated__ = '2017-05-18'
__updated__ = '2017-05-23'
logger = logging.getLogger(__name__)
@ -98,6 +98,7 @@ class OGProvider(ServiceProvider):
checkCert = gui.CheckBoxField(label=_('Check Cert.'), order=3, tooltip=_('If checked, ssl certificate of OpenGnsys server must be valid, not self signed)'))
username = gui.TextField(length=32, label=_('Username'), order=4, tooltip=_('User with valid privileges on OpenGnsys'), required=True)
password = gui.PasswordField(lenth=32, label=_('Password'), order=5, tooltip=_('Password of the user of OpenGnsys'), required=True)
udsServerAccessUrl = gui.TextField(length=32, label=_('UDS Server URL'), order=6, tooltip=_('URL used by OpenGnsys to access UDS. If empty, UDS will guess it.'), required=False, tab=gui.PARAMETERS_TAB)
maxPreparingServices = gui.NumericField(length=3, label=_('Creation concurrency'), defvalue='10', minValue=1, maxValue=65536, order=50, tooltip=_('Maximum number of concurrently creating VMs'), required=True, tab=gui.ADVANCED_TAB)
maxRemovingServices = gui.NumericField(length=3, label=_('Removal concurrency'), defvalue='5', minValue=1, maxValue=65536, order=51, tooltip=_('Maximum number of concurrently removing VMs'), required=True, tab=gui.ADVANCED_TAB)
@ -123,7 +124,6 @@ class OGProvider(ServiceProvider):
def endpoint(self):
return 'https://{}:{}/rest'.format(self.host.value, self.port.value)
@property
def api(self):
if self._api is None:

View File

@ -37,7 +37,7 @@ import random
import six
import logging
__updated__ = '2017-05-18'
__updated__ = '2017-05-19'
logger = logging.getLogger(__name__)
@ -212,8 +212,7 @@ def get(path, errMsg):
return []
elif path[-6:] == 'status':
rnd = random.randint(0, 100)
logger.debug('Random generated: {}'.format(rnd))
if rnd < 95:
if rnd < 25:
return STATUS_READY_LINUX
return STATUS_OFF

View File

@ -74,7 +74,10 @@ gui.authenticators.link = (event) ->
$select.empty()
gui.doLog data
$.each data, (undefined_, value) ->
$select.append "<option value=\"" + value.id + "\">" + value.id + " (" + value.name + ")</option>"
$select.append($('<option>',
value: value.id
text: value.id + " (" + value.name + ")"
))
return
return

View File

@ -195,8 +195,8 @@ uds.launch = (el, url, alt) ->
alert data.error
else
# Fix access provided in url in case of https
# if window.location.protocol is 'https:'
# data.url = data.url.replace('uds://', 'udss://') # Ensures that protocol is https also for plugin, fixing if needed UDS provided info
if window.location.protocol is 'https:'
data.url = data.url.replace('uds://', 'udss://') # Ensures that protocol is https also for plugin, fixing if needed UDS provided info
if bypassPluginDetection is false
uds.doLaunch el, data.url, alt
else

View File

@ -68,7 +68,7 @@
<select multiple name="groups" class="selectpicker show-menu-arrow show-tick modal_field_data" data-style="btn-default" data-width="100%" id="id_state">
{{# each groups_all }}
{{# ifequals type 'group' }}
<option value="{{ id }}"{{# ifbelongs id ../groups }} selected{{/ ifbelongs}}>{{ name }}</option>
<option value="{{ id }}"{{# ifbelongs id ../groups }} selected{{/ ifbelongs}}>{{ name }} ({{ comments }})</option>
{{/ ifequals }}
{{/ each }}
</select>

View File

@ -1,3 +1,5 @@
# This is a template
# Saved as .py for easier editing
from __future__ import unicode_literals
# pylint: disable=import-error, no-name-in-module
@ -9,8 +11,15 @@ from uds import tools # @UnresolvedImport
import six
try:
thePass = six.binary_type('{m.password}'.encode('UTF-16LE'))
password = win32crypt.CryptProtectData(thePass, None, None, None, None, 0x01).encode('hex')
except Exception:
logger.info('Cannot encrypt for user, trying for machine')
password = win32crypt.CryptProtectData(thePass, None, None, None, None, 0x05).encode('hex')
# The password must be encoded, to be included in a .rdp file, as 'UTF-16LE' before protecting (CtrpyProtectData) it in order to work with mstsc
theFile = sp['as_file'].format(password=win32crypt.CryptProtectData(six.binary_type(sp['password'].encode('UTF-16LE')), None, None, None, None, 0x01).encode('hex')) # @UndefinedVariable
theFile = '''{m.r.as_file}'''.format(password=password)
filename = tools.saveTempFile(theFile)
executable = tools.findApp('mstsc.exe')

View File

@ -8,21 +8,29 @@ import win32crypt # @UnresolvedImport
import os
import subprocess
from uds.forward import forward # @UnresolvedImport
from uds.log import logger # @UnresolvedImport
from uds import tools # @UnresolvedImport
import six
forwardThread, port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], 3389, sp['tunWait']) # @UndefinedVariable
forwardThread, port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], 3389, waitTime=sp['tunWait']) # @UndefinedVariable
if forwardThread.status == 2:
raise Exception('Unable to open tunnel')
tools.addTaskToWait(forwardThread)
try:
thePass = six.binary_type('{m.password}'.encode('UTF-16LE'))
password = win32crypt.CryptProtectData(thePass, None, None, None, None, 0x01).encode('hex')
except Exception:
logger.info('Cannot encrypt for user, trying for machine')
password = win32crypt.CryptProtectData(thePass, None, None, None, None, 0x05).encode('hex')
# The password must be encoded, to be included in a .rdp file, as 'UTF-16LE' before protecting (CtrpyProtectData) it in order to work with mstsc
theFile = sp['as_file'].format(# @UndefinedVariable
password=win32crypt.CryptProtectData(six.binary_type(sp['password'].encode('UTF-16LE')), None, None, None, None, 0x01).encode('hex'), # @UndefinedVariable
password=password,
address='127.0.0.1:{}'.format(port)
)

View File

@ -48,7 +48,7 @@ import uds.web.errors as errors
import logging
logger = logging.getLogger(__name__)
__updated__ = '2017-04-19'
__updated__ = '2017-06-01'
# Allow cross-domain login
# @csrf_exempt
@ -91,6 +91,8 @@ def login(request, tag=None):
except Exception:
authenticator = Authenticator()
userName = form.cleaned_data['user']
if GlobalConfig.LOWERCASE_USERNAME.getBool(True) is True:
userName = userName.lower()
cache = Cache('auth')
cacheKey = str(authenticator.id) + userName