func mustNewTransport(t *testing.T, tlsInfo transport.TLSInfo) *http.Transport { // tick in integration test is short, so 1s dial timeout could play well. tr, err := transport.NewTimeoutTransport(tlsInfo, time.Second, rafthttp.ConnReadTimeout, rafthttp.ConnWriteTimeout) if err != nil { t.Fatal(err) } return tr }
func (t *Transport) Start() error { var err error // Read/write timeout is set for stream roundTripper to promptly // find out broken status, which minimizes the number of messages // sent on broken connection. t.streamRt, err = transport.NewTimeoutTransport(t.TLSInfo, t.DialTimeout, ConnReadTimeout, ConnWriteTimeout) if err != nil { return err } t.pipelineRt, err = transport.NewTransport(t.TLSInfo, t.DialTimeout) if err != nil { return err } t.remotes = make(map[types.ID]*remote) t.peers = make(map[types.ID]Peer) t.snapst = &snapshotStore{} t.prober = probing.NewProber(t.pipelineRt) return nil }
// startProxy launches an HTTP proxy for client communication which proxies to other etcd nodes. func startProxy(cfg *config) error { urlsmap, _, err := getPeerURLsMapAndToken(cfg, "proxy") if err != nil { return fmt.Errorf("error setting up initial cluster: %v", err) } pt, err := transport.NewTimeoutTransport(cfg.peerTLSInfo, time.Duration(cfg.proxyDialTimeoutMs)*time.Millisecond, time.Duration(cfg.proxyReadTimeoutMs)*time.Millisecond, time.Duration(cfg.proxyWriteTimeoutMs)*time.Millisecond) if err != nil { return err } pt.MaxIdleConnsPerHost = proxy.DefaultMaxIdleConnsPerHost tr, err := transport.NewTimeoutTransport(cfg.peerTLSInfo, time.Duration(cfg.proxyDialTimeoutMs)*time.Millisecond, time.Duration(cfg.proxyReadTimeoutMs)*time.Millisecond, time.Duration(cfg.proxyWriteTimeoutMs)*time.Millisecond) if err != nil { return err } cfg.dir = path.Join(cfg.dir, "proxy") err = os.MkdirAll(cfg.dir, 0700) if err != nil { return err } var peerURLs []string clusterfile := path.Join(cfg.dir, "cluster") b, err := ioutil.ReadFile(clusterfile) switch { case err == nil: if cfg.durl != "" { plog.Warningf("discovery token ignored since the proxy has already been initialized. Valid cluster file found at %q", clusterfile) } urls := struct{ PeerURLs []string }{} err := json.Unmarshal(b, &urls) if err != nil { return err } peerURLs = urls.PeerURLs plog.Infof("proxy: using peer urls %v from cluster file %q", peerURLs, clusterfile) case os.IsNotExist(err): if cfg.durl != "" { s, err := discovery.GetCluster(cfg.durl, cfg.dproxy) if err != nil { return err } if urlsmap, err = types.NewURLsMap(s); err != nil { return err } } peerURLs = urlsmap.URLs() plog.Infof("proxy: using peer urls %v ", peerURLs) default: return err } clientURLs := []string{} uf := func() []string { gcls, err := etcdserver.GetClusterFromRemotePeers(peerURLs, tr) // TODO: remove the 2nd check when we fix GetClusterFromPeers // GetClusterFromPeers should not return nil error with an invalid empty cluster if err != nil { plog.Warningf("proxy: %v", err) return []string{} } if len(gcls.Members()) == 0 { return clientURLs } clientURLs = gcls.ClientURLs() urls := struct{ PeerURLs []string }{gcls.PeerURLs()} b, err := json.Marshal(urls) if err != nil { plog.Warningf("proxy: error on marshal peer urls %s", err) return clientURLs } err = ioutil.WriteFile(clusterfile+".bak", b, 0600) if err != nil { plog.Warningf("proxy: error on writing urls %s", err) return clientURLs } err = os.Rename(clusterfile+".bak", clusterfile) if err != nil { plog.Warningf("proxy: error on updating clusterfile %s", err) return clientURLs } if !reflect.DeepEqual(gcls.PeerURLs(), peerURLs) { plog.Noticef("proxy: updated peer urls in cluster file from %v to %v", peerURLs, gcls.PeerURLs()) } peerURLs = gcls.PeerURLs() return clientURLs } ph := proxy.NewHandler(pt, uf, time.Duration(cfg.proxyFailureWaitMs)*time.Millisecond, time.Duration(cfg.proxyRefreshIntervalMs)*time.Millisecond) ph = &cors.CORSHandler{ Handler: ph, Info: cfg.corsInfo, } if cfg.isReadonlyProxy() { ph = proxy.NewReadonlyHandler(ph) } // Start a proxy server goroutine for each listen address for _, u := range cfg.lcurls { l, err := transport.NewListener(u.Host, u.Scheme, cfg.clientTLSInfo) if err != nil { return err } host := u.String() go func() { plog.Info("proxy: listening for client requests on ", host) mux := http.NewServeMux() mux.Handle("/metrics", prometheus.Handler()) mux.Handle("/", ph) plog.Fatal(http.Serve(l, mux)) }() } return nil }