github.com/kafkaliu/etcd@v0.1.2-0.20131007164923-44c16dd30d69/util.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  	"encoding/json"
    21  	"fmt"
    22  	"io"
    23  	"net"
    24  	"net/http"
    25  	"net/url"
    26  	"os"
    27  	"os/signal"
    28  	"runtime/pprof"
    29  	"strconv"
    30  	"time"
    31  
    32  	"github.com/coreos/etcd/web"
    33  	"github.com/coreos/go-log/log"
    34  )
    35  
    36  //--------------------------------------
    37  // etcd http Helper
    38  //--------------------------------------
    39  
    40  // Convert string duration to time format
    41  func durationToExpireTime(strDuration string) (time.Time, error) {
    42  	if strDuration != "" {
    43  		duration, err := strconv.Atoi(strDuration)
    44  
    45  		if err != nil {
    46  			return time.Unix(0, 0), err
    47  		}
    48  		return time.Now().Add(time.Second * (time.Duration)(duration)), nil
    49  
    50  	} else {
    51  		return time.Unix(0, 0), nil
    52  	}
    53  }
    54  
    55  //--------------------------------------
    56  // Web Helper
    57  //--------------------------------------
    58  var storeMsg chan string
    59  
    60  // Help to send msg from store to webHub
    61  func webHelper() {
    62  	storeMsg = make(chan string)
    63  	etcdStore.SetMessager(storeMsg)
    64  	for {
    65  		// transfer the new msg to webHub
    66  		web.Hub().Send(<-storeMsg)
    67  	}
    68  }
    69  
    70  // startWebInterface starts web interface if webURL is not empty
    71  func startWebInterface() {
    72  	if argInfo.WebURL != "" {
    73  		// start web
    74  		go webHelper()
    75  		go web.Start(r.Server, argInfo.WebURL)
    76  	}
    77  }
    78  
    79  //--------------------------------------
    80  // HTTP Utilities
    81  //--------------------------------------
    82  
    83  func decodeJsonRequest(req *http.Request, data interface{}) error {
    84  	decoder := json.NewDecoder(req.Body)
    85  	if err := decoder.Decode(&data); err != nil && err != io.EOF {
    86  		warnf("Malformed json request: %v", err)
    87  		return fmt.Errorf("Malformed json request: %v", err)
    88  	}
    89  	return nil
    90  }
    91  
    92  func encodeJsonResponse(w http.ResponseWriter, status int, data interface{}) {
    93  	w.Header().Set("Content-Type", "application/json")
    94  	w.WriteHeader(status)
    95  
    96  	if data != nil {
    97  		encoder := json.NewEncoder(w)
    98  		encoder.Encode(data)
    99  	}
   100  }
   101  
   102  // sanitizeURL will cleanup a host string in the format hostname:port and
   103  // attach a schema.
   104  func sanitizeURL(host string, defaultScheme string) string {
   105  	// Blank URLs are fine input, just return it
   106  	if len(host) == 0 {
   107  		return host
   108  	}
   109  
   110  	p, err := url.Parse(host)
   111  	if err != nil {
   112  		fatal(err)
   113  	}
   114  
   115  	// Make sure the host is in Host:Port format
   116  	_, _, err = net.SplitHostPort(host)
   117  	if err != nil {
   118  		fatal(err)
   119  	}
   120  
   121  	p = &url.URL{Host: host, Scheme: defaultScheme}
   122  
   123  	return p.String()
   124  }
   125  
   126  // sanitizeListenHost cleans up the ListenHost parameter and appends a port
   127  // if necessary based on the advertised port.
   128  func sanitizeListenHost(listen string, advertised string) string {
   129  	aurl, err := url.Parse(advertised)
   130  	if err != nil {
   131  		fatal(err)
   132  	}
   133  
   134  	ahost, aport, err := net.SplitHostPort(aurl.Host)
   135  	if err != nil {
   136  		fatal(err)
   137  	}
   138  
   139  	// If the listen host isn't set use the advertised host
   140  	if listen == "" {
   141  		listen = ahost
   142  	}
   143  
   144  	return net.JoinHostPort(listen, aport)
   145  }
   146  
   147  func redirect(node string, etcd bool, w http.ResponseWriter, req *http.Request) {
   148  	var url string
   149  	path := req.URL.Path
   150  
   151  	if etcd {
   152  		etcdAddr, _ := nameToEtcdURL(node)
   153  		url = etcdAddr + path
   154  	} else {
   155  		raftAddr, _ := nameToRaftURL(node)
   156  		url = raftAddr + path
   157  	}
   158  
   159  	debugf("Redirect to %s", url)
   160  
   161  	http.Redirect(w, req, url, http.StatusTemporaryRedirect)
   162  }
   163  
   164  func check(err error) {
   165  	if err != nil {
   166  		fatal(err)
   167  	}
   168  }
   169  
   170  //--------------------------------------
   171  // Log
   172  //--------------------------------------
   173  
   174  var logger *log.Logger = log.New("etcd", false,
   175  	log.CombinedSink(os.Stdout, "[%s] %s %-9s | %s\n", []string{"prefix", "time", "priority", "message"}))
   176  
   177  func infof(format string, v ...interface{}) {
   178  	logger.Infof(format, v...)
   179  }
   180  
   181  func debugf(format string, v ...interface{}) {
   182  	if verbose {
   183  		logger.Debugf(format, v...)
   184  	}
   185  }
   186  
   187  func debug(v ...interface{}) {
   188  	if verbose {
   189  		logger.Debug(v...)
   190  	}
   191  }
   192  
   193  func warnf(format string, v ...interface{}) {
   194  	logger.Warningf(format, v...)
   195  }
   196  
   197  func warn(v ...interface{}) {
   198  	logger.Warning(v...)
   199  }
   200  
   201  func fatalf(format string, v ...interface{}) {
   202  	logger.Fatalf(format, v...)
   203  }
   204  
   205  func fatal(v ...interface{}) {
   206  	logger.Fatalln(v...)
   207  }
   208  
   209  //--------------------------------------
   210  // CPU profile
   211  //--------------------------------------
   212  func runCPUProfile() {
   213  
   214  	f, err := os.Create(cpuprofile)
   215  	if err != nil {
   216  		fatal(err)
   217  	}
   218  	pprof.StartCPUProfile(f)
   219  
   220  	c := make(chan os.Signal, 1)
   221  	signal.Notify(c, os.Interrupt)
   222  	go func() {
   223  		for sig := range c {
   224  			infof("captured %v, stopping profiler and exiting..", sig)
   225  			pprof.StopCPUProfile()
   226  			os.Exit(1)
   227  		}
   228  	}()
   229  }
   230  
   231  //--------------------------------------
   232  // Testing
   233  //--------------------------------------
   234  func directSet() {
   235  	c := make(chan bool, 1000)
   236  	for i := 0; i < 1000; i++ {
   237  		go send(c)
   238  	}
   239  
   240  	for i := 0; i < 1000; i++ {
   241  		<-c
   242  	}
   243  }
   244  
   245  func send(c chan bool) {
   246  	for i := 0; i < 10; i++ {
   247  		command := &SetCommand{}
   248  		command.Key = "foo"
   249  		command.Value = "bar"
   250  		command.ExpireTime = time.Unix(0, 0)
   251  		r.Do(command)
   252  	}
   253  	c <- true
   254  }