This commit is contained in:
2025-12-04 15:59:56 +01:00
parent 0ab5e9627b
commit 90712be4b2
2 changed files with 68 additions and 15 deletions

View File

@@ -725,9 +725,11 @@ class Portainer:
self.get_stack(stack, endpoint_id) self.get_stack(stack, endpoint_id)
else: else:
if stack is not None: if stack is not None:
self.stack_ids = [self.get_stack(stack, endpoint_id)["Id"]] self.stack_ids = [self._resolve_stack_id(stack, endpoint_id)]
# print(self.stack_ids)
for stck in self.stack_ids: for stck in self.stack_ids:
path = f"/stacks/{stack}/stop" path = f"/stacks/{stck}/stop"
# print(path)
if self.endpoint_id is not None: if self.endpoint_id is not None:
path += f"?endpointId={self.endpoint_id}" path += f"?endpointId={self.endpoint_id}"
try: try:

View File

@@ -11,6 +11,8 @@ import logging
import sys import sys
import json import json
import argparse import argparse
import tty
import termios
from tabulate import tabulate from tabulate import tabulate
from port import Portainer from port import Portainer
@@ -189,6 +191,41 @@ def prompt_missing_args(args_in, defaults_in, fields):
""" """
fields = [("arg_name", "Prompt text")] fields = [("arg_name", "Prompt text")]
""" """
def input_with_default(prompt, default):
full_prompt = f" >> {prompt:40}"
sys.stdout.write(full_prompt)
sys.stdout.flush()
checkmark = "\033[92m\u2714\033[0m"
# read raw input char-by-char
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(fd)
user_input = ""
while True:
ch = sys.stdin.read(1)
if ch in ("\n", "\r"): # ENTER
break
elif ch == "\x7f": # BACKSPACE
if user_input:
user_input = user_input[:-1]
sys.stdout.write("\b \b")
sys.stdout.flush()
else:
user_input += ch
sys.stdout.write(ch)
sys.stdout.flush()
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
if not user_input:
user_input = default
# rewrite final line cleanly
sys.stdout.write(f"\r{full_prompt}{user_input:10} {checkmark}\n")
sys.stdout.flush()
return user_input
for field, text in fields: for field, text in fields:
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())
@@ -196,10 +233,12 @@ def prompt_missing_args(args_in, defaults_in, fields):
if value_in is None: if value_in is None:
if default is not None: if default is not None:
prompt = f"{text} (default={default}) : " prompt = f"{text} (default={default}) : "
value_in = input(prompt) or default # value_in = input(prompt) or default
value_in = input_with_default(prompt, default)
defaults_in[f"PORTAINER_{field}".upper()] = value_in defaults_in[f"PORTAINER_{field}".upper()] = value_in
else: else:
value_in = input(f"{text}: ") #value_in = input(f"{text}: ")
value_in = input_with_default(text, default)
defaults_in[f"PORTAINER_{field}".upper()] = value_in defaults_in[f"PORTAINER_{field}".upper()] = value_in
setattr(args, field, value_in) setattr(args, field, value_in)
os.environ[field] = value_in os.environ[field] = value_in
@@ -214,6 +253,7 @@ print(cur_config)
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.
# 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")
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",
@@ -232,14 +272,14 @@ if __name__ == "__main__":
"refresh_status", "refresh_status",
"update_status", "update_status",
] ]
print("Possible actions: ") print("Possible actions: \n")
i = 1 i = 1
for a in actions: for a in actions:
print(f" > {i}. {a}") print(f" > {i:>2}. {a}")
i += 1 i += 1
ans = input("\nSelect action to perform: ") ans = input("\nSelect action to perform: ")
args.action = actions[int(ans) - 1] args.action = actions[int(ans) - 1]
os.system("cls" if os.name == "nt" else "clear")
# Example: list endpoints # Example: list endpoints
por = Portainer(base, PORTAINER_API_KEY, timeout=args.timeout) por = Portainer(base, PORTAINER_API_KEY, timeout=args.timeout)
@@ -297,18 +337,29 @@ if __name__ == "__main__":
sys.exit() sys.exit()
if args.action == "stop_stack": if args.action == "stop_stack":
if args.endpoint_id is None: args = prompt_missing_args(
args.endpoint_id = input("Endpoint ID is required for stopping stacks : ") args,
if args.stack is None: cur_config,
args.stack = input("Stack name or ID is required for stopping stacks : ") [
("site", "Site"),
("endpoint_id", "Endpoint ID"),
("stack", "Stack name or ID"),
],
)
por.stop_stack(args.stack, args.endpoint_id) por.stop_stack(args.stack, args.endpoint_id)
sys.exit() sys.exit()
if args.action == "start_stack": if args.action == "start_stack":
if args.endpoint_id is None: args = prompt_missing_args(
args.endpoint_id = input("Endpoint ID is required for starting stacks : ") args,
if args.stack is None: cur_config,
args.stack = input("Stack name or ID is required for starting stacks : ") [
("site", "Site"),
("endpoint_id", "Endpoint ID"),
("stack", "Stack name or ID"),
],
)
por.start_stack(args.stack, args.endpoint_id) por.start_stack(args.stack, args.endpoint_id)
sys.exit() sys.exit()