Compare commits

..

8 Commits

Author SHA1 Message Date
63e158899e build 2025-12-20 15:22:59 +01:00
9336b56f96 build 2025-12-20 15:22:40 +01:00
66fba7b994 build 2025-12-20 15:20:29 +01:00
7804dbb117 build 2025-12-20 15:19:00 +01:00
fb1763e14d build 2025-12-20 15:16:40 +01:00
829891d1ba build 2025-12-20 15:13:14 +01:00
174aab4faa build 2025-12-19 17:23:20 +01:00
9c6445ee03 build 2025-12-19 17:08:15 +01:00
2 changed files with 66 additions and 49 deletions

82
port.py
View File

@@ -315,6 +315,7 @@ class Portainer:
def get_endpoint_id(self): def get_endpoint_id(self):
'''Get endpoint ID from either ID or name input.''' '''Get endpoint ID from either ID or name input.'''
# input(self.args.endpoint_id)
if self._is_number(self.args.endpoint_id): if self._is_number(self.args.endpoint_id):
self.endpoint_id = self.args.endpoint_id self.endpoint_id = self.args.endpoint_id
self.endpoint_name = self.endpoints["by_id"][self.args.endpoint_id] self.endpoint_name = self.endpoints["by_id"][self.args.endpoint_id]
@@ -394,14 +395,13 @@ class Portainer:
else: else:
eps = [self.get_endpoint_id()] eps = [self.get_endpoint_id()]
#input(eps)
for endpoint in eps: for endpoint in eps:
# print(s)
#print(self.args.stack) #print(self.args.stack)
if self.args.stack in ["all", None]: if self.args.stack in ["all", None]:
# input([id for id in self.all_data["stacks"][endpoint]['by_id'].keys()]) # input([id for id in self.all_data["stacks"][endpoint]['by_id'].keys()])
for s in [id for id in self.all_data["stacks"][endpoint]['by_id'].keys()]: for e in [id for id in self.all_data["stacks"][endpoint]['by_name'].keys()]:
#input(e)
# if s not in self.all_data["stacks"]: # if s not in self.all_data["stacks"]:
# continue # continue
#input(self.all_data) #input(self.all_data)
@@ -409,36 +409,36 @@ class Portainer:
# print(f"Endpoint {self.all_data["endpoints"]["by_id"][s]} is offline") # print(f"Endpoint {self.all_data["endpoints"]["by_id"][s]} is offline")
continue continue
# input(self.all_data["stacks"][endpoint]["by_name"]) # input(self.all_data["stacks"][endpoint]["by_name"])
for e in self.all_data["stacks"][endpoint]["by_name"]:
#input(e) #input(e)
path = ( path = (
f"/endpoints/{endpoint}/docker/containers/json" f"/endpoints/{endpoint}/docker/containers/json"
f'?all=1&filters={{"label": ["com.docker.compose.project={e}"]}}' f'?all=1&filters={{"label": ["com.docker.compose.project={e}"]}}'
)
logging.info(f"request : {path}")
try:
containers = self._api_get(path)
#input(containers)
except Exception as e:
print(f"failed to get containers from {path}: {e}")
continue
contr = []
try:
for c in containers:
# input(c)
cont.append(c["Names"][0].replace("/", ""))
contr.append(c["Names"][0].replace("/", ""))
if self.all_data["endpoints"]["by_id"][endpoint] in data:
data[self.all_data["endpoints"]["by_id"][endpoint]][e] = contr
else:
data[self.all_data["endpoints"]["by_id"][endpoint]] = {
e: contr
}
except Exception as e:
logger.debug(
f"Exception while getting containers for stack {e} ",
f"on endpoint {self.all_data['endpoints']['by_id'][endpoint]}: {e}",
) )
logging.info(f"request : {path}")
try:
containers = self._api_get(path)
#input(containers)
except Exception as e:
print(f"failed to get containers from {path}: {e}")
continue
contr = []
try:
for c in containers:
# input(c)
cont.append(c["Names"][0].replace("/", ""))
contr.append(c["Names"][0].replace("/", ""))
if self.all_data["endpoints"]["by_id"][endpoint] in data:
data[self.all_data["endpoints"]["by_id"][endpoint]][e] = contr
else:
data[self.all_data["endpoints"]["by_id"][endpoint]] = {
e: contr
}
except Exception as e:
logger.debug(
f"Exception while getting containers for stack {e} ",
f"on endpoint {self.all_data['endpoints']['by_id'][endpoint]}: {e}",
)
self.all_data["containers"] = data self.all_data["containers"] = data
@@ -834,7 +834,7 @@ class Portainer:
} }
self._api_post_file(path, self.endpoint_id, stack, envs, file) self._api_post_file(path, self.endpoint_id, stack, envs, file)
def print_stacks(self, endpoint="all"): def print_stacks(self, args):
"""Print a table of stacks, optionally filtered by endpoint.""" """Print a table of stacks, optionally filtered by endpoint."""
stacks = self.get_stacks() stacks = self.get_stacks()
count = 0 count = 0
@@ -842,11 +842,11 @@ class Portainer:
stack_names = [] stack_names = []
for stack in stacks: for stack in stacks:
# print(stack) # print(stack)
if endpoint is not None: if args.endpoint_id is not None:
if not stack["EndpointId"] in self.endpoints["by_id"]: if not stack["EndpointId"] in self.endpoints["by_id"]:
continue continue
if endpoint != "all": if args.endpoint_id != "all":
if self.endpoints["by_name"][endpoint] != stack["EndpointId"]: if self.endpoints["by_name"][args.endpoint_id] != stack["EndpointId"]:
continue continue
try: try:
stack_names.append(stack["Name"]) stack_names.append(stack["Name"])
@@ -873,7 +873,7 @@ class Portainer:
def update_containers(self): def update_containers(self):
all_containers = self.all_data["containers"][self.args.endpoint_id] all_containers = self.all_data["containers"][self.args.endpoint_id]
#input(all_containers) #input(all_containers)
service_tuples = [(s[1], s[0]) for s in all_containers if "." not in s[0]] service_tuples = [(s[1], s[0]) for s in all_containers if "." not in s[0] and not s[0].startswith("runner-")]
service_tuples = sorted(service_tuples, key=lambda x: x[1]) service_tuples = sorted(service_tuples, key=lambda x: x[1])
service_dict = dict(service_tuples) service_dict = dict(service_tuples)
# input(service_tuples) # input(service_tuples)
@@ -930,7 +930,7 @@ class Portainer:
print("?") print("?")
elif resp['Status'] == "outdated": elif resp['Status'] == "outdated":
if pull: if pull:
print("Recreate") #print("Recreate")
self.recreate_container(service_id, pull) self.recreate_container(service_id, pull)
#print(f"Service {service_dict[service_id]:<{longest}} : updated") #print(f"Service {service_dict[service_id]:<{longest}} : updated")
self.gotify_message(f"Service {service_dict[service_id]} updated") self.gotify_message(f"Service {service_dict[service_id]} updated")
@@ -1016,7 +1016,7 @@ class Portainer:
self.restart_srv(service_id, pull) self.restart_srv(service_id, pull)
#print(f"Service {service_dict[service_id]:<{longest}} : updated") #print(f"Service {service_dict[service_id]:<{longest}} : updated")
self.gotify_message(f"Service {service_dict[service_id]} updated") self.gotify_message(f"Service {service_dict[service_id]} updated")
print(ok) print(f"{ok} updated")
else: else:
print(f"\r\033[4m{service_dict[service_id]:<{longest}}\033[0m ", end="", flush=True) print(f"\r\033[4m{service_dict[service_id]:<{longest}}\033[0m ", end="", flush=True)
#print(f"\033[4m{service_dict[service_id]:<{longest}} {err}\033[0m") #print(f"\033[4m{service_dict[service_id]:<{longest}} {err}\033[0m")
@@ -1094,7 +1094,7 @@ class Portainer:
def recreate_container(self,service_id, pull=False): def recreate_container(self,service_id, pull=False):
"""Restart a service on an endpoint.""" """Restart a service on an endpoint."""
path = f"/docker/{self.endpoint_id}/containers/{service_id}/recreate" path = f"/docker/{self.endpoint_id}/containers/{service_id}/recreate"
print(path) # print(path)
params={"pullImage": pull} params={"pullImage": pull}
try: try:
resp = self._api_post(path, json=params, timeout=20) resp = self._api_post(path, json=params, timeout=20)

