This commit is contained in:
Joseph Schorr 2017-07-19 11:08:33 -04:00
parent e7d6e60d97
commit 48c79003c6
7 changed files with 64 additions and 60 deletions

View file

@ -3,14 +3,14 @@
import logging import logging
from flask import request from flask import request
from endpoints.api import (RepositoryParamResource, nickname, resource, require_repo_admin, from endpoints.api import (
log_action, validate_json_request, request_error, RepositoryParamResource, nickname, resource, require_repo_admin, log_action,
path_param, disallow_for_app_repositories, InvalidRequest) validate_json_request, request_error, path_param, disallow_for_app_repositories, InvalidRequest)
from endpoints.exception import NotFound from endpoints.exception import NotFound
from notifications.models_interface import Repository from notifications.models_interface import Repository
from notifications.notificationevent import NotificationEvent from notifications.notificationevent import NotificationEvent
from notifications.notificationmethod import (NotificationMethod, from notifications.notificationmethod import (
CannotValidateNotificationMethodException) NotificationMethod, CannotValidateNotificationMethodException)
from endpoints.api.repositorynotification_models_pre_oci import pre_oci_model as model from endpoints.api.repositorynotification_models_pre_oci import pre_oci_model as model
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -69,17 +69,16 @@ class RepositoryNotificationList(RepositoryParamResource):
raise request_error(message=ex.message) raise request_error(message=ex.message)
new_notification = model.create_repo_notification(namespace_name, repository_name, new_notification = model.create_repo_notification(namespace_name, repository_name,
parsed['event'], parsed['event'], parsed['method'],
parsed['method'], parsed['config'], parsed['eventConfig'],
parsed['config'],
parsed['eventConfig'],
parsed.get('title')) parsed.get('title'))
log_action('add_repo_notification', namespace_name, log_action('add_repo_notification', namespace_name, {
{'repo': repository_name, 'namespace': namespace_name, 'repo': repository_name,
'notification_id': new_notification.uuid, 'namespace': namespace_name,
'event': new_notification.event_name, 'method': new_notification.method_name}, 'notification_id': new_notification.uuid,
repo_name=repository_name) 'event': new_notification.event_name,
'method': new_notification.method_name}, repo_name=repository_name)
return new_notification.to_dict(), 201 return new_notification.to_dict(), 201
@require_repo_admin @require_repo_admin
@ -88,9 +87,7 @@ class RepositoryNotificationList(RepositoryParamResource):
def get(self, namespace_name, repository_name): def get(self, namespace_name, repository_name):
""" List the notifications for the specified repository. """ """ List the notifications for the specified repository. """
notifications = model.list_repo_notifications(namespace_name, repository_name) notifications = model.list_repo_notifications(namespace_name, repository_name)
return { return {'notifications': [n.to_dict() for n in notifications]}
'notifications': [n.to_dict() for n in notifications]
}
@resource('/v1/repository/<apirepopath:repository>/notification/<uuid>') @resource('/v1/repository/<apirepopath:repository>/notification/<uuid>')
@ -98,6 +95,7 @@ class RepositoryNotificationList(RepositoryParamResource):
@path_param('uuid', 'The UUID of the notification') @path_param('uuid', 'The UUID of the notification')
class RepositoryNotification(RepositoryParamResource): class RepositoryNotification(RepositoryParamResource):
""" Resource for dealing with specific notifications. """ """ Resource for dealing with specific notifications. """
@require_repo_admin @require_repo_admin
@nickname('getRepoNotification') @nickname('getRepoNotification')
@disallow_for_app_repositories @disallow_for_app_repositories
@ -115,12 +113,15 @@ class RepositoryNotification(RepositoryParamResource):
""" Deletes the specified notification. """ """ Deletes the specified notification. """
deleted = model.delete_repo_notification(namespace_name, repository_name, uuid) deleted = model.delete_repo_notification(namespace_name, repository_name, uuid)
if not deleted: if not deleted:
raise InvalidRequest("No repository notification found for: %s, %s, %s" % (namespace_name, repository_name, uuid)) raise InvalidRequest("No repository notification found for: %s, %s, %s" %
(namespace_name, repository_name, uuid))
log_action('delete_repo_notification', namespace_name, log_action('delete_repo_notification', namespace_name, {
{'repo': repository_name, 'namespace': namespace_name, 'notification_id': uuid, 'repo': repository_name,
'event': deleted.event_name, 'method': deleted.method_name}, 'namespace': namespace_name,
repo_name=repository_name) 'notification_id': uuid,
'event': deleted.event_name,
'method': deleted.method_name}, repo_name=repository_name)
return 'No Content', 204 return 'No Content', 204
@ -131,12 +132,15 @@ class RepositoryNotification(RepositoryParamResource):
""" Resets repository notification to 0 failures. """ """ Resets repository notification to 0 failures. """
reset = model.reset_notification_number_of_failures(namespace_name, repository_name, uuid) reset = model.reset_notification_number_of_failures(namespace_name, repository_name, uuid)
if not reset: if not reset:
raise InvalidRequest("No repository notification found for: %s, %s, %s" % (namespace_name, repository_name, uuid)) raise InvalidRequest("No repository notification found for: %s, %s, %s" %
(namespace_name, repository_name, uuid))
log_action('reset_repo_notification', namespace_name, log_action('reset_repo_notification', namespace_name, {
{'repo': repository_name, 'namespace': namespace_name, 'notification_id': uuid, 'repo': repository_name,
'event': reset.event_name, 'method': reset.method_name}, 'namespace': namespace_name,
repo_name=repository_name) 'notification_id': uuid,
'event': reset.event_name,
'method': reset.method_name}, repo_name=repository_name)
return 'No Content', 204 return 'No Content', 204
@ -146,6 +150,7 @@ class RepositoryNotification(RepositoryParamResource):
@path_param('uuid', 'The UUID of the notification') @path_param('uuid', 'The UUID of the notification')
class TestRepositoryNotification(RepositoryParamResource): class TestRepositoryNotification(RepositoryParamResource):
""" Resource for queuing a test of a notification. """ """ Resource for queuing a test of a notification. """
@require_repo_admin @require_repo_admin
@nickname('testRepoNotification') @nickname('testRepoNotification')
@disallow_for_app_repositories @disallow_for_app_repositories
@ -153,6 +158,7 @@ class TestRepositoryNotification(RepositoryParamResource):
""" Queues a test notification for this repository. """ """ Queues a test notification for this repository. """
test_note = model.queue_test_notification(uuid) test_note = model.queue_test_notification(uuid)
if not test_note: if not test_note:
raise InvalidRequest("No repository notification found for: %s, %s, %s" % (namespace_name, repository_name, uuid)) raise InvalidRequest("No repository notification found for: %s, %s, %s" %
(namespace_name, repository_name, uuid))
return {}, 200 return {}, 200

