Compare commits

...

3 Commits

Author SHA1 Message Date
609cc0ef24
started new script running system
All checks were successful
continuous-integration/drone/push Build is passing
2023-06-15 17:13:34 +02:00
25b208094d
merged commands_utils into Machine class 2023-06-15 17:10:16 +02:00
5e77c93865
removed patchwork from requirement 2023-06-15 16:58:49 +02:00
5 changed files with 208 additions and 202 deletions

View File

@ -1,2 +1 @@
fabric~=3.1.0 fabric~=3.1.0
patchwork~=1.0.1

View File

@ -4,7 +4,7 @@ import logging
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from ..utils import commands_utils from . import lxc_utils
from ..utils.resources_utils import get_path from ..utils.resources_utils import get_path
if TYPE_CHECKING: if TYPE_CHECKING:
@ -174,9 +174,9 @@ def run_steps(lxc: LXC):
# Support for scripts # Support for scripts
case "script": case "script":
commands_utils.run_script(lxc, step) lxc_utils.run_script_parser(lxc, step)
case "file_create": case "file_create":
commands_utils.create_file_in_lxc(lxc, step["path"], optional(step["permission"], 644)) lxc.create_file(step["path"], optional(step["permission"], 644))
case "file_copy": case "file_copy":
commands_utils.copy_local_file_to_lxc(lxc, get_path(lxc, step["path"]), step["destination"]) commands_utils.copy_local_file_to_lxc(lxc, get_path(lxc, step["path"]), step["destination"])
case "folder": case "folder":

View File

@ -117,3 +117,24 @@ def generate_pct_command_for_lxc(lxc: LXC, create: bool = True):
# TODO: add gateway4 # TODO: add gateway4
# f"ip6={self.ipv6},gw6={self.gateway6},trunks={self.vlan} " \ # TODO # f"ip6={self.ipv6},gw6={self.gateway6},trunks={self.vlan} " \ # TODO
return pct_command return pct_command
def run_script_parser(lxc: LXC, step: dict):
# Install bash if not installed
# Sometimes only ash or sh are installed, which doesn't work for some scripts
if not lxc.has_program("bash"):
lxc.install_package("bash")
# # Run local script
# if "path" in step:
# path = get_path(lxc, step["local_path"])
# _run_local_script_on_lxc(lxc, path)
#
# # Run remote script
# elif "url" in step:
# _run_remote_script_on_lxc(lxc, step["url"])
#
# # Run script in LXC
# elif "lxc_path" in step:
# path = get_path(lxc, step["lxc_path"])
# _run_script_on_lxc(lxc, path)

View File

