go.etcd.io/etcd@v3.3.27+incompatible/etcdmain/gateway.go (about) 1 // Copyright 2016 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package etcdmain 16 17 import ( 18 "fmt" 19 "net" 20 "net/url" 21 "os" 22 "time" 23 24 "github.com/coreos/etcd/proxy/tcpproxy" 25 26 "github.com/spf13/cobra" 27 ) 28 29 var ( 30 gatewayListenAddr string 31 gatewayEndpoints []string 32 gatewayDNSCluster string 33 gatewayInsecureDiscovery bool 34 getewayRetryDelay time.Duration 35 gatewayCA string 36 ) 37 38 var ( 39 rootCmd = &cobra.Command{ 40 Use: "etcd", 41 Short: "etcd server", 42 SuggestFor: []string{"etcd"}, 43 } 44 ) 45 46 func init() { 47 rootCmd.AddCommand(newGatewayCommand()) 48 } 49 50 // newGatewayCommand returns the cobra command for "gateway". 51 func newGatewayCommand() *cobra.Command { 52 lpc := &cobra.Command{ 53 Use: "gateway <subcommand>", 54 Short: "gateway related command", 55 } 56 lpc.AddCommand(newGatewayStartCommand()) 57 58 return lpc 59 } 60 61 func newGatewayStartCommand() *cobra.Command { 62 cmd := cobra.Command{ 63 Use: "start", 64 Short: "start the gateway", 65 Run: startGateway, 66 } 67 68 cmd.Flags().StringVar(&gatewayListenAddr, "listen-addr", "127.0.0.1:23790", "listen address") 69 cmd.Flags().StringVar(&gatewayDNSCluster, "discovery-srv", "", "DNS domain used to bootstrap initial cluster") 70 cmd.Flags().BoolVar(&gatewayInsecureDiscovery, "insecure-discovery", false, "accept insecure SRV records") 71 cmd.Flags().StringVar(&gatewayCA, "trusted-ca-file", "", "path to the client server TLS CA file for verifying the discovered endpoints when discovery-srv is provided.") 72 73 cmd.Flags().StringSliceVar(&gatewayEndpoints, "endpoints", []string{"127.0.0.1:2379"}, "comma separated etcd cluster endpoints") 74 75 cmd.Flags().DurationVar(&getewayRetryDelay, "retry-delay", time.Minute, "duration of delay before retrying failed endpoints") 76 77 return &cmd 78 } 79 80 func stripSchema(eps []string) []string { 81 var endpoints []string 82 83 for _, ep := range eps { 84 85 if u, err := url.Parse(ep); err == nil && u.Host != "" { 86 ep = u.Host 87 } 88 89 endpoints = append(endpoints, ep) 90 } 91 92 return endpoints 93 } 94 95 func startGateway(cmd *cobra.Command, args []string) { 96 srvs := discoverEndpoints(gatewayDNSCluster, gatewayCA, gatewayInsecureDiscovery) 97 if len(srvs.Endpoints) == 0 { 98 // no endpoints discovered, fall back to provided endpoints 99 srvs.Endpoints = gatewayEndpoints 100 } 101 // Strip the schema from the endpoints because we start just a TCP proxy 102 srvs.Endpoints = stripSchema(srvs.Endpoints) 103 if len(srvs.SRVs) == 0 { 104 for _, ep := range srvs.Endpoints { 105 h, p, err := net.SplitHostPort(ep) 106 if err != nil { 107 plog.Fatalf("error parsing endpoint %q", ep) 108 } 109 var port uint16 110 fmt.Sscanf(p, "%d", &port) 111 srvs.SRVs = append(srvs.SRVs, &net.SRV{Target: h, Port: port}) 112 } 113 } 114 115 lhost, lport, err := net.SplitHostPort(gatewayListenAddr) 116 if err != nil { 117 fmt.Println("failed to validate listen address:", gatewayListenAddr) 118 os.Exit(1) 119 } 120 121 laddrs, err := net.LookupHost(lhost) 122 if err != nil { 123 fmt.Println("failed to resolve listen host:", lhost) 124 os.Exit(1) 125 } 126 laddrsMap := make(map[string]bool) 127 for _, addr := range laddrs { 128 laddrsMap[addr] = true 129 } 130 131 for _, srv := range srvs.SRVs { 132 eaddrs, err := net.LookupHost(srv.Target) 133 if err != nil { 134 fmt.Println("failed to resolve endpoint host:", srv.Target) 135 os.Exit(1) 136 } 137 if fmt.Sprintf("%d", srv.Port) != lport { 138 continue 139 } 140 141 for _, ea := range eaddrs { 142 if laddrsMap[ea] { 143 fmt.Printf("SRV or endpoint (%s:%d->%s:%d) should not resolve to the gateway listen addr (%s)\n", srv.Target, srv.Port, ea, srv.Port, gatewayListenAddr) 144 os.Exit(1) 145 } 146 } 147 } 148 149 if len(srvs.Endpoints) == 0 { 150 plog.Fatalf("no endpoints found") 151 } 152 153 l, err := net.Listen("tcp", gatewayListenAddr) 154 if err != nil { 155 fmt.Fprintln(os.Stderr, err) 156 os.Exit(1) 157 } 158 159 tp := tcpproxy.TCPProxy{ 160 Listener: l, 161 Endpoints: srvs.SRVs, 162 MonitorInterval: getewayRetryDelay, 163 } 164 165 // At this point, etcd gateway listener is initialized 166 notifySystemd() 167 168 tp.Run() 169 }