Compare commits

..

14 Commits

Author SHA1 Message Date
jaydee 5adb2c7c2e build 2026-03-29 20:18:13 +02:00
jaydee 8067ac8561 build 2026-03-28 12:33:16 +01:00
jaydee 79e9e708b4 build 2026-03-28 12:33:00 +01:00
ladislav.dusa 64c3615705 build 2026-03-25 14:56:28 +01:00
jaydee f5c883964a build 2026-03-24 23:19:58 +01:00
jaydee bc984f05d2 build 2026-03-24 12:26:15 +01:00
jaydee a9a4de2038 build 2026-03-24 12:16:29 +01:00
jaydee 9205e0c8f7 build 2026-03-23 16:56:46 +01:00
jaydee 062176a875 build 2026-03-22 15:28:56 +01:00
jaydee db7005b304 build 2026-03-21 22:46:02 +01:00
jaydee 0e8fcaa530 build 2026-03-21 21:53:36 +01:00
jaydee df151c4c7f build 2026-03-21 21:24:03 +01:00
jaydee eba757bf25 build 2026-03-21 21:19:48 +01:00
jaydee 1e1f82e658 build 2026-03-21 21:07:18 +01:00
8 changed files with 68 additions and 16 deletions
Binary file not shown.
+47 -8
View File
@@ -16,6 +16,8 @@ import time
import base64 import base64
import shutil import shutil
import requests import requests
import tempfile
import subprocess
from portainer.api import PortainerApi from portainer.api import PortainerApi
from git import Repo from git import Repo
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
@@ -46,7 +48,7 @@ def setup_vault():
# Specify the mount point of your KV engine # Specify the mount point of your KV engine
return vclient return vclient
VERSION = "0.1.75" VERSION = "0.1.77"
defaults = { defaults = {
@@ -224,6 +226,41 @@ def wl(msg):
if args.debug: if args.debug:
print(msg) print(msg)
def run(cmd, cwd=None):
result = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True)
if result.returncode != 0:
raise RuntimeError(result.stderr)
return result.stdout.strip()
def get_compose_files():
#git clone --depth=1 --filter=blob:none --no-checkout https://github.com/user/repo.git
with tempfile.TemporaryDirectory() as tmpdir:
repo_path = os.path.join(tmpdir, "repo")
# Clone with minimal data (no checkout, no blobs)
run([
"git", "clone",
"--depth=1",
"--filter=blob:none",
"--no-checkout",
"git@gitlab.sectorq.eu:/home/docker-compose.git",
repo_path
])
# List files in HEAD
output = run([
"git", "ls-tree",
"-r",
"HEAD",
"--name-only"
], cwd=repo_path)
folders = []
for line in output.splitlines():
if "/" in line and line.split("/")[0] != "__swarm":
folders.append(line.split("/")[0])
return list(dict.fromkeys(folders))
def prompt_missing_args(args_in, defaults_in, fields, action=None,stacks=None): def prompt_missing_args(args_in, defaults_in, fields, action=None,stacks=None):
""" """
@@ -259,13 +296,14 @@ def prompt_missing_args(args_in, defaults_in, fields, action=None,stacks=None):
elif field == "stack": elif field == "stack":
if args.action == "create_stack": if args.action == "create_stack":
# input(json.dumps(stacks, indent=2)) # input(json.dumps(stacks, indent=2))
commands = [ commands = get_compose_files()
'api_server', 'authentik', 'bitwarden', 'bookstack', 'databasus', 'dockermon', 'duplicati', 'fail2ban', 'filebrowser', 'gitea', 'gitlab', 'grafana', 'grocy', # commands = [
'hashicorp', 'home-assistant', 'homebox','homepage', 'immich', 'influxdb', 'jupyter', 'kestra', 'kopia', 'linkding', 'linkwarden', 'mailu3', # 'api_server', 'authentik', 'bitwarden', 'bookstack', 'databasus', 'dockermon', 'duplicati', 'fail2ban', 'filebrowser', 'gitea', 'gitlab', 'grafana', 'grocy',
'mealie', 'mediacenter', 'mosquitto', 'motioneye', 'n8n', 'nebula', 'nextcloud', 'nginx', # 'hashicorp', 'home-assistant', 'homebox','homepage', 'immich', 'influxdb', 'jupyter', 'kestra', 'kopia', 'linkding', 'linkwarden', 'mailu3',
'node-red', 'octoprint', 'ollama', 'onlyoffice', 'paperless-ngx', 'pihole', 'portainer-ce','portainerce', 'rancher', 'registry', # 'mealie', 'mediacenter', 'mosquitto', 'motioneye', 'n8n', 'nebula', 'nextcloud', 'nginx',
'regsync', 'repo_mirror', 'searxng','semaphore', 'unifibrowser', 'uptime-kuma', 'watchtower', 'wazuh', 'webhub', 'wordpress', # 'node-red', 'octoprint', 'ollama', 'onlyoffice', 'paperless-ngx', 'pihole', 'portainer-ce','portainerce', 'puppet', 'puppet-agent', 'rancher', 'registry',
'wud', 'zabbix-server'] # 'regsync', 'repo_mirror', 'searxng','semaphore', 'unifibrowser', 'uptime-kuma', 'watchtower', 'wazuh', 'webhub', 'wordpress',
# 'wud', 'zabbix-server']
try: try:
print(por.all_data['stacks'][defaults_in[f"PORTAINER_ENDPOINT_ID".upper()]]['by_name'].keys()) print(por.all_data['stacks'][defaults_in[f"PORTAINER_ENDPOINT_ID".upper()]]['by_name'].keys())
for s in por.all_data['stacks'][defaults_in[f"PORTAINER_ENDPOINT_ID".upper()]]['by_name'].keys(): for s in por.all_data['stacks'][defaults_in[f"PORTAINER_ENDPOINT_ID".upper()]]['by_name'].keys():
@@ -719,6 +757,7 @@ if __name__ == "__main__":
args.stack = ",".join(args.stack) args.stack = ",".join(args.stack)
one_time_command += f" --stack={args.stack}" one_time_command += f" --stack={args.stack}"
width = shutil.get_terminal_size().columns width = shutil.get_terminal_size().columns
input(width)
print("#"*width) print("#"*width)
print(f"COMMAND : {one_time_command}") print(f"COMMAND : {one_time_command}")
print("#"*width) print("#"*width)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+19 -6
View File
@@ -13,6 +13,8 @@ import tabulate
from git import Repo from git import Repo
import requests import requests
import hvac import hvac
import subprocess
import tempfile
from prompt_toolkit import prompt from prompt_toolkit import prompt
from prompt_toolkit.completion import WordCompleter from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.shortcuts import checkboxlist_dialog from prompt_toolkit.shortcuts import checkboxlist_dialog
@@ -178,7 +180,7 @@ class PortainerApi:
def _api_get(self, path, timeout=120): def _api_get(self, path, timeout=120):
url = f"{self.base_url.rstrip('/')}{path}" url = f"{self.base_url.rstrip('/')}{path}"
headers = {"X-API-Key": f"{self.token}"} headers = {"X-API-Key": f"{self.token}"}
resp = requests.get(url, headers=headers, timeout=timeout) resp = requests.get(url, headers=headers, timeout=120)
if resp.status_code != 200: if resp.status_code != 200:
return resp.status_code return resp.status_code
print(f"Error: {resp.status_code} - {resp.text}") print(f"Error: {resp.status_code} - {resp.text}")
@@ -275,7 +277,7 @@ class PortainerApi:
stcks = [] stcks = []
stacks = self._api_get(path, timeout=timeout) stacks = self._api_get(path, timeout=timeout)
self.stacks_all = {} self.stacks_all = {}
fail_endponts = [20, 39, 41, 32, 43] fail_endponts = [20, 39, 41, 32, 43, 44]
# print(json.dumps(stacks,indent=2)) # print(json.dumps(stacks,indent=2))
webhooks = {} webhooks = {}
for s in stacks: for s in stacks:
@@ -658,11 +660,17 @@ class PortainerApi:
autostart=False, autostart=False,
stack_mode="swarm", stack_mode="swarm",
): ):
diff_stacks = ['mediacenter']
for stack in stacks: for stack in stacks:
if self.endpoint_name == "nas":
server = "_nas"
else:
server = "" server = ""
print("Stack:", stack)
print("Endpoint:", endpoint)
if stack in diff_stacks:
if endpoint == "nas":
server = "_nas"
elif endpoint == "m-s":
server = "_m-server"
if stack_mode == "swarm": if stack_mode == "swarm":
swarm_id = self.get_swarm_id(endpoint) swarm_id = self.get_swarm_id(endpoint)
@@ -1258,6 +1266,7 @@ class PortainerApi:
"""Stop one stack or all stacks on an endpoint.""" """Stop one stack or all stacks on an endpoint."""
# print(f"Stopping stack {stack}") # print(f"Stopping stack {stack}")
protected_stack = ['hashicorp','nginx','pihole',]
ok = "\033[92m✔\033[0m" ok = "\033[92m✔\033[0m"
ok2 = "\033[93m✔\033[0m" ok2 = "\033[93m✔\033[0m"
err = "\033[91m✖\033[0m" err = "\033[91m✖\033[0m"
@@ -1274,8 +1283,12 @@ class PortainerApi:
size = size + 5 size = size + 5
self.stack_ids = list(dict.fromkeys(self.stack_ids)) self.stack_ids = list(dict.fromkeys(self.stack_ids))
for stck in self.stack_ids: for stck in self.stack_ids:
if self.stacks_all[self.endpoint_id]['by_id'] in protected_stack:
ans = input(f"Really stop {self.stacks_all[self.endpoint_id]['by_id'][stck]} ? ") or "n"
if ans != "y":
continue
print( print(
f"Stopping stack {self.stacks_all[self.endpoint_id]['by_id'][stck]}", f"Stopping stack {self.stacks_all[self.endpoint_id]['by_id'][stck][:size].ljust(size)}",
end="", end="",
flush=True flush=True
) )