remade the steps runner and improved some functions
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Mathieu Broillet 2023-06-22 15:43:35 +02:00
parent 0473d7b9da
commit 099638570f
No known key found for this signature in database
GPG Key ID: 7D4F25BC50A0AA32
6 changed files with 216 additions and 67 deletions

View File

@ -1,11 +1,8 @@
from __future__ import annotations from __future__ import annotations
import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from . import lxc_utils from ..utils import steps_utils
from ..utils import conditions_utils
from ..utils.resources_utils import get_path
if TYPE_CHECKING: if TYPE_CHECKING:
from .lxc import LXC from .lxc import LXC
@ -20,54 +17,7 @@ def run_steps(lxc: LXC):
The LXC object used to run the creation steps The LXC object used to run the creation steps
""" """
creation = lxc.creation creation_steps = lxc.creation["steps"]
creation_steps = creation["steps"]
for index, step in enumerate(creation_steps): # Run the steps
steps_utils.run_steps(lxc, creation_steps)
if conditions_utils.verify_step_conditions(lxc, step):
logging.info(f"Conditions already met for step {index + 1}/{len(creation_steps)} for LXC {lxc.id}, "
f"skipping...")
continue
logging.info(f"Running step {index + 1}/{len(creation_steps)} for LXC {lxc.id}...")
match step["type"]:
# Support for scripts
case "script":
lxc_utils.run_script_step_parser(lxc, step)
case "file_create":
lxc.create_file(step["path"], step.get("permission", 644), step.get("owner", "root"))
case "file_copy":
lxc.pve.copy_file_to_lxc(lxc, get_path(lxc, step["path"]), step["destination"])
case "folder_create":
lxc.create_directory(step["path"], step.get("permission", 755), step.get("owner", "root"))
case "folder_copy":
lxc.pve.copy_folder_to_lxc(lxc, get_path(lxc, step["path"]), step["destination"])
case "command":
lxc.run_command(command=step["command"], working_directory=step.get("working_directory"),
return_status_code=True)
case "docker":
lxc.run_docker_command(step["container"], step["command"])
case "docker_compose":
lxc.run_docker_compose_command(command=step["command"],
working_directory=step.get("working_directory"))
case "git":
lxc.run_command(command=f"git clone {step['url']} {step['destination']}", return_status_code=True)
case "download":
lxc.download_file(step["url"], step["destination"])
case "unzip":
lxc.unzip_file(step["path"], step.get("destination"))
case "install-package":
lxc.install_package(step["package"])
case "remove-package":
lxc.remove_package(step["package"])
case "start":
lxc.start()
case "stop":
lxc.stop()
case "reboot":
lxc.reboot()
case "replace-in-files":
lxc.replace_in_files(step["files"], step["search"], step["replace"])

View File

@ -7,6 +7,7 @@ class LinuxMachine:
def __init__(self): def __init__(self):
self.known_programs = [] self.known_programs = []
self.id = None
pass pass
def update(self): def update(self):
@ -144,7 +145,7 @@ class LinuxMachine:
self.run_command(f"rm -rf {directory}", return_status_code=True) self.run_command(f"rm -rf {directory}", return_status_code=True)
def run_docker_command(self, container, command): def run_docker_command(self, container, command: str or list):
"""Run a command inside a docker container on a linux host """Run a command inside a docker container on a linux host
Parameters Parameters
@ -159,6 +160,9 @@ class LinuxMachine:
>>> self.run_docker_command(linux_machine, "<container-name>", "<command>") >>> self.run_docker_command(linux_machine, "<container-name>", "<command>")
""" """
if type(command) == list:
command = " && ".join(command)
if not self.has_program("docker"): if not self.has_program("docker"):
raise Exception(f"Docker is not installed on this machine {self.get_hostname()}") raise Exception(f"Docker is not installed on this machine {self.get_hostname()}")
@ -188,12 +192,12 @@ class LinuxMachine:
else: else:
self.run_command(f"{docker_compose_exec} {command}", return_status_code=True) self.run_command(f"{docker_compose_exec} {command}", return_status_code=True)
def download_file(self, url: str, destination: str): def download_file(self, url: str or list, destination: str):
"""Download a file from a URL to the Linux Machine and save it to the destination """Download a file from a URL to the Linux Machine and save it to the destination
Parameters Parameters
---------- ----------
url: str url: str or list
URL of the file to download URL of the file to download
destination: str destination: str
Path to the destination to save the file to Path to the destination to save the file to
@ -206,7 +210,7 @@ class LinuxMachine:
if type(url) is list: if type(url) is list:
for u in url: for u in url:
self.run_command(f"wget {u} --directory-prefix={destination}", return_status_code=True) self.download_file(u, destination)
else: else:
self.run_command(f"wget {url} --directory-prefix={destination}", return_status_code=True) self.run_command(f"wget {url} --directory-prefix={destination}", return_status_code=True)

