mirror of
https://gitlab.sectorq.eu/jaydee/portainer.git
synced 2025-12-14 02:34:53 +01:00
build
This commit is contained in:
71
port.py
71
port.py
@@ -1,3 +1,5 @@
|
||||
'''Portainer API wrapper module.'''
|
||||
|
||||
import os
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
import json
|
||||
@@ -12,7 +14,6 @@ from git import Repo
|
||||
import requests
|
||||
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -108,18 +109,23 @@ class Portainer:
|
||||
self.get_endpoints()
|
||||
self.get_stacks()
|
||||
self.get_containers()
|
||||
|
||||
|
||||
|
||||
def get_site(self, site):
|
||||
if site == "portainer":
|
||||
self.base_url = os.getenv("PORTAINER_URL", "https://portainer.sectorq.eu/api")
|
||||
self.base_url = os.getenv(
|
||||
"PORTAINER_URL", "https://portainer.sectorq.eu/api"
|
||||
)
|
||||
self.token = "ptr_GCNUoFcTOaXm7k8ZxPdQGmrFIamxZPTydbserYofMHc="
|
||||
elif site == "port":
|
||||
self.base_url = os.getenv("PORTAINER_URL", "https://port.sectorq.eu/api")
|
||||
self.token = "ptr_/5RkMCT/j3BTaL32vMSDtXFi76yOXRKVFOrUtzMsl5Y="
|
||||
else:
|
||||
self.base_url = os.getenv("PORTAINER_URL", "https://portainer.sectorq.eu/api")
|
||||
self.base_url = os.getenv(
|
||||
"PORTAINER_URL", "https://portainer.sectorq.eu/api"
|
||||
)
|
||||
self.token = "ptr_GCNUoFcTOaXm7k8ZxPdQGmrFIamxZPTydbserYofMHc="
|
||||
self.get_endpoints()
|
||||
self.get_stacks()
|
||||
|
||||
def _is_number(self, s):
|
||||
"""Check if the input string is a number."""
|
||||
@@ -176,12 +182,14 @@ class Portainer:
|
||||
return resp.status_code
|
||||
|
||||
def refresh(self):
|
||||
'''Refresh all data from Portainer.'''
|
||||
self.get_endpoints()
|
||||
self.get_stacks(self)
|
||||
self.get_containers(self)
|
||||
return True
|
||||
|
||||
def get_stacks(self, endpoint_id="all", timeout=10):
|
||||
'''Get a list of stacks for a specific endpoint or all endpoints.'''
|
||||
if endpoint_id != "all":
|
||||
endpoint_id = self.get_endpoint_id(endpoint_id)
|
||||
path = "/stacks"
|
||||
@@ -248,12 +256,14 @@ class Portainer:
|
||||
return stcks
|
||||
|
||||
def update_status(self, endpoint, stack):
|
||||
'''Get the update status of a specific stack on an endpoint.'''
|
||||
path = f"/stacks/{self.all_data['stacks'][endpoint]['by_name'][stack]}/images_status?refresh=true"
|
||||
# input(path)
|
||||
stats = self._api_get(path)
|
||||
print(stats)
|
||||
|
||||
def get_endpoint_id(self, endpoint):
|
||||
'''Get endpoint ID from either ID or name input.'''
|
||||
if self._is_number(endpoint):
|
||||
self.endpoint_id = endpoint
|
||||
self.endpoint_name = self.endpoints["by_id"][endpoint]
|
||||
@@ -264,6 +274,7 @@ class Portainer:
|
||||
return self.endpoints["by_name"][endpoint]
|
||||
|
||||
def get_endpoint_name(self, endpoint):
|
||||
'''Get endpoint name from either ID or name input.'''
|
||||
if self._is_number(endpoint):
|
||||
self.endpoint_id = endpoint
|
||||
self.endpoint_name = self.endpoints["by_id"][endpoint]
|
||||
@@ -274,6 +285,7 @@ class Portainer:
|
||||
return endpoint
|
||||
|
||||
def get_containers(self, endpoint="all", stack="all", timeout=30):
|
||||
'''Get a list of containers for a specific endpoint and stack.'''
|
||||
# print(json.dumps(self.all_data,indent=2))
|
||||
# print(endpoint)
|
||||
# print(stack)
|
||||
@@ -325,6 +337,7 @@ class Portainer:
|
||||
return cont
|
||||
|
||||
def stop_containers(self, endpoint, containers, timeout=130):
|
||||
'''Stop containers on an endpoint.'''
|
||||
if self.all_data["endpoints_status"][endpoint] != 1:
|
||||
print(f"Endpoint {self.get_endpoint_name(endpoint)} is offline")
|
||||
ep_id = self.endpoints["by_name"][endpoint]
|
||||
@@ -342,6 +355,7 @@ class Portainer:
|
||||
# return 0
|
||||
|
||||
def start_containers(self, endpoint, containers, timeout=130):
|
||||
'''Start containers on an endpoint.'''
|
||||
ep_id = self.endpoints["by_name"][endpoint]
|
||||
|
||||
def stop(c):
|
||||
@@ -352,6 +366,7 @@ class Portainer:
|
||||
exe.map(stop, containers)
|
||||
|
||||
def update_stack(self, endpoint, stack, autostart, timeout=130):
|
||||
'''Update one stack or all stacks on an endpoint.'''
|
||||
stcs = []
|
||||
if stack == "all":
|
||||
for s in self.all_data["webhooks"][endpoint]:
|
||||
@@ -386,6 +401,7 @@ class Portainer:
|
||||
self.stop_containers(endpoint, cont)
|
||||
|
||||
def get_endpoints(self, timeout=10):
|
||||
'''Get a list of all endpoints.'''
|
||||
endpoints = self._api_get("/endpoints")
|
||||
eps = {"by_id": {}, "by_name": {}}
|
||||
eps_stats = {}
|
||||
@@ -395,6 +411,7 @@ class Portainer:
|
||||
eps_stats[ep["Id"]] = ep["Status"]
|
||||
eps_stats[ep["Name"]] = ep["Status"]
|
||||
self.endpoints = eps
|
||||
self.endpoints_names = list(eps["by_name"])
|
||||
self.all_data["endpoints"] = eps
|
||||
self.all_data["endpoints_status"] = eps_stats
|
||||
# input(eps_stats)
|
||||
@@ -402,6 +419,7 @@ class Portainer:
|
||||
return eps
|
||||
|
||||
def get_endpoint(self, endpoint_id=None, timeout=30):
|
||||
'''Get endpoint ID and name from either ID or name input.'''
|
||||
self.get_endpoints()
|
||||
# print(self.endpoints)
|
||||
if self._is_number(endpoint_id):
|
||||
@@ -413,6 +431,7 @@ class Portainer:
|
||||
return self.endpoint_id
|
||||
|
||||
def get_swarm_id(self, endpoint):
|
||||
'''Get the swarm ID for a specific endpoint.'''
|
||||
ep_id = self.endpoints["by_name"][endpoint]
|
||||
path = f"/endpoints/{ep_id}/docker/info"
|
||||
stats = self._api_get(path)
|
||||
@@ -459,9 +478,9 @@ class Portainer:
|
||||
stack=None,
|
||||
mode="git",
|
||||
autostart=False,
|
||||
stack_mode='swarm',
|
||||
stack_mode="swarm",
|
||||
):
|
||||
if stack_mode == 'swarm':
|
||||
if stack_mode == "swarm":
|
||||
swarm_id = self.get_swarm_id(endpoint)
|
||||
p = "swarm"
|
||||
env_path = f"{self.repo_dir}/__swarm/{stack}/.env"
|
||||
@@ -505,7 +524,7 @@ class Portainer:
|
||||
if stack_check:
|
||||
print(f"Stack {stack} already exist")
|
||||
continue
|
||||
print(f"Working on {stack}")
|
||||
print(f"Working on {stack} , stack mode: {stack_mode}")
|
||||
|
||||
envs = []
|
||||
if os.path.exists(f"{env_path}"):
|
||||
@@ -571,13 +590,13 @@ class Portainer:
|
||||
"method": "repository",
|
||||
"swarmID": None,
|
||||
}
|
||||
if stack_mode == 'swarm':
|
||||
if stack_mode == "swarm":
|
||||
req["type"] = "swarm"
|
||||
req["swarmID"] = swarm_id
|
||||
req["composeFile"] = f"__swarm/{stack}/{stack}-swarm.yml"
|
||||
req["ConfigFilePath"] = f"__swarm/{stack}/{stack}-swarm.yml"
|
||||
|
||||
print(json.dumps(req))
|
||||
if self._debug:
|
||||
print(json.dumps(req))
|
||||
res = self._api_post(path, req)
|
||||
if "Id" in res:
|
||||
# print("Deploy request OK")
|
||||
@@ -675,7 +694,7 @@ class Portainer:
|
||||
self._api_post_file(path, self.endpoint_id, stack, envs, file)
|
||||
|
||||
def print_stacks(self, endpoint="all"):
|
||||
'''Print a table of stacks, optionally filtered by endpoint.'''
|
||||
"""Print a table of stacks, optionally filtered by endpoint."""
|
||||
stacks = self.get_stacks()
|
||||
count = 0
|
||||
data = []
|
||||
@@ -697,7 +716,7 @@ class Portainer:
|
||||
except KeyError as e:
|
||||
data.append([stack["Id"], stack["Name"], "?"])
|
||||
logger.debug(
|
||||
"KeyError getting endpoint name for stack %s : %s", stack['Name'],e
|
||||
"KeyError getting endpoint name for stack %s : %s", stack["Name"], e
|
||||
)
|
||||
count += 1
|
||||
|
||||
@@ -706,7 +725,7 @@ class Portainer:
|
||||
print(f"Total stacks: {count}")
|
||||
|
||||
def start_stack(self, stack=None, endpoint_id=None):
|
||||
'''Start one stack or all stacks on an endpoint.'''
|
||||
"""Start one stack or all stacks on an endpoint."""
|
||||
if endpoint_id is not None:
|
||||
print("Getting endpoint")
|
||||
self.get_endpoint(endpoint_id)
|
||||
@@ -732,7 +751,7 @@ class Portainer:
|
||||
return True
|
||||
|
||||
def stop_stack(self, stack, endpoint_id):
|
||||
'''Stop one stack or all stacks on an endpoint.'''
|
||||
"""Stop one stack or all stacks on an endpoint."""
|
||||
print(f"Stopping stack {stack}")
|
||||
if endpoint_id is not None:
|
||||
self.get_endpoint(endpoint_id)
|
||||
@@ -761,10 +780,9 @@ class Portainer:
|
||||
f"Stack {self.stacks_all[self.endpoint_id]['by_id'][stck]} : {json.loads(resp)['message']}"
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
|
||||
def _resolve_endpoint(self, endpoint_id):
|
||||
|
||||
|
||||
self.get_endpoints()
|
||||
if self._debug:
|
||||
print(endpoint_id)
|
||||
@@ -775,7 +793,7 @@ class Portainer:
|
||||
else:
|
||||
self.endpoint_name = endpoint_id
|
||||
self.endpoint_id = int(self.endpoints["by_name"][endpoint_id])
|
||||
|
||||
|
||||
def _resolve_stack_id(self, stack, endpoint_id):
|
||||
if stack == "all":
|
||||
return "all"
|
||||
@@ -785,6 +803,7 @@ class Portainer:
|
||||
return result["Id"]
|
||||
|
||||
return int(stack)
|
||||
|
||||
def _delete_all_stacks(self, endpoint_id):
|
||||
stacks = self.get_stacks(endpoint_id)
|
||||
paths = []
|
||||
@@ -794,11 +813,7 @@ class Portainer:
|
||||
continue
|
||||
|
||||
path = f"/stacks/{s['Id']}?endpointId={endpoint_id}&removeVolumes=true"
|
||||
paths.append([
|
||||
self.get_endpoint_name(endpoint_id),
|
||||
s["Name"],
|
||||
path
|
||||
])
|
||||
paths.append([self.get_endpoint_name(endpoint_id), s["Name"], path])
|
||||
|
||||
def delete_item(item):
|
||||
print(f"Delete stack {item[1]} from {item[0]}")
|
||||
@@ -809,7 +824,7 @@ class Portainer:
|
||||
exe.map(delete_item, paths)
|
||||
|
||||
return "Done"
|
||||
|
||||
|
||||
def _delete_single_stack(self, stack_id, endpoint_id):
|
||||
path = f"/stacks/{stack_id}?endpointId={endpoint_id}&removeVolumes=true"
|
||||
|
||||
@@ -836,9 +851,7 @@ class Portainer:
|
||||
return self._delete_all_stacks(endpoint_id)
|
||||
|
||||
return self._delete_single_stack(stack_id, endpoint_id)
|
||||
|
||||
|
||||
|
||||
|
||||
# def delete_stack(self, endpoint_id=None, stack=None):
|
||||
# """
|
||||
# Return a list of stacks. If endpoint_id is provided, it will be added as a query param.
|
||||
@@ -906,7 +919,7 @@ class Portainer:
|
||||
# return stacks
|
||||
|
||||
def create_secret(self, name, value, endpoint_id=None, timeout=None):
|
||||
'''Create a Docker secret on the specified endpoint.'''
|
||||
"""Create a Docker secret on the specified endpoint."""
|
||||
endpoint_id = int(self.endpoints["by_name"][endpoint_id])
|
||||
path = f"/endpoints/{endpoint_id}/docker/secrets/create"
|
||||
encoded = base64.b64encode(value.encode()).decode()
|
||||
|
||||
Reference in New Issue
Block a user