outpost: enable docker controller
This commit is contained in:
parent
9954eeac86
commit
3b61191614
|
@ -52,6 +52,7 @@ services:
|
||||||
PASSBOOK_POSTGRESQL__PASSWORD: ${PG_PASS}
|
PASSBOOK_POSTGRESQL__PASSWORD: ${PG_PASS}
|
||||||
volumes:
|
volumes:
|
||||||
- ./backups:/backups
|
- ./backups:/backups
|
||||||
|
- /var/run/docker.socket:/var/run/docker.socket
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
static:
|
static:
|
||||||
|
|
|
@ -313,9 +313,7 @@ class Token(ExpiringModel):
|
||||||
description = models.TextField(default="", blank=True)
|
description = models.TextField(default="", blank=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return (
|
return f"Token {self.identifier} (expires={self.expires})"
|
||||||
f"Token {self.identifier} (expires={self.expires})"
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
"""Docker controller"""
|
"""Docker controller"""
|
||||||
|
from typing import Dict, Tuple
|
||||||
|
|
||||||
from docker import DockerClient, from_env
|
from docker import DockerClient, from_env
|
||||||
from docker.errors import NotFound
|
from docker.errors import NotFound
|
||||||
from docker.models.containers import Container
|
from docker.models.containers import Container
|
||||||
|
@ -21,36 +23,80 @@ class DockerController(BaseController):
|
||||||
super().__init__(outpost_pk)
|
super().__init__(outpost_pk)
|
||||||
self.client = from_env()
|
self.client = from_env()
|
||||||
|
|
||||||
def _get_container(self) -> Container:
|
def _get_env(self) -> Dict[str, str]:
|
||||||
|
return {
|
||||||
|
"PASSBOOK_HOST": self.outpost.config.passbook_host,
|
||||||
|
"PASSBOOK_INSECURE": str(self.outpost.config.passbook_host_insecure),
|
||||||
|
"PASSBOOK_TOKEN": self.outpost.token.token_uuid.hex,
|
||||||
|
}
|
||||||
|
|
||||||
|
def _comp_env(self, container: Container) -> bool:
|
||||||
|
"""Check if container's env is equal to what we would set. Return true if container needs
|
||||||
|
to be rebuilt."""
|
||||||
|
should_be = self._get_env()
|
||||||
|
container_env = container.attrs.get("Config", {}).get("Env", {})
|
||||||
|
for key, expected_value in should_be.items():
|
||||||
|
if key not in container_env:
|
||||||
|
continue
|
||||||
|
if container_env[key] != expected_value:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _get_container(self) -> Tuple[Container, bool]:
|
||||||
container_name = f"passbook-proxy-{self.outpost.uuid.hex}"
|
container_name = f"passbook-proxy-{self.outpost.uuid.hex}"
|
||||||
try:
|
try:
|
||||||
return self.client.containers.get(container_name)
|
return self.client.containers.get(container_name), False
|
||||||
except NotFound:
|
except NotFound:
|
||||||
return self.client.containers.create(
|
self.logger.info("Container does not exist, creating")
|
||||||
image=f"{self.image_base}-{self.outpost.type}:{__version__}",
|
image_name = f"{self.image_base}-{self.outpost.type}:{__version__}"
|
||||||
name=f"passbook-proxy-{self.outpost.uuid.hex}",
|
self.client.images.pull(image_name)
|
||||||
detach=True,
|
return (
|
||||||
ports={x: x for _, x in self.deployment_ports.items()},
|
self.client.containers.create(
|
||||||
environment={
|
image=image_name,
|
||||||
"PASSBOOK_HOST": self.outpost.config.passbook_host,
|
name=f"passbook-proxy-{self.outpost.uuid.hex}",
|
||||||
"PASSBOOK_INSECURE": str(
|
detach=True,
|
||||||
self.outpost.config.passbook_host_insecure
|
ports={x: x for _, x in self.deployment_ports.items()},
|
||||||
),
|
environment=self._get_env(),
|
||||||
"PASSBOOK_TOKEN": self.outpost.token.token_uuid.hex,
|
),
|
||||||
},
|
True,
|
||||||
)
|
)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
container = self._get_container()
|
container, has_been_created = self._get_container()
|
||||||
|
if has_been_created:
|
||||||
|
return None
|
||||||
# Check if the container is out of date, delete it and retry
|
# Check if the container is out of date, delete it and retry
|
||||||
if len(container.image.tags) > 0:
|
if len(container.image.tags) > 0:
|
||||||
tag: str = container.iamge.tags[0]
|
tag: str = container.image.tags[0]
|
||||||
_, _, version = tag.partition(":")
|
_, _, version = tag.partition(":")
|
||||||
if version != __version__:
|
if version != __version__:
|
||||||
|
self.logger.info(
|
||||||
|
"Container has mismatched version, re-creating...",
|
||||||
|
has=version,
|
||||||
|
should=__version__,
|
||||||
|
)
|
||||||
container.kill()
|
container.kill()
|
||||||
container.remove(force=True)
|
container.remove(force=True)
|
||||||
return self.run()
|
return self.run()
|
||||||
|
# Check that container values match our values
|
||||||
|
if self._comp_env(container):
|
||||||
|
self.logger.info("Container has outdated config, re-creating...")
|
||||||
|
container.kill()
|
||||||
|
container.remove(force=True)
|
||||||
|
return self.run()
|
||||||
|
# Check that container is healthy
|
||||||
|
if (
|
||||||
|
container.status == "running"
|
||||||
|
and container.attrs.get("State", {}).get("Health", {}).get("Status", "")
|
||||||
|
!= "healthy"
|
||||||
|
):
|
||||||
|
# At this point we know the config is correct, but the container isn't healthy,
|
||||||
|
# so we just restart it with the same config
|
||||||
|
self.logger.info("Container is unhealthy, restarting...")
|
||||||
|
container.restart()
|
||||||
|
# Check that container is running
|
||||||
if container.status != "running":
|
if container.status != "running":
|
||||||
|
self.logger.info("Container is not running, restarting...")
|
||||||
container.start()
|
container.start()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
"""Outposts Settings"""
|
"""Outposts Settings"""
|
||||||
# from celery.schedules import crontab
|
from celery.schedules import crontab
|
||||||
|
|
||||||
# CELERY_BEAT_SCHEDULE = {
|
CELERY_BEAT_SCHEDULE = {
|
||||||
# "outposts_k8s": {
|
"outposts_k8s": {
|
||||||
# "task": "passbook.outposts.tasks.outpost_k8s_controller",
|
"task": "passbook.outposts.tasks.outpost_controller",
|
||||||
# "schedule": crontab(minute="*/5"), # Run every 5 minutes
|
"schedule": crontab(minute="*/5"), # Run every 5 minutes
|
||||||
# "options": {"queue": "passbook_scheduled"},
|
"options": {"queue": "passbook_scheduled"},
|
||||||
# }
|
}
|
||||||
# }
|
}
|
||||||
|
|
Reference in a new issue