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

     1  // Copyright (c) 2015-2021 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 notify
    19  
    20  import (
    21  	"context"
    22  	"crypto/tls"
    23  	"crypto/x509"
    24  	"errors"
    25  	"fmt"
    26  	"net/http"
    27  	"strconv"
    28  	"strings"
    29  	"time"
    30  
    31  	"github.com/minio/minio/internal/config"
    32  	"github.com/minio/minio/internal/event"
    33  	"github.com/minio/minio/internal/event/target"
    34  	"github.com/minio/minio/internal/logger"
    35  	"github.com/minio/pkg/v2/env"
    36  	xnet "github.com/minio/pkg/v2/net"
    37  )
    38  
    39  const (
    40  	formatNamespace = "namespace"
    41  )
    42  
    43  // ErrTargetsOffline - Indicates single/multiple target failures.
    44  var ErrTargetsOffline = errors.New("one or more targets are offline. Please use `mc admin info --json` to check the offline targets")
    45  
    46  // TestSubSysNotificationTargets - tests notification targets of given subsystem
    47  func TestSubSysNotificationTargets(ctx context.Context, cfg config.Config, subSys string, transport *http.Transport) error {
    48  	if err := checkValidNotificationKeysForSubSys(subSys, cfg[subSys]); err != nil {
    49  		return err
    50  	}
    51  
    52  	targetList, err := fetchSubSysTargets(ctx, cfg, subSys, transport)
    53  	if err != nil {
    54  		return err
    55  	}
    56  
    57  	for _, target := range targetList {
    58  		defer target.Close()
    59  	}
    60  
    61  	tgts, ok := ctx.Value(config.ContextKeyForTargetFromConfig).(map[string]bool)
    62  	if !ok {
    63  		tgts = make(map[string]bool)
    64  	}
    65  	for _, target := range targetList {
    66  		if tgts[target.ID().ID] {
    67  			// When target set should be online
    68  			yes, err := target.IsActive()
    69  			if err == nil && !yes {
    70  				err = ErrTargetsOffline
    71  			}
    72  			if err != nil {
    73  				return fmt.Errorf("error (%s): %w", target.ID(), err)
    74  			}
    75  		} else {
    76  			// Just for call init.
    77  			// Ignore target is online or offline
    78  			_, _ = target.IsActive()
    79  		}
    80  	}
    81  
    82  	return nil
    83  }
    84  
    85  func fetchSubSysTargets(ctx context.Context, cfg config.Config, subSys string, transport *http.Transport) (targets []event.Target, err error) {
    86  	if err := checkValidNotificationKeysForSubSys(subSys, cfg[subSys]); err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	switch subSys {
    91  	case config.NotifyAMQPSubSys:
    92  		amqpTargets, err := GetNotifyAMQP(cfg[config.NotifyAMQPSubSys])
    93  		if err != nil {
    94  			return nil, err
    95  		}
    96  		for id, args := range amqpTargets {
    97  			if !args.Enable {
    98  				continue
    99  			}
   100  			t, err := target.NewAMQPTarget(id, args, logger.LogOnceIf)
   101  			if err != nil {
   102  				return nil, err
   103  			}
   104  			targets = append(targets, t)
   105  		}
   106  	case config.NotifyESSubSys:
   107  		esTargets, err := GetNotifyES(cfg[config.NotifyESSubSys], transport)
   108  		if err != nil {
   109  			return nil, err
   110  		}
   111  		for id, args := range esTargets {
   112  			if !args.Enable {
   113  				continue
   114  			}
   115  			t, err := target.NewElasticsearchTarget(id, args, logger.LogOnceIf)
   116  			if err != nil {
   117  				return nil, err
   118  			}
   119  			targets = append(targets, t)
   120  
   121  		}
   122  	case config.NotifyKafkaSubSys:
   123  		kafkaTargets, err := GetNotifyKafka(cfg[config.NotifyKafkaSubSys])
   124  		if err != nil {
   125  			return nil, err
   126  		}
   127  		for id, args := range kafkaTargets {
   128  			if !args.Enable {
   129  				continue
   130  			}
   131  			args.TLS.RootCAs = transport.TLSClientConfig.RootCAs
   132  			t, err := target.NewKafkaTarget(id, args, logger.LogOnceIf)
   133  			if err != nil {
   134  				return nil, err
   135  			}
   136  			targets = append(targets, t)
   137  
   138  		}
   139  
   140  	case config.NotifyMQTTSubSys:
   141  		mqttTargets, err := GetNotifyMQTT(cfg[config.NotifyMQTTSubSys], transport.TLSClientConfig.RootCAs)
   142  		if err != nil {
   143  			return nil, err
   144  		}
   145  		for id, args := range mqttTargets {
   146  			if !args.Enable {
   147  				continue
   148  			}
   149  			args.RootCAs = transport.TLSClientConfig.RootCAs
   150  			t, err := target.NewMQTTTarget(id, args, logger.LogOnceIf)
   151  			if err != nil {
   152  				return nil, err
   153  			}
   154  			targets = append(targets, t)
   155  		}
   156  	case config.NotifyMySQLSubSys:
   157  		mysqlTargets, err := GetNotifyMySQL(cfg[config.NotifyMySQLSubSys])
   158  		if err != nil {
   159  			return nil, err
   160  		}
   161  		for id, args := range mysqlTargets {
   162  			if !args.Enable {
   163  				continue
   164  			}
   165  			t, err := target.NewMySQLTarget(id, args, logger.LogOnceIf)
   166  			if err != nil {
   167  				return nil, err
   168  			}
   169  			targets = append(targets, t)
   170  		}
   171  	case config.NotifyNATSSubSys:
   172  		natsTargets, err := GetNotifyNATS(cfg[config.NotifyNATSSubSys], transport.TLSClientConfig.RootCAs)
   173  		if err != nil {
   174  			return nil, err
   175  		}
   176  		for id, args := range natsTargets {
   177  			if !args.Enable {
   178  				continue
   179  			}
   180  			t, err := target.NewNATSTarget(id, args, logger.LogOnceIf)
   181  			if err != nil {
   182  				return nil, err
   183  			}
   184  			targets = append(targets, t)
   185  		}
   186  	case config.NotifyNSQSubSys:
   187  		nsqTargets, err := GetNotifyNSQ(cfg[config.NotifyNSQSubSys])
   188  		if err != nil {
   189  			return nil, err
   190  		}
   191  		for id, args := range nsqTargets {
   192  			if !args.Enable {
   193  				continue
   194  			}
   195  			t, err := target.NewNSQTarget(id, args, logger.LogOnceIf)
   196  			if err != nil {
   197  				return nil, err
   198  			}
   199  			targets = append(targets, t)
   200  		}
   201  	case config.NotifyPostgresSubSys:
   202  		postgresTargets, err := GetNotifyPostgres(cfg[config.NotifyPostgresSubSys])
   203  		if err != nil {
   204  			return nil, err
   205  		}
   206  		for id, args := range postgresTargets {
   207  			if !args.Enable {
   208  				continue
   209  			}
   210  			t, err := target.NewPostgreSQLTarget(id, args, logger.LogOnceIf)
   211  			if err != nil {
   212  				return nil, err
   213  			}
   214  			targets = append(targets, t)
   215  		}
   216  	case config.NotifyRedisSubSys:
   217  		redisTargets, err := GetNotifyRedis(cfg[config.NotifyRedisSubSys])
   218  		if err != nil {
   219  			return nil, err
   220  		}
   221  		for id, args := range redisTargets {
   222  			if !args.Enable {
   223  				continue
   224  			}
   225  			t, err := target.NewRedisTarget(id, args, logger.LogOnceIf)
   226  			if err != nil {
   227  				return nil, err
   228  			}
   229  			targets = append(targets, t)
   230  		}
   231  	case config.NotifyWebhookSubSys:
   232  		webhookTargets, err := GetNotifyWebhook(cfg[config.NotifyWebhookSubSys], transport)
   233  		if err != nil {
   234  			return nil, err
   235  		}
   236  		for id, args := range webhookTargets {
   237  			if !args.Enable {
   238  				continue
   239  			}
   240  			t, err := target.NewWebhookTarget(ctx, id, args, logger.LogOnceIf, transport)
   241  			if err != nil {
   242  				return nil, err
   243  			}
   244  			targets = append(targets, t)
   245  		}
   246  	}
   247  	return targets, nil
   248  }
   249  
   250  // FetchEnabledTargets - Returns a set of configured TargetList
   251  func FetchEnabledTargets(ctx context.Context, cfg config.Config, transport *http.Transport) (_ *event.TargetList, err error) {
   252  	targetList := event.NewTargetList(ctx)
   253  	for _, subSys := range config.NotifySubSystems.ToSlice() {
   254  		targets, err := fetchSubSysTargets(ctx, cfg, subSys, transport)
   255  		if err != nil {
   256  			return nil, err
   257  		}
   258  		for _, t := range targets {
   259  			if err = targetList.Add(t); err != nil {
   260  				return nil, err
   261  			}
   262  		}
   263  	}
   264  	return targetList, nil
   265  }
   266  
   267  // DefaultNotificationKVS - default notification list of kvs.
   268  var (
   269  	DefaultNotificationKVS = map[string]config.KVS{
   270  		config.NotifyAMQPSubSys:     DefaultAMQPKVS,
   271  		config.NotifyKafkaSubSys:    DefaultKafkaKVS,
   272  		config.NotifyMQTTSubSys:     DefaultMQTTKVS,
   273  		config.NotifyMySQLSubSys:    DefaultMySQLKVS,
   274  		config.NotifyNATSSubSys:     DefaultNATSKVS,
   275  		config.NotifyNSQSubSys:      DefaultNSQKVS,
   276  		config.NotifyPostgresSubSys: DefaultPostgresKVS,
   277  		config.NotifyRedisSubSys:    DefaultRedisKVS,
   278  		config.NotifyWebhookSubSys:  DefaultWebhookKVS,
   279  		config.NotifyESSubSys:       DefaultESKVS,
   280  	}
   281  )
   282  
   283  func checkValidNotificationKeysForSubSys(subSys string, tgt map[string]config.KVS) error {
   284  	validKVS, ok := DefaultNotificationKVS[subSys]
   285  	if !ok {
   286  		return nil
   287  	}
   288  	for tname, kv := range tgt {
   289  		subSysTarget := subSys
   290  		if tname != config.Default {
   291  			subSysTarget = subSys + config.SubSystemSeparator + tname
   292  		}
   293  		if v, ok := kv.Lookup(config.Enable); ok && v == config.EnableOn {
   294  			if err := config.CheckValidKeys(subSysTarget, kv, validKVS); err != nil {
   295  				return err
   296  			}
   297  		}
   298  	}
   299  	return nil
   300  }
   301  
   302  // DefaultKafkaKVS - default KV for kafka target
   303  var (
   304  	DefaultKafkaKVS = config.KVS{
   305  		config.KV{
   306  			Key:   config.Enable,
   307  			Value: config.EnableOff,
   308  		},
   309  		config.KV{
   310  			Key:   target.KafkaTopic,
   311  			Value: "",
   312  		},
   313  		config.KV{
   314  			Key:   target.KafkaBrokers,
   315  			Value: "",
   316  		},
   317  		config.KV{
   318  			Key:   target.KafkaSASLUsername,
   319  			Value: "",
   320  		},
   321  		config.KV{
   322  			Key:   target.KafkaSASLPassword,
   323  			Value: "",
   324  		},
   325  		config.KV{
   326  			Key:   target.KafkaSASLMechanism,
   327  			Value: "plain",
   328  		},
   329  		config.KV{
   330  			Key:   target.KafkaClientTLSCert,
   331  			Value: "",
   332  		},
   333  		config.KV{
   334  			Key:   target.KafkaClientTLSKey,
   335  			Value: "",
   336  		},
   337  		config.KV{
   338  			Key:   target.KafkaTLSClientAuth,
   339  			Value: "0",
   340  		},
   341  		config.KV{
   342  			Key:   target.KafkaSASL,
   343  			Value: config.EnableOff,
   344  		},
   345  		config.KV{
   346  			Key:   target.KafkaTLS,
   347  			Value: config.EnableOff,
   348  		},
   349  		config.KV{
   350  			Key:   target.KafkaTLSSkipVerify,
   351  			Value: config.EnableOff,
   352  		},
   353  		config.KV{
   354  			Key:   target.KafkaQueueLimit,
   355  			Value: "0",
   356  		},
   357  		config.KV{
   358  			Key:   target.KafkaQueueDir,
   359  			Value: "",
   360  		},
   361  		config.KV{
   362  			Key:   target.KafkaVersion,
   363  			Value: "",
   364  		},
   365  		config.KV{
   366  			Key:   target.KafkaBatchSize,
   367  			Value: "0",
   368  		},
   369  		config.KV{
   370  			Key:   target.KafkaCompressionCodec,
   371  			Value: "",
   372  		},
   373  		config.KV{
   374  			Key:   target.KafkaCompressionLevel,
   375  			Value: "",
   376  		},
   377  	}
   378  )
   379  
   380  // GetNotifyKafka - returns a map of registered notification 'kafka' targets
   381  func GetNotifyKafka(kafkaKVS map[string]config.KVS) (map[string]target.KafkaArgs, error) {
   382  	kafkaTargets := make(map[string]target.KafkaArgs)
   383  	for k, kv := range config.Merge(kafkaKVS, target.EnvKafkaEnable, DefaultKafkaKVS) {
   384  		enableEnv := target.EnvKafkaEnable
   385  		if k != config.Default {
   386  			enableEnv = enableEnv + config.Default + k
   387  		}
   388  		enabled, err := config.ParseBool(env.Get(enableEnv, kv.Get(config.Enable)))
   389  		if err != nil {
   390  			return nil, err
   391  		}
   392  		if !enabled {
   393  			continue
   394  		}
   395  		var brokers []xnet.Host
   396  		brokersEnv := target.EnvKafkaBrokers
   397  		if k != config.Default {
   398  			brokersEnv = brokersEnv + config.Default + k
   399  		}
   400  		kafkaBrokers := env.Get(brokersEnv, kv.Get(target.KafkaBrokers))
   401  		if len(kafkaBrokers) == 0 {
   402  			return nil, config.Errorf("kafka 'brokers' cannot be empty")
   403  		}
   404  		for _, s := range strings.Split(kafkaBrokers, config.ValueSeparator) {
   405  			var host *xnet.Host
   406  			host, err = xnet.ParseHost(s)
   407  			if err != nil {
   408  				break
   409  			}
   410  			brokers = append(brokers, *host)
   411  		}
   412  		if err != nil {
   413  			return nil, err
   414  		}
   415  
   416  		queueLimitEnv := target.EnvKafkaQueueLimit
   417  		if k != config.Default {
   418  			queueLimitEnv = queueLimitEnv + config.Default + k
   419  		}
   420  		queueLimit, err := strconv.ParseUint(env.Get(queueLimitEnv, kv.Get(target.KafkaQueueLimit)), 10, 64)
   421  		if err != nil {
   422  			return nil, err
   423  		}
   424  
   425  		clientAuthEnv := target.EnvKafkaTLSClientAuth
   426  		if k != config.Default {
   427  			clientAuthEnv = clientAuthEnv + config.Default + k
   428  		}
   429  		clientAuth, err := strconv.Atoi(env.Get(clientAuthEnv, kv.Get(target.KafkaTLSClientAuth)))
   430  		if err != nil {
   431  			return nil, err
   432  		}
   433  
   434  		topicEnv := target.EnvKafkaTopic
   435  		if k != config.Default {
   436  			topicEnv = topicEnv + config.Default + k
   437  		}
   438  
   439  		queueDirEnv := target.EnvKafkaQueueDir
   440  		if k != config.Default {
   441  			queueDirEnv = queueDirEnv + config.Default + k
   442  		}
   443  
   444  		versionEnv := target.EnvKafkaVersion
   445  		if k != config.Default {
   446  			versionEnv = versionEnv + config.Default + k
   447  		}
   448  
   449  		batchSizeEnv := target.EnvKafkaBatchSize
   450  		if k != config.Default {
   451  			batchSizeEnv = batchSizeEnv + config.Default + k
   452  		}
   453  		batchSize, err := strconv.ParseUint(env.Get(batchSizeEnv, kv.Get(target.KafkaBatchSize)), 10, 32)
   454  		if err != nil {
   455  			return nil, err
   456  		}
   457  
   458  		kafkaArgs := target.KafkaArgs{
   459  			Enable:     enabled,
   460  			Brokers:    brokers,
   461  			Topic:      env.Get(topicEnv, kv.Get(target.KafkaTopic)),
   462  			QueueDir:   env.Get(queueDirEnv, kv.Get(target.KafkaQueueDir)),
   463  			QueueLimit: queueLimit,
   464  			Version:    env.Get(versionEnv, kv.Get(target.KafkaVersion)),
   465  			BatchSize:  uint32(batchSize),
   466  		}
   467  
   468  		tlsEnableEnv := target.EnvKafkaTLS
   469  		if k != config.Default {
   470  			tlsEnableEnv = tlsEnableEnv + config.Default + k
   471  		}
   472  		tlsSkipVerifyEnv := target.EnvKafkaTLSSkipVerify
   473  		if k != config.Default {
   474  			tlsSkipVerifyEnv = tlsSkipVerifyEnv + config.Default + k
   475  		}
   476  
   477  		tlsClientTLSCertEnv := target.EnvKafkaClientTLSCert
   478  		if k != config.Default {
   479  			tlsClientTLSCertEnv = tlsClientTLSCertEnv + config.Default + k
   480  		}
   481  
   482  		tlsClientTLSKeyEnv := target.EnvKafkaClientTLSKey
   483  		if k != config.Default {
   484  			tlsClientTLSKeyEnv = tlsClientTLSKeyEnv + config.Default + k
   485  		}
   486  
   487  		kafkaArgs.TLS.Enable = env.Get(tlsEnableEnv, kv.Get(target.KafkaTLS)) == config.EnableOn
   488  		kafkaArgs.TLS.SkipVerify = env.Get(tlsSkipVerifyEnv, kv.Get(target.KafkaTLSSkipVerify)) == config.EnableOn
   489  		kafkaArgs.TLS.ClientAuth = tls.ClientAuthType(clientAuth)
   490  
   491  		kafkaArgs.TLS.ClientTLSCert = env.Get(tlsClientTLSCertEnv, kv.Get(target.KafkaClientTLSCert))
   492  		kafkaArgs.TLS.ClientTLSKey = env.Get(tlsClientTLSKeyEnv, kv.Get(target.KafkaClientTLSKey))
   493  
   494  		compressionCodecEnv := target.EnvKafkaProducerCompressionCodec
   495  		if k != config.Default {
   496  			compressionCodecEnv = compressionCodecEnv + config.Default + k
   497  		}
   498  		kafkaArgs.Producer.Compression = env.Get(compressionCodecEnv, kv.Get(target.KafkaCompressionCodec))
   499  
   500  		compressionLevelEnv := target.EnvKafkaProducerCompressionLevel
   501  		if k != config.Default {
   502  			compressionLevelEnv = compressionLevelEnv + config.Default + k
   503  		}
   504  		compressionLevel, _ := strconv.Atoi(env.Get(compressionLevelEnv, kv.Get(target.KafkaCompressionLevel)))
   505  		kafkaArgs.Producer.CompressionLevel = compressionLevel
   506  
   507  		saslEnableEnv := target.EnvKafkaSASLEnable
   508  		if k != config.Default {
   509  			saslEnableEnv = saslEnableEnv + config.Default + k
   510  		}
   511  		saslUsernameEnv := target.EnvKafkaSASLUsername
   512  		if k != config.Default {
   513  			saslUsernameEnv = saslUsernameEnv + config.Default + k
   514  		}
   515  		saslPasswordEnv := target.EnvKafkaSASLPassword
   516  		if k != config.Default {
   517  			saslPasswordEnv = saslPasswordEnv + config.Default + k
   518  		}
   519  		saslMechanismEnv := target.EnvKafkaSASLMechanism
   520  		if k != config.Default {
   521  			saslMechanismEnv = saslMechanismEnv + config.Default + k
   522  		}
   523  		kafkaArgs.SASL.Enable = env.Get(saslEnableEnv, kv.Get(target.KafkaSASL)) == config.EnableOn
   524  		kafkaArgs.SASL.User = env.Get(saslUsernameEnv, kv.Get(target.KafkaSASLUsername))
   525  		kafkaArgs.SASL.Password = env.Get(saslPasswordEnv, kv.Get(target.KafkaSASLPassword))
   526  		kafkaArgs.SASL.Mechanism = env.Get(saslMechanismEnv, kv.Get(target.KafkaSASLMechanism))
   527  
   528  		if err = kafkaArgs.Validate(); err != nil {
   529  			return nil, err
   530  		}
   531  
   532  		kafkaTargets[k] = kafkaArgs
   533  	}
   534  
   535  	return kafkaTargets, nil
   536  }
   537  
   538  // DefaultMQTTKVS - default MQTT config
   539  var (
   540  	DefaultMQTTKVS = config.KVS{
   541  		config.KV{
   542  			Key:   config.Enable,
   543  			Value: config.EnableOff,
   544  		},
   545  		config.KV{
   546  			Key:   target.MqttBroker,
   547  			Value: "",
   548  		},
   549  		config.KV{
   550  			Key:   target.MqttTopic,
   551  			Value: "",
   552  		},
   553  		config.KV{
   554  			Key:   target.MqttPassword,
   555  			Value: "",
   556  		},
   557  		config.KV{
   558  			Key:   target.MqttUsername,
   559  			Value: "",
   560  		},
   561  		config.KV{
   562  			Key:   target.MqttQoS,
   563  			Value: "0",
   564  		},
   565  		config.KV{
   566  			Key:   target.MqttKeepAliveInterval,
   567  			Value: "0s",
   568  		},
   569  		config.KV{
   570  			Key:   target.MqttReconnectInterval,
   571  			Value: "0s",
   572  		},
   573  		config.KV{
   574  			Key:   target.MqttQueueDir,
   575  			Value: "",
   576  		},
   577  		config.KV{
   578  			Key:   target.MqttQueueLimit,
   579  			Value: "0",
   580  		},
   581  	}
   582  )
   583  
   584  // GetNotifyMQTT - returns a map of registered notification 'mqtt' targets
   585  func GetNotifyMQTT(mqttKVS map[string]config.KVS, rootCAs *x509.CertPool) (map[string]target.MQTTArgs, error) {
   586  	mqttTargets := make(map[string]target.MQTTArgs)
   587  	for k, kv := range config.Merge(mqttKVS, target.EnvMQTTEnable, DefaultMQTTKVS) {
   588  		enableEnv := target.EnvMQTTEnable
   589  		if k != config.Default {
   590  			enableEnv = enableEnv + config.Default + k
   591  		}
   592  
   593  		enabled, err := config.ParseBool(env.Get(enableEnv, kv.Get(config.Enable)))
   594  		if err != nil {
   595  			return nil, err
   596  		}
   597  		if !enabled {
   598  			continue
   599  		}
   600  
   601  		brokerEnv := target.EnvMQTTBroker
   602  		if k != config.Default {
   603  			brokerEnv = brokerEnv + config.Default + k
   604  		}
   605  
   606  		brokerURL, err := xnet.ParseURL(env.Get(brokerEnv, kv.Get(target.MqttBroker)))
   607  		if err != nil {
   608  			return nil, err
   609  		}
   610  
   611  		reconnectIntervalEnv := target.EnvMQTTReconnectInterval
   612  		if k != config.Default {
   613  			reconnectIntervalEnv = reconnectIntervalEnv + config.Default + k
   614  		}
   615  		reconnectInterval, err := time.ParseDuration(env.Get(reconnectIntervalEnv,
   616  			kv.Get(target.MqttReconnectInterval)))
   617  		if err != nil {
   618  			return nil, err
   619  		}
   620  
   621  		keepAliveIntervalEnv := target.EnvMQTTKeepAliveInterval
   622  		if k != config.Default {
   623  			keepAliveIntervalEnv = keepAliveIntervalEnv + config.Default + k
   624  		}
   625  		keepAliveInterval, err := time.ParseDuration(env.Get(keepAliveIntervalEnv,
   626  			kv.Get(target.MqttKeepAliveInterval)))
   627  		if err != nil {
   628  			return nil, err
   629  		}
   630  
   631  		queueLimitEnv := target.EnvMQTTQueueLimit
   632  		if k != config.Default {
   633  			queueLimitEnv = queueLimitEnv + config.Default + k
   634  		}
   635  		queueLimit, err := strconv.ParseUint(env.Get(queueLimitEnv, kv.Get(target.MqttQueueLimit)), 10, 64)
   636  		if err != nil {
   637  			return nil, err
   638  		}
   639  
   640  		qosEnv := target.EnvMQTTQoS
   641  		if k != config.Default {
   642  			qosEnv = qosEnv + config.Default + k
   643  		}
   644  
   645  		// Parse uint8 value
   646  		qos, err := strconv.ParseUint(env.Get(qosEnv, kv.Get(target.MqttQoS)), 10, 8)
   647  		if err != nil {
   648  			return nil, err
   649  		}
   650  
   651  		topicEnv := target.EnvMQTTTopic
   652  		if k != config.Default {
   653  			topicEnv = topicEnv + config.Default + k
   654  		}
   655  
   656  		usernameEnv := target.EnvMQTTUsername
   657  		if k != config.Default {
   658  			usernameEnv = usernameEnv + config.Default + k
   659  		}
   660  
   661  		passwordEnv := target.EnvMQTTPassword
   662  		if k != config.Default {
   663  			passwordEnv = passwordEnv + config.Default + k
   664  		}
   665  
   666  		queueDirEnv := target.EnvMQTTQueueDir
   667  		if k != config.Default {
   668  			queueDirEnv = queueDirEnv + config.Default + k
   669  		}
   670  
   671  		mqttArgs := target.MQTTArgs{
   672  			Enable:               enabled,
   673  			Broker:               *brokerURL,
   674  			Topic:                env.Get(topicEnv, kv.Get(target.MqttTopic)),
   675  			QoS:                  byte(qos),
   676  			User:                 env.Get(usernameEnv, kv.Get(target.MqttUsername)),
   677  			Password:             env.Get(passwordEnv, kv.Get(target.MqttPassword)),
   678  			MaxReconnectInterval: reconnectInterval,
   679  			KeepAlive:            keepAliveInterval,
   680  			RootCAs:              rootCAs,
   681  			QueueDir:             env.Get(queueDirEnv, kv.Get(target.MqttQueueDir)),
   682  			QueueLimit:           queueLimit,
   683  		}
   684  
   685  		if err = mqttArgs.Validate(); err != nil {
   686  			return nil, err
   687  		}
   688  		mqttTargets[k] = mqttArgs
   689  	}
   690  	return mqttTargets, nil
   691  }
   692  
   693  // DefaultMySQLKVS - default KV for MySQL
   694  var (
   695  	DefaultMySQLKVS = config.KVS{
   696  		config.KV{
   697  			Key:   config.Enable,
   698  			Value: config.EnableOff,
   699  		},
   700  		config.KV{
   701  			Key:   target.MySQLFormat,
   702  			Value: formatNamespace,
   703  		},
   704  		config.KV{
   705  			Key:   target.MySQLDSNString,
   706  			Value: "",
   707  		},
   708  		config.KV{
   709  			Key:   target.MySQLTable,
   710  			Value: "",
   711  		},
   712  		config.KV{
   713  			Key:   target.MySQLQueueDir,
   714  			Value: "",
   715  		},
   716  		config.KV{
   717  			Key:   target.MySQLQueueLimit,
   718  			Value: "0",
   719  		},
   720  		config.KV{
   721  			Key:   target.MySQLMaxOpenConnections,
   722  			Value: "2",
   723  		},
   724  	}
   725  )
   726  
   727  // GetNotifyMySQL - returns a map of registered notification 'mysql' targets
   728  func GetNotifyMySQL(mysqlKVS map[string]config.KVS) (map[string]target.MySQLArgs, error) {
   729  	mysqlTargets := make(map[string]target.MySQLArgs)
   730  	for k, kv := range config.Merge(mysqlKVS, target.EnvMySQLEnable, DefaultMySQLKVS) {
   731  		enableEnv := target.EnvMySQLEnable
   732  		if k != config.Default {
   733  			enableEnv = enableEnv + config.Default + k
   734  		}
   735  
   736  		enabled, err := config.ParseBool(env.Get(enableEnv, kv.Get(config.Enable)))
   737  		if err != nil {
   738  			return nil, err
   739  		}
   740  		if !enabled {
   741  			continue
   742  		}
   743  
   744  		queueLimitEnv := target.EnvMySQLQueueLimit
   745  		if k != config.Default {
   746  			queueLimitEnv = queueLimitEnv + config.Default + k
   747  		}
   748  		queueLimit, err := strconv.ParseUint(env.Get(queueLimitEnv, kv.Get(target.MySQLQueueLimit)), 10, 64)
   749  		if err != nil {
   750  			return nil, err
   751  		}
   752  
   753  		formatEnv := target.EnvMySQLFormat
   754  		if k != config.Default {
   755  			formatEnv = formatEnv + config.Default + k
   756  		}
   757  
   758  		dsnStringEnv := target.EnvMySQLDSNString
   759  		if k != config.Default {
   760  			dsnStringEnv = dsnStringEnv + config.Default + k
   761  		}
   762  
   763  		tableEnv := target.EnvMySQLTable
   764  		if k != config.Default {
   765  			tableEnv = tableEnv + config.Default + k
   766  		}
   767  
   768  		queueDirEnv := target.EnvMySQLQueueDir
   769  		if k != config.Default {
   770  			queueDirEnv = queueDirEnv + config.Default + k
   771  		}
   772  
   773  		maxOpenConnectionsEnv := target.EnvMySQLMaxOpenConnections
   774  		if k != config.Default {
   775  			maxOpenConnectionsEnv = maxOpenConnectionsEnv + config.Default + k
   776  		}
   777  
   778  		maxOpenConnections, cErr := strconv.Atoi(env.Get(maxOpenConnectionsEnv, kv.Get(target.MySQLMaxOpenConnections)))
   779  		if cErr != nil {
   780  			return nil, cErr
   781  		}
   782  
   783  		mysqlArgs := target.MySQLArgs{
   784  			Enable:             enabled,
   785  			Format:             env.Get(formatEnv, kv.Get(target.MySQLFormat)),
   786  			DSN:                env.Get(dsnStringEnv, kv.Get(target.MySQLDSNString)),
   787  			Table:              env.Get(tableEnv, kv.Get(target.MySQLTable)),
   788  			QueueDir:           env.Get(queueDirEnv, kv.Get(target.MySQLQueueDir)),
   789  			QueueLimit:         queueLimit,
   790  			MaxOpenConnections: maxOpenConnections,
   791  		}
   792  		if err = mysqlArgs.Validate(); err != nil {
   793  			return nil, err
   794  		}
   795  		mysqlTargets[k] = mysqlArgs
   796  	}
   797  	return mysqlTargets, nil
   798  }
   799  
   800  // DefaultNATSKVS - NATS KV for nats config.
   801  var (
   802  	DefaultNATSKVS = config.KVS{
   803  		config.KV{
   804  			Key:   config.Enable,
   805  			Value: config.EnableOff,
   806  		},
   807  		config.KV{
   808  			Key:   target.NATSAddress,
   809  			Value: "",
   810  		},
   811  		config.KV{
   812  			Key:   target.NATSSubject,
   813  			Value: "",
   814  		},
   815  		config.KV{
   816  			Key:   target.NATSUsername,
   817  			Value: "",
   818  		},
   819  		config.KV{
   820  			Key:   target.NATSPassword,
   821  			Value: "",
   822  		},
   823  		config.KV{
   824  			Key:   target.NATSToken,
   825  			Value: "",
   826  		},
   827  		config.KV{
   828  			Key:   target.NATSTLS,
   829  			Value: config.EnableOff,
   830  		},
   831  		config.KV{
   832  			Key:   target.NATSTLSSkipVerify,
   833  			Value: config.EnableOff,
   834  		},
   835  		config.KV{
   836  			Key:   target.NATSCertAuthority,
   837  			Value: "",
   838  		},
   839  		config.KV{
   840  			Key:   target.NATSClientCert,
   841  			Value: "",
   842  		},
   843  		config.KV{
   844  			Key:   target.NATSClientKey,
   845  			Value: "",
   846  		},
   847  		config.KV{
   848  			Key:   target.NATSPingInterval,
   849  			Value: "0",
   850  		},
   851  		config.KV{
   852  			Key:   target.NATSJetStream,
   853  			Value: config.EnableOff,
   854  		},
   855  		config.KV{
   856  			Key:   target.NATSStreaming,
   857  			Value: config.EnableOff,
   858  		},
   859  		config.KV{
   860  			Key:   target.NATSStreamingAsync,
   861  			Value: config.EnableOff,
   862  		},
   863  		config.KV{
   864  			Key:   target.NATSStreamingMaxPubAcksInFlight,
   865  			Value: "0",
   866  		},
   867  		config.KV{
   868  			Key:   target.NATSStreamingClusterID,
   869  			Value: "",
   870  		},
   871  		config.KV{
   872  			Key:   target.NATSQueueDir,
   873  			Value: "",
   874  		},
   875  		config.KV{
   876  			Key:   target.NATSQueueLimit,
   877  			Value: "0",
   878  		},
   879  	}
   880  )
   881  
   882  // GetNotifyNATS - returns a map of registered notification 'nats' targets
   883  func GetNotifyNATS(natsKVS map[string]config.KVS, rootCAs *x509.CertPool) (map[string]target.NATSArgs, error) {
   884  	natsTargets := make(map[string]target.NATSArgs)
   885  	for k, kv := range config.Merge(natsKVS, target.EnvNATSEnable, DefaultNATSKVS) {
   886  		enableEnv := target.EnvNATSEnable
   887  		if k != config.Default {
   888  			enableEnv = enableEnv + config.Default + k
   889  		}
   890  
   891  		enabled, err := config.ParseBool(env.Get(enableEnv, kv.Get(config.Enable)))
   892  		if err != nil {
   893  			return nil, err
   894  		}
   895  		if !enabled {
   896  			continue
   897  		}
   898  
   899  		addressEnv := target.EnvNATSAddress
   900  		if k != config.Default {
   901  			addressEnv = addressEnv + config.Default + k
   902  		}
   903  
   904  		address, err := xnet.ParseHost(env.Get(addressEnv, kv.Get(target.NATSAddress)))
   905  		if err != nil {
   906  			return nil, err
   907  		}
   908  
   909  		pingIntervalEnv := target.EnvNATSPingInterval
   910  		if k != config.Default {
   911  			pingIntervalEnv = pingIntervalEnv + config.Default + k
   912  		}
   913  
   914  		pingInterval, err := strconv.ParseInt(env.Get(pingIntervalEnv, kv.Get(target.NATSPingInterval)), 10, 64)
   915  		if err != nil {
   916  			return nil, err
   917  		}
   918  
   919  		queueLimitEnv := target.EnvNATSQueueLimit
   920  		if k != config.Default {
   921  			queueLimitEnv = queueLimitEnv + config.Default + k
   922  		}
   923  
   924  		queueLimit, err := strconv.ParseUint(env.Get(queueLimitEnv, kv.Get(target.NATSQueueLimit)), 10, 64)
   925  		if err != nil {
   926  			return nil, err
   927  		}
   928  
   929  		tlsEnv := target.EnvNATSTLS
   930  		if k != config.Default {
   931  			tlsEnv = tlsEnv + config.Default + k
   932  		}
   933  
   934  		tlsSkipVerifyEnv := target.EnvNATSTLSSkipVerify
   935  		if k != config.Default {
   936  			tlsSkipVerifyEnv = tlsSkipVerifyEnv + config.Default + k
   937  		}
   938  
   939  		subjectEnv := target.EnvNATSSubject
   940  		if k != config.Default {
   941  			subjectEnv = subjectEnv + config.Default + k
   942  		}
   943  
   944  		usernameEnv := target.EnvNATSUsername
   945  		if k != config.Default {
   946  			usernameEnv = usernameEnv + config.Default + k
   947  		}
   948  
   949  		userCredentialsEnv := target.NATSUserCredentials
   950  		if k != config.Default {
   951  			userCredentialsEnv = userCredentialsEnv + config.Default + k
   952  		}
   953  
   954  		passwordEnv := target.EnvNATSPassword
   955  		if k != config.Default {
   956  			passwordEnv = passwordEnv + config.Default + k
   957  		}
   958  
   959  		tokenEnv := target.EnvNATSToken
   960  		if k != config.Default {
   961  			tokenEnv = tokenEnv + config.Default + k
   962  		}
   963  
   964  		queueDirEnv := target.EnvNATSQueueDir
   965  		if k != config.Default {
   966  			queueDirEnv = queueDirEnv + config.Default + k
   967  		}
   968  
   969  		certAuthorityEnv := target.EnvNATSCertAuthority
   970  		if k != config.Default {
   971  			certAuthorityEnv = certAuthorityEnv + config.Default + k
   972  		}
   973  
   974  		clientCertEnv := target.EnvNATSClientCert
   975  		if k != config.Default {
   976  			clientCertEnv = clientCertEnv + config.Default + k
   977  		}
   978  
   979  		clientKeyEnv := target.EnvNATSClientKey
   980  		if k != config.Default {
   981  			clientKeyEnv = clientKeyEnv + config.Default + k
   982  		}
   983  
   984  		jetStreamEnableEnv := target.EnvNATSJetStream
   985  		if k != config.Default {
   986  			jetStreamEnableEnv = jetStreamEnableEnv + config.Default + k
   987  		}
   988  
   989  		natsArgs := target.NATSArgs{
   990  			Enable:          true,
   991  			Address:         *address,
   992  			Subject:         env.Get(subjectEnv, kv.Get(target.NATSSubject)),
   993  			Username:        env.Get(usernameEnv, kv.Get(target.NATSUsername)),
   994  			UserCredentials: env.Get(userCredentialsEnv, kv.Get(target.NATSUserCredentials)),
   995  			Password:        env.Get(passwordEnv, kv.Get(target.NATSPassword)),
   996  			CertAuthority:   env.Get(certAuthorityEnv, kv.Get(target.NATSCertAuthority)),
   997  			ClientCert:      env.Get(clientCertEnv, kv.Get(target.NATSClientCert)),
   998  			ClientKey:       env.Get(clientKeyEnv, kv.Get(target.NATSClientKey)),
   999  			Token:           env.Get(tokenEnv, kv.Get(target.NATSToken)),
  1000  			TLS:             env.Get(tlsEnv, kv.Get(target.NATSTLS)) == config.EnableOn,
  1001  			TLSSkipVerify:   env.Get(tlsSkipVerifyEnv, kv.Get(target.NATSTLSSkipVerify)) == config.EnableOn,
  1002  			PingInterval:    pingInterval,
  1003  			QueueDir:        env.Get(queueDirEnv, kv.Get(target.NATSQueueDir)),
  1004  			QueueLimit:      queueLimit,
  1005  			RootCAs:         rootCAs,
  1006  		}
  1007  		natsArgs.JetStream.Enable = env.Get(jetStreamEnableEnv, kv.Get(target.NATSJetStream)) == config.EnableOn
  1008  
  1009  		streamingEnableEnv := target.EnvNATSStreaming
  1010  		if k != config.Default {
  1011  			streamingEnableEnv = streamingEnableEnv + config.Default + k
  1012  		}
  1013  
  1014  		streamingEnabled := env.Get(streamingEnableEnv, kv.Get(target.NATSStreaming)) == config.EnableOn
  1015  		if streamingEnabled {
  1016  			asyncEnv := target.EnvNATSStreamingAsync
  1017  			if k != config.Default {
  1018  				asyncEnv = asyncEnv + config.Default + k
  1019  			}
  1020  			maxPubAcksInflightEnv := target.EnvNATSStreamingMaxPubAcksInFlight
  1021  			if k != config.Default {
  1022  				maxPubAcksInflightEnv = maxPubAcksInflightEnv + config.Default + k
  1023  			}
  1024  			maxPubAcksInflight, err := strconv.Atoi(env.Get(maxPubAcksInflightEnv,
  1025  				kv.Get(target.NATSStreamingMaxPubAcksInFlight)))
  1026  			if err != nil {
  1027  				return nil, err
  1028  			}
  1029  			clusterIDEnv := target.EnvNATSStreamingClusterID
  1030  			if k != config.Default {
  1031  				clusterIDEnv = clusterIDEnv + config.Default + k
  1032  			}
  1033  			natsArgs.Streaming.Enable = streamingEnabled
  1034  			natsArgs.Streaming.ClusterID = env.Get(clusterIDEnv, kv.Get(target.NATSStreamingClusterID))
  1035  			natsArgs.Streaming.Async = env.Get(asyncEnv, kv.Get(target.NATSStreamingAsync)) == config.EnableOn
  1036  			natsArgs.Streaming.MaxPubAcksInflight = maxPubAcksInflight
  1037  		}
  1038  
  1039  		if err = natsArgs.Validate(); err != nil {
  1040  			return nil, err
  1041  		}
  1042  
  1043  		natsTargets[k] = natsArgs
  1044  	}
  1045  	return natsTargets, nil
  1046  }
  1047  
  1048  // DefaultNSQKVS - NSQ KV for config
  1049  var (
  1050  	DefaultNSQKVS = config.KVS{
  1051  		config.KV{
  1052  			Key:   config.Enable,
  1053  			Value: config.EnableOff,
  1054  		},
  1055  		config.KV{
  1056  			Key:   target.NSQAddress,
  1057  			Value: "",
  1058  		},
  1059  		config.KV{
  1060  			Key:   target.NSQTopic,
  1061  			Value: "",
  1062  		},
  1063  		config.KV{
  1064  			Key:   target.NSQTLS,
  1065  			Value: config.EnableOff,
  1066  		},
  1067  		config.KV{
  1068  			Key:   target.NSQTLSSkipVerify,
  1069  			Value: config.EnableOff,
  1070  		},
  1071  		config.KV{
  1072  			Key:   target.NSQQueueDir,
  1073  			Value: "",
  1074  		},
  1075  		config.KV{
  1076  			Key:   target.NSQQueueLimit,
  1077  			Value: "0",
  1078  		},
  1079  	}
  1080  )
  1081  
  1082  // GetNotifyNSQ - returns a map of registered notification 'nsq' targets
  1083  func GetNotifyNSQ(nsqKVS map[string]config.KVS) (map[string]target.NSQArgs, error) {
  1084  	nsqTargets := make(map[string]target.NSQArgs)
  1085  	for k, kv := range config.Merge(nsqKVS, target.EnvNSQEnable, DefaultNSQKVS) {
  1086  		enableEnv := target.EnvNSQEnable
  1087  		if k != config.Default {
  1088  			enableEnv = enableEnv + config.Default + k
  1089  		}
  1090  
  1091  		enabled, err := config.ParseBool(env.Get(enableEnv, kv.Get(config.Enable)))
  1092  		if err != nil {
  1093  			return nil, err
  1094  		}
  1095  		if !enabled {
  1096  			continue
  1097  		}
  1098  
  1099  		addressEnv := target.EnvNSQAddress
  1100  		if k != config.Default {
  1101  			addressEnv = addressEnv + config.Default + k
  1102  		}
  1103  		nsqdAddress, err := xnet.ParseHost(env.Get(addressEnv, kv.Get(target.NSQAddress)))
  1104  		if err != nil {
  1105  			return nil, err
  1106  		}
  1107  		tlsEnableEnv := target.EnvNSQTLS
  1108  		if k != config.Default {
  1109  			tlsEnableEnv = tlsEnableEnv + config.Default + k
  1110  		}
  1111  		tlsSkipVerifyEnv := target.EnvNSQTLSSkipVerify
  1112  		if k != config.Default {
  1113  			tlsSkipVerifyEnv = tlsSkipVerifyEnv + config.Default + k
  1114  		}
  1115  
  1116  		queueLimitEnv := target.EnvNSQQueueLimit
  1117  		if k != config.Default {
  1118  			queueLimitEnv = queueLimitEnv + config.Default + k
  1119  		}
  1120  		queueLimit, err := strconv.ParseUint(env.Get(queueLimitEnv, kv.Get(target.NSQQueueLimit)), 10, 64)
  1121  		if err != nil {
  1122  			return nil, err
  1123  		}
  1124  
  1125  		topicEnv := target.EnvNSQTopic
  1126  		if k != config.Default {
  1127  			topicEnv = topicEnv + config.Default + k
  1128  		}
  1129  		queueDirEnv := target.EnvNSQQueueDir
  1130  		if k != config.Default {
  1131  			queueDirEnv = queueDirEnv + config.Default + k
  1132  		}
  1133  
  1134  		nsqArgs := target.NSQArgs{
  1135  			Enable:      enabled,
  1136  			NSQDAddress: *nsqdAddress,
  1137  			Topic:       env.Get(topicEnv, kv.Get(target.NSQTopic)),
  1138  			QueueDir:    env.Get(queueDirEnv, kv.Get(target.NSQQueueDir)),
  1139  			QueueLimit:  queueLimit,
  1140  		}
  1141  		nsqArgs.TLS.Enable = env.Get(tlsEnableEnv, kv.Get(target.NSQTLS)) == config.EnableOn
  1142  		nsqArgs.TLS.SkipVerify = env.Get(tlsSkipVerifyEnv, kv.Get(target.NSQTLSSkipVerify)) == config.EnableOn
  1143  
  1144  		if err = nsqArgs.Validate(); err != nil {
  1145  			return nil, err
  1146  		}
  1147  
  1148  		nsqTargets[k] = nsqArgs
  1149  	}
  1150  	return nsqTargets, nil
  1151  }
  1152  
  1153  // DefaultPostgresKVS - default Postgres KV for server config.
  1154  var (
  1155  	DefaultPostgresKVS = config.KVS{
  1156  		config.KV{
  1157  			Key:   config.Enable,
  1158  			Value: config.EnableOff,
  1159  		},
  1160  		config.KV{
  1161  			Key:   target.PostgresFormat,
  1162  			Value: formatNamespace,
  1163  		},
  1164  		config.KV{
  1165  			Key:   target.PostgresConnectionString,
  1166  			Value: "",
  1167  		},
  1168  		config.KV{
  1169  			Key:   target.PostgresTable,
  1170  			Value: "",
  1171  		},
  1172  		config.KV{
  1173  			Key:   target.PostgresQueueDir,
  1174  			Value: "",
  1175  		},
  1176  		config.KV{
  1177  			Key:   target.PostgresQueueLimit,
  1178  			Value: "0",
  1179  		},
  1180  		config.KV{
  1181  			Key:   target.PostgresMaxOpenConnections,
  1182  			Value: "2",
  1183  		},
  1184  	}
  1185  )
  1186  
  1187  // GetNotifyPostgres - returns a map of registered notification 'postgres' targets
  1188  func GetNotifyPostgres(postgresKVS map[string]config.KVS) (map[string]target.PostgreSQLArgs, error) {
  1189  	psqlTargets := make(map[string]target.PostgreSQLArgs)
  1190  	for k, kv := range config.Merge(postgresKVS, target.EnvPostgresEnable, DefaultPostgresKVS) {
  1191  		enableEnv := target.EnvPostgresEnable
  1192  		if k != config.Default {
  1193  			enableEnv = enableEnv + config.Default + k
  1194  		}
  1195  
  1196  		enabled, err := config.ParseBool(env.Get(enableEnv, kv.Get(config.Enable)))
  1197  		if err != nil {
  1198  			return nil, err
  1199  		}
  1200  		if !enabled {
  1201  			continue
  1202  		}
  1203  
  1204  		queueLimitEnv := target.EnvPostgresQueueLimit
  1205  		if k != config.Default {
  1206  			queueLimitEnv = queueLimitEnv + config.Default + k
  1207  		}
  1208  
  1209  		queueLimit, err := strconv.Atoi(env.Get(queueLimitEnv, kv.Get(target.PostgresQueueLimit)))
  1210  		if err != nil {
  1211  			return nil, err
  1212  		}
  1213  
  1214  		formatEnv := target.EnvPostgresFormat
  1215  		if k != config.Default {
  1216  			formatEnv = formatEnv + config.Default + k
  1217  		}
  1218  
  1219  		connectionStringEnv := target.EnvPostgresConnectionString
  1220  		if k != config.Default {
  1221  			connectionStringEnv = connectionStringEnv + config.Default + k
  1222  		}
  1223  
  1224  		tableEnv := target.EnvPostgresTable
  1225  		if k != config.Default {
  1226  			tableEnv = tableEnv + config.Default + k
  1227  		}
  1228  
  1229  		queueDirEnv := target.EnvPostgresQueueDir
  1230  		if k != config.Default {
  1231  			queueDirEnv = queueDirEnv + config.Default + k
  1232  		}
  1233  
  1234  		maxOpenConnectionsEnv := target.EnvPostgresMaxOpenConnections
  1235  		if k != config.Default {
  1236  			maxOpenConnectionsEnv = maxOpenConnectionsEnv + config.Default + k
  1237  		}
  1238  
  1239  		maxOpenConnections, cErr := strconv.Atoi(env.Get(maxOpenConnectionsEnv, kv.Get(target.PostgresMaxOpenConnections)))
  1240  		if cErr != nil {
  1241  			return nil, cErr
  1242  		}
  1243  
  1244  		psqlArgs := target.PostgreSQLArgs{
  1245  			Enable:             enabled,
  1246  			Format:             env.Get(formatEnv, kv.Get(target.PostgresFormat)),
  1247  			ConnectionString:   env.Get(connectionStringEnv, kv.Get(target.PostgresConnectionString)),
  1248  			Table:              env.Get(tableEnv, kv.Get(target.PostgresTable)),
  1249  			QueueDir:           env.Get(queueDirEnv, kv.Get(target.PostgresQueueDir)),
  1250  			QueueLimit:         uint64(queueLimit),
  1251  			MaxOpenConnections: maxOpenConnections,
  1252  		}
  1253  		if err = psqlArgs.Validate(); err != nil {
  1254  			return nil, err
  1255  		}
  1256  		psqlTargets[k] = psqlArgs
  1257  	}
  1258  
  1259  	return psqlTargets, nil
  1260  }
  1261  
  1262  // DefaultRedisKVS - default KV for redis config
  1263  var (
  1264  	DefaultRedisKVS = config.KVS{
  1265  		config.KV{
  1266  			Key:   config.Enable,
  1267  			Value: config.EnableOff,
  1268  		},
  1269  		config.KV{
  1270  			Key:   target.RedisFormat,
  1271  			Value: formatNamespace,
  1272  		},
  1273  		config.KV{
  1274  			Key:   target.RedisAddress,
  1275  			Value: "",
  1276  		},
  1277  		config.KV{
  1278  			Key:   target.RedisKey,
  1279  			Value: "",
  1280  		},
  1281  		config.KV{
  1282  			Key:   target.RedisPassword,
  1283  			Value: "",
  1284  		},
  1285  		config.KV{
  1286  			Key:   target.RedisUser,
  1287  			Value: "",
  1288  		},
  1289  		config.KV{
  1290  			Key:   target.RedisQueueDir,
  1291  			Value: "",
  1292  		},
  1293  		config.KV{
  1294  			Key:   target.RedisQueueLimit,
  1295  			Value: "0",
  1296  		},
  1297  	}
  1298  )
  1299  
  1300  // GetNotifyRedis - returns a map of registered notification 'redis' targets
  1301  func GetNotifyRedis(redisKVS map[string]config.KVS) (map[string]target.RedisArgs, error) {
  1302  	redisTargets := make(map[string]target.RedisArgs)
  1303  	for k, kv := range config.Merge(redisKVS, target.EnvRedisEnable, DefaultRedisKVS) {
  1304  		enableEnv := target.EnvRedisEnable
  1305  		if k != config.Default {
  1306  			enableEnv = enableEnv + config.Default + k
  1307  		}
  1308  
  1309  		enabled, err := config.ParseBool(env.Get(enableEnv, kv.Get(config.Enable)))
  1310  		if err != nil {
  1311  			return nil, err
  1312  		}
  1313  		if !enabled {
  1314  			continue
  1315  		}
  1316  
  1317  		addressEnv := target.EnvRedisAddress
  1318  		if k != config.Default {
  1319  			addressEnv = addressEnv + config.Default + k
  1320  		}
  1321  		addr, err := xnet.ParseHost(env.Get(addressEnv, kv.Get(target.RedisAddress)))
  1322  		if err != nil {
  1323  			return nil, err
  1324  		}
  1325  		queueLimitEnv := target.EnvRedisQueueLimit
  1326  		if k != config.Default {
  1327  			queueLimitEnv = queueLimitEnv + config.Default + k
  1328  		}
  1329  		queueLimit, err := strconv.Atoi(env.Get(queueLimitEnv, kv.Get(target.RedisQueueLimit)))
  1330  		if err != nil {
  1331  			return nil, err
  1332  		}
  1333  		formatEnv := target.EnvRedisFormat
  1334  		if k != config.Default {
  1335  			formatEnv = formatEnv + config.Default + k
  1336  		}
  1337  		passwordEnv := target.EnvRedisPassword
  1338  		if k != config.Default {
  1339  			passwordEnv = passwordEnv + config.Default + k
  1340  		}
  1341  		userEnv := target.EnvRedisUser
  1342  		if k != config.Default {
  1343  			userEnv = userEnv + config.Default + k
  1344  		}
  1345  		keyEnv := target.EnvRedisKey
  1346  		if k != config.Default {
  1347  			keyEnv = keyEnv + config.Default + k
  1348  		}
  1349  		queueDirEnv := target.EnvRedisQueueDir
  1350  		if k != config.Default {
  1351  			queueDirEnv = queueDirEnv + config.Default + k
  1352  		}
  1353  		redisArgs := target.RedisArgs{
  1354  			Enable:     enabled,
  1355  			Format:     env.Get(formatEnv, kv.Get(target.RedisFormat)),
  1356  			Addr:       *addr,
  1357  			Password:   env.Get(passwordEnv, kv.Get(target.RedisPassword)),
  1358  			User:       env.Get(userEnv, kv.Get(target.RedisUser)),
  1359  			Key:        env.Get(keyEnv, kv.Get(target.RedisKey)),
  1360  			QueueDir:   env.Get(queueDirEnv, kv.Get(target.RedisQueueDir)),
  1361  			QueueLimit: uint64(queueLimit),
  1362  		}
  1363  		if err = redisArgs.Validate(); err != nil {
  1364  			return nil, err
  1365  		}
  1366  		redisTargets[k] = redisArgs
  1367  	}
  1368  	return redisTargets, nil
  1369  }
  1370  
  1371  // DefaultWebhookKVS - default KV for webhook config
  1372  var (
  1373  	DefaultWebhookKVS = config.KVS{
  1374  		config.KV{
  1375  			Key:   config.Enable,
  1376  			Value: config.EnableOff,
  1377  		},
  1378  		config.KV{
  1379  			Key:   target.WebhookEndpoint,
  1380  			Value: "",
  1381  		},
  1382  		config.KV{
  1383  			Key:   target.WebhookAuthToken,
  1384  			Value: "",
  1385  		},
  1386  		config.KV{
  1387  			Key:   target.WebhookQueueLimit,
  1388  			Value: "0",
  1389  		},
  1390  		config.KV{
  1391  			Key:   target.WebhookQueueDir,
  1392  			Value: "",
  1393  		},
  1394  		config.KV{
  1395  			Key:   target.WebhookClientCert,
  1396  			Value: "",
  1397  		},
  1398  		config.KV{
  1399  			Key:   target.WebhookClientKey,
  1400  			Value: "",
  1401  		},
  1402  	}
  1403  )
  1404  
  1405  // GetNotifyWebhook - returns a map of registered notification 'webhook' targets
  1406  func GetNotifyWebhook(webhookKVS map[string]config.KVS, transport *http.Transport) (
  1407  	map[string]target.WebhookArgs, error,
  1408  ) {
  1409  	webhookTargets := make(map[string]target.WebhookArgs)
  1410  	for k, kv := range config.Merge(webhookKVS, target.EnvWebhookEnable, DefaultWebhookKVS) {
  1411  		enableEnv := target.EnvWebhookEnable
  1412  		if k != config.Default {
  1413  			enableEnv = enableEnv + config.Default + k
  1414  		}
  1415  		enabled, err := config.ParseBool(env.Get(enableEnv, kv.Get(config.Enable)))
  1416  		if err != nil {
  1417  			return nil, err
  1418  		}
  1419  		if !enabled {
  1420  			continue
  1421  		}
  1422  		urlEnv := target.EnvWebhookEndpoint
  1423  		if k != config.Default {
  1424  			urlEnv = urlEnv + config.Default + k
  1425  		}
  1426  		url, err := xnet.ParseHTTPURL(env.Get(urlEnv, kv.Get(target.WebhookEndpoint)))
  1427  		if err != nil {
  1428  			return nil, err
  1429  		}
  1430  		queueLimitEnv := target.EnvWebhookQueueLimit
  1431  		if k != config.Default {
  1432  			queueLimitEnv = queueLimitEnv + config.Default + k
  1433  		}
  1434  		queueLimit, err := strconv.Atoi(env.Get(queueLimitEnv, kv.Get(target.WebhookQueueLimit)))
  1435  		if err != nil {
  1436  			return nil, err
  1437  		}
  1438  		queueDirEnv := target.EnvWebhookQueueDir
  1439  		if k != config.Default {
  1440  			queueDirEnv = queueDirEnv + config.Default + k
  1441  		}
  1442  		authEnv := target.EnvWebhookAuthToken
  1443  		if k != config.Default {
  1444  			authEnv = authEnv + config.Default + k
  1445  		}
  1446  		clientCertEnv := target.EnvWebhookClientCert
  1447  		if k != config.Default {
  1448  			clientCertEnv = clientCertEnv + config.Default + k
  1449  		}
  1450  
  1451  		clientKeyEnv := target.EnvWebhookClientKey
  1452  		if k != config.Default {
  1453  			clientKeyEnv = clientKeyEnv + config.Default + k
  1454  		}
  1455  
  1456  		webhookArgs := target.WebhookArgs{
  1457  			Enable:     enabled,
  1458  			Endpoint:   *url,
  1459  			Transport:  transport,
  1460  			AuthToken:  env.Get(authEnv, kv.Get(target.WebhookAuthToken)),
  1461  			QueueDir:   env.Get(queueDirEnv, kv.Get(target.WebhookQueueDir)),
  1462  			QueueLimit: uint64(queueLimit),
  1463  			ClientCert: env.Get(clientCertEnv, kv.Get(target.WebhookClientCert)),
  1464  			ClientKey:  env.Get(clientKeyEnv, kv.Get(target.WebhookClientKey)),
  1465  		}
  1466  		if err = webhookArgs.Validate(); err != nil {
  1467  			return nil, err
  1468  		}
  1469  		webhookTargets[k] = webhookArgs
  1470  	}
  1471  	return webhookTargets, nil
  1472  }
  1473  
  1474  // DefaultESKVS - default KV config for Elasticsearch target
  1475  var (
  1476  	DefaultESKVS = config.KVS{
  1477  		config.KV{
  1478  			Key:   config.Enable,
  1479  			Value: config.EnableOff,
  1480  		},
  1481  		config.KV{
  1482  			Key:   target.ElasticURL,
  1483  			Value: "",
  1484  		},
  1485  		config.KV{
  1486  			Key:   target.ElasticFormat,
  1487  			Value: formatNamespace,
  1488  		},
  1489  		config.KV{
  1490  			Key:   target.ElasticIndex,
  1491  			Value: "",
  1492  		},
  1493  		config.KV{
  1494  			Key:   target.ElasticQueueDir,
  1495  			Value: "",
  1496  		},
  1497  		config.KV{
  1498  			Key:   target.ElasticQueueLimit,
  1499  			Value: "0",
  1500  		},
  1501  		config.KV{
  1502  			Key:   target.ElasticUsername,
  1503  			Value: "",
  1504  		},
  1505  		config.KV{
  1506  			Key:   target.ElasticPassword,
  1507  			Value: "",
  1508  		},
  1509  	}
  1510  )
  1511  
  1512  // GetNotifyES - returns a map of registered notification 'elasticsearch' targets
  1513  func GetNotifyES(esKVS map[string]config.KVS, transport *http.Transport) (map[string]target.ElasticsearchArgs, error) {
  1514  	esTargets := make(map[string]target.ElasticsearchArgs)
  1515  	for k, kv := range config.Merge(esKVS, target.EnvElasticEnable, DefaultESKVS) {
  1516  		enableEnv := target.EnvElasticEnable
  1517  		if k != config.Default {
  1518  			enableEnv = enableEnv + config.Default + k
  1519  		}
  1520  		enabled, err := config.ParseBool(env.Get(enableEnv, kv.Get(config.Enable)))
  1521  		if err != nil {
  1522  			return nil, err
  1523  		}
  1524  		if !enabled {
  1525  			continue
  1526  		}
  1527  
  1528  		urlEnv := target.EnvElasticURL
  1529  		if k != config.Default {
  1530  			urlEnv = urlEnv + config.Default + k
  1531  		}
  1532  
  1533  		url, err := xnet.ParseHTTPURL(env.Get(urlEnv, kv.Get(target.ElasticURL)))
  1534  		if err != nil {
  1535  			return nil, err
  1536  		}
  1537  
  1538  		queueLimitEnv := target.EnvElasticQueueLimit
  1539  		if k != config.Default {
  1540  			queueLimitEnv = queueLimitEnv + config.Default + k
  1541  		}
  1542  
  1543  		queueLimit, err := strconv.Atoi(env.Get(queueLimitEnv, kv.Get(target.ElasticQueueLimit)))
  1544  		if err != nil {
  1545  			return nil, err
  1546  		}
  1547  
  1548  		formatEnv := target.EnvElasticFormat
  1549  		if k != config.Default {
  1550  			formatEnv = formatEnv + config.Default + k
  1551  		}
  1552  
  1553  		indexEnv := target.EnvElasticIndex
  1554  		if k != config.Default {
  1555  			indexEnv = indexEnv + config.Default + k
  1556  		}
  1557  
  1558  		queueDirEnv := target.EnvElasticQueueDir
  1559  		if k != config.Default {
  1560  			queueDirEnv = queueDirEnv + config.Default + k
  1561  		}
  1562  
  1563  		usernameEnv := target.EnvElasticUsername
  1564  		if k != config.Default {
  1565  			usernameEnv = usernameEnv + config.Default + k
  1566  		}
  1567  
  1568  		passwordEnv := target.EnvElasticPassword
  1569  		if k != config.Default {
  1570  			passwordEnv = passwordEnv + config.Default + k
  1571  		}
  1572  
  1573  		esArgs := target.ElasticsearchArgs{
  1574  			Enable:     enabled,
  1575  			Format:     env.Get(formatEnv, kv.Get(target.ElasticFormat)),
  1576  			URL:        *url,
  1577  			Index:      env.Get(indexEnv, kv.Get(target.ElasticIndex)),
  1578  			QueueDir:   env.Get(queueDirEnv, kv.Get(target.ElasticQueueDir)),
  1579  			QueueLimit: uint64(queueLimit),
  1580  			Transport:  transport,
  1581  			Username:   env.Get(usernameEnv, kv.Get(target.ElasticUsername)),
  1582  			Password:   env.Get(passwordEnv, kv.Get(target.ElasticPassword)),
  1583  		}
  1584  		if err = esArgs.Validate(); err != nil {
  1585  			return nil, err
  1586  		}
  1587  		esTargets[k] = esArgs
  1588  	}
  1589  	return esTargets, nil
  1590  }
  1591  
  1592  // DefaultAMQPKVS - default KV for AMQP config
  1593  var (
  1594  	DefaultAMQPKVS = config.KVS{
  1595  		config.KV{
  1596  			Key:   config.Enable,
  1597  			Value: config.EnableOff,
  1598  		},
  1599  		config.KV{
  1600  			Key:   target.AmqpURL,
  1601  			Value: "",
  1602  		},
  1603  		config.KV{
  1604  			Key:   target.AmqpExchange,
  1605  			Value: "",
  1606  		},
  1607  		config.KV{
  1608  			Key:   target.AmqpExchangeType,
  1609  			Value: "",
  1610  		},
  1611  		config.KV{
  1612  			Key:   target.AmqpRoutingKey,
  1613  			Value: "",
  1614  		},
  1615  		config.KV{
  1616  			Key:   target.AmqpMandatory,
  1617  			Value: config.EnableOff,
  1618  		},
  1619  		config.KV{
  1620  			Key:   target.AmqpDurable,
  1621  			Value: config.EnableOff,
  1622  		},
  1623  		config.KV{
  1624  			Key:   target.AmqpNoWait,
  1625  			Value: config.EnableOff,
  1626  		},
  1627  		config.KV{
  1628  			Key:   target.AmqpInternal,
  1629  			Value: config.EnableOff,
  1630  		},
  1631  		config.KV{
  1632  			Key:   target.AmqpAutoDeleted,
  1633  			Value: config.EnableOff,
  1634  		},
  1635  		config.KV{
  1636  			Key:   target.AmqpDeliveryMode,
  1637  			Value: "0",
  1638  		},
  1639  		config.KV{
  1640  			Key:   target.AmqpPublisherConfirms,
  1641  			Value: config.EnableOff,
  1642  		},
  1643  		config.KV{
  1644  			Key:   target.AmqpQueueLimit,
  1645  			Value: "0",
  1646  		},
  1647  		config.KV{
  1648  			Key:   target.AmqpQueueDir,
  1649  			Value: "",
  1650  		},
  1651  	}
  1652  )
  1653  
  1654  // GetNotifyAMQP - returns a map of registered notification 'amqp' targets
  1655  func GetNotifyAMQP(amqpKVS map[string]config.KVS) (map[string]target.AMQPArgs, error) {
  1656  	amqpTargets := make(map[string]target.AMQPArgs)
  1657  	for k, kv := range config.Merge(amqpKVS, target.EnvAMQPEnable, DefaultAMQPKVS) {
  1658  		enableEnv := target.EnvAMQPEnable
  1659  		if k != config.Default {
  1660  			enableEnv = enableEnv + config.Default + k
  1661  		}
  1662  		enabled, err := config.ParseBool(env.Get(enableEnv, kv.Get(config.Enable)))
  1663  		if err != nil {
  1664  			return nil, err
  1665  		}
  1666  		if !enabled {
  1667  			continue
  1668  		}
  1669  		urlEnv := target.EnvAMQPURL
  1670  		if k != config.Default {
  1671  			urlEnv = urlEnv + config.Default + k
  1672  		}
  1673  		url, err := xnet.ParseURL(env.Get(urlEnv, kv.Get(target.AmqpURL)))
  1674  		if err != nil {
  1675  			return nil, err
  1676  		}
  1677  		deliveryModeEnv := target.EnvAMQPDeliveryMode
  1678  		if k != config.Default {
  1679  			deliveryModeEnv = deliveryModeEnv + config.Default + k
  1680  		}
  1681  		deliveryMode, err := strconv.Atoi(env.Get(deliveryModeEnv, kv.Get(target.AmqpDeliveryMode)))
  1682  		if err != nil {
  1683  			return nil, err
  1684  		}
  1685  		exchangeEnv := target.EnvAMQPExchange
  1686  		if k != config.Default {
  1687  			exchangeEnv = exchangeEnv + config.Default + k
  1688  		}
  1689  		routingKeyEnv := target.EnvAMQPRoutingKey
  1690  		if k != config.Default {
  1691  			routingKeyEnv = routingKeyEnv + config.Default + k
  1692  		}
  1693  		exchangeTypeEnv := target.EnvAMQPExchangeType
  1694  		if k != config.Default {
  1695  			exchangeTypeEnv = exchangeTypeEnv + config.Default + k
  1696  		}
  1697  		mandatoryEnv := target.EnvAMQPMandatory
  1698  		if k != config.Default {
  1699  			mandatoryEnv = mandatoryEnv + config.Default + k
  1700  		}
  1701  		immediateEnv := target.EnvAMQPImmediate
  1702  		if k != config.Default {
  1703  			immediateEnv = immediateEnv + config.Default + k
  1704  		}
  1705  		durableEnv := target.EnvAMQPDurable
  1706  		if k != config.Default {
  1707  			durableEnv = durableEnv + config.Default + k
  1708  		}
  1709  		internalEnv := target.EnvAMQPInternal
  1710  		if k != config.Default {
  1711  			internalEnv = internalEnv + config.Default + k
  1712  		}
  1713  		noWaitEnv := target.EnvAMQPNoWait
  1714  		if k != config.Default {
  1715  			noWaitEnv = noWaitEnv + config.Default + k
  1716  		}
  1717  		autoDeletedEnv := target.EnvAMQPAutoDeleted
  1718  		if k != config.Default {
  1719  			autoDeletedEnv = autoDeletedEnv + config.Default + k
  1720  		}
  1721  		publisherConfirmsEnv := target.EnvAMQPPublisherConfirms
  1722  		if k != config.Default {
  1723  			publisherConfirmsEnv = publisherConfirmsEnv + config.Default + k
  1724  		}
  1725  		queueDirEnv := target.EnvAMQPQueueDir
  1726  		if k != config.Default {
  1727  			queueDirEnv = queueDirEnv + config.Default + k
  1728  		}
  1729  		queueLimitEnv := target.EnvAMQPQueueLimit
  1730  		if k != config.Default {
  1731  			queueLimitEnv = queueLimitEnv + config.Default + k
  1732  		}
  1733  		queueLimit, err := strconv.ParseUint(env.Get(queueLimitEnv, kv.Get(target.AmqpQueueLimit)), 10, 64)
  1734  		if err != nil {
  1735  			return nil, err
  1736  		}
  1737  		amqpArgs := target.AMQPArgs{
  1738  			Enable:            enabled,
  1739  			URL:               *url,
  1740  			Exchange:          env.Get(exchangeEnv, kv.Get(target.AmqpExchange)),
  1741  			RoutingKey:        env.Get(routingKeyEnv, kv.Get(target.AmqpRoutingKey)),
  1742  			ExchangeType:      env.Get(exchangeTypeEnv, kv.Get(target.AmqpExchangeType)),
  1743  			DeliveryMode:      uint8(deliveryMode),
  1744  			Mandatory:         env.Get(mandatoryEnv, kv.Get(target.AmqpMandatory)) == config.EnableOn,
  1745  			Immediate:         env.Get(immediateEnv, kv.Get(target.AmqpImmediate)) == config.EnableOn,
  1746  			Durable:           env.Get(durableEnv, kv.Get(target.AmqpDurable)) == config.EnableOn,
  1747  			Internal:          env.Get(internalEnv, kv.Get(target.AmqpInternal)) == config.EnableOn,
  1748  			NoWait:            env.Get(noWaitEnv, kv.Get(target.AmqpNoWait)) == config.EnableOn,
  1749  			AutoDeleted:       env.Get(autoDeletedEnv, kv.Get(target.AmqpAutoDeleted)) == config.EnableOn,
  1750  			PublisherConfirms: env.Get(publisherConfirmsEnv, kv.Get(target.AmqpPublisherConfirms)) == config.EnableOn,
  1751  			QueueDir:          env.Get(queueDirEnv, kv.Get(target.AmqpQueueDir)),
  1752  			QueueLimit:        queueLimit,
  1753  		}
  1754  		if err = amqpArgs.Validate(); err != nil {
  1755  			return nil, err
  1756  		}
  1757  		amqpTargets[k] = amqpArgs
  1758  	}
  1759  	return amqpTargets, nil
  1760  }