mirror of https://github.com/jumpserver/jumpserver
				
				
				
			
		
			
				
	
	
		
			141 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			141 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Python
		
	
	
| import os
 | ||
| from collections import defaultdict
 | ||
| 
 | ||
| from django.db import models
 | ||
| from django.utils import timezone
 | ||
| from django.utils.translation import gettext_lazy as _
 | ||
| from rest_framework.exceptions import ValidationError
 | ||
| from simple_history.utils import bulk_create_with_history
 | ||
| 
 | ||
| from assets.models import Host
 | ||
| from common.db.models import JMSBaseModel
 | ||
| from common.utils import random_string
 | ||
| 
 | ||
| __all__ = ['AppletHost', 'AppletHostDeployment']
 | ||
| 
 | ||
| 
 | ||
| class AppletHost(Host):
 | ||
|     deploy_options = models.JSONField(default=dict, verbose_name=_('Deploy options'))
 | ||
|     inited = models.BooleanField(default=False, verbose_name=_('Inited'))
 | ||
|     date_inited = models.DateTimeField(null=True, blank=True, verbose_name=_('Date inited'))
 | ||
|     date_synced = models.DateTimeField(null=True, blank=True, verbose_name=_('Date synced'))
 | ||
|     terminal = models.OneToOneField(
 | ||
|         'terminal.Terminal', on_delete=models.PROTECT, null=True, blank=True,
 | ||
|         related_name='applet_host', verbose_name=_('Terminal')
 | ||
|     )
 | ||
|     applets = models.ManyToManyField(
 | ||
|         'Applet', verbose_name=_('Applet'),
 | ||
|         through='AppletPublication', through_fields=('host', 'applet'),
 | ||
|     )
 | ||
|     LOCKING_ORG = '00000000-0000-0000-0000-000000000004'
 | ||
| 
 | ||
|     class Meta:
 | ||
|         verbose_name = _('Hosting')
 | ||
| 
 | ||
|     def __str__(self):
 | ||
|         return self.name
 | ||
| 
 | ||
|     @property
 | ||
|     def load(self):
 | ||
|         if not self.terminal:
 | ||
|             return 'offline'
 | ||
|         return self.terminal.load
 | ||
| 
 | ||
|     def check_terminal_binding(self, request):
 | ||
|         request_terminal = getattr(request.user, 'terminal', None)
 | ||
|         if not request_terminal:
 | ||
|             raise ValidationError('Request user has no terminal')
 | ||
| 
 | ||
|         self.date_synced = timezone.now()
 | ||
|         if self.terminal == request_terminal:
 | ||
|             self.save(update_fields=['date_synced'])
 | ||
|         else:
 | ||
|             self.terminal = request_terminal
 | ||
|             self.save(update_fields=['terminal', 'date_synced'])
 | ||
| 
 | ||
|     def check_applets_state(self, applets_value_list):
 | ||
|         applets = self.applets.all()
 | ||
|         name_version_mapper = {
 | ||
|             value['name']: value['version']
 | ||
|             for value in applets_value_list
 | ||
|         }
 | ||
| 
 | ||
|         status_applets = defaultdict(list)
 | ||
|         for applet in applets:
 | ||
|             if applet.name not in name_version_mapper:
 | ||
|                 status_applets['unpublished'].append(applet)
 | ||
|             elif applet.version != name_version_mapper[applet.name]:
 | ||
|                 status_applets['not_match'].append(applet)
 | ||
|             else:
 | ||
|                 status_applets['published'].append(applet)
 | ||
| 
 | ||
|         for status, applets in status_applets.items():
 | ||
|             self.publications.filter(applet__in=applets) \
 | ||
|                 .exclude(status=status) \
 | ||
|                 .update(status=status)
 | ||
| 
 | ||
|     @staticmethod
 | ||
|     def random_username():
 | ||
|         return 'jms_' + random_string(8)
 | ||
| 
 | ||
|     @staticmethod
 | ||
|     def random_password():
 | ||
|         return random_string(16, special_char=True)
 | ||
| 
 | ||
|     def generate_accounts(self):
 | ||
|         amount = int(os.getenv('TERMINAL_ACCOUNTS_AMOUNT', 100))
 | ||
|         now_count = self.accounts.filter(privileged=False).count()
 | ||
|         need = amount - now_count
 | ||
| 
 | ||
|         accounts = []
 | ||
|         account_model = self.accounts.model
 | ||
|         for i in range(need):
 | ||
|             username = self.random_username()
 | ||
|             password = self.random_password()
 | ||
|             account = account_model(
 | ||
|                 username=username, secret=password, name=username,
 | ||
|                 asset_id=self.id, secret_type='password', version=1,
 | ||
|                 org_id=self.LOCKING_ORG, is_active=False,
 | ||
|             )
 | ||
|             accounts.append(account)
 | ||
|         bulk_create_with_history(accounts, account_model, batch_size=20)
 | ||
| 
 | ||
| 
 | ||
| class AppletHostDeployment(JMSBaseModel):
 | ||
|     host = models.ForeignKey('AppletHost', on_delete=models.CASCADE, verbose_name=_('Hosting'))
 | ||
|     initial = models.BooleanField(default=False, verbose_name=_('Initial'))
 | ||
|     status = models.CharField(max_length=16, default='pending', verbose_name=_('Status'))
 | ||
|     date_start = models.DateTimeField(null=True, verbose_name=_('Date start'), db_index=True)
 | ||
|     date_finished = models.DateTimeField(null=True, verbose_name=_("Date finished"))
 | ||
|     comment = models.TextField(default='', blank=True, verbose_name=_('Comment'))
 | ||
|     task = models.UUIDField(null=True, verbose_name=_('Task'))
 | ||
| 
 | ||
|     class Meta:
 | ||
|         ordering = ('-date_start',)
 | ||
| 
 | ||
|     def start(self, **kwargs):
 | ||
|         # 重新初始化部署,applet host 关联的终端需要删除
 | ||
|         # 否则 tinker 会因终端注册名称相同,造成冲突,执行任务失败
 | ||
|         if self.host.terminal:
 | ||
|             terminal = self.host.terminal
 | ||
|             self.host.terminal = None
 | ||
|             self.host.save()
 | ||
|             terminal.delete()
 | ||
|         from ...automations.deploy_applet_host import DeployAppletHostManager
 | ||
|         manager = DeployAppletHostManager(self)
 | ||
|         manager.run(**kwargs)
 | ||
| 
 | ||
|     def install_applet(self, applet_id, **kwargs):
 | ||
|         from ...automations.deploy_applet_host import DeployAppletHostManager
 | ||
|         from .applet import Applet
 | ||
|         if applet_id:
 | ||
|             applet = Applet.objects.get(id=applet_id)
 | ||
|         else:
 | ||
|             applet = None
 | ||
|         manager = DeployAppletHostManager(self, applet=applet)
 | ||
|         manager.install_applet(**kwargs)
 | ||
| 
 | ||
|     def save_task(self, task):
 | ||
|         self.task = task
 | ||
|         self.save(update_fields=['task'])
 |