View File

@ -2,8 +2,8 @@ import logging
from pathlib import Path from pathlib import Path
from .lxc.lxc_utils import load_lxc, get_all_lxcs from .lxc.lxc_utils import load_lxc, get_all_lxcs
from .utils import git_utils
from .proxmox.proxmox import ProxmoxHost from .proxmox.proxmox import ProxmoxHost
from .utils import git_utils
def run(args): def run(args):
@ -20,11 +20,11 @@ def run(args):
# Check if the repo is already cloned # Check if the repo is already cloned
if not pve.has_directory(pve.repo_path): if not pve.has_directory(pve.repo_path):
logging.info(f"Cloning repository {args.repo} to {args.path}...") logging.info(f"Cloning repository {args.repo} to {args.path}...")
git_utils.clone_repo(url=args.repo, path=pve.repo_path, linux_machine=pve) git_utils.clone_repo(linux_machine=pve, url=args.repo, path=pve.repo_path)
if pve.has_directory(Path(pve.repo_path).joinpath(".git")): if pve.has_directory(Path(pve.repo_path).joinpath(".git")):
logging.info(f"Repository already cloned at {pve.repo_path}, updating...") logging.info(f"Repository already cloned at {pve.repo_path}, updating...")
git_utils.update_repo(path=pve.repo_path, linux_machine=pve) git_utils.update_repo(linux_machine=pve, path=pve.repo_path)
if not pve.has_directory(pve.repo_path): if not pve.has_directory(pve.repo_path):
raise FileNotFoundError(f"Repo not found at {pve.repo_path}") raise FileNotFoundError(f"Repo not found at {pve.repo_path}")

View File

