This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/endpoints/api/logs.py

242 lines
9.2 KiB
Python
Raw Normal View History

""" Access usage logs for organizations or repositories. """
2015-05-14 20:47:38 +00:00
2014-03-14 20:02:13 +00:00
import json
from datetime import datetime, timedelta
2016-01-01 23:34:38 +00:00
from dateutil.relativedelta import relativedelta
2014-03-14 20:02:13 +00:00
from endpoints.api import (resource, nickname, ApiResource, query_param, parse_args,
RepositoryParamResource, require_repo_admin, related_user_resource,
format_date, Unauthorized, NotFound, require_user_admin,
internal_only, path_param, require_scope)
2014-03-14 20:02:13 +00:00
from auth.permissions import AdministerOrganizationPermission, AdministerOrganizationPermission
from auth.auth_context import get_authenticated_user
from data import model
from auth import scopes
2015-04-20 18:00:10 +00:00
from app import avatar
2014-03-14 20:02:13 +00:00
LOGS_PER_PAGE = 50
MAX_PAGES = 20
2014-03-14 20:02:13 +00:00
def log_view(log, kinds):
2014-03-14 20:02:13 +00:00
view = {
'kind': kinds[log.kind_id],
2014-03-14 20:02:13 +00:00
'metadata': json.loads(log.metadata_json),
2014-11-24 21:07:38 +00:00
'ip': log.ip,
'datetime': format_date(log.datetime),
2014-03-14 20:02:13 +00:00
}
if log.performer and log.performer.username:
2014-03-14 20:02:13 +00:00
view['performer'] = {
'kind': 'user',
'name': log.performer.username,
'is_robot': log.performer.robot,
2015-04-20 18:00:10 +00:00
'avatar': avatar.get_data_for_user(log.performer)
2014-03-14 20:02:13 +00:00
}
return view
def aggregated_log_view(log, kinds, start_time):
# Because we aggregate based on the day of the month in SQL, we only have that information.
# Therefore, create a synthetic date based on the day and the month of the start time.
# Logs are allowed for a maximum period of one week, so this calculation should always work.
2016-01-01 23:34:38 +00:00
synthetic_date = datetime(start_time.year, start_time.month, int(log.day))
if synthetic_date.day < start_time.day:
synthetic_date = synthetic_date + relativedelta(months=1)
view = {
'kind': kinds[log.kind_id],
'count': log.count,
2016-01-01 23:34:38 +00:00
'datetime': format_date(synthetic_date),
}
return view
2014-03-14 20:02:13 +00:00
def _validate_logs_arguments(start_time, end_time, performer_name):
2014-03-14 20:02:13 +00:00
performer = None
if performer_name:
performer = model.user.get_user(performer_name)
2014-03-14 20:02:13 +00:00
if start_time:
try:
start_time = datetime.strptime(start_time + ' UTC', '%m/%d/%Y %Z')
except ValueError:
start_time = None
2014-11-24 21:07:38 +00:00
if not start_time:
2014-03-14 20:02:13 +00:00
start_time = datetime.today() - timedelta(7) # One week
if end_time:
try:
end_time = datetime.strptime(end_time + ' UTC', '%m/%d/%Y %Z')
end_time = end_time + timedelta(days=1)
except ValueError:
end_time = None
2014-11-24 21:07:38 +00:00
if not end_time:
2014-03-14 20:02:13 +00:00
end_time = datetime.today()
return (start_time, end_time, performer)
def get_logs(start_time, end_time, performer_name=None, repository=None, namespace=None, page=None):
(start_time, end_time, performer) = _validate_logs_arguments(start_time, end_time, performer_name)
page = min(MAX_PAGES, page if page else 1)
kinds = model.log.get_log_entry_kinds()
logs = model.log.list_logs(start_time, end_time, performer=performer, repository=repository,
namespace=namespace, page=page, count=LOGS_PER_PAGE + 1)
2014-03-14 20:02:13 +00:00
return {
'start_time': format_date(start_time),
'end_time': format_date(end_time),
'logs': [log_view(log, kinds) for log in logs[0:LOGS_PER_PAGE]],
'page': page,
'has_additional': len(logs) > LOGS_PER_PAGE,
}
def get_aggregate_logs(start_time, end_time, performer_name=None, repository=None, namespace=None):
(start_time, end_time, performer) = _validate_logs_arguments(start_time, end_time, performer_name)
kinds = model.log.get_log_entry_kinds()
aggregated_logs = model.log.get_aggregated_logs(start_time, end_time, performer=performer,
repository=repository, namespace=namespace)
return {
'aggregated': [aggregated_log_view(log, kinds, start_time) for log in aggregated_logs]
2014-03-14 20:02:13 +00:00
}
@resource('/v1/repository/<repopath:repository>/logs')
@path_param('repository', 'The full path of the repository. e.g. namespace/name')
2014-03-14 20:02:13 +00:00
class RepositoryLogs(RepositoryParamResource):
""" Resource for fetching logs for the specific repository. """
@require_repo_admin
@nickname('listRepoLogs')
@parse_args
@query_param('starttime', 'Earliest time from which to get logs (%m/%d/%Y %Z)', type=str)
@query_param('endtime', 'Latest time to which to get logs (%m/%d/%Y %Z)', type=str)
@query_param('page', 'The page number for the logs', type=int, default=1)
2014-03-14 20:02:13 +00:00
def get(self, args, namespace, repository):
""" List the logs for the specified repository. """
repo = model.repository.get_repository(namespace, repository)
2014-03-14 20:02:13 +00:00
if not repo:
raise NotFound()
2014-03-14 20:02:13 +00:00
start_time = args['starttime']
end_time = args['endtime']
return get_logs(start_time, end_time, repository=repo, page=args['page'])
2014-03-14 20:02:13 +00:00
@resource('/v1/user/logs')
@internal_only
class UserLogs(ApiResource):
""" Resource for fetching logs for the current user. """
@require_user_admin
@nickname('listUserLogs')
@parse_args
@query_param('starttime', 'Earliest time from which to get logs. (%m/%d/%Y %Z)', type=str)
@query_param('endtime', 'Latest time to which to get logs. (%m/%d/%Y %Z)', type=str)
@query_param('performer', 'Username for which to filter logs.', type=str)
@query_param('page', 'The page number for the logs', type=int, default=1)
def get(self, args):
""" List the logs for the current user. """
performer_name = args['performer']
start_time = args['starttime']
end_time = args['endtime']
user = get_authenticated_user()
return get_logs(start_time, end_time, performer_name=performer_name, namespace=user.username,
page=args['page'])
2014-03-14 20:02:13 +00:00
@resource('/v1/organization/<orgname>/logs')
@path_param('orgname', 'The name of the organization')
@related_user_resource(UserLogs)
2014-03-14 20:02:13 +00:00
class OrgLogs(ApiResource):
""" Resource for fetching logs for the entire organization. """
@nickname('listOrgLogs')
@parse_args
@query_param('starttime', 'Earliest time from which to get logs. (%m/%d/%Y %Z)', type=str)
@query_param('endtime', 'Latest time to which to get logs. (%m/%d/%Y %Z)', type=str)
@query_param('performer', 'Username for which to filter logs.', type=str)
@query_param('page', 'The page number for the logs', type=int, default=1)
@require_scope(scopes.ORG_ADMIN)
2014-03-14 20:02:13 +00:00
def get(self, args, orgname):
""" List the logs for the specified organization. """
permission = AdministerOrganizationPermission(orgname)
if permission.can():
performer_name = args['performer']
start_time = args['starttime']
end_time = args['endtime']
return get_logs(start_time, end_time, namespace=orgname, performer_name=performer_name,
page=args['page'])
raise Unauthorized()
@resource('/v1/repository/<repopath:repository>/aggregatelogs')
@path_param('repository', 'The full path of the repository. e.g. namespace/name')
class RepositoryAggregateLogs(RepositoryParamResource):
""" Resource for fetching aggregated logs for the specific repository. """
@require_repo_admin
@nickname('getAggregateRepoLogs')
@parse_args
@query_param('starttime', 'Earliest time from which to get logs (%m/%d/%Y %Z)', type=str)
@query_param('endtime', 'Latest time to which to get logs (%m/%d/%Y %Z)', type=str)
def get(self, args, namespace, repository):
""" Returns the aggregated logs for the specified repository. """
repo = model.repository.get_repository(namespace, repository)
if not repo:
raise NotFound()
start_time = args['starttime']
end_time = args['endtime']
return get_aggregate_logs(start_time, end_time, repository=repo)
@resource('/v1/user/aggregatelogs')
@internal_only
class UserAggregateLogs(ApiResource):
""" Resource for fetching aggregated logs for the current user. """
@require_user_admin
@nickname('getAggregateUserLogs')
@parse_args
@query_param('starttime', 'Earliest time from which to get logs. (%m/%d/%Y %Z)', type=str)
@query_param('endtime', 'Latest time to which to get logs. (%m/%d/%Y %Z)', type=str)
@query_param('performer', 'Username for which to filter logs.', type=str)
def get(self, args):
""" Returns the aggregated logs for the current user. """
performer_name = args['performer']
start_time = args['starttime']
end_time = args['endtime']
user = get_authenticated_user()
return get_aggregate_logs(start_time, end_time, performer_name=performer_name,
namespace=user.username)
@resource('/v1/organization/<orgname>/aggregatelogs')
@path_param('orgname', 'The name of the organization')
@related_user_resource(UserLogs)
class OrgAggregateLogs(ApiResource):
""" Resource for fetching aggregate logs for the entire organization. """
@nickname('getAggregateOrgLogs')
@parse_args
@query_param('starttime', 'Earliest time from which to get logs. (%m/%d/%Y %Z)', type=str)
@query_param('endtime', 'Latest time to which to get logs. (%m/%d/%Y %Z)', type=str)
@query_param('performer', 'Username for which to filter logs.', type=str)
@require_scope(scopes.ORG_ADMIN)
def get(self, args, orgname):
""" Gets the aggregated logs for the specified organization. """
permission = AdministerOrganizationPermission(orgname)
if permission.can():
performer_name = args['performer']
start_time = args['starttime']
end_time = args['endtime']
return get_aggregate_logs(start_time, end_time, namespace=orgname,
performer_name=performer_name)
2014-03-14 20:02:13 +00:00
raise Unauthorized()