@ -1,195 +0,0 @@
from pathlib import PurePosixPath
from src.utils import utils
from src.utils.machine import LinuxMachine
def run_docker_command(linux_machine: LinuxMachine, container: str, command: str):
"""Run a command inside a docker container on a linux host
Parameters
----------
linux_machine : LinuxMachine
The LinuxMachine object of the linux host to run the command in
container : str
Name of the docker container to run the command in
command : str
Command to run in the docker container
Examples
--------
>>> run_docker_command(linux_machine, "<container-name>", "<command>")
"""
linux_machine.run_command(f"docker exec -it {container} {command}", exception_on_empty_stdout=False)
def run_docker_compose_command(linux_machine: LinuxMachine, command: str, working_directory: str = None):
"""Run a docker-compose command on a linux host
Parameters
----------
linux_machine: LinuxMachine
The LinuxMachine object of the linux host to run the command in
command: str
The docker-compose command to run
working_directory: str, optional
The working directory to run the command in
Examples
--------
>>> run_docker_compose_command(linux_machine, "up -d", "/home/user/traefik")
"""
docker_compose_exec = "docker-compose"
if not linux_machine.has_program(docker_compose_exec):
docker_compose_exec = "docker compose"
if working_directory is not None:
linux_machine.run_command(f"cd {working_directory} && {docker_compose_exec} {command}", return_status_code=True)
else:
linux_machine.run_command(f"{docker_compose_exec} {command}", return_status_code=True)
def download_file(linux_machine: LinuxMachine, url: str, destination: str):
"""Download a file from a URL to the Linux Machine and save it to the destination
Parameters
----------
linux_machine: LinuxMachine
The LinuxMachine object of the linux host to download the file to
url: str
URL of the file to download
destination: str
Path to the destination to save the file to
Needs to end with a trailing slash
Examples
--------
>>> download_file(linux_machine, "https://example.com/file.zip", "/home/user/")
"""
if type(url) is list:
for u in url:
linux_machine.run_command(f"wget {u} --directory-prefix={destination}", return_status_code=True)
else:
linux_machine.run_command(f"wget {url} --directory-prefix={destination}", return_status_code=True)
def unzip_file(linux_machine: LinuxMachine, path: str, destination: str = None):
"""Unzip a file
Parameters
----------
linux_machine: LinuxMachine
The LinuxMachine object of the linux host to unzip the file in
path: str
Path to the file to unzip
destination: str, optional
Path to the destination to unzip the file to
If not specified, it will unzip the file in the same directory as the file
Needs to end with a trailing slash
Examples
--------
>>> unzip_file(linux_machine, "/home/user/file.zip", "/home/user/extracted_files/")
>>> unzip_file(linux_machine, "/home/user/file.tar.gz", "/home/user/extracted_files/")
"""
if destination is None:
destination = PurePosixPath(path).parent
if ".zip" in path:
linux_machine.run_command(f"unzip {path} -d {destination}", return_status_code=True)
elif ".tar.gz" in path:
linux_machine.run_command(f"mkdir -p {destination} && tar -xzf {path} --directory {destination}",
return_status_code=True)
def install_package(linux_machine: LinuxMachine, package: str or list):
"""Install a package in the Linux Machine
Parameters
----------
linux_machine: LinuxMachine
The LinuxMachine object of the host to install the package in
package: str or list
Name(s) of the package(s) to install
Examples
--------
>>> install_package(linux_machine, "nginx")
>>> install_package(linux_machine, ["nginx", "apache2"])
"""
if type(package) is list:
for p in package:
linux_machine.run_command(f"{utils.get_install_package_command(linux_machine.get_os_name())} {package}",
return_status_code=True)
else:
linux_machine.run_command(f"{utils.get_install_package_command(linux_machine.get_os_name())} {package}",
return_status_code=True)
def remove_package(linux_machine: LinuxMachine, package: str or list):
"""Remove a package in the Linux Machine
Parameters
----------
linux_machine: LinuxMachine
The LinuxMachine object of the host to remove the package in
package: str or list
Name(s) of the package(s) to remove
Examples
--------
>>> remove_package(linux_machine, "nginx")
>>> remove_package(linux_machine, ["nginx", "apache2"])
"""
if type(package) is list:
packages = []
for p in package:
packages.append(p)
linux_machine.run_command(
f"{utils.get_remove_package_command(linux_machine.get_os_name())} {' '.join(packages)}",
return_status_code=True)
else:
linux_machine.run_command(f"{utils.get_remove_package_command(linux_machine.get_os_name())} {package}",
return_status_code=True)
def replace_in_files(linux_machine: LinuxMachine, path: str or list, search: str, replace: str,
case_sensitive: bool = False):
"""Replace a string in one or multiples files in a LinuxMachine
Parameters
----------
linux_machine : LinuxMachine
The LinuxMachine object of the host to replace the string in
path : str or list of str
Path to the file(s) to replace the string in
search : str
String to search for
replace : str
String to replace the search string with
case_sensitive : bool, optional
Whether the search should be case sensitive or not
Examples
--------
>>> replace_in_files(linux_machine, "/home/user/file.txt", "username=root", "username=administrator"
>>> replace_in_files(linux_machine, ["/home/user/file1.txt", "/home/user/file2.txt"], \
"username=root", "username=administrator", case_sensitive=True)
"""
if type(path) is list:
for p in path:
linux_machine.run_command(f"sed {'-i' if case_sensitive else ''} 's/{search}/{replace}/g' {p}",
return_status_code=True)
else:
linux_machine.run_command(f"sed {'-i' if case_sensitive else ''} 's/{search}/{replace}/g' {path}",
return_status_code=True)

View File

