From 0589f7fe33e07775a026832a97847e658e3d4519 Mon Sep 17 00:00:00 2001 From: Eric <xplzv@126.com> Date: Wed, 20 Mar 2024 19:23:44 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E6=94=AF=E6=8C=81=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E6=9C=BA=E5=8D=B8=E8=BD=BD=E8=BF=9C=E7=A8=8B=E5=BA=94=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/api/applet/host.py | 32 +++++++++++++++++-- .../deploy_applet_host/__init__.py | 20 ++++++++++++ .../deploy_applet_host/uninstall_applet.yml | 11 +++++++ apps/terminal/models/applet/host.py | 10 ++++++ apps/terminal/serializers/applet_host.py | 9 ++++-- apps/terminal/tasks.py | 11 +++++++ 6 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 apps/terminal/automations/deploy_applet_host/uninstall_applet.yml diff --git a/apps/terminal/api/applet/host.py b/apps/terminal/api/applet/host.py index 69ed5e0da..6022a3b49 100644 --- a/apps/terminal/api/applet/host.py +++ b/apps/terminal/api/applet/host.py @@ -11,9 +11,14 @@ from common.permissions import IsServiceAccount from orgs.utils import tmp_to_builtin_org from terminal.models import AppletHost, AppletHostDeployment from terminal.serializers import ( - AppletHostSerializer, AppletHostDeploymentSerializer, AppletHostStartupSerializer + AppletHostSerializer, AppletHostDeploymentSerializer, + AppletHostStartupSerializer, AppletSetupSerializer +) +from terminal.tasks import ( + run_applet_host_deployment, + run_applet_host_deployment_install_applet, + run_applet_host_deployment_uninstall_applet ) -from terminal.tasks import run_applet_host_deployment, run_applet_host_deployment_install_applet __all__ = ['AppletHostViewSet', 'AppletHostDeploymentViewSet'] @@ -56,6 +61,7 @@ class AppletHostDeploymentViewSet(viewsets.ModelViewSet): filterset_fields = ['host', ] rbac_perms = ( ('applets', 'terminal.view_AppletHostDeployment'), + ('uninstall', 'terminal.change_applethost'), ) @staticmethod @@ -90,7 +96,29 @@ class AppletHostDeploymentViewSet(viewsets.ModelViewSet): transaction.on_commit(lambda: self.start_install_applet(applet_host_deployment_ids, applet_id, task_id)) return Response({'task': task_id}, status=201) + @action(methods=['post'], detail=False) + def uninstall(self, request, *args, **kwargs): + serializer = AppletSetupSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + validated_data = serializer.validated_data + hosts = validated_data.pop('hosts', []) + applet_id = validated_data.pop('applet_id', '') + hosts_qs = AppletHost.objects.filter(id__in=hosts) + if not hosts_qs.exists(): + return Response(status=status.HTTP_404_NOT_FOUND) + task_id = str(uuid.uuid4()) + objs = [AppletHostDeployment(host=host, task=task_id) for host in hosts_qs] + applet_host_deployments = AppletHostDeployment.objects.bulk_create(objs) + applet_host_deployment_ids = [str(obj.id) for obj in applet_host_deployments] + transaction.on_commit(lambda: self.start_uninstall_applet(applet_host_deployment_ids, applet_id, task_id)) + return Response({'task': task_id}, status=201) + @staticmethod def start_install_applet(applet_host_deployment_ids, applet_id, task_id): run_applet_host_deployment_install_applet.apply_async((applet_host_deployment_ids, applet_id), task_id=str(task_id)) + + @staticmethod + def start_uninstall_applet(applet_host_deployment_ids, applet_id, task_id): + run_applet_host_deployment_uninstall_applet.apply_async((applet_host_deployment_ids, applet_id), + task_id=str(task_id)) diff --git a/apps/terminal/automations/deploy_applet_host/__init__.py b/apps/terminal/automations/deploy_applet_host/__init__.py index d1d76870e..2a96f6823 100644 --- a/apps/terminal/automations/deploy_applet_host/__init__.py +++ b/apps/terminal/automations/deploy_applet_host/__init__.py @@ -36,6 +36,9 @@ class DeployAppletHostManager: def install_applet(self, **kwargs): self._run(self._run_install_applet, **kwargs) + def uninstall_applet(self, **kwargs): + self._run(self._run_uninstall_applet, **kwargs) + def _run_initial_deploy(self, **kwargs): playbook = self.generate_initial_playbook return self._run_playbook(playbook, **kwargs) @@ -47,6 +50,13 @@ class DeployAppletHostManager: generate_playbook = self.generate_install_all_playbook return self._run_playbook(generate_playbook, **kwargs) + def _run_uninstall_applet(self, **kwargs): + if self.applet: + generate_playbook = self.generate_uninstall_applet_playbook + else: + raise ValueError("applet is required for uninstall_applet") + return self._run_playbook(generate_playbook, **kwargs) + def generate_initial_playbook(self): site_url = settings.SITE_URL download_host = settings.APPLET_DOWNLOAD_HOST @@ -92,6 +102,16 @@ class DeployAppletHostManager: return self._generate_playbook("install_applet.yml", handler) + def generate_uninstall_applet_playbook(self): + applet_name = self.applet.name + + def handler(plays): + for play in plays: + play["vars"]["applet_name"] = applet_name + return plays + + return self._generate_playbook("uninstall_applet.yml", handler) + def generate_inventory(self): inventory = JMSInventory( [self.deployment.host], account_policy="privileged_only" diff --git a/apps/terminal/automations/deploy_applet_host/uninstall_applet.yml b/apps/terminal/automations/deploy_applet_host/uninstall_applet.yml new file mode 100644 index 000000000..3da0b6d0e --- /dev/null +++ b/apps/terminal/automations/deploy_applet_host/uninstall_applet.yml @@ -0,0 +1,11 @@ +--- + +- hosts: all + vars: + applet_name: chrome + + tasks: + - name: uninstall applet + ansible.windows.win_powershell: + script: | + tinkerd uninstall --name {{ applet_name }} diff --git a/apps/terminal/models/applet/host.py b/apps/terminal/models/applet/host.py index 0a1eab0f5..96eeee56a 100644 --- a/apps/terminal/models/applet/host.py +++ b/apps/terminal/models/applet/host.py @@ -168,6 +168,16 @@ class AppletHostDeployment(JMSBaseModel): manager = DeployAppletHostManager(self, applet=applet) manager.install_applet(**kwargs) + def uninstall_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.uninstall_applet(**kwargs) + def save_task(self, task): self.task = task self.save(update_fields=['task']) diff --git a/apps/terminal/serializers/applet_host.py b/apps/terminal/serializers/applet_host.py index 1e2b0bd16..00cabf2e7 100644 --- a/apps/terminal/serializers/applet_host.py +++ b/apps/terminal/serializers/applet_host.py @@ -15,7 +15,7 @@ from ..models import AppletHost, AppletHostDeployment __all__ = [ 'AppletHostSerializer', 'AppletHostDeploymentSerializer', 'AppletHostAccountSerializer', 'AppletHostAppletReportSerializer', - 'AppletHostStartupSerializer' + 'AppletHostStartupSerializer', 'AppletSetupSerializer' ] @@ -143,7 +143,7 @@ class AppletHostDeploymentSerializer(serializers.ModelSerializer): 'status', 'date_created', 'date_updated', 'date_start', 'date_finished' ] - write_only_fields = ['install_applets',] + write_only_fields = ['install_applets', ] fields = fields_mini + ['comment'] + read_only_fields + write_only_fields @@ -161,3 +161,8 @@ class AppletHostAppletReportSerializer(serializers.Serializer): class AppletHostStartupSerializer(serializers.Serializer): pass + + +class AppletSetupSerializer(serializers.Serializer): + hosts = serializers.ListField(child=serializers.UUIDField(label=_('Host ID')), label=_('Hosts')) + applet_id = serializers.UUIDField(label=_('Applet ID')) diff --git a/apps/terminal/tasks.py b/apps/terminal/tasks.py index 71bb2aba7..b8bd89f73 100644 --- a/apps/terminal/tasks.py +++ b/apps/terminal/tasks.py @@ -108,6 +108,17 @@ def run_applet_host_deployment_install_applet(ids, applet_id): deployment.install_applet(applet_id) +@shared_task( + verbose_name=_('Uninstall applet'), + activity_callback=lambda self, ids, applet_id, *args, **kwargs: (ids,) +) +def run_applet_host_deployment_uninstall_applet(ids, applet_id): + with tmp_to_builtin_org(system=1): + for did in ids: + deployment = AppletHostDeployment.objects.get(id=did) + deployment.uninstall_applet(applet_id) + + @shared_task( verbose_name=_('Generate applet host accounts'), activity_callback=lambda self, host_id, *args, **kwargs: ([host_id],)