github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/engine/pkg/meta/model/config.go (about)

     1  // Copyright 2022 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package model
    15  
    16  import (
    17  	"crypto/tls"
    18  	"strings"
    19  
    20  	validation "github.com/go-ozzo/ozzo-validation/v4"
    21  	dmysql "github.com/go-sql-driver/mysql"
    22  	"github.com/pingcap/tidb/pkg/util"
    23  	"github.com/pingcap/tiflow/engine/pkg/dbutil"
    24  	"github.com/pingcap/tiflow/pkg/errors"
    25  	"github.com/pingcap/tiflow/pkg/security"
    26  )
    27  
    28  const (
    29  	defaultReadTimeout  = "3s"
    30  	defaultWriteTimeout = "3s"
    31  	defaultDialTimeout  = "3s"
    32  )
    33  
    34  // StoreType is the type of metastore
    35  type StoreType = string
    36  
    37  const (
    38  	defaultStoreType = StoreTypeMySQL
    39  	// StoreTypeEtcd is the store type string for etcd
    40  	StoreTypeEtcd = "etcd"
    41  	// StoreTypeMySQL is the store type string for MySQL
    42  	StoreTypeMySQL = "mysql"
    43  
    44  	// StoreTypeSQLite is the store type string for SQLite
    45  	// Only for test now
    46  	StoreTypeSQLite = "sqlite"
    47  	// StoreTypeMockKV is a specific store type which can generate
    48  	// a mock kvclient (using map as backend)
    49  	// Only for test now
    50  	StoreTypeMockKV = "mock-kv"
    51  )
    52  
    53  // AuthConfParams is basic authentication configurations
    54  type AuthConfParams struct {
    55  	User   string `toml:"user" json:"user"`
    56  	Passwd string `toml:"passwd" json:"passwd"`
    57  }
    58  
    59  // StoreConfig is metastore connection configurations
    60  type StoreConfig struct {
    61  	// StoreID is the unique readable identifier for a store
    62  	StoreID string `toml:"store-id" json:"store-id"`
    63  	// StoreType supports 'etcd' or 'mysql', default is 'mysql'
    64  	StoreType StoreType `toml:"store-type" json:"store-type"`
    65  	Endpoints []string  `toml:"endpoints" json:"endpoints"`
    66  	User      string    `toml:"user" json:"user"`
    67  	Password  string    `toml:"password" json:"password"`
    68  	// Schema is the predefine schema name for mysql-compatible metastore
    69  	// 1.It needs to stay UNCHANGED for one dataflow engine cluster
    70  	// 2.It needs be different between any two dataflow engine clusters
    71  	// 3.Naming rule: https://dev.mysql.com/doc/refman/5.7/en/identifiers.html
    72  	Schema       string `toml:"schema" json:"schema"`
    73  	ReadTimeout  string `toml:"read-timeout" json:"read-timeout"`
    74  	WriteTimeout string `toml:"write-timeout" json:"write-timeout"`
    75  	DialTimeout  string `toml:"dial-timeout" json:"dial-timeout"`
    76  	// DBConf is the db config for mysql-compatible metastore
    77  	DBConf *dbutil.DBConfig `toml:"dbconfs" json:"dbconfs"`
    78  
    79  	Security *security.Credential `toml:"security" json:"security"`
    80  }
    81  
    82  // SetEndpoints sets endpoints to StoreConfig
    83  func (s *StoreConfig) SetEndpoints(endpoints string) {
    84  	if endpoints != "" {
    85  		s.Endpoints = strings.Split(endpoints, ",")
    86  	}
    87  }
    88  
    89  // Validate implements the validation.Validatable interface
    90  func (s StoreConfig) Validate() error {
    91  	return validation.ValidateStruct(&s,
    92  		validation.Field(&s.StoreType, validation.In(StoreTypeEtcd, StoreTypeMySQL)),
    93  		validation.Field(&s.Schema, validation.When(s.StoreType == StoreTypeMySQL, validation.Required, validation.Length(1, 128))),
    94  	)
    95  }
    96  
    97  // DefaultStoreConfig return a default *StoreConfig
    98  func DefaultStoreConfig() *StoreConfig {
    99  	return &StoreConfig{
   100  		StoreType:    defaultStoreType,
   101  		Endpoints:    []string{},
   102  		ReadTimeout:  defaultReadTimeout,
   103  		WriteTimeout: defaultWriteTimeout,
   104  		DialTimeout:  defaultDialTimeout,
   105  		DBConf:       dbutil.DefaultDBConfig(),
   106  	}
   107  }
   108  
   109  // GenerateDSNByParams generates a dsn string.
   110  // dsn format: [username[:password]@][protocol[(address)]]/
   111  func GenerateDSNByParams(storeConf *StoreConfig, pairs map[string]string) (string, error) {
   112  	if storeConf == nil {
   113  		return "", errors.ErrMetaParamsInvalid.GenWithStackByArgs("input store config is nil")
   114  	}
   115  
   116  	dsnCfg := dmysql.NewConfig()
   117  	if dsnCfg.Params == nil {
   118  		dsnCfg.Params = make(map[string]string, 1)
   119  	}
   120  	if storeConf.User != "" {
   121  		dsnCfg.User = storeConf.User
   122  	}
   123  	if storeConf.Password != "" {
   124  		dsnCfg.Passwd = storeConf.Password
   125  	}
   126  
   127  	if storeConf.Security != nil {
   128  		cfg, err := util.NewTLSConfig(
   129  			util.WithCAPath(storeConf.Security.CAPath),
   130  			util.WithCertAndKeyPath(storeConf.Security.CertPath, storeConf.Security.KeyPath),
   131  			util.WithVerifyCommonName(storeConf.Security.CertAllowedCN),
   132  			util.WithMinTLSVersion(tls.VersionTLS10))
   133  		if err != nil {
   134  			return "", errors.ErrMetaParamsInvalid.Wrap(err)
   135  		}
   136  		tlsName := "engine_tls" + storeConf.StoreID
   137  		if cfg != nil {
   138  			if err := dmysql.RegisterTLSConfig(tlsName, cfg); err != nil {
   139  				return "", errors.ErrMetaParamsInvalid.Wrap(err)
   140  			}
   141  		}
   142  		dsnCfg.Params["tls"] = tlsName
   143  	}
   144  
   145  	dsnCfg.Net = "tcp"
   146  	dsnCfg.Addr = storeConf.Endpoints[0]
   147  	dsnCfg.DBName = storeConf.Schema
   148  	dsnCfg.InterpolateParams = true
   149  	dsnCfg.Params["parseTime"] = "true"
   150  	// TODO: check for timezone
   151  	dsnCfg.Params["loc"] = "Local"
   152  	dsnCfg.Params["readTimeout"] = storeConf.ReadTimeout
   153  	dsnCfg.Params["writeTimeout"] = storeConf.WriteTimeout
   154  	dsnCfg.Params["timeout"] = storeConf.DialTimeout
   155  
   156  	for k, v := range pairs {
   157  		dsnCfg.Params[k] = v
   158  	}
   159  
   160  	return dsnCfg.FormatDSN(), nil
   161  }
   162  
   163  // ToClientType translates store type to client type
   164  func ToClientType(storeType StoreType) ClientType {
   165  	switch storeType {
   166  	case StoreTypeEtcd:
   167  		return EtcdKVClientType
   168  	case StoreTypeMySQL:
   169  		return SQLKVClientType
   170  	case StoreTypeMockKV:
   171  		return MockKVClientType
   172  	}
   173  
   174  	return UnknownKVClientType
   175  }