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  }