@ -78,7 +78,7 @@ class ProxmoxHost(LinuxMachine):
self.connection = Connection(host=self.host, user=self.user, port=self.port) self.connection = Connection(host=self.host, user=self.user, port=self.port)
def run_command(self, command: str, return_status_code: bool = False, exception_on_exit: bool = True, def run_command(self, command: str, return_status_code: bool = False, exception_on_exit: bool = True,
exception_on_empty_stdout: bool = False, **kwargs): exception_on_empty_stdout: bool = False, working_directory=None, **kwargs):
"""Run a command on the Proxmox VE host """Run a command on the Proxmox VE host
The default behavior is as follows : The default behavior is as follows :
- runs the command on the Proxmox VE host - runs the command on the Proxmox VE host
@ -92,7 +92,7 @@ class ProxmoxHost(LinuxMachine):
Parameters Parameters
---------- ----------
command_result: str command: str
command to run command to run
return_status_code: bool, optional return_status_code: bool, optional
should it return the exit code and not the stdout, disables exception_on_exit should it return the exit code and not the stdout, disables exception_on_exit
@ -121,6 +121,12 @@ class ProxmoxHost(LinuxMachine):
if the stdout is empty and exception_on_empty_stdout is True if the stdout is empty and exception_on_empty_stdout is True
""" """
if type(command) == list:
command = ' && '.join(command)
if working_directory:
command = f"cd {working_directory} && {command}"
start_time = time.time() start_time = time.time()
# Check if host is None, if it is, run the command locally, else run it on the host via SSH # Check if host is None, if it is, run the command locally, else run it on the host via SSH
@ -242,7 +248,8 @@ class ProxmoxHost(LinuxMachine):
self.run_command(f"qm reboot {vm_id}") self.run_command(f"qm reboot {vm_id}")
def copy_file_to_lxc(self, lxc: LXC, source: str or Path, destination: str or Path, use_ssh: bool = True): def copy_file_to_lxc(self, lxc: LXC, source: str or Path, destination: str or Path, permission: int = 644,
owner: str = "root", use_ssh: bool = True):
"""Copy the given file to the given LXC.""" """Copy the given file to the given LXC."""
if isinstance(source, Path): if isinstance(source, Path):
source = str(source.as_posix()) source = str(source.as_posix())
@ -252,7 +259,13 @@ class ProxmoxHost(LinuxMachine):
lxc.create_directory(destination.parent.as_posix(), use_ssh=use_ssh) lxc.create_directory(destination.parent.as_posix(), use_ssh=use_ssh)
self.run_command(f"pct push {lxc.id} {source} {destination.as_posix()}") self.run_command(f"pct push {lxc.id} {source} {destination.as_posix()}")
def copy_folder_to_lxc(self, lxc: LXC, source: str or Path, destination: str or Path): if permission != 755:
lxc.run_command(f"chmod {permission} {destination}", return_status_code=True, use_ssh=use_ssh)
if owner != "root":
lxc.run_command(f"chown {owner} {destination}", return_status_code=True)
def copy_folder_to_lxc(self, lxc: LXC, source: str or Path, destination: str or Path, permission: int = 755,
owner: str = "root"):
"""Copy the given folder to the given LXC.""" """Copy the given folder to the given LXC."""
if isinstance(source, Path): if isinstance(source, Path):
source = str(source.as_posix()) source = str(source.as_posix())
@ -261,6 +274,11 @@ class ProxmoxHost(LinuxMachine):
self.run_command(f"scp -o StrictHostKeyChecking=no -B -r {source} {lxc.get_ssh_string()}:{destination}") self.run_command(f"scp -o StrictHostKeyChecking=no -B -r {source} {lxc.get_ssh_string()}:{destination}")
if permission != 755:
lxc.run_command(f"chmod -R {permission} {destination}", return_status_code=True)
if owner != "root":
lxc.run_command(f"chown -R {owner} {destination}", return_status_code=True)
def list_dir(self, directory: str or Path, glob_filter: str = '*'): def list_dir(self, directory: str or Path, glob_filter: str = '*'):
"""List the given directory.""" """List the given directory."""
if isinstance(directory, Path): if isinstance(directory, Path):

View File

@ -3,13 +3,13 @@ import logging
from ..machine.machine import LinuxMachine from ..machine.machine import LinuxMachine
def clone_repo(url, path, linux_machine: LinuxMachine): def clone_repo(linux_machine: LinuxMachine, url, path):
"""Clone the given repository to the given path""" """Clone the given repository to the given path"""
logging.info(f"Cloning repository {url} to {path}...") logging.info(f"Cloning repository {url} to {path}...")
linux_machine.run_command(f"git clone {url} {path}") linux_machine.run_command(f"git clone {url} {path}")
def update_repo(path, linux_machine: LinuxMachine): def update_repo(linux_machine: LinuxMachine, path):
"""Update the given repository""" """Update the given repository"""
logging.info(f"Updating repository at {path}...") logging.info(f"Updating repository at {path}...")
linux_machine.run_command(f"git -C {path} pull") linux_machine.run_command(f"git -C {path} pull")

177
src/utils/steps_utils.py Normal file
View File

