|
|
|
@@ -1,12 +1,12 @@
|
|
|
|
"""Provides setup and the core Composer class functionality to interact with a compose stack"""
|
|
|
|
"""Provides setup and the core Composer class functionality to interact with a compose stack"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from apscheduler.schedulers.background import BackgroundScheduler
|
|
|
|
from git import exc, Repo
|
|
|
|
from git import exc, Repo
|
|
|
|
import logging
|
|
|
|
import logging
|
|
|
|
from os import environ, getenv
|
|
|
|
from os import environ, getenv
|
|
|
|
from pathlib import Path
|
|
|
|
from pathlib import Path
|
|
|
|
from python_on_whales import DockerClient
|
|
|
|
from python_on_whales import DockerClient
|
|
|
|
from python_on_whales.exceptions import DockerException
|
|
|
|
from python_on_whales.exceptions import DockerException
|
|
|
|
import schedule
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
|
|
handler = logging.StreamHandler(sys.stdout)
|
|
|
|
handler = logging.StreamHandler(sys.stdout)
|
|
|
|
@@ -82,6 +82,7 @@ class Composer:
|
|
|
|
Attributes:
|
|
|
|
Attributes:
|
|
|
|
docker: DockerClient instance used to interact with the compose stack
|
|
|
|
docker: DockerClient instance used to interact with the compose stack
|
|
|
|
services: list of Service objects defined by the stack
|
|
|
|
services: list of Service objects defined by the stack
|
|
|
|
|
|
|
|
scheduler: BackgroundScheduler for updates
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
services = []
|
|
|
|
services = []
|
|
|
|
@@ -110,7 +111,9 @@ class Composer:
|
|
|
|
raise Exception("Failed to authenticate remote!")
|
|
|
|
raise Exception("Failed to authenticate remote!")
|
|
|
|
if self.docker.compose.config(return_json=True)["name"] != "stack":
|
|
|
|
if self.docker.compose.config(return_json=True)["name"] != "stack":
|
|
|
|
logger.warn(f"Composer stack name is wrong, either make sure it is set manually or keep it store/stack")
|
|
|
|
logger.warn(f"Composer stack name is wrong, either make sure it is set manually or keep it store/stack")
|
|
|
|
self.start_update_job()
|
|
|
|
self.scheduler = BackgroundScheduler()
|
|
|
|
|
|
|
|
self.scheduler.start()
|
|
|
|
|
|
|
|
self._update_job = self.start_update_job()
|
|
|
|
self._create_services()
|
|
|
|
self._create_services()
|
|
|
|
self.set_status("up")
|
|
|
|
self.set_status("up")
|
|
|
|
logger.info("Composer started and services created")
|
|
|
|
logger.info("Composer started and services created")
|
|
|
|
@@ -142,6 +145,9 @@ class Composer:
|
|
|
|
"""Schedules a recurring update based on the UPDATE environment variable
|
|
|
|
"""Schedules a recurring update based on the UPDATE environment variable
|
|
|
|
|
|
|
|
|
|
|
|
Each update occurs after an interval of UPDATE minutes. If UPDATE does not contain a valid integer in minutes, defaults to 1 minute.
|
|
|
|
Each update occurs after an interval of UPDATE minutes. If UPDATE does not contain a valid integer in minutes, defaults to 1 minute.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
apscheduler.job.Job instance of the scheduled update job
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
update_time = getenv("UPDATE", 1)
|
|
|
|
update_time = getenv("UPDATE", 1)
|
|
|
|
@@ -151,7 +157,7 @@ class Composer:
|
|
|
|
except (AssertionError, ValueError):
|
|
|
|
except (AssertionError, ValueError):
|
|
|
|
self.update_time = 1
|
|
|
|
self.update_time = 1
|
|
|
|
logging.warn(f"Composer has an invalid UPDATE value of {getenv("UPDATE")}, defaulting to update interval of {self.update_time} minutes")
|
|
|
|
logging.warn(f"Composer has an invalid UPDATE value of {getenv("UPDATE")}, defaulting to update interval of {self.update_time} minutes")
|
|
|
|
schedule.every(self.update_time).minutes.do(self.update)
|
|
|
|
return self.scheduler.add_job(self.update, 'interval', minutes=self.update_time)
|
|
|
|
|
|
|
|
|
|
|
|
def set_status(self, status):
|
|
|
|
def set_status(self, status):
|
|
|
|
|
|
|
|
|
|
|
|
@@ -190,6 +196,7 @@ class Composer:
|
|
|
|
|
|
|
|
|
|
|
|
"""Updates the Composer stack based on the remote repo"""
|
|
|
|
"""Updates the Composer stack based on the remote repo"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger.info("Check for new compose stack")
|
|
|
|
current = self.repo.head.commit
|
|
|
|
current = self.repo.head.commit
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
self.repo.remotes.origin.pull('master')
|
|
|
|
self.repo.remotes.origin.pull('master')
|
|
|
|
@@ -229,15 +236,18 @@ class Service:
|
|
|
|
|
|
|
|
|
|
|
|
"""Safely removes the service instance"""
|
|
|
|
"""Safely removes the service instance"""
|
|
|
|
|
|
|
|
|
|
|
|
if self.update_time is None:
|
|
|
|
if self._update_task is None:
|
|
|
|
return None
|
|
|
|
return None
|
|
|
|
schedule.cancel_job(self._update_task)
|
|
|
|
self._update_task.remove()
|
|
|
|
|
|
|
|
|
|
|
|
def start_update_job(self):
|
|
|
|
def start_update_job(self):
|
|
|
|
|
|
|
|
|
|
|
|
"""Schedules a recurring update based on the composer.update label
|
|
|
|
"""Schedules a recurring update based on the composer.update label
|
|
|
|
|
|
|
|
|
|
|
|
Each update occurs after an interval of composer.update minutes. If composer.update does not contain a valid integer in minutes, defaults to the parent Composer's update_time.
|
|
|
|
Each update occurs after an interval of composer.update minutes. If composer.update does not contain a valid integer in minutes, defaults to the parent Composer's update_time.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
apscheduler.job.Job instance of the scheduled job, None if the job was not scheduled
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
self.update_time = self.parent.update_time
|
|
|
|
self.update_time = self.parent.update_time
|
|
|
|
@@ -249,7 +259,7 @@ class Service:
|
|
|
|
self.update_time = self.parent.update_time
|
|
|
|
self.update_time = self.parent.update_time
|
|
|
|
logging.warn(f"Service {self.name} has an invalid composer.update value of {self.labels['composer.update']}, defaulting to update interval of {self.update_time} minutes")
|
|
|
|
logging.warn(f"Service {self.name} has an invalid composer.update value of {self.labels['composer.update']}, defaulting to update interval of {self.update_time} minutes")
|
|
|
|
if self.update_time != 0:
|
|
|
|
if self.update_time != 0:
|
|
|
|
return schedule.every(self.update_time).minutes.do(self.update)
|
|
|
|
return self.parent.scheduler.add_job(self.update, 'interval', minutes=self.update_time)
|
|
|
|
return None
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def set_status(self, status):
|
|
|
|
def set_status(self, status):
|
|
|
|
|