github.com/XiaoMi/Gaea@v1.2.5/models/store.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/json"
    19  	"fmt"
    20  	etcdclientv3 "github.com/XiaoMi/Gaea/models/etcdv3"
    21  	"path/filepath"
    22  	"strings"
    23  	"time"
    24  
    25  	"github.com/XiaoMi/Gaea/log"
    26  	etcdclient "github.com/XiaoMi/Gaea/models/etcd"
    27  	fileclient "github.com/XiaoMi/Gaea/models/file"
    28  )
    29  
    30  // config type
    31  const (
    32  	ConfigFile   = "file"
    33  	ConfigEtcd   = "etcd"
    34  	ConfigEtcdV3 = "etcdv3"
    35  )
    36  
    37  // Client client interface
    38  type Client interface {
    39  	Create(path string, data []byte) error
    40  	Update(path string, data []byte) error
    41  	UpdateWithTTL(path string, data []byte, ttl time.Duration) error
    42  	Delete(path string) error
    43  	Read(path string) ([]byte, error)
    44  	List(path string) ([]string, error)
    45  	Close() error
    46  	BasePrefix() string
    47  }
    48  
    49  // Store means exported client to use
    50  type Store struct {
    51  	client Client
    52  	prefix string
    53  }
    54  
    55  // NewClient constructor to create client by case etcd/file/zk etc.
    56  func NewClient(configType, addr, username, password, root string) Client {
    57  	switch configType {
    58  	case ConfigFile:
    59  		// 使用文档 File 去读取设定值
    60  		c, err := fileclient.New(root)
    61  		if err != nil {
    62  			log.Warn("create fileclient failed, %s", addr)
    63  			return nil
    64  		}
    65  		return c
    66  	case ConfigEtcd:
    67  		// 使用 Etcd V2 API 去读取设定值
    68  		c, err := etcdclient.New(addr, time.Minute, username, password, root)
    69  		if err != nil {
    70  			log.Fatal("create etcdclient v2 to %s failed, %v", addr, err)
    71  			return nil
    72  		}
    73  		return c
    74  	case ConfigEtcdV3:
    75  		// 使用 Etcd V3 API 去读取设定值
    76  		c, err := etcdclientv3.New(addr, time.Minute, username, password, root)
    77  		if err != nil {
    78  			log.Fatal("create etcdclient v3 to %s failed, %v", addr, err)
    79  			return nil
    80  		}
    81  		return c
    82  	}
    83  	log.Fatal("unknown config type")
    84  	return nil
    85  }
    86  
    87  // NewStore constructor of Store
    88  func NewStore(client Client) *Store {
    89  	return &Store{
    90  		client: client,
    91  		prefix: client.BasePrefix(),
    92  	}
    93  }
    94  
    95  // Close close store
    96  func (s *Store) Close() error {
    97  	return s.client.Close()
    98  }
    99  
   100  // NamespaceBase return namespace path base
   101  func (s *Store) NamespaceBase() string {
   102  	return filepath.Join(s.prefix, "namespace")
   103  }
   104  
   105  // NamespacePath concat namespace path
   106  func (s *Store) NamespacePath(name string) string {
   107  	return filepath.Join(s.prefix, "namespace", name)
   108  }
   109  
   110  // ProxyBase return proxy path base
   111  func (s *Store) ProxyBase() string {
   112  	return filepath.Join(s.prefix, "proxy")
   113  }
   114  
   115  // ProxyPath concat proxy path
   116  func (s *Store) ProxyPath(token string) string {
   117  	return filepath.Join(s.prefix, "proxy", fmt.Sprintf("proxy-%s", token))
   118  }
   119  
   120  // CreateProxy create proxy model
   121  func (s *Store) CreateProxy(p *ProxyInfo) error {
   122  	// 就在这里,会在 etcd 服务器上新增一个 key /gaea_cluster/proxy/proxy-127.0.0.1:13306
   123  	return s.client.Update(s.ProxyPath(p.Token), p.Encode())
   124  }
   125  
   126  // DeleteProxy delete proxy path
   127  func (s *Store) DeleteProxy(token string) error {
   128  	return s.client.Delete(s.ProxyPath(token))
   129  }
   130  
   131  // ListNamespace list namespace
   132  func (s *Store) ListNamespace() ([]string, error) {
   133  	files, err := s.client.List(s.NamespaceBase())
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  	for i := 0; i < len(files); i++ {
   138  		tmp := strings.Split(files[i], "/")
   139  		files[i] = tmp[len(tmp)-1]
   140  	}
   141  	return files, nil
   142  }
   143  
   144  // LoadNamespace load namespace value
   145  func (s *Store) LoadNamespace(key, name string) (*Namespace, error) {
   146  	b, err := s.client.Read(s.NamespacePath(name))
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  
   151  	if b == nil {
   152  		return nil, fmt.Errorf("node %s not exists", s.NamespacePath(name))
   153  	}
   154  
   155  	p := &Namespace{}
   156  	if err = json.Unmarshal(b, p); err != nil {
   157  		return nil, err
   158  	}
   159  
   160  	if err = p.Verify(); err != nil {
   161  		return nil, err
   162  	}
   163  
   164  	if err = p.Decrypt(key); err != nil {
   165  		return nil, err
   166  	}
   167  
   168  	return p, nil
   169  }
   170  
   171  // UpdateNamespace update namespace path with data
   172  func (s *Store) UpdateNamespace(p *Namespace) error {
   173  	return s.client.Update(s.NamespacePath(p.Name), p.Encode())
   174  }
   175  
   176  // DelNamespace delete namespace
   177  func (s *Store) DelNamespace(name string) error {
   178  	return s.client.Delete(s.NamespacePath(name))
   179  }
   180  
   181  // ListProxyMonitorMetrics list proxies in proxy register path
   182  func (s *Store) ListProxyMonitorMetrics() (map[string]*ProxyMonitorMetric, error) {
   183  	files, err := s.client.List(s.ProxyBase())
   184  	if err != nil {
   185  		return nil, err
   186  	}
   187  	proxy := make(map[string]*ProxyMonitorMetric)
   188  	for _, path := range files {
   189  		b, err := s.client.Read(path)
   190  		if err != nil {
   191  			return nil, err
   192  		}
   193  		p := &ProxyMonitorMetric{}
   194  		if err := JSONDecode(p, b); err != nil {
   195  			return nil, err
   196  		}
   197  		proxy[p.Token] = p
   198  	}
   199  	return proxy, nil
   200  }