aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/minio/minio-go/v7/pkg/notification/notification.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/minio/minio-go/v7/pkg/notification/notification.go')
-rw-r--r--vendor/github.com/minio/minio-go/v7/pkg/notification/notification.go440
1 files changed, 440 insertions, 0 deletions
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/notification/notification.go b/vendor/github.com/minio/minio-go/v7/pkg/notification/notification.go
new file mode 100644
index 0000000..a44799d
--- /dev/null
+++ b/vendor/github.com/minio/minio-go/v7/pkg/notification/notification.go
@@ -0,0 +1,440 @@
1/*
2 * MinIO Go Library for Amazon S3 Compatible Cloud Storage
3 * Copyright 2020 MinIO, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package notification
19
20import (
21 "encoding/xml"
22 "errors"
23 "fmt"
24 "strings"
25
26 "github.com/minio/minio-go/v7/pkg/set"
27)
28
29// EventType is a S3 notification event associated to the bucket notification configuration
30type EventType string
31
32// The role of all event types are described in :
33//
34// http://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html#notification-how-to-event-types-and-destinations
35const (
36 ObjectCreatedAll EventType = "s3:ObjectCreated:*"
37 ObjectCreatedPut EventType = "s3:ObjectCreated:Put"
38 ObjectCreatedPost EventType = "s3:ObjectCreated:Post"
39 ObjectCreatedCopy EventType = "s3:ObjectCreated:Copy"
40 ObjectCreatedDeleteTagging EventType = "s3:ObjectCreated:DeleteTagging"
41 ObjectCreatedCompleteMultipartUpload EventType = "s3:ObjectCreated:CompleteMultipartUpload"
42 ObjectCreatedPutLegalHold EventType = "s3:ObjectCreated:PutLegalHold"
43 ObjectCreatedPutRetention EventType = "s3:ObjectCreated:PutRetention"
44 ObjectCreatedPutTagging EventType = "s3:ObjectCreated:PutTagging"
45 ObjectAccessedGet EventType = "s3:ObjectAccessed:Get"
46 ObjectAccessedHead EventType = "s3:ObjectAccessed:Head"
47 ObjectAccessedGetRetention EventType = "s3:ObjectAccessed:GetRetention"
48 ObjectAccessedGetLegalHold EventType = "s3:ObjectAccessed:GetLegalHold"
49 ObjectAccessedAll EventType = "s3:ObjectAccessed:*"
50 ObjectRemovedAll EventType = "s3:ObjectRemoved:*"
51 ObjectRemovedDelete EventType = "s3:ObjectRemoved:Delete"
52 ObjectRemovedDeleteMarkerCreated EventType = "s3:ObjectRemoved:DeleteMarkerCreated"
53 ObjectReducedRedundancyLostObject EventType = "s3:ReducedRedundancyLostObject"
54 ObjectTransitionAll EventType = "s3:ObjectTransition:*"
55 ObjectTransitionFailed EventType = "s3:ObjectTransition:Failed"
56 ObjectTransitionComplete EventType = "s3:ObjectTransition:Complete"
57 ObjectTransitionPost EventType = "s3:ObjectRestore:Post"
58 ObjectTransitionCompleted EventType = "s3:ObjectRestore:Completed"
59 ObjectReplicationAll EventType = "s3:Replication:*"
60 ObjectReplicationOperationCompletedReplication EventType = "s3:Replication:OperationCompletedReplication"
61 ObjectReplicationOperationFailedReplication EventType = "s3:Replication:OperationFailedReplication"
62 ObjectReplicationOperationMissedThreshold EventType = "s3:Replication:OperationMissedThreshold"
63 ObjectReplicationOperationNotTracked EventType = "s3:Replication:OperationNotTracked"
64 ObjectReplicationOperationReplicatedAfterThreshold EventType = "s3:Replication:OperationReplicatedAfterThreshold"
65 ObjectScannerManyVersions EventType = "s3:Scanner:ManyVersions"
66 ObjectScannerBigPrefix EventType = "s3:Scanner:BigPrefix"
67 ObjectScannerAll EventType = "s3:Scanner:*"
68 BucketCreatedAll EventType = "s3:BucketCreated:*"
69 BucketRemovedAll EventType = "s3:BucketRemoved:*"
70)
71
72// FilterRule - child of S3Key, a tag in the notification xml which
73// carries suffix/prefix filters
74type FilterRule struct {
75 Name string `xml:"Name"`
76 Value string `xml:"Value"`
77}
78
79// S3Key - child of Filter, a tag in the notification xml which
80// carries suffix/prefix filters
81type S3Key struct {
82 FilterRules []FilterRule `xml:"FilterRule,omitempty"`
83}
84
85// Filter - a tag in the notification xml structure which carries
86// suffix/prefix filters
87type Filter struct {
88 S3Key S3Key `xml:"S3Key,omitempty"`
89}
90
91// Arn - holds ARN information that will be sent to the web service,
92// ARN desciption can be found in http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html
93type Arn struct {
94 Partition string
95 Service string
96 Region string
97 AccountID string
98 Resource string
99}
100
101// NewArn creates new ARN based on the given partition, service, region, account id and resource
102func NewArn(partition, service, region, accountID, resource string) Arn {
103 return Arn{
104 Partition: partition,
105 Service: service,
106 Region: region,
107 AccountID: accountID,
108 Resource: resource,
109 }
110}
111
112var (
113 // ErrInvalidArnPrefix is returned when ARN string format does not start with 'arn'
114 ErrInvalidArnPrefix = errors.New("invalid ARN format, must start with 'arn:'")
115 // ErrInvalidArnFormat is returned when ARN string format is not valid
116 ErrInvalidArnFormat = errors.New("invalid ARN format, must be 'arn:<partition>:<service>:<region>:<accountID>:<resource>'")
117)
118
119// NewArnFromString parses string representation of ARN into Arn object.
120// Returns an error if the string format is incorrect.
121func NewArnFromString(arn string) (Arn, error) {
122 parts := strings.Split(arn, ":")
123 if len(parts) != 6 {
124 return Arn{}, ErrInvalidArnFormat
125 }
126 if parts[0] != "arn" {
127 return Arn{}, ErrInvalidArnPrefix
128 }
129
130 return NewArn(parts[1], parts[2], parts[3], parts[4], parts[5]), nil
131}
132
133// String returns the string format of the ARN
134func (arn Arn) String() string {
135 return "arn:" + arn.Partition + ":" + arn.Service + ":" + arn.Region + ":" + arn.AccountID + ":" + arn.Resource
136}
137
138// Config - represents one single notification configuration
139// such as topic, queue or lambda configuration.
140type Config struct {
141 ID string `xml:"Id,omitempty"`
142 Arn Arn `xml:"-"`
143 Events []EventType `xml:"Event"`
144 Filter *Filter `xml:"Filter,omitempty"`
145}
146
147// NewConfig creates one notification config and sets the given ARN
148func NewConfig(arn Arn) Config {
149 return Config{Arn: arn, Filter: &Filter{}}
150}
151
152// AddEvents adds one event to the current notification config
153func (t *Config) AddEvents(events ...EventType) {
154 t.Events = append(t.Events, events...)
155}
156
157// AddFilterSuffix sets the suffix configuration to the current notification config
158func (t *Config) AddFilterSuffix(suffix string) {
159 if t.Filter == nil {
160 t.Filter = &Filter{}
161 }
162 newFilterRule := FilterRule{Name: "suffix", Value: suffix}
163 // Replace any suffix rule if existing and add to the list otherwise
164 for index := range t.Filter.S3Key.FilterRules {
165 if t.Filter.S3Key.FilterRules[index].Name == "suffix" {
166 t.Filter.S3Key.FilterRules[index] = newFilterRule
167 return
168 }
169 }
170 t.Filter.S3Key.FilterRules = append(t.Filter.S3Key.FilterRules, newFilterRule)
171}
172
173// AddFilterPrefix sets the prefix configuration to the current notification config
174func (t *Config) AddFilterPrefix(prefix string) {
175 if t.Filter == nil {
176 t.Filter = &Filter{}
177 }
178 newFilterRule := FilterRule{Name: "prefix", Value: prefix}
179 // Replace any prefix rule if existing and add to the list otherwise
180 for index := range t.Filter.S3Key.FilterRules {
181 if t.Filter.S3Key.FilterRules[index].Name == "prefix" {
182 t.Filter.S3Key.FilterRules[index] = newFilterRule
183 return
184 }
185 }
186 t.Filter.S3Key.FilterRules = append(t.Filter.S3Key.FilterRules, newFilterRule)
187}
188
189// EqualEventTypeList tells whether a and b contain the same events
190func EqualEventTypeList(a, b []EventType) bool {
191 if len(a) != len(b) {
192 return false
193 }
194 setA := set.NewStringSet()
195 for _, i := range a {
196 setA.Add(string(i))
197 }
198
199 setB := set.NewStringSet()
200 for _, i := range b {
201 setB.Add(string(i))
202 }
203
204 return setA.Difference(setB).IsEmpty()
205}
206
207// EqualFilterRuleList tells whether a and b contain the same filters
208func EqualFilterRuleList(a, b []FilterRule) bool {
209 if len(a) != len(b) {
210 return false
211 }
212
213 setA := set.NewStringSet()
214 for _, i := range a {
215 setA.Add(fmt.Sprintf("%s-%s", i.Name, i.Value))
216 }
217
218 setB := set.NewStringSet()
219 for _, i := range b {
220 setB.Add(fmt.Sprintf("%s-%s", i.Name, i.Value))
221 }
222
223 return setA.Difference(setB).IsEmpty()
224}
225
226// Equal returns whether this `Config` is equal to another defined by the passed parameters
227func (t *Config) Equal(events []EventType, prefix, suffix string) bool {
228 if t == nil {
229 return false
230 }
231
232 // Compare events
233 passEvents := EqualEventTypeList(t.Events, events)
234
235 // Compare filters
236 var newFilterRules []FilterRule
237 if prefix != "" {
238 newFilterRules = append(newFilterRules, FilterRule{Name: "prefix", Value: prefix})
239 }
240 if suffix != "" {
241 newFilterRules = append(newFilterRules, FilterRule{Name: "suffix", Value: suffix})
242 }
243
244 var currentFilterRules []FilterRule
245 if t.Filter != nil {
246 currentFilterRules = t.Filter.S3Key.FilterRules
247 }
248
249 passFilters := EqualFilterRuleList(currentFilterRules, newFilterRules)
250 return passEvents && passFilters
251}
252
253// TopicConfig carries one single topic notification configuration
254type TopicConfig struct {
255 Config
256 Topic string `xml:"Topic"`
257}
258
259// QueueConfig carries one single queue notification configuration
260type QueueConfig struct {
261 Config
262 Queue string `xml:"Queue"`
263}
264
265// LambdaConfig carries one single cloudfunction notification configuration
266type LambdaConfig struct {
267 Config
268 Lambda string `xml:"CloudFunction"`
269}
270
271// Configuration - the struct that represents the whole XML to be sent to the web service
272type Configuration struct {
273 XMLName xml.Name `xml:"NotificationConfiguration"`
274 LambdaConfigs []LambdaConfig `xml:"CloudFunctionConfiguration"`
275 TopicConfigs []TopicConfig `xml:"TopicConfiguration"`
276 QueueConfigs []QueueConfig `xml:"QueueConfiguration"`
277}
278
279// AddTopic adds a given topic config to the general bucket notification config
280func (b *Configuration) AddTopic(topicConfig Config) bool {
281 newTopicConfig := TopicConfig{Config: topicConfig, Topic: topicConfig.Arn.String()}
282 for _, n := range b.TopicConfigs {
283 // If new config matches existing one
284 if n.Topic == newTopicConfig.Arn.String() && newTopicConfig.Filter == n.Filter {
285
286 existingConfig := set.NewStringSet()
287 for _, v := range n.Events {
288 existingConfig.Add(string(v))
289 }
290
291 newConfig := set.NewStringSet()
292 for _, v := range topicConfig.Events {
293 newConfig.Add(string(v))
294 }
295
296 if !newConfig.Intersection(existingConfig).IsEmpty() {
297 return false
298 }
299 }
300 }
301 b.TopicConfigs = append(b.TopicConfigs, newTopicConfig)
302 return true
303}
304
305// AddQueue adds a given queue config to the general bucket notification config
306func (b *Configuration) AddQueue(queueConfig Config) bool {
307 newQueueConfig := QueueConfig{Config: queueConfig, Queue: queueConfig.Arn.String()}
308 for _, n := range b.QueueConfigs {
309 if n.Queue == newQueueConfig.Arn.String() && newQueueConfig.Filter == n.Filter {
310
311 existingConfig := set.NewStringSet()
312 for _, v := range n.Events {
313 existingConfig.Add(string(v))
314 }
315
316 newConfig := set.NewStringSet()
317 for _, v := range queueConfig.Events {
318 newConfig.Add(string(v))
319 }
320
321 if !newConfig.Intersection(existingConfig).IsEmpty() {
322 return false
323 }
324 }
325 }
326 b.QueueConfigs = append(b.QueueConfigs, newQueueConfig)
327 return true
328}
329
330// AddLambda adds a given lambda config to the general bucket notification config
331func (b *Configuration) AddLambda(lambdaConfig Config) bool {
332 newLambdaConfig := LambdaConfig{Config: lambdaConfig, Lambda: lambdaConfig.Arn.String()}
333 for _, n := range b.LambdaConfigs {
334 if n.Lambda == newLambdaConfig.Arn.String() && newLambdaConfig.Filter == n.Filter {
335
336 existingConfig := set.NewStringSet()
337 for _, v := range n.Events {
338 existingConfig.Add(string(v))
339 }
340
341 newConfig := set.NewStringSet()
342 for _, v := range lambdaConfig.Events {
343 newConfig.Add(string(v))
344 }
345
346 if !newConfig.Intersection(existingConfig).IsEmpty() {
347 return false
348 }
349 }
350 }
351 b.LambdaConfigs = append(b.LambdaConfigs, newLambdaConfig)
352 return true
353}
354
355// RemoveTopicByArn removes all topic configurations that match the exact specified ARN
356func (b *Configuration) RemoveTopicByArn(arn Arn) {
357 var topics []TopicConfig
358 for _, topic := range b.TopicConfigs {
359 if topic.Topic != arn.String() {
360 topics = append(topics, topic)
361 }
362 }
363 b.TopicConfigs = topics
364}
365
366// ErrNoConfigMatch is returned when a notification configuration (sqs,sns,lambda) is not found when trying to delete
367var ErrNoConfigMatch = errors.New("no notification configuration matched")
368
369// RemoveTopicByArnEventsPrefixSuffix removes a topic configuration that match the exact specified ARN, events, prefix and suffix
370func (b *Configuration) RemoveTopicByArnEventsPrefixSuffix(arn Arn, events []EventType, prefix, suffix string) error {
371 removeIndex := -1
372 for i, v := range b.TopicConfigs {
373 // if it matches events and filters, mark the index for deletion
374 if v.Topic == arn.String() && v.Config.Equal(events, prefix, suffix) {
375 removeIndex = i
376 break // since we have at most one matching config
377 }
378 }
379 if removeIndex >= 0 {
380 b.TopicConfigs = append(b.TopicConfigs[:removeIndex], b.TopicConfigs[removeIndex+1:]...)
381 return nil
382 }
383 return ErrNoConfigMatch
384}
385
386// RemoveQueueByArn removes all queue configurations that match the exact specified ARN
387func (b *Configuration) RemoveQueueByArn(arn Arn) {
388 var queues []QueueConfig
389 for _, queue := range b.QueueConfigs {
390 if queue.Queue != arn.String() {
391 queues = append(queues, queue)
392 }
393 }
394 b.QueueConfigs = queues
395}
396
397// RemoveQueueByArnEventsPrefixSuffix removes a queue configuration that match the exact specified ARN, events, prefix and suffix
398func (b *Configuration) RemoveQueueByArnEventsPrefixSuffix(arn Arn, events []EventType, prefix, suffix string) error {
399 removeIndex := -1
400 for i, v := range b.QueueConfigs {
401 // if it matches events and filters, mark the index for deletion
402 if v.Queue == arn.String() && v.Config.Equal(events, prefix, suffix) {
403 removeIndex = i
404 break // since we have at most one matching config
405 }
406 }
407 if removeIndex >= 0 {
408 b.QueueConfigs = append(b.QueueConfigs[:removeIndex], b.QueueConfigs[removeIndex+1:]...)
409 return nil
410 }
411 return ErrNoConfigMatch
412}
413
414// RemoveLambdaByArn removes all lambda configurations that match the exact specified ARN
415func (b *Configuration) RemoveLambdaByArn(arn Arn) {
416 var lambdas []LambdaConfig
417 for _, lambda := range b.LambdaConfigs {
418 if lambda.Lambda != arn.String() {
419 lambdas = append(lambdas, lambda)
420 }
421 }
422 b.LambdaConfigs = lambdas
423}
424
425// RemoveLambdaByArnEventsPrefixSuffix removes a topic configuration that match the exact specified ARN, events, prefix and suffix
426func (b *Configuration) RemoveLambdaByArnEventsPrefixSuffix(arn Arn, events []EventType, prefix, suffix string) error {
427 removeIndex := -1
428 for i, v := range b.LambdaConfigs {
429 // if it matches events and filters, mark the index for deletion
430 if v.Lambda == arn.String() && v.Config.Equal(events, prefix, suffix) {
431 removeIndex = i
432 break // since we have at most one matching config
433 }
434 }
435 if removeIndex >= 0 {
436 b.LambdaConfigs = append(b.LambdaConfigs[:removeIndex], b.LambdaConfigs[removeIndex+1:]...)
437 return nil
438 }
439 return ErrNoConfigMatch
440}