storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/config/notify/parse.go (about)

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