github.com/XiaoMi/Gaea@v1.2.5/models/namespace.go (about)

     1  // Copyright 2019 The Gaea Authors. All Rights Reserved.
     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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package models
    16  
    17  import (
    18  	"encoding/base64"
    19  	"errors"
    20  	"fmt"
    21  	"strconv"
    22  	"strings"
    23  
    24  	"github.com/XiaoMi/Gaea/mysql"
    25  	"github.com/XiaoMi/Gaea/util"
    26  	"github.com/XiaoMi/Gaea/util/crypto"
    27  )
    28  
    29  // Namespace means namespace model stored in etcd
    30  type Namespace struct {
    31  	OpenGeneralLog    bool              `json:"open_general_log"`
    32  	IsEncrypt         bool              `json:"is_encrypt"` // true: 加密存储 false: 非加密存储,目前加密Slice、User中的用户名、密码
    33  	Name              string            `json:"name"`
    34  	Online            bool              `json:"online"`
    35  	ReadOnly          bool              `json:"read_only"`
    36  	AllowedDBS        map[string]bool   `json:"allowed_dbs"`
    37  	DefaultPhyDBS     map[string]string `json:"default_phy_dbs"`
    38  	SlowSQLTime       string            `json:"slow_sql_time"`
    39  	BlackSQL          []string          `json:"black_sql"`
    40  	AllowedIP         []string          `json:"allowed_ip"`
    41  	Slices            []*Slice          `json:"slices"`
    42  	ShardRules        []*Shard          `json:"shard_rules"`
    43  	Users             []*User           `json:"users"` // 客户端接入proxy用户,每个用户可以设置读写分离、读写权限等
    44  	DefaultSlice      string            `json:"default_slice"`
    45  	GlobalSequences   []*GlobalSequence `json:"global_sequences"`
    46  	DefaultCharset    string            `json:"default_charset"`
    47  	DefaultCollation  string            `json:"default_collation"`
    48  	MaxSqlExecuteTime int               `json:"max_sql_execute_time"` // sql最大执行时间,大于该时间,进行熔断
    49  	MaxSqlResultSize  int               `json:"max_sql_result_size"`  // 限制单分片返回结果集大小不超过max_select_rows
    50  }
    51  
    52  // Encode encode json
    53  func (n *Namespace) Encode() []byte {
    54  	return JSONEncode(n)
    55  }
    56  
    57  // Verify verify namespace contents
    58  func (n *Namespace) Verify() error {
    59  	if err := n.verifyName(); err != nil {
    60  		return err
    61  	}
    62  
    63  	if err := n.verifyAllowDBS(); err != nil {
    64  		return err
    65  	}
    66  
    67  	if err := n.verifyUsers(); err != nil {
    68  		return err
    69  	}
    70  
    71  	if err := n.verifySlowSQLTime(); err != nil {
    72  		return err
    73  	}
    74  
    75  	if err := n.verifyDBs(); err != nil {
    76  		return err
    77  	}
    78  
    79  	if err := n.verifyAllowIps(); err != nil {
    80  		return err
    81  	}
    82  
    83  	if err := n.verifyCharset(); err != nil {
    84  		return err
    85  	}
    86  
    87  	if err := n.verifySlices(); err != nil {
    88  		return err
    89  	}
    90  
    91  	if err := n.verifyDefaultSlice(); err != nil {
    92  		return err
    93  	}
    94  
    95  	if err := n.verifyShardRules(); err != nil {
    96  		return err
    97  	}
    98  
    99  	return nil
   100  }
   101  
   102  func (n *Namespace) verifyName() error {
   103  	if !n.isNameExists() {
   104  		return fmt.Errorf("must specify namespace name")
   105  	}
   106  	return nil
   107  }
   108  
   109  func (n *Namespace) isNameExists() bool {
   110  	return n.Name != ""
   111  }
   112  
   113  func (n *Namespace) verifyAllowDBS() error {
   114  	if n.isAllowedDBSEmpty() {
   115  		return errors.New("must specify usable dbs")
   116  	}
   117  	return nil
   118  }
   119  
   120  func (n *Namespace) isAllowedDBSEmpty() bool {
   121  	return len(n.AllowedDBS) == 0
   122  }
   123  
   124  func (n *Namespace) verifyUsers() error {
   125  	if n.isUsersEmpty() {
   126  		return errors.New("must specify proxy access users")
   127  	}
   128  
   129  	for i, u := range n.Users {
   130  		//check namespace
   131  		if u.Namespace == "" {
   132  			u.Namespace = n.Name
   133  		} else if u.Namespace != n.Name {
   134  			return fmt.Errorf("user's namespace name mismatch, user: %s, namespace: %s, %s", u.UserName, n.Name, u.Namespace)
   135  		}
   136  
   137  		if err := u.verify(); err != nil {
   138  			return fmt.Errorf("user config error, schema: %s, %v", n.Name, err)
   139  		}
   140  
   141  		//check repeat username
   142  		for j := 0; j < i; j++ {
   143  			if n.Users[j].UserName == u.UserName {
   144  				return fmt.Errorf("user duped, namespace: %s, user: %s", n.Name, u.UserName)
   145  			}
   146  		}
   147  	}
   148  	return nil
   149  }
   150  
   151  func (n *Namespace) isUsersEmpty() bool {
   152  	return len(n.Users) == 0
   153  }
   154  
   155  func (n *Namespace) verifySlowSQLTime() error {
   156  	if !n.isSlowSQLTimeExists() {
   157  		return nil
   158  	}
   159  	if err := n.isSlowSQLTimeValid(); err != nil {
   160  		return err
   161  	}
   162  	return nil
   163  }
   164  
   165  func (n *Namespace) isSlowSQLTimeExists() bool {
   166  	return n.SlowSQLTime != ""
   167  }
   168  
   169  func (n *Namespace) isSlowSQLTimeValid() error {
   170  	if slowSQLTime, err := strconv.ParseInt(n.SlowSQLTime, 10, 64); err != nil || slowSQLTime < 0 {
   171  		return errors.New("invalid slow sql time")
   172  	}
   173  	return nil
   174  }
   175  
   176  func (n *Namespace) verifyDBs() error {
   177  	// no logic database mode
   178  	if n.isDefaultPhyDBSEmpty() {
   179  		return nil
   180  	}
   181  
   182  	// logic database mode
   183  	if err := n.isAllowedDBSValid(); err != nil {
   184  		return err
   185  	}
   186  	return nil
   187  }
   188  
   189  func (n *Namespace) isDefaultPhyDBSEmpty() bool {
   190  	return len(n.DefaultPhyDBS) == 0
   191  }
   192  
   193  func (n *Namespace) isAllowedDBSValid() error {
   194  	for db := range n.AllowedDBS {
   195  		if _, ok := n.DefaultPhyDBS[db]; !ok {
   196  			return fmt.Errorf("db %s have no phy db", db)
   197  		}
   198  	}
   199  	return nil
   200  }
   201  
   202  func (n *Namespace) verifyAllowIps() error {
   203  	for _, ipStr := range n.AllowedIP {
   204  		ipStr = strings.TrimSpace(ipStr)
   205  		if len(ipStr) == 0 {
   206  			continue
   207  		}
   208  
   209  		if _, err := util.ParseIPInfo(ipStr); err != nil {
   210  			return fmt.Errorf("verify allowips error: %v", err)
   211  		}
   212  	}
   213  	return nil
   214  }
   215  
   216  func (n *Namespace) verifyCharset() error {
   217  	if err := mysql.VerifyCharset(n.DefaultCharset, n.DefaultCollation); err != nil {
   218  		return fmt.Errorf("verify charset error: %v", err)
   219  	}
   220  	return nil
   221  }
   222  
   223  func (n *Namespace) verifySlices() error {
   224  	if n.isSlicesEmpty() {
   225  		return errors.New("empty slices")
   226  	}
   227  	if err := n.verifyEachSlice(); err != nil {
   228  		return err
   229  	}
   230  	return nil
   231  }
   232  
   233  func (n *Namespace) isSlicesEmpty() bool {
   234  	return len(n.Slices) == 0
   235  }
   236  
   237  func (n *Namespace) verifyEachSlice() error {
   238  	for i, slice := range n.Slices {
   239  		if err := slice.verify(); err != nil {
   240  			return fmt.Errorf("slice cfg error, namespace: %s, err: %s", n.Name, err.Error())
   241  		}
   242  
   243  		//check repeat slice
   244  		for j := 0; j < i; j++ {
   245  			if n.Slices[j].Name == slice.Name {
   246  				return fmt.Errorf("slice name duped, namespace: %s, slice: %s", n.Name, slice.Name)
   247  			}
   248  		}
   249  	}
   250  	return nil
   251  }
   252  
   253  func (n *Namespace) verifyDefaultSlice() error {
   254  	if n.DefaultSlice != "" {
   255  		exist := false
   256  		for _, slice := range n.Slices {
   257  			if slice.Name == n.DefaultSlice {
   258  				exist = true
   259  				break
   260  			}
   261  		}
   262  
   263  		if !exist {
   264  			return fmt.Errorf("invalid default slice: %s", n.DefaultSlice)
   265  		}
   266  	}
   267  	return nil
   268  }
   269  
   270  func (n *Namespace) verifyShardRules() error {
   271  	var sliceNames []string
   272  	var linkedRuleShards []*Shard
   273  	var rules = make(map[string]map[string]string)
   274  
   275  	for _, slice := range n.Slices {
   276  		sliceNames = append(sliceNames, slice.Name)
   277  	}
   278  
   279  	for _, s := range n.ShardRules {
   280  		for _, slice := range s.Slices {
   281  			if !includeSlice(sliceNames, slice) {
   282  				return fmt.Errorf("shard table[%s] slice[%s] not in the namespace.slices list:[%s]",
   283  					s.Table, slice, strings.Join(s.Slices, ","))
   284  			}
   285  		}
   286  
   287  		switch s.Type {
   288  		case ShardDefault:
   289  			return errors.New("[default-rule] duplicate, must only one")
   290  		// get index of linked table config and handle it later
   291  		case ShardLinked:
   292  			linkedRuleShards = append(linkedRuleShards, s)
   293  		default:
   294  			if err := s.verify(); err != nil {
   295  				return err
   296  			}
   297  		}
   298  
   299  		//if the database exist in rules
   300  		if _, ok := rules[s.DB]; ok {
   301  			if _, ok := rules[s.DB][s.Table]; ok {
   302  				return fmt.Errorf("table %s rule in %s duplicate", s.Table, s.DB)
   303  			} else {
   304  				rules[s.DB][s.Table] = s.Type
   305  			}
   306  		} else {
   307  			m := make(map[string]string)
   308  			rules[s.DB] = m
   309  			rules[s.DB][s.Table] = s.Type
   310  		}
   311  	}
   312  
   313  	for _, s := range linkedRuleShards {
   314  		tableRules, ok := rules[s.DB]
   315  		if !ok {
   316  			return fmt.Errorf("db of LinkedRule is not found in parent rules")
   317  		}
   318  		dbRuleType, ok := tableRules[s.ParentTable]
   319  		if !ok {
   320  			return fmt.Errorf("parent table of LinkedRule is not found in parent rules")
   321  		}
   322  		if dbRuleType == ShardLinked {
   323  			return fmt.Errorf("LinkedRule cannot link to another LinkedRule")
   324  		}
   325  	}
   326  	return nil
   327  }
   328  
   329  // Decrypt decrypt user/password in namespace
   330  func (n *Namespace) Decrypt(key string) (err error) {
   331  	if !n.IsEncrypt {
   332  		return nil
   333  	}
   334  	// Users
   335  	for i := range n.Users {
   336  		n.Users[i].UserName, err = decrypt(key, n.Users[i].UserName)
   337  		if err != nil {
   338  			return
   339  		}
   340  		n.Users[i].Password, err = decrypt(key, n.Users[i].Password)
   341  		if err != nil {
   342  			return
   343  		}
   344  	}
   345  	// Slices
   346  	for i := range n.Slices {
   347  		n.Slices[i].UserName, err = decrypt(key, n.Slices[i].UserName)
   348  		if err != nil {
   349  			return
   350  		}
   351  		n.Slices[i].Password, err = decrypt(key, n.Slices[i].Password)
   352  		if err != nil {
   353  			return
   354  		}
   355  	}
   356  
   357  	return nil
   358  }
   359  
   360  // Encrypt encrypt user/password in namespace
   361  func (n *Namespace) Encrypt(key string) (err error) {
   362  	n.IsEncrypt = true
   363  	// Users
   364  	for i := range n.Users {
   365  		n.Users[i].UserName, err = encrypt(key, n.Users[i].UserName)
   366  		if err != nil {
   367  			return
   368  		}
   369  		n.Users[i].Password, err = encrypt(key, n.Users[i].Password)
   370  		if err != nil {
   371  			return
   372  		}
   373  	}
   374  	// Slices
   375  	for i := range n.Slices {
   376  		n.Slices[i].UserName, err = encrypt(key, n.Slices[i].UserName)
   377  		if err != nil {
   378  			return
   379  		}
   380  		n.Slices[i].Password, err = encrypt(key, n.Slices[i].Password)
   381  		if err != nil {
   382  			return
   383  		}
   384  	}
   385  
   386  	return nil
   387  }
   388  
   389  func decrypt(key, data string) (string, error) {
   390  	t, _ := base64.StdEncoding.DecodeString(data)
   391  	origin, err := crypto.DecryptECB(key, t)
   392  	if err != nil {
   393  		return "", err
   394  	}
   395  	return string(origin), nil
   396  }
   397  
   398  func encrypt(key, data string) (string, error) {
   399  	tmp, err := crypto.EncryptECB(key, []byte(data))
   400  	if err != nil {
   401  		return "", err
   402  	}
   403  	base64Str := base64.StdEncoding.EncodeToString(tmp)
   404  	return base64Str, nil
   405  }