|
|
|
@ -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 { |
|
|
|
|