admin: add views for outpost service-connections
This commit is contained in:
		@ -49,7 +49,7 @@ class KubernetesServiceConnectionSerializer(ModelSerializer):
 | 
			
		||||
    class Meta:
 | 
			
		||||
 | 
			
		||||
        model = KubernetesServiceConnection
 | 
			
		||||
        fields = ["pk", "name", "local", "config"]
 | 
			
		||||
        fields = ["pk", "name", "local", "kubeconfig"]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class KubernetesServiceConnectionViewSet(ModelViewSet):
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ from pathlib import Path
 | 
			
		||||
from socket import gethostname
 | 
			
		||||
from urllib.parse import urlparse
 | 
			
		||||
 | 
			
		||||
import yaml
 | 
			
		||||
from django.apps import AppConfig
 | 
			
		||||
from django.db import ProgrammingError
 | 
			
		||||
from docker.constants import DEFAULT_UNIX_SOCKET
 | 
			
		||||
@ -43,19 +44,21 @@ class PassbookOutpostConfig(AppConfig):
 | 
			
		||||
            if not KubernetesServiceConnection.objects.filter(local=True).exists():
 | 
			
		||||
                LOGGER.debug("Created Service Connection for in-cluster")
 | 
			
		||||
                KubernetesServiceConnection.objects.create(
 | 
			
		||||
                    name="Local Kubernetes Cluster", local=True, config={}
 | 
			
		||||
                    name="Local Kubernetes Cluster", local=True, kubeconfig={}
 | 
			
		||||
                )
 | 
			
		||||
        # For development, check for the existence of a kubeconfig file
 | 
			
		||||
        kubeconfig_path = expanduser(KUBE_CONFIG_DEFAULT_LOCATION)
 | 
			
		||||
        if Path(kubeconfig_path).exists():
 | 
			
		||||
            LOGGER.debug("Detected kubeconfig")
 | 
			
		||||
            kubeconfig_local_name = f"k8s-{gethostname()}"
 | 
			
		||||
            if not KubernetesServiceConnection.objects.filter(
 | 
			
		||||
                name=gethostname()
 | 
			
		||||
                name=kubeconfig_local_name
 | 
			
		||||
            ).exists():
 | 
			
		||||
                LOGGER.debug("Creating kubeconfig Service Connection")
 | 
			
		||||
                with open(kubeconfig_path, "r") as _kubeconfig:
 | 
			
		||||
                    KubernetesServiceConnection.objects.create(
 | 
			
		||||
                        name=gethostname(), config=_kubeconfig.read()
 | 
			
		||||
                        name=kubeconfig_local_name,
 | 
			
		||||
                        kubeconfig=yaml.safe_load(_kubeconfig),
 | 
			
		||||
                    )
 | 
			
		||||
        unix_socket_path = urlparse(DEFAULT_UNIX_SOCKET).path
 | 
			
		||||
        socket = Path(unix_socket_path)
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ class KubernetesController(BaseController):
 | 
			
		||||
            if self.connection.local:
 | 
			
		||||
                load_incluster_config()
 | 
			
		||||
            else:
 | 
			
		||||
                load_kube_config_from_dict(self.connection.config)
 | 
			
		||||
                load_kube_config_from_dict(self.connection.kubeconfig)
 | 
			
		||||
        except ConfigException:
 | 
			
		||||
            load_kube_config()
 | 
			
		||||
        self.reconcilers = {
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,11 @@ from django import forms
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from passbook.admin.fields import CodeMirrorWidget, YAMLField
 | 
			
		||||
from passbook.outposts.models import Outpost
 | 
			
		||||
from passbook.outposts.models import (
 | 
			
		||||
    DockerServiceConnection,
 | 
			
		||||
    KubernetesServiceConnection,
 | 
			
		||||
    Outpost,
 | 
			
		||||
)
 | 
			
		||||
from passbook.providers.proxy.models import ProxyProvider
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -33,3 +37,35 @@ class OutpostForm(forms.ModelForm):
 | 
			
		||||
            "_config": YAMLField,
 | 
			
		||||
        }
 | 
			
		||||
        labels = {"_config": _("Configuration")}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DockerServiceConnectionForm(forms.ModelForm):
 | 
			
		||||
    """Docker service-connection form"""
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
 | 
			
		||||
        model = DockerServiceConnection
 | 
			
		||||
        fields = ["name", "local", "url", "tls"]
 | 
			
		||||
        widgets = {
 | 
			
		||||
            "name": forms.TextInput,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class KubernetesServiceConnectionForm(forms.ModelForm):
 | 
			
		||||
    """Kubernetes service-connection form"""
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
 | 
			
		||||
        model = KubernetesServiceConnection
 | 
			
		||||
        fields = [
 | 
			
		||||
            "name",
 | 
			
		||||
            "local",
 | 
			
		||||
            "kubeconfig",
 | 
			
		||||
        ]
 | 
			
		||||
        widgets = {
 | 
			
		||||
            "name": forms.TextInput,
 | 
			
		||||
            "kubeconfig": CodeMirrorWidget,
 | 
			
		||||
        }
 | 
			
		||||
        field_classes = {
 | 
			
		||||
            "kubeconfig": YAMLField,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,8 @@ from django.apps.registry import Apps
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
 | 
			
		||||
 | 
			
		||||
import passbook.lib.models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def migrate_to_service_connection(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
 | 
			
		||||
    db_alias = schema_editor.connection.alias
 | 
			
		||||
@ -98,7 +100,7 @@ class Migration(migrations.Migration):
 | 
			
		||||
                        to="passbook_outposts.outpostserviceconnection",
 | 
			
		||||
                    ),
 | 
			
		||||
                ),
 | 
			
		||||
                ("config", models.JSONField()),
 | 
			
		||||
                ("kubeconfig", models.JSONField()),
 | 
			
		||||
            ],
 | 
			
		||||
            bases=("passbook_outposts.outpostserviceconnection",),
 | 
			
		||||
        ),
 | 
			
		||||
