outposts: implement docker controller
This commit is contained in:
parent
d3a96ac7aa
commit
d506e8f1a3
|
@ -1,36 +0,0 @@
|
|||
"""Docker Compose controller"""
|
||||
from yaml import safe_dump
|
||||
|
||||
from passbook import __version__
|
||||
from passbook.outposts.controllers.base import BaseController
|
||||
|
||||
|
||||
class DockerComposeController(BaseController):
|
||||
"""Docker Compose controller"""
|
||||
|
||||
image_base = "beryju/passbook"
|
||||
|
||||
def run(self):
|
||||
self.logger.warning("DockerComposeController does not implement run")
|
||||
raise NotImplementedError
|
||||
|
||||
def get_static_deployment(self) -> str:
|
||||
"""Generate docker-compose yaml for proxy, version 3.5"""
|
||||
ports = [f"{x}:{x}" for _, x in self.deployment_ports.items()]
|
||||
compose = {
|
||||
"version": "3.5",
|
||||
"services": {
|
||||
f"passbook_{self.outpost.type}": {
|
||||
"image": f"{self.image_base}-{self.outpost.type}:{__version__}",
|
||||
"ports": ports,
|
||||
"environment": {
|
||||
"PASSBOOK_HOST": self.outpost.config.passbook_host,
|
||||
"PASSBOOK_INSECURE": str(
|
||||
self.outpost.config.passbook_host_insecure
|
||||
),
|
||||
"PASSBOOK_TOKEN": self.outpost.token.token_uuid.hex,
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
return safe_dump(compose, default_flow_style=False)
|
|
@ -0,0 +1,76 @@
|
|||
"""Docker controller"""
|
||||
from docker import DockerClient, from_env
|
||||
from docker.errors import NotFound
|
||||
from docker.models.containers import Container
|
||||
from yaml import safe_dump
|
||||
|
||||
from passbook import __version__
|
||||
from passbook.outposts.controllers.base import BaseController
|
||||
|
||||
|
||||
class DockerController(BaseController):
|
||||
"""Docker controller"""
|
||||
|
||||
client: DockerClient
|
||||
|
||||
container: Container
|
||||
|
||||
image_base = "beryju/passbook"
|
||||
|
||||
def __init__(self, outpost_pk: str) -> None:
|
||||
super().__init__(outpost_pk)
|
||||
self.client = from_env()
|
||||
|
||||
def _get_container(self) -> Container:
|
||||
container_name = f"passbook-proxy-{self.outpost.uuid.hex}"
|
||||
try:
|
||||
return self.client.containers.get(container_name)
|
||||
except NotFound:
|
||||
return self.client.containers.create(
|
||||
image=f"{self.image_base}-{self.outpost.type}:{__version__}",
|
||||
name=f"passbook-proxy-{self.outpost.uuid.hex}",
|
||||
detach=True,
|
||||
ports={x: x for _, x in self.deployment_ports.items()},
|
||||
environment={
|
||||
"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 run(self):
|
||||
container = self._get_container()
|
||||
# Check if the container is out of date, delete it and retry
|
||||
if len(container.image.tags) > 0:
|
||||
tag: str = container.iamge.tags[0]
|
||||
_, _, version = tag.partition(":")
|
||||
if version != __version__:
|
||||
container.kill()
|
||||
container.remove(force=True)
|
||||
return self.run()
|
||||
if container.status != "running":
|
||||
container.start()
|
||||
return None
|
||||
|
||||
def get_static_deployment(self) -> str:
|
||||
"""Generate docker-compose yaml for proxy, version 3.5"""
|
||||
ports = [f"{x}:{x}" for _, x in self.deployment_ports.items()]
|
||||
compose = {
|
||||
"version": "3.5",
|
||||
"services": {
|
||||
f"passbook_{self.outpost.type}": {
|
||||
"image": f"{self.image_base}-{self.outpost.type}:{__version__}",
|
||||
"ports": ports,
|
||||
"environment": {
|
||||
"PASSBOOK_HOST": self.outpost.config.passbook_host,
|
||||
"PASSBOOK_INSECURE": str(
|
||||
self.outpost.config.passbook_host_insecure
|
||||
),
|
||||
"PASSBOOK_TOKEN": self.outpost.token.token_uuid.hex,
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
return safe_dump(compose, default_flow_style=False)
|
|
@ -0,0 +1,26 @@
|
|||
# Generated by Django 3.1.2 on 2020-10-03 22:39
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("passbook_outposts", "0005_auto_20200909_1733"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="outpost",
|
||||
name="deployment_type",
|
||||
field=models.TextField(
|
||||
choices=[
|
||||
("kubernetes", "Kubernetes"),
|
||||
("docker", "Docker"),
|
||||
("custom", "Custom"),
|
||||
],
|
||||
default="custom",
|
||||
help_text="Select between passbook-managed deployment types or a custom deployment.",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -59,7 +59,8 @@ class OutpostType(models.TextChoices):
|
|||
class OutpostDeploymentType(models.TextChoices):
|
||||
"""Deployment types that are managed through passbook"""
|
||||
|
||||
# KUBERNETES = "kubernetes"
|
||||
KUBERNETES = "kubernetes"
|
||||
DOCKER = "docker"
|
||||
CUSTOM = "custom"
|
||||
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ from passbook.outposts.models import (
|
|||
OutpostModel,
|
||||
OutpostType,
|
||||
)
|
||||
from passbook.providers.proxy.controllers.docker import ProxyDockerController
|
||||
from passbook.providers.proxy.controllers.kubernetes import ProxyKubernetesController
|
||||
from passbook.root.celery import CELERY_APP
|
||||
|
||||
|
@ -20,20 +21,27 @@ LOGGER = get_logger()
|
|||
|
||||
@CELERY_APP.task(bind=True)
|
||||
# pylint: disable=unused-argument
|
||||
def outpost_k8s_controller(self):
|
||||
"""Launch Kubernetes Controller for all Outposts which are deployed in kubernetes"""
|
||||
for outpost in Outpost.objects.filter(
|
||||
deployment_type=OutpostDeploymentType.KUBERNETES
|
||||
def outpost_controller(self):
|
||||
"""Launch Controller for all Outposts which support it"""
|
||||
for outpost in Outpost.objects.exclude(
|
||||
deployment_type=OutpostDeploymentType.CUSTOM
|
||||
):
|
||||
outpost_k8s_controller_single.delay(outpost.pk.hex, outpost.type)
|
||||
outpost_controller_single.delay(
|
||||
outpost.pk.hex, outpost.deployment_type, outpost.type
|
||||
)
|
||||
|
||||
|
||||
@CELERY_APP.task(bind=True)
|
||||
# pylint: disable=unused-argument
|
||||
def outpost_k8s_controller_single(self, outpost: str, outpost_type: str):
|
||||
"""Launch Kubernetes manager and reconcile deployment/service/etc"""
|
||||
def outpost_controller_single(
|
||||
self, outpost: str, deployment_type: str, outpost_type: str
|
||||
):
|
||||
"""Launch controller and reconcile deployment/service/etc"""
|
||||
if outpost_type == OutpostType.PROXY:
|
||||
if deployment_type == OutpostDeploymentType.KUBERNETES:
|
||||
ProxyKubernetesController(outpost).run()
|
||||
if deployment_type == OutpostDeploymentType.DOCKER:
|
||||
ProxyDockerController(outpost).run()
|
||||
|
||||
|
||||
@CELERY_APP.task()
|
||||
|
|
|
@ -11,7 +11,7 @@ from guardian.shortcuts import get_objects_for_user
|
|||
from structlog import get_logger
|
||||
|
||||
from passbook.core.models import User
|
||||
from passbook.outposts.controllers.compose import DockerComposeController
|
||||
from passbook.outposts.controllers.docker import DockerController
|
||||
from passbook.outposts.models import Outpost, OutpostType
|
||||
from passbook.providers.proxy.controllers.kubernetes import ProxyKubernetesController
|
||||
|
||||
|
@ -35,7 +35,7 @@ class DockerComposeView(LoginRequiredMixin, View):
|
|||
)
|
||||
manifest = ""
|
||||
if outpost.type == OutpostType.PROXY:
|
||||
controller = DockerComposeController(outpost_pk)
|
||||
controller = DockerController(outpost_pk)
|
||||
manifest = controller.get_static_deployment()
|
||||
|
||||
return HttpResponse(manifest, content_type="text/vnd.yaml")
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
"""Proxy Provider Docker Contoller"""
|
||||
from passbook.outposts.controllers.docker import DockerController
|
||||
|
||||
|
||||
class ProxyDockerController(DockerController):
|
||||
"""Proxy Provider Docker Contoller"""
|
||||
|
||||
def __init__(self, outpost_pk: str):
|
||||
super().__init__(outpost_pk)
|
||||
self.deployment_ports = {
|
||||
"http": 4180,
|
||||
"https": 4443,
|
||||
}
|
Reference in New Issue