@ -1,4 +1,6 @@
from pathlib import Path from pathlib import Path, PurePosixPath
from src.utils import utils
class LinuxMachine(): class LinuxMachine():
@ -13,7 +15,13 @@ class LinuxMachine():
return self.run_command("uptime -p") return self.run_command("uptime -p")
def get_os_name(self): def get_os_name(self):
"""Get OS name""" """Get OS name
Returns
-------
str
OS name
"""
return self.run_command("""cat /etc/os-release | grep -E '^NAME=' | cut -d '=' -f 2 | tr -d '"'""") return self.run_command("""cat /etc/os-release | grep -E '^NAME=' | cut -d '=' -f 2 | tr -d '"'""")
def get_memory(self): def get_memory(self):
@ -116,3 +124,176 @@ class LinuxMachine():
directory = str(directory.as_posix()) directory = str(directory.as_posix())
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):
"""Run a command inside a docker container on a linux host
Parameters
----------
container : str
Name of the docker container to run the command in
command : str
Command to run in the docker container
Examples
--------
>>> self.run_docker_command(linux_machine, "<container-name>", "<command>")
"""
if not self.has_program("docker"):
raise Exception(f"Docker is not installed on this machine {self.get_hostname()}")
self.run_command(f"docker exec -it {container} {command}", exception_on_empty_stdout=False)
def run_docker_compose_command(self, command: str, working_directory: str = None):
"""Run a docker-compose command on a linux host
Parameters
----------
command: str
The docker-compose command to run
working_directory: str, optional
The working directory to run the command in
Examples
--------
>>> self.run_docker_compose_command(linux_machine, "up -d", "/home/user/traefik")
"""
docker_compose_exec = "docker-compose"
if not self.has_program(docker_compose_exec):
docker_compose_exec = "docker compose"
if working_directory is not None:
self.run_command(f"cd {working_directory} && {docker_compose_exec} {command}", return_status_code=True)
else:
self.run_command(f"{docker_compose_exec} {command}", return_status_code=True)
def download_file(self, url: str, destination: str):
"""Download a file from a URL to the Linux Machine and save it to the destination
Parameters
----------
url: str
URL of the file to download
destination: str
Path to the destination to save the file to
Needs to end with a trailing slash
Examples
--------
>>> self.download_file("https://example.com/file.zip", "/home/user/")
"""
if type(url) is list:
for u in url:
self.run_command(f"wget {u} --directory-prefix={destination}", return_status_code=True)
else:
self.run_command(f"wget {url} --directory-prefix={destination}", return_status_code=True)
def unzip_file(self, path: str, destination: str = None):
"""Unzip a file
Parameters
----------
path: str
Path to the file to unzip
destination: str, optional
Path to the destination to unzip the file to
If not specified, it will unzip the file in the same directory as the file
Needs to end with a trailing slash
Examples
--------
>>> self.unzip_file("/home/user/file.zip", "/home/user/extracted_files/")
>>> self.unzip_file("/home/user/file.tar.gz", "/home/user/extracted_files/")
"""
if destination is None:
destination = PurePosixPath(path).parent
if ".zip" in path:
self.run_command(f"unzip {path} -d {destination}", return_status_code=True)
elif ".tar.gz" in path:
self.run_command(f"mkdir -p {destination} && tar -xzf {path} --directory {destination}",
return_status_code=True)
def install_package(self, package: str or list):
"""Install a package in the Linux Machine
Parameters
----------
package: str or list
Name(s) of the package(s) to install
Examples
--------
>>> self.install_package("nginx")
>>> self.install_package(["nginx", "apache2"])
"""
if type(package) is list:
for p in package:
self.run_command(f"{utils.get_install_package_command(self.get_os_name())} {package}",
return_status_code=True)
else:
self.run_command(f"{utils.get_install_package_command(self.get_os_name())} {package}",
return_status_code=True)
def remove_package(self, package: str or list):
"""Remove a package in the Linux Machine
Parameters
----------
package: str or list
Name(s) of the package(s) to remove
Examples
--------
>>> self.remove_package("nginx")
>>> self.remove_package(["nginx", "apache2"])
"""
if type(package) is list:
packages = []
for p in package:
packages.append(p)
self.run_command(
f"{utils.get_remove_package_command(self.get_os_name())} {' '.join(packages)}",
return_status_code=True)
else:
self.run_command(f"{utils.get_remove_package_command(self.get_os_name())} {package}",
return_status_code=True)
def replace_in_files(self, path: str or list, search: str, replace: str,
case_sensitive: bool = False):
"""Replace a string in one or multiples files in a LinuxMachine
Parameters
----------
path : str or list of str
Path to the file(s) to replace the string in
search : str
String to search for
replace : str
String to replace the search string with
case_sensitive : bool, optional
Whether the search should be case sensitive or not
Examples
--------
>>> self.replace_in_files("/home/user/file.txt", "username=root", "username=administrator"
>>> self.replace_in_files(["/home/user/file1.txt", "/home/user/file2.txt"], \
"username=root", "username=administrator", case_sensitive=True)
"""
if type(path) is list:
for p in path:
self.run_command(f"sed {'-i' if case_sensitive else ''} 's/{search}/{replace}/g' {p}",
return_status_code=True)
else:
self.run_command(f"sed {'-i' if case_sensitive else ''} 's/{search}/{replace}/g' {path}",
return_status_code=True)