This commit is contained in:
2025-12-04 22:02:58 +01:00
parent f8b0acdfcc
commit ee01577a6c
2 changed files with 135 additions and 43 deletions

View File

@@ -16,7 +16,8 @@ import tty
import termios
from tabulate import tabulate
from port import Portainer
from prompt_toolkit import prompt
from prompt_toolkit.completion import WordCompleter
VERSION = "0.0.5"
@@ -42,7 +43,7 @@ else:
print("No /myapps/portainer.conf file found, proceeding with env vars.")
os.makedirs("/myapps", exist_ok=True)
for field in defaults.keys():
value_in = os.getenv(f"PORTAINER_{field.upper()}")
if value_in is not None:
@@ -176,16 +177,17 @@ logging.info("script started")
logger = logging.getLogger(__name__)
def wl(msg):
"""Write log message if debug is enabled."""
if args.debug:
print(msg)
def prompt_missing_args(args_in, defaults_in, fields):
"""
fields = [("arg_name", "Prompt text")]
"""
def input_with_default(prompt, default, longest):
full_prompt = f" >> {prompt:{longest}}"
sys.stdout.write(full_prompt)
@@ -219,11 +221,12 @@ def prompt_missing_args(args_in, defaults_in, fields):
# rewrite final line cleanly
sys.stdout.write(f"\r{full_prompt}{user_input:10} {checkmark}\n")
sys.stdout.flush()
return user_input
longest = 0
for field, text in fields:
a = text + " (default= " + cur_config["PORTAINER_" + field.upper()] + ")"
a = text + " (default= " + cur_config["PORTAINER_" + field.upper()] + ")"
if len(a) > longest:
longest = len(a)
@@ -233,24 +236,96 @@ def prompt_missing_args(args_in, defaults_in, fields):
cur_site = defaults_in.get("PORTAINER_SITE".upper())
if value_in is None:
if default is not None:
prompt = f"{text} (default={default}) : "
prompt_text = f"{text} (default={default}) : "
# value_in = input(prompt) or default
value_in = input_with_default(prompt, default, longest+2)
defaults_in[f"PORTAINER_{field}".upper()] = value_in
if field == "site":
commands = ["portainer", "port"]
elif field == "deploy_mode":
commands = ["git", "upload"]
elif field == "stack_mode":
commands = ["swarm", "compose"]
elif field == "endpoint_id":
commands = por.endpoints_names
elif field == "stack":
if args.action == "create_stack":
commands = []
else:
commands = []
if por._debug:
input(por.stacks_all)
# print(defaults_in[f"PORTAINER_ENDPOINT_ID".upper()])
try:
for s in por.stacks_all[
defaults_in[f"PORTAINER_ENDPOINT_ID".upper()]
]["by_name"].keys():
commands.append(s)
except KeyError:
print(
"No stacks found for endpoint",
defaults_in[f"PORTAINER_ENDPOINT_ID".upper()],
)
sys.exit(1)
else:
commands = []
completer = WordCompleter(
commands, ignore_case=True, match_middle=False
)
try:
value_in = (
prompt(
f" >> {prompt_text}",
completer=completer,
placeholder=default,
)
or default
)
except KeyboardInterrupt:
print("\n^C received — exiting cleanly.")
sys.exit(0)
# value_in = input_with_default(prompt_text, default, longest+2)
else:
#value_in = input(f"{text}: ")
value_in = input_with_default(text, default, longest+2)
defaults_in[f"PORTAINER_{field}".upper()] = value_in
# value_in = input(f"{text}: ")
commands = ["start", "stop", "status", "restart", "reload", "exit"]
completer = WordCompleter(commands, ignore_case=True)
try:
value_in = (
prompt(
f" >> {text} {default}",
completer=completer,
placeholder=default,
)
or default
)
except KeyboardInterrupt:
print("\n^C received — exiting cleanly.")
sys.exit(0)
# value_in = input_with_default(text, default, longest+2)
if por._debug:
print("Value entered:", value_in)
defaults_in[f"PORTAINER_{field}".upper()] = value_in
setattr(args, field, value_in)
os.environ[field] = value_in
if field == "site" and value_in != cur_site:
por.get_site(value_in)
if por._debug:
print(f"{defaults_in} {field} {value_in}")
if field == "endpoint_id" and value_in != defaults_in.get(
"PORTAINER_ENDPOINT_ID".upper()
):
print("refreshing environment")
por.get_endpoints()
with open("/myapps/portainer.conf", "w") as f:
for k in defaults_in.keys():
f.write(f"{k}={defaults_in[k]}\n")
return args
print(cur_config)
if __name__ == "__main__":
# Example usage: set PORTAINER_USER and PORTAINER_PASS in env, or pass literals below.
@@ -289,7 +364,7 @@ if __name__ == "__main__":
args.action = actions[int(ans) - 1]
os.system("cls" if os.name == "nt" else "clear")
# Example: list endpoints
por = Portainer(defaults['site'], timeout=args.timeout)
por = Portainer(defaults["site"], timeout=args.timeout)
if args.debug:
por._debug = True
if args.action == "secrets":
@@ -318,6 +393,10 @@ if __name__ == "__main__":
("stack", "Stack name or ID"),
],
)
input(
f"Delete stack {args.stack} on endpoint {args.endpoint_id}. Press ENTER to continue..."
)
por.delete_stack(
args.endpoint_id,
args.stack,
@@ -355,7 +434,7 @@ if __name__ == "__main__":
("stack", "Stack name or ID"),
],
)
por.stop_stack(args.stack, args.endpoint_id)
sys.exit()