github.com/kafkaliu/etcd@v0.1.2-0.20131007164923-44c16dd30d69/etcd.go (about) 1 /* 2 Copyright 2013 CoreOS 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 main 18 19 import ( 20 "crypto/tls" 21 "flag" 22 "fmt" 23 "io/ioutil" 24 "net/url" 25 "os" 26 "strings" 27 "time" 28 29 "github.com/coreos/etcd/store" 30 "github.com/coreos/go-raft" 31 ) 32 33 //------------------------------------------------------------------------------ 34 // 35 // Initialization 36 // 37 //------------------------------------------------------------------------------ 38 39 var ( 40 verbose bool 41 veryVerbose bool 42 43 machines string 44 machinesFile string 45 46 cluster []string 47 48 argInfo Info 49 dirPath string 50 51 force bool 52 53 maxSize int 54 55 snapshot bool 56 57 retryTimes int 58 59 maxClusterSize int 60 61 cpuprofile string 62 63 cors string 64 corsList map[string]bool 65 ) 66 67 func init() { 68 flag.BoolVar(&verbose, "v", false, "verbose logging") 69 flag.BoolVar(&veryVerbose, "vv", false, "very verbose logging") 70 71 flag.StringVar(&machines, "C", "", "the ip address and port of a existing machines in the cluster, sepearate by comma") 72 flag.StringVar(&machinesFile, "CF", "", "the file contains a list of existing machines in the cluster, seperate by comma") 73 74 flag.StringVar(&argInfo.Name, "n", "default-name", "the node name (required)") 75 flag.StringVar(&argInfo.EtcdURL, "c", "127.0.0.1:4001", "the advertised public hostname:port for etcd client communication") 76 flag.StringVar(&argInfo.RaftURL, "s", "127.0.0.1:7001", "the advertised public hostname:port for raft server communication") 77 flag.StringVar(&argInfo.EtcdListenHost, "cl", "", "the listening hostname for etcd client communication (defaults to advertised ip)") 78 flag.StringVar(&argInfo.RaftListenHost, "sl", "", "the listening hostname for raft server communication (defaults to advertised ip)") 79 flag.StringVar(&argInfo.WebURL, "w", "", "the hostname:port of web interface") 80 81 flag.StringVar(&argInfo.RaftTLS.CAFile, "serverCAFile", "", "the path of the CAFile") 82 flag.StringVar(&argInfo.RaftTLS.CertFile, "serverCert", "", "the cert file of the server") 83 flag.StringVar(&argInfo.RaftTLS.KeyFile, "serverKey", "", "the key file of the server") 84 85 flag.StringVar(&argInfo.EtcdTLS.CAFile, "clientCAFile", "", "the path of the client CAFile") 86 flag.StringVar(&argInfo.EtcdTLS.CertFile, "clientCert", "", "the cert file of the client") 87 flag.StringVar(&argInfo.EtcdTLS.KeyFile, "clientKey", "", "the key file of the client") 88 89 flag.StringVar(&dirPath, "d", ".", "the directory to store log and snapshot") 90 91 flag.BoolVar(&force, "f", false, "force new node configuration if existing is found (WARNING: data loss!)") 92 93 flag.BoolVar(&snapshot, "snapshot", false, "open or close snapshot") 94 95 flag.IntVar(&maxSize, "m", 1024, "the max size of result buffer") 96 97 flag.IntVar(&retryTimes, "r", 3, "the max retry attempts when trying to join a cluster") 98 99 flag.IntVar(&maxClusterSize, "maxsize", 9, "the max size of the cluster") 100 101 flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to file") 102 103 flag.StringVar(&cors, "cors", "", "whitelist origins for cross-origin resource sharing (e.g. '*' or 'http://localhost:8001,etc')") 104 } 105 106 const ( 107 ElectionTimeout = 200 * time.Millisecond 108 HeartbeatTimeout = 50 * time.Millisecond 109 RetryInterval = 10 110 ) 111 112 //------------------------------------------------------------------------------ 113 // 114 // Typedefs 115 // 116 //------------------------------------------------------------------------------ 117 118 type TLSInfo struct { 119 CertFile string `json:"CertFile"` 120 KeyFile string `json:"KeyFile"` 121 CAFile string `json:"CAFile"` 122 } 123 124 type Info struct { 125 Name string `json:"name"` 126 127 RaftURL string `json:"raftURL"` 128 EtcdURL string `json:"etcdURL"` 129 WebURL string `json:"webURL"` 130 131 RaftListenHost string `json:"raftListenHost"` 132 EtcdListenHost string `json:"etcdListenHost"` 133 134 RaftTLS TLSInfo `json:"raftTLS"` 135 EtcdTLS TLSInfo `json:"etcdTLS"` 136 } 137 138 type TLSConfig struct { 139 Scheme string 140 Server tls.Config 141 Client tls.Config 142 } 143 144 //------------------------------------------------------------------------------ 145 // 146 // Variables 147 // 148 //------------------------------------------------------------------------------ 149 150 var etcdStore *store.Store 151 152 //------------------------------------------------------------------------------ 153 // 154 // Functions 155 // 156 //------------------------------------------------------------------------------ 157 158 //-------------------------------------- 159 // Main 160 //-------------------------------------- 161 162 func main() { 163 flag.Parse() 164 165 if cpuprofile != "" { 166 runCPUProfile() 167 } 168 169 if veryVerbose { 170 verbose = true 171 raft.SetLogLevel(raft.Debug) 172 } 173 174 parseCorsFlag() 175 176 if machines != "" { 177 cluster = strings.Split(machines, ",") 178 } else if machinesFile != "" { 179 b, err := ioutil.ReadFile(machinesFile) 180 if err != nil { 181 fatalf("Unable to read the given machines file: %s", err) 182 } 183 cluster = strings.Split(string(b), ",") 184 } 185 186 // Check TLS arguments 187 raftTLSConfig, ok := tlsConfigFromInfo(argInfo.RaftTLS) 188 if !ok { 189 fatal("Please specify cert and key file or cert and key file and CAFile or none of the three") 190 } 191 192 etcdTLSConfig, ok := tlsConfigFromInfo(argInfo.EtcdTLS) 193 if !ok { 194 fatal("Please specify cert and key file or cert and key file and CAFile or none of the three") 195 } 196 197 argInfo.Name = strings.TrimSpace(argInfo.Name) 198 if argInfo.Name == "" { 199 fatal("ERROR: server name required. e.g. '-n=server_name'") 200 } 201 202 // Check host name arguments 203 argInfo.RaftURL = sanitizeURL(argInfo.RaftURL, raftTLSConfig.Scheme) 204 argInfo.EtcdURL = sanitizeURL(argInfo.EtcdURL, etcdTLSConfig.Scheme) 205 argInfo.WebURL = sanitizeURL(argInfo.WebURL, "http") 206 207 argInfo.RaftListenHost = sanitizeListenHost(argInfo.RaftListenHost, argInfo.RaftURL) 208 argInfo.EtcdListenHost = sanitizeListenHost(argInfo.EtcdListenHost, argInfo.EtcdURL) 209 210 // Read server info from file or grab it from user. 211 if err := os.MkdirAll(dirPath, 0744); err != nil { 212 fatalf("Unable to create path: %s", err) 213 } 214 215 info := getInfo(dirPath) 216 217 // Create etcd key-value store 218 etcdStore = store.CreateStore(maxSize) 219 snapConf = newSnapshotConf() 220 221 // Create etcd and raft server 222 e = newEtcdServer(info.Name, info.EtcdURL, info.EtcdListenHost, &etcdTLSConfig, &info.EtcdTLS) 223 r = newRaftServer(info.Name, info.RaftURL, info.RaftListenHost, &raftTLSConfig, &info.RaftTLS) 224 225 startWebInterface() 226 r.ListenAndServe() 227 e.ListenAndServe() 228 229 } 230 231 // parseCorsFlag gathers up the cors whitelist and puts it into the corsList. 232 func parseCorsFlag() { 233 if cors != "" { 234 corsList = make(map[string]bool) 235 list := strings.Split(cors, ",") 236 for _, v := range list { 237 fmt.Println(v) 238 if v != "*" { 239 _, err := url.Parse(v) 240 if err != nil { 241 panic(fmt.Sprintf("bad cors url: %s", err)) 242 } 243 } 244 corsList[v] = true 245 } 246 } 247 }