show cache on admin overview, add modal to clear cache, re-add logging to policy

This commit is contained in:
Jens Langhammer 2019-04-29 20:37:44 +02:00
parent f576985cc9
commit e0d597eeac
4 changed files with 79 additions and 15 deletions

View file

@ -152,10 +152,8 @@
<div class="col-xs-6 col-sm-2 col-md-2"> <div class="col-xs-6 col-sm-2 col-md-2">
<div class="card-pf card-pf-accented card-pf-aggregate-status"> <div class="card-pf card-pf-accented card-pf-aggregate-status">
<h2 class="card-pf-title"> <h2 class="card-pf-title">
<a href="#">
<span class="pficon-bundle"></span> <span class="pficon-bundle"></span>
<span class="card-pf-aggregate-status-count"></span> {% trans 'Version' %} <span class="card-pf-aggregate-status-count"></span> {% trans 'Version' %}
</a>
</h2> </h2>
<div class="card-pf-body"> <div class="card-pf-body">
<p class="card-pf-aggregate-status-notifications"> <p class="card-pf-aggregate-status-notifications">
@ -192,5 +190,59 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-xs-6 col-sm-2 col-md-2">
<div class="card-pf card-pf-accented card-pf-aggregate-status">
<h2 class="card-pf-title">
<span class="pficon-server"></span>
<span class="card-pf-aggregate-status-count"></span> {% trans 'Cached Policies' %}
</h2>
<div class="card-pf-body">
<p class="card-pf-aggregate-status-notifications">
<span class="card-pf-aggregate-status-notification">
<a href="#" data-toggle="modal" data-target="#clearCacheMOdal">
{% if cached_policies < 1 %}
<span class="pficon-warning-triangle-o" data-toggle="tooltip" data-placement="right"
title="{% trans 'No policies cached. Users may experience slow response times.' %}"></span> {{ cached_policies }}
{% else %}
<span class="pficon pficon-ok"></span>{{ cached_policies }}
{% endif %}
</a>
</span>
</p>
</div>
</div>
</div>
</div>
<div class="modal fade" id="clearCacheMOdal" tabindex="-1" role="dialog" aria-labelledby="clearCacheMOdalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">
<span class="pficon pficon-close"></span>
</button>
<h4 class="modal-title" id="clearCacheMOdalLabel">{% trans 'Clear Cache' %}</h4>
</div>
<div class="modal-body">
<form method="post" id="clearForm">
{% csrf_token %}
<input type="hidden" name="clear">
<p>
{% blocktrans %}
Are you sure you want to clear the cache? This includes all user sessions and all cached Policy results.
{% endblocktrans %}
</p>
<h3>
{% blocktrans %}
This will also log you out.
{% endblocktrans %}
</h3>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button form="clearForm" type="submit" type="button" class="btn btn-danger">{% trans 'Clear' %}</button>
</div>
</div>
</div>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -1,4 +1,6 @@
"""passbook administration overview""" """passbook administration overview"""
from django.core.cache import cache
from django.shortcuts import redirect, reverse
from django.views.generic import TemplateView from django.views.generic import TemplateView
from passbook.admin.mixins import AdminRequiredMixin from passbook.admin.mixins import AdminRequiredMixin
@ -13,6 +15,12 @@ class AdministrationOverviewView(AdminRequiredMixin, TemplateView):
template_name = 'administration/overview.html' template_name = 'administration/overview.html'
def post(self, *args, **kwargs):
if 'clear' in self.request.POST:
cache.clear()
return redirect(reverse('passbook_core:auth-login'))
return self.get(*args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
kwargs['application_count'] = len(Application.objects.all()) kwargs['application_count'] = len(Application.objects.all())
kwargs['policy_count'] = len(Policy.objects.all()) kwargs['policy_count'] = len(Policy.objects.all())
@ -25,4 +33,6 @@ class AdministrationOverviewView(AdminRequiredMixin, TemplateView):
kwargs['worker_count'] = len(CELERY_APP.control.ping(timeout=0.5)) kwargs['worker_count'] = len(CELERY_APP.control.ping(timeout=0.5))
kwargs['providers_without_application'] = Provider.objects.filter(application=None) kwargs['providers_without_application'] = Provider.objects.filter(application=None)
kwargs['policies_without_attachment'] = len(Policy.objects.filter(policymodel__isnull=True)) kwargs['policies_without_attachment'] = len(Policy.objects.filter(policymodel__isnull=True))
kwargs['cached_policies'] = len(cache.keys('policy_*'))
print(cache.keys('*'))
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)

View file

