Merge branch 'master' of git.dorfsvald.net:ewandor/portainer_updater

This commit is contained in:
2024-04-25 11:00:52 +02:00
3 changed files with 67 additions and 33 deletions

86
main.py Normal file → Executable file
View File

@@ -1,3 +1,5 @@
#!/usr/bin/env python3
import os
import json
from time import sleep
@@ -6,10 +8,10 @@ import requests
import config
DOCKER_COMPOSE_PATH = config.portainer_compose_dir + '/{}/docker-compose.yml'
BASH_COMPANION_SCRIPT = os.getcwd() + '/docker_updater.sh'
REPO_UPDATER_SCRIPT = os.getcwd() + '/update_repos.sh'
SCRIPT_DIR = os.path.dirname(__file__)
BASH_COMPANION_SCRIPT = f'{SCRIPT_DIR}/docker_updater.sh'
REPO_UPDATER_SCRIPT = f'{SCRIPT_DIR}/update_repos.sh'
class PortainerClient:
@@ -30,8 +32,12 @@ class PortainerClient:
response = requests.get(f"{self.api_url}/{uri}", headers=self._get_headers())
return response.json()
def list_stacks(self):
return self._get('stacks')
def list_endpoints(self):
return self._get("endpoints")
def list_stacks(self, endpoint_id=None):
filters = f'?filters={{"EndpointID":{endpoint_id}}}' if endpoint_id else ""
return self._get(f'stacks{filters}')
def get_stack(self, stack_id):
return self._get(f'stacks/{stack_id}')
@@ -76,6 +82,12 @@ class PortainerClient:
return f"Downloaded newer image for {image}" in status
def delete_image(self, endpoint, image):
response = requests.delete(
f"{self.api_url}/endpoints/{endpoint}/docker/images/{image}?force=false",
headers=self._get_headers()
)
def ping_server(self):
try:
r = requests.get(f"{self.api_url}/", headers=self._get_headers())
@@ -92,7 +104,19 @@ def update_repositories():
exit(ret)
def update_local_stack(stack):
def update_stack_images(endpoint, stack_name):
containers = client.list_stack_containers(endpoint, stack_name)
updated_images = []
for c in containers:
if client.update_image(endpoint, c['Image']):
print(f"{c['Image']} was updated.")
updated_images.append(c['ImageID'])
return updated_images
def upgrade_local_stack(stack):
project_name = stack['Name']
print(f"Updating stack: {project_name}")
@@ -105,32 +129,42 @@ def update_local_stack(stack):
print(f"Stack {project_name} updated!\n")
if __name__ == '__main__':
update_repositories()
client = PortainerClient(portainer_url=config.portainer_url, access_token=config.access_token)
for stack in client.list_stacks():
endpoint = stack['EndpointId']
stack_name = stack['Name']
def upgrade_endpoint_stack(client, endpoint):
endpoint_id = endpoint['Id']
endpoint_updated_images = []
for stack in client.list_stacks(endpoint_id):
if stack['Status'] == 1:
containers = client.list_stack_containers(endpoint, stack_name)
stack_name = stack['Name']
an_image_was_updated = False
for c in containers:
this_image_was_updated = client.update_image(endpoint, c['Image'])
if this_image_was_updated:
print(f"{c['Image']} was updated")
an_image_was_updated = True
print(f"Checking {stack_name} for updates.")
if an_image_was_updated:
print(f"Restarting {stack_name}")
if endpoint == 2 and stack_name in ('portainer', 'traefik'):
update_local_stack(stack)
updated_images = update_stack_images(endpoint_id, stack_name)
if updated_images:
endpoint_updated_images += updated_images
print(f"{stack_name} was updated. Restarting...")
if endpoint_id == 2 and stack_name in ('portainer', 'traefik'):
upgrade_local_stack(stack)
while not client.ping_server():
print("Waiting for server to be back online...")
sleep(1)
else:
client.upgrade_stack(stack)
print(f"{stack_name} restarted.")
else:
print(f"{stack_name} is up to date. Skipping.")
os.system('docker image prune -fa')
if endpoint_updated_images:
print("Deleting obsolete images")
for image_id in endpoint_updated_images:
client.delete_image(endpoint_id, image_id)
else:
print("No obsolete image to delete")
if __name__ == '__main__':
update_repositories()
client = PortainerClient(portainer_url=config.portainer_url, access_token=config.access_token)
for e in client.list_endpoints():
upgrade_endpoint_stack(client, e)