mirror of
https://gitlab.sectorq.eu/jaydee/portainer.git
synced 2025-12-14 18:44:53 +01:00
build
This commit is contained in:
532
portainer.py
532
portainer.py
@@ -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)
|
||||||
|
|
||||||
Reference in New Issue
Block a user