@ -1,5 +1,6 @@
"""passbook core policy engine""" """passbook core policy engine"""
# from logging import getLogger from logging import getLogger
from amqp.exceptions import UnexpectedFrame from amqp.exceptions import UnexpectedFrame
from celery import group from celery import group
from celery.exceptions import TimeoutError as CeleryTimeoutError from celery.exceptions import TimeoutError as CeleryTimeoutError
@ -9,10 +10,10 @@ from ipware import get_client_ip
from passbook.core.celery import CELERY_APP from passbook.core.celery import CELERY_APP
from passbook.core.models import Policy, User from passbook.core.models import Policy, User
# LOGGER = getLogger(__name__) LOGGER = getLogger(__name__)
def _cache_key(policy, user): def _cache_key(policy, user):
return "%s#%s" % (policy.uuid, user.pk) return "policy_%s#%s" % (policy.uuid, user.pk)
@CELERY_APP.task() @CELERY_APP.task()
def _policy_engine_task(user_pk, policy_pk, **kwargs): def _policy_engine_task(user_pk, policy_pk, **kwargs):
@ -23,8 +24,8 @@ def _policy_engine_task(user_pk, policy_pk, **kwargs):
user_obj = User.objects.get(pk=user_pk) user_obj = User.objects.get(pk=user_pk)
for key, value in kwargs.items(): for key, value in kwargs.items():
setattr(user_obj, key, value) setattr(user_obj, key, value)
# LOGGER.debug("Running policy `%s`#%s for user %s...", policy_obj.name, LOGGER.debug("Running policy `%s`#%s for user %s...", policy_obj.name,
# policy_obj.pk.hex, user_obj) policy_obj.pk.hex, user_obj)
policy_result = policy_obj.passes(user_obj) policy_result = policy_obj.passes(user_obj)
# Handle policy result correctly if result, message or just result # Handle policy result correctly if result, message or just result
message = None message = None
@ -33,10 +34,10 @@ def _policy_engine_task(user_pk, policy_pk, **kwargs):
# Invert result if policy.negate is set # Invert result if policy.negate is set
if policy_obj.negate: if policy_obj.negate:
policy_result = not policy_result policy_result = not policy_result
# LOGGER.debug("Policy %r#%s got %s", policy_obj.name, policy_obj.pk.hex, policy_result) LOGGER.debug("Policy %r#%s got %s", policy_obj.name, policy_obj.pk.hex, policy_result)
cache_key = _cache_key(policy_obj, user_obj) cache_key = _cache_key(policy_obj, user_obj)
cache.set(cache_key, (policy_obj.action, policy_result, message)) cache.set(cache_key, (policy_obj.action, policy_result, message))
# LOGGER.debug("Cached entry as %s", cache_key) LOGGER.debug("Cached entry as %s", cache_key)
return policy_obj.action, policy_result, message return policy_obj.action, policy_result, message
class PolicyEngine: class PolicyEngine:
@ -81,16 +82,16 @@ class PolicyEngine:
for policy in self.policies: for policy in self.policies:
cached_policy = cache.get(_cache_key(policy, self.__user), None) cached_policy = cache.get(_cache_key(policy, self.__user), None)
if cached_policy: if cached_policy:
# LOGGER.debug("Taking result from cache for %s", policy.pk.hex) LOGGER.debug("Taking result from cache for %s", policy.pk.hex)
cached_policies.append(cached_policy) cached_policies.append(cached_policy)
else: else:
# LOGGER.debug("Evaluating policy %s", policy.pk.hex) LOGGER.debug("Evaluating policy %s", policy.pk.hex)
signatures.append(_policy_engine_task.signature( signatures.append(_policy_engine_task.signature(
args=(self.__user.pk, policy.pk.hex), args=(self.__user.pk, policy.pk.hex),
kwargs=kwargs, kwargs=kwargs,
time_limit=policy.timeout)) time_limit=policy.timeout))
self.__get_timeout += policy.timeout self.__get_timeout += policy.timeout
# LOGGER.debug("Set total policy timeout to %r", self.__get_timeout) LOGGER.debug("Set total policy timeout to %r", self.__get_timeout)
# If all policies are cached, we have an empty list here. # If all policies are cached, we have an empty list here.
if signatures: if signatures:
self.__group = group(signatures)() self.__group = group(signatures)()
@ -119,7 +120,7 @@ class PolicyEngine:
for policy_action, policy_result, policy_message in result: for policy_action, policy_result, policy_message in result:
passing = (policy_action == Policy.ACTION_ALLOW and policy_result) or \ passing = (policy_action == Policy.ACTION_ALLOW and policy_result) or \
(policy_action == Policy.ACTION_DENY and not policy_result) (policy_action == Policy.ACTION_DENY and not policy_result)
# LOGGER.debug('Action=%s, Result=%r => %r', policy_action, policy_result, passing) LOGGER.debug('Action=%s, Result=%r => %r', policy_action, policy_result, passing)
if policy_message: if policy_message:
messages.append(policy_message) messages.append(policy_message)
if not passing: if not passing:

View file

@ -2,6 +2,7 @@
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView from django.views.generic import TemplateView
from passbook.core.models import Application from passbook.core.models import Application
from passbook.core.policies import PolicyEngine from passbook.core.policies import PolicyEngine