forked from shaba/openuds
Added metapools capacity of show grouped pools transports
This commit is contained in:
parent
ce73d4e29f
commit
e9a719a2eb
@ -63,7 +63,7 @@ class MetaPools(ModelHandler):
|
||||
}
|
||||
|
||||
save_fields = ['name', 'short_name', 'comments', 'tags',
|
||||
'image_id', 'servicesPoolGroup_id', 'visible', 'policy', 'calendar_message']
|
||||
'image_id', 'servicesPoolGroup_id', 'visible', 'policy', 'calendar_message', 'transport_grouping']
|
||||
|
||||
table_title = _('Meta Pools')
|
||||
table_fields = [
|
||||
@ -74,6 +74,7 @@ class MetaPools(ModelHandler):
|
||||
{'user_services_in_preparation': {'title': _('In Preparation')}},
|
||||
{'visible': {'title': _('Visible'), 'type': 'callback'}},
|
||||
{'pool_group_name': {'title': _('Pool Group')}},
|
||||
{'label': {'title': _('Label')}},
|
||||
{'tags': {'title': _('tags'), 'visible': False}},
|
||||
]
|
||||
|
||||
@ -113,6 +114,7 @@ class MetaPools(ModelHandler):
|
||||
'fallbackAccess': item.fallbackAccess,
|
||||
'permission': permissions.getEffectivePermission(self._user, item),
|
||||
'calendar_message': item.calendar_message,
|
||||
'transport_grouping': item.transport_grouping
|
||||
}
|
||||
|
||||
return val
|
||||
@ -135,7 +137,7 @@ class MetaPools(ModelHandler):
|
||||
'tooltip': ugettext('Image assocciated with this service'),
|
||||
'type': gui.InputField.IMAGECHOICE_TYPE,
|
||||
'order': 120,
|
||||
'tab': ugettext('Display'),
|
||||
'tab': gui.DISPLAY_TAB,
|
||||
}, {
|
||||
'name': 'servicesPoolGroup_id',
|
||||
'values': [gui.choiceImage(-1, _('Default'), DEFAULT_THUMB_BASE64)] + gui.sortedChoices([gui.choiceImage(v.uuid, v.name, v.thumb64) for v in ServicePoolGroup.objects.all()]),
|
||||
@ -143,7 +145,7 @@ class MetaPools(ModelHandler):
|
||||
'tooltip': ugettext('Pool group for this pool (for pool classify on display)'),
|
||||
'type': gui.InputField.IMAGECHOICE_TYPE,
|
||||
'order': 121,
|
||||
'tab': ugettext('Display'),
|
||||
'tab': gui.DISPLAY_TAB,
|
||||
}, {
|
||||
'name': 'visible',
|
||||
'value': True,
|
||||
@ -151,7 +153,7 @@ class MetaPools(ModelHandler):
|
||||
'tooltip': ugettext('If active, metapool will be visible for users'),
|
||||
'type': gui.InputField.CHECKBOX_TYPE,
|
||||
'order': 123,
|
||||
'tab': ugettext('Display'),
|
||||
'tab': gui.DISPLAY_TAB,
|
||||
}, {
|
||||
'name': 'calendar_message',
|
||||
'value': '',
|
||||
@ -159,7 +161,15 @@ class MetaPools(ModelHandler):
|
||||
'tooltip': ugettext('Custom message to be shown to users if access is limited by calendar rules.'),
|
||||
'type': gui.InputField.TEXT_TYPE,
|
||||
'order': 124,
|
||||
'tab': ugettext('Display'),
|
||||
'tab': gui.DISPLAY_TAB,
|
||||
}, {
|
||||
'name': 'transport_grouping',
|
||||
'values': [gui.choiceItem(k, str(v)) for k, v in MetaPool.TRANSPORT_SELECT.items()],
|
||||
'label': ugettext('Transport Selection'),
|
||||
'tooltip': ugettext('Transport selection policy'),
|
||||
'type': gui.InputField.CHOICE_TYPE,
|
||||
'order': 125,
|
||||
'tab': gui.DISPLAY_TAB
|
||||
}]:
|
||||
self.addField(localGUI, field)
|
||||
|
||||
|
@ -36,6 +36,7 @@ import typing
|
||||
from django.utils.translation import ugettext_lazy as _, ugettext
|
||||
from uds.models import Transport, Network, ServicePool
|
||||
from uds.core import transports
|
||||
from uds.core.ui import gui
|
||||
from uds.core.util import permissions
|
||||
from uds.core.util import os_detector as OsDetector
|
||||
|
||||
@ -49,7 +50,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class Transports(ModelHandler):
|
||||
model = Transport
|
||||
save_fields = ['name', 'comments', 'tags', 'priority', 'nets_positive', 'allowed_oss']
|
||||
save_fields = ['name', 'comments', 'tags', 'priority', 'nets_positive', 'allowed_oss', 'label']
|
||||
|
||||
table_title = _('Transports')
|
||||
table_fields = [
|
||||
@ -107,6 +108,16 @@ class Transports(ModelHandler):
|
||||
'type': 'multichoice',
|
||||
'order': 103
|
||||
})
|
||||
field = self.addField(field, {
|
||||
'name': 'label',
|
||||
'length': 32,
|
||||
'value': '',
|
||||
'label': ugettext('Label'),
|
||||
'tooltip': ugettext('Metapool transport label (only used on metapool transports grouping)'),
|
||||
'type': 'text',
|
||||
'order': 201,
|
||||
'tab': gui.ADVANCED_TAB
|
||||
})
|
||||
|
||||
return field
|
||||
|
||||
@ -120,6 +131,7 @@ class Transports(ModelHandler):
|
||||
'comments': item.comments,
|
||||
'priority': item.priority,
|
||||
'nets_positive': item.nets_positive,
|
||||
'label': item.label,
|
||||
'networks': [{'id': n.uuid} for n in item.networks.all()],
|
||||
'allowed_oss': [{'id': x} for x in item.allowed_oss.split(',')] if item.allowed_oss != '' else [],
|
||||
'pools': pools,
|
||||
|
@ -749,7 +749,7 @@ class UserServiceManager:
|
||||
Get service info from user service
|
||||
"""
|
||||
if idService[0] == 'M': # Meta pool
|
||||
return self.getMeta(user, srcIp, os, idService[1:])
|
||||
return self.getMeta(user, srcIp, os, idService[1:], idTransport)
|
||||
|
||||
userService = self.locateUserService(user, idService, create=True)
|
||||
|
||||
@ -908,6 +908,7 @@ class UserServiceManager:
|
||||
srcIp: str,
|
||||
os: typing.MutableMapping,
|
||||
idMetaPool: str,
|
||||
idTransport: str,
|
||||
clientHostName: typing.Optional[str] = None,
|
||||
) -> typing.Tuple[
|
||||
typing.Optional[str],
|
||||
@ -953,7 +954,13 @@ class UserServiceManager:
|
||||
) -> typing.Optional[typing.Tuple[ServicePool, Transport]]:
|
||||
found = None
|
||||
t: Transport
|
||||
for t in pool.transports.all().order_by('priority'):
|
||||
if idTransport == 'meta': # Autoselected:
|
||||
q = pool.transports.all().order_by('priority')
|
||||
elif idTransport[:6] == 'LABEL:':
|
||||
q = pool.transports.filter(label=idTransport[6:])
|
||||
else:
|
||||
q = pool.transports.filter(uuid=idTransport)
|
||||
for t in q:
|
||||
typeTrans = t.getType()
|
||||
if (
|
||||
t.getType()
|
||||
|
23
server/src/uds/migrations/0040_auto_20210422_1340.py
Normal file
23
server/src/uds/migrations/0040_auto_20210422_1340.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Generated by Django 3.2 on 2021-04-22 13:40
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('uds', '0039_auto_20201111_1329'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='metapool',
|
||||
name='transport_grouping',
|
||||
field=models.IntegerField(default=0),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transport',
|
||||
name='label',
|
||||
field=models.CharField(db_index=True, default='', max_length=32),
|
||||
),
|
||||
]
|
@ -68,12 +68,22 @@ class MetaPool(UUIDModel, TaggingMixin): # type: ignore
|
||||
PRIORITY_POOL = 1
|
||||
MOST_AVAILABLE_BY_NUMBER = 2
|
||||
|
||||
TYPES = {
|
||||
TYPES: typing.Mapping[int, str] = {
|
||||
ROUND_ROBIN_POOL: _('Evenly distributed'),
|
||||
PRIORITY_POOL: _('Priority'),
|
||||
MOST_AVAILABLE_BY_NUMBER: _('Greater % available'),
|
||||
}
|
||||
|
||||
# Type of transport grouping
|
||||
AUTO_TRANSPORT_SELECT = 0
|
||||
COMMON_TRANSPORT_SELECT = 1
|
||||
LABEL_TRANSPORT_SELECT = 2
|
||||
TRANSPORT_SELECT: typing.Mapping[int, str] = {
|
||||
AUTO_TRANSPORT_SELECT: _('Automatic selection'),
|
||||
COMMON_TRANSPORT_SELECT: _('Use only common transports'),
|
||||
LABEL_TRANSPORT_SELECT: _('Group Transports by label')
|
||||
}
|
||||
|
||||
name = models.CharField(max_length=128, default='')
|
||||
short_name = models.CharField(max_length=32, default='')
|
||||
comments = models.CharField(max_length=256, default='')
|
||||
@ -103,6 +113,8 @@ class MetaPool(UUIDModel, TaggingMixin): # type: ignore
|
||||
|
||||
# Pool selection policy
|
||||
policy = models.SmallIntegerField(default=0)
|
||||
# If use common transports instead of auto select one
|
||||
transport_grouping = models.IntegerField(default=0)
|
||||
|
||||
# "fake" declarations for type checking
|
||||
objects: 'models.BaseManager[MetaPool]'
|
||||
|
@ -62,6 +62,8 @@ class Transport(ManagedObjectModel, TaggingMixin):
|
||||
nets_positive = models.BooleanField(default=False)
|
||||
# We store allowed oss as a comma-separated list
|
||||
allowed_oss = models.CharField(max_length=255, default='')
|
||||
# Label, to group transports on meta pools
|
||||
label = models.CharField(max_length=32, default='', db_index=True)
|
||||
|
||||
# "fake" declarations for type checking
|
||||
objects: 'models.BaseManager[Transport]'
|
||||
|
File diff suppressed because one or more lines are too long
@ -93,6 +93,6 @@
|
||||
</svg>
|
||||
</div>
|
||||
</uds-root>
|
||||
<script src="/uds/res/admin/runtime.js?stamp=1619085422" defer></script><script src="/uds/res/admin/polyfills-es5.js?stamp=1619085422" nomodule defer></script><script src="/uds/res/admin/polyfills.js?stamp=1619085422" defer></script><script src="/uds/res/admin/main.js?stamp=1619085422" defer></script></body>
|
||||
<script src="/uds/res/admin/runtime.js?stamp=1619092209" defer></script><script src="/uds/res/admin/polyfills-es5.js?stamp=1619092209" nomodule defer></script><script src="/uds/res/admin/polyfills.js?stamp=1619092209" defer></script><script src="/uds/res/admin/main.js?stamp=1619092209" defer></script></body>
|
||||
|
||||
</html>
|
||||
|
@ -101,12 +101,12 @@ urlpatterns = [
|
||||
re_path(r'^uds/utility/download/(?P<idDownload>[a-zA-Z0-9-]*)$', uds.web.views.download, name='utility.downloader'),
|
||||
|
||||
# WEB API path (not REST api, frontend)
|
||||
re_path(r'^uds/webapi/img/transport/(?P<idTrans>[a-zA-Z0-9-]+)$', uds.web.views.transportIcon, name='webapi.transportIcon'),
|
||||
re_path(r'^uds/webapi/img/transport/(?P<idTrans>[a-zA-Z0-9:-]+)$', uds.web.views.transportIcon, name='webapi.transportIcon'),
|
||||
re_path(r'^uds/webapi/img/gallery/(?P<idImage>[a-zA-Z0-9-]+)$', uds.web.views.image, name='webapi.galleryImage'),
|
||||
|
||||
re_path(r'^uds/webapi/action/(?P<idService>.+)/enable/(?P<idTransport>[a-zA-Z0-9-]+)$', uds.web.views.userServiceEnabler, name='webapi.enabler'),
|
||||
re_path(r'^uds/webapi/action/(?P<idService>.+)/enable/(?P<idTransport>[a-zA-Z0-9:-]+)$', uds.web.views.userServiceEnabler, name='webapi.enabler'),
|
||||
|
||||
re_path(r'^uds/webapi/action/(?P<idService>.+)/(?P<actionString>[a-zA-Z0-9-]+)$', uds.web.views.action, name='webapi.action'),
|
||||
re_path(r'^uds/webapi/action/(?P<idService>.+)/(?P<actionString>[a-zA-Z0-9:-]+)$', uds.web.views.action, name='webapi.action'),
|
||||
|
||||
# Services list, ...
|
||||
path(r'uds/webapi/services', uds.web.views.modern.servicesData, name='webapi.services'),
|
||||
|
@ -101,6 +101,34 @@ def getServicesData(
|
||||
|
||||
logger.debug('Checking meta pools: %s', availMetaPools)
|
||||
services = []
|
||||
|
||||
# Metapool helpers
|
||||
def transportIterator(member) -> typing.Iterable[Transport]:
|
||||
for t in member.pool.transports.all():
|
||||
typeTrans = t.getType()
|
||||
if (
|
||||
typeTrans
|
||||
and t.validForIp(request.ip)
|
||||
and typeTrans.supportsOs(osName)
|
||||
and t.validForOs(osName)
|
||||
):
|
||||
yield t
|
||||
|
||||
def buildMetaTransports(
|
||||
transports: typing.Iterable[Transport],
|
||||
isLabel: bool,
|
||||
) -> typing.List[typing.Mapping[str, typing.Any]]:
|
||||
idd = lambda i: i.uuid if not isLabel else 'LABEL:' + i.label
|
||||
return [
|
||||
{
|
||||
'id': idd(i),
|
||||
'name': i.name,
|
||||
'link': html.udsAccessLink(request, 'M' + meta.uuid, idd(i)),
|
||||
'priority': 0,
|
||||
}
|
||||
for i in transports
|
||||
]
|
||||
|
||||
# Preload all assigned user services for this user
|
||||
# Add meta pools data first
|
||||
for meta in availMetaPools:
|
||||
@ -108,35 +136,48 @@ def getServicesData(
|
||||
metaTransports: typing.List[typing.Mapping[str, typing.Any]] = []
|
||||
in_use = meta.number_in_use > 0 # type: ignore # anotated value
|
||||
|
||||
if True: # If meta.use_common_transports
|
||||
inAll: typing.Optional[typing.Set[str]] = None
|
||||
tmpSet: typing.Set[str]
|
||||
if (
|
||||
meta.transport_grouping == MetaPool.COMMON_TRANSPORT_SELECT
|
||||
): # If meta.use_common_transports
|
||||
# only keep transports that are in ALL members
|
||||
inAll: typing.Optional[typing.Set[str]] = None
|
||||
for member in meta.members.all():
|
||||
tmpSet: typing.Set[str] = set()
|
||||
for t in member.pool.transports.all():
|
||||
if inAll is None: # if first...
|
||||
typeTrans = t.getType()
|
||||
if (
|
||||
typeTrans
|
||||
and t.validForIp(request.ip)
|
||||
and typeTrans.supportsOs(osName)
|
||||
and t.validForOs(osName)
|
||||
):
|
||||
tmpSet.add(t.uuid)
|
||||
elif t.uuid in inAll:
|
||||
for member in meta.members.all().order_by('priority'):
|
||||
tmpSet = set()
|
||||
# if first pool, get all its transports and check that are valid
|
||||
for t in transportIterator(member):
|
||||
if inAll is None:
|
||||
tmpSet.add(t.uuid)
|
||||
|
||||
elif t.uuid in inAll: # For subsequent, reduce...
|
||||
tmpSet.add(t.uuid)
|
||||
|
||||
inAll = tmpSet
|
||||
# tmpSet has ALL common transports
|
||||
metaTransports = [
|
||||
{
|
||||
'id': i.uuid,
|
||||
'name': i.name,
|
||||
'link': html.udsAccessLink(request, 'M' + meta.uuid, i.uuid),
|
||||
'priority': 0,
|
||||
}
|
||||
for i in Transport.objects.filter(uuid__in=inAll or [])
|
||||
]
|
||||
metaTransports = buildMetaTransports(
|
||||
Transport.objects.filter(uuid__in=inAll or []),
|
||||
isLabel=False
|
||||
)
|
||||
elif meta.transport_grouping == MetaPool.LABEL_TRANSPORT_SELECT:
|
||||
ltrans: typing.MutableMapping[str, Transport] = {}
|
||||
for member in meta.members.all():
|
||||
tmpSet = set()
|
||||
# if first pool, get all its transports and check that are valid
|
||||
for t in transportIterator(member):
|
||||
if not t.label:
|
||||
continue
|
||||
if t.label not in ltrans:
|
||||
ltrans[t.label] = t
|
||||
if inAll is None:
|
||||
tmpSet.add(t.label)
|
||||
elif t.label in inAll: # For subsequent, reduce...
|
||||
tmpSet.add(t.label)
|
||||
|
||||
inAll = tmpSet
|
||||
# tmpSet has ALL common transports
|
||||
metaTransports = buildMetaTransports(
|
||||
(v for k, v in ltrans.items() if k in (inAll or set())),
|
||||
isLabel=True
|
||||
)
|
||||
else:
|
||||
for member in meta.members.all():
|
||||
# if pool.isInMaintenance():
|
||||
@ -187,7 +228,7 @@ def getServicesData(
|
||||
'group': group,
|
||||
'transports': metaTransports,
|
||||
'imageId': meta.image and meta.image.uuid or 'x',
|
||||
'show_transports': False,
|
||||
'show_transports': len(metaTransports) > 1,
|
||||
'allow_users_remove': False,
|
||||
'allow_users_reset': False,
|
||||
'maintenance': meta.isInMaintenance(),
|
||||
@ -209,7 +250,7 @@ def getServicesData(
|
||||
use_count = str(sPool.usage_count) # type: ignore # anotated value
|
||||
left_count = str(sPool.max_srvs - sPool.usage_count) # type: ignore # anotated value
|
||||
|
||||
trans = []
|
||||
trans: typing.List[typing.MutableMapping[str, typing.Any]] = []
|
||||
for t in sorted(
|
||||
sPool.transports.all(), key=lambda x: x.priority
|
||||
): # In memory sort, allows reuse prefetched and not too big array
|
||||
|
@ -100,7 +100,12 @@ def transportOwnLink(
|
||||
@cache_page(3600, key_prefix='img', cache='memory')
|
||||
def transportIcon(request: 'ExtendedHttpRequest', idTrans: str) -> HttpResponse:
|
||||
try:
|
||||
transport: Transport = Transport.objects.get(uuid=processUuid(idTrans))
|
||||
transport: Transport
|
||||
if idTrans[:6] == 'LABEL:':
|
||||
# Get First label
|
||||
transport = Transport.objects.filter(label=idTrans[6:]).order_by('priority')[0]
|
||||
else:
|
||||
transport = Transport.objects.get(uuid=processUuid(idTrans))
|
||||
return HttpResponse(transport.getInstance().icon(), content_type='image/png')
|
||||
except Exception:
|
||||
return HttpResponse(DEFAULT_IMAGE, content_type='image/png')
|
||||
|
Loading…
Reference in New Issue
Block a user