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 }