github.com/argoproj/argo-events@v1.9.1/eventsources/sources/minio/start.go (about) 1 /* 2 Copyright 2018 BlackRock, Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package minio 18 19 import ( 20 "context" 21 "crypto/tls" 22 "crypto/x509" 23 "encoding/json" 24 "fmt" 25 "net/http" 26 "time" 27 28 "github.com/minio/minio-go/v7" 29 "github.com/minio/minio-go/v7/pkg/credentials" 30 "github.com/minio/minio-go/v7/pkg/notification" 31 "go.uber.org/zap" 32 33 "github.com/argoproj/argo-events/common" 34 "github.com/argoproj/argo-events/common/logging" 35 eventsourcecommon "github.com/argoproj/argo-events/eventsources/common" 36 "github.com/argoproj/argo-events/eventsources/sources" 37 metrics "github.com/argoproj/argo-events/metrics" 38 apicommon "github.com/argoproj/argo-events/pkg/apis/common" 39 "github.com/argoproj/argo-events/pkg/apis/events" 40 ) 41 42 // EventListener implements Eventing for minio event sources 43 type EventListener struct { 44 EventSourceName string 45 EventName string 46 MinioEventSource apicommon.S3Artifact 47 Metrics *metrics.Metrics 48 } 49 50 // GetEventSourceName returns name of event source 51 func (el *EventListener) GetEventSourceName() string { 52 return el.EventSourceName 53 } 54 55 // GetEventName returns name of event 56 func (el *EventListener) GetEventName() string { 57 return el.EventName 58 } 59 60 // GetEventSourceType return type of event server 61 func (el *EventListener) GetEventSourceType() apicommon.EventSourceType { 62 return apicommon.MinioEvent 63 } 64 65 // StartListening starts listening events 66 func (el *EventListener) StartListening(ctx context.Context, dispatch func([]byte, ...eventsourcecommon.Option) error) error { 67 log := logging.FromContext(ctx). 68 With(logging.LabelEventSourceType, el.GetEventSourceType(), logging.LabelEventName, el.GetEventName(), 69 zap.String("bucketName", el.MinioEventSource.Bucket.Name)) 70 defer sources.Recover(el.GetEventName()) 71 72 log.Info("starting minio event source...") 73 74 minioEventSource := &el.MinioEventSource 75 76 log.Info("retrieving access and secret key...") 77 accessKey, err := common.GetSecretFromVolume(minioEventSource.AccessKey) 78 if err != nil { 79 return fmt.Errorf("failed to get the access key for event source %s, %w", el.GetEventName(), err) 80 } 81 secretKey, err := common.GetSecretFromVolume(minioEventSource.SecretKey) 82 if err != nil { 83 return fmt.Errorf("failed to retrieve the secret key for event source %s, %w", el.GetEventName(), err) 84 } 85 86 var minioClient *minio.Client 87 var clientErr error 88 if minioEventSource.CACertificate != nil { 89 log.Info("retrieving CA certificate...") 90 caCertificate, err := common.GetSecretFromVolume(minioEventSource.CACertificate) 91 if err != nil { 92 return fmt.Errorf("failed to get the CA certificate for event source %s, %w", el.GetEventName(), err) 93 } 94 caCertPool := x509.NewCertPool() 95 caCertPool.AppendCertsFromPEM([]byte(caCertificate)) 96 tlsConfig := &tls.Config{ 97 RootCAs: caCertPool, 98 } 99 log.Info("setting up a minio client with custom CA...") 100 minioClient, clientErr = minio.New(minioEventSource.Endpoint, &minio.Options{ 101 Creds: credentials.NewStaticV4(accessKey, secretKey, ""), 102 Secure: !minioEventSource.Insecure, 103 Transport: &http.Transport{ 104 TLSClientConfig: tlsConfig, 105 }, 106 }) 107 } else { 108 log.Info("setting up a minio client...") 109 minioClient, clientErr = minio.New(minioEventSource.Endpoint, &minio.Options{ 110 Creds: credentials.NewStaticV4(accessKey, secretKey, ""), 111 Secure: !minioEventSource.Insecure, 112 }) 113 } 114 if clientErr != nil { 115 return fmt.Errorf("failed to create a client for event source %s, %w", el.GetEventName(), err) 116 } 117 118 prefix, suffix := getFilters(minioEventSource) 119 120 log.Info("started listening to bucket notifications...") 121 for notification := range minioClient.ListenBucketNotification(ctx, minioEventSource.Bucket.Name, prefix, suffix, minioEventSource.Events) { 122 if notification.Err != nil { 123 log.Errorw("invalid notification", zap.Error(notification.Err)) 124 continue 125 } 126 127 if err := el.handleOne(notification, dispatch, log); err != nil { 128 log.Errorw("failed to process a Minio event", zap.Error(err)) 129 el.Metrics.EventProcessingFailed(el.GetEventSourceName(), el.GetEventName()) 130 } 131 } 132 133 log.Info("event source is stopped") 134 return nil 135 } 136 137 func (el *EventListener) handleOne(notification notification.Info, dispatch func([]byte, ...eventsourcecommon.Option) error, log *zap.SugaredLogger) error { 138 defer func(start time.Time) { 139 el.Metrics.EventProcessingDuration(el.GetEventSourceName(), el.GetEventName(), float64(time.Since(start)/time.Millisecond)) 140 }(time.Now()) 141 142 eventData := &events.MinioEventData{Notification: notification.Records, Metadata: el.MinioEventSource.Metadata} 143 eventBytes, err := json.Marshal(eventData) 144 if err != nil { 145 return fmt.Errorf("failed to marshal the event data, rejecting the event, %w", err) 146 } 147 148 log.Info("dispatching the event on data channel...") 149 if err = dispatch(eventBytes); err != nil { 150 return fmt.Errorf("failed to dispatch minio event, %w", err) 151 } 152 return nil 153 } 154 155 func getFilters(eventSource *apicommon.S3Artifact) (string, string) { 156 if eventSource.Filter == nil { 157 return "", "" 158 } 159 if eventSource.Filter.Prefix != "" && eventSource.Filter.Suffix != "" { 160 return eventSource.Filter.Prefix, eventSource.Filter.Suffix 161 } 162 if eventSource.Filter.Prefix != "" { 163 return eventSource.Filter.Prefix, "" 164 } 165 if eventSource.Filter.Suffix != "" { 166 return "", eventSource.Filter.Suffix 167 } 168 return "", "" 169 }