web: migrate Outpost Service Connection to web
This commit is contained in:
parent
8008918d8b
commit
865f652476
|
@ -1,153 +0,0 @@
|
||||||
{% extends "administration/base.html" %}
|
|
||||||
|
|
||||||
{% load i18n %}
|
|
||||||
{% load humanize %}
|
|
||||||
{% load authentik_utils %}
|
|
||||||
|
|
||||||
{% 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 authentik 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">
|
|
||||||
<ak-dropdown 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>
|
|
||||||
<ak-modal-button href="{% url 'authentik_admin:outpost-service-connection-create' %}?type={{ type }}">
|
|
||||||
<button slot="trigger" class="pf-c-dropdown__menu-item">
|
|
||||||
{{ name|verbose_name }}<br>
|
|
||||||
<small>
|
|
||||||
{{ name|doc }}
|
|
||||||
</small>
|
|
||||||
</button>
|
|
||||||
<div slot="modal"></div>
|
|
||||||
</ak-modal-button>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</ak-dropdown>
|
|
||||||
<button role="ak-refresh" class="pf-c-button pf-m-primary">
|
|
||||||
{% trans 'Refresh' %}
|
|
||||||
</button>
|
|
||||||
</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="columnheader" scope="col">{% trans 'Status' %}</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 role="cell">
|
|
||||||
<span>
|
|
||||||
{% if sc.state.healthy %}
|
|
||||||
<i class="fas fa-check pf-m-success"></i> {{ sc.state.version }}
|
|
||||||
{% else %}
|
|
||||||
<i class="fas fa-times pf-m-danger"></i> {% trans 'Unhealthy' %}
|
|
||||||
{% endif %}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<ak-modal-button href="{% url 'authentik_admin:outpost-service-connection-update' pk=sc.pk %}">
|
|
||||||
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
|
||||||
{% trans 'Edit' %}
|
|
||||||
</ak-spinner-button>
|
|
||||||
<div slot="modal"></div>
|
|
||||||
</ak-modal-button>
|
|
||||||
<ak-modal-button href="{% url 'authentik_admin:outpost-service-connection-delete' pk=sc.pk %}">
|
|
||||||
<ak-spinner-button slot="trigger" class="pf-m-danger">
|
|
||||||
{% trans 'Delete' %}
|
|
||||||
</ak-spinner-button>
|
|
||||||
<div slot="modal"></div>
|
|
||||||
</ak-modal-button>
|
|
||||||
</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>
|
|
||||||
<ak-dropdown 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>
|
|
||||||
<ak-modal-button href="{% url 'authentik_admin:outpost-service-connection-create' %}?type={{ type }}">
|
|
||||||
<button slot="trigger" class="pf-c-dropdown__menu-item">
|
|
||||||
{{ name|verbose_name }}<br>
|
|
||||||
<small>
|
|
||||||
{{ name|doc }}
|
|
||||||
</small>
|
|
||||||
</button>
|
|
||||||
<div slot="modal"></div>
|
|
||||||
</ak-modal-button>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</ak-dropdown>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
{% endblock %}
|
|
|
@ -308,11 +308,6 @@ urlpatterns = [
|
||||||
name="outpost-delete",
|
name="outpost-delete",
|
||||||
),
|
),
|
||||||
# Outpost Service Connections
|
# Outpost Service Connections
|
||||||
path(
|
|
||||||
"outpost_service_connections/",
|
|
||||||
outposts_service_connections.OutpostServiceConnectionListView.as_view(),
|
|
||||||
name="outpost-service-connections",
|
|
||||||
),
|
|
||||||
path(
|
path(
|
||||||
"outpost_service_connections/create/",
|
"outpost_service_connections/create/",
|
||||||
outposts_service_connections.OutpostServiceConnectionCreateView.as_view(),
|
outposts_service_connections.OutpostServiceConnectionCreateView.as_view(),
|
||||||
|
|
|
@ -4,38 +4,18 @@ from django.contrib.auth.mixins import (
|
||||||
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
|
PermissionRequiredMixin as DjangoPermissionRequiredMixin,
|
||||||
)
|
)
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
from django.urls import reverse_lazy
|
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
from guardian.mixins import PermissionRequiredMixin
|
||||||
|
|
||||||
from authentik.admin.views.utils import (
|
from authentik.admin.views.utils import (
|
||||||
BackSuccessUrlMixin,
|
BackSuccessUrlMixin,
|
||||||
DeleteMessageView,
|
DeleteMessageView,
|
||||||
InheritanceCreateView,
|
InheritanceCreateView,
|
||||||
InheritanceListView,
|
|
||||||
InheritanceUpdateView,
|
InheritanceUpdateView,
|
||||||
SearchListMixin,
|
|
||||||
UserPaginateListMixin,
|
|
||||||
)
|
)
|
||||||
from authentik.outposts.models import OutpostServiceConnection
|
from authentik.outposts.models import OutpostServiceConnection
|
||||||
|
|
||||||
|
|
||||||
class OutpostServiceConnectionListView(
|
|
||||||
LoginRequiredMixin,
|
|
||||||
PermissionListMixin,
|
|
||||||
UserPaginateListMixin,
|
|
||||||
SearchListMixin,
|
|
||||||
InheritanceListView,
|
|
||||||
):
|
|
||||||
"""Show list of all outpost-service-connections"""
|
|
||||||
|
|
||||||
model = OutpostServiceConnection
|
|
||||||
permission_required = "authentik_outposts.add_outpostserviceconnection"
|
|
||||||
template_name = "administration/outpost_service_connection/list.html"
|
|
||||||
ordering = "pk"
|
|
||||||
search_fields = ["pk", "name"]
|
|
||||||
|
|
||||||
|
|
||||||
class OutpostServiceConnectionCreateView(
|
class OutpostServiceConnectionCreateView(
|
||||||
SuccessMessageMixin,
|
SuccessMessageMixin,
|
||||||
BackSuccessUrlMixin,
|
BackSuccessUrlMixin,
|
||||||
|
@ -49,7 +29,7 @@ class OutpostServiceConnectionCreateView(
|
||||||
permission_required = "authentik_outposts.add_outpostserviceconnection"
|
permission_required = "authentik_outposts.add_outpostserviceconnection"
|
||||||
|
|
||||||
template_name = "generic/create.html"
|
template_name = "generic/create.html"
|
||||||
success_url = reverse_lazy("authentik_admin:outpost-service-connections")
|
success_url = "/"
|
||||||
success_message = _("Successfully created Outpost Service Connection")
|
success_message = _("Successfully created Outpost Service Connection")
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,7 +46,7 @@ class OutpostServiceConnectionUpdateView(
|
||||||
permission_required = "authentik_outposts.change_outpostserviceconnection"
|
permission_required = "authentik_outposts.change_outpostserviceconnection"
|
||||||
|
|
||||||
template_name = "generic/update.html"
|
template_name = "generic/update.html"
|
||||||
success_url = reverse_lazy("authentik_admin:outpost-service-connections")
|
success_url = "/"
|
||||||
success_message = _("Successfully updated Outpost Service Connection")
|
success_message = _("Successfully updated Outpost Service Connection")
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,5 +59,5 @@ class OutpostServiceConnectionDeleteView(
|
||||||
permission_required = "authentik_outposts.delete_outpostserviceconnection"
|
permission_required = "authentik_outposts.delete_outpostserviceconnection"
|
||||||
|
|
||||||
template_name = "generic/delete.html"
|
template_name = "generic/delete.html"
|
||||||
success_url = reverse_lazy("authentik_admin:outpost-service-connections")
|
success_url = "/"
|
||||||
success_message = _("Successfully deleted Outpost Service Connection")
|
success_message = _("Successfully deleted Outpost Service Connection")
|
||||||
|
|
|
@ -1,7 +1,19 @@
|
||||||
"""Outpost API Views"""
|
"""Outpost API Views"""
|
||||||
from rest_framework.serializers import ModelSerializer
|
from dataclasses import asdict
|
||||||
|
|
||||||
|
from django.db.models.base import Model
|
||||||
|
from django.shortcuts import reverse
|
||||||
|
from drf_yasg2.utils import swagger_auto_schema
|
||||||
|
from rest_framework.decorators import action
|
||||||
|
from rest_framework.fields import BooleanField, CharField, SerializerMethodField
|
||||||
|
from rest_framework.request import Request
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.serializers import ModelSerializer, Serializer
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
|
from authentik.core.api.utils import MetaNameSerializer, TypeCreateSerializer
|
||||||
|
from authentik.lib.templatetags.authentik_utils import verbose_name
|
||||||
|
from authentik.lib.utils.reflection import all_subclasses
|
||||||
from authentik.outposts.models import (
|
from authentik.outposts.models import (
|
||||||
DockerServiceConnection,
|
DockerServiceConnection,
|
||||||
KubernetesServiceConnection,
|
KubernetesServiceConnection,
|
||||||
|
@ -9,32 +21,79 @@ from authentik.outposts.models import (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ServiceConnectionSerializer(ModelSerializer):
|
class ServiceConnectionSerializer(ModelSerializer, MetaNameSerializer):
|
||||||
"""ServiceConnection Serializer"""
|
"""ServiceConnection Serializer"""
|
||||||
|
|
||||||
|
object_type = SerializerMethodField()
|
||||||
|
|
||||||
|
def get_object_type(self, obj: OutpostServiceConnection) -> str:
|
||||||
|
"""Get object type so that we know which API Endpoint to use to get the full object"""
|
||||||
|
return obj._meta.object_name.lower().replace("serviceconnection", "")
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
model = OutpostServiceConnection
|
model = OutpostServiceConnection
|
||||||
fields = ["pk", "name"]
|
fields = [
|
||||||
|
"pk",
|
||||||
|
"name",
|
||||||
|
"local",
|
||||||
|
"object_type",
|
||||||
|
"verbose_name",
|
||||||
|
"verbose_name_plural",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceConnectionStateSerializer(Serializer):
|
||||||
|
"""Serializer for Service connection state"""
|
||||||
|
|
||||||
|
healthy = BooleanField(read_only=True)
|
||||||
|
version = CharField(read_only=True)
|
||||||
|
|
||||||
|
def create(self, validated_data: dict) -> Model:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def update(self, instance: Model, validated_data: dict) -> Model:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
class ServiceConnectionViewSet(ModelViewSet):
|
class ServiceConnectionViewSet(ModelViewSet):
|
||||||
"""ServiceConnection Viewset"""
|
"""ServiceConnection Viewset"""
|
||||||
|
|
||||||
queryset = OutpostServiceConnection.objects.all()
|
queryset = OutpostServiceConnection.objects.select_subclasses()
|
||||||
serializer_class = ServiceConnectionSerializer
|
serializer_class = ServiceConnectionSerializer
|
||||||
|
|
||||||
|
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||||
|
@action(detail=False)
|
||||||
|
def types(self, request: Request) -> Response:
|
||||||
|
"""Get all creatable service connection types"""
|
||||||
|
data = []
|
||||||
|
for subclass in all_subclasses(self.queryset.model):
|
||||||
|
data.append(
|
||||||
|
{
|
||||||
|
"name": verbose_name(subclass),
|
||||||
|
"description": subclass.__doc__,
|
||||||
|
"link": reverse("authentik_admin:outpost-service-connection-create")
|
||||||
|
+ f"?type={subclass.__name__}",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return Response(TypeCreateSerializer(data, many=True).data)
|
||||||
|
|
||||||
class DockerServiceConnectionSerializer(ModelSerializer):
|
@swagger_auto_schema(responses={200: ServiceConnectionStateSerializer(many=False)})
|
||||||
|
@action(detail=True)
|
||||||
|
# pylint: disable=unused-argument, invalid-name
|
||||||
|
def state(self, request: Request, pk: str) -> Response:
|
||||||
|
"""Get the service connection's state"""
|
||||||
|
connection = self.get_object()
|
||||||
|
return Response(asdict(connection.state))
|
||||||
|
|
||||||
|
|
||||||
|
class DockerServiceConnectionSerializer(ServiceConnectionSerializer):
|
||||||
"""DockerServiceConnection Serializer"""
|
"""DockerServiceConnection Serializer"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
model = DockerServiceConnection
|
model = DockerServiceConnection
|
||||||
fields = [
|
fields = ServiceConnectionSerializer.Meta.fields + [
|
||||||
"pk",
|
|
||||||
"name",
|
|
||||||
"local",
|
|
||||||
"url",
|
"url",
|
||||||
"tls_verification",
|
"tls_verification",
|
||||||
"tls_authentication",
|
"tls_authentication",
|
||||||
|
@ -48,13 +107,13 @@ class DockerServiceConnectionViewSet(ModelViewSet):
|
||||||
serializer_class = DockerServiceConnectionSerializer
|
serializer_class = DockerServiceConnectionSerializer
|
||||||
|
|
||||||
|
|
||||||
class KubernetesServiceConnectionSerializer(ModelSerializer):
|
class KubernetesServiceConnectionSerializer(ServiceConnectionSerializer):
|
||||||
"""KubernetesServiceConnection Serializer"""
|
"""KubernetesServiceConnection Serializer"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
model = KubernetesServiceConnection
|
model = KubernetesServiceConnection
|
||||||
fields = ["pk", "name", "local", "kubeconfig"]
|
fields = ServiceConnectionSerializer.Meta.fields + ["kubeconfig"]
|
||||||
|
|
||||||
|
|
||||||
class KubernetesServiceConnectionViewSet(ModelViewSet):
|
class KubernetesServiceConnectionViewSet(ModelViewSet):
|
||||||
|
|
147
swagger.yaml
147
swagger.yaml
|
@ -2169,6 +2169,42 @@ paths:
|
||||||
tags:
|
tags:
|
||||||
- outposts
|
- outposts
|
||||||
parameters: []
|
parameters: []
|
||||||
|
/outposts/service_connections/all/types/:
|
||||||
|
get:
|
||||||
|
operationId: outposts_service_connections_all_types
|
||||||
|
description: Get all creatable service connection types
|
||||||
|
parameters:
|
||||||
|
- name: ordering
|
||||||
|
in: query
|
||||||
|
description: Which field to use when ordering the results.
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
- name: search
|
||||||
|
in: query
|
||||||
|
description: A search term.
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
- name: page
|
||||||
|
in: query
|
||||||
|
description: A page number within the paginated result set.
|
||||||
|
required: false
|
||||||
|
type: integer
|
||||||
|
- name: page_size
|
||||||
|
in: query
|
||||||
|
description: Number of results to return per page.
|
||||||
|
required: false
|
||||||
|
type: integer
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Types of an object that can be created
|
||||||
|
schema:
|
||||||
|
description: ''
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/TypeCreate'
|
||||||
|
tags:
|
||||||
|
- outposts
|
||||||
|
parameters: []
|
||||||
/outposts/service_connections/all/{uuid}/:
|
/outposts/service_connections/all/{uuid}/:
|
||||||
get:
|
get:
|
||||||
operationId: outposts_service_connections_all_read
|
operationId: outposts_service_connections_all_read
|
||||||
|
@ -2229,6 +2265,25 @@ paths:
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
|
/outposts/service_connections/all/{uuid}/state/:
|
||||||
|
get:
|
||||||
|
operationId: outposts_service_connections_all_state
|
||||||
|
description: Get the service connection's state
|
||||||
|
parameters: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Serializer for Service connection state
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ServiceConnectionState'
|
||||||
|
tags:
|
||||||
|
- outposts
|
||||||
|
parameters:
|
||||||
|
- name: uuid
|
||||||
|
in: path
|
||||||
|
description: A UUID string identifying this Outpost Service-Connection.
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
/outposts/service_connections/docker/:
|
/outposts/service_connections/docker/:
|
||||||
get:
|
get:
|
||||||
operationId: outposts_service_connections_docker_list
|
operationId: outposts_service_connections_docker_list
|
||||||
|
@ -8797,6 +8852,55 @@ definitions:
|
||||||
title: Name
|
title: Name
|
||||||
type: string
|
type: string
|
||||||
minLength: 1
|
minLength: 1
|
||||||
|
local:
|
||||||
|
title: Local
|
||||||
|
description: If enabled, use the local connection. Required Docker socket/Kubernetes
|
||||||
|
Integration
|
||||||
|
type: boolean
|
||||||
|
object_type:
|
||||||
|
title: Object type
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
verbose_name:
|
||||||
|
title: Verbose name
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
verbose_name_plural:
|
||||||
|
title: Verbose name plural
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
TypeCreate:
|
||||||
|
description: Types of an object that can be created
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
title: Name
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
minLength: 1
|
||||||
|
description:
|
||||||
|
title: Description
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
minLength: 1
|
||||||
|
link:
|
||||||
|
title: Link
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
minLength: 1
|
||||||
|
ServiceConnectionState:
|
||||||
|
description: Serializer for Service connection state
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
healthy:
|
||||||
|
title: Healthy
|
||||||
|
type: boolean
|
||||||
|
readOnly: true
|
||||||
|
version:
|
||||||
|
title: Version
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
minLength: 1
|
||||||
DockerServiceConnection:
|
DockerServiceConnection:
|
||||||
description: DockerServiceConnection Serializer
|
description: DockerServiceConnection Serializer
|
||||||
required:
|
required:
|
||||||
|
@ -8818,6 +8922,18 @@ 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
|
||||||
|
object_type:
|
||||||
|
title: Object type
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
verbose_name:
|
||||||
|
title: Verbose name
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
verbose_name_plural:
|
||||||
|
title: Verbose name plural
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
url:
|
url:
|
||||||
title: Url
|
title: Url
|
||||||
description: Can be in the format of 'unix://<path>' when connecting to a
|
description: Can be in the format of 'unix://<path>' when connecting to a
|
||||||
|
@ -8859,6 +8975,18 @@ 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
|
||||||
|
object_type:
|
||||||
|
title: Object type
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
verbose_name:
|
||||||
|
title: Verbose name
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
verbose_name_plural:
|
||||||
|
title: Verbose name plural
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
kubeconfig:
|
kubeconfig:
|
||||||
title: Kubeconfig
|
title: Kubeconfig
|
||||||
description: Paste your kubeconfig here. authentik will automatically use
|
description: Paste your kubeconfig here. authentik will automatically use
|
||||||
|
@ -8898,25 +9026,6 @@ definitions:
|
||||||
title: Bound to
|
title: Bound to
|
||||||
type: integer
|
type: integer
|
||||||
readOnly: true
|
readOnly: true
|
||||||
TypeCreate:
|
|
||||||
description: Types of an object that can be created
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
name:
|
|
||||||
title: Name
|
|
||||||
type: string
|
|
||||||
readOnly: true
|
|
||||||
minLength: 1
|
|
||||||
description:
|
|
||||||
title: Description
|
|
||||||
type: string
|
|
||||||
readOnly: true
|
|
||||||
minLength: 1
|
|
||||||
link:
|
|
||||||
title: Link
|
|
||||||
type: string
|
|
||||||
readOnly: true
|
|
||||||
minLength: 1
|
|
||||||
PolicyBinding:
|
PolicyBinding:
|
||||||
description: PolicyBinding Serializer
|
description: PolicyBinding Serializer
|
||||||
required:
|
required:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { DefaultClient, AKResponse, QueryArguments } from "./Client";
|
import { DefaultClient, AKResponse, QueryArguments } from "./Client";
|
||||||
import { Provider } from "./Providers";
|
import { Provider, TypeCreate } from "./Providers";
|
||||||
|
|
||||||
export interface OutpostHealth {
|
export interface OutpostHealth {
|
||||||
last_seen: number;
|
last_seen: number;
|
||||||
|
@ -38,3 +38,42 @@ export class Outpost {
|
||||||
return `/administration/outposts/${rest}`;
|
return `/administration/outposts/${rest}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OutpostServiceConnectionState {
|
||||||
|
version: string;
|
||||||
|
healthy: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class OutpostServiceConnection {
|
||||||
|
pk: string;
|
||||||
|
name: string;
|
||||||
|
local: boolean;
|
||||||
|
object_type: string;
|
||||||
|
verbose_name: string;
|
||||||
|
verbose_name_plural: string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
throw Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
static get(pk: string): Promise<OutpostServiceConnection> {
|
||||||
|
return DefaultClient.fetch<OutpostServiceConnection>(["outposts", "service_connections", "all", pk]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static list(filter?: QueryArguments): Promise<AKResponse<OutpostServiceConnection>> {
|
||||||
|
return DefaultClient.fetch<AKResponse<OutpostServiceConnection>>(["outposts", "service_connections", "all"], filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
static state(pk: string): Promise<OutpostServiceConnectionState> {
|
||||||
|
return DefaultClient.fetch<OutpostServiceConnectionState>(["outposts", "service_connections", "all", pk, "state"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getTypes(): Promise<TypeCreate[]> {
|
||||||
|
return DefaultClient.fetch<TypeCreate[]>(["outposts", "service_connections", "all", "types"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static adminUrl(rest: string): string {
|
||||||
|
return `/administration/outpost_service_connections/${rest}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [
|
||||||
),
|
),
|
||||||
new SidebarItem("Providers", "/providers"),
|
new SidebarItem("Providers", "/providers"),
|
||||||
new SidebarItem("Outposts", "/outposts"),
|
new SidebarItem("Outposts", "/outposts"),
|
||||||
new SidebarItem("Outpost Service Connections", "/administration/outpost_service_connections/"),
|
new SidebarItem("Outpost Service Connections", "/outpost-service-connections"),
|
||||||
).when((): Promise<boolean> => {
|
).when((): Promise<boolean> => {
|
||||||
return User.me().then(u => u.is_superuser);
|
return User.me().then(u => u.is_superuser);
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -7,6 +7,7 @@ import "../../elements/Tabs";
|
||||||
import "../../elements/AdminLoginsChart";
|
import "../../elements/AdminLoginsChart";
|
||||||
import "../../elements/buttons/ModalButton";
|
import "../../elements/buttons/ModalButton";
|
||||||
import "../../elements/buttons/SpinnerButton";
|
import "../../elements/buttons/SpinnerButton";
|
||||||
|
import "../../elements/buttons/Dropdown";
|
||||||
import "../../elements/policies/BoundPoliciesList";
|
import "../../elements/policies/BoundPoliciesList";
|
||||||
import { FlowStageBinding, Stage } from "../../api/Flows";
|
import { FlowStageBinding, Stage } from "../../api/Flows";
|
||||||
import { until } from "lit-html/directives/until";
|
import { until } from "lit-html/directives/until";
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
import { gettext } from "django";
|
||||||
|
import { customElement, property } from "lit-element";
|
||||||
|
import { html, TemplateResult } from "lit-html";
|
||||||
|
import { AKResponse } from "../../api/Client";
|
||||||
|
import { OutpostServiceConnection } from "../../api/Outposts";
|
||||||
|
import { TableColumn } from "../../elements/table/Table";
|
||||||
|
import { TablePage } from "../../elements/table/TablePage";
|
||||||
|
|
||||||
|
import "./OutpostHealth";
|
||||||
|
import "../../elements/buttons/SpinnerButton";
|
||||||
|
import "../../elements/buttons/ModalButton";
|
||||||
|
import "../../elements/buttons/Dropdown";
|
||||||
|
import { until } from "lit-html/directives/until";
|
||||||
|
|
||||||
|
@customElement("ak-outpost-service-connection-list")
|
||||||
|
export class OutpostServiceConnectionListPage extends TablePage<OutpostServiceConnection> {
|
||||||
|
pageTitle(): string {
|
||||||
|
return "Outpost Service-Connections";
|
||||||
|
}
|
||||||
|
pageDescription(): string | undefined {
|
||||||
|
return "Outpost Service-Connections define how authentik connects to external platforms to manage and deploy Outposts.";
|
||||||
|
}
|
||||||
|
pageIcon(): string {
|
||||||
|
return "pf-icon pf-icon-integration";
|
||||||
|
}
|
||||||
|
searchEnabled(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
apiEndpoint(page: number): Promise<AKResponse<OutpostServiceConnection>> {
|
||||||
|
return OutpostServiceConnection.list({
|
||||||
|
ordering: this.order,
|
||||||
|
page: page,
|
||||||
|
search: this.search || "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
columns(): TableColumn[] {
|
||||||
|
return [
|
||||||
|
new TableColumn("Name", "name"),
|
||||||
|
new TableColumn("Type"),
|
||||||
|
new TableColumn("Local", "local"),
|
||||||
|
new TableColumn("State"),
|
||||||
|
new TableColumn(""),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
@property()
|
||||||
|
order = "name";
|
||||||
|
|
||||||
|
row(item: OutpostServiceConnection): TemplateResult[] {
|
||||||
|
return [
|
||||||
|
html`${item.name}`,
|
||||||
|
html`${item.verbose_name}`,
|
||||||
|
html`${item.local ? "Yes" : "No"}`,
|
||||||
|
html`${until(OutpostServiceConnection.state(item.pk).then((state) => {
|
||||||
|
if (state.healthy) {
|
||||||
|
return html`<i class="fas fa-check pf-m-success"></i> ${state.version}`;
|
||||||
|
}
|
||||||
|
return html`<i class="fas fa-times pf-m-danger"></i> ${gettext("Unhealthy")}`;
|
||||||
|
}), html`<ak-spinner></ak-spinner>`)}`,
|
||||||
|
html`
|
||||||
|
<ak-modal-button href="${OutpostServiceConnection.adminUrl(`${item.pk}/update/`)}">
|
||||||
|
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
||||||
|
${gettext("Edit")}
|
||||||
|
</ak-spinner-button>
|
||||||
|
<div slot="modal"></div>
|
||||||
|
</ak-modal-button>
|
||||||
|
<ak-modal-button href="${OutpostServiceConnection.adminUrl(`${item.pk}/delete/`)}">
|
||||||
|
<ak-spinner-button slot="trigger" class="pf-m-danger">
|
||||||
|
${gettext("Delete")}
|
||||||
|
</ak-spinner-button>
|
||||||
|
<div slot="modal"></div>
|
||||||
|
</ak-modal-button>`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
renderToolbar(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<ak-dropdown class="pf-c-dropdown">
|
||||||
|
<button class="pf-m-primary pf-c-dropdown__toggle" type="button">
|
||||||
|
<span class="pf-c-dropdown__toggle-text">${gettext("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>
|
||||||
|
${until(OutpostServiceConnection.getTypes().then((types) => {
|
||||||
|
return types.map((type) => {
|
||||||
|
return html`<li>
|
||||||
|
<ak-modal-button href="${type.link}">
|
||||||
|
<button slot="trigger" class="pf-c-dropdown__menu-item">${type.name}<br>
|
||||||
|
<small>${type.description}</small>
|
||||||
|
</button>
|
||||||
|
<div slot="modal"></div>
|
||||||
|
</ak-modal-button>
|
||||||
|
</li>`;
|
||||||
|
});
|
||||||
|
}), html`<ak-spinner></ak-spinner>`)}
|
||||||
|
</ul>
|
||||||
|
</ak-dropdown>
|
||||||
|
${super.renderToolbar()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -54,7 +54,7 @@ export class PolicyListPage extends TablePage<Policy> {
|
||||||
${gettext(`Assigned to ${item.bound_to} objects.`)}
|
${gettext(`Assigned to ${item.bound_to} objects.`)}
|
||||||
</small>`:
|
</small>`:
|
||||||
html`<i class="pf-icon pf-icon-warning-triangle"></i>
|
html`<i class="pf-icon pf-icon-warning-triangle"></i>
|
||||||
<small>${gettext("Warning: Policy is not assigned.")}/small>`}
|
<small>${gettext("Warning: Policy is not assigned.")}</small>`}
|
||||||
</div>`,
|
</div>`,
|
||||||
html`${item.verbose_name}`,
|
html`${item.verbose_name}`,
|
||||||
html`
|
html`
|
||||||
|
|
|
@ -13,6 +13,7 @@ import "./pages/flows/FlowListPage";
|
||||||
import "./pages/flows/FlowViewPage";
|
import "./pages/flows/FlowViewPage";
|
||||||
import "./pages/LibraryPage";
|
import "./pages/LibraryPage";
|
||||||
import "./pages/outposts/OutpostListPage";
|
import "./pages/outposts/OutpostListPage";
|
||||||
|
import "./pages/outposts/OutpostServiceConnectionListPage";
|
||||||
import "./pages/policies/PolicyListPage";
|
import "./pages/policies/PolicyListPage";
|
||||||
import "./pages/property-mappings/PropertyMappingListPage";
|
import "./pages/property-mappings/PropertyMappingListPage";
|
||||||
import "./pages/providers/ProviderListPage";
|
import "./pages/providers/ProviderListPage";
|
||||||
|
@ -53,5 +54,6 @@ export const ROUTES: Route[] = [
|
||||||
new Route(new RegExp("^/events/rules$"), html`<ak-event-rule-list></ak-event-rule-list>`),
|
new Route(new RegExp("^/events/rules$"), html`<ak-event-rule-list></ak-event-rule-list>`),
|
||||||
new Route(new RegExp("^/property-mappings$"), html`<ak-property-mapping-list></ak-property-mapping-list>`),
|
new Route(new RegExp("^/property-mappings$"), html`<ak-property-mapping-list></ak-property-mapping-list>`),
|
||||||
new Route(new RegExp("^/outposts$"), html`<ak-outpost-list></ak-outpost-list>`),
|
new Route(new RegExp("^/outposts$"), html`<ak-outpost-list></ak-outpost-list>`),
|
||||||
|
new Route(new RegExp("^/outpost-service-connections$"), html`<ak-outpost-service-connection-list></ak-outpost-service-connection-list>`),
|
||||||
new Route(new RegExp("^/crypto/certificates$"), html`<ak-crypto-certificatekeypair-list></ak-crypto-certificatekeypair-list>`),
|
new Route(new RegExp("^/crypto/certificates$"), html`<ak-crypto-certificatekeypair-list></ak-crypto-certificatekeypair-list>`),
|
||||||
];
|
];
|
||||||
|
|
Reference in New Issue