1
0
mirror of https://github.com/dkmstr/openuds.git synced 2025-01-11 05:17:55 +03:00

Merge remote-tracking branch 'origin/v2.2'

This commit is contained in:
Adolfo Gómez García 2018-11-20 11:00:42 +01:00
commit 462e53efea
13 changed files with 206 additions and 115 deletions

View File

@ -259,7 +259,7 @@ class UDSSystemTray(QtGui.QSystemTrayIcon):
if remainingTime <= 0:
logger.info('User has been idle for too long, notifying Broker that service can be reclaimed')
self.quit(logoff=True)
self.quit(logoff=True, extra=' (idle: {} vs {})'.format(idleTime, self.maxIdleTime))
def displayMessage(self, message):
logger.debug('Displaying message')
@ -296,14 +296,14 @@ class UDSSystemTray(QtGui.QSystemTrayIcon):
def about(self):
self.aboutDlg.exec_()
def quit(self, logoff=False):
def quit(self, logoff=False, extra=''):
global doLogoff
logger.debug('Quit invoked')
if not self.stopped:
self.stopped = True
try:
# If we close Client, send Logoff to Broker
self.ipc.sendLogout(operations.getCurrentUser())
self.ipc.sendLogout(operations.getCurrentUser() + extra)
self.timer.stop()
self.ipc.stop()
except Exception:

View File

@ -78,7 +78,7 @@ class OsManagerError(RESTError):
try:
import urllib3 # @UnusedImport @UnresolvedImport
except Exception:
from requests.packages import urllib3 # @Reimport
from requests.packages import urllib3 # @Reimport @UnresolvedImport
try:
urllib3.disable_warnings() # @UndefinedVariable
@ -113,7 +113,7 @@ class Api(object):
self.maxSession = None
self.secretKey = six.text_type(uuid.uuid4())
try:
self.newerRequestLib = requests.__version__.split('.')[0] >= '1'
self.newerRequestLib = requests.__version__.split('.')[0] >= '1' # @UndefinedVariable
except Exception:
self.newerRequestLib = False # I no version, guess this must be an old requests
@ -208,7 +208,7 @@ class Api(object):
raise ConnectionError('REST api has not been initialized')
if processData:
if not isinstance(data, six.text_type):
if data and not isinstance(data, six.text_type):
data = data.decode('utf8')
data = json.dumps({'data': data})
url = self._getUrl('/'.join([self.uuid, msg]))

View File

@ -45,6 +45,7 @@ OTHER, DEBUG, INFO, WARN, ERROR, FATAL = (10000 * (x + 1) for x in six.moves.xra
class Logger(object):
def __init__(self):
self.logLevel = INFO
self.logger = LocalLogger()
@ -61,7 +62,6 @@ class Logger(object):
self.remoteLogger = remoteLogger
def log(self, level, message):
print(level)
if level < self.logLevel: # Skip not wanted messages
return

View File

@ -317,8 +317,8 @@ class CommonService(object):
if self.api is not None:
try:
self.api.notifyComm(None)
except Exception:
logger.error('Couln\'t remove comms url from broker')
except Exception as e:
logger.error('Couln\'t remove comms url from broker: {}'.format(e))
# self.notifyStop()

View File

@ -210,7 +210,10 @@ def initIdleDuration(atLeastSeconds):
def getIdleDuration():
lastInputInfo = LASTINPUTINFO()
lastInputInfo.cbSize = ctypes.sizeof(lastInputInfo)
ctypes.windll.user32.GetLastInputInfo(ctypes.byref(lastInputInfo))
if ctypes.windll.user32.GetLastInputInfo(ctypes.byref(lastInputInfo)) == 0:
return 0
if lastInputInfo.dwTime > 1000000000: # Value toooo high, nonsense...
return 0
millis = ctypes.windll.kernel32.GetTickCount() - lastInputInfo.dwTime # @UndefinedVariable
return millis / 1000.0

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2014-2018 Virtual Cable S.L.
# Copyright (c) 2014 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
@ -103,6 +103,7 @@ class ServicesPools(ModelHandler):
custom_methods = [('setFallbackAccess', True), ('actionsList', True)]
def item_as_dict(self, item):
summary = 'summarize' in self._params
# if item does not have an associated service, hide it (the case, for example, for a removed service)
# Access from dict will raise an exception, and item will be skipped
poolGroupId = None
@ -131,30 +132,51 @@ class ServicesPools(ModelHandler):
'state': state,
'thumb': item.image.thumb64 if item.image is not None else DEFAULT_THUMB_BASE64,
'account': item.account.name if item.account is not None else '',
'account_id': item.account.uuid if item.account is not None else None,
'service_id': item.service.uuid,
'provider_id': item.service.provider.uuid,
'image_id': item.image.uuid if item.image is not None else None,
'servicesPoolGroup_id': poolGroupId,
'account_id': item.account.uuid if item.account is not None else None,
'pool_group_name': poolGroupName,
'pool_group_thumb': poolGroupThumb,
'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.exclude(state__in=State.INFO_STATES).count(),
'user_services_in_preparation': item.userServices.filter(state=State.PREPARING).count(),
'restrained': item.isRestrained(),
'show_transports': item.show_transports,
'visible': item.visible,
'allow_users_remove': item.allow_users_remove,
'allow_users_reset': item.allow_users_reset,
'ignores_unused': item.ignores_unused,
'fallbackAccess': item.fallbackAccess,
'permission': permissions.getEffectivePermission(self._user, item),
'info': Services.serviceInfo(item.service),
}
# Extended info
if not summary:
state = item.state
if item.isInMaintenance():
state = State.MAINTENANCE
elif userServiceManager().canInitiateServiceFromDeployedService(item) is False:
state = State.SLOWED_DOWN
poolGroupId = None
poolGroupName = _('Default')
poolGroupThumb = DEFAULT_THUMB_BASE64
if item.servicesPoolGroup is not None:
poolGroupId = item.servicesPoolGroup.uuid
poolGroupName = item.servicesPoolGroup.name
if item.servicesPoolGroup.image is not None:
poolGroupThumb = item.servicesPoolGroup.image.thumb64
val['state'] = state
val['thumb'] = item.image.thumb64 if item.image is not None else DEFAULT_THUMB_BASE64
val['user_services_count'] = item.userServices.exclude(state__in=State.INFO_STATES).count()
val['user_services_in_preparation'] = item.userServices.filter(state=State.PREPARING).count()
val['tags'] = [tag.tag for tag in item.tags.all()]
val['restrained'] = item.isRestrained()
val['permission'] = permissions.getEffectivePermission(self._user, item)
val['info'] = Services.serviceInfo(item.service)
val['servicesPoolGroup_id'] = poolGroupId
val['pool_group_name'] = poolGroupName
val['pool_group_thumb'] = poolGroupThumb
if item.osmanager is not None:
val['osmanager_id'] = item.osmanager.uuid