View file

@ -26,6 +26,7 @@ class RepositoryNotification(
:type event_config: string :type event_config: string
:type number_of_failures: int :type number_of_failures: int
""" """
def to_dict(self): def to_dict(self):
try: try:
config = json.loads(self.config_json) config = json.loads(self.config_json)
@ -55,7 +56,8 @@ class RepoNotificationInterface(object):
""" """
@abstractmethod @abstractmethod
def create_repo_notification(self, namespace_name, repository_name, event_name, method_name, method_config, event_config, title=None): def create_repo_notification(self, namespace_name, repository_name, event_name, method_name,
method_config, event_config, title=None):
""" """
Args: Args:

View file

@ -3,25 +3,25 @@ import json
from app import notification_queue from app import notification_queue
from data import model from data import model
from data.model import InvalidNotificationException from data.model import InvalidNotificationException
from endpoints.api.repositorynotification_models_interface import RepoNotificationInterface, RepositoryNotification from endpoints.api.repositorynotification_models_interface import (RepoNotificationInterface,
RepositoryNotification)
from notifications import build_notification_data from notifications import build_notification_data
from notifications.notificationevent import NotificationEvent from notifications.notificationevent import NotificationEvent
class RepoNotificationPreOCIModel(RepoNotificationInterface): class RepoNotificationPreOCIModel(RepoNotificationInterface):
def create_repo_notification(self, namespace_name, repository_name, event_name, method_name,
def create_repo_notification(self, namespace_name, repository_name, event_name, method_name, method_config, event_config, title=None): method_config, event_config, title=None):
repository = model.repository.get_repository(namespace_name, repository_name) repository = model.repository.get_repository(namespace_name, repository_name)
return self._notification(model.notification.create_repo_notification(repository, return self._notification(
event_name, model.notification.create_repo_notification(repository, event_name, method_name,
method_name, method_config, event_config, title))
method_config,
event_config,
title))
def list_repo_notifications(self, namespace_name, repository_name, event_name=None): def list_repo_notifications(self, namespace_name, repository_name, event_name=None):
return [self._notification(n) return [
for n in model.notification.list_repo_notifications(namespace_name, repository_name, event_name)] self._notification(n)
for n in model.notification.list_repo_notifications(namespace_name, repository_name,
event_name)]
def get_repo_notification(self, uuid): def get_repo_notification(self, uuid):
try: try:
@ -39,7 +39,8 @@ class RepoNotificationPreOCIModel(RepoNotificationInterface):
def reset_notification_number_of_failures(self, namespace_name, repository_name, uuid): def reset_notification_number_of_failures(self, namespace_name, repository_name, uuid):
return self._notification( return self._notification(
model.notification.reset_notification_number_of_failures(namespace_name, repository_name, uuid)) model.notification.reset_notification_number_of_failures(namespace_name, repository_name,
uuid))
def queue_test_notification(self, uuid): def queue_test_notification(self, uuid):
try: try:
@ -52,23 +53,20 @@ class RepoNotificationPreOCIModel(RepoNotificationInterface):
sample_data = event_info.get_sample_data(notification.repository.namespace_user.username, sample_data = event_info.get_sample_data(notification.repository.namespace_user.username,
notification.repository.name, event_config) notification.repository.name, event_config)
notification_data = build_notification_data(notification, sample_data) notification_data = build_notification_data(notification, sample_data)
notification_queue.put([notification.repository.namespace_user.username, notification.uuid, notification_queue.put([
notification.event.name], json.dumps(notification_data)) notification.repository.namespace_user.username, notification.uuid, notification.event.name],
json.dumps(notification_data))
return self._notification(notification) return self._notification(notification)
def _notification(self, notification): def _notification(self, notification):
if not notification: if not notification:
return None return None
return RepositoryNotification(uuid=notification.uuid, return RepositoryNotification(
title=notification.title, uuid=notification.uuid, title=notification.title, event_name=notification.event.name,
event_name=notification.event.name, method_name=notification.method.name, config_json=notification.config_json,
method_name=notification.method.name, event_config_json=notification.event_config_json,
config_json=notification.config_json, number_of_failures=notification.number_of_failures)
event_config_json=notification.event_config_json,
number_of_failures=notification.number_of_failures)
pre_oci_model = RepoNotificationPreOCIModel() pre_oci_model = RepoNotificationPreOCIModel()

View file

@ -14,7 +14,6 @@ from auth.permissions import (
CreateRepositoryPermission, repository_read_grant, repository_write_grant) CreateRepositoryPermission, repository_read_grant, repository_write_grant)
from auth.signedgrant import generate_signed_token from auth.signedgrant import generate_signed_token
from endpoints.decorators import anon_protect, anon_allowed, parse_repository_name from endpoints.decorators import anon_protect, anon_allowed, parse_repository_name
from endpoints.notificationhelper import spawn_notification
from endpoints.v1 import v1_bp from endpoints.v1 import v1_bp
from endpoints.v1.models_pre_oci import pre_oci_model as model from endpoints.v1.models_pre_oci import pre_oci_model as model
from notifications import spawn_notification from notifications import spawn_notification