View File

@@ -39,7 +39,7 @@ else:
raise Exception("Failed to authenticate with Vault") raise Exception("Failed to authenticate with Vault")
# Specify the mount point of your KV engine # Specify the mount point of your KV engine
VERSION = "0.1.16" VERSION = "0.1.17"
defaults = { defaults = {
"endpoint_id": "vm01", "endpoint_id": "vm01",
@@ -83,10 +83,6 @@ def load_config(defaults=defaults):
print("Configuration written to /myapps/portainer.conf") print("Configuration written to /myapps/portainer.conf")
return cur_config return cur_config
a = load_config(defaults) a = load_config(defaults)
# ENV_VARS = [ # ENV_VARS = [
@@ -109,7 +105,11 @@ def update_configs(cur_config):
print("Configuration written to /myapps/portainer.conf") print("Configuration written to /myapps/portainer.conf")
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Portainer helper - use env vars or pass credentials." description=f"""\
Portainer helper - use env vars or pass credentials."
version: {VERSION}
""",
formatter_class=argparse.RawTextHelpFormatter,
) )
parser.add_argument( parser.add_argument(
"--base", "--base",
@@ -372,7 +372,7 @@ def prompt_missing_args(args_in, defaults_in, fields, action=None,stacks=None):
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")
def signal_handler(sig, frame): def signal_handler(sig, frame):
logger.warning("Killed manually %s, %s", sig, frame) logger.warning("Killed manually %s, %s", sig, frame)
print("\nTerminated by user") print("\nTerminated by user")
@@ -579,7 +579,15 @@ if __name__ == "__main__":
if args.action == "list_containers": if args.action == "list_containers":
print("Getting containers") print("Getting containers")
print(por.get_containers()) args = prompt_missing_args(
args,
cur_config,
[
("site", "Site"),
("endpoint_id", "Endpoint ID"),
],
)
print("\n".join(por.get_containers()))
sys.exit() sys.exit()
if args.action == "update_stack": if args.action == "update_stack":
@@ -613,6 +621,15 @@ if __name__ == "__main__":
sys.exit() sys.exit()
if args.action == "stop_containers": if args.action == "stop_containers":
# TODO: does not work
args = prompt_missing_args(
args,
cur_config,
[
("site", "Site"),
("endpoint_id", "Endpoint ID"),
],
)
if por.all_data["endpoints_status"][args.endpoint_id] != 1: if por.all_data["endpoints_status"][args.endpoint_id] != 1:
print(f"Endpoint {por.get_endpoint_name(args.endpoint_id)} is offline") print(f"Endpoint {por.get_endpoint_name(args.endpoint_id)} is offline")
sys.exit() sys.exit()