View File

@ -27,13 +27,13 @@
# 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.
"""
'''
@itemor: Adolfo Gómez, dkmaster at dkmon dot com
"""
'''
from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _, ugettext
from uds.models import Transport, Network
from uds.models import Transport, Network, ServicePool
from uds.core.transports import factory
from uds.core.util import permissions
from uds.core.util import OsDetector
@ -65,32 +65,44 @@ class Transports(ModelHandler):
def getGui(self, type_):
try:
return self.addField(
self.addField(
self.addField(self.addDefaultFields(factory().lookup(type_).guiDescription(), ['name', 'comments', 'tags', 'priority']), {
'name': 'nets_positive',
'value': True,
'label': ugettext('Network access'),
'tooltip': ugettext('If checked, the transport will be enabled for the selected networks. If unchecked, transport will be disabled for selected networks'),
'type': 'checkbox',
'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
'label': ugettext('Networks'),
'tooltip': ugettext('Networks associated with this transport. If No network selected, will mean "all networks"'),
'type': 'multichoice',
'order': 101
}), {
'name': 'allowed_oss',
'value': [],
'values': sorted([{'id': x, 'text': x} for x in OsDetector.knownOss], key=lambda x: x['text'].lower()), # TODO: We will fix this behavior after current admin client is fully removed
'label': ugettext('Allowed Devices'),
'tooltip': ugettext('If empty, any kind of device compatible with this transport will be allowed. Else, only devices compatible with selected values will be allowed'),
'type': 'multichoice',
'order': 102
})
field = self.addDefaultFields(factory().lookup(type_).guiDescription(), ['name', 'comments', 'tags', 'priority'])
field = self.addField(field, {
'name': 'nets_positive',
'value': True,
'label': ugettext('Network access'),
'tooltip': ugettext('If checked, the transport will be enabled for the selected networks. If unchecked, transport will be disabled for selected networks'),
'type': 'checkbox',
'order': 100, # At end
})
field = self.addField(field, {
'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
'label': ugettext('Networks'),
'tooltip': ugettext('Networks associated with this transport. If No network selected, will mean "all networks"'),
'type': 'multichoice',
'order': 101
})
field = self.addField(field, {
'name': 'allowed_oss',
'value': [],
'values': sorted([{'id': x, 'text': x} for x in OsDetector.knownOss], key=lambda x: x['text'].lower()), # TODO: We will fix this behavior after current admin client is fully removed
'label': ugettext('Allowed Devices'),
'tooltip': ugettext('If empty, any kind of device compatible with this transport will be allowed. Else, only devices compatible with selected values will be allowed'),
'type': 'multichoice',
'order': 102
})
field = self.addField(field, {
'name': 'pools',
'value': [],
'values': [{'id': x.id, 'text': x.name} for x in ServicePool.objects.all().order_by('name')], # TODO: We will fix this behavior after current admin client is fully removed
'label': ugettext('Service Pools'),
'tooltip': ugettext('Currently assigned services pools'),
'type': 'multichoice',
'order': 103
})
return field
except Exception:
self.invalidItemException()
@ -106,6 +118,7 @@ class Transports(ModelHandler):
'nets_positive': item.nets_positive,
'networks': [{'id': n.id} for n in item.networks.all()],
'allowed_oss': [{'id': x} for x in item.allowed_oss.split(',')] if item.allowed_oss != '' else [],
'pools': [{'id': x.id} for x in item.deployedServices.all()],
'deployed_count': item.deployedServices.count(),
'type': type_.type(),
'protocol': type_.protocol,
@ -123,9 +136,21 @@ class Transports(ModelHandler):
return
if networks is None:
return
logger.debug('Networks: {0}'.format(networks))
logger.debug('Networks: {}'.format(networks))
item.networks.set(Network.objects.filter(id__in=networks))
try:
pools = self._params['pools']
except Exception:
logger.debug('No pools')
pools = None
if pools is None:
return
logger.debug('Pools: %s', pools)
item.deployedServices.set(pools)
# try:
# oss = ','.join(self._params['allowed_oss'])
# except:

View File

@ -252,11 +252,17 @@ class Groups(DetailHandler):
'meta_if_any': i.meta_if_any
}
if i.is_meta:
val['groups'] = list(x.uuid for x in i.groups.all())
val['groups'] = list(x.uuid for x in i.groups.all().order_by('name'))
res.append(val)
if multi:
return res
return res[0]
# Add pools field if 1 item only
res = res[0]
if i.is_meta:
res['pools'] = [] # Meta groups do not have "assigned "pools, they get it from groups interaction
else:
res['pools'] = [v.uuid for v in i.deployedServices.all()]
return res
except:
logger.exception('REST groups')
self.invalidItemException()
@ -298,8 +304,10 @@ class Groups(DetailHandler):
try:
is_meta = self._params['type'] == 'meta'
meta_if_any = self._params.get('meta_if_any', False)
pools = self._params.get('pools', None)
logger.debug('Saving group {0} / {1}'.format(parent, item))
logger.debug('Meta any {}'.format(meta_if_any))
logger.debug('Pools: %s', pools)
valid_fields = ['name', 'comments', 'state']
fields = self.readFieldsFromParams(valid_fields)
is_pattern = fields.get('name', '').find('pat:') == 0
@ -328,7 +336,11 @@ class Groups(DetailHandler):
group.__dict__.update(toSave)
if is_meta:
group.groups = parent.groups.filter(uuid__in=self._params['groups'])
group.groups.set(parent.groups.filter(uuid__in=self._params['groups']))
if pools:
# Update pools
group.deployedServices.set(ServicePool.objects.filter(uuid__in=pools))
group.save()
except Group.DoesNotExist:

View File

@ -54,7 +54,7 @@ import logging
logger = logging.getLogger(__name__)
__updated__ = '2018-11-05'
__updated__ = '2018-11-20'
# a few constants
OVERVIEW = 'overview'
@ -635,7 +635,6 @@ class ModelHandler(BaseModelHandler):
# gui related
def getGui(self, type_):
self.invalidRequestException()
return None # Will never reach this because previous raises an exception
# Delete related, checks if the item can be deleted
# If it can't be so, raises an exception

View File

@ -224,6 +224,12 @@ class BasicModelRest
success: success_fnc
fail: fail_fnc
summary: (success_fnc, fail_fnc) ->
@get
id: "overview?summarize"
success: success_fnc
fail: fail_fnc
item: (itemId, success_fnc, fail_fnc) ->
@get

View File

@ -323,42 +323,47 @@ gui.authenticators.link = (event) ->
onEdit: (value, event, table, refreshFnc) ->
exec = (groups_all) ->
gui.tools.blockUI()
api.templates.get "group", (tmpl) -> # Get form template
group.rest.item value.id, (item) -> # Get item to edit
# Creates modal
modalId = gui.launchModal(gettext("Edit group") + " <b>" + item.name + "</b>", api.templates.evaluate(tmpl,
id: item.id
type: item.type
meta_if_any: item.meta_if_any
groupname: item.name
groupname_label: type.groupNameLabel
comments: item.comments
state: item.state
external: type.isExternal
canSearchGroups: type.canSearchGroups
groups: item.groups
groups_all: groups_all
))
gui.tools.applyCustoms modalId
gui.tools.unblockUI()
$(modalId + " .button-accept").click ->
fields = gui.forms.read(modalId)
gui.doLog "Fields", fields
group.rest.save fields, ((data) -> # Success on put
$(modalId).modal "hide"
refreshFnc()
gui.notify gettext("Group saved"), "success"
api.servicesPools.summary (servicePools) ->
gui.tools.blockUI()
api.templates.get "group", (tmpl) -> # Get form template
group.rest.item value.id, (item) -> # Get item to edit
if item.type is 'meta'
servicePools = undefined
# Creates modal
modalId = gui.launchModal(gettext("Edit group") + " <b>" + item.name + "</b>", api.templates.evaluate(tmpl,
id: item.id
type: item.type
meta_if_any: item.meta_if_any
groupname: item.name
groupname_label: type.groupNameLabel
comments: item.comments
state: item.state
external: type.isExternal
canSearchGroups: type.canSearchGroups
groups: item.groups
groups_all: groups_all
pools_all: servicePools
pools: item.pools
))
gui.tools.applyCustoms modalId
gui.tools.unblockUI()
$(modalId + " .button-accept").click ->
fields = gui.forms.read(modalId)
gui.doLog "Fields", fields
group.rest.save fields, ((data) -> # Success on put
$(modalId).modal "hide"
refreshFnc()
gui.notify gettext("Group saved"), "success"
return
), gui.failRequestModalFnc("Error saving group", true)
return
), gui.failRequestModalFnc("Error saving group", true)
return
return
return
return
if value.type is "meta"
# Meta will get all groups
@ -372,39 +377,43 @@ gui.authenticators.link = (event) ->
onNew: (t, table, refreshFnc) ->
exec = (groups_all) ->
gui.tools.blockUI()
api.templates.get "group", (tmpl) -> # Get form template
# Creates modal
if t is "meta"
title = gettext("New meta group")
else
title = gettext("New group")
modalId = gui.launchModal(title, api.templates.evaluate(tmpl,
type: t
groupname_label: type.groupNameLabel
external: type.isExternal
canSearchGroups: type.canSearchGroups
groups: []
groups_all: groups_all
))
gui.tools.unblockUI()
gui.tools.applyCustoms modalId
searchForm modalId, "group", id, gettext("Search groups"), gettext("Group"), gettext("Groups found") # Enable search button click, if it exist ofc
$(modalId + " .button-accept").click ->
fields = gui.forms.read(modalId)
gui.doLog "Fields", fields
group.rest.create fields, ((data) -> # Success on put
$(modalId).modal "hide"
refreshFnc()
gui.notify gettext("Group saved"), "success"
api.servicesPools.summary (servicePools) ->
gui.tools.blockUI()
api.templates.get "group", (tmpl) -> # Get form template
# Creates modal
if t is "meta"
title = gettext("New meta group")
servicePools = undefined # Clear service pools
else
title = gettext("New group")
modalId = gui.launchModal(title, api.templates.evaluate(tmpl,
type: t
groupname_label: type.groupNameLabel
external: type.isExternal
canSearchGroups: type.canSearchGroups
groups_all: groups_all
groups: []
pools_all: servicePools
pools: []
))
gui.tools.unblockUI()
gui.tools.applyCustoms modalId
searchForm modalId, "group", id, gettext("Search groups"), gettext("Group"), gettext("Groups found") # Enable search button click, if it exist ofc
$(modalId + " .button-accept").click ->
fields = gui.forms.read(modalId)
gui.doLog "Fields", fields
group.rest.create fields, ((data) -> # Success on put
$(modalId).modal "hide"
refreshFnc()
gui.notify gettext("Group saved"), "success"
return
), gui.failRequestModalFnc(gettext("Group saving error"), true)
return
), gui.failRequestModalFnc(gettext("Group saving error"), true)
return
return
return
if t is "meta"
# Meta will get all groups
group.rest.overview (groups) ->

View File

@ -76,5 +76,20 @@
</div>
{{/ if }}
{{# if pools_all }}
<div class="form-group">
<label for="id_state" class="col-sm-2 control-label">{% endverbatim %}{% trans 'Service Pools' %}{% verbatim %}</label>
<div class="col-sm-10">
<select multiple name="pools" class="selectpicker show-menu-arrow show-tick modal_field_data" data-style="btn-default" data-width="100%" id="id_state">
{{# each pools_all }}
<option value="{{ id }}"{{# ifbelongs id ../pools }} selected{{/ ifbelongs}}>{{ name }}</option>
{{/ each }}
</select>
</div>
</div>
{{/ if }}
</form>
{% endverbatim %}

View File

@ -39,7 +39,7 @@ from uds.core.util import OsDetector
import six
import shlex
__updated__ = '2018-05-18'
__updated__ = '2018-11-08'
class RDPFile(object):
@ -135,8 +135,8 @@ class RDPFile(object):
else:
params.append('/printer')
if self.compression:
params.append('/compression:on')
# if not self.compression:
# params.append('-compression')
if self.showWallpaper:
params.append('+themes')