flows: add API to clear cache

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-03-23 10:37:41 +01:00
parent b6d797fc78
commit 6961089425
8 changed files with 76 additions and 89 deletions

View File

@ -1,20 +0,0 @@
{% extends base_template|default:"generic/form.html" %}
{% load authentik_utils %}
{% load i18n %}
{% block above_form %}
<h1>
{% trans form.title %}
</h1>
{% endblock %}
{% block beneath_form %}
<p>
{% trans form.body %}
</p>
{% endblock %}
{% block action %}
{% trans 'Confirm' %}
{% endblock %}

View File

@ -10,7 +10,6 @@ from authentik.admin.views import (
groups, groups,
outposts, outposts,
outposts_service_connections, outposts_service_connections,
overview,
policies, policies,
policies_bindings, policies_bindings,
property_mappings, property_mappings,
@ -25,16 +24,6 @@ from authentik.admin.views import (
from authentik.providers.saml.views.metadata import MetadataImportView from authentik.providers.saml.views.metadata import MetadataImportView
urlpatterns = [ urlpatterns = [
path(
"overview/cache/flow/",
overview.FlowCacheClearView.as_view(),
name="overview-clear-flow-cache",
),
path(
"overview/cache/policy/",
overview.PolicyCacheClearView.as_view(),
name="overview-clear-policy-cache",
),
# Applications # Applications
path( path(
"applications/create/", "applications/create/",

View File

@ -1,47 +0,0 @@
"""authentik administration overview"""
from django.contrib.messages.views import SuccessMessageMixin
from django.core.cache import cache
from django.http.request import HttpRequest
from django.http.response import HttpResponse
from django.utils.translation import gettext as _
from django.views.generic import FormView
from structlog.stdlib import get_logger
from authentik.admin.forms.overview import FlowCacheClearForm, PolicyCacheClearForm
from authentik.admin.mixins import AdminRequiredMixin
from authentik.core.api.applications import user_app_cache_key
LOGGER = get_logger()
class PolicyCacheClearView(AdminRequiredMixin, SuccessMessageMixin, FormView):
"""View to clear Policy cache"""
form_class = PolicyCacheClearForm
success_url = "/"
template_name = "generic/form_non_model.html"
success_message = _("Successfully cleared Policy cache")
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
keys = cache.keys("policy_*")
cache.delete_many(keys)
LOGGER.debug("Cleared Policy cache", keys=len(keys))
# Also delete user application cache
keys = cache.keys(user_app_cache_key("*"))
cache.delete_many(keys)
return super().post(request, *args, **kwargs)
class FlowCacheClearView(AdminRequiredMixin, SuccessMessageMixin, FormView):
"""View to clear Flow cache"""
form_class = FlowCacheClearForm
success_url = "/"
template_name = "generic/form_non_model.html"
success_message = _("Successfully cleared Flow cache")
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
keys = cache.keys("flow_*")
cache.delete_many(keys)
LOGGER.debug("Cleared flow cache", keys=len(keys))
return super().post(request, *args, **kwargs)

View File

@ -3,10 +3,10 @@ from dataclasses import dataclass
from django.core.cache import cache from django.core.cache import cache
from django.db.models import Model from django.db.models import Model
from django.http.response import JsonResponse from django.http.response import HttpResponseBadRequest, JsonResponse
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from drf_yasg2 import openapi from drf_yasg2 import openapi
from drf_yasg2.utils import swagger_auto_schema from drf_yasg2.utils import no_body, swagger_auto_schema, unset
from guardian.shortcuts import get_objects_for_user from guardian.shortcuts import get_objects_for_user
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.exceptions import PermissionDenied from rest_framework.exceptions import PermissionDenied
@ -19,6 +19,7 @@ from rest_framework.serializers import (
SerializerMethodField, SerializerMethodField,
) )
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from structlog.stdlib import get_logger
from authentik.core.api.utils import CacheSerializer from authentik.core.api.utils import CacheSerializer
from authentik.flows.models import Flow from authentik.flows.models import Flow
@ -26,6 +27,8 @@ from authentik.flows.planner import cache_key
from authentik.flows.transfer.common import DataclassEncoder from authentik.flows.transfer.common import DataclassEncoder
from authentik.flows.transfer.exporter import FlowExporter from authentik.flows.transfer.exporter import FlowExporter
LOGGER = get_logger()
class FlowSerializer(ModelSerializer): class FlowSerializer(ModelSerializer):
"""Flow Serializer""" """Flow Serializer"""
@ -88,10 +91,24 @@ class FlowViewSet(ModelViewSet):
@swagger_auto_schema(responses={200: CacheSerializer(many=False)}) @swagger_auto_schema(responses={200: CacheSerializer(many=False)})
@action(detail=False) @action(detail=False)
def cached(self, request: Request) -> Response: def cache_info(self, request: Request) -> Response:
"""Info about cached flows""" """Info about cached flows"""
return Response(data={"count": len(cache.keys("flow_*"))}) return Response(data={"count": len(cache.keys("flow_*"))})
@swagger_auto_schema(
request_body=no_body,
responses={204: "Successfully cleared cache", 400: "Bad request"},
)
@action(detail=False, methods=["POST"])
def cache_clear(self, request: Request) -> Response:
"""Clear flow cache"""
if not request.user.is_superuser:
return HttpResponseBadRequest()
keys = cache.keys("flow_*")
cache.delete_many(keys)
LOGGER.debug("Cleared flow cache", keys=len(keys))
return Response(status=204)
@swagger_auto_schema( @swagger_auto_schema(
responses={ responses={
"200": openapi.Response( "200": openapi.Response(

View File

@ -1,8 +1,9 @@
"""policy API Views""" """policy API Views"""
from django.core.cache import cache from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.http.response import HttpResponseBadRequest
from django.urls import reverse from django.urls import reverse
from drf_yasg2.utils import swagger_auto_schema from drf_yasg2.utils import no_body, swagger_auto_schema
from rest_framework import mixins from rest_framework import mixins
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.request import Request from rest_framework.request import Request
@ -13,7 +14,9 @@ from rest_framework.serializers import (
SerializerMethodField, SerializerMethodField,
) )
from rest_framework.viewsets import GenericViewSet, ModelViewSet from rest_framework.viewsets import GenericViewSet, ModelViewSet
from structlog.stdlib import get_logger
from authentik.core.api.applications import user_app_cache_key
from authentik.core.api.utils import ( from authentik.core.api.utils import (
CacheSerializer, CacheSerializer,
MetaNameSerializer, MetaNameSerializer,
@ -23,6 +26,8 @@ from authentik.lib.templatetags.authentik_utils import verbose_name
from authentik.lib.utils.reflection import all_subclasses from authentik.lib.utils.reflection import all_subclasses
from authentik.policies.models import Policy, PolicyBinding, PolicyBindingModel from authentik.policies.models import Policy, PolicyBinding, PolicyBindingModel
LOGGER = get_logger()
class PolicyBindingModelForeignKey(PrimaryKeyRelatedField): class PolicyBindingModelForeignKey(PrimaryKeyRelatedField):
"""rest_framework PrimaryKeyRelatedField which resolves """rest_framework PrimaryKeyRelatedField which resolves
@ -139,10 +144,27 @@ class PolicyViewSet(
@swagger_auto_schema(responses={200: CacheSerializer(many=False)}) @swagger_auto_schema(responses={200: CacheSerializer(many=False)})
@action(detail=False) @action(detail=False)
def cached(self, request: Request) -> Response: def cache_info(self, request: Request) -> Response:
"""Info about cached policies""" """Info about cached policies"""
return Response(data={"count": len(cache.keys("policy_*"))}) return Response(data={"count": len(cache.keys("policy_*"))})
@swagger_auto_schema(
request_body=no_body,
responses={204: "Successfully cleared cache", 400: "Bad request"},
)
@action(detail=False, methods=["POST"])
def cache_clear(self, request: Request) -> Response:
"""Clear policy cache"""
if not request.user.is_superuser:
return HttpResponseBadRequest()
keys = cache.keys("policy_*")
cache.delete_many(keys)
LOGGER.debug("Cleared Policy cache", keys=len(keys))
# Also delete user application cache
keys = cache.keys(user_app_cache_key("*"))
cache.delete_many(keys)
return Response(status=204)
class PolicyBindingSerializer(ModelSerializer): class PolicyBindingSerializer(ModelSerializer):
"""PolicyBinding Serializer""" """PolicyBinding Serializer"""

View File

@ -2878,9 +2878,22 @@ paths:
tags: tags:
- flows - flows
parameters: [] parameters: []
/flows/instances/cached/: /flows/instances/cache_clear/:
post:
operationId: flows_instances_cache_clear
description: Clear flow cache
parameters: []
responses:
'204':
description: Successfully cleared cache
'400':
description: Bad request
tags:
- flows
parameters: []
/flows/instances/cache_info/:
get: get:
operationId: flows_instances_cached operationId: flows_instances_cache_info
description: Info about cached flows description: Info about cached flows
parameters: parameters:
- name: flow_uuid - name: flow_uuid
@ -4116,9 +4129,22 @@ paths:
tags: tags:
- policies - policies
parameters: [] parameters: []
/policies/all/cached/: /policies/all/cache_clear/:
post:
operationId: policies_all_cache_clear
description: Clear policy cache
parameters: []
responses:
'204':
description: Successfully cleared cache
'400':
description: Bad request
tags:
- policies
parameters: []
/policies/all/cache_info/:
get: get:
operationId: policies_all_cached operationId: policies_all_cache_info
description: Info about cached policies description: Info about cached policies
parameters: parameters:
- name: bindings__isnull - name: bindings__isnull

View File

@ -9,7 +9,7 @@ import { DEFAULT_CONFIG } from "../../../api/Config";
export class FlowCacheStatusCard extends AdminStatusCard<number> { export class FlowCacheStatusCard extends AdminStatusCard<number> {
getPrimaryValue(): Promise<number> { getPrimaryValue(): Promise<number> {
return new FlowsApi(DEFAULT_CONFIG).flowsInstancesCached({}).then((value) => { return new FlowsApi(DEFAULT_CONFIG).flowsInstancesCacheInfo({}).then((value) => {
return value.count || 0; return value.count || 0;
}); });
} }

View File

@ -10,7 +10,7 @@ import { DEFAULT_CONFIG } from "../../../api/Config";
export class PolicyCacheStatusCard extends AdminStatusCard<number> { export class PolicyCacheStatusCard extends AdminStatusCard<number> {
getPrimaryValue(): Promise<number> { getPrimaryValue(): Promise<number> {
return new PoliciesApi(DEFAULT_CONFIG).policiesAllCached({}).then((value) => { return new PoliciesApi(DEFAULT_CONFIG).policiesAllCacheInfo({}).then((value) => {
return value.count || 0; return value.count || 0;
}); });
} }