def __init__(self, bucket_notification_configuration, **kwargs): self.settings = kwargs self.bucket_notification_configuration = bucket_notification_configuration self.events = [] # Validate all notifications have an id. This important because # we'll rely on this id to create/modify/delete notifactions if 'id' in self.settings: self.id = self.settings['id'] else: raise exceptions.ResourceValidationError( ("You need to define an id which identifies the " "notification {}").format(self.settings)) # Validate that events is present, and that it contains valid values if 'events' in self.settings and self.settings['events']: for event in self.settings['events']: event_match = re.match(r's3\:(\w+|\*)(?:\:(\w+|\*))?', event) if event_match: self.events.append([event] + list(event_match.groups())) else: raise exceptions.ResourceValidationError( "Invalid event {}".format(event)) else: raise exceptions.ResourceValidationError( ("You need to define a list of events for the " "notification {}").format(self.name)) # Validate that filters are a subset of (prefix, suffix) and keys # are not duplicated. _filters = self.settings.get('key_filters', {}) if set(_filters.values()) > set(('prefix', 'suffix')): raise exceptions.ResourceValidationError( """You can't create filters for '{}'.""".format( ', '.join(_filters))) else: self.filters = [(k, v) for k, v in six.iteritems(_filters)] # Check if a source account has been added for the event. if 'source_account' in self.settings and self.settings[ 'source_account']: account = self.settings['source_account'] account_match = re.match("^[0-9]{12}$", account) if account_match: self.source_account = account else: raise exceptions.ResourceValidationError( ("The source account for the event must be a " "12 digit number: {}").format(account)) else: self.source_account = troposphere.Ref(troposphere.AWS_ACCOUNT_ID)
def validate(self): """Validate that there are no any other resources in the project which try to register notifications for the same bucket than this resource""" for resource in \ (r for r in self.project.get_resources() if isinstance(r, self.__class__) and r.bucket == self.bucket): raise exceptions.ResourceValidationError( ("Both resources '{}' and '{}', registers notifications for " "the bucket '{}'. Because AWS API limitations we need you to " "register all notifications of one bucket in the same " "resource.").format(self, resource, self.bucket))
def _validate_notifications(self): # Validate that notifications events don't overlap top_events_for_bucket = set() sub_events_for_top = defaultdict(list) for notification_id, notification in six.iteritems( self._notifications): for event, top, sub in notification.events: if top in top_events_for_bucket or \ top in sub_events_for_top or\ sub in sub_events_for_top.get(top, []): raise exceptions.ResourceValidationError( ("Event {} overlaps with some other event " "registered for the same bucket.").format(event)) else: top_events_for_bucket.add(top) sub_events_for_top[top].append(sub) # Validate that all key prefix/suffix filters for a bucket # don't overlap one to each other. all_filters = defaultdict(list) for notification_id, notification in six.iteritems( self._notifications): for name, value in notification.filters: all_filters[name].append(value) overlap_checks = {'prefix': 'startswith', 'suffix': 'endswith'} for filter_type, values in six.iteritems(all_filters): check = overlap_checks.get(filter_type) # Don't check fields that are Ref instances # since Refs aren't bound until apply if isinstance(check, Ref): continue overlaps = [ sum([int(getattr(v, check)(z)) for z in values]) for v in values ] if sum(overlaps) > len(values): raise exceptions.ResourceValidationError( "One or more {} filters overlap one to each other {}.". format(filter_type, ', '.join(values)))
def from_dict(cls, data, id, bucket_notification_configuration): notification_type = set( ('lambda', 'topic', 'queue')) & set(data.keys()) if len(notification_type) != 1: raise exceptions.ResourceValidationError( ("You need to define either a lamda, a queue or a topic " "as destination of your notification {}" ).format(bucket_notification_configuration)) return { 'lambda': LambdaFunctionNotification, 'queue': QueueNotification, 'topic': TopicNotification }.get( list(notification_type)[0] )(id=id, bucket_notification_configuration=bucket_notification_configuration, **data)
def _validate_notifications(self): # Validate that all key prefix/suffix filters for a bucket # don't overlap one to each other. all_filters = defaultdict(list) for notification_id, notification in six.iteritems( self._notifications): for name, value in notification.filters: all_filters[name].append(value) overlap_checks = {'prefix': 'startswith', 'suffix': 'endswith'} for filter_type, values in six.iteritems(all_filters): check = overlap_checks.get(filter_type) # Don't check fields that are Ref instances # since Refs aren't bound until apply if isinstance(check, Ref): continue overlaps = [ sum([int(getattr(v, check)(z)) for z in values]) for v in values ] if sum(overlaps) > len(values): raise exceptions.ResourceValidationError( "One or more {} filters overlap one to each other {}.". format(filter_type, ', '.join(values)))