From 19ef1844e094cb3d1944b081aec8f977611cb429 Mon Sep 17 00:00:00 2001 From: "Daniel M. Lambea" Date: Thu, 8 Jun 2017 19:14:58 +0100 Subject: [PATCH 1/5] DNS-SRV based discovery function, derived from etcd's own. --- locksmithctl/discovery.go | 57 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 locksmithctl/discovery.go diff --git a/locksmithctl/discovery.go b/locksmithctl/discovery.go new file mode 100644 index 0000000..3bf6e69 --- /dev/null +++ b/locksmithctl/discovery.go @@ -0,0 +1,57 @@ +// Copyright 2015 CoreOS, Inc. +// +// 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 main + +import ( + "fmt" + "net" + "net/url" +) + +const ( + etcdClientService = "etcd-client" +) + +// discoverEndpoints looks up the client endpoints for a domain. +func discoverEndpoints(domain string) ([]string, error) { + var urls []*url.URL + + updateURLs := func(service, scheme string) error { + _, addrs, err := net.LookupSRV(service, "tcp", domain) + if err != nil { + return err + } + for _, srv := range addrs { + urls = append(urls, &url.URL{ + Scheme: scheme, + Host: net.JoinHostPort(srv.Target, fmt.Sprintf("%d", srv.Port)), + }) + } + return nil + } + + errHTTPS := updateURLs(etcdClientService+"-ssl", "https") + errHTTP := updateURLs(etcdClientService, "http") + + if errHTTPS != nil && errHTTP != nil { + return nil, fmt.Errorf("dns lookup errors: %s and %s", errHTTPS, errHTTP) + } + + endpoints := make([]string, len(urls)) + for i := range urls { + endpoints[i] = urls[i].String() + } + return endpoints, nil +} From 08e32ec4e07d96e0b57c2099c984211ded181aab Mon Sep 17 00:00:00 2001 From: "Daniel M. Lambea" Date: Thu, 8 Jun 2017 19:18:03 +0100 Subject: [PATCH 2/5] Added new cmdline flag '-discovery-srv' for using DNS SRV records for etcd client service discovery. '-endpoint' flag has precedence for backwards compatibility. --- locksmithctl/locksmithctl.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/locksmithctl/locksmithctl.go b/locksmithctl/locksmithctl.go index 9721e21..d4eac0e 100644 --- a/locksmithctl/locksmithctl.go +++ b/locksmithctl/locksmithctl.go @@ -47,6 +47,7 @@ var ( globalFlags = struct { Debug bool + DiscoverySrv string Endpoints endpoints EtcdKeyFile string EtcdCertFile string @@ -86,7 +87,8 @@ func init() { out.Init(os.Stdout, 0, 8, 1, '\t', 0) globalFlagSet.BoolVar(&globalFlags.Debug, "debug", false, "Print out debug information to stderr.") - globalFlagSet.Var(&globalFlags.Endpoints, "endpoint", "etcd endpoint for locksmith. Specify multiple times to use multiple endpoints.") + globalFlagSet.StringVar(&globalFlags.DiscoverySrv, "discovery-srv", "", "DNS domain used to discover the etcd endpoints.") + globalFlagSet.Var(&globalFlags.Endpoints, "endpoint", "etcd endpoint for locksmith. Specify multiple times to use multiple endpoints. Overrides discovery-srv option.") globalFlagSet.StringVar(&globalFlags.EtcdKeyFile, "etcd-keyfile", "", "etcd key file authentication") globalFlagSet.StringVar(&globalFlags.EtcdCertFile, "etcd-certfile", "", "etcd cert file authentication") globalFlagSet.StringVar(&globalFlags.EtcdCAFile, "etcd-cafile", "", "etcd CA file authentication") @@ -131,6 +133,13 @@ func main() { globalFlagSet.Parse(os.Args[1:]) var args = globalFlagSet.Args() + if len(globalFlags.Endpoints) == 0 && globalFlags.DiscoverySrv != "" { + var err error + if globalFlags.Endpoints, err = discoverEndpoints(globalFlags.DiscoverySrv); err != nil { + fmt.Fprintln(os.Stderr, "DNS SRV discovery failed:", err) + } + } + if len(globalFlags.Endpoints) == 0 { globalFlags.Endpoints = defaultEndpoints } From 3585ca659b1f5e6f4371cca1c167e7eec1e7a162 Mon Sep 17 00:00:00 2001 From: "Daniel M. Lambea" Date: Thu, 8 Jun 2017 19:51:51 +0100 Subject: [PATCH 3/5] Use FlagSet.Set() on successful DNS discovery to honour 'flagsFromEnv' visiting procedure. --- locksmithctl/locksmithctl.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/locksmithctl/locksmithctl.go b/locksmithctl/locksmithctl.go index d4eac0e..508e43b 100644 --- a/locksmithctl/locksmithctl.go +++ b/locksmithctl/locksmithctl.go @@ -134,12 +134,17 @@ func main() { var args = globalFlagSet.Args() if len(globalFlags.Endpoints) == 0 && globalFlags.DiscoverySrv != "" { - var err error - if globalFlags.Endpoints, err = discoverEndpoints(globalFlags.DiscoverySrv); err != nil { + endpoints, err := discoverEndpoints(globalFlags.DiscoverySrv) + if err == nil { + for _, ep := range endpoints { + globalFlagSet.Set("endpoint", ep) + } + } else { fmt.Fprintln(os.Stderr, "DNS SRV discovery failed:", err) } } + // still no endpoints defined - use defaults if len(globalFlags.Endpoints) == 0 { globalFlags.Endpoints = defaultEndpoints } @@ -162,7 +167,7 @@ func main() { } flagsFromEnv("LOCKSMITHCTL", globalFlagSet) - + fmt.Printf("Endpoints: %v", globalFlags.Endpoints) var cmd *Command // determine which Command should be run From fe3abcdd1111178f20b509f167f5c16c9951b10c Mon Sep 17 00:00:00 2001 From: "Daniel M. Lambea" Date: Thu, 8 Jun 2017 19:57:49 +0100 Subject: [PATCH 4/5] Added instructions about DNS discovery --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 03ece08..9719145 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,19 @@ passing a comma-delimited list, e.g.: LOCKSMITHCTL_ENDPOINT=, +### Discovering endpoints + +DNS SRV records can be used to discover the endpoints. You will need to setup [etcd DNS Discovery](https://coreos.com/etcd/docs/latest/v2/clustering.html#dns-discovery) on your domain first. The `-discovery-srv=` option triggers DNS SRV discovery, as long as no `-endpoint` option is specified. E.g.: + + -discovery-srv=mydomain.com + +This would trigger DNS discovery on the following SRV records: + +``` +_etcd-client-ssl._tcp.mydomain.com +_etcd-client._tcp.mydomain.com +``` + ### Listing the Holders ``` From 8074637bdc94376d529314d006e154ca51935657 Mon Sep 17 00:00:00 2001 From: "Daniel M. Lambea" Date: Thu, 8 Jun 2017 20:02:59 +0100 Subject: [PATCH 5/5] Removed unused fmt.Printf() --- locksmithctl/locksmithctl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locksmithctl/locksmithctl.go b/locksmithctl/locksmithctl.go index 508e43b..790a575 100644 --- a/locksmithctl/locksmithctl.go +++ b/locksmithctl/locksmithctl.go @@ -167,7 +167,7 @@ func main() { } flagsFromEnv("LOCKSMITHCTL", globalFlagSet) - fmt.Printf("Endpoints: %v", globalFlags.Endpoints) + var cmd *Command // determine which Command should be run