|
|
@@ -16,6 +16,8 @@ package etcdmain
|
|
|
|
|
|
import (
|
|
|
"context"
|
|
|
+ "crypto/tls"
|
|
|
+ "crypto/x509"
|
|
|
"fmt"
|
|
|
"io/ioutil"
|
|
|
"log"
|
|
|
@@ -31,7 +33,6 @@ import (
|
|
|
"go.etcd.io/etcd/clientv3/leasing"
|
|
|
"go.etcd.io/etcd/clientv3/namespace"
|
|
|
"go.etcd.io/etcd/clientv3/ordering"
|
|
|
- "go.etcd.io/etcd/etcdserver/api/etcdhttp"
|
|
|
"go.etcd.io/etcd/etcdserver/api/v3election/v3electionpb"
|
|
|
"go.etcd.io/etcd/etcdserver/api/v3lock/v3lockpb"
|
|
|
pb "go.etcd.io/etcd/etcdserver/etcdserverpb"
|
|
|
@@ -114,7 +115,7 @@ func newGRPCProxyStartCommand() *cobra.Command {
|
|
|
cmd.Flags().StringVar(&grpcProxyListenAddr, "listen-addr", "127.0.0.1:23790", "listen address")
|
|
|
cmd.Flags().StringVar(&grpcProxyDNSCluster, "discovery-srv", "", "domain name to query for SRV records describing cluster endpoints")
|
|
|
cmd.Flags().StringVar(&grpcProxyDNSClusterServiceName, "discovery-srv-name", "", "service name to query when using DNS discovery")
|
|
|
- cmd.Flags().StringVar(&grpcProxyMetricsListenAddr, "metrics-addr", "", "listen for /metrics requests on an additional interface")
|
|
|
+ cmd.Flags().StringVar(&grpcProxyMetricsListenAddr, "metrics-addr", "", "listen for endpoint /metrics requests on an additional interface")
|
|
|
cmd.Flags().BoolVar(&grpcProxyInsecureDiscovery, "insecure-discovery", false, "accept insecure SRV records")
|
|
|
cmd.Flags().StringSliceVar(&grpcProxyEndpoints, "endpoints", []string{"127.0.0.1:2379"}, "comma separated etcd cluster endpoints")
|
|
|
cmd.Flags().StringVar(&grpcProxyAdvertiseClientURL, "advertise-client-url", "127.0.0.1:23790", "advertise address to register (must be reachable by client)")
|
|
|
@@ -184,7 +185,6 @@ func startGRPCProxy(cmd *cobra.Command, args []string) {
|
|
|
lg.Info("gRPC proxy server TLS", zap.String("tls-info", fmt.Sprintf("%+v", tlsinfo)))
|
|
|
}
|
|
|
m := mustListenCMux(lg, tlsinfo)
|
|
|
-
|
|
|
grpcl := m.Match(cmux.HTTP2())
|
|
|
defer func() {
|
|
|
grpcl.Close()
|
|
|
@@ -192,6 +192,7 @@ func startGRPCProxy(cmd *cobra.Command, args []string) {
|
|
|
}()
|
|
|
|
|
|
client := mustNewClient(lg)
|
|
|
+ httpClient := mustNewHTTPClient(lg)
|
|
|
|
|
|
srvhttp, httpl := mustHTTPListener(lg, m, tlsinfo, client)
|
|
|
errc := make(chan error)
|
|
|
@@ -202,7 +203,7 @@ func startGRPCProxy(cmd *cobra.Command, args []string) {
|
|
|
mhttpl := mustMetricsListener(lg, tlsinfo)
|
|
|
go func() {
|
|
|
mux := http.NewServeMux()
|
|
|
- etcdhttp.HandlePrometheus(mux)
|
|
|
+ grpcproxy.HandleMetrics(mux, httpClient, client.Endpoints())
|
|
|
grpcproxy.HandleHealth(mux, client)
|
|
|
lg.Info("gRPC proxy server metrics URL serving")
|
|
|
herr := http.Serve(mhttpl, mux)
|
|
|
@@ -372,16 +373,14 @@ func newGRPCProxyServer(lg *zap.Logger, client *clientv3.Client) *grpc.Server {
|
|
|
v3electionpb.RegisterElectionServer(server, electionp)
|
|
|
v3lockpb.RegisterLockServer(server, lockp)
|
|
|
|
|
|
- // set zero values for metrics registered for this grpc server
|
|
|
- grpc_prometheus.Register(server)
|
|
|
-
|
|
|
return server
|
|
|
}
|
|
|
|
|
|
func mustHTTPListener(lg *zap.Logger, m cmux.CMux, tlsinfo *transport.TLSInfo, c *clientv3.Client) (*http.Server, net.Listener) {
|
|
|
+ httpClient := mustNewHTTPClient(lg)
|
|
|
httpmux := http.NewServeMux()
|
|
|
httpmux.HandleFunc("/", http.NotFound)
|
|
|
- etcdhttp.HandlePrometheus(httpmux)
|
|
|
+ grpcproxy.HandleMetrics(httpmux, httpClient, c.Endpoints())
|
|
|
grpcproxy.HandleHealth(httpmux, c)
|
|
|
if grpcProxyEnablePprof {
|
|
|
for p, h := range debugutil.PProfHandlers() {
|
|
|
@@ -406,6 +405,43 @@ func mustHTTPListener(lg *zap.Logger, m cmux.CMux, tlsinfo *transport.TLSInfo, c
|
|
|
return srvhttp, m.Match(cmux.Any())
|
|
|
}
|
|
|
|
|
|
+func mustNewHTTPClient(lg *zap.Logger) *http.Client {
|
|
|
+ transport, err := newHTTPTransport(grpcProxyCA, grpcProxyCert, grpcProxyKey)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Fprintln(os.Stderr, err)
|
|
|
+ os.Exit(1)
|
|
|
+ }
|
|
|
+ return &http.Client{Transport: transport}
|
|
|
+}
|
|
|
+
|
|
|
+func newHTTPTransport(ca, cert, key string) (*http.Transport, error) {
|
|
|
+ tr := &http.Transport{}
|
|
|
+
|
|
|
+ if ca != "" && cert != "" && key != "" {
|
|
|
+ caCert, err := ioutil.ReadFile(ca)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ keyPair, err := tls.LoadX509KeyPair(cert, key)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ caPool := x509.NewCertPool()
|
|
|
+ caPool.AppendCertsFromPEM(caCert)
|
|
|
+
|
|
|
+ tlsConfig := &tls.Config{
|
|
|
+ Certificates: []tls.Certificate{keyPair},
|
|
|
+ RootCAs: caPool,
|
|
|
+ }
|
|
|
+ tlsConfig.BuildNameToCertificate()
|
|
|
+ tr.TLSClientConfig = tlsConfig
|
|
|
+ } else if grpcProxyInsecureSkipTLSVerify {
|
|
|
+ tlsConfig := &tls.Config{InsecureSkipVerify: grpcProxyInsecureSkipTLSVerify}
|
|
|
+ tr.TLSClientConfig = tlsConfig
|
|
|
+ }
|
|
|
+ return tr, nil
|
|
|
+}
|
|
|
+
|
|
|
func mustMetricsListener(lg *zap.Logger, tlsinfo *transport.TLSInfo) net.Listener {
|
|
|
murl, err := url.Parse(grpcProxyMetricsListenAddr)
|
|
|
if err != nil {
|