@ -0,0 +1,177 @@
import logging
import time
from . import git_utils
from .resources_utils import get_path
from ..lxc import lxc_utils
from ..lxc.lxc import LXC
from ..machine.machine import LinuxMachine
from ..utils import conditions_utils
def _run_script_step(linux_machine, step):
if isinstance(linux_machine, LXC):
lxc_utils.run_script_step_parser(linux_machine, step)
else:
logging.warning(f"Script step only supported on LXCs")
pass
def _run_file_create_step(linux_machine, step):
linux_machine.create_file(step["path"], step.get("permission", 644), step.get("owner", "root"))
def _run_file_copy_step(linux_machine, step):
if isinstance(linux_machine, LXC):
linux_machine.pve.copy_file_to_lxc(linux_machine, get_path(linux_machine, step["path"]), step["destination"],
step.get("permission", 644), step.get("owner", "root"))
else:
logging.warning(f"File copy step only supported on LXCs")
def _run_folder_create_step(linux_machine, step):
linux_machine.create_directory(step["path"], step.get("permission", 755), step.get("owner", "root"))
def _run_folder_copy_step(linux_machine, step):
linux_machine.pve.copy_folder_to_lxc(linux_machine, get_path(linux_machine, step["path"]), step["destination"],
step.get("permission", 644), step.get("owner", "root"))
def _run_command_step(linux_machine, step):
linux_machine.run_command(command=step["command"], working_directory=step.get("workdir"),
return_status_code=True)
def _run_docker_step(linux_machine, step):
linux_machine.run_docker_command(step["container"], step["command"])
def _run_docker_compose_step(linux_machine, step):
linux_machine.run_docker_compose_command(command=step["command"], working_directory=step.get("working_directory"))
def _run_git_clone_step(linux_machine, step):
git_utils.clone_repo(linux_machine=linux_machine, url=step["url"], path=step["destination"])
def _run_git_pull_step(linux_machine, step):
git_utils.update_repo(linux_machine=linux_machine, path=step["path"])
def _run_download_step(linux_machine, step):
linux_machine.download_file(step["url"], step["destination"])
def _run_install_package_step(linux_machine, step):
linux_machine.install_package(step["package"])
def _run_remove_package_step(linux_machine, step):
linux_machine.remove_package(step["package"])
def _run_start_step(linux_machine, step):
linux_machine.start()
def _run_stop_step(linux_machine, step):
linux_machine.stop()
def _run_reboot_step(linux_machine, step):
linux_machine.reboot()
def _run_service_start_step(linux_machine, step):
pass
def _run_service_stop_step(linux_machine, step):
pass
def _run_service_restart_step(linux_machine, step):
pass
def _run_service_enable_step(linux_machine, step):
pass
def _run_service_disable_step(linux_machine, step):
pass
def _run_replace_in_file_step(linux_machine, step):
pass
def _run_unzip_step(linux_machine, step):
linux_machine.unzip_file(step["path"], step.get("destination"))
def _run_wait_step(step):
time.sleep(step["seconds"])
def run_steps(linux_machine: LinuxMachine, steps: dict):
for index, step in enumerate(steps):
if conditions_utils.verify_step_conditions(linux_machine, step):
logging.info(f"Conditions already met for step {index + 1}/{len(steps)} for LXC {linux_machine.id}, "
f"skipping...")
continue
logging.info(f"Running step {index + 1}/{len(steps)} for LXC {linux_machine.id}...")
# Run command step
match step['type']:
case "script":
_run_script_step(linux_machine, step)
case "file_create":
_run_file_create_step(linux_machine, step)
case "file_copy":
_run_file_copy_step(linux_machine, step)
case "folder_create":
_run_folder_create_step(linux_machine, step)
case "folder_copy":
_run_folder_copy_step(linux_machine, step)
case "command":
_run_command_step(linux_machine, step)
case "docker":
_run_docker_step(linux_machine, step)
case "docker_compose":
_run_docker_compose_step(linux_machine, step)
case "git_clone":
_run_git_clone_step(linux_machine, step)
case "git_pull":
_run_git_pull_step(linux_machine, step)
case "download":
_run_download_step(linux_machine, step)
case "install_package":
_run_install_package_step(linux_machine, step)
case "remove_package":
_run_remove_package_step(linux_machine, step)
case "start":
_run_start_step(linux_machine, step)
case "stop":
_run_stop_step(linux_machine, step)
case "reboot":
_run_reboot_step(linux_machine, step)
case "service_start":
_run_service_start_step(linux_machine, step)
case "service_stop":
_run_service_stop_step(linux_machine, step)
case "service_restart":
_run_service_restart_step(linux_machine, step)
case "service_enable":
_run_service_enable_step(linux_machine, step)
case "service_disable":
_run_service_disable_step(linux_machine, step)
case "replace_in_file":
_run_replace_in_file_step(linux_machine, step)
case "unzip":
_run_unzip_step(linux_machine, step)
case "wait":
_run_wait_step(step)