admin: add views for outpost service-connections
This commit is contained in:
parent
bd74e518a7
commit
c04d0a373a
|
@ -46,12 +46,29 @@
|
||||||
{% trans 'Providers' %}
|
{% trans 'Providers' %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="pf-c-nav__item pf-m-expanded">
|
||||||
|
<a href="#" class="pf-c-nav__link" aria-expanded="true">{% trans 'Outposts' %}
|
||||||
|
<span class="pf-c-nav__toggle">
|
||||||
|
<i class="fas fa-angle-right" aria-hidden="true"></i>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<section class="pf-c-nav__subnav">
|
||||||
|
<ul class="pf-c-nav__simple-list">
|
||||||
<li class="pf-c-nav__item">
|
<li class="pf-c-nav__item">
|
||||||
<a href="{% url 'passbook_admin:outposts' %}"
|
<a href="{% url 'passbook_admin:outposts' %}"
|
||||||
class="pf-c-nav__link {% is_active 'passbook_admin:outposts' 'passbook_admin:outpost-create' 'passbook_admin:outpost-update' 'passbook_admin:outpost-delete' %}">
|
class="pf-c-nav__link {% is_active 'passbook_admin:outposts' 'passbook_admin:outpost-create' 'passbook_admin:outpost-update' 'passbook_admin:outpost-delete' %}">
|
||||||
{% trans 'Outposts' %}
|
{% trans 'Outposts' %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="pf-c-nav__item">
|
||||||
|
<a href="{% url 'passbook_admin:outpost-service-connections' %}"
|
||||||
|
class="pf-c-nav__link {% is_active 'passbook_admin:outpost-service-connections' 'passbook_admin:outpost-service-connections-create' 'passbook_admin:outpost-service-connections-update' 'passbook_admin:outpost-service-connections-delete' %}">
|
||||||
|
{% trans 'Service Connections' %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</li>
|
||||||
<li class="pf-c-nav__item">
|
<li class="pf-c-nav__item">
|
||||||
<a href="{% url 'passbook_admin:property-mappings' %}"
|
<a href="{% url 'passbook_admin:property-mappings' %}"
|
||||||
class="pf-c-nav__link {% is_active 'passbook_admin:property-mappings' 'passbook_admin:property-mapping-create' 'passbook_admin:property-mapping-update' 'passbook_admin:property-mapping-delete' %}">
|
class="pf-c-nav__link {% is_active 'passbook_admin:property-mappings' 'passbook_admin:property-mapping-create' 'passbook_admin:property-mapping-update' 'passbook_admin:property-mapping-delete' %}">
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
{% extends "administration/base.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
{% load humanize %}
|
||||||
|
{% load passbook_utils %}
|
||||||
|
{% load admin_reflection %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<section class="pf-c-page__main-section pf-m-light">
|
||||||
|
<div class="pf-c-content">
|
||||||
|
<h1>
|
||||||
|
<i class="pf-icon-integration"></i>
|
||||||
|
{% trans 'Outpost Service-Connections' %}
|
||||||
|
</h1>
|
||||||
|
<p>{% trans "Outpost Service-Connections define how passbook connects to external platforms to manage and deploy Outposts." %}</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||||
|
<div class="pf-c-card">
|
||||||
|
{% if object_list %}
|
||||||
|
<div class="pf-c-toolbar">
|
||||||
|
<div class="pf-c-toolbar__content">
|
||||||
|
{% include 'partials/toolbar_search.html' %}
|
||||||
|
<div class="pf-c-toolbar__bulk-select">
|
||||||
|
<div class="pf-c-dropdown">
|
||||||
|
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
||||||
|
<span class="pf-c-dropdown__toggle-text">{% trans 'Create' %}</span>
|
||||||
|
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
<ul class="pf-c-dropdown__menu" hidden>
|
||||||
|
{% for type, name in types.items %}
|
||||||
|
<li>
|
||||||
|
<a class="pf-c-dropdown__menu-item" href="{% url 'passbook_admin:outpost-service-connection-create' %}?type={{ type }}&back={{ request.get_full_path }}">
|
||||||
|
{{ name|verbose_name }}<br>
|
||||||
|
<small>
|
||||||
|
{{ name|doc }}
|
||||||
|
</small>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% include 'partials/pagination.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table class="pf-c-table pf-m-compact pf-m-grid-xl" role="grid">
|
||||||
|
<thead>
|
||||||
|
<tr role="row">
|
||||||
|
<th role="columnheader" scope="col">{% trans 'Name' %}</th>
|
||||||
|
<th role="columnheader" scope="col">{% trans 'Type' %}</th>
|
||||||
|
<th role="columnheader" scope="col">{% trans 'Local?' %}</th>
|
||||||
|
<th role="cell"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody role="rowgroup">
|
||||||
|
{% for sc in object_list %}
|
||||||
|
<tr role="row">
|
||||||
|
<th role="columnheader">
|
||||||
|
<span>{{ sc.name }}</span>
|
||||||
|
</th>
|
||||||
|
<td role="cell">
|
||||||
|
<span>
|
||||||
|
{{ sc|verbose_name }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td role="cell">
|
||||||
|
<span>
|
||||||
|
{{ sc.local|yesno:"Yes,No" }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="pf-c-button pf-m-secondary" href="{% url 'passbook_admin:outpost-service-connection-update' pk=sc.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||||
|
<a class="pf-c-button pf-m-danger" href="{% url 'passbook_admin:outpost-service-connection-delete' pk=sc.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="pf-c-pagination pf-m-bottom">
|
||||||
|
{% include 'partials/pagination.html' %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="pf-c-toolbar">
|
||||||
|
<div class="pf-c-toolbar__content">
|
||||||
|
{% include 'partials/toolbar_search.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pf-c-empty-state">
|
||||||
|
<div class="pf-c-empty-state__content">
|
||||||
|
<i class="fas fa-map-marker pf-c-empty-state__icon" aria-hidden="true"></i>
|
||||||
|
<h1 class="pf-c-title pf-m-lg">
|
||||||
|
{% trans 'No Outpost Service Connections.' %}
|
||||||
|
</h1>
|
||||||
|
<div class="pf-c-empty-state__body">
|
||||||
|
{% if request.GET.search != "" %}
|
||||||
|
{% trans "Your search query doesn't match any outposts." %}
|
||||||
|
{% else %}
|
||||||
|
{% trans 'Currently no service connections exist. Click the button below to create one.' %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="pf-c-dropdown">
|
||||||
|
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
||||||
|
<span class="pf-c-dropdown__toggle-text">{% trans 'Create' %}</span>
|
||||||
|
<i class="fas fa-caret-down pf-c-dropdown__toggle-icon" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
<ul class="pf-c-dropdown__menu" hidden>
|
||||||
|
{% for type, name in types.items %}
|
||||||
|
<li>
|
||||||
|
<a class="pf-c-dropdown__menu-item" href="{% url 'passbook_admin:outpost-service-connection-create' %}?type={{ type }}&back={{ request.get_full_path }}">
|
||||||
|
{{ name|verbose_name }}<br>
|
||||||
|
<small>
|
||||||
|
{{ name|doc }}
|
||||||
|
</small>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
|
@ -7,10 +7,11 @@ from passbook.admin.views import (
|
||||||
flows,
|
flows,
|
||||||
groups,
|
groups,
|
||||||
outposts,
|
outposts,
|
||||||
|
outposts_service_connections,
|
||||||
overview,
|
overview,
|
||||||
policies,
|
policies,
|
||||||
policies_bindings,
|
policies_bindings,
|
||||||
property_mapping,
|
property_mappings,
|
||||||
providers,
|
providers,
|
||||||
sources,
|
sources,
|
||||||
stages,
|
stages,
|
||||||
|
@ -225,22 +226,22 @@ urlpatterns = [
|
||||||
# Property Mappings
|
# Property Mappings
|
||||||
path(
|
path(
|
||||||
"property-mappings/",
|
"property-mappings/",
|
||||||
property_mapping.PropertyMappingListView.as_view(),
|
property_mappings.PropertyMappingListView.as_view(),
|
||||||
name="property-mappings",
|
name="property-mappings",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"property-mappings/create/",
|
"property-mappings/create/",
|
||||||
property_mapping.PropertyMappingCreateView.as_view(),
|
property_mappings.PropertyMappingCreateView.as_view(),
|
||||||
name="property-mapping-create",
|
name="property-mapping-create",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"property-mappings/<uuid:pk>/update/",
|
"property-mappings/<uuid:pk>/update/",
|
||||||
property_mapping.PropertyMappingUpdateView.as_view(),
|
property_mappings.PropertyMappingUpdateView.as_view(),
|
||||||
name="property-mapping-update",
|
name="property-mapping-update",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"property-mappings/<uuid:pk>/delete/",
|
"property-mappings/<uuid:pk>/delete/",
|
||||||
property_mapping.PropertyMappingDeleteView.as_view(),
|
property_mappings.PropertyMappingDeleteView.as_view(),
|
||||||
name="property-mapping-delete",
|
name="property-mapping-delete",
|
||||||
),
|
),
|
||||||
# Users
|
# Users
|
||||||
|
@ -312,6 +313,27 @@ urlpatterns = [
|
||||||
outposts.OutpostDeleteView.as_view(),
|
outposts.OutpostDeleteView.as_view(),
|
||||||
name="outpost-delete",
|
name="outpost-delete",
|
||||||
),
|
),
|
||||||
|
# Outpost Service Connections
|
||||||
|
path(
|
||||||
|
"outposts/service_connections/",
|
||||||
|
outposts_service_connections.OutpostServiceConnectionListView.as_view(),
|
||||||
|
name="outpost-service-connections",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"outposts/service_connections/create/",
|
||||||
|
outposts_service_connections.OutpostServiceConnectionCreateView.as_view(),
|
||||||
|
name="outpost-service-connection-create",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"outposts/service_connections/<uuid:pk>/update/",
|
||||||
|
outposts_service_connections.OutpostServiceConnectionUpdateView.as_view(),
|
||||||
|
name="outpost-service-connection-update",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"outposts/service_connections/<uuid:pk>/delete/",
|
||||||
|
outposts_service_connections.OutpostServiceConnectionDeleteView.as_view(),
|
||||||
|
name="outpost-service-connection-delete",
|
||||||
|
),
|
||||||
# Tasks
|
# Tasks
|
||||||
path(
|
path(
|
||||||
"tasks/",
|
"tasks/",
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
"""passbook OutpostServiceConnection administration"""
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.contrib.auth.mixins import (
|
||||||
|
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
|
||||||
|
)
|
||||||
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||||
|
|
||||||
|
from passbook.admin.views.utils import (
|
||||||
|
BackSuccessUrlMixin,
|
||||||
|
DeleteMessageView,
|
||||||
|
InheritanceCreateView,
|
||||||
|
InheritanceListView,
|
||||||
|
InheritanceUpdateView,
|
||||||
|
SearchListMixin,
|
||||||
|
UserPaginateListMixin,
|
||||||
|
)
|
||||||
|
from passbook.outposts.models import OutpostServiceConnection
|
||||||
|
|
||||||
|
|
||||||
|
class OutpostServiceConnectionListView(
|
||||||
|
LoginRequiredMixin,
|
||||||
|
PermissionListMixin,
|
||||||
|
UserPaginateListMixin,
|
||||||
|
SearchListMixin,
|
||||||
|
InheritanceListView,
|
||||||
|
):
|
||||||
|
"""Show list of all outpost-service-connections"""
|
||||||
|
|
||||||
|
model = OutpostServiceConnection
|
||||||
|
permission_required = "passbook_outposts.add_outpostserviceconnection"
|
||||||
|
template_name = "administration/outpost_service_connection/list.html"
|
||||||
|
ordering = "pk"
|
||||||
|
search_fields = ["pk", "name"]
|
||||||
|
|
||||||
|
|
||||||
|
class OutpostServiceConnectionCreateView(
|
||||||
|
SuccessMessageMixin,
|
||||||
|
BackSuccessUrlMixin,
|
||||||
|
LoginRequiredMixin,
|
||||||
|
DjangoPermissionRequiredMixin,
|
||||||
|
InheritanceCreateView,
|
||||||
|
):
|
||||||
|
"""Create new OutpostServiceConnection"""
|
||||||
|
|
||||||
|
model = OutpostServiceConnection
|
||||||
|
permission_required = "passbook_outposts.add_outpostserviceconnection"
|
||||||
|
|
||||||
|
template_name = "generic/create.html"
|
||||||
|
success_url = reverse_lazy("passbook_admin:outpost-service-connections")
|
||||||
|
success_message = _("Successfully created OutpostServiceConnection")
|
||||||
|
|
||||||
|
|
||||||
|
class OutpostServiceConnectionUpdateView(
|
||||||
|
SuccessMessageMixin,
|
||||||
|
BackSuccessUrlMixin,
|
||||||
|
LoginRequiredMixin,
|
||||||
|
PermissionRequiredMixin,
|
||||||
|
InheritanceUpdateView,
|
||||||
|
):
|
||||||
|
"""Update outpostserviceconnection"""
|
||||||
|
|
||||||
|
model = OutpostServiceConnection
|
||||||
|
permission_required = "passbook_outposts.change_outpostserviceconnection"
|
||||||
|
|
||||||
|
template_name = "generic/update.html"
|
||||||
|
success_url = reverse_lazy("passbook_admin:outpost-service-connections")
|
||||||
|
success_message = _("Successfully updated OutpostServiceConnection")
|
||||||
|
|
||||||
|
|
||||||
|
class OutpostServiceConnectionDeleteView(
|
||||||
|
LoginRequiredMixin, PermissionRequiredMixin, DeleteMessageView
|
||||||
|
):
|
||||||
|
"""Delete outpostserviceconnection"""
|
||||||
|
|
||||||
|
model = OutpostServiceConnection
|
||||||
|
permission_required = "passbook_outposts.delete_outpostserviceconnection"
|
||||||
|
|
||||||
|
template_name = "generic/delete.html"
|
||||||
|
success_url = reverse_lazy("passbook_admin:outpost-service-connections")
|
||||||
|
success_message = _("Successfully deleted OutpostServiceConnection")
|
|
@ -32,8 +32,8 @@ class ProviderListView(
|
||||||
model = Provider
|
model = Provider
|
||||||
permission_required = "passbook_core.add_provider"
|
permission_required = "passbook_core.add_provider"
|
||||||
template_name = "administration/provider/list.html"
|
template_name = "administration/provider/list.html"
|
||||||
ordering = "id"
|
ordering = "pk"
|
||||||
search_fields = ["id", "name"]
|
search_fields = ["pk", "name"]
|
||||||
|
|
||||||
|
|
||||||
class ProviderCreateView(
|
class ProviderCreateView(
|
||||||
|
|
|
@ -19,7 +19,11 @@ from passbook.core.api.tokens import TokenViewSet
|
||||||
from passbook.core.api.users import UserViewSet
|
from passbook.core.api.users import UserViewSet
|
||||||
from passbook.crypto.api import CertificateKeyPairViewSet
|
from passbook.crypto.api import CertificateKeyPairViewSet
|
||||||
from passbook.flows.api import FlowStageBindingViewSet, FlowViewSet, StageViewSet
|
from passbook.flows.api import FlowStageBindingViewSet, FlowViewSet, StageViewSet
|
||||||
from passbook.outposts.api import OutpostViewSet, DockerServiceConnectionViewSet, KubernetesServiceConnectionViewSet
|
from passbook.outposts.api import (
|
||||||
|
DockerServiceConnectionViewSet,
|
||||||
|
KubernetesServiceConnectionViewSet,
|
||||||
|
OutpostViewSet,
|
||||||
|
)
|
||||||
from passbook.policies.api import PolicyBindingViewSet, PolicyViewSet
|
from passbook.policies.api import PolicyBindingViewSet, PolicyViewSet
|
||||||
from passbook.policies.dummy.api import DummyPolicyViewSet
|
from passbook.policies.dummy.api import DummyPolicyViewSet
|
||||||
from passbook.policies.expiry.api import PasswordExpiryPolicyViewSet
|
from passbook.policies.expiry.api import PasswordExpiryPolicyViewSet
|
||||||
|
@ -67,7 +71,9 @@ router.register("core/tokens", TokenViewSet)
|
||||||
|
|
||||||
router.register("outposts/outposts", OutpostViewSet)
|
router.register("outposts/outposts", OutpostViewSet)
|
||||||
router.register("outposts/service_connections/docker", DockerServiceConnectionViewSet)
|
router.register("outposts/service_connections/docker", DockerServiceConnectionViewSet)
|
||||||
router.register("outposts/service_connections/kubernetes", KubernetesServiceConnectionViewSet)
|
router.register(
|
||||||
|
"outposts/service_connections/kubernetes", KubernetesServiceConnectionViewSet
|
||||||
|
)
|
||||||
router.register("outposts/proxy", ProxyOutpostConfigViewSet)
|
router.register("outposts/proxy", ProxyOutpostConfigViewSet)
|
||||||
|
|
||||||
router.register("flows/instances", FlowViewSet)
|
router.register("flows/instances", FlowViewSet)
|
||||||
|
|
|
@ -49,7 +49,7 @@ class KubernetesServiceConnectionSerializer(ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
model = KubernetesServiceConnection
|
model = KubernetesServiceConnection
|
||||||
fields = ["pk", "name", "local", "config"]
|
fields = ["pk", "name", "local", "kubeconfig"]
|
||||||
|
|
||||||
|
|
||||||
class KubernetesServiceConnectionViewSet(ModelViewSet):
|
class KubernetesServiceConnectionViewSet(ModelViewSet):
|
||||||
|
|
|
@ -6,6 +6,7 @@ from pathlib import Path
|
||||||
from socket import gethostname
|
from socket import gethostname
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
import yaml
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
from django.db import ProgrammingError
|
from django.db import ProgrammingError
|
||||||
from docker.constants import DEFAULT_UNIX_SOCKET
|
from docker.constants import DEFAULT_UNIX_SOCKET
|
||||||
|
@ -43,19 +44,21 @@ class PassbookOutpostConfig(AppConfig):
|
||||||
if not KubernetesServiceConnection.objects.filter(local=True).exists():
|
if not KubernetesServiceConnection.objects.filter(local=True).exists():
|
||||||
LOGGER.debug("Created Service Connection for in-cluster")
|
LOGGER.debug("Created Service Connection for in-cluster")
|
||||||
KubernetesServiceConnection.objects.create(
|
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
|
# For development, check for the existence of a kubeconfig file
|
||||||
kubeconfig_path = expanduser(KUBE_CONFIG_DEFAULT_LOCATION)
|
kubeconfig_path = expanduser(KUBE_CONFIG_DEFAULT_LOCATION)
|
||||||
if Path(kubeconfig_path).exists():
|
if Path(kubeconfig_path).exists():
|
||||||
LOGGER.debug("Detected kubeconfig")
|
LOGGER.debug("Detected kubeconfig")
|
||||||
|
kubeconfig_local_name = f"k8s-{gethostname()}"
|
||||||
if not KubernetesServiceConnection.objects.filter(
|
if not KubernetesServiceConnection.objects.filter(
|
||||||
name=gethostname()
|
name=kubeconfig_local_name
|
||||||
).exists():
|
).exists():
|
||||||
LOGGER.debug("Creating kubeconfig Service Connection")
|
LOGGER.debug("Creating kubeconfig Service Connection")
|
||||||
with open(kubeconfig_path, "r") as _kubeconfig:
|
with open(kubeconfig_path, "r") as _kubeconfig:
|
||||||
KubernetesServiceConnection.objects.create(
|
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
|
unix_socket_path = urlparse(DEFAULT_UNIX_SOCKET).path
|
||||||
socket = Path(unix_socket_path)
|
socket = Path(unix_socket_path)
|
||||||
|
|
|
@ -33,7 +33,7 @@ class KubernetesController(BaseController):
|
||||||
if self.connection.local:
|
if self.connection.local:
|
||||||
load_incluster_config()
|
load_incluster_config()
|
||||||
else:
|
else:
|
||||||
load_kube_config_from_dict(self.connection.config)
|
load_kube_config_from_dict(self.connection.kubeconfig)
|
||||||
except ConfigException:
|
except ConfigException:
|
||||||
load_kube_config()
|
load_kube_config()
|
||||||
self.reconcilers = {
|
self.reconcilers = {
|
||||||
|
|
|
@ -4,7 +4,11 @@ from django import forms
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from passbook.admin.fields import CodeMirrorWidget, YAMLField
|
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
|
from passbook.providers.proxy.models import ProxyProvider
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,3 +37,35 @@ class OutpostForm(forms.ModelForm):
|
||||||
"_config": YAMLField,
|
"_config": YAMLField,
|
||||||
}
|
}
|
||||||
labels = {"_config": _("Configuration")}
|
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 import migrations, models
|
||||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||||
|
|
||||||
|
import passbook.lib.models
|
||||||
|
|
||||||
|
|
||||||
def migrate_to_service_connection(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
|
def migrate_to_service_connection(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
|
||||||
db_alias = schema_editor.connection.alias
|
db_alias = schema_editor.connection.alias
|
||||||
|
@ -98,7 +100,7 @@ class Migration(migrations.Migration):
|
||||||
to="passbook_outposts.outpostserviceconnection",
|
to="passbook_outposts.outpostserviceconnection",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("config", models.JSONField()),
|
("kubeconfig", models.JSONField()),
|
||||||
],
|
],
|
||||||
bases=("passbook_outposts.outpostserviceconnection",),
|
bases=("passbook_outposts.outpostserviceconnection",),
|
||||||
),
|
),
|
||||||
|
@ -119,4 +121,46 @@ class Migration(migrations.Migration):
|
||||||
model_name="outpost",
|
model_name="outpost",
|
||||||
name="deployment_type",
|
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"""
|
"""Outpost models"""
|
||||||
from dataclasses import asdict, dataclass, field
|
from dataclasses import asdict, dataclass, field
|
||||||
from datetime import datetime
|
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 uuid import uuid4
|
||||||
|
|
||||||
from dacite import from_dict
|
from dacite import from_dict
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
from django.db.models.base import Model
|
from django.db.models.base import Model
|
||||||
|
from django.forms.models import ModelForm
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from guardian.models import UserObjectPermission
|
from guardian.models import UserObjectPermission
|
||||||
|
@ -86,18 +87,63 @@ class OutpostServiceConnection(models.Model):
|
||||||
|
|
||||||
objects = InheritanceManager()
|
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):
|
class DockerServiceConnection(OutpostServiceConnection):
|
||||||
"""Service Connection to a docker endpoint"""
|
"""Service Connection to a Docker endpoint"""
|
||||||
|
|
||||||
url = models.TextField()
|
url = models.TextField()
|
||||||
tls = models.BooleanField()
|
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):
|
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):
|
class Outpost(models.Model):
|
||||||
|
|
12
swagger.yaml
12
swagger.yaml
|
@ -1476,7 +1476,7 @@ paths:
|
||||||
parameters:
|
parameters:
|
||||||
- name: uuid
|
- name: uuid
|
||||||
in: path
|
in: path
|
||||||
description: A UUID string identifying this docker service connection.
|
description: A UUID string identifying this Docker Service-Connection.
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
|
@ -1603,7 +1603,7 @@ paths:
|
||||||
parameters:
|
parameters:
|
||||||
- name: uuid
|
- name: uuid
|
||||||
in: path
|
in: path
|
||||||
description: A UUID string identifying this kubernetes service connection.
|
description: A UUID string identifying this Kubernetes Service-Connection.
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
|
@ -6888,7 +6888,7 @@ definitions:
|
||||||
description: KubernetesServiceConnection Serializer
|
description: KubernetesServiceConnection Serializer
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
- config
|
- kubeconfig
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
pk:
|
pk:
|
||||||
|
@ -6905,8 +6905,10 @@ definitions:
|
||||||
description: If enabled, use the local connection. Required Docker socket/Kubernetes
|
description: If enabled, use the local connection. Required Docker socket/Kubernetes
|
||||||
Integration
|
Integration
|
||||||
type: boolean
|
type: boolean
|
||||||
config:
|
kubeconfig:
|
||||||
title: Config
|
title: Kubeconfig
|
||||||
|
description: Paste your kubeconfig here. passbook will automatically use the
|
||||||
|
currently selected context.
|
||||||
type: object
|
type: object
|
||||||
Policy:
|
Policy:
|
||||||
description: Policy Serializer
|
description: Policy Serializer
|
||||||
|
|
Reference in New Issue