Browse Source

perf: 优化 applet 账号选择

pull/11222/head
ibuler 1 year ago committed by Bryan
parent
commit
680d31dad2
  1. 2
      apps/terminal/migrations/0061_applet_can_concurrent.py
  2. 71
      apps/terminal/models/applet/applet.py

2
apps/terminal/migrations/0061_applet_can_concurrent.py

@ -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'),
),
]

71
apps/terminal/models/applet/applet.py

@ -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_{}_{}'
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))
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)
# 优先使用 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…
Cancel
Save