mirror of
https://gitlab.sectorq.eu/jaydee/portainer.git
synced 2025-12-14 10:44:52 +01:00
build
This commit is contained in:
4
port.py
4
port.py
@@ -27,6 +27,7 @@ class Portainer:
|
|||||||
def __init__(self, site, timeout=10):
|
def __init__(self, site, timeout=10):
|
||||||
self.base_url = None
|
self.base_url = None
|
||||||
self.token = None
|
self.token = None
|
||||||
|
self.action = None
|
||||||
self._debug = False
|
self._debug = False
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
self.git_url = "git@gitlab.sectorq.eu:home/docker-compose.git"
|
self.git_url = "git@gitlab.sectorq.eu:home/docker-compose.git"
|
||||||
@@ -36,6 +37,7 @@ class Portainer:
|
|||||||
self.stack_ids = []
|
self.stack_ids = []
|
||||||
self.endpoint_name = None
|
self.endpoint_name = None
|
||||||
self.endpoint_id = None
|
self.endpoint_id = None
|
||||||
|
|
||||||
# self.git_url = "https://gitlab.sectorq.eu/home/docker-compose.git"
|
# self.git_url = "https://gitlab.sectorq.eu/home/docker-compose.git"
|
||||||
self.git_url = "git@gitlab.sectorq.eu:home/docker-compose.git"
|
self.git_url = "git@gitlab.sectorq.eu:home/docker-compose.git"
|
||||||
self.repo_dir = "/tmp/docker-compose"
|
self.repo_dir = "/tmp/docker-compose"
|
||||||
@@ -192,7 +194,7 @@ class Portainer:
|
|||||||
self.get_containers(self)
|
self.get_containers(self)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_stacks(self, endpoint_id="all", timeout=10):
|
def get_stacks(self, endpoint_id="all", timeout=20):
|
||||||
'''Get a list of stacks for a specific endpoint or all endpoints.'''
|
'''Get a list of stacks for a specific endpoint or all endpoints.'''
|
||||||
if endpoint_id != "all":
|
if endpoint_id != "all":
|
||||||
endpoint_id = self.get_endpoint_id(endpoint_id)
|
endpoint_id = self.get_endpoint_id(endpoint_id)
|
||||||
|
|||||||
172
portainer.py
172
portainer.py
@@ -19,7 +19,12 @@ from port import Portainer
|
|||||||
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
|
||||||
|
from prompt_toolkit.shortcuts import radiolist_dialog
|
||||||
|
from prompt_toolkit.application import Application
|
||||||
|
from prompt_toolkit.layout import Layout
|
||||||
|
from prompt_toolkit.widgets import RadioList
|
||||||
|
from prompt_toolkit.key_binding import KeyBindings
|
||||||
|
from prompt_toolkit.layout.containers import HSplit
|
||||||
VERSION = "0.1.3"
|
VERSION = "0.1.3"
|
||||||
|
|
||||||
defaults = {
|
defaults = {
|
||||||
@@ -32,6 +37,91 @@ defaults = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cur_config = {}
|
cur_config = {}
|
||||||
|
|
||||||
|
def menu(title, options):
|
||||||
|
"""
|
||||||
|
Display a menu and return selected value.
|
||||||
|
options must be list of (value, text) or text (auto-wrapped)
|
||||||
|
"""
|
||||||
|
if isinstance(options[0], str):
|
||||||
|
options = [(item, item) for item in options]
|
||||||
|
|
||||||
|
radio = RadioList(options)
|
||||||
|
|
||||||
|
kb = KeyBindings()
|
||||||
|
|
||||||
|
@kb.add("enter")
|
||||||
|
def _(event):
|
||||||
|
event.app.exit(result=radio.current_value)
|
||||||
|
@kb.add("q")
|
||||||
|
def _(event):
|
||||||
|
event.app.exit(result=None)
|
||||||
|
layout = Layout(HSplit([radio]))
|
||||||
|
|
||||||
|
app = Application(
|
||||||
|
layout=layout,
|
||||||
|
key_bindings=kb,
|
||||||
|
full_screen=True
|
||||||
|
)
|
||||||
|
|
||||||
|
return app.run()
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------
|
||||||
|
# MULTI-LEVEL MENU
|
||||||
|
# --------------------------
|
||||||
|
|
||||||
|
def main_menu():
|
||||||
|
while True:
|
||||||
|
choice = menu("Main Menu", [
|
||||||
|
"System",
|
||||||
|
"Network",
|
||||||
|
"Services",
|
||||||
|
"Exit"
|
||||||
|
])
|
||||||
|
|
||||||
|
if choice == "System":
|
||||||
|
system_menu()
|
||||||
|
|
||||||
|
elif choice == "Network":
|
||||||
|
network_menu()
|
||||||
|
|
||||||
|
elif choice == "Services":
|
||||||
|
services_menu()
|
||||||
|
|
||||||
|
elif choice == "Exit":
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def system_menu():
|
||||||
|
choice = menu("System Menu", [
|
||||||
|
"Info",
|
||||||
|
"Reboot",
|
||||||
|
"Back"
|
||||||
|
])
|
||||||
|
print("SYSTEM →", choice)
|
||||||
|
|
||||||
|
|
||||||
|
def network_menu():
|
||||||
|
choice = menu("Network Menu", [
|
||||||
|
"Show IP",
|
||||||
|
"Restart Networking",
|
||||||
|
"Back"
|
||||||
|
])
|
||||||
|
print("NETWORK →", choice)
|
||||||
|
|
||||||
|
|
||||||
|
def services_menu():
|
||||||
|
choice = menu("Services", [
|
||||||
|
"Start Service",
|
||||||
|
"Stop Service",
|
||||||
|
"Status",
|
||||||
|
"Back"
|
||||||
|
])
|
||||||
|
print("SERVICES →", choice)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def load_config(defaults=defaults):
|
def load_config(defaults=defaults):
|
||||||
'''Load configuration from /myapps/portainer.conf if it exists, else from env vars or defaults.'''
|
'''Load configuration from /myapps/portainer.conf if it exists, else from env vars or defaults.'''
|
||||||
if os.path.exists("/myapps/portainer.conf"):
|
if os.path.exists("/myapps/portainer.conf"):
|
||||||
@@ -212,7 +302,7 @@ def wl(msg):
|
|||||||
print(msg)
|
print(msg)
|
||||||
|
|
||||||
|
|
||||||
def prompt_missing_args(args_in, defaults_in, fields, action=None):
|
def prompt_missing_args(args_in, defaults_in, fields, action=None,stacks=None):
|
||||||
"""
|
"""
|
||||||
fields = [("arg_name", "Prompt text")]
|
fields = [("arg_name", "Prompt text")]
|
||||||
"""
|
"""
|
||||||
@@ -227,6 +317,7 @@ def prompt_missing_args(args_in, defaults_in, fields, action=None):
|
|||||||
value_in = getattr(args_in, field)
|
value_in = getattr(args_in, field)
|
||||||
default = defaults_in.get(f"PORTAINER_{field}".upper())
|
default = defaults_in.get(f"PORTAINER_{field}".upper())
|
||||||
cur_site = defaults_in.get("PORTAINER_SITE".upper())
|
cur_site = defaults_in.get("PORTAINER_SITE".upper())
|
||||||
|
cur_env = defaults_in.get("PORTAINER_ENVIRONMENT_ID".upper())
|
||||||
if value_in is None:
|
if value_in is None:
|
||||||
if default is not None:
|
if default is not None:
|
||||||
prompt_text = f"{text} (default={default}) : "
|
prompt_text = f"{text} (default={default}) : "
|
||||||
@@ -241,13 +332,19 @@ def prompt_missing_args(args_in, defaults_in, fields, action=None):
|
|||||||
commands = por.endpoints_names
|
commands = por.endpoints_names
|
||||||
elif field == "stack":
|
elif field == "stack":
|
||||||
if args.action == "create_stack":
|
if args.action == "create_stack":
|
||||||
|
# input(json.dumps(stacks, indent=2))
|
||||||
commands = [
|
commands = [
|
||||||
'authentik', 'bitwarden', 'bookstack', 'dockermon', 'fail2ban', 'gitea', 'gitlab', 'grafana',
|
'authentik', 'bitwarden', 'bookstack', 'dockermon', 'fail2ban', 'gitea', 'gitlab', 'grafana',
|
||||||
'home-assistant', 'homepage', 'immich', 'influxdb', 'jupyter', 'kestra', 'mailu3',
|
'home-assistant', 'homepage', 'immich', 'influxdb', 'jupyter', 'kestra', 'mailu3',
|
||||||
'mealie', 'mediacenter', 'mosquitto', 'motioneye', 'n8n', 'nextcloud', 'nginx',
|
'mealie', 'mediacenter', 'mosquitto', 'motioneye', 'n8n', 'nebula', 'nextcloud', 'nginx',
|
||||||
'node-red', 'octoprint', 'ollama', 'pihole', 'portainer-ce', 'rancher', 'registry',
|
'node-red', 'octoprint', 'ollama', 'pihole', 'portainer-ce', 'rancher', 'registry',
|
||||||
'regsync', 'semaphore', 'unifibrowser', 'uptime-kuma', 'watchtower', 'wazuh', 'webhub',
|
'regsync', 'semaphore', 'unifibrowser', 'uptime-kuma', 'watchtower', 'wazuh', 'webhub',
|
||||||
'wud', 'zabbix-server']
|
'wud', 'zabbix-server']
|
||||||
|
for s in por.all_data['stacks'][defaults_in[f"PORTAINER_ENDPOINT_ID".upper()]]['by_name'].keys():
|
||||||
|
|
||||||
|
# print(s)
|
||||||
|
commands.remove(s)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
commands = []
|
commands = []
|
||||||
if por._debug:
|
if por._debug:
|
||||||
@@ -280,11 +377,11 @@ def prompt_missing_args(args_in, defaults_in, fields, action=None):
|
|||||||
).run()
|
).run()
|
||||||
if value_in is None:
|
if value_in is None:
|
||||||
print("Cancelled.")
|
print("Cancelled.")
|
||||||
|
sys.exit(0)
|
||||||
elif "__ALL__" in value_in:
|
elif "__ALL__" in value_in:
|
||||||
# User selected "Select ALL"
|
# User selected "Select ALL"
|
||||||
value_in = commands # all real commands
|
value_in = commands # all real commands
|
||||||
if "pihole" in value_in:
|
if "pihole" in value_in:
|
||||||
|
|
||||||
if action == "delete_stack":
|
if action == "delete_stack":
|
||||||
value_in.remove("pihole")
|
value_in.remove("pihole")
|
||||||
value_in.append("pihole")
|
value_in.append("pihole")
|
||||||
@@ -333,7 +430,6 @@ def prompt_missing_args(args_in, defaults_in, fields, action=None):
|
|||||||
|
|
||||||
if field == "site" and value_in != cur_site:
|
if field == "site" and value_in != cur_site:
|
||||||
por.get_site(value_in)
|
por.get_site(value_in)
|
||||||
|
|
||||||
if field == "stack" and value_in != cur_site:
|
if field == "stack" and value_in != cur_site:
|
||||||
os.environ[field] = ",".join(value_in)
|
os.environ[field] = ",".join(value_in)
|
||||||
else:
|
else:
|
||||||
@@ -364,35 +460,52 @@ if __name__ == "__main__":
|
|||||||
os.system("cls" if os.name == "nt" else "clear")
|
os.system("cls" if os.name == "nt" else "clear")
|
||||||
if args.action is None:
|
if args.action is None:
|
||||||
actions = [
|
actions = [
|
||||||
"create_stack",
|
("create_stack","create_stack"),
|
||||||
"delete_stack",
|
("delete_stack","delete_stack"),
|
||||||
"stop_stack",
|
("stop_stack","stop_stack"),
|
||||||
"start_stack",
|
("start_stack","start_stack"),
|
||||||
"list_stacks",
|
("list_stacks","list_stacks"),
|
||||||
"update_stack",
|
("update_stack","update_stack"),
|
||||||
"secrets",
|
("secrets","secrets"),
|
||||||
"print_all_data",
|
("print_all_data","print_all_data"),
|
||||||
"list_endpoints",
|
("list_endpoints","list_endpoints"),
|
||||||
"list_containers",
|
("list_containers","list_containers"),
|
||||||
"stop_containers",
|
("stop_containers","stop_containers"),
|
||||||
"start_containers",
|
("start_containers","start_containers"),
|
||||||
"refresh_environment",
|
("refresh_environment","refresh_environment"),
|
||||||
"refresh_status",
|
("refresh_status","refresh_status"),
|
||||||
"update_status",
|
("update_status","update_status"),
|
||||||
]
|
]
|
||||||
print("Possible actions: \n")
|
|
||||||
i = 1
|
selected_action = radiolist_dialog(
|
||||||
for a in actions:
|
title="Select one service",
|
||||||
print(f" > {i:>2}. {a}")
|
text="Choose a service:",
|
||||||
i += 1
|
values=actions
|
||||||
ans = input("\nSelect action to perform: ")
|
).run()
|
||||||
args.action = actions[int(ans) - 1]
|
|
||||||
|
|
||||||
|
|
||||||
|
print("Selected:", selected_action)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# print("Possible actions: \n")
|
||||||
|
# i = 1
|
||||||
|
# for a in actions:
|
||||||
|
# print(f" > {i:>2}. {a}")
|
||||||
|
# i += 1
|
||||||
|
# ans = input("\nSelect action to perform: ")
|
||||||
|
args.action = selected_action
|
||||||
|
|
||||||
|
|
||||||
os.system("cls" if os.name == "nt" else "clear")
|
os.system("cls" if os.name == "nt" else "clear")
|
||||||
# Example: list endpoints
|
# Example: list endpoints
|
||||||
por = Portainer(cur_config["PORTAINER_SITE"], timeout=args.timeout)
|
por = Portainer(cur_config["PORTAINER_SITE"], timeout=args.timeout)
|
||||||
por.set_defaults(cur_config)
|
por.set_defaults(cur_config)
|
||||||
if args.debug:
|
if args.debug:
|
||||||
por._debug = True
|
por._debug = True
|
||||||
|
|
||||||
if args.action == "secrets":
|
if args.action == "secrets":
|
||||||
args = prompt_missing_args(
|
args = prompt_missing_args(
|
||||||
args,
|
args,
|
||||||
@@ -402,7 +515,6 @@ if __name__ == "__main__":
|
|||||||
("endpoint_id", "Endpoint ID"),
|
("endpoint_id", "Endpoint ID"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
secrets = {
|
secrets = {
|
||||||
"gitea_runner_registration_token": "8nmKqJhkvYwltmNfF2o9vs0tzo70ufHSQpVg6ymb",
|
"gitea_runner_registration_token": "8nmKqJhkvYwltmNfF2o9vs0tzo70ufHSQpVg6ymb",
|
||||||
"influxdb2-admin-token": "l4c1j4yd33Du5lo",
|
"influxdb2-admin-token": "l4c1j4yd33Du5lo",
|
||||||
@@ -437,6 +549,7 @@ if __name__ == "__main__":
|
|||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
if args.action == "create_stack":
|
if args.action == "create_stack":
|
||||||
|
por.action = "create_stack"
|
||||||
args = prompt_missing_args(
|
args = prompt_missing_args(
|
||||||
args,
|
args,
|
||||||
cur_config,
|
cur_config,
|
||||||
@@ -447,6 +560,7 @@ if __name__ == "__main__":
|
|||||||
("stack_mode", "Stack mode (swarm or compose)"),
|
("stack_mode", "Stack mode (swarm or compose)"),
|
||||||
("deploy_mode", "Deploy mode (git or upload)"),
|
("deploy_mode", "Deploy mode (git or upload)"),
|
||||||
],
|
],
|
||||||
|
por,
|
||||||
)
|
)
|
||||||
por.create_stack(
|
por.create_stack(
|
||||||
args.endpoint_id,
|
args.endpoint_id,
|
||||||
|
|||||||
Reference in New Issue
Block a user