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  }