2016-05-13 06:51:48 +03:00
// Copyright 2016 The etcd Authors
2016-04-15 07:00:03 +03:00
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package etcdmain
import (
"fmt"
"net"
2017-03-08 21:00:11 +03:00
"net/url"
2016-04-15 07:00:03 +03:00
"os"
2016-05-13 03:03:00 +03:00
"time"
2016-04-15 07:00:03 +03:00
2020-04-27 00:03:37 +03:00
"go.etcd.io/etcd/v3/proxy/tcpproxy"
2017-03-09 20:11:43 +03:00
2016-04-15 07:00:03 +03:00
"github.com/spf13/cobra"
2018-04-27 00:22:58 +03:00
"go.uber.org/zap"
2016-04-15 07:00:03 +03:00
)
var (
2018-11-09 17:48:35 +03:00
gatewayListenAddr string
gatewayEndpoints [ ] string
gatewayDNSCluster string
gatewayDNSClusterServiceName string
gatewayInsecureDiscovery bool
2020-04-02 05:04:35 +03:00
gatewayRetryDelay time . Duration
2018-11-09 17:48:35 +03:00
gatewayCA string
2016-04-15 07:00:03 +03:00
)
var (
rootCmd = & cobra . Command {
Use : "etcd" ,
Short : "etcd server" ,
SuggestFor : [ ] string { "etcd" } ,
}
)
func init ( ) {
rootCmd . AddCommand ( newGatewayCommand ( ) )
}
// newGatewayCommand returns the cobra command for "gateway".
func newGatewayCommand ( ) * cobra . Command {
lpc := & cobra . Command {
Use : "gateway <subcommand>" ,
Short : "gateway related command" ,
}
lpc . AddCommand ( newGatewayStartCommand ( ) )
return lpc
}
func newGatewayStartCommand ( ) * cobra . Command {
cmd := cobra . Command {
Use : "start" ,
Short : "start the gateway" ,
Run : startGateway ,
}
cmd . Flags ( ) . StringVar ( & gatewayListenAddr , "listen-addr" , "127.0.0.1:23790" , "listen address" )
2016-07-19 06:26:42 +03:00
cmd . Flags ( ) . StringVar ( & gatewayDNSCluster , "discovery-srv" , "" , "DNS domain used to bootstrap initial cluster" )
2018-11-09 17:48:35 +03:00
cmd . Flags ( ) . StringVar ( & gatewayDNSClusterServiceName , "discovery-srv-name" , "" , "service name to query when using DNS discovery" )
2016-08-03 02:52:05 +03:00
cmd . Flags ( ) . BoolVar ( & gatewayInsecureDiscovery , "insecure-discovery" , false , "accept insecure SRV records" )
2020-06-24 07:07:36 +03:00
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." )
2016-07-19 06:26:42 +03:00
2016-05-13 03:03:00 +03:00
cmd . Flags ( ) . StringSliceVar ( & gatewayEndpoints , "endpoints" , [ ] string { "127.0.0.1:2379" } , "comma separated etcd cluster endpoints" )
2016-07-19 06:26:42 +03:00
2020-04-02 05:04:35 +03:00
cmd . Flags ( ) . DurationVar ( & gatewayRetryDelay , "retry-delay" , time . Minute , "duration of delay before retrying failed endpoints" )
2016-04-15 07:00:03 +03:00
return & cmd
}
2017-03-08 21:00:11 +03:00
func stripSchema ( eps [ ] string ) [ ] string {
var endpoints [ ] string
for _ , ep := range eps {
if u , err := url . Parse ( ep ) ; err == nil && u . Host != "" {
ep = u . Host
}
endpoints = append ( endpoints , ep )
}
return endpoints
}
2017-04-06 01:25:22 +03:00
2017-05-05 07:57:54 +03:00
func startGateway ( cmd * cobra . Command , args [ ] string ) {
2018-04-27 00:22:58 +03:00
var lg * zap . Logger
lg , err := zap . NewProduction ( )
if err != nil {
fmt . Fprintln ( os . Stderr , err )
os . Exit ( 1 )
}
2018-11-09 17:48:35 +03:00
srvs := discoverEndpoints ( lg , gatewayDNSCluster , gatewayCA , gatewayInsecureDiscovery , gatewayDNSClusterServiceName )
2017-05-05 07:57:54 +03:00
if len ( srvs . Endpoints ) == 0 {
// no endpoints discovered, fall back to provided endpoints
srvs . Endpoints = gatewayEndpoints
2016-08-03 02:52:05 +03:00
}
2017-03-08 21:00:11 +03:00
// Strip the schema from the endpoints because we start just a TCP proxy
2017-05-05 07:57:54 +03:00
srvs . Endpoints = stripSchema ( srvs . Endpoints )
if len ( srvs . SRVs ) == 0 {
for _ , ep := range srvs . Endpoints {
2018-05-09 23:18:13 +03:00
h , p , serr := net . SplitHostPort ( ep )
if serr != nil {
2018-04-15 08:52:39 +03:00
fmt . Printf ( "error parsing endpoint %q" , ep )
os . Exit ( 1 )
2017-05-05 07:57:54 +03:00
}
var port uint16
fmt . Sscanf ( p , "%d" , & port )
srvs . SRVs = append ( srvs . SRVs , & net . SRV { Target : h , Port : port } )
}
}
2017-03-08 21:00:11 +03:00
2020-05-05 01:42:01 +03:00
lhost , lport , err := net . SplitHostPort ( gatewayListenAddr )
if err != nil {
fmt . Println ( "failed to validate listen address:" , gatewayListenAddr )
os . Exit ( 1 )
}
laddrs , err := net . LookupHost ( lhost )
if err != nil {
fmt . Println ( "failed to resolve listen host:" , lhost )
os . Exit ( 1 )
}
laddrsMap := make ( map [ string ] bool )
for _ , addr := range laddrs {
laddrsMap [ addr ] = true
}
for _ , srv := range srvs . SRVs {
eaddrs , err := net . LookupHost ( srv . Target )
if err != nil {
fmt . Println ( "failed to resolve endpoint host:" , srv . Target )
os . Exit ( 1 )
}
if fmt . Sprintf ( "%d" , srv . Port ) != lport {
continue
}
for _ , ea := range eaddrs {
if laddrsMap [ ea ] {
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 )
os . Exit ( 1 )
}
}
}
2017-05-05 07:57:54 +03:00
if len ( srvs . Endpoints ) == 0 {
2018-04-15 08:52:39 +03:00
fmt . Println ( "no endpoints found" )
os . Exit ( 1 )
}
var l net . Listener
l , err = net . Listen ( "tcp" , gatewayListenAddr )
2016-04-15 07:00:03 +03:00
if err != nil {
fmt . Fprintln ( os . Stderr , err )
os . Exit ( 1 )
}
tp := tcpproxy . TCPProxy {
2018-04-15 08:52:39 +03:00
Logger : lg ,
2016-05-13 03:03:00 +03:00
Listener : l ,
2017-05-05 07:57:54 +03:00
Endpoints : srvs . SRVs ,
2020-04-02 05:04:35 +03:00
MonitorInterval : gatewayRetryDelay ,
2016-04-15 07:00:03 +03:00
}
2017-03-09 20:11:43 +03:00
// At this point, etcd gateway listener is initialized
2018-04-15 08:52:39 +03:00
notifySystemd ( lg )
2017-03-09 20:11:43 +03:00
2016-04-15 07:00:03 +03:00
tp . Run ( )
}