github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/config/lambda/parse.go (about)

     1  // Copyright (c) 2015-2023 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package lambda
    19  
    20  import (
    21  	"context"
    22  	"errors"
    23  	"fmt"
    24  	"net/http"
    25  
    26  	"github.com/minio/minio/internal/config"
    27  	"github.com/minio/minio/internal/config/lambda/event"
    28  	"github.com/minio/minio/internal/config/lambda/target"
    29  	"github.com/minio/minio/internal/logger"
    30  	"github.com/minio/pkg/v2/env"
    31  	xnet "github.com/minio/pkg/v2/net"
    32  )
    33  
    34  // ErrTargetsOffline - Indicates single/multiple target failures.
    35  var ErrTargetsOffline = errors.New("one or more targets are offline. Please use `mc admin info --json` to check the offline targets")
    36  
    37  // TestSubSysLambdaTargets - tests notification targets of given subsystem
    38  func TestSubSysLambdaTargets(ctx context.Context, cfg config.Config, subSys string, transport *http.Transport) error {
    39  	if err := checkValidLambdaKeysForSubSys(subSys, cfg[subSys]); err != nil {
    40  		return err
    41  	}
    42  
    43  	targetList, err := fetchSubSysTargets(ctx, cfg, subSys, transport)
    44  	if err != nil {
    45  		return err
    46  	}
    47  
    48  	for _, target := range targetList {
    49  		defer target.Close()
    50  	}
    51  
    52  	for _, target := range targetList {
    53  		yes, err := target.IsActive()
    54  		if err == nil && !yes {
    55  			err = ErrTargetsOffline
    56  		}
    57  		if err != nil {
    58  			return fmt.Errorf("error (%s): %w", target.ID(), err)
    59  		}
    60  	}
    61  
    62  	return nil
    63  }
    64  
    65  func fetchSubSysTargets(ctx context.Context, cfg config.Config, subSys string, transport *http.Transport) (targets []event.Target, err error) {
    66  	if err := checkValidLambdaKeysForSubSys(subSys, cfg[subSys]); err != nil {
    67  		return nil, err
    68  	}
    69  
    70  	if subSys == config.LambdaWebhookSubSys {
    71  		webhookTargets, err := GetLambdaWebhook(cfg[config.LambdaWebhookSubSys], transport)
    72  		if err != nil {
    73  			return nil, err
    74  		}
    75  		for id, args := range webhookTargets {
    76  			if !args.Enable {
    77  				continue
    78  			}
    79  			t, err := target.NewWebhookTarget(ctx, id, args, logger.LogOnceIf, transport)
    80  			if err != nil {
    81  				return nil, err
    82  			}
    83  			targets = append(targets, t)
    84  		}
    85  	}
    86  	return targets, nil
    87  }
    88  
    89  // FetchEnabledTargets - Returns a set of configured TargetList
    90  func FetchEnabledTargets(ctx context.Context, cfg config.Config, transport *http.Transport) (*event.TargetList, error) {
    91  	targetList := event.NewTargetList()
    92  	for _, subSys := range config.LambdaSubSystems.ToSlice() {
    93  		targets, err := fetchSubSysTargets(ctx, cfg, subSys, transport)
    94  		if err != nil {
    95  			return nil, err
    96  		}
    97  		for _, t := range targets {
    98  			if err = targetList.Add(t); err != nil {
    99  				return nil, err
   100  			}
   101  		}
   102  	}
   103  	return targetList, nil
   104  }
   105  
   106  // DefaultLambdaKVS - default notification list of kvs.
   107  var (
   108  	DefaultLambdaKVS = map[string]config.KVS{
   109  		config.LambdaWebhookSubSys: DefaultWebhookKVS,
   110  	}
   111  )
   112  
   113  // DefaultWebhookKVS - default KV for webhook config
   114  var (
   115  	DefaultWebhookKVS = config.KVS{
   116  		config.KV{
   117  			Key:   config.Enable,
   118  			Value: config.EnableOff,
   119  		},
   120  		config.KV{
   121  			Key:   target.WebhookEndpoint,
   122  			Value: "",
   123  		},
   124  		config.KV{
   125  			Key:   target.WebhookAuthToken,
   126  			Value: "",
   127  		},
   128  		config.KV{
   129  			Key:   target.WebhookClientCert,
   130  			Value: "",
   131  		},
   132  		config.KV{
   133  			Key:   target.WebhookClientKey,
   134  			Value: "",
   135  		},
   136  	}
   137  )
   138  
   139  func checkValidLambdaKeysForSubSys(subSys string, tgt map[string]config.KVS) error {
   140  	validKVS, ok := DefaultLambdaKVS[subSys]
   141  	if !ok {
   142  		return nil
   143  	}
   144  	for tname, kv := range tgt {
   145  		subSysTarget := subSys
   146  		if tname != config.Default {
   147  			subSysTarget = subSys + config.SubSystemSeparator + tname
   148  		}
   149  		if v, ok := kv.Lookup(config.Enable); ok && v == config.EnableOn {
   150  			if err := config.CheckValidKeys(subSysTarget, kv, validKVS); err != nil {
   151  				return err
   152  			}
   153  		}
   154  	}
   155  	return nil
   156  }
   157  
   158  // GetLambdaWebhook - returns a map of registered notification 'webhook' targets
   159  func GetLambdaWebhook(webhookKVS map[string]config.KVS, transport *http.Transport) (
   160  	map[string]target.WebhookArgs, error,
   161  ) {
   162  	webhookTargets := make(map[string]target.WebhookArgs)
   163  	for k, kv := range config.Merge(webhookKVS, target.EnvWebhookEnable, DefaultWebhookKVS) {
   164  		enableEnv := target.EnvWebhookEnable
   165  		if k != config.Default {
   166  			enableEnv = enableEnv + config.Default + k
   167  		}
   168  		enabled, err := config.ParseBool(env.Get(enableEnv, kv.Get(config.Enable)))
   169  		if err != nil {
   170  			return nil, err
   171  		}
   172  		if !enabled {
   173  			continue
   174  		}
   175  		urlEnv := target.EnvWebhookEndpoint
   176  		if k != config.Default {
   177  			urlEnv = urlEnv + config.Default + k
   178  		}
   179  		url, err := xnet.ParseHTTPURL(env.Get(urlEnv, kv.Get(target.WebhookEndpoint)))
   180  		if err != nil {
   181  			return nil, err
   182  		}
   183  		authEnv := target.EnvWebhookAuthToken
   184  		if k != config.Default {
   185  			authEnv = authEnv + config.Default + k
   186  		}
   187  		clientCertEnv := target.EnvWebhookClientCert
   188  		if k != config.Default {
   189  			clientCertEnv = clientCertEnv + config.Default + k
   190  		}
   191  
   192  		clientKeyEnv := target.EnvWebhookClientKey
   193  		if k != config.Default {
   194  			clientKeyEnv = clientKeyEnv + config.Default + k
   195  		}
   196  
   197  		webhookArgs := target.WebhookArgs{
   198  			Enable:     enabled,
   199  			Endpoint:   *url,
   200  			Transport:  transport,
   201  			AuthToken:  env.Get(authEnv, kv.Get(target.WebhookAuthToken)),
   202  			ClientCert: env.Get(clientCertEnv, kv.Get(target.WebhookClientCert)),
   203  			ClientKey:  env.Get(clientKeyEnv, kv.Get(target.WebhookClientKey)),
   204  		}
   205  		if err = webhookArgs.Validate(); err != nil {
   206  			return nil, err
   207  		}
   208  		webhookTargets[k] = webhookArgs
   209  	}
   210  	return webhookTargets, nil
   211  }