mirror of https://github.com/jumpserver/jumpserver
perf: 优化 applet 账号选择
parent
a297355a0d
commit
680d31dad2
|
@ -13,6 +13,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AddField(
|
||||
model_name='applet',
|
||||
name='can_concurrent',
|
||||
field=models.BooleanField(default=True, verbose_name='Can concurrent'),
|
||||
field=models.BooleanField(default=False, verbose_name='Can concurrent'),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -39,7 +39,7 @@ class Applet(JMSBaseModel):
|
|||
is_active = models.BooleanField(default=True, verbose_name=_('Is active'))
|
||||
builtin = models.BooleanField(default=False, verbose_name=_('Builtin'))
|
||||
protocols = models.JSONField(default=list, verbose_name=_('Protocol'))
|
||||
can_concurrent = models.BooleanField(default=True, verbose_name=_('Can concurrent'))
|
||||
can_concurrent = models.BooleanField(default=False, verbose_name=_('Can concurrent'))
|
||||
tags = models.JSONField(default=list, verbose_name=_('Tags'))
|
||||
comment = models.TextField(default='', blank=True, verbose_name=_('Comment'))
|
||||
hosts = models.ManyToManyField(
|
||||
|
@ -193,38 +193,59 @@ class Applet(JMSBaseModel):
|
|||
cache.set(prefer_host_account_key, account.id, timeout=None)
|
||||
return account
|
||||
|
||||
accounts_using_key_tmpl = 'applet_host_accounts_{}_{}_{}'
|
||||
|
||||
def select_a_public_account(self, user, host, valid_accounts):
|
||||
using_keys = cache.keys(self.accounts_using_key_tmpl.format(host.id, '*', '*')) or []
|
||||
accounts_username_used = list(cache.get_many(using_keys).values())
|
||||
logger.debug('Applet host account using: {}: {}'.format(host.name, accounts_username_used))
|
||||
accounts = valid_accounts.exclude(username__in=accounts_username_used)
|
||||
public_accounts = accounts.filter(username__startswith='jms_')
|
||||
if not public_accounts:
|
||||
public_accounts = accounts.exclude(username__in=['Administrator', 'root'])
|
||||
account = self.random_select_prefer_account(user, host, public_accounts)
|
||||
return account
|
||||
|
||||
def try_to_use_private_account(self, user, host, valid_accounts):
|
||||
host_can_concurrent = str(host.deploy_options.get('RDS_fSingleSessionPerUser', 0)) == '0'
|
||||
app_can_concurrent = self.can_concurrent or self.type == 'web'
|
||||
all_can_concurrent = host_can_concurrent and app_can_concurrent
|
||||
|
||||
private_account = valid_accounts.filter(username='js_{}'.format(user.username)).first()
|
||||
if not private_account:
|
||||
return None
|
||||
# 优先使用 private account,支持并发或者不支持并发时,如果私有没有被占用,则使用私有
|
||||
account = None
|
||||
# 如果都支持,不管私有是否被占用,都使用私有
|
||||
if all_can_concurrent:
|
||||
account = private_account
|
||||
# 如果主机都不支持并发,则查询一下私有账号有没有任何应用使用,如果没有被使用,则使用私有
|
||||
elif not host_can_concurrent:
|
||||
private_using_key = self.accounts_using_key_tmpl.format(host.id, private_account.username, '*')
|
||||
private_is_using = len(cache.keys(private_using_key, [])) > 0
|
||||
if not private_is_using:
|
||||
account = private_account
|
||||
# 如果主机支持,但是应用不支持并发,则查询一下私有账号有没有被这个应用使用, 如果没有被使用,则使用私有
|
||||
elif host_can_concurrent and not app_can_concurrent:
|
||||
private_app_using_key = self.accounts_using_key_tmpl.format(host.id, private_account.username, self.name)
|
||||
private_is_using_by_this_app = cache.get(private_app_using_key, False)
|
||||
if not private_is_using_by_this_app:
|
||||
account = private_account
|
||||
return account
|
||||
|
||||
def select_host_account(self, user, asset):
|
||||
# 选择激活的发布机
|
||||
host = self.select_host(user, asset)
|
||||
if not host:
|
||||
return None
|
||||
host_concurrent = str(host.deploy_options.get('RDS_fSingleSessionPerUser', 0)) == '0'
|
||||
can_concurrent = (self.can_concurrent or self.type == 'web') and host_concurrent
|
||||
|
||||
accounts = host.accounts.all().filter(is_active=True, privileged=False)
|
||||
private_account = accounts.filter(username='js_{}'.format(user.username)).first()
|
||||
accounts_using_key_tmpl = 'applet_host_accounts_{}_{}'
|
||||
valid_accounts = host.accounts.all().filter(is_active=True, privileged=False)
|
||||
account = self.try_to_use_private_account(user, host, valid_accounts)
|
||||
if not account:
|
||||
account = self.select_a_public_account(user, host, valid_accounts)
|
||||
|
||||
if private_account and can_concurrent:
|
||||
account = private_account
|
||||
else:
|
||||
using_keys = cache.keys(accounts_using_key_tmpl.format(host.id, '*')) or []
|
||||
accounts_username_used = list(cache.get_many(using_keys).values())
|
||||
logger.debug('Applet host account using: {}: {}'.format(host.name, accounts_username_used))
|
||||
|
||||
# 优先使用 private account
|
||||
if private_account and private_account.username not in accounts_username_used:
|
||||
account = private_account
|
||||
else:
|
||||
accounts = accounts.exclude(username__in=accounts_username_used)
|
||||
public_accounts = accounts.filter(username__startswith='jms_')
|
||||
if not public_accounts:
|
||||
public_accounts = accounts.exclude(username__in=['Administrator', 'root'])
|
||||
account = self.random_select_prefer_account(user, host, public_accounts)
|
||||
if not account:
|
||||
return
|
||||
ttl = 60 * 60 * 24
|
||||
lock_key = accounts_using_key_tmpl.format(host.id, account.username)
|
||||
lock_key = self.accounts_using_key_tmpl.format(host.id, account.username, self.name)
|
||||
cache.set(lock_key, account.username, ttl)
|
||||
|
||||
return {
|
||||
|
|
Loading…
Reference in New Issue