@ -119,4 +121,46 @@ class Migration(migrations.Migration):
 | 
			
		||||
            model_name="outpost",
 | 
			
		||||
            name="deployment_type",
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterModelOptions(
 | 
			
		||||
            name="dockerserviceconnection",
 | 
			
		||||
            options={
 | 
			
		||||
                "verbose_name": "Docker Service-Connection",
 | 
			
		||||
                "verbose_name_plural": "Docker Service-Connections",
 | 
			
		||||
            },
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterModelOptions(
 | 
			
		||||
            name="kubernetesserviceconnection",
 | 
			
		||||
            options={
 | 
			
		||||
                "verbose_name": "Kubernetes Service-Connection",
 | 
			
		||||
                "verbose_name_plural": "Kubernetes Service-Connections",
 | 
			
		||||
            },
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name="outpost",
 | 
			
		||||
            name="service_connection",
 | 
			
		||||
            field=passbook.lib.models.InheritanceForeignKey(
 | 
			
		||||
                blank=True,
 | 
			
		||||
                default=None,
 | 
			
		||||
                help_text="Select Service-Connection passbook should use to manage this outpost. Leave empty if passbook should not handle the deployment.",
 | 
			
		||||
                null=True,
 | 
			
		||||
                on_delete=django.db.models.deletion.SET_DEFAULT,
 | 
			
		||||
                to="passbook_outposts.outpostserviceconnection",
 | 
			
		||||
            ),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterModelOptions(
 | 
			
		||||
            name="outpostserviceconnection",
 | 
			
		||||
            options={
 | 
			
		||||
                "verbose_name": "Outpost Service-Connection",
 | 
			
		||||
                "verbose_name_plural": "Outpost Service-Connections",
 | 
			
		||||
            },
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name="kubernetesserviceconnection",
 | 
			
		||||
            name="kubeconfig",
 | 
			
		||||
            field=models.JSONField(
 | 
			
		||||
                default=None,
 | 
			
		||||
                help_text="Paste your kubeconfig here. passbook will automatically use the currently selected context.",
 | 
			
		||||
            ),
 | 
			
		||||
            preserve_default=False,
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
@ -1,13 +1,14 @@
 | 
			
		||||
"""Outpost models"""
 | 
			
		||||
from dataclasses import asdict, dataclass, field
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from typing import Dict, Iterable, List, Optional, Union
 | 
			
		||||
from typing import Dict, Iterable, List, Optional, Type, Union
 | 
			
		||||
from uuid import uuid4
 | 
			
		||||
 | 
			
		||||
from dacite import from_dict
 | 
			
		||||
from django.core.cache import cache
 | 
			
		||||
from django.db import models, transaction
 | 
			
		||||
from django.db.models.base import Model
 | 
			
		||||
from django.forms.models import ModelForm
 | 
			
		||||
from django.http import HttpRequest
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from guardian.models import UserObjectPermission
 | 
			
		||||
@ -86,18 +87,63 @@ class OutpostServiceConnection(models.Model):
 | 
			
		||||
 | 
			
		||||
    objects = InheritanceManager()
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def form(self) -> Type[ModelForm]:
 | 
			
		||||
        """Return Form class used to edit this object"""
 | 
			
		||||
        raise NotImplementedError
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
 | 
			
		||||
        verbose_name = _("Outpost Service-Connection")
 | 
			
		||||
        verbose_name_plural = _("Outpost Service-Connections")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DockerServiceConnection(OutpostServiceConnection):
 | 
			
		||||
    """Service Connection to a docker endpoint"""
 | 
			
		||||
    """Service Connection to a Docker endpoint"""
 | 
			
		||||
 | 
			
		||||
    url = models.TextField()
 | 
			
		||||
    tls = models.BooleanField()
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def form(self) -> Type[ModelForm]:
 | 
			
		||||
        from passbook.outposts.forms import DockerServiceConnectionForm
 | 
			
		||||
 | 
			
		||||
        return DockerServiceConnectionForm
 | 
			
		||||
 | 
			
		||||
    def __str__(self) -> str:
 | 
			
		||||
        return f"Docker Service-Connection {self.name}"
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
 | 
			
		||||
        verbose_name = _("Docker Service-Connection")
 | 
			
		||||
        verbose_name_plural = _("Docker Service-Connections")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class KubernetesServiceConnection(OutpostServiceConnection):
 | 
			
		||||
    """Service Connection to a kubernetes cluster"""
 | 
			
		||||
    """Service Connection to a Kubernetes cluster"""
 | 
			
		||||
 | 
			
		||||
    config = models.JSONField()
 | 
			
		||||
    kubeconfig = models.JSONField(
 | 
			
		||||
        help_text=_(
 | 
			
		||||
            (
 | 
			
		||||
                "Paste your kubeconfig here. passbook will automatically use "
 | 
			
		||||
                "the currently selected context."
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def form(self) -> Type[ModelForm]:
 | 
			
		||||
        from passbook.outposts.forms import KubernetesServiceConnectionForm
 | 
			
		||||
 | 
			
		||||
        return KubernetesServiceConnectionForm
 | 
			
		||||
 | 
			
		||||
    def __str__(self) -> str:
 | 
			
		||||
        return f"Kubernetes Service-Connection {self.name}"
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
 | 
			
		||||
        verbose_name = _("Kubernetes Service-Connection")
 | 
			
		||||
        verbose_name_plural = _("Kubernetes Service-Connections")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Outpost(models.Model):
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user