forked from shaba/openuds
Merge remote-tracking branch 'origin/v2.2'
This commit is contained in:
commit
b9cb82c054
@ -64,6 +64,7 @@ class Services(DetailHandler): # pylint: disable=too-many-public-methods
|
||||
@staticmethod
|
||||
def serviceInfo(item):
|
||||
info = item.getType()
|
||||
|
||||
return {
|
||||
'icon': info.icon().replace('\n', ''),
|
||||
'needs_publication': info.publicationType is not None,
|
||||
@ -76,6 +77,7 @@ class Services(DetailHandler): # pylint: disable=too-many-public-methods
|
||||
'allowedProtocols': info.allowedProtocols,
|
||||
'servicesTypeProvided': info.servicesTypeProvided,
|
||||
'must_assign_manually': info.mustAssignManually,
|
||||
'can_reset': info.canReset,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
|
@ -73,7 +73,8 @@ class ServicesPools(ModelHandler):
|
||||
save_fields = ['name', 'short_name', 'comments', 'tags', 'service_id',
|
||||
'osmanager_id', 'image_id', 'servicesPoolGroup_id', 'initial_srvs',
|
||||
'cache_l1_srvs', 'cache_l2_srvs', 'max_srvs', 'show_transports',
|
||||
'allow_users_remove', 'ignores_unused']
|
||||
'allow_users_remove', 'allow_users_reset', 'ignores_unused']
|
||||
|
||||
remove_fields = ['osmanager_id', 'service_id']
|
||||
|
||||
table_title = _('Service Pools')
|
||||
@ -139,6 +140,7 @@ class ServicesPools(ModelHandler):
|
||||
'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),
|
||||
@ -191,13 +193,21 @@ class ServicesPools(ModelHandler):
|
||||
'type': gui.InputField.CHECKBOX_TYPE,
|
||||
'order': 111,
|
||||
'tab': ugettext('Advanced'),
|
||||
}, {
|
||||
'name': 'allow_users_reset',
|
||||
'value': False,
|
||||
'label': ugettext('Allow reset by users'),
|
||||
'tooltip': ugettext('If active, the user will be allowed to reset the service'),
|
||||
'type': gui.InputField.CHECKBOX_TYPE,
|
||||
'order': 112,
|
||||
'tab': ugettext('Advanced'),
|
||||
}, {
|
||||
'name': 'ignores_unused',
|
||||
'value': False,
|
||||
'label': ugettext('Ignores unused'),
|
||||
'tooltip': ugettext('If the option is enabled, UDS will not attempt to detect and remove the user services assigned but not in use.'),
|
||||
'type': gui.InputField.CHECKBOX_TYPE,
|
||||
'order': 112,
|
||||
'order': 113,
|
||||
'tab': ugettext('Advanced'),
|
||||
}, {
|
||||
'name': 'image_id',
|
||||
|
@ -51,6 +51,8 @@ import requests
|
||||
import json
|
||||
import logging
|
||||
|
||||
__updated__ = '2018-03-14'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
traceLogger = logging.getLogger('traceLog')
|
||||
|
||||
@ -363,10 +365,23 @@ class UserServiceManager(object):
|
||||
UserServiceOpChecker.makeUnique(uService, ui, state)
|
||||
return False
|
||||
|
||||
def reset(self, uService):
|
||||
UserService.objects.update()
|
||||
uService = UserService.objects.get(id=uService.id)
|
||||
if uService.deployed_service.service.getType().canReset is False:
|
||||
return
|
||||
|
||||
logger.debug('Reseting'.format(uService))
|
||||
|
||||
ui = uService.getInstance()
|
||||
try:
|
||||
ui.reset()
|
||||
except Exception:
|
||||
logger.exception('Reseting service')
|
||||
|
||||
def notifyPreconnect(self, uService, userName, protocol):
|
||||
|
||||
proxy = uService.deployed_service.proxy
|
||||
|
||||
url = uService.getCommsUrl()
|
||||
if url is None:
|
||||
logger.debug('No notification is made because agent does not supports notifications')
|
||||
|
@ -36,7 +36,7 @@ from uds.core import Environmentable
|
||||
from uds.core import Serializable
|
||||
from uds.core.util.State import State
|
||||
|
||||
__updated__ = '2017-09-29'
|
||||
__updated__ = '2018-03-14'
|
||||
|
||||
|
||||
class UserDeployment(Environmentable, Serializable):
|
||||
@ -574,6 +574,13 @@ class UserDeployment(Environmentable, Serializable):
|
||||
"""
|
||||
raise Exception('cancel method for class {0} not provided!'.format(self.__class__.__name__))
|
||||
|
||||
def reset(self):
|
||||
'''
|
||||
This method is invoked for "reset" an user service
|
||||
This method is not intended to be a task right now, it's more like the
|
||||
'''
|
||||
raise Exception('reset method for class {0} not provided!'.format(self.__class__.__name__))
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
Mainly used for debugging purposses
|
||||
|
@ -27,9 +27,9 @@
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
'''
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
@ -37,11 +37,11 @@ from uds.core import Module
|
||||
from uds.core.transports import protocols
|
||||
from . import types
|
||||
|
||||
__updated__ = '2017-01-12'
|
||||
__updated__ = '2018-03-14'
|
||||
|
||||
|
||||
class Service(Module):
|
||||
"""
|
||||
'''
|
||||
This class is in fact an interface, and represents a service, that is the
|
||||
definition of an offering for consumers (users).
|
||||
|
||||
@ -76,7 +76,7 @@ class Service(Module):
|
||||
only need data that is keeped at form fields, marshal and unmarshal and in fact
|
||||
not needed.
|
||||
|
||||
"""
|
||||
'''
|
||||
|
||||
# : Constant for indicating that max elements this service can deploy is unlimited.
|
||||
UNLIMITED = -1
|
||||
@ -170,79 +170,79 @@ class Service(Module):
|
||||
# : Default behavior is False (and most common), but some services may need to respawn a new "copy" on every launch
|
||||
spawnsNew = False
|
||||
|
||||
# : If the service allows "reset", here we will announce it
|
||||
# : Defaults to False
|
||||
canReset = False
|
||||
|
||||
# : 'kind' of services that this service provides:
|
||||
# : For example, VDI, VAPP, ...
|
||||
servicesTypeProvided = types.ALL
|
||||
|
||||
# : If the service can provide any other option on release appart of "delete" & "keep assigned"
|
||||
# : Defaults to None (no any other options are provided)
|
||||
actionsOnRelease = None
|
||||
|
||||
def __init__(self, environment, parent, values=None):
|
||||
"""
|
||||
'''
|
||||
Do not forget to invoke this in your derived class using "super(self.__class__, self).__init__(environment, parent, values)".
|
||||
We want to use the env, parent methods outside class. If not called, you must implement your own methods
|
||||
cache and storage are "convenient" methods to access _env.cache and _env.storage
|
||||
"""
|
||||
'''
|
||||
super(Service, self).__init__(environment, values)
|
||||
self._provider = parent
|
||||
self.initialize(values)
|
||||
|
||||
def initialize(self, values):
|
||||
"""
|
||||
'''
|
||||
This method will be invoked from __init__ constructor.
|
||||
This is provided so you don't have to provide your own __init__ method,
|
||||
and invoke base methods.
|
||||
This will get invoked when all initialization stuff is done
|
||||
|
||||
Args:
|
||||
values: If values is not none, this object is being initialized
|
||||
Values: If values is not none, this object is being initialized
|
||||
from administration interface, and not unmarshal will be done.
|
||||
If it's None, this is initialized internally, and unmarshal will
|
||||
be called after this.
|
||||
|
||||
Default implementation does nothing
|
||||
"""
|
||||
'''
|
||||
pass
|
||||
|
||||
def parent(self):
|
||||
"""
|
||||
'''
|
||||
Utility method to access parent provider for this service
|
||||
|
||||
Returns
|
||||
|
||||
Parent provider instance object (not database object)
|
||||
"""
|
||||
'''
|
||||
return self._provider
|
||||
|
||||
def requestServicesForAssignation(self, **kwargs):
|
||||
"""
|
||||
'''
|
||||
override this if mustAssignManualy is True
|
||||
@params kwargs: Named arguments
|
||||
@return an array with the services that we can assign (they must be of type deployedType)
|
||||
We will access the returned array in "name" basis. This means that the service will be assigned by "name", so be care that every single service
|
||||
returned are not repeated... :-)
|
||||
"""
|
||||
'''
|
||||
raise Exception('The class {0} has been marked as manually asignable but no requestServicesForAssignetion provided!!!'.format(self.__class__.__name__))
|
||||
|
||||
def macGenerator(self):
|
||||
"""
|
||||
'''
|
||||
Utility method to access provided macs generator (inside environment)
|
||||
|
||||
Returns the environment unique mac addresses generator
|
||||
"""
|
||||
'''
|
||||
return self.idGenerators('mac')
|
||||
|
||||
def nameGenerator(self):
|
||||
"""
|
||||
'''
|
||||
Utility method to access provided names generator (inside environment)
|
||||
|
||||
Returns the environment unique name generator
|
||||
"""
|
||||
'''
|
||||
return self.idGenerators('name')
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
'''
|
||||
String method, mainly used for debugging purposes
|
||||
"""
|
||||
'''
|
||||
return "Base Service Provider"
|
||||
|
@ -39,7 +39,7 @@ import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
__updated__ = '2016-04-25'
|
||||
__updated__ = '2018-03-14'
|
||||
|
||||
|
||||
class ServiceProvider(Module):
|
||||
|
@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.9 on 2018-03-14 06:06
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('uds', '0026_auto_20180302_0525'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='deployedservice',
|
||||
name='allow_users_reset',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
@ -63,7 +63,7 @@ import logging
|
||||
import pickle
|
||||
import six
|
||||
|
||||
__updated__ = '2018-02-14'
|
||||
__updated__ = '2018-03-14'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -86,7 +86,10 @@ class DeployedService(UUIDModel, TaggingMixin):
|
||||
show_transports = models.BooleanField(default=True)
|
||||
visible = models.BooleanField(default=True)
|
||||
allow_users_remove = models.BooleanField(default=False)
|
||||
allow_users_reset = models.BooleanField(default=False)
|
||||
|
||||
ignores_unused = models.BooleanField(default=False)
|
||||
|
||||
image = models.ForeignKey(Image, null=True, blank=True, related_name='deployedServices', on_delete=models.SET_NULL)
|
||||
|
||||
servicesPoolGroup = models.ForeignKey(ServicesPoolGroup, null=True, blank=True, related_name='servicesPools', on_delete=models.SET_NULL)
|
||||
|
@ -72,6 +72,7 @@ gui.servicesPools.link = (event) ->
|
||||
serviceChangedFnc = (formId) ->
|
||||
$fld = $(formId + " [name=\"service_id\"]")
|
||||
$osmFld = $(formId + " [name=\"osmanager_id\"]")
|
||||
$canResetFld = $(formId + " [name=\"allow_users_reset\"]")
|
||||
selectors = []
|
||||
$.each [
|
||||
"initial_srvs"
|
||||
@ -89,6 +90,13 @@ gui.servicesPools.link = (event) ->
|
||||
unless $fld.val() is -1
|
||||
api.providers.service $fld.val(), (data) ->
|
||||
gui.doLog "Onchange", data
|
||||
if $canResetFld.bootstrapSwitch("readonly") == data.info.can_reset
|
||||
gui.doLog('reset doent not match field')
|
||||
$canResetFld.bootstrapSwitch "toggleReadonly", true
|
||||
if data.info.can_reset is false
|
||||
gui.doLog($canResetFld.bootstrapSwitch("readonly"), data.info.can_reset)
|
||||
|
||||
|
||||
if data.info.needs_manager is false
|
||||
$osmFld.prop "disabled", "disabled"
|
||||
else
|
||||
|
@ -50,6 +50,9 @@
|
||||
{% if ser.allow_users_remove %}
|
||||
<span data-href="{% url 'Releaser' idService=ser.id %}" class="release fa fa-trash"> </span>
|
||||
{% endif %}
|
||||
{% if ser.allow_users_reset %}
|
||||
<span data-href="{% url 'Reseter' idService=ser.id %}" class="reseter fa fa-refresh"> </span>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
@ -284,6 +287,10 @@
|
||||
span.gear > span.release {
|
||||
cursor: cell;
|
||||
}
|
||||
|
||||
span.gear > span.reseter {
|
||||
cursor: cell;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
@ -377,6 +384,26 @@
|
||||
return false;
|
||||
});
|
||||
|
||||
$('div.service:not(.maintenance, .notaccesible) > span.gear > span.release').on("click", function (event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
if ( confirm("{%trans 'Are you sure that you want to release this service. Its current content will be lost!' %}") ) {
|
||||
window.location.href = $(this).attr('data-href');
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$('div.service:not(.maintenance, .notaccesible) > span.gear > span.reseter').on("click", function (event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
if ( confirm("{%trans 'Are you sure that you want to reset this service. USE WITH CAUTION!' %}") ) {
|
||||
window.location.href = $(this).attr('data-href');
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$(".maintenance").click( function(event) {
|
||||
$('#maintenance-dialog').modal({
|
||||
keyboard: false
|
||||
|
@ -73,7 +73,7 @@ urlpatterns = [
|
||||
|
||||
# Releaser
|
||||
re_path(r'^release/(?P<idService>.+)$', uds.web.views.release, name='Releaser'),
|
||||
|
||||
re_path(r'^reset/(?P<idService>.+)$', 'web.views.reset', name='Reseter'),
|
||||
# Custom authentication callback
|
||||
re_path(r'^auth/(?P<authName>.+)', uds.web.views.authCallback, name='uds.web.views.authCallback'),
|
||||
re_path(r'^authinfo/(?P<authName>.+)', uds.web.views.authInfo, name='uds.web.views.authInfo'),
|
||||
|
@ -35,7 +35,7 @@ import logging
|
||||
from .login import login, logout, customAuth
|
||||
from .index import index, about
|
||||
from .prefs import prefs
|
||||
from .service import transportOwnLink, transportIcon, clientEnabler, serviceImage, release
|
||||
from .service import transportOwnLink, transportIcon, clientEnabler, serviceImage, release, reset
|
||||
from .auth import authCallback, authInfo, ticketAuth
|
||||
from .download import download
|
||||
from .client_download import client_downloads, plugin_detection
|
||||
@ -43,4 +43,6 @@ from ..errors import error
|
||||
from .images import image
|
||||
from .file_storage import file_storage
|
||||
|
||||
__updated__ = '2018-03-14'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -49,7 +49,7 @@ import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
__updated__ = '2018-02-14'
|
||||
__updated__ = '2018-03-14'
|
||||
|
||||
|
||||
def about(request):
|
||||
@ -137,6 +137,7 @@ def index(request):
|
||||
'imageId': imageId,
|
||||
'show_transports': servicePool.show_transports,
|
||||
'allow_users_remove': servicePool.allow_users_remove,
|
||||
'allow_users_reset': servicePool.allow_users_reset,
|
||||
'maintenance': servicePool.isInMaintenance(),
|
||||
'not_accesible': not servicePool.isAccessAllowed(),
|
||||
'in_use': svr.in_use,
|
||||
@ -196,6 +197,7 @@ def index(request):
|
||||
'imageId': imageId,
|
||||
'show_transports': svr.show_transports,
|
||||
'allow_users_remove': svr.allow_users_remove,
|
||||
'allow_users_reset': svr.allow_users_reset,
|
||||
'maintenance': svr.isInMaintenance(),
|
||||
'not_accesible': not svr.isAccessAllowed(),
|
||||
'in_use': in_use,
|
||||
|
@ -54,6 +54,8 @@ import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
__updated__ = '2018-03-14'
|
||||
|
||||
|
||||
@webLoginRequired(admin=False)
|
||||
def transportOwnLink(request, idService, idTransport):
|
||||
@ -154,7 +156,7 @@ def clientEnabler(request, idService, idTransport):
|
||||
def release(request, idService):
|
||||
logger.debug('ID Service: {}'.format(idService))
|
||||
userService = userServiceManager().locateUserService(request.user, idService, create=False)
|
||||
logger.debug('UserSrvice: >{}<'.format(userService))
|
||||
logger.debug('UserService: >{}<'.format(userService))
|
||||
if userService is not None and userService.deployed_service.allow_users_remove:
|
||||
log.doLog(
|
||||
userService.deployed_service,
|
||||
@ -167,3 +169,23 @@ def release(request, idService):
|
||||
|
||||
return HttpResponseRedirect(reverse('Index'))
|
||||
|
||||
|
||||
@webLoginRequired(admin=False)
|
||||
@never_cache
|
||||
def reset(request, idService):
|
||||
logger.debug('ID Service: {}'.format(idService))
|
||||
userService = userServiceManager().locateUserService(request.user, idService, create=False)
|
||||
logger.debug('UserService: >{}<'.format(userService))
|
||||
if (userService is not None and userService.deployed_service.allow_users_reset
|
||||
and userService.deployed_service.service.getType().canReset):
|
||||
log.doLog(
|
||||
userService.deployed_service,
|
||||
log.INFO,
|
||||
"Reseting User Service {} as requested by {} from {}".format(userService.friendly_name, request.user.pretty_name, request.ip),
|
||||
log.WEB
|
||||
)
|
||||
# userServiceManager().requestLogoff(userService)
|
||||
userServiceManager().reset(userService)
|
||||
|
||||
return HttpResponseRedirect(reverse('Index'))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user