View file

@ -10,7 +10,6 @@ from app import docker_v2_signing_key, app, metric_queue
from auth.registry_jwt_auth import process_registry_jwt_auth from auth.registry_jwt_auth import process_registry_jwt_auth
from digest import digest_tools from digest import digest_tools
from endpoints.decorators import anon_protect, parse_repository_name from endpoints.decorators import anon_protect, parse_repository_name
from endpoints.notificationhelper import spawn_notification
from endpoints.v2 import v2_bp, require_repo_read, require_repo_write from endpoints.v2 import v2_bp, require_repo_read, require_repo_write
from endpoints.v2.models_interface import Label from endpoints.v2.models_interface import Label
from endpoints.v2.models_pre_oci import data_model as model from endpoints.v2.models_pre_oci import data_model as model

View file

@ -6,7 +6,6 @@ from app import app, notification_queue
from data import model from data import model
from auth.auth_context import get_authenticated_user, get_validated_oauth_token from auth.auth_context import get_authenticated_user, get_validated_oauth_token
DEFAULT_BATCH_SIZE = 1000 DEFAULT_BATCH_SIZE = 1000
@ -17,8 +16,7 @@ def build_repository_event_data(namespace_name, repo_name, extra_data=None, subp
""" """
repo_string = '%s/%s' % (namespace_name, repo_name) repo_string = '%s/%s' % (namespace_name, repo_name)
homepage = '%s://%s/repository/%s' % (app.config['PREFERRED_URL_SCHEME'], homepage = '%s://%s/repository/%s' % (app.config['PREFERRED_URL_SCHEME'],
app.config['SERVER_HOSTNAME'], app.config['SERVER_HOSTNAME'], repo_string)
repo_string)
if subpage: if subpage:
if not subpage.startswith('/'): if not subpage.startswith('/'):
@ -37,6 +35,7 @@ def build_repository_event_data(namespace_name, repo_name, extra_data=None, subp
event_data.update(extra_data or {}) event_data.update(extra_data or {})
return event_data return event_data
def build_notification_data(notification, event_data, performer_data=None): def build_notification_data(notification, event_data, performer_data=None):
if not performer_data: if not performer_data:
performer_data = {} performer_data = {}
@ -67,13 +66,13 @@ def notification_batch(batch_size=DEFAULT_BATCH_SIZE):
the callable will be bulk inserted into the queue with the specified batch size. the callable will be bulk inserted into the queue with the specified batch size.
""" """
with notification_queue.batch_insert(batch_size) as queue_put: with notification_queue.batch_insert(batch_size) as queue_put:
def spawn_notification_batch(repo, event_name, extra_data=None, subpage=None, pathargs=None, def spawn_notification_batch(repo, event_name, extra_data=None, subpage=None, pathargs=None,
performer_data=None): performer_data=None):
event_data = build_repository_event_data(repo.namespace_name, repo.name, event_data = build_repository_event_data(repo.namespace_name, repo.name,
extra_data=extra_data, subpage=subpage) extra_data=extra_data, subpage=subpage)
notifications = model.notification.list_repo_notifications(repo.namespace_name, notifications = model.notification.list_repo_notifications(repo.namespace_name, repo.name,
repo.name,
event_name=event_name) event_name=event_name)
path = [repo.namespace_name, repo.name, event_name] + (pathargs or []) path = [repo.namespace_name, repo.name, event_name] + (pathargs or [])
for notification in list(notifications): for notification in list(notifications):

View file

@ -1,5 +1,6 @@
from collections import namedtuple from collections import namedtuple
class Repository(namedtuple('Repository', ['namespace_name', 'name'])): class Repository(namedtuple('Repository', ['namespace_name', 'name'])):
""" """
Repository represents a repository. Repository represents a repository.