diff --git a/apps/terminal/migrations/0061_applet_can_concurrent.py b/apps/terminal/migrations/0061_applet_can_concurrent.py index 4ca762e65..5041e5425 100644 --- a/apps/terminal/migrations/0061_applet_can_concurrent.py +++ b/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'), ), ] diff --git a/apps/terminal/models/applet/applet.py b/apps/terminal/models/applet/applet.py index be6b397ff..07d63bce1 100644 --- a/apps/terminal/models/applet/applet.py +++ b/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 {