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  }