mirror of
https://github.com/dw-0/kiauh.git
synced 2025-12-24 08:13:36 +05:00
feat(utils): add several util methods
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
This commit is contained in:
@@ -8,5 +8,12 @@
|
|||||||
# #
|
# #
|
||||||
# This file may be distributed under the terms of the GNU GPLv3 license #
|
# This file may be distributed under the terms of the GNU GPLv3 license #
|
||||||
# ======================================================================= #
|
# ======================================================================= #
|
||||||
|
import os
|
||||||
|
|
||||||
|
MODULE_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||||
INVALID_CHOICE = "Invalid choice. Please select a valid value."
|
INVALID_CHOICE = "Invalid choice. Please select a valid value."
|
||||||
|
|
||||||
|
# ================== NGINX =====================#
|
||||||
|
NGINX_SITES_AVAILABLE = "/etc/nginx/sites-available"
|
||||||
|
NGINX_SITES_ENABLED = "/etc/nginx/sites-enabled"
|
||||||
|
NGINX_CONFD = "/etc/nginx/conf.d"
|
||||||
|
|||||||
6
kiauh/utils/res/common_vars.conf
Normal file
6
kiauh/utils/res/common_vars.conf
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# /etc/nginx/conf.d/common_vars.conf
|
||||||
|
|
||||||
|
map $http_upgrade $connection_upgrade {
|
||||||
|
default upgrade;
|
||||||
|
'' close;
|
||||||
|
}
|
||||||
96
kiauh/utils/res/nginx_cfg
Normal file
96
kiauh/utils/res/nginx_cfg
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
# /etc/nginx/sites-available/%NAME%
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen %PORT%;
|
||||||
|
|
||||||
|
access_log /var/log/nginx/%NAME%-access.log;
|
||||||
|
error_log /var/log/nginx/%NAME%-error.log;
|
||||||
|
|
||||||
|
# disable this section on smaller hardware like a pi zero
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_proxied any;
|
||||||
|
gzip_proxied expired no-cache no-store private auth;
|
||||||
|
gzip_comp_level 4;
|
||||||
|
gzip_buffers 16 8k;
|
||||||
|
gzip_http_version 1.1;
|
||||||
|
gzip_types text/plain text/css text/xml text/javascript application/javascript application/x-javascript application/json application/xml;
|
||||||
|
|
||||||
|
# web_path from %NAME% static files
|
||||||
|
root %ROOT_DIR%;
|
||||||
|
|
||||||
|
index index.html;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
# disable max upload size checks
|
||||||
|
client_max_body_size 0;
|
||||||
|
|
||||||
|
# disable proxy request buffering
|
||||||
|
proxy_request_buffering off;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /index.html {
|
||||||
|
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||||
|
}
|
||||||
|
|
||||||
|
location /websocket {
|
||||||
|
proxy_pass http://apiserver/websocket;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 86400;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/(printer|api|access|machine|server)/ {
|
||||||
|
proxy_pass http://apiserver$request_uri;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Scheme $scheme;
|
||||||
|
proxy_read_timeout 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /webcam/ {
|
||||||
|
postpone_output 0;
|
||||||
|
proxy_buffering off;
|
||||||
|
proxy_ignore_headers X-Accel-Buffering;
|
||||||
|
access_log off;
|
||||||
|
error_log off;
|
||||||
|
proxy_pass http://mjpgstreamer1/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /webcam2/ {
|
||||||
|
postpone_output 0;
|
||||||
|
proxy_buffering off;
|
||||||
|
proxy_ignore_headers X-Accel-Buffering;
|
||||||
|
access_log off;
|
||||||
|
error_log off;
|
||||||
|
proxy_pass http://mjpgstreamer2/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /webcam3/ {
|
||||||
|
postpone_output 0;
|
||||||
|
proxy_buffering off;
|
||||||
|
proxy_ignore_headers X-Accel-Buffering;
|
||||||
|
access_log off;
|
||||||
|
error_log off;
|
||||||
|
proxy_pass http://mjpgstreamer3/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /webcam4/ {
|
||||||
|
postpone_output 0;
|
||||||
|
proxy_buffering off;
|
||||||
|
proxy_ignore_headers X-Accel-Buffering;
|
||||||
|
access_log off;
|
||||||
|
error_log off;
|
||||||
|
proxy_pass http://mjpgstreamer4/;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
kiauh/utils/res/upstreams.conf
Normal file
25
kiauh/utils/res/upstreams.conf
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# /etc/nginx/conf.d/upstreams.conf
|
||||||
|
upstream apiserver {
|
||||||
|
ip_hash;
|
||||||
|
server 127.0.0.1:7125;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream mjpgstreamer1 {
|
||||||
|
ip_hash;
|
||||||
|
server 127.0.0.1:8080;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream mjpgstreamer2 {
|
||||||
|
ip_hash;
|
||||||
|
server 127.0.0.1:8081;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream mjpgstreamer3 {
|
||||||
|
ip_hash;
|
||||||
|
server 127.0.0.1:8082;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream mjpgstreamer4 {
|
||||||
|
ip_hash;
|
||||||
|
server 127.0.0.1:8083;
|
||||||
|
}
|
||||||
@@ -18,8 +18,15 @@ import time
|
|||||||
import urllib.error
|
import urllib.error
|
||||||
import urllib.request
|
import urllib.request
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List
|
from typing import List, Literal
|
||||||
|
from zipfile import ZipFile
|
||||||
|
|
||||||
|
from kiauh.utils import (
|
||||||
|
NGINX_CONFD,
|
||||||
|
MODULE_PATH,
|
||||||
|
NGINX_SITES_AVAILABLE,
|
||||||
|
NGINX_SITES_ENABLED,
|
||||||
|
)
|
||||||
from kiauh.utils.input_utils import get_confirm
|
from kiauh.utils.input_utils import get_confirm
|
||||||
from kiauh.utils.logger import Logger
|
from kiauh.utils.logger import Logger
|
||||||
|
|
||||||
@@ -273,11 +280,22 @@ def get_ipv4_addr() -> str:
|
|||||||
s.close()
|
s.close()
|
||||||
|
|
||||||
|
|
||||||
def download_file(url: str, target_folder: str, target_name: str, show_progress=True):
|
def download_file(
|
||||||
|
url: str, target_folder: str, target_name: str, show_progress=True
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Helper method for downloading files from a provided URL |
|
||||||
|
:param url: the url to the file
|
||||||
|
:param target_folder: the target folder to download the file into
|
||||||
|
:param target_name: the name of the downloaded file
|
||||||
|
:param show_progress: show download progress or not
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
target_path = os.path.join(target_folder, target_name)
|
target_path = os.path.join(target_folder, target_name)
|
||||||
try:
|
try:
|
||||||
if show_progress:
|
if show_progress:
|
||||||
urllib.request.urlretrieve(url, target_path, download_progress)
|
urllib.request.urlretrieve(url, target_path, download_progress)
|
||||||
|
sys.stdout.write("\n")
|
||||||
else:
|
else:
|
||||||
urllib.request.urlretrieve(url, target_path)
|
urllib.request.urlretrieve(url, target_path)
|
||||||
except urllib.error.HTTPError as e:
|
except urllib.error.HTTPError as e:
|
||||||
@@ -291,7 +309,14 @@ def download_file(url: str, target_folder: str, target_name: str, show_progress=
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def download_progress(block_num, block_size, total_size):
|
def download_progress(block_num, block_size, total_size) -> None:
|
||||||
|
"""
|
||||||
|
Reporthook method for urllib.request.urlretrieve() method call in download_file() |
|
||||||
|
:param block_num:
|
||||||
|
:param block_size:
|
||||||
|
:param total_size: total filesize in bytes
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
downloaded = block_num * block_size
|
downloaded = block_num * block_size
|
||||||
percent = 100 if downloaded >= total_size else downloaded / total_size * 100
|
percent = 100 if downloaded >= total_size else downloaded / total_size * 100
|
||||||
mb = 1024 * 1024
|
mb = 1024 * 1024
|
||||||
@@ -300,3 +325,151 @@ def download_progress(block_num, block_size, total_size):
|
|||||||
dl = f"\rDownloading: [{'#' * progress}{remaining}]{percent:.2f}% ({downloaded/mb:.2f}/{total_size/mb:.2f}MB)"
|
dl = f"\rDownloading: [{'#' * progress}{remaining}]{percent:.2f}% ({downloaded/mb:.2f}/{total_size/mb:.2f}MB)"
|
||||||
sys.stdout.write(dl)
|
sys.stdout.write(dl)
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
|
def unzip(file: str, target_dir: str) -> None:
|
||||||
|
"""
|
||||||
|
Helper function to unzip a zip-archive into a target directory |
|
||||||
|
:param file: the zip-file to unzip
|
||||||
|
:param target_dir: the target directory to extract the files into
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
with ZipFile(file, "r") as _zip:
|
||||||
|
_zip.extractall(target_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def create_upstream_nginx_cfg() -> None:
|
||||||
|
"""
|
||||||
|
Creates an upstream.conf in /etc/nginx/conf.d
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
source = os.path.join(MODULE_PATH, "res", "upstreams.conf")
|
||||||
|
target = os.path.join(NGINX_CONFD, "upstreams.conf")
|
||||||
|
try:
|
||||||
|
command = ["sudo", "cp", source, target]
|
||||||
|
subprocess.run(command, stderr=subprocess.PIPE, check=True)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
log = f"Unable to create upstreams.conf: {e.stderr.decode()}"
|
||||||
|
Logger.print_error(log)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def create_common_vars_nginx_cfg() -> None:
|
||||||
|
"""
|
||||||
|
Creates a common_vars.conf in /etc/nginx/conf.d
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
source = os.path.join(MODULE_PATH, "res", "common_vars.conf")
|
||||||
|
target = os.path.join(NGINX_CONFD, "common_vars.conf")
|
||||||
|
try:
|
||||||
|
command = ["sudo", "cp", source, target]
|
||||||
|
subprocess.run(command, stderr=subprocess.PIPE, check=True)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
log = f"Unable to create upstreams.conf: {e.stderr.decode()}"
|
||||||
|
Logger.print_error(log)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def create_nginx_cfg(name: str, port: int, root_dir: str) -> None:
|
||||||
|
"""
|
||||||
|
Creates an NGINX config from a template file and replaces all placeholders
|
||||||
|
:param name: name of the config to create
|
||||||
|
:param port: listen port
|
||||||
|
:param root_dir: directory of the static files
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
tmp = f"{Path.home()}/{name}.tmp"
|
||||||
|
shutil.copy(os.path.join(MODULE_PATH, "res", "nginx_cfg"), tmp)
|
||||||
|
with open(tmp, "r+") as f:
|
||||||
|
content = f.read()
|
||||||
|
content = content.replace("%NAME%", name)
|
||||||
|
content = content.replace("%PORT%", str(port))
|
||||||
|
content = content.replace("%ROOT_DIR%", root_dir)
|
||||||
|
f.seek(0)
|
||||||
|
f.write(content)
|
||||||
|
f.truncate()
|
||||||
|
|
||||||
|
target = os.path.join(NGINX_SITES_AVAILABLE, name)
|
||||||
|
try:
|
||||||
|
command = ["sudo", "mv", tmp, target]
|
||||||
|
subprocess.run(command, stderr=subprocess.PIPE, check=True)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
log = f"Unable to create '{target}': {e.stderr.decode()}"
|
||||||
|
Logger.print_error(log)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def delete_default_nginx_cfg() -> None:
|
||||||
|
"""
|
||||||
|
Deletes a default NGINX config
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
default_cfg = Path("/etc/nginx/sites-enabled/default")
|
||||||
|
if not check_file_exists(default_cfg):
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
command = ["sudo", "rm", default_cfg]
|
||||||
|
subprocess.run(command, stderr=subprocess.PIPE, check=True)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
log = f"Unable to delete '{default_cfg}': {e.stderr.decode()}"
|
||||||
|
Logger.print_error(log)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def enable_nginx_cfg(name: str) -> None:
|
||||||
|
"""
|
||||||
|
Helper method to enable an NGINX config |
|
||||||
|
:param name: name of the config to enable
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
source = os.path.join(NGINX_SITES_AVAILABLE, name)
|
||||||
|
target = os.path.join(NGINX_SITES_ENABLED, name)
|
||||||
|
if check_file_exists(Path(target)):
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
command = ["sudo", "ln", "-s", source, target]
|
||||||
|
subprocess.run(command, stderr=subprocess.PIPE, check=True)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
log = f"Unable to create symlink: {e.stderr.decode()}"
|
||||||
|
Logger.print_error(log)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def set_nginx_permissions() -> None:
|
||||||
|
"""
|
||||||
|
Check if permissions of the users home directory
|
||||||
|
grant execution rights to group and other and set them if not set.
|
||||||
|
Required permissions for NGINX to be able to serve Mainsail/Fluidd.
|
||||||
|
This seems to have become necessary with Ubuntu 21+. |
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
cmd1 = f"ls -ld {Path.home()} | cut -d' ' -f1"
|
||||||
|
homedir_perm = subprocess.run(cmd1, shell=True, stdout=subprocess.PIPE, text=True)
|
||||||
|
homedir_perm = homedir_perm.stdout
|
||||||
|
|
||||||
|
if homedir_perm.count("x") < 3:
|
||||||
|
Logger.print_status("Granting NGINX the required permissions ...")
|
||||||
|
subprocess.run(["chmod", "og+x", Path.home()])
|
||||||
|
Logger.print_ok("Permissions granted.")
|
||||||
|
|
||||||
|
|
||||||
|
def control_systemd_service(
|
||||||
|
name: str, action: Literal["start", "stop", "restart", "disable"]
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Helper method to execute several actions for a specific systemd service. |
|
||||||
|
:param name: the service name
|
||||||
|
:param action: Either "start", "stop", "restart" or "disable"
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
Logger.print_status(f"{action.capitalize()} {name}.service ...")
|
||||||
|
command = ["sudo", "systemctl", action, f"{name}.service"]
|
||||||
|
subprocess.run(command, stderr=subprocess.PIPE, check=True)
|
||||||
|
Logger.print_ok(f"OK!")
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
log = f"Failed to {action} {name}.service: {e.stderr.decode()}"
|
||||||
|
Logger.print_error(log)
|
||||||
|
raise
|
||||||
|
|||||||
Reference in New Issue
Block a user