jumpserver/apps/terminal/automations/deploy_applet_host/__init__.py

163 lines
6.0 KiB
Python
Raw Normal View History

2022-10-28 10:19:44 +00:00
import datetime
2022-11-14 10:48:21 +00:00
import os
import re
import shutil
2022-11-01 03:52:51 +00:00
2022-11-01 09:04:44 +00:00
import yaml
2022-10-28 10:19:44 +00:00
from django.conf import settings
2022-11-14 10:48:21 +00:00
from django.utils import timezone
2022-10-28 10:19:44 +00:00
2022-11-01 03:52:51 +00:00
from common.db.utils import safe_db_connection
from common.utils import get_logger, random_string
from ops.ansible import SuperPlaybookRunner, JMSInventory
2022-11-14 10:48:21 +00:00
from terminal.models import Applet, AppletHostDeployment
2022-10-28 10:19:44 +00:00
2022-11-01 03:52:51 +00:00
logger = get_logger(__name__)
2022-10-28 10:19:44 +00:00
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
class DeployAppletHostManager:
def __init__(self, deployment: AppletHostDeployment, applet: Applet = None,
install_applets: bool = True, **kwargs):
2022-11-01 03:52:51 +00:00
self.deployment = deployment
2022-11-14 10:48:21 +00:00
self.applet = applet
2022-10-28 10:19:44 +00:00
self.run_dir = self.get_run_dir()
self.install_applets = bool(install_applets)
2022-10-28 10:19:44 +00:00
@staticmethod
def get_run_dir():
2022-11-11 07:11:10 +00:00
base = os.path.join(settings.ANSIBLE_DIR, "applet_host_deploy")
now = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
2022-10-28 10:19:44 +00:00
return os.path.join(base, now)
2022-11-14 10:48:21 +00:00
def run(self, **kwargs):
self._run(self._run_initial_deploy, **kwargs)
def install_applet(self, **kwargs):
self._run(self._run_install_applet, **kwargs)
def uninstall_applet(self, **kwargs):
self._run(self._run_uninstall_applet, **kwargs)
2022-11-14 10:48:21 +00:00
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 _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)
2022-11-14 10:48:21 +00:00
def generate_initial_playbook(self):
site_url = settings.SITE_URL
2022-11-17 08:02:22 +00:00
download_host = settings.APPLET_DOWNLOAD_HOST
2022-11-03 10:03:46 +00:00
bootstrap_token = settings.BOOTSTRAP_TOKEN
host_id = str(self.deployment.host.id)
2022-11-14 10:48:21 +00:00
if not site_url:
site_url = "http://localhost:8080"
options = self.deployment.host.deploy_options
core_host = options.get("CORE_HOST", site_url)
core_host = core_host.rstrip("/")
2023-02-02 07:26:19 +00:00
if not download_host:
download_host = core_host
2022-11-17 08:02:22 +00:00
download_host = download_host.rstrip("/")
2022-11-01 09:04:44 +00:00
2022-11-14 10:48:21 +00:00
def handler(plays):
2023-11-08 05:47:24 +00:00
# 替换所有的特殊字符为下划线 _ , 防止因主机名称造成任务执行失败
applet_host_name = re.sub(r'\W', '_', self.deployment.host.name, flags=re.UNICODE)
hostname = '{}-{}'.format(applet_host_name, random_string(7))
2022-11-14 10:48:21 +00:00
for play in plays:
play["vars"].update(options)
2022-11-17 08:02:22 +00:00
play["vars"]["APPLET_DOWNLOAD_HOST"] = download_host
play["vars"]["CORE_HOST"] = core_host
2022-11-14 10:48:21 +00:00
play["vars"]["BOOTSTRAP_TOKEN"] = bootstrap_token
play["vars"]["HOST_ID"] = host_id
play["vars"]["HOST_NAME"] = hostname
play["vars"]["INSTALL_APPLETS"] = self.install_applets
2022-11-17 08:02:22 +00:00
return plays
2022-11-14 10:48:21 +00:00
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)
2022-10-28 10:19:44 +00:00
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)
2022-10-28 10:19:44 +00:00
def generate_inventory(self):
2022-11-11 07:11:10 +00:00
inventory = JMSInventory(
[self.deployment.host], account_policy="privileged_only"
)
inventory_dir = os.path.join(self.run_dir, "inventory")
inventory_path = os.path.join(inventory_dir, "hosts.yml")
2022-10-28 10:19:44 +00:00
inventory.write_to_file(inventory_path)
return inventory_path
2022-11-14 10:48:21 +00:00
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):
2022-10-28 10:19:44 +00:00
inventory = self.generate_inventory()
2022-11-14 10:48:21 +00:00
playbook = generate_playbook()
runner = SuperPlaybookRunner(
2022-10-28 10:19:44 +00:00
inventory=inventory, playbook=playbook, project_dir=self.run_dir
)
return runner.run(**kwargs)
2022-11-01 03:52:51 +00:00
def delete_runtime_dir(self):
if settings.DEBUG_DEV:
return
shutil.rmtree(self.run_dir, ignore_errors=True)
2022-11-14 10:48:21 +00:00
def _run(self, cb_func: callable, **kwargs):
2022-11-01 03:52:51 +00:00
try:
self.deployment.date_start = timezone.now()
2022-11-14 10:48:21 +00:00
cb = cb_func(**kwargs)
2022-11-01 03:52:51 +00:00
self.deployment.status = cb.status
except Exception as e:
logger.error("Error: {}".format(e))
2022-11-11 07:11:10 +00:00
self.deployment.status = "error"
2022-11-01 03:52:51 +00:00
finally:
self.deployment.date_finished = timezone.now()
with safe_db_connection():
self.deployment.save()
self.delete_runtime_dir()