etcd: Connection options (socket file, ipv6)
- Allow unix domain socket to be used as client url - Using ::1 as clienturl should not create default local ipv4 listener - Add shell tests
This commit is contained in:
23
etcd/etcd.go
23
etcd/etcd.go
@@ -194,6 +194,7 @@ type EmbdEtcd struct { // EMBeddeD etcd
|
||||
advertiseClientURLs etcdtypes.URLs // client urls to advertise
|
||||
advertiseServerURLs etcdtypes.URLs // server urls to advertise
|
||||
noServer bool // disable all server peering if true
|
||||
noNetwork bool // use unix:// sockets instead of TCP for clients/servers
|
||||
|
||||
// local tracked state
|
||||
nominated etcdtypes.URLsMap // copy of who's nominated to locally track state
|
||||
@@ -220,7 +221,7 @@ type EmbdEtcd struct { // EMBeddeD etcd
|
||||
}
|
||||
|
||||
// NewEmbdEtcd creates the top level embedded etcd struct client and server obj.
|
||||
func NewEmbdEtcd(hostname string, seeds, clientURLs, serverURLs, advertiseClientURLs, advertiseServerURLs etcdtypes.URLs, noServer bool, idealClusterSize uint16, flags Flags, prefix string, converger converger.Converger) *EmbdEtcd {
|
||||
func NewEmbdEtcd(hostname string, seeds, clientURLs, serverURLs, advertiseClientURLs, advertiseServerURLs etcdtypes.URLs, noServer bool, noNetwork bool, idealClusterSize uint16, flags Flags, prefix string, converger converger.Converger) *EmbdEtcd {
|
||||
endpoints := make(etcdtypes.URLsMap)
|
||||
if hostname == seedSentinel { // safety
|
||||
return nil
|
||||
@@ -229,6 +230,15 @@ func NewEmbdEtcd(hostname string, seeds, clientURLs, serverURLs, advertiseClient
|
||||
log.Printf("Etcd: need at least one seed if running with --no-server!")
|
||||
return nil
|
||||
}
|
||||
if noNetwork {
|
||||
if len(clientURLs) != 0 || len(serverURLs) != 0 || len(seeds) != 0 {
|
||||
log.Printf("--no-network is mutual exclusive with --seeds, --client-urls and --server-urls")
|
||||
return nil
|
||||
}
|
||||
clientURLs, _ = etcdtypes.NewURLs([]string{"unix://clients.sock:0"})
|
||||
serverURLs, _ = etcdtypes.NewURLs([]string{"unix://servers.sock:0"})
|
||||
}
|
||||
|
||||
if len(seeds) > 0 {
|
||||
endpoints[seedSentinel] = seeds
|
||||
idealClusterSize = 0 // unset, get from running cluster
|
||||
@@ -253,6 +263,7 @@ func NewEmbdEtcd(hostname string, seeds, clientURLs, serverURLs, advertiseClient
|
||||
advertiseClientURLs: advertiseClientURLs,
|
||||
advertiseServerURLs: advertiseServerURLs,
|
||||
noServer: noServer,
|
||||
noNetwork: noNetwork,
|
||||
|
||||
idealClusterSize: idealClusterSize,
|
||||
converger: converger,
|
||||
@@ -304,7 +315,7 @@ func (obj *EmbdEtcd) GetConfig() etcd.Config {
|
||||
// XXX: filter out any urls which wouldn't resolve here ?
|
||||
for _, eps := range obj.endpoints { // flatten map
|
||||
for _, u := range eps {
|
||||
endpoints = append(endpoints, u.Host) // remove http:// prefix
|
||||
endpoints = append(endpoints, u.String()) // use full url including scheme
|
||||
}
|
||||
}
|
||||
sort.Strings(endpoints) // sort for determinism
|
||||
@@ -1692,8 +1703,12 @@ func (obj *EmbdEtcd) LocalhostClientURLs() etcdtypes.URLs {
|
||||
// look through obj.clientURLs and return the localhost ones
|
||||
urls := etcdtypes.URLs{}
|
||||
for _, x := range obj.clientURLs {
|
||||
// "localhost" or anything in 127.0.0.0/8 is valid!
|
||||
if s := x.Host; strings.HasPrefix(s, "localhost") || strings.HasPrefix(s, "127.") {
|
||||
// "localhost", ::1 or anything in 127.0.0.0/8 is valid!
|
||||
if s := x.Host; strings.HasPrefix(s, "localhost") || strings.HasPrefix(s, "127.") || strings.HasPrefix(s, "[::1]") {
|
||||
urls = append(urls, x)
|
||||
}
|
||||
// or local unix domain socket
|
||||
if x.Scheme == "unix" {
|
||||
urls = append(urls, x)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func TestNewEmbdEtcd(t *testing.T) {
|
||||
noServer := false
|
||||
var flags Flags
|
||||
|
||||
obj := NewEmbdEtcd("", nil, nil, nil, nil, nil, noServer, 0, flags, "", nil)
|
||||
obj := NewEmbdEtcd("", nil, nil, nil, nil, nil, noServer, false, 0, flags, "", nil)
|
||||
if obj == nil {
|
||||
t.Fatal("failed to create server object")
|
||||
}
|
||||
@@ -44,7 +44,7 @@ func TestNewEmbdEtcdConfigValidation(t *testing.T) {
|
||||
noServer := true
|
||||
var flags Flags
|
||||
|
||||
obj := NewEmbdEtcd("", seeds, nil, nil, nil, nil, noServer, 0, flags, "", nil)
|
||||
obj := NewEmbdEtcd("", seeds, nil, nil, nil, nil, noServer, false, 0, flags, "", nil)
|
||||
if obj != nil {
|
||||
t.Fatal("server initialization should fail on invalid configuration")
|
||||
}
|
||||
|
||||
@@ -171,7 +171,11 @@ func CLI(program, version string, flags Flags) error {
|
||||
Name: "no-server",
|
||||
Usage: "do not start embedded etcd server (do not promote from client to peer)",
|
||||
},
|
||||
|
||||
cli.BoolFlag{
|
||||
Name: "no-network",
|
||||
Usage: "run single node instance without clustering or opening tcp ports to the outside",
|
||||
EnvVar: "MGMT_NO_NETWORK",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "no-pgp",
|
||||
Usage: "don't create pgp keys",
|
||||
|
||||
@@ -89,6 +89,7 @@ type Main struct {
|
||||
AdvertiseServerURLs []string // list of URLs to advertise for server (peer) traffic
|
||||
IdealClusterSize int // ideal number of server peers in cluster; only read by initial server
|
||||
NoServer bool // do not let other servers peer with me
|
||||
NoNetwork bool // run single node instance without clustering or opening tcp ports to the outside
|
||||
|
||||
seeds etcdtypes.URLs // processed seeds value
|
||||
clientURLs etcdtypes.URLs // processed client urls value
|
||||
@@ -354,6 +355,7 @@ func (obj *Main) Run() error {
|
||||
obj.advertiseClientURLs,
|
||||
obj.advertiseServerURLs,
|
||||
obj.NoServer,
|
||||
obj.NoNetwork,
|
||||
obj.idealClusterSize,
|
||||
etcd.Flags{
|
||||
Debug: obj.Flags.Debug,
|
||||
|
||||
@@ -107,6 +107,7 @@ func run(c *cli.Context, name string, gapiObj gapi.GAPI) error {
|
||||
obj.AdvertiseServerURLs = cliContext.StringSlice("advertise-server-urls")
|
||||
obj.IdealClusterSize = cliContext.Int("ideal-cluster-size")
|
||||
obj.NoServer = cliContext.Bool("no-server")
|
||||
obj.NoNetwork = cliContext.Bool("no-network")
|
||||
|
||||
obj.NoPgp = cliContext.Bool("no-pgp")
|
||||
|
||||
|
||||
40
test/shell/clustersize.sh
Executable file
40
test/shell/clustersize.sh
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
if ! command -v etcdctl >/dev/null; then
|
||||
echo "Missing etcdctl, skipping"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
. "$(dirname "$0")/../util.sh"
|
||||
|
||||
mkdir /tmp/mgmt/{A..E}
|
||||
|
||||
# kill servers on error/exit
|
||||
trap 'pkill -9 mgmt' EXIT
|
||||
|
||||
"$MGMT" run --hostname h1 --tmp-prefix --no-pgp empty &
|
||||
"$MGMT" run --hostname h2 --tmp-prefix --no-pgp --seeds http://127.0.0.1:2379 --client-urls http://127.0.0.1:2381 --server-urls http://127.0.0.1:2382 empty &
|
||||
"$MGMT" run --hostname h3 --tmp-prefix --no-pgp --seeds http://127.0.0.1:2379 --client-urls http://127.0.0.1:2383 --server-urls http://127.0.0.1:2384 empty &
|
||||
|
||||
# wait for everything to converge
|
||||
sleep 10
|
||||
|
||||
ETCDCTL_API=3 etcdctl --endpoints 127.0.0.1:2379 put /_mgmt/idealClusterSize 3
|
||||
|
||||
"$MGMT" run --hostname h4 --tmp-prefix --no-pgp --seeds http://127.0.0.1:2379 --client-urls http://127.0.0.1:2385 --server-urls http://127.0.0.1:2386 empty &
|
||||
"$MGMT" run --hostname h5 --tmp-prefix --no-pgp --seeds http://127.0.0.1:2379 --client-urls http://127.0.0.1:2387 --server-urls http://127.0.0.1:2388 empty &
|
||||
|
||||
# wait for everything to converge
|
||||
sleep 10
|
||||
|
||||
test "$(ETCDCTL_API=3 etcdctl --endpoints 127.0.0.1:2379 member list | wc -l)" -eq 3
|
||||
|
||||
ETCDCTL_API=3 etcdctl --endpoints 127.0.0.1:2381 put /_mgmt/idealClusterSize 5
|
||||
|
||||
# wait for everything to converge
|
||||
sleep 5
|
||||
|
||||
test "$(ETCDCTL_API=3 etcdctl --endpoints 127.0.0.1:2381 member list | wc -l)" -eq 5
|
||||
22
test/shell/exchange.sh
Executable file
22
test/shell/exchange.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
. "$(dirname "$0")/../util.sh"
|
||||
|
||||
"$MGMT" run --hostname h1 --ideal-cluster-size 1 --tmp-prefix --no-pgp lang --lang exchange0.mcl &
|
||||
"$MGMT" run --hostname h2 --seeds http://127.0.0.1:2379 --client-urls http://127.0.0.1:2381 --server-urls http://127.0.0.1:2382 --tmp-prefix --no-pgp lang --lang exchange0.mcl &
|
||||
"$MGMT" run --hostname h3 --seeds http://127.0.0.1:2379 --client-urls http://127.0.0.1:2383 --server-urls http://127.0.0.1:2384 --tmp-prefix --no-pgp lang --lang exchange0.mcl &
|
||||
"$MGMT" run --hostname h4 --seeds http://127.0.0.1:2379 --client-urls http://127.0.0.1:2385 --server-urls http://127.0.0.1:2386 --tmp-prefix --no-pgp lang --lang exchange0.mcl &
|
||||
|
||||
# kill servers on error/exit
|
||||
trap 'pkill -9 mgmt' EXIT
|
||||
|
||||
# wait for everything to converge
|
||||
sleep 10
|
||||
|
||||
test "$(cat /tmp/mgmt/exchange-* | grep -c h1)" -eq 4
|
||||
test "$(cat /tmp/mgmt/exchange-* | grep -c h2)" -eq 4
|
||||
test "$(cat /tmp/mgmt/exchange-* | grep -c h3)" -eq 4
|
||||
test "$(cat /tmp/mgmt/exchange-* | grep -c h4)" -eq 4
|
||||
16
test/shell/exchange0.mcl
Normal file
16
test/shell/exchange0.mcl
Normal file
@@ -0,0 +1,16 @@
|
||||
# run this example with these commands
|
||||
# watch -n 0.1 'tail *' # run this in /tmp/mgmt/
|
||||
# time ./mgmt run --hostname h1 --ideal-cluster-size 1 --tmp-prefix --no-pgp lang --lang examples/lang/exchange0.mcl
|
||||
# time ./mgmt run --hostname h2 --seeds http://127.0.0.1:2379 --client-urls http://127.0.0.1:2381 --server-urls http://127.0.0.1:2382 --tmp-prefix --no-pgp lang --lang examples/lang/exchange0.mcl
|
||||
# time ./mgmt run --hostname h3 --seeds http://127.0.0.1:2379 --client-urls http://127.0.0.1:2383 --server-urls http://127.0.0.1:2384 --tmp-prefix --no-pgp lang --lang examples/lang/exchange0.mcl
|
||||
# time ./mgmt run --hostname h4 --seeds http://127.0.0.1:2379 --client-urls http://127.0.0.1:2385 --server-urls http://127.0.0.1:2386 --tmp-prefix --no-pgp lang --lang examples/lang/exchange0.mcl
|
||||
|
||||
import "sys"
|
||||
import "world"
|
||||
|
||||
$rand = random1(8)
|
||||
$exchanged = world.exchange("keyns", $rand)
|
||||
|
||||
file "/tmp/mgmt/exchange-${sys.hostname()}" {
|
||||
content => template("Found: {{ . }}\n", $exchanged),
|
||||
}
|
||||
29
test/shell/ipv6-localhost.sh
Executable file
29
test/shell/ipv6-localhost.sh
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
if ! ifconfig lo | grep 'inet6 ::1' >/dev/null; then
|
||||
echo "No IPv6, skipping test"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
. "$(dirname "$0")/../util.sh"
|
||||
|
||||
tmpdir="$($mktemp --tmpdir -d tmp.XXX)"
|
||||
|
||||
# run empty graph listing only to IPv6 addresses
|
||||
"$MGMT" run --client-urls "http://[::1]:2379" --server-urls "http://[::1]:2380" --tmp-prefix empty &
|
||||
pid=$!
|
||||
|
||||
# kill server on error/exit
|
||||
trap 'pkill -9 mgmt' EXIT
|
||||
|
||||
# give mgmt a little time to startup
|
||||
sleep 10
|
||||
|
||||
# mgmt configured for ipv6 only should not listen on any IPv4 ports
|
||||
lsof -Pn -p "$pid" -a -i | grep '127.0.0.1' && false
|
||||
|
||||
# instead it should listen on IPv6
|
||||
lsof -Pn -p "$pid" -a -i | grep '::1' || false
|
||||
26
test/shell/no-network.sh
Executable file
26
test/shell/no-network.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Tests the behaviour of the --no-network
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
. "$(dirname "$0")/../util.sh"
|
||||
|
||||
tmpdir="$($mktemp --tmpdir -d tmp.XXX)"
|
||||
|
||||
# run empty graph, with standalone enabled
|
||||
"$MGMT" run --no-network --prefix "$tmpdir" empty &
|
||||
pid=$!
|
||||
|
||||
# kill server on error/exit
|
||||
trap 'kill -SIGINT "$pid"' EXIT
|
||||
|
||||
# give mgmt a little time to startup
|
||||
sleep 10
|
||||
|
||||
# standalone mgmt should not listen on any tcp ports
|
||||
lsof -i | grep "$pid" | grep TCP && false
|
||||
|
||||
# instead unix domain sockets should have been created
|
||||
test -S "servers.sock:0"
|
||||
test -S "clients.sock:0"
|
||||
@@ -21,7 +21,7 @@ fi
|
||||
|
||||
# As per https://github.com/travis-ci/docs-travis-ci-com/blob/master/user/docker.md
|
||||
# Docker is not supported on Travis macOS test instances.
|
||||
if [[ "$TRAVIS_OS_NAME" == "osx" ]];then
|
||||
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
|
||||
XTAGS+=('nodocker')
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user