This commit is contained in:
2025-11-17 13:56:15 +01:00
parent 666a9ee234
commit 43637f5b28

View File

@@ -1,8 +1,15 @@
import os import os
import sys
import requests import requests
import json import json
import uuid import uuid
import argparse import argparse
import shutil
import time
from tabulate import tabulate
from git import Repo # pip install gitpython
from port import Portainer
parser = argparse.ArgumentParser(description="Portainer helper - use env vars or pass credentials.") parser = argparse.ArgumentParser(description="Portainer helper - use env vars or pass credentials.")
parser.add_argument("--base", "-b", default=os.getenv("PORTAINER_URL", "https://portainer.example.com"), parser.add_argument("--base", "-b", default=os.getenv("PORTAINER_URL", "https://portainer.example.com"),
help="Base URL for Portainer (ENV: PORTAINER_URL)") help="Base URL for Portainer (ENV: PORTAINER_URL)")
@@ -15,19 +22,36 @@ parser.add_argument("--list-endpoints", action="store_true", help="List endpoint
parser.add_argument("--list-stacks", "-l", action="store_true", help="List stacks") parser.add_argument("--list-stacks", "-l", action="store_true", help="List stacks")
parser.add_argument("--delete-stack", "-d", action="store_true", help="Delete stack") parser.add_argument("--delete-stack", "-d", action="store_true", help="Delete stack")
parser.add_argument("--get-stack", metavar="NAME_OR_ID", help="Get stack by name or numeric id") parser.add_argument("--get-stack", metavar="NAME_OR_ID", help="Get stack by name or numeric id")
parser.add_argument("--create-stack","-c", action='store_true') parser.add_argument("--autostart", "-a", action="store_true", help="Auto-start created stacks")
parser.add_argument("--start-stack", "-x", action='store_true')
parser.add_argument("--stop-stack", "-o", action='store_true')
parser.add_argument("--debug", "-D", action='store_true')
parser.add_argument("--create-stack1","-c", action='store_true')
parser.add_argument("--create-stack","-n", action='store_true')
parser.add_argument("--create-stack_new2","-N", action='store_true')
parser.add_argument("--gpu","-g", action='store_true') parser.add_argument("--gpu","-g", action='store_true')
parser.add_argument("--create-stacks","-C", action='store_true') parser.add_argument("--create-stacks","-C", action='store_true')
parser.add_argument("--stack-id", "-s", type=str, help="Stack ID for operations") parser.add_argument("--refresh-status","-r", action='store_true')
parser.add_argument("--stack", "-s", type=str, help="Stack ID for operations")
parser.add_argument("--token-only", action="store_true", help="Print auth token and exit") parser.add_argument("--token-only", action="store_true", help="Print auth token and exit")
parser.add_argument("--timeout", type=int, default=10, help="Request timeout seconds") parser.add_argument("--timeout", type=int, default=10, help="Request timeout seconds")
parser.add_argument("--deploy-mode","-m", type=str, default="git", help="Deploy mode")
args = parser.parse_args() args = parser.parse_args()
nas_stacks = ["pihole","authentik","bitwarden","bookstack","dockermon","gitea","gitlab","grafana","home-assistant","homepage","immich","jupiter","kestra","mailu3","mealie","mediacenter"]
portainer_api_key = "ptr_QoHE/e6kfqIirE3fhzYMRFRxK7eL42wtCxo5P18i1zQ=" portainer_api_key = "ptr_QoHE/e6kfqIirE3fhzYMRFRxK7eL42wtCxo5P18i1zQ="
def wl(msg):
if args.debug:
print(msg)
def is_number(s):
"""Check if the input string is a number."""
try:
float(s)
return True
except ValueError:
return False
def get_portainer_token(base_url, username=None, password=None, timeout=10): def get_portainer_token(base_url, username=None, password=None, timeout=10):
@@ -58,7 +82,7 @@ def api_get(base_url, path, token, timeout=10):
resp.raise_for_status() resp.raise_for_status()
return resp.json() return resp.json()
def api_post(base_url, path, token, data, timeout=120): def api_post(base_url, path, token, data, timeout=240):
"""Example authenticated GET request to Portainer API.""" """Example authenticated GET request to Portainer API."""
url = f"{base_url.rstrip('/')}{path}" url = f"{base_url.rstrip('/')}{path}"
headers = {"Authorization": f"Bearer {token}"} headers = {"Authorization": f"Bearer {token}"}
@@ -66,70 +90,164 @@ def api_post(base_url, path, token, data, timeout=120):
resp = requests.post(url, headers=headers, json=data, timeout=timeout) resp = requests.post(url, headers=headers, json=data, timeout=timeout)
resp.raise_for_status() resp.raise_for_status()
return resp.json() return resp.json()
def api_post2(base_url, path, token, endpoint_id, name, envs, file, timeout=240):
#input("API POST2 called. Press Enter to continue.")
"""Example authenticated GET request to Portainer API."""
url = f"{base_url.rstrip('/')}{path}"
headers = {"Authorization": f"Bearer {token}"}
headers = {"X-API-Key": f"{token}"}
data = {
"EndpointId": endpoint_id,
"Name": name,
"Env": json.dumps(envs)
}
print(data)
resp = requests.post(url, headers=headers, files=file, data=data, timeout=timeout)
resp.raise_for_status()
return resp.json()
def api_post_no_body(base_url, path, token, timeout=120):
"""Example authenticated GET request to Portainer API."""
url = f"{base_url.rstrip('/')}{path}"
headers = {"Authorization": f"Bearer {token}"}
headers = {"X-API-Key": f"{token}"}
resp = requests.post(url, headers=headers, timeout=timeout)
resp.raise_for_status()
return resp.json()
def api_delete(base_url, path, token, timeout=20): def api_delete(base_url, path, token, timeout=20):
"""Example authenticated DELETE request to Portainer API.""" """Example authenticated DELETE request to Portainer API."""
wl("Deleting stack via API...")
url = f"{base_url.rstrip('/')}{path}" url = f"{base_url.rstrip('/')}{path}"
headers = {"Authorization": f"Bearer {token}"} headers = {"Authorization": f"Bearer {token}"}
headers = {"X-API-Key": f"{token}"} headers = {"X-API-Key": f"{token}"}
resp = requests.delete(url, headers=headers, timeout=timeout) resp = requests.delete(url, headers=headers, timeout=timeout)
wl(resp)
resp.raise_for_status() resp.raise_for_status()
print(resp.status_code) wl(resp.status_code)
return resp.status_code return resp.status_code
def refresh_status(base_url, token, stack, timeout=20):
path = f"/api/stacks/{stack}/images_status?refresh=true"
wl(path)
stacks = api_get(base_url, path, token, timeout=timeout)
wl(json.dumps(stacks, indent=2))
if stcks is None:
return []
return stcks
def get_stacks(base_url, token, endpoint_id=None, timeout=10): def get_stacks(base_url, token, endpoint_id=None, timeout=10):
""" """
Return a list of stacks. If endpoint_id is provided, it will be added as a query param. Return a list of stacks. If endpoint_id is provided, it will be added as a query param.
""" """
path = "/api/stacks" path = "/api/stacks"
if endpoint_id is not None: stcks = []
path += f"?endpointId={endpoint_id}"
stacks = api_get(base_url, path, token, timeout=timeout) stacks = api_get(base_url, path, token, timeout=timeout)
if stacks is None: for s in stacks:
if s['EndpointId'] == endpoint_id:
stcks.append(s)
wl(json.dumps(stacks, indent=2))
if stcks is None:
return [] return []
return stacks return stcks
def get_stack(base_url, identifier, token, endpoint_id=None, timeout=10): def get_stack(base_url, identifier, token, endpoint_id=None, timeout=10):
wl("get_stack")
""" """
Retrieve a single stack by numeric Id or by Name. Retrieve a single stack by numeric Id or by Name.
Identifier may be an int (Id) or a string (Name). Raises ValueError if not found. Identifier may be an int (Id) or a string (Name). Raises ValueError if not found.
""" """
#print(endpoint_id)
stacks = get_stacks(base_url, token, endpoint_id=endpoint_id, timeout=timeout) stacks = get_stacks(base_url, token, endpoint_id=endpoint_id, timeout=timeout)
# Normalize identifier # Normalize identifier
#input(stacks)
ident_id = None ident_id = None
#print(identifier)
try: try:
ident_id = int(identifier) ident_id = int(identifier)
except (TypeError, ValueError): except (TypeError, ValueError):
pass pass
#wl(stacks)
for s in stacks: for s in stacks:
# Many Portainer responses use 'Id' and 'Name' keys # Many Portainer responses use 'Id' and 'Name' keys
if ident_id is not None and s.get("Id") == ident_id: if ident_id is not None and s.get("Id") == ident_id and endpoint_id == s.get("EndpointId"):
return s return s
if str(s.get("Name")) == str(identifier): if str(s.get("Name")) == str(identifier) and endpoint_id == s.get("EndpointId"):
return s return s
raise ValueError(f"Stack not found: {identifier}") raise ValueError(f"Stack not found: {identifier}")
def create_stack(base_url, token, endpoint_id=None, data={}, timeout=120): def create_stack(base_url, token, endpoint_id=None, data={}, timeout=300):
""" """
Return a list of stacks. If endpoint_id is provided, it will be added as a query param. Return a list of stacks. If endpoint_id is provided, it will be added as a query param.
""" """
path = "/api/stacks/create/standalone/repository" path = "/api/stacks/create/standalone/repository"
if endpoint_id is not None: if endpoint_id is not None:
path += f"?endpointId={endpoint_id}" path += f"?endpointId={endpoint_id}"
wl(path)
try: try:
stacks = api_post(base_url, path, token, data, timeout=timeout) stacks = api_post(base_url, path, token, data, timeout=timeout)
except Exception as e: except Exception as e:
print(f"Error creating stack: {e}")
#print(f"Error creating stack: {e}")
if "Conflict for url" in str(e): if "Conflict for url" in str(e):
print("Stack with this name may already exist.") print("Stack with this name may already exist.")
else:
print(f"Error creating stack: {e}")
wl(json.dumps(data, indent=2))
return [] return []
if stacks is None: if stacks is None:
return [] return []
return stacks return stacks
def create_stack2(base_url, token, endpoint_id=None, name="", file="", envs=[], timeout=300):
#input("Creating stack from file... Press Enter to continue.")
"""
Return a list of stacks. If endpoint_id is provided, it will be added as a query param.
"""
path = "/api/stacks/create/standalone/file"
if endpoint_id is not None:
path += f"?endpointId={endpoint_id}&name={name}"
wl(path)
try:
stacks = api_post2(base_url, path, token, endpoint_id, name=name, envs=envs, file=file, timeout=timeout)
except Exception as e:
def delete_stack(base_url, token, endpoint_id=None, stack=None, timeout=30): print(f"Error creating stack: {e}")
if "Conflict for url" in str(e):
print("Stack with this name may already exist.")
else:
print(json.dumps(envs, indent=2))
return []
if stacks is None:
return []
return stacks
def stop_stack(base_url, token, endpoint_id=None, stack=None, timeout=120):
path = f"/api/stacks/{stack}/stop"
if endpoint_id is not None:
path += f"?endpointId={endpoint_id}"
try:
api_post_no_body(base_url, path, token, timeout=timeout)
except Exception as e:
print(f"Error stoping stack: {e}")
return []
return True
def start_stack(base_url, token, endpoint_id=None, stack=None, timeout=120):
path = f"/api/stacks/{stack}/start"
if endpoint_id is not None:
path += f"?endpointId={endpoint_id}"
try:
stacks = api_post_no_body(base_url, path, token, timeout=timeout)
except Exception as e:
print(f"Error starting stack: {e}")
return []
if stacks is None:
return []
return stacks
def delete_stack(base_url, token, endpoint_id=None, stack=None, timeout=120):
""" """
Return a list of stacks. If endpoint_id is provided, it will be added as a query param. Return a list of stacks. If endpoint_id is provided, it will be added as a query param.
""" """
@@ -144,14 +262,21 @@ def delete_stack(base_url, token, endpoint_id=None, stack=None, timeout=30):
path = f"/api/stacks/{s['Id']}" path = f"/api/stacks/{s['Id']}"
if endpoint_id is not None: if endpoint_id is not None:
path += f"?endpointId={endpoint_id}&removeVolumes=true" path += f"?endpointId={endpoint_id}&removeVolumes=true"
#print(path) if args.debug:
print(path)
out = api_delete(base_url, path, token, timeout=timeout) out = api_delete(base_url, path, token, timeout=timeout)
return "Done" return "Done"
else: else:
path = f"/api/stacks/{stack}" path = f"/api/stacks/{stack}"
if endpoint_id is not None:
path += f"?endpointId={endpoint_id}&removeVolumes=true"
# print(path)
try: try:
#print(path) # print(path)
# print(base_url)
# print(token)
stacks = api_delete(base_url, path, token, timeout=timeout) stacks = api_delete(base_url, path, token, timeout=timeout)
except Exception as e: except Exception as e:
#print(f"Error creating stack: {e}") #print(f"Error creating stack: {e}")
@@ -159,45 +284,316 @@ def delete_stack(base_url, token, endpoint_id=None, stack=None, timeout=30):
print("Stack with this name may already exist.") print("Stack with this name may already exist.")
else: else:
print(f"Error deleting stack: {e}") print(f"Error deleting stack: {e}")
print(stacks) #print(stacks)
return [] return []
if stacks is None: if stacks is None:
return [] return []
return stacks return stacks
def print_stacks(base, token): def print_stacks(base, token, endpoint=None,endpoints={}):
stacks = get_stacks(base, token) stacks = get_stacks(base, token, endpoint)
count = 0
lst = []
data = []
#print(stacks)
for stack in stacks: for stack in stacks:
#print(endpoint)
#print(stack['EndpointId'])
#print(stack)
if endpoint != None:
if not stack['EndpointId'] in endpoints['by_id']:
continue
if endpoint != stack['EndpointId']:
continue
if not stack['Name'] in basic_stacks:
lst.append(stack['Name'])
try: try:
print(f"Stack ID: {stack['Id']}, Name: {stack['Name']}, EndpointName: {eps[stack['EndpointId']]}") #print(f"Stack ID: {stack['Id']}, Name: {stack['Name']}, EndpointName: {eps[stack['EndpointId']]}")
data.append([stack['Id'], stack['Name'], endpoints['by_id'][stack['EndpointId']]])
except KeyError as e: except KeyError as e:
print(f"Stack ID: {stack['Id']}, Name: {stack['Name']}, EndpointName: ?") #print(f"Stack ID: {stack['Id']}, Name: {stack['Name']}, EndpointName: ?")
data.append([stack['Id'], stack['Name'], "?"])
count += 1
headers = ["StackID", "Name", "Endpoint"]
print(tabulate(data, headers=headers, tablefmt="github"))
print(f"Total stacks: {count}")
def resolve_endpoins(base,token):
base = os.getenv("PORTAINER_URL", "https://portainer.sectorq.eu")
endpoints = api_get(base, "/api/endpoints", token)
eps = {"by_id":{}, "by_name":{}}
for ep in endpoints:
eps['by_id'][ep['Id']] = ep['Name']
eps['by_name'][ep['Name']] = ep['Id']
return eps
if __name__ == "__main__": if __name__ == "__main__":
# Example usage: set PORTAINER_USER and PORTAINER_PASS in env, or pass literals below. # Example usage: set PORTAINER_USER and PORTAINER_PASS in env, or pass literals below.
base = os.getenv("PORTAINER_URL", "https://portainer.sectorq.eu") base = os.getenv("PORTAINER_URL", "https://portainer.sectorq.eu/api")
#token = get_portainer_token(base,"admin","l4c1j4yd33Du5lo") # or get_portainer_token(base, "admin", "secret") #token = get_portainer_token(base,"admin","l4c1j4yd33Du5lo") # or get_portainer_token(base, "admin", "secret")
token = portainer_api_key token = portainer_api_key
# Example: list endpoints # Example: list endpoints
endpoints = api_get(base, "/api/endpoints", token) por = Portainer(base, token)
#print(endpoints) if args.delete_stack:
eps = {} por.delete_stack(args.endpoint_id,args.stack,)
install_endpoint_id = None sys.exit()
for ep in endpoints:
eps[ep['Id']] = ep['Name'] if args.create_stack:
print(f"Endpoint ID: {ep['Id']}, Name: {ep['Name']}") por.create_stack(args.endpoint_id,args.stack, args.deploy_mode, args.autostart)
if args.endpoint_id == str(ep['Name']): sys.exit()
install_endpoint_id = ep['Id']
if install_endpoint_id == None: #print(por.base_url)
install_endpoint_id = args.endpoint_id
if args.stop_stack:
por.stop_stack(args.stack,args.endpoint_id)
sys.exit()
#print(por.base_url)
if args.start_stack:
por.start_stack(args.stack,args.endpoint_id)
sys.exit()
#print(por.base_url)
endpoints = resolve_endpoins(base, token)
wl(endpoints)
if is_number(args.endpoint_id):
install_endpoint_id = int(args.endpoint_id)
install_endpoint_name = endpoints['by_id'][install_endpoint_id]
else:
install_endpoint_id = endpoints['by_name'][args.endpoint_id]
install_endpoint_name = args.endpoint_id
wl(install_endpoint_name)
wl(install_endpoint_id)
if args.list_stacks: if args.list_stacks:
print_stacks(base, token) print_stacks(base, token, install_endpoint_id,endpoints)
if args.create_stack_new21:
print("Creating new stack from git repo...")
if not args.stack_id:
args.stack_id = input("Stack name? : ")
if install_endpoint_id == None:
install_endpoint_id = endpoints['by_id'][input("Endpoint name? : ")]
if is_number(install_endpoint_id):
install_endpoint_id = int(install_endpoint_id)
else:
install_endpoint_id = endpoints['by_name'][install_endpoint_id]
git_url = "https://gitlab.sectorq.eu/home/docker-compose.git"
git_url = "git@gitlab.sectorq.eu:home/docker-compose.git"
repo_dir = "/tmp/docker-compose"
# Check if folder exists
if os.path.exists(repo_dir):
shutil.rmtree(repo_dir)
print(f"Folder '{repo_dir}' has been removed.")
else:
print(f"Folder '{repo_dir}' does not exist.")
Repo.clone_from(git_url, repo_dir)
wl(args.stack_id)
wl(install_endpoint_id)
if args.stack_id == "all":
wl("All stacks selected")
if install_endpoint_name == "nas":
args.stack_id = nas_stacks
elif install_endpoint_name == "rpi5":
print("RPI5 stacks selected")
args.stack_id = rpi5_stacks
elif install_endpoint_name == "rack":
args.stack_id = rack_stacks
else:
args.stack_id = [args.stack_id]
for s in args.stack_id:
print(f"Processing stack: {s}")
if os.path.exists(f"{repo_dir}/{s}/.env"):
f = open(f"{repo_dir}/{s}/.env","r")
env_vars = f.read().splitlines()
envs = []
for ev in env_vars:
if ev.startswith("#") or ev.strip() == "":
continue
if "=" in ev:
name, value = ev.split("=",1)
envs.append({"name": name, "value": value})
f.close()
#wl(envs)
for e in envs:
wl(f"Env: {e['name']} = {e['value']}")
HWS = ["HW_MODE","HW_MODE1","HW_MODE2"]
if e['name'] == "RESTART" and args.endpoint_id == "m-server":
e['value'] = "always"
if e['name'] in HWS:
wl("Found HW_MODE env var.")
if args.gpu:
e['value'] = "hw"
else:
e['value'] = "cpu"
if e['name'] == "LOGGING":
wl("Found LOGGING env var.")
if args.gpu:
e['value'] = "journald"
else:
e['value'] = "syslog"
req = {
"Name": s,
"Env": envs,
"AdditionalFiles": [],
"AutoUpdate": None,
"repositoryURL": "https://gitlab.sectorq.eu/home/docker-compose.git",
"ReferenceName": "refs/heads/main",
"composeFile": f"{s}/docker-compose.yml",
"ConfigFilePath": f"{s}/docker-compose.yml",
"repositoryAuthentication": True,
"repositoryUsername": "jaydee",
"repositoryPassword": "glpat-uj-n-eEfTY398PE4vKSS",
"AuthorizationType": 0,
"TLSSkipVerify": False,
"supportRelativePath": True,
"repositoryAuthentication": True,
"fromAppTemplate": False,
"registries": [6,3],
"FromAppTemplate": False,
"Namespace": "",
"CreatedByUserId": "",
"Webhook": "",
"filesystemPath": "/share/docker_data/portainer/portainer-data/",
"RegistryID": 4,
"isDetachedFromGit": True
}
#wl(json.dumps(req, indent=2))
create_stack(base, token, install_endpoint_id, data=req)
if not args.autostart and s != "pihole":
tries = 0
while True:
try:
stck2 = get_stack(base, s, token, endpoint_id=install_endpoint_id)
break
except Exception as e:
print(f"Waiting for stack {s} to be created...")
time.sleep(10)
tries += 1
if tries > 20:
print(f"Error retrieving stack {s} after creation: {e}")
break
try:
print(f"Stopping stack: ID {stck2['Id']}, Name: {stck2['Name']}")
stop_stack(base, token, install_endpoint_id, stck2['Id'])
except Exception as e:
print(f"Error stopping stack {s}: {e}")
if args.create_stack_new2:
print("Creating new stack from file...")
if not args.stack_id:
args.stack_id = input("Stack name? : ")
if install_endpoint_id == None:
install_endpoint_id = endpoints['by_id'][input("Endpoint name? : ")]
if is_number(install_endpoint_id):
install_endpoint_id = int(install_endpoint_id)
else:
install_endpoint_id = endpoints['by_name'][install_endpoint_id]
git_url = "https://gitlab.sectorq.eu/home/docker-compose.git"
git_url = "git@gitlab.sectorq.eu:home/docker-compose.git"
repo_dir = "/tmp/docker-compose"
# Check if folder exists
if os.path.exists(repo_dir):
shutil.rmtree(repo_dir)
print(f"Folder '{repo_dir}' has been removed.")
else:
print(f"Folder '{repo_dir}' does not exist.")
Repo.clone_from(git_url, repo_dir)
wl(args.stack_id)
wl(install_endpoint_id)
if args.stack_id == "all":
wl("All stacks selected")
if install_endpoint_name == "nas":
args.stack_id = nas_stacks
elif install_endpoint_name == "rpi5":
print("RPI5 stacks selected")
args.stack_id = rpi5_stacks
elif install_endpoint_name == "rack":
args.stack_id = rack_stacks
else:
args.stack_id = [args.stack_id]
for s in args.stack_id:
# file = f"/tmp/docker-compose/{s}/docker-compose.yml"
print(f"Processing stack: {s}")
file = {
# ("filename", file_object)
"file": ("docker-compose.yml", open(f"/tmp/docker-compose/{s}/docker-compose.yml", "rb")),
}
print(file)
if os.path.exists(f"{repo_dir}/{s}/.env"):
f = open(f"{repo_dir}/{s}/.env","r")
env_vars = f.read().splitlines()
envs = []
for ev in env_vars:
if ev.startswith("#") or ev.strip() == "":
continue
if "=" in ev:
name, value = ev.split("=",1)
envs.append({"name": name, "value": value})
f.close()
#wl(envs)
for e in envs:
wl(f"Env: {e['name']} = {e['value']}")
HWS = ["HW_MODE","HW_MODE1","HW_MODE2"]
if e['name'] in HWS:
wl("Found HW_MODE env var.")
if args.gpu:
e['value'] = "hw"
else:
e['value'] = "cpu"
if e['name'] == "LOGGING":
wl("Found LOGGING env var.")
if args.gpu:
e['value'] = "journald"
else:
e['value'] = "syslog"
create_stack2(base, token, install_endpoint_id, name=s, file=file, envs=envs)
if not args.autostart and s != "pihole":
tries = 0
while True:
try:
stck2 = get_stack(base, s, token, endpoint_id=install_endpoint_id)
break
except Exception as e:
print(f"Waiting for stack {s} to be created...")
time.sleep(2)
tries += 1
if tries > 5:
print(f"Error retrieving stack {s} after creation: {e}")
break
try:
print(f"Stopping stack: ID {stck2['Id']}, Name: {stck2['Name']}")
stop_stack(base, token, install_endpoint_id, stck2['Id'])
except Exception as e:
print(f"Error stopping stack {s}: {e}")
#print(json.dumps(req, indent=2)) #print(json.dumps(req, indent=2))
if args.create_stack: if args.create_stack:
if not args.stack_id:
input("Stack name?")
stck = get_stack(base, args.stack_id, token) stck = get_stack(base, args.stack_id, token)
print(f"Found stack: ID {stck['Id']}, Name: {stck['Name']}") print(f"Found stack: ID {stck['Id']}, Name: {stck['Name']}")
print(json.dumps(stck, indent=2)) print(json.dumps(stck, indent=2))
@@ -277,15 +673,24 @@ if __name__ == "__main__":
} }
print(json.dumps(req, indent=2)) print(json.dumps(req, indent=2))
create_stack(base, token, install_endpoint_id, data=req) create_stack(base, token, install_endpoint_id, data=req)
else:
print("Not creating stack, --create-stack not provided.")
if args.create_stacks: if args.create_stacks:
for ns in nas_stacks: if args.endpoint_id == "nas":
s = nas_stacks
elif args.endpoint_id == "rpi5":
s = rpi5_stacks
elif args.endpoint_id == "rack":
s = rack_stacks
wl(s)
for ns in s:
wl(f"Processing stack: {ns}")
stck = get_stack(base, ns, token) stck = get_stack(base, ns, token)
print(f"Found stack: ID {stck['Id']}, Name: {stck['Name']}") print(f"Found stack: ID {stck['Id']}, Name: {stck['Name']}")
#print(json.dumps(stck, indent=2)) #print(json.dumps(stck, indent=2))
for e in stck["Env"]: for e in stck["Env"]:
#print(f"Env: {e['name']} = {e['value']}") #print(f"Env: {e['name']} = {e['value']}")
if e['name'] == "RESTART" and stck["Env"] == install_endpoint_id:
e['value'] = "always"
HWS = ["HW_MODE","HW_MODE1","HW_MODE2"] HWS = ["HW_MODE","HW_MODE1","HW_MODE2"]
if e['name'] in HWS: if e['name'] in HWS:
print("Found HW_MODE env var.") print("Found HW_MODE env var.")
@@ -304,7 +709,7 @@ if __name__ == "__main__":
try: try:
stck["AutoUpdate"]["Webhook"] = uid stck["AutoUpdate"]["Webhook"] = uid
except: except:
stck["AutoUpdate"] = {} stck["AutoUpdate"] = None
try: try:
req = { req = {
"Name": stck["Name"], "Name": stck["Name"],
@@ -359,11 +764,48 @@ if __name__ == "__main__":
} }
print(f"Creating stack: {ns}") print(f"Creating stack: {ns}")
create_stack(base, token, install_endpoint_id, data=req) create_stack(base, token, install_endpoint_id, data=req)
else: if not args.autostart:
print("Not creating stack, --create-stack not provided.") stck2 = get_stack(base, ns, token, endpoint_id=install_endpoint_id)
print(print_stacks(base, token, install_endpoint_id,endpoints))
print(f"Stopping stack: ID {stck2['Id']}, Name: {stck2['Name']}")
stop_stack(base, token, install_endpoint_id, stck2['Id'])
if args.delete_stack22:
print(f"Delete stack {args.stack_id}")
if not is_number(args.stack_id) and args.stack_id != "all":
args.stack_id = get_stack(base, args.stack_id, token, install_endpoint_id)['Id']
#print(args.stack_id)
#print(install_endpoint_id)
if args.delete_stack:
delete_stack(base, token, install_endpoint_id, args.stack_id) delete_stack(base, token, install_endpoint_id, args.stack_id)
else:
print("Not deleting stack, --create-stack not provided.") if args.stop_stack:
if args.stack_id == "all":
print("Stopping all stacks...")
stcks = get_stacks(base, token, endpoint_id=install_endpoint_id)
# stcks = get_stack(base, sta, token, endpoint_id=install_endpoint_id)
else:
stcks = [get_stack(base, args.stack_id, token, endpoint_id=install_endpoint_id)]
for stck in stcks:
print(f"Stopping stack {stck['Name']}")
stop_stack(base, token, install_endpoint_id, stck['Id'])
if args.start_stack:
if args.stack_id == "all":
print("Starting all stacks...")
stcks = get_stacks(base, token, endpoint_id=install_endpoint_id)
# stcks = get_stack(base, sta, token, endpoint_id=install_endpoint_id)
else:
stcks = [get_stack(base, args.stack_id, token, endpoint_id=install_endpoint_id)]
for stck in stcks:
print(f"Starting stack {stck['Name']}")
start_stack(base, token, install_endpoint_id, stck['Id'])
if args.refresh_status:
if args.stack_id == "all":
print("Stopping all stacks...")
stcks = get_stacks(base, token, endpoint_id=install_endpoint_id)
# stcks = get_stack(base, sta, token, endpoint_id=install_endpoint_id)
else:
refresh_status(base, args.stack_id, token)