github.com/matm/etcd@v0.3.1-0.20140328024009-5b4a473f1453/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 "fmt" 21 "net/http" 22 "os" 23 "path/filepath" 24 "runtime" 25 "time" 26 27 "github.com/coreos/etcd/third_party/github.com/goraft/raft" 28 29 "github.com/coreos/etcd/config" 30 ehttp "github.com/coreos/etcd/http" 31 "github.com/coreos/etcd/log" 32 "github.com/coreos/etcd/metrics" 33 "github.com/coreos/etcd/server" 34 "github.com/coreos/etcd/store" 35 ) 36 37 func main() { 38 // Load configuration. 39 var config = config.New() 40 if err := config.Load(os.Args[1:]); err != nil { 41 fmt.Println(server.Usage() + "\n") 42 fmt.Println(err.Error() + "\n") 43 os.Exit(1) 44 } else if config.ShowVersion { 45 fmt.Println("etcd version", server.ReleaseVersion) 46 os.Exit(0) 47 } else if config.ShowHelp { 48 fmt.Println(server.Usage() + "\n") 49 os.Exit(0) 50 } 51 52 // Enable options. 53 if config.VeryVeryVerbose { 54 log.Verbose = true 55 raft.SetLogLevel(raft.Trace) 56 } else if config.VeryVerbose { 57 log.Verbose = true 58 raft.SetLogLevel(raft.Debug) 59 } else if config.Verbose { 60 log.Verbose = true 61 } 62 if config.CPUProfileFile != "" { 63 profile(config.CPUProfileFile) 64 } 65 66 if config.DataDir == "" { 67 log.Fatal("The data dir was not set and could not be guessed from machine name") 68 } 69 70 // Create data directory if it doesn't already exist. 71 if err := os.MkdirAll(config.DataDir, 0744); err != nil { 72 log.Fatalf("Unable to create path: %s", err) 73 } 74 75 // Warn people if they have an info file 76 info := filepath.Join(config.DataDir, "info") 77 if _, err := os.Stat(info); err == nil { 78 log.Warnf("All cached configuration is now ignored. The file %s can be removed.", info) 79 } 80 81 var mbName string 82 if config.Trace() { 83 mbName = config.MetricsBucketName() 84 runtime.SetBlockProfileRate(1) 85 } 86 87 mb := metrics.NewBucket(mbName) 88 89 if config.GraphiteHost != "" { 90 err := mb.Publish(config.GraphiteHost) 91 if err != nil { 92 panic(err) 93 } 94 } 95 96 // Retrieve CORS configuration 97 corsInfo, err := ehttp.NewCORSInfo(config.CorsOrigins) 98 if err != nil { 99 log.Fatal("CORS:", err) 100 } 101 102 // Create etcd key-value store and registry. 103 store := store.New() 104 registry := server.NewRegistry(store) 105 106 // Create stats objects 107 followersStats := server.NewRaftFollowersStats(config.Name) 108 serverStats := server.NewRaftServerStats(config.Name) 109 110 // Calculate all of our timeouts 111 heartbeatInterval := time.Duration(config.Peer.HeartbeatInterval) * time.Millisecond 112 electionTimeout := time.Duration(config.Peer.ElectionTimeout) * time.Millisecond 113 dialTimeout := (3 * heartbeatInterval) + electionTimeout 114 responseHeaderTimeout := (3 * heartbeatInterval) + electionTimeout 115 116 // Create peer server 117 psConfig := server.PeerServerConfig{ 118 Name: config.Name, 119 Scheme: config.PeerTLSInfo().Scheme(), 120 URL: config.Peer.Addr, 121 SnapshotCount: config.SnapshotCount, 122 RetryTimes: config.MaxRetryAttempts, 123 RetryInterval: config.RetryInterval, 124 } 125 ps := server.NewPeerServer(psConfig, registry, store, &mb, followersStats, serverStats) 126 127 // Create raft transporter and server 128 raftTransporter := server.NewTransporter(followersStats, serverStats, registry, heartbeatInterval, dialTimeout, responseHeaderTimeout) 129 if psConfig.Scheme == "https" { 130 raftClientTLSConfig, err := config.PeerTLSInfo().ClientConfig() 131 if err != nil { 132 log.Fatal("raft client TLS error: ", err) 133 } 134 raftTransporter.SetTLSConfig(*raftClientTLSConfig) 135 } 136 raftServer, err := raft.NewServer(config.Name, config.DataDir, raftTransporter, store, ps, "") 137 if err != nil { 138 log.Fatal(err) 139 } 140 raftServer.SetElectionTimeout(electionTimeout) 141 raftServer.SetHeartbeatInterval(heartbeatInterval) 142 ps.SetRaftServer(raftServer) 143 144 // Create etcd server 145 s := server.New(config.Name, config.Addr, ps, registry, store, &mb) 146 147 if config.Trace() { 148 s.EnableTracing() 149 } 150 151 ps.SetServer(s) 152 153 // Generating config could be slow. 154 // Put it here to make listen happen immediately after peer-server starting. 155 peerTLSConfig := server.TLSServerConfig(config.PeerTLSInfo()) 156 etcdTLSConfig := server.TLSServerConfig(config.EtcdTLSInfo()) 157 158 go func() { 159 // Starting peer server should be followed close by listening on its port 160 // If not, it may leave many requests unaccepted, or cannot receive heartbeat from the cluster. 161 // One severe problem caused if failing receiving heartbeats is when the second node joins one-node cluster, 162 // the cluster could be out of work as long as the two nodes cannot transfer messages. 163 ps.Start(config.Snapshot, config.Discovery, config.Peers) 164 log.Infof("peer server [name %s, listen on %s, advertised url %s]", ps.Config.Name, config.Peer.BindAddr, ps.Config.URL) 165 l := server.NewListener(psConfig.Scheme, config.Peer.BindAddr, peerTLSConfig) 166 167 sHTTP := &ehttp.CORSHandler{ps.HTTPHandler(), corsInfo} 168 log.Fatal(http.Serve(l, sHTTP)) 169 }() 170 171 log.Infof("etcd server [name %s, listen on %s, advertised url %s]", s.Name, config.BindAddr, s.URL()) 172 l := server.NewListener(config.EtcdTLSInfo().Scheme(), config.BindAddr, etcdTLSConfig) 173 sHTTP := &ehttp.CORSHandler{s.HTTPHandler(), corsInfo} 174 log.Fatal(http.Serve(l, sHTTP)) 175 }