Skip to content
This repository was archived by the owner on Sep 18, 2020. It is now read-only.
Open
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,19 @@ passing a comma-delimited list, e.g.:

LOCKSMITHCTL_ENDPOINT=<url>,<url>

### 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=<domain>` 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

```
Expand Down
57 changes: 57 additions & 0 deletions locksmithctl/discovery.go
Original file line number Diff line number Diff line change
@@ -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
}
16 changes: 15 additions & 1 deletion locksmithctl/locksmithctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ var (

globalFlags = struct {
Debug bool
DiscoverySrv string
Endpoints endpoints
EtcdKeyFile string
EtcdCertFile string
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -132,6 +134,18 @@ func main() {
globalFlagSet.Parse(os.Args[1:])
var args = globalFlagSet.Args()

if len(globalFlags.Endpoints) == 0 && globalFlags.DiscoverySrv != "" {
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
}
Expand Down