Merge branch 'master' of git.dorfsvald.net:ewandor/portainer_updater
This commit is contained in:
@@ -5,6 +5,6 @@ set -e
|
|||||||
PROJECT_NAME=$1
|
PROJECT_NAME=$1
|
||||||
COMPOSE_FILE=$2
|
COMPOSE_FILE=$2
|
||||||
|
|
||||||
docker compose -p $PROJECT_NAME -f $COMPOSE_FILE stop
|
docker compose -p "$PROJECT_NAME" -f "$COMPOSE_FILE" pull
|
||||||
docker compose -p $PROJECT_NAME -f $COMPOSE_FILE pull
|
docker compose -p "$PROJECT_NAME" -f "$COMPOSE_FILE" down
|
||||||
docker compose -p $PROJECT_NAME -f $COMPOSE_FILE up -d
|
docker compose -p "$PROJECT_NAME" -f "$COMPOSE_FILE" up -d
|
||||||
|
|||||||
86
main.py
Normal file → Executable file
86
main.py
Normal file → Executable file
@@ -1,3 +1,5 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
from time import sleep
|
from time import sleep
|
||||||
@@ -6,10 +8,10 @@ import requests
|
|||||||
|
|
||||||
import config
|
import config
|
||||||
|
|
||||||
|
|
||||||
DOCKER_COMPOSE_PATH = config.portainer_compose_dir + '/{}/docker-compose.yml'
|
DOCKER_COMPOSE_PATH = config.portainer_compose_dir + '/{}/docker-compose.yml'
|
||||||
BASH_COMPANION_SCRIPT = os.getcwd() + '/docker_updater.sh'
|
SCRIPT_DIR = os.path.dirname(__file__)
|
||||||
REPO_UPDATER_SCRIPT = os.getcwd() + '/update_repos.sh'
|
BASH_COMPANION_SCRIPT = f'{SCRIPT_DIR}/docker_updater.sh'
|
||||||
|
REPO_UPDATER_SCRIPT = f'{SCRIPT_DIR}/update_repos.sh'
|
||||||
|
|
||||||
|
|
||||||
class PortainerClient:
|
class PortainerClient:
|
||||||
@@ -30,8 +32,12 @@ class PortainerClient:
|
|||||||
response = requests.get(f"{self.api_url}/{uri}", headers=self._get_headers())
|
response = requests.get(f"{self.api_url}/{uri}", headers=self._get_headers())
|
||||||
return response.json()
|
return response.json()
|
||||||
|
|
||||||
def list_stacks(self):
|
def list_endpoints(self):
|
||||||
return self._get('stacks')
|
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):
|
def get_stack(self, stack_id):
|
||||||
return self._get(f'stacks/{stack_id}')
|
return self._get(f'stacks/{stack_id}')
|
||||||
@@ -76,6 +82,12 @@ class PortainerClient:
|
|||||||
|
|
||||||
return f"Downloaded newer image for {image}" in status
|
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):
|
def ping_server(self):
|
||||||
try:
|
try:
|
||||||
r = requests.get(f"{self.api_url}/", headers=self._get_headers())
|
r = requests.get(f"{self.api_url}/", headers=self._get_headers())
|
||||||
@@ -92,7 +104,19 @@ def update_repositories():
|
|||||||
exit(ret)
|
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']
|
project_name = stack['Name']
|
||||||
|
|
||||||
print(f"Updating stack: {project_name}")
|
print(f"Updating stack: {project_name}")
|
||||||
@@ -105,32 +129,42 @@ def update_local_stack(stack):
|
|||||||
print(f"Stack {project_name} updated!\n")
|
print(f"Stack {project_name} updated!\n")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def upgrade_endpoint_stack(client, endpoint):
|
||||||
update_repositories()
|
endpoint_id = endpoint['Id']
|
||||||
|
endpoint_updated_images = []
|
||||||
client = PortainerClient(portainer_url=config.portainer_url, access_token=config.access_token)
|
for stack in client.list_stacks(endpoint_id):
|
||||||
|
|
||||||
for stack in client.list_stacks():
|
|
||||||
endpoint = stack['EndpointId']
|
|
||||||
stack_name = stack['Name']
|
|
||||||
if stack['Status'] == 1:
|
if stack['Status'] == 1:
|
||||||
containers = client.list_stack_containers(endpoint, stack_name)
|
stack_name = stack['Name']
|
||||||
|
|
||||||
an_image_was_updated = False
|
print(f"Checking {stack_name} for updates.")
|
||||||
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
|
|
||||||
|
|
||||||
if an_image_was_updated:
|
updated_images = update_stack_images(endpoint_id, stack_name)
|
||||||
print(f"Restarting {stack_name}")
|
if updated_images:
|
||||||
if endpoint == 2 and stack_name in ('portainer', 'traefik'):
|
endpoint_updated_images += updated_images
|
||||||
update_local_stack(stack)
|
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():
|
while not client.ping_server():
|
||||||
print("Waiting for server to be back online...")
|
print("Waiting for server to be back online...")
|
||||||
sleep(1)
|
sleep(1)
|
||||||
else:
|
else:
|
||||||
client.upgrade_stack(stack)
|
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)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
REPO_PATH=$1
|
REPO_PATH=$1
|
||||||
|
|
||||||
git -C $REPO_PATH fetch --tags
|
git -C "$REPO_PATH" fetch --tags
|
||||||
LAST_HASH=`git -C $REPO_PATH rev-list --tags --max-count=1`
|
LAST_HASH=$(git -C "$REPO_PATH" rev-list --tags --max-count=1)
|
||||||
LAST_TAG=`git -C $REPO_PATH describe --tags $LAST_HASH`
|
LAST_TAG=$(git -C "$REPO_PATH" describe --tags "$LAST_HASH")
|
||||||
git -C $REPO_PATH checkout $LAST_TAG
|
git -C "$REPO_PATH" checkout "$LAST_TAG"
|
||||||
|
|||||||
Reference in New Issue
Block a user