|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
# Copyright 2010 - 2017 RhodeCode GmbH and the AppEnlight project authors
|
|
|
#
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
# You may obtain a copy of the License at
|
|
|
#
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
#
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
# See the License for the specific language governing permissions and
|
|
|
# limitations under the License.
|
|
|
|
|
|
import copy
|
|
|
import json
|
|
|
import logging
|
|
|
import six
|
|
|
|
|
|
from datetime import datetime, timedelta
|
|
|
|
|
|
import colander
|
|
|
from pyramid.httpexceptions import HTTPFound, HTTPUnprocessableEntity
|
|
|
from pyramid.view import view_config
|
|
|
from webob.multidict import MultiDict
|
|
|
from zope.sqlalchemy import mark_changed
|
|
|
from ziggurat_foundations.permissions import ANY_PERMISSION
|
|
|
|
|
|
import appenlight.forms as forms
|
|
|
from appenlight.models import DBSession
|
|
|
from appenlight.models.resource import Resource
|
|
|
from appenlight.models.application import Application
|
|
|
from appenlight.models.application_postprocess_conf import \
|
|
|
ApplicationPostprocessConf
|
|
|
from appenlight.models.user import User
|
|
|
from appenlight.models.user_resource_permission import UserResourcePermission
|
|
|
from appenlight.models.group_resource_permission import GroupResourcePermission
|
|
|
from appenlight.models.services.application import ApplicationService
|
|
|
from appenlight.models.services.application_postprocess_conf import \
|
|
|
ApplicationPostprocessConfService
|
|
|
from appenlight.models.services.group import GroupService
|
|
|
from appenlight.models.services.group_resource_permission import \
|
|
|
GroupResourcePermissionService
|
|
|
from appenlight.models.services.request_metric import RequestMetricService
|
|
|
from appenlight.models.services.report_group import ReportGroupService
|
|
|
from appenlight.models.services.slow_call import SlowCallService
|
|
|
from appenlight.lib import helpers as h
|
|
|
from appenlight.lib.utils import build_filter_settings_from_query_dict
|
|
|
from appenlight.security import RootFactory
|
|
|
from appenlight.models.report import REPORT_TYPE_MATRIX
|
|
|
from appenlight.validators import build_rule_schema
|
|
|
|
|
|
_ = str
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
def app_not_found(request, id):
|
|
|
"""
|
|
|
Redirects on non found and sets a flash message
|
|
|
"""
|
|
|
request.session.flash(_('Application not found'), 'warning')
|
|
|
return HTTPFound(
|
|
|
location=request.route_url('applications', action='index'))
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_no_id',
|
|
|
renderer='json', request_method="GET", permission='authenticated')
|
|
|
def applications_list(request):
|
|
|
"""
|
|
|
Applications list
|
|
|
|
|
|
if query params contain ?type=foo, it will list applications
|
|
|
with one of those permissions for user,
|
|
|
otherwise only list of owned applications will
|
|
|
be returned
|
|
|
|
|
|
appending ?root_list while being administration will allow to list all
|
|
|
applications in the system
|
|
|
|
|
|
"""
|
|
|
is_root = request.has_permission('root_administration',
|
|
|
RootFactory(request))
|
|
|
if is_root and request.GET.get('root_list'):
|
|
|
resources = Resource.all().order_by(Resource.resource_name)
|
|
|
resource_type = request.GET.get('resource_type', 'application')
|
|
|
if resource_type:
|
|
|
resources = resources.filter(
|
|
|
Resource.resource_type == resource_type)
|
|
|
else:
|
|
|
permissions = request.params.getall('permission')
|
|
|
if permissions:
|
|
|
resources = request.user.resources_with_perms(
|
|
|
permissions,
|
|
|
resource_types=[request.GET.get('resource_type',
|
|
|
'application')])
|
|
|
else:
|
|
|
resources = request.user.resources.filter(
|
|
|
Application.resource_type == request.GET.get(
|
|
|
'resource_type',
|
|
|
'application'))
|
|
|
return [r.get_dict(include_keys=['resource_id', 'resource_name', 'domains',
|
|
|
'owner_user_name', 'owner_group_name'])
|
|
|
for
|
|
|
r in resources]
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications', renderer='json',
|
|
|
request_method="GET", permission='view')
|
|
|
def application_GET(request):
|
|
|
resource = request.context.resource
|
|
|
include_sensitive_info = False
|
|
|
if request.has_permission('edit'):
|
|
|
include_sensitive_info = True
|
|
|
resource_dict = resource.get_dict(
|
|
|
include_perms=include_sensitive_info,
|
|
|
include_processing_rules=include_sensitive_info)
|
|
|
return resource_dict
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_no_id', request_method="POST",
|
|
|
renderer='json', permission='create_resources')
|
|
|
def application_create(request):
|
|
|
"""
|
|
|
Creates new application instances
|
|
|
"""
|
|
|
user = request.user
|
|
|
form = forms.ApplicationCreateForm(MultiDict(request.unsafe_json_body),
|
|
|
csrf_context=request)
|
|
|
if form.validate():
|
|
|
session = DBSession()
|
|
|
resource = Application()
|
|
|
DBSession.add(resource)
|
|
|
form.populate_obj(resource)
|
|
|
resource.api_key = resource.generate_api_key()
|
|
|
user.resources.append(resource)
|
|
|
request.session.flash(_('Application created'))
|
|
|
DBSession.flush()
|
|
|
mark_changed(session)
|
|
|
else:
|
|
|
return HTTPUnprocessableEntity(body=form.errors_json)
|
|
|
|
|
|
return resource.get_dict()
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications', request_method="PATCH",
|
|
|
renderer='json', permission='edit')
|
|
|
def application_update(request):
|
|
|
"""
|
|
|
Updates main application configuration
|
|
|
"""
|
|
|
resource = request.context.resource
|
|
|
if not resource:
|
|
|
return app_not_found()
|
|
|
|
|
|
# disallow setting permanent storage by non-admins
|
|
|
# use default/non-resource based context for this check
|
|
|
req_dict = copy.copy(request.unsafe_json_body)
|
|
|
if not request.has_permission('root_administration', RootFactory(request)):
|
|
|
req_dict['allow_permanent_storage'] = ''
|
|
|
if not req_dict.get('uptime_url'):
|
|
|
# needed cause validator is still triggered by default
|
|
|
req_dict.pop('uptime_url', '')
|
|
|
application_form = forms.ApplicationUpdateForm(MultiDict(req_dict),
|
|
|
csrf_context=request)
|
|
|
if application_form.validate():
|
|
|
application_form.populate_obj(resource)
|
|
|
request.session.flash(_('Application updated'))
|
|
|
else:
|
|
|
return HTTPUnprocessableEntity(body=application_form.errors_json)
|
|
|
|
|
|
include_sensitive_info = False
|
|
|
if request.has_permission('edit'):
|
|
|
include_sensitive_info = True
|
|
|
resource_dict = resource.get_dict(
|
|
|
include_perms=include_sensitive_info,
|
|
|
include_processing_rules=include_sensitive_info)
|
|
|
return resource_dict
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property', match_param='key=api_key',
|
|
|
request_method="POST", renderer='json',
|
|
|
permission='delete')
|
|
|
def application_regenerate_key(request):
|
|
|
"""
|
|
|
Regenerates API keys for application
|
|
|
"""
|
|
|
resource = request.context.resource
|
|
|
|
|
|
form = forms.CheckPasswordForm(MultiDict(request.unsafe_json_body),
|
|
|
csrf_context=request)
|
|
|
form.password.user = request.user
|
|
|
|
|
|
if form.validate():
|
|
|
resource.api_key = resource.generate_api_key()
|
|
|
resource.public_key = resource.generate_api_key()
|
|
|
msg = 'API keys regenerated - please update your application config.'
|
|
|
request.session.flash(_(msg))
|
|
|
else:
|
|
|
return HTTPUnprocessableEntity(body=form.errors_json)
|
|
|
|
|
|
if request.has_permission('edit'):
|
|
|
include_sensitive_info = True
|
|
|
resource_dict = resource.get_dict(
|
|
|
include_perms=include_sensitive_info,
|
|
|
include_processing_rules=include_sensitive_info)
|
|
|
return resource_dict
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property',
|
|
|
match_param='key=delete_resource',
|
|
|
request_method="PATCH", renderer='json', permission='delete')
|
|
|
def application_remove(request):
|
|
|
"""
|
|
|
Removes application resources
|
|
|
"""
|
|
|
resource = request.context.resource
|
|
|
# we need polymorphic object here, to properly launch sqlalchemy events
|
|
|
resource = ApplicationService.by_id(resource.resource_id)
|
|
|
form = forms.CheckPasswordForm(MultiDict(request.safe_json_body or {}),
|
|
|
csrf_context=request)
|
|
|
form.password.user = request.user
|
|
|
if form.validate():
|
|
|
DBSession.delete(resource)
|
|
|
request.session.flash(_('Application removed'))
|
|
|
else:
|
|
|
return HTTPUnprocessableEntity(body=form.errors_json)
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property', match_param='key=owner',
|
|
|
request_method="PATCH", renderer='json', permission='delete')
|
|
|
def application_ownership_transfer(request):
|
|
|
"""
|
|
|
Allows application owner to transfer application ownership to other user
|
|
|
"""
|
|
|
resource = request.context.resource
|
|
|
form = forms.ChangeApplicationOwnerForm(
|
|
|
MultiDict(request.safe_json_body or {}), csrf_context=request)
|
|
|
form.password.user = request.user
|
|
|
if form.validate():
|
|
|
user = User.by_user_name(form.user_name.data)
|
|
|
user.resources.append(resource)
|
|
|
# remove integrations to not leak security data of external applications
|
|
|
for integration in resource.integrations[:]:
|
|
|
resource.integrations.remove(integration)
|
|
|
request.session.flash(_('Application transfered'))
|
|
|
else:
|
|
|
return HTTPUnprocessableEntity(body=form.errors_json)
|
|
|
return True
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property',
|
|
|
match_param='key=postprocessing_rules', renderer='json',
|
|
|
request_method='POST', permission='edit')
|
|
|
def applications_postprocess_POST(request):
|
|
|
"""
|
|
|
Creates new postprocessing rules for applications
|
|
|
"""
|
|
|
resource = request.context.resource
|
|
|
conf = ApplicationPostprocessConf()
|
|
|
conf.do = 'postprocess'
|
|
|
conf.new_value = '1'
|
|
|
resource.postprocess_conf.append(conf)
|
|
|
DBSession.flush()
|
|
|
return conf.get_dict()
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property',
|
|
|
match_param='key=postprocessing_rules', renderer='json',
|
|
|
request_method='PATCH', permission='edit')
|
|
|
def applications_postprocess_PATCH(request):
|
|
|
"""
|
|
|
Creates new postprocessing rules for applications
|
|
|
"""
|
|
|
json_body = request.unsafe_json_body
|
|
|
|
|
|
schema = build_rule_schema(json_body['rule'], REPORT_TYPE_MATRIX)
|
|
|
try:
|
|
|
schema.deserialize(json_body['rule'])
|
|
|
except colander.Invalid as exc:
|
|
|
return HTTPUnprocessableEntity(body=json.dumps(exc.asdict()))
|
|
|
|
|
|
resource = request.context.resource
|
|
|
conf = ApplicationPostprocessConfService.by_pkey_and_resource_id(
|
|
|
json_body['pkey'], resource.resource_id)
|
|
|
conf.rule = request.unsafe_json_body['rule']
|
|
|
# for now hardcode int since we dont support anything else so far
|
|
|
conf.new_value = int(request.unsafe_json_body['new_value'])
|
|
|
return conf.get_dict()
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property',
|
|
|
match_param='key=postprocessing_rules', renderer='json',
|
|
|
request_method='DELETE', permission='edit')
|
|
|
def applications_postprocess_DELETE(request):
|
|
|
"""
|
|
|
Removes application postprocessing rules
|
|
|
"""
|
|
|
form = forms.ReactorForm(request.POST, csrf_context=request)
|
|
|
resource = request.context.resource
|
|
|
if form.validate():
|
|
|
for postprocess_conf in resource.postprocess_conf:
|
|
|
if postprocess_conf.pkey == int(request.GET['pkey']):
|
|
|
# remove rule
|
|
|
DBSession.delete(postprocess_conf)
|
|
|
return True
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property',
|
|
|
match_param='key=report_graphs', renderer='json',
|
|
|
permission='view')
|
|
|
@view_config(route_name='applications_property',
|
|
|
match_param='key=slow_report_graphs', renderer='json',
|
|
|
permission='view')
|
|
|
def get_application_report_stats(request):
|
|
|
query_params = request.GET.mixed()
|
|
|
query_params['resource'] = (request.context.resource.resource_id,)
|
|
|
|
|
|
filter_settings = build_filter_settings_from_query_dict(request,
|
|
|
query_params)
|
|
|
if not filter_settings.get('end_date'):
|
|
|
end_date = datetime.utcnow().replace(microsecond=0, second=0)
|
|
|
filter_settings['end_date'] = end_date
|
|
|
|
|
|
if not filter_settings.get('start_date'):
|
|
|
delta = timedelta(hours=1)
|
|
|
filter_settings['start_date'] = filter_settings['end_date'] - delta
|
|
|
|
|
|
result = ReportGroupService.get_report_stats(request, filter_settings)
|
|
|
return result
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property',
|
|
|
match_param='key=metrics_graphs', renderer='json',
|
|
|
permission='view')
|
|
|
def metrics_graphs(request):
|
|
|
"""
|
|
|
Handles metric dashboard graphs
|
|
|
Returns information for time/tier breakdown
|
|
|
"""
|
|
|
query_params = request.GET.mixed()
|
|
|
query_params['resource'] = (request.context.resource.resource_id,)
|
|
|
|
|
|
filter_settings = build_filter_settings_from_query_dict(request,
|
|
|
query_params)
|
|
|
|
|
|
if not filter_settings.get('end_date'):
|
|
|
end_date = datetime.utcnow().replace(microsecond=0, second=0)
|
|
|
filter_settings['end_date'] = end_date
|
|
|
|
|
|
delta = timedelta(hours=1)
|
|
|
if not filter_settings.get('start_date'):
|
|
|
filter_settings['start_date'] = filter_settings['end_date'] - delta
|
|
|
if filter_settings['end_date'] <= filter_settings['start_date']:
|
|
|
filter_settings['end_date'] = filter_settings['start_date']
|
|
|
|
|
|
delta = filter_settings['end_date'] - filter_settings['start_date']
|
|
|
if delta < h.time_deltas.get('12h')['delta']:
|
|
|
divide_by_min = 1
|
|
|
elif delta <= h.time_deltas.get('3d')['delta']:
|
|
|
divide_by_min = 5.0
|
|
|
elif delta >= h.time_deltas.get('2w')['delta']:
|
|
|
divide_by_min = 60.0 * 24
|
|
|
else:
|
|
|
divide_by_min = 60.0
|
|
|
|
|
|
results = RequestMetricService.get_metrics_stats(
|
|
|
request, filter_settings)
|
|
|
# because requests are PER SECOND / we divide 1 min stats by 60
|
|
|
# requests are normalized to 1 min average
|
|
|
# results are average seconds time spent per request in specific area
|
|
|
for point in results:
|
|
|
if point['requests']:
|
|
|
point['main'] = (point['main'] - point['sql'] -
|
|
|
point['nosql'] - point['remote'] -
|
|
|
point['tmpl'] -
|
|
|
point['custom']) / point['requests']
|
|
|
point['sql'] = point['sql'] / point['requests']
|
|
|
point['nosql'] = point['nosql'] / point['requests']
|
|
|
point['remote'] = point['remote'] / point['requests']
|
|
|
point['tmpl'] = point['tmpl'] / point['requests']
|
|
|
point['custom'] = point['custom'] / point['requests']
|
|
|
point['requests_2'] = point['requests'] / 60.0 / divide_by_min
|
|
|
|
|
|
selected_types = ['main', 'sql', 'nosql', 'remote', 'tmpl', 'custom']
|
|
|
|
|
|
for point in results:
|
|
|
for stat_type in selected_types:
|
|
|
point[stat_type] = round(point.get(stat_type, 0), 3)
|
|
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property',
|
|
|
match_param='key=response_graphs', renderer='json',
|
|
|
permission='view')
|
|
|
def response_graphs(request):
|
|
|
"""
|
|
|
Handles dashboard infomation for avg. response time split by today,
|
|
|
2 days ago and week ago
|
|
|
"""
|
|
|
query_params = request.GET.mixed()
|
|
|
query_params['resource'] = (request.context.resource.resource_id,)
|
|
|
|
|
|
filter_settings = build_filter_settings_from_query_dict(request,
|
|
|
query_params)
|
|
|
|
|
|
if not filter_settings.get('end_date'):
|
|
|
end_date = datetime.utcnow().replace(microsecond=0, second=0)
|
|
|
filter_settings['end_date'] = end_date
|
|
|
|
|
|
delta = timedelta(hours=1)
|
|
|
if not filter_settings.get('start_date'):
|
|
|
filter_settings['start_date'] = filter_settings['end_date'] - delta
|
|
|
|
|
|
result_now = RequestMetricService.get_metrics_stats(
|
|
|
request, filter_settings)
|
|
|
|
|
|
filter_settings_2d = filter_settings.copy()
|
|
|
filter_settings_2d['start_date'] = filter_settings['start_date'] - \
|
|
|
timedelta(days=2)
|
|
|
filter_settings_2d['end_date'] = filter_settings['end_date'] - \
|
|
|
timedelta(days=2)
|
|
|
result_2d = RequestMetricService.get_metrics_stats(
|
|
|
request, filter_settings_2d)
|
|
|
|
|
|
filter_settings_7d = filter_settings.copy()
|
|
|
filter_settings_7d['start_date'] = filter_settings['start_date'] - \
|
|
|
timedelta(days=7)
|
|
|
filter_settings_7d['end_date'] = filter_settings['end_date'] - \
|
|
|
timedelta(days=7)
|
|
|
result_7d = RequestMetricService.get_metrics_stats(
|
|
|
request, filter_settings_7d)
|
|
|
|
|
|
plot_data = []
|
|
|
|
|
|
for item in result_now:
|
|
|
point = {'x': item['x'], 'today': 0, 'days_ago_2': 0,
|
|
|
'days_ago_7': 0}
|
|
|
if item['requests']:
|
|
|
point['today'] = round(item['main'] / item['requests'], 3)
|
|
|
plot_data.append(point)
|
|
|
|
|
|
for i, item in enumerate(result_2d[:len(plot_data)]):
|
|
|
plot_data[i]['days_ago_2'] = 0
|
|
|
point = result_2d[i]
|
|
|
if point['requests']:
|
|
|
plot_data[i]['days_ago_2'] = round(point['main'] /
|
|
|
point['requests'], 3)
|
|
|
|
|
|
for i, item in enumerate(result_7d[:len(plot_data)]):
|
|
|
plot_data[i]['days_ago_7'] = 0
|
|
|
point = result_7d[i]
|
|
|
if point['requests']:
|
|
|
plot_data[i]['days_ago_7'] = round(point['main'] /
|
|
|
point['requests'], 3)
|
|
|
|
|
|
return plot_data
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property',
|
|
|
match_param='key=requests_graphs', renderer='json',
|
|
|
permission='view')
|
|
|
def requests_graphs(request):
|
|
|
"""
|
|
|
Handles dashboard infomation for avg. response time split by today,
|
|
|
2 days ago and week ago
|
|
|
"""
|
|
|
query_params = request.GET.mixed()
|
|
|
query_params['resource'] = (request.context.resource.resource_id,)
|
|
|
|
|
|
filter_settings = build_filter_settings_from_query_dict(request,
|
|
|
query_params)
|
|
|
|
|
|
if not filter_settings.get('end_date'):
|
|
|
end_date = datetime.utcnow().replace(microsecond=0, second=0)
|
|
|
filter_settings['end_date'] = end_date
|
|
|
|
|
|
delta = timedelta(hours=1)
|
|
|
if not filter_settings.get('start_date'):
|
|
|
filter_settings['start_date'] = filter_settings['end_date'] - delta
|
|
|
|
|
|
result_now = RequestMetricService.get_metrics_stats(
|
|
|
request, filter_settings)
|
|
|
|
|
|
delta = filter_settings['end_date'] - filter_settings['start_date']
|
|
|
if delta < h.time_deltas.get('12h')['delta']:
|
|
|
seconds = h.time_deltas['1m']['minutes'] * 60.0
|
|
|
elif delta <= h.time_deltas.get('3d')['delta']:
|
|
|
seconds = h.time_deltas['5m']['minutes'] * 60.0
|
|
|
elif delta >= h.time_deltas.get('2w')['delta']:
|
|
|
seconds = h.time_deltas['24h']['minutes'] * 60.0
|
|
|
else:
|
|
|
seconds = h.time_deltas['1h']['minutes'] * 60.0
|
|
|
|
|
|
for item in result_now:
|
|
|
if item['requests']:
|
|
|
item['requests'] = round(item['requests'] / seconds, 3)
|
|
|
return result_now
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property',
|
|
|
match_param='key=apdex_stats', renderer='json',
|
|
|
permission='view')
|
|
|
def get_apdex_stats(request):
|
|
|
"""
|
|
|
Returns information and calculates APDEX score per server for dashboard
|
|
|
server information (upper right stats boxes)
|
|
|
"""
|
|
|
query_params = request.GET.mixed()
|
|
|
query_params['resource'] = (request.context.resource.resource_id,)
|
|
|
|
|
|
filter_settings = build_filter_settings_from_query_dict(request,
|
|
|
query_params)
|
|
|
# make sure we have only one resource here to don't produce
|
|
|
# weird results when we have wrong app in app selector
|
|
|
filter_settings['resource'] = [filter_settings['resource'][0]]
|
|
|
|
|
|
if not filter_settings.get('end_date'):
|
|
|
end_date = datetime.utcnow().replace(microsecond=0, second=0)
|
|
|
filter_settings['end_date'] = end_date
|
|
|
|
|
|
delta = timedelta(hours=1)
|
|
|
if not filter_settings.get('start_date'):
|
|
|
filter_settings['start_date'] = filter_settings['end_date'] - delta
|
|
|
|
|
|
return RequestMetricService.get_apdex_stats(request, filter_settings)
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property', match_param='key=slow_calls',
|
|
|
renderer='json', permission='view')
|
|
|
def get_slow_calls(request):
|
|
|
"""
|
|
|
Returns information for time consuming calls in specific time interval
|
|
|
"""
|
|
|
query_params = request.GET.mixed()
|
|
|
query_params['resource'] = (request.context.resource.resource_id,)
|
|
|
|
|
|
filter_settings = build_filter_settings_from_query_dict(request,
|
|
|
query_params)
|
|
|
|
|
|
if not filter_settings.get('end_date'):
|
|
|
end_date = datetime.utcnow().replace(microsecond=0, second=0)
|
|
|
filter_settings['end_date'] = end_date
|
|
|
|
|
|
delta = timedelta(hours=1)
|
|
|
if not filter_settings.get('start_date'):
|
|
|
filter_settings['start_date'] = filter_settings['end_date'] - delta
|
|
|
|
|
|
return SlowCallService.get_time_consuming_calls(request, filter_settings)
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property',
|
|
|
match_param='key=requests_breakdown',
|
|
|
renderer='json', permission='view')
|
|
|
def get_requests_breakdown(request):
|
|
|
"""
|
|
|
Used on dashboard to get information which views are most used in
|
|
|
a time interval
|
|
|
"""
|
|
|
query_params = request.GET.mixed()
|
|
|
query_params['resource'] = (request.context.resource.resource_id,)
|
|
|
|
|
|
filter_settings = build_filter_settings_from_query_dict(request,
|
|
|
query_params)
|
|
|
if not filter_settings.get('end_date'):
|
|
|
end_date = datetime.utcnow().replace(microsecond=0, second=0)
|
|
|
filter_settings['end_date'] = end_date
|
|
|
|
|
|
if not filter_settings.get('start_date'):
|
|
|
delta = timedelta(hours=1)
|
|
|
filter_settings['start_date'] = filter_settings['end_date'] - delta
|
|
|
|
|
|
series = RequestMetricService.get_requests_breakdown(
|
|
|
request, filter_settings)
|
|
|
|
|
|
results = []
|
|
|
for row in series:
|
|
|
d_row = {'avg_response': round(row['main'] / row['requests'], 3),
|
|
|
'requests': row['requests'],
|
|
|
'main': row['main'],
|
|
|
'view_name': row['key'],
|
|
|
'latest_details': row['latest_details'],
|
|
|
'percentage': round(row['percentage'] * 100, 1)}
|
|
|
|
|
|
results.append(d_row)
|
|
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property',
|
|
|
match_param='key=trending_reports', renderer='json',
|
|
|
permission='view')
|
|
|
def trending_reports(request):
|
|
|
"""
|
|
|
Returns exception/slow reports trending for specific time interval
|
|
|
"""
|
|
|
query_params = request.GET.mixed().copy()
|
|
|
# pop report type to rewrite it to tag later
|
|
|
report_type = query_params.pop('report_type', None)
|
|
|
if report_type:
|
|
|
query_params['type'] = report_type
|
|
|
|
|
|
query_params['resource'] = (request.context.resource.resource_id,)
|
|
|
|
|
|
filter_settings = build_filter_settings_from_query_dict(request,
|
|
|
query_params)
|
|
|
|
|
|
if not filter_settings.get('end_date'):
|
|
|
end_date = datetime.utcnow().replace(microsecond=0, second=0)
|
|
|
filter_settings['end_date'] = end_date
|
|
|
|
|
|
if not filter_settings.get('start_date'):
|
|
|
delta = timedelta(hours=1)
|
|
|
filter_settings['start_date'] = filter_settings['end_date'] - delta
|
|
|
|
|
|
results = ReportGroupService.get_trending(request, filter_settings)
|
|
|
|
|
|
trending = []
|
|
|
for occurences, group in results:
|
|
|
report_group = group.get_dict(request)
|
|
|
# show the occurences in time range instead of global ones
|
|
|
report_group['occurences'] = occurences
|
|
|
trending.append(report_group)
|
|
|
|
|
|
return trending
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property',
|
|
|
match_param='key=integrations',
|
|
|
renderer='json', permission='view')
|
|
|
def integrations(request):
|
|
|
"""
|
|
|
Integration list for given application
|
|
|
"""
|
|
|
application = request.context.resource
|
|
|
return {'resource': application}
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property',
|
|
|
match_param='key=user_permissions', renderer='json',
|
|
|
permission='owner', request_method='POST')
|
|
|
def user_resource_permission_create(request):
|
|
|
"""
|
|
|
Set new permissions for user for a resource
|
|
|
"""
|
|
|
resource = request.context.resource
|
|
|
user_name = request.unsafe_json_body.get('user_name')
|
|
|
user = User.by_user_name(user_name)
|
|
|
if not user:
|
|
|
user = User.by_email(user_name)
|
|
|
if not user:
|
|
|
return False
|
|
|
|
|
|
for perm_name in request.unsafe_json_body.get('permissions', []):
|
|
|
permission = UserResourcePermission.by_resource_user_and_perm(
|
|
|
user.id, perm_name, resource.resource_id)
|
|
|
if not permission:
|
|
|
permission = UserResourcePermission(perm_name=perm_name,
|
|
|
user_id=user.id)
|
|
|
resource.user_permissions.append(permission)
|
|
|
DBSession.flush()
|
|
|
perms = [p.perm_name for p in resource.perms_for_user(user)
|
|
|
if p.type == 'user']
|
|
|
result = {'user_name': user.user_name,
|
|
|
'permissions': list(set(perms))}
|
|
|
return result
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property',
|
|
|
match_param='key=user_permissions', renderer='json',
|
|
|
permission='owner', request_method='DELETE')
|
|
|
def user_resource_permission_delete(request):
|
|
|
"""
|
|
|
Removes user permission from specific resource
|
|
|
"""
|
|
|
resource = request.context.resource
|
|
|
|
|
|
user = User.by_user_name(request.GET.get('user_name'))
|
|
|
if not user:
|
|
|
return False
|
|
|
|
|
|
for perm_name in request.GET.getall('permissions'):
|
|
|
permission = UserResourcePermission.by_resource_user_and_perm(
|
|
|
user.id, perm_name, resource.resource_id)
|
|
|
resource.user_permissions.remove(permission)
|
|
|
DBSession.flush()
|
|
|
perms = [p.perm_name for p in resource.perms_for_user(user)
|
|
|
if p.type == 'user']
|
|
|
result = {'user_name': user.user_name,
|
|
|
'permissions': list(set(perms))}
|
|
|
return result
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property',
|
|
|
match_param='key=group_permissions', renderer='json',
|
|
|
permission='owner', request_method='POST')
|
|
|
def group_resource_permission_create(request):
|
|
|
"""
|
|
|
Set new permissions for group for a resource
|
|
|
"""
|
|
|
resource = request.context.resource
|
|
|
group = GroupService.by_id(request.unsafe_json_body.get('group_id'))
|
|
|
if not group:
|
|
|
return False
|
|
|
|
|
|
for perm_name in request.unsafe_json_body.get('permissions', []):
|
|
|
permission = GroupResourcePermissionService.by_resource_group_and_perm(
|
|
|
group.id, perm_name, resource.resource_id)
|
|
|
if not permission:
|
|
|
permission = GroupResourcePermission(perm_name=perm_name,
|
|
|
group_id=group.id)
|
|
|
resource.group_permissions.append(permission)
|
|
|
DBSession.flush()
|
|
|
perm_tuples = resource.groups_for_perm(
|
|
|
ANY_PERMISSION,
|
|
|
limit_group_permissions=True,
|
|
|
group_ids=[group.id])
|
|
|
perms = [p.perm_name for p in perm_tuples if p.type == 'group']
|
|
|
result = {'group': group.get_dict(),
|
|
|
'permissions': list(set(perms))}
|
|
|
return result
|
|
|
|
|
|
|
|
|
@view_config(route_name='applications_property',
|
|
|
match_param='key=group_permissions', renderer='json',
|
|
|
permission='owner', request_method='DELETE')
|
|
|
def group_resource_permission_delete(request):
|
|
|
"""
|
|
|
Removes group permission from specific resource
|
|
|
"""
|
|
|
form = forms.ReactorForm(request.POST, csrf_context=request)
|
|
|
form.validate()
|
|
|
resource = request.context.resource
|
|
|
group = GroupService.by_id(request.GET.get('group_id'))
|
|
|
if not group:
|
|
|
return False
|
|
|
|
|
|
for perm_name in request.GET.getall('permissions'):
|
|
|
permission = GroupResourcePermissionService.by_resource_group_and_perm(
|
|
|
group.id, perm_name, resource.resource_id)
|
|
|
resource.group_permissions.remove(permission)
|
|
|
DBSession.flush()
|
|
|
perm_tuples = resource.groups_for_perm(
|
|
|
ANY_PERMISSION,
|
|
|
limit_group_permissions=True,
|
|
|
group_ids=[group.id])
|
|
|
perms = [p.perm_name for p in perm_tuples if p.type == 'group']
|
|
|
result = {'group': group.get_dict(),
|
|
|
'permissions': list(set(perms))}
|
|
|
return result
|
|
|
|