Merge branch 'v3' of github.com:jumpserver/jumpserver into v3

pull/9075/head
ibuler 2022-11-15 10:43:51 +08:00
commit 22dd9906c7
9 changed files with 283 additions and 186 deletions

View File

@ -10,11 +10,11 @@ __all__ = ["SpecialAccount", "ActionChoices"]
class ActionChoices(BitChoices):
connect = bit(0), _("Connect")
upload = bit(1), _("Upload")
download = bit(2), _("Download")
copy = bit(3), _("Copy")
paste = bit(4), _("Paste")
connect = bit(1), _("Connect")
upload = bit(2), _("Upload")
download = bit(3), _("Download")
copy = bit(4), _("Copy")
paste = bit(5), _("Paste")
@classmethod
def is_tree(cls):

View File

@ -2,16 +2,15 @@ from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from common.permissions import IsServiceAccount
from common.drf.api import JMSModelViewSet
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
AppletHostStartupSerializer, AppletHostDeployAppletSerializer
)
from terminal.models import AppletHost, AppletHostDeployment
from terminal.tasks import run_applet_host_deployment
from terminal.tasks import run_applet_host_deployment, run_applet_host_deployment_install_applet
__all__ = ['AppletHostViewSet', 'AppletHostDeploymentViewSet']
@ -41,6 +40,9 @@ class AppletHostViewSet(JMSModelViewSet):
class AppletHostDeploymentViewSet(viewsets.ModelViewSet):
serializer_class = AppletHostDeploymentSerializer
queryset = AppletHostDeployment.objects.all()
rbac_perms = (
('applets', 'terminal.view_AppletHostDeployment'),
)
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
@ -49,3 +51,11 @@ class AppletHostDeploymentViewSet(viewsets.ModelViewSet):
task = run_applet_host_deployment.delay(instance.id)
return Response({'task': str(task.id)}, status=201)
@action(methods=['post'], detail=False, serializer_class=AppletHostDeployAppletSerializer)
def applets(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
applet_id = serializer.validated_data.get('applet_id')
instance = serializer.save()
task = run_applet_host_deployment_install_applet.delay(instance.id, applet_id)
return Response({'task': str(task.id)}, status=201)

View File

@ -1,22 +1,23 @@
import os
import datetime
import shutil
import os
import yaml
from django.utils import timezone
from django.conf import settings
from django.utils import timezone
from common.utils import get_logger
from common.db.utils import safe_db_connection
from common.utils import get_logger
from ops.ansible import PlaybookRunner, JMSInventory
from terminal.models import Applet, AppletHostDeployment
logger = get_logger(__name__)
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
class DeployAppletHostManager:
def __init__(self, deployment):
def __init__(self, deployment: AppletHostDeployment, applet: Applet = None):
self.deployment = deployment
self.applet = applet
self.run_dir = self.get_run_dir()
@staticmethod
@ -25,29 +26,56 @@ class DeployAppletHostManager:
now = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
return os.path.join(base, now)
def generate_playbook(self):
playbook_src = os.path.join(CURRENT_DIR, "playbook.yml")
base_site_url = settings.BASE_SITE_URL
def run(self, **kwargs):
self._run(self._run_initial_deploy, **kwargs)
def install_applet(self, **kwargs):
self._run(self._run_install_applet, **kwargs)
def _run_initial_deploy(self, **kwargs):
playbook = self.generate_initial_playbook
return self._run_playbook(playbook, **kwargs)
def _run_install_applet(self, **kwargs):
if self.applet:
generate_playbook = self.generate_install_applet_playbook
else:
generate_playbook = self.generate_install_all_playbook
return self._run_playbook(generate_playbook, **kwargs)
def generate_initial_playbook(self):
site_url = settings.SITE_URL
bootstrap_token = settings.BOOTSTRAP_TOKEN
host_id = str(self.deployment.host.id)
if not base_site_url:
base_site_url = "http://localhost:8080"
with open(playbook_src) as f:
plays = yaml.safe_load(f)
for play in plays:
play["vars"].update(self.deployment.host.deploy_options)
play["vars"]["DownloadHost"] = base_site_url + "/download"
play["vars"]["CORE_HOST"] = base_site_url
play["vars"]["BOOTSTRAP_TOKEN"] = bootstrap_token
play["vars"]["HOST_ID"] = host_id
play["vars"]["HOST_NAME"] = self.deployment.host.name
if not site_url:
site_url = "http://localhost:8080"
options = self.deployment.host.deploy_options
playbook_dir = os.path.join(self.run_dir, "playbook")
playbook_dst = os.path.join(playbook_dir, "main.yml")
os.makedirs(playbook_dir, exist_ok=True)
with open(playbook_dst, "w") as f:
yaml.safe_dump(plays, f)
return playbook_dst
def handler(plays):
for play in plays:
play["vars"].update(options)
play["vars"]["DownloadHost"] = site_url + "/download"
play["vars"]["CORE_HOST"] = site_url
play["vars"]["BOOTSTRAP_TOKEN"] = bootstrap_token
play["vars"]["HOST_ID"] = host_id
play["vars"]["HOST_NAME"] = self.deployment.host.name
return self._generate_playbook("playbook.yml", handler)
def generate_install_all_playbook(self):
return self._generate_playbook("install_all.yml")
def generate_install_applet_playbook(self):
applet_name = self.applet.name
options = self.deployment.host.deploy_options
def handler(plays):
for play in plays:
play["vars"].update(options)
play["vars"]["applet_name"] = applet_name
return plays
return self._generate_playbook("install_applet.yml", handler)
def generate_inventory(self):
inventory = JMSInventory(
@ -58,18 +86,31 @@ class DeployAppletHostManager:
inventory.write_to_file(inventory_path)
return inventory_path
def _run(self, **kwargs):
def _generate_playbook(self, playbook_template_name, plays_handler: callable = None):
playbook_src = os.path.join(CURRENT_DIR, playbook_template_name)
with open(playbook_src) as f:
plays = yaml.safe_load(f)
if plays_handler:
plays = plays_handler(plays)
playbook_dir = os.path.join(self.run_dir, "playbook")
playbook_dst = os.path.join(playbook_dir, "main.yml")
os.makedirs(playbook_dir, exist_ok=True)
with open(playbook_dst, "w") as f:
yaml.safe_dump(plays, f)
return playbook_dst
def _run_playbook(self, generate_playbook: callable, **kwargs):
inventory = self.generate_inventory()
playbook = self.generate_playbook()
playbook = generate_playbook()
runner = PlaybookRunner(
inventory=inventory, playbook=playbook, project_dir=self.run_dir
)
return runner.run(**kwargs)
def run(self, **kwargs):
def _run(self, cb_func: callable, **kwargs):
try:
self.deployment.date_start = timezone.now()
cb = self._run(**kwargs)
cb = cb_func(**kwargs)
self.deployment.status = cb.status
except Exception as e:
logger.error("Error: {}".format(e))

View File

@ -0,0 +1,8 @@
---
- hosts: all
tasks:
- name: Install all applets
ansible.windows.win_shell:
"tinkerd install all"

View File

@ -0,0 +1,11 @@
---
- hosts: all
vars:
applet_name: chrome
tasks:
- name: Install applet
ansible.windows.win_shell:
"tinkerd install --name {{ applet_name }}"
when: applet_name != 'all'

View File

@ -3,7 +3,6 @@
- hosts: all
vars:
DownloadHost: https://demo.jumpserver.org/download
Initial: 0
HOST_NAME: test
HOST_ID: 00000000-0000-0000-0000-000000000000
CORE_HOST: https://demo.jumpserver.org
@ -17,166 +16,166 @@
TinkerInstaller: Tinker_Installer_v0.0.1.exe
tasks:
- name: Install RDS-Licensing (RDS)
ansible.windows.win_feature:
name: RDS-Licensing
state: present
include_management_tools: yes
when: RDS_Licensing
- name: Install RDS-Licensing (RDS)
ansible.windows.win_feature:
name: RDS-Licensing
state: present
include_management_tools: yes
when: RDS_Licensing
- name: Install RDS-RD-Server (RDS)
ansible.windows.win_feature:
name: RDS-RD-Server
state: present
include_management_tools: yes
register: rds_install
- name: Install RDS-RD-Server (RDS)
ansible.windows.win_feature:
name: RDS-RD-Server
state: present
include_management_tools: yes
register: rds_install
- name: Download JumpServer Tinker installer (jumpserver)
ansible.windows.win_get_url:
- name: Download JumpServer Tinker installer (jumpserver)
ansible.windows.win_get_url:
url: "{{ DownloadHost }}/{{ TinkerInstaller }}"
dest: "{{ ansible_env.TEMP }}\\{{ TinkerInstaller }}"
- name: Install JumpServer Tinker (jumpserver)
ansible.windows.win_package:
path: "{{ ansible_env.TEMP }}\\{{ TinkerInstaller }}"
arguments:
- /VERYSILENT
- /SUPPRESSMSGBOXES
- /NORESTART
state: present
- name: Install JumpServer Tinker (jumpserver)
ansible.windows.win_package:
path: "{{ ansible_env.TEMP }}\\{{ TinkerInstaller }}"
arguments:
- /VERYSILENT
- /SUPPRESSMSGBOXES
- /NORESTART
state: present
- name: Set remote-server on the global system path (remote-server)
ansible.windows.win_path:
elements:
- '%USERPROFILE%\AppData\Local\Programs\Tinker\'
scope: user
- name: Set remote-server on the global system path (remote-server)
ansible.windows.win_path:
elements:
- '%USERPROFILE%\AppData\Local\Programs\Tinker\'
scope: user
- name: Download python-3.10.8
ansible.windows.win_get_url:
url: "{{ DownloadHost }}/python-3.10.8-amd64.exe"
dest: "{{ ansible_env.TEMP }}\\python-3.10.8-amd64.exe"
- name: Download python-3.10.8
ansible.windows.win_get_url:
url: "{{ DownloadHost }}/python-3.10.8-amd64.exe"
dest: "{{ ansible_env.TEMP }}\\python-3.10.8-amd64.exe"
- name: Install the python-3.10.8
ansible.windows.win_package:
path: "{{ ansible_env.TEMP }}\\python-3.10.8-amd64.exe"
product_id: '{371d0d73-d418-4ffe-b280-58c3e7987525}'
arguments:
- /quiet
- InstallAllUsers=1
- PrependPath=1
- Include_test=0
- Include_launcher=0
state: present
register: win_install_python
- name: Install the python-3.10.8
ansible.windows.win_package:
path: "{{ ansible_env.TEMP }}\\python-3.10.8-amd64.exe"
product_id: '{371d0d73-d418-4ffe-b280-58c3e7987525}'
arguments:
- /quiet
- InstallAllUsers=1
- PrependPath=1
- Include_test=0
- Include_launcher=0
state: present
register: win_install_python
- name: Reboot if installing requires it
ansible.windows.win_reboot:
post_reboot_delay: 10
test_command: whoami
when: rds_install.reboot_required or win_install_python.reboot_required
- name: Reboot if installing requires it
ansible.windows.win_reboot:
post_reboot_delay: 10
test_command: whoami
when: rds_install.reboot_required or win_install_python.reboot_required
- name: Set RDS LicenseServer (regedit)
ansible.windows.win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services
name: LicenseServers
data: "{{ RDS_LicenseServer }}"
type: string
- name: Set RDS LicenseServer (regedit)
ansible.windows.win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services
name: LicenseServers
data: "{{ RDS_LicenseServer }}"
type: string
- name: Set RDS LicensingMode (regedit)
ansible.windows.win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services
name: LicensingMode
data: "{{ RDS_LicensingMode }}"
type: dword
- name: Set RDS LicensingMode (regedit)
ansible.windows.win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services
name: LicensingMode
data: "{{ RDS_LicensingMode }}"
type: dword
- name: Set RDS fSingleSessionPerUser (regedit)
ansible.windows.win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services
name: fSingleSessionPerUser
data: "{{ RDS_fSingleSessionPerUser }}"
type: dword
- name: Set RDS fSingleSessionPerUser (regedit)
ansible.windows.win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services
name: fSingleSessionPerUser
data: "{{ RDS_fSingleSessionPerUser }}"
type: dword
- name: Set RDS MaxDisconnectionTime (regedit)
ansible.windows.win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services
name: MaxDisconnectionTime
data: "{{ RDS_MaxDisconnectionTime }}"
type: dword
when: RDS_MaxDisconnectionTime >= 60000
- name: Set RDS MaxDisconnectionTime (regedit)
ansible.windows.win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services
name: MaxDisconnectionTime
data: "{{ RDS_MaxDisconnectionTime }}"
type: dword
when: RDS_MaxDisconnectionTime >= 60000
- name: Set RDS RemoteAppLogoffTimeLimit (regedit)
ansible.windows.win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services
name: RemoteAppLogoffTimeLimit
data: "{{ RDS_RemoteAppLogoffTimeLimit }}"
type: dword
- name: Set RDS RemoteAppLogoffTimeLimit (regedit)
ansible.windows.win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services
name: RemoteAppLogoffTimeLimit
data: "{{ RDS_RemoteAppLogoffTimeLimit }}"
type: dword
- name: Download pip packages
ansible.windows.win_get_url:
url: "{{ DownloadHost }}/pip_packages_v0.0.1.zip"
dest: "{{ ansible_env.TEMP }}\\pip_packages_v0.0.1.zip"
- name: Download pip packages
ansible.windows.win_get_url:
url: "{{ DownloadHost }}/pip_packages_v0.0.1.zip"
dest: "{{ ansible_env.TEMP }}\\pip_packages_v0.0.1.zip"
- name: Unzip pip_packages
community.windows.win_unzip:
src: "{{ ansible_env.TEMP }}\\pip_packages_v0.0.1.zip"
dest: "{{ ansible_env.TEMP }}"
- name: Unzip pip_packages
community.windows.win_unzip:
src: "{{ ansible_env.TEMP }}\\pip_packages_v0.0.1.zip"
dest: "{{ ansible_env.TEMP }}"
- name: Install python requirements offline
ansible.windows.win_shell: >
- name: Install python requirements offline
ansible.windows.win_shell: >
pip install -r '{{ ansible_env.TEMP }}\pip_packages_v0.0.1\requirements.txt'
--no-index --find-links='{{ ansible_env.TEMP }}\pip_packages_v0.0.1'
- name: Download chromedriver (chrome)
ansible.windows.win_get_url:
url: "{{ DownloadHost }}/chromedriver_win32.107.zip"
dest: "{{ ansible_env.TEMP }}\\chromedriver_win32.107.zip"
- name: Download chromedriver (chrome)
ansible.windows.win_get_url:
url: "{{ DownloadHost }}/chromedriver_win32.107.zip"
dest: "{{ ansible_env.TEMP }}\\chromedriver_win32.107.zip"
- name: Unzip chromedriver (chrome)
community.windows.win_unzip:
src: "{{ ansible_env.TEMP }}\\chromedriver_win32.107.zip"
dest: C:\Program Files\JumpServer\drivers
- name: Unzip chromedriver (chrome)
community.windows.win_unzip:
src: "{{ ansible_env.TEMP }}\\chromedriver_win32.107.zip"
dest: C:\Program Files\JumpServer\drivers
- name: Set chromedriver on the global system path (chrome)
ansible.windows.win_path:
elements:
- 'C:\Program Files\JumpServer\drivers'
- name: Set chromedriver on the global system path (chrome)
ansible.windows.win_path:
elements:
- 'C:\Program Files\JumpServer\drivers'
- name: Download chrome msi package (chrome)
ansible.windows.win_get_url:
url: "{{ DownloadHost }}/googlechromestandaloneenterprise64.msi"
dest: "{{ ansible_env.TEMP }}\\googlechromestandaloneenterprise64.msi"
- name: Download chrome msi package (chrome)
ansible.windows.win_get_url:
url: "{{ DownloadHost }}/googlechromestandaloneenterprise64.msi"
dest: "{{ ansible_env.TEMP }}\\googlechromestandaloneenterprise64.msi"
- name: Install chrome (chrome)
ansible.windows.win_package:
path: "{{ ansible_env.TEMP }}\\googlechromestandaloneenterprise64.msi"
state: present
arguments:
- /quiet
- name: Install chrome (chrome)
ansible.windows.win_package:
path: "{{ ansible_env.TEMP }}\\googlechromestandaloneenterprise64.msi"
state: present
arguments:
- /quiet
- name: Generate tinkerd component config
ansible.windows.win_shell:
"tinkerd config --hostname {{ HOST_NAME }} --core_host {{ CORE_HOST }}
- name: Generate tinkerd component config
ansible.windows.win_shell:
"tinkerd config --hostname {{ HOST_NAME }} --core_host {{ CORE_HOST }}
--token {{ BOOTSTRAP_TOKEN }} --host_id {{ HOST_ID }}"
- name: Install tinkerd service
ansible.windows.win_shell:
"tinkerd service install"
- name: Install tinkerd service
ansible.windows.win_shell:
"tinkerd service install"
- name: Start tinkerd service
ansible.windows.win_shell:
"tinkerd service start"
- name: Start tinkerd service
ansible.windows.win_shell:
"tinkerd service start"
- name: Wait Tinker api health
ansible.windows.win_uri:
url: http://localhost:6068/api/health/
status_code: 200
method: GET
register: _result
until: _result.status_code == 200
retries: 30
delay: 5
- name: Wait Tinker api health
ansible.windows.win_uri:
url: http://localhost:6068/api/health/
status_code: 200
method: GET
register: _result
until: _result.status_code == 200
retries: 30
delay: 5
- name: Sync all remote applets
ansible.windows.win_shell:
"tinkerd install all"
- name: Sync all remote applets
ansible.windows.win_shell:
"tinkerd install all"

View File

@ -110,3 +110,13 @@ class AppletHostDeployment(JMSBaseModel):
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)

View File

@ -1,19 +1,18 @@
from rest_framework import serializers
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from common.validators import ProjectUniqueValidator
from common.drf.fields import ObjectRelatedField, LabeledChoiceField
from assets.models import Platform, Account
from assets.serializers import HostSerializer
from ..models import AppletHost, AppletHostDeployment, Applet
from common.drf.fields import LabeledChoiceField
from common.validators import ProjectUniqueValidator
from .applet import AppletSerializer
from .. import const
from ..models import AppletHost, AppletHostDeployment
__all__ = [
'AppletHostSerializer', 'AppletHostDeploymentSerializer',
'AppletHostAccountSerializer', 'AppletHostAppletReportSerializer',
'AppletHostStartupSerializer',
'AppletHostStartupSerializer', 'AppletHostDeployAppletSerializer'
]
@ -29,7 +28,8 @@ class DeployOptionsSerializer(serializers.Serializer):
RDS_Licensing = serializers.BooleanField(default=False, label=_("RDS Licensing"))
RDS_LicenseServer = serializers.CharField(default='127.0.0.1', label=_('RDS License Server'), max_length=1024)
RDS_LicensingMode = serializers.ChoiceField(choices=LICENSE_MODE_CHOICES, default=4, label=_('RDS Licensing Mode'))
RDS_fSingleSessionPerUser = serializers.ChoiceField(choices=SESSION_PER_USER, default=1, label=_("RDS fSingleSessionPerUser"))
RDS_fSingleSessionPerUser = serializers.ChoiceField(choices=SESSION_PER_USER, default=1,
label=_("RDS fSingleSessionPerUser"))
RDS_MaxDisconnectionTime = serializers.IntegerField(default=60000, label=_("RDS Max Disconnection Time"))
RDS_RemoteAppLogoffTimeLimit = serializers.IntegerField(default=0, label=_("RDS Remote App Logoff Time Limit"))
@ -94,6 +94,18 @@ class AppletHostDeploymentSerializer(serializers.ModelSerializer):
fields = fields_mini + ['comment'] + read_only_fields
class AppletHostDeployAppletSerializer(AppletHostDeploymentSerializer):
applet_id = serializers.UUIDField(write_only=True, allow_null=True, required=False)
class Meta(AppletHostDeploymentSerializer.Meta):
fields = AppletHostDeploymentSerializer.Meta.fields + ['applet_id']
def create(self, validated_data):
applet_id = validated_data.pop('applet_id', None)
deployment = super().create(validated_data)
return deployment
class AppletHostAccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account

View File

@ -1,26 +1,25 @@
# -*- coding: utf-8 -*-
#
import datetime
import os
import subprocess
import datetime
from celery import shared_task
from celery.utils.log import get_task_logger
from django.utils import timezone
from django.core.files.storage import default_storage
from django.utils import timezone
from common.utils import get_log_keep_day
from ops.celery.decorator import (
register_as_period_task, after_app_ready_start,
after_app_shutdown_clean_periodic
)
from .models import (
Status, Session, Command, Task, AppletHost,
AppletHostDeployment
)
from orgs.utils import tmp_to_builtin_org
from .backends import server_replay_storage
from .models import (
Status, Session, Command, Task, AppletHostDeployment
)
from .utils import find_session_replay_local
CACHE_REFRESH_INTERVAL = 10
@ -57,7 +56,7 @@ def clean_orphan_session():
@shared_task
@register_as_period_task(interval=3600*24)
@register_as_period_task(interval=3600 * 24)
@after_app_ready_start
@after_app_shutdown_clean_periodic
def clean_expired_session_period():
@ -114,3 +113,10 @@ def run_applet_host_deployment(did):
with tmp_to_builtin_org(system=1):
deployment = AppletHostDeployment.objects.get(id=did)
deployment.start()
@shared_task
def run_applet_host_deployment_install_applet(did, applet_id):
with tmp_to_builtin_org(system=1):
deployment = AppletHostDeployment.objects.get(id=did)
deployment.install_applet(applet_id)