This commit is contained in:
2025-12-11 22:10:12 +01:00
parent 2e3c611c2a
commit 101bfbc9a4
2 changed files with 91 additions and 14 deletions

84
port.py
View File

@@ -109,12 +109,13 @@ class Portainer:
] ]
self.log_mode = False self.log_mode = False
self.hw_mode = False self.hw_mode = False
self.all_data = {"containers": {}, "stacks": {}, "endpoints": {}} self.all_data = {"containers": {}, "stacks": {}, "endpoints": {}, "services":{}}
self.get_site(site) self.get_site(site)
self.get_endpoints() self.get_endpoints()
self.get_stacks() self.get_stacks()
self.get_containers() self.get_containers()
def set_defaults(self, config): def set_defaults(self, config):
'''Set default configuration from provided config dictionary.''' '''Set default configuration from provided config dictionary.'''
self.cur_config = config self.cur_config = config
@@ -272,9 +273,11 @@ class Portainer:
# input(json.dumps(self.stacks_all,indent=2)) # input(json.dumps(self.stacks_all,indent=2))
return stcks return stcks
def get_services(self, endpoint, stack, timeout=30): def get_services(self, endpoint, timeout=30):
'''Get a list of services for a specific stack on an endpoint.''' '''Get a list of services for a specific stack on an endpoint.'''
path = f"/endpoints/{self.all_data['endpoints']['by_name'][endpoint]}/docker/services" print(json.dumps(self.all_data,indent=2))
path = f"/endpoints/{endpoint}/docker/services"
print(path)
#path += f'?filters={{"label": ["com.docker.compose.project={stack}"]}}' #path += f'?filters={{"label": ["com.docker.compose.project={stack}"]}}'
services = self._api_get(path, timeout=timeout) services = self._api_get(path, timeout=timeout)
return services return services
@@ -756,6 +759,70 @@ class Portainer:
print(f"Total stacks: {count}") print(f"Total stacks: {count}")
# print(sorted(stack_names)) # print(sorted(stack_names))
def update_service(self, endpoint_id=None, service_id=None):
all_services = self.get_services(self.get_endpoint_id(endpoint_id))
service_tuples = [(s['ID'], s['Spec']['Name']) for s in all_services]
input(service_tuples)
if service_id == "all":
service_id = self.all
#services = [(s["Id"], s["Name"]) for s in self.get_stacks(endpoint_id)]
services.insert(0, ("__ALL__", "[Select ALL]"))
service_ids = checkboxlist_dialog(
title="Select one service",
text="Choose a service:",
values=services
).run()
if service_ids == "__ALL__":
pass
print(service_ids)
service_dict = dict(service_ids)
services = self.get_services(self.endpoint_name, stack_id)
svc_name = service_dict.get(stack_id)
stack_svcs = []
svc_menu = []
for s in services:
try:
if svc_name in s['Spec']['Name']:
stack_svcs.append([s['Version']['Index'], s['Spec']['Name']])
svc_menu.append([s['ID'], s['Spec']['Name']])
except KeyError as e:
print(e)
service_id = radiolist_dialog(
title="Select one service",
text="Choose a service:",
values=svc_menu
).run()
"""Restart a service on an endpoint."""
path = f"/docker/{self.endpoint_id}/services/{service_id}/image_status?refresh=true"
try:
resp = self._api_get(path, timeout=20)
except ValueError as e:
print(f"Error restarting service: {e}")
return []
if resp['Status'] == "outdated":
self.restart_srv(service_id, True)
print(f"Service {service_id} : restarted")
return True
def restart_srv(self,service_id, pool=False):
"""Restart a service on an endpoint."""
path = f"/endpoints/{self.endpoint_id}/forceupdateservice"
params={"serviceID": service_id, "pullImage": pool}
try:
resp = self._api_put(path, json=params, timeout=20)
print(resp)
except ValueError as e:
print(f"Error restarting service: {e}")
return []
def restart_service(self, endpoint_id, service_id): def restart_service(self, endpoint_id, service_id):
stacks = [(s["Id"], s["Name"]) for s in self.get_stacks(endpoint_id)] stacks = [(s["Id"], s["Name"]) for s in self.get_stacks(endpoint_id)]
stack_id = radiolist_dialog( stack_id = radiolist_dialog(
@@ -782,17 +849,8 @@ class Portainer:
text="Choose a service:", text="Choose a service:",
values=svc_menu values=svc_menu
).run() ).run()
"""Restart a service on an endpoint.""" self.restart_srv(service_id, False)
path = f"/endpoints/{self.endpoint_id}/forceupdateservice"
params={"serviceID": service_id, "pullImage": False}
try:
resp = self._api_put(path, json=params, timeout=20)
print(resp)
except ValueError as e:
print(f"Error restarting service: {e}")
return []
print(f"Service {service_id} : restarted") print(f"Service {service_id} : restarted")
return True return True

View File

@@ -109,6 +109,13 @@ parser.add_argument(
default=None, default=None,
help="Endpoint ID to limit stack operations", help="Endpoint ID to limit stack operations",
) )
parser.add_argument(
"--service-id",
"-i",
type=str,
default=None,
help="Service ID to limit service operations",
)
parser.add_argument( parser.add_argument(
"--refresh-environment", "-R", action="store_true", help="List endpoints" "--refresh-environment", "-R", action="store_true", help="List endpoints"
) )
@@ -393,6 +400,7 @@ if __name__ == "__main__":
("stop_stack","stop_stack"), ("stop_stack","stop_stack"),
("start_stack","start_stack"), ("start_stack","start_stack"),
("restart_service","restart_service"), ("restart_service","restart_service"),
("update_service","update_service"),
("list_stacks","list_stacks"), ("list_stacks","list_stacks"),
("update_stack","update_stack"), ("update_stack","update_stack"),
("secrets","secrets"), ("secrets","secrets"),
@@ -538,7 +546,18 @@ if __name__ == "__main__":
) )
por.restart_service(args.endpoint_id, "lala") por.restart_service(args.endpoint_id, "lala")
sys.exit() sys.exit()
if args.action == "update_service":
args = prompt_missing_args(
args,
cur_config,
[
("site", "Site"),
("endpoint_id", "Endpoint ID")
],
)
por.update_service(args.endpoint_id, args.service_id)
sys.exit()
if args.action == "list_stacks": if args.action == "list_stacks":
args = prompt_missing_args( args = prompt_missing_args(
args, args,