command: allow wan ring to be modified separately from lan pools

This commit is contained in:
Ryan Uber 2014-09-21 11:52:28 -07:00
parent 431b366d4f
commit cfbf2b4f94
4 changed files with 103 additions and 56 deletions

View File

@ -1,17 +1,12 @@
package agent package agent
import ( import (
<<<<<<< HEAD
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
=======
"github.com/hashicorp/consul/testutil"
"github.com/mitchellh/cli"
"io/ioutil"
"path/filepath" "path/filepath"
>>>>>>> command: test generated keyring file content and conflicting args for agent "strings"
"testing" "testing"
"github.com/hashicorp/consul/testutil" "github.com/hashicorp/consul/testutil"
@ -45,7 +40,6 @@ func TestValidDatacenter(t *testing.T) {
} }
} }
<<<<<<< HEAD
func TestRetryJoin(t *testing.T) { func TestRetryJoin(t *testing.T) {
dir, agent := makeAgent(t, nextConfig()) dir, agent := makeAgent(t, nextConfig())
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
@ -169,7 +163,9 @@ func TestRetryJoinWanFail(t *testing.T) {
if code := cmd.Run(args); code == 0 { if code := cmd.Run(args); code == 0 {
t.Fatalf("bad: %d", code) t.Fatalf("bad: %d", code)
======= }
}
func TestArgConflict(t *testing.T) { func TestArgConflict(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &Command{Ui: ui} c := &Command{Ui: ui}
@ -196,6 +192,5 @@ func TestArgConflict(t *testing.T) {
} }
if !strings.Contains(ui.ErrorWriter.String(), "keyring files exist") { if !strings.Contains(ui.ErrorWriter.String(), "keyring files exist") {
t.Fatalf("bad: %#v", ui.ErrorWriter.String()) t.Fatalf("bad: %#v", ui.ErrorWriter.String())
>>>>>>> command: test generated keyring file content and conflicting args for agent
} }
} }

View File

@ -22,7 +22,7 @@ type KeyringCommand struct {
func (c *KeyringCommand) Run(args []string) int { func (c *KeyringCommand) Run(args []string) int {
var installKey, useKey, removeKey, init, dataDir string var installKey, useKey, removeKey, init, dataDir string
var listKeys bool var listKeys, wan bool
cmdFlags := flag.NewFlagSet("keys", flag.ContinueOnError) cmdFlags := flag.NewFlagSet("keys", flag.ContinueOnError)
cmdFlags.Usage = func() { c.Ui.Output(c.Help()) } cmdFlags.Usage = func() { c.Ui.Output(c.Help()) }
@ -33,6 +33,7 @@ func (c *KeyringCommand) Run(args []string) int {
cmdFlags.BoolVar(&listKeys, "list", false, "list keys") cmdFlags.BoolVar(&listKeys, "list", false, "list keys")
cmdFlags.StringVar(&init, "init", "", "initialize keyring") cmdFlags.StringVar(&init, "init", "", "initialize keyring")
cmdFlags.StringVar(&dataDir, "data-dir", "", "data directory") cmdFlags.StringVar(&dataDir, "data-dir", "", "data directory")
cmdFlags.BoolVar(&wan, "wan", false, "operate on wan keyring")
rpcAddr := RPCAddrFlag(cmdFlags) rpcAddr := RPCAddrFlag(cmdFlags)
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
@ -105,51 +106,57 @@ func (c *KeyringCommand) Run(args []string) int {
} }
if listKeys { if listKeys {
c.Ui.Info("Asking all WAN members for installed keys...") if wan {
if rval := c.listKeysOperation(client.ListKeysWAN); rval != 0 { c.Ui.Info("Asking all WAN members for installed keys...")
return rval return c.listKeysOperation(client.ListKeysWAN)
} }
c.Ui.Info("Asking all LAN members for installed keys...") c.Ui.Info("Asking all LAN members for installed keys...")
if rval := c.listKeysOperation(client.ListKeysLAN); rval != 0 { return c.listKeysOperation(client.ListKeysLAN)
return rval
}
return 0
} }
if installKey != "" { if installKey != "" {
c.Ui.Info("Installing new WAN gossip encryption key...") if wan {
if rval := c.keyOperation(installKey, client.InstallKeyWAN); rval != 0 { c.Ui.Info("Installing new WAN gossip encryption key...")
return rval if rval := c.keyOperation(installKey, client.InstallKeyWAN); rval != 0 {
} return rval
c.Ui.Info("Installing new LAN gossip encryption key...") }
if rval := c.keyOperation(installKey, client.InstallKeyLAN); rval != 0 { } else {
return rval c.Ui.Info("Installing new LAN gossip encryption key...")
if rval := c.keyOperation(installKey, client.InstallKeyLAN); rval != 0 {
return rval
}
} }
c.Ui.Info("Successfully installed key!") c.Ui.Info("Successfully installed key!")
return 0 return 0
} }
if useKey != "" { if useKey != "" {
c.Ui.Info("Changing primary WAN gossip encryption key...") if wan {
if rval := c.keyOperation(useKey, client.UseKeyWAN); rval != 0 { c.Ui.Info("Changing primary WAN gossip encryption key...")
return rval if rval := c.keyOperation(useKey, client.UseKeyWAN); rval != 0 {
} return rval
c.Ui.Info("Changing primary LAN gossip encryption key...") }
if rval := c.keyOperation(useKey, client.UseKeyLAN); rval != 0 { } else {
return rval c.Ui.Info("Changing primary LAN gossip encryption key...")
if rval := c.keyOperation(useKey, client.UseKeyLAN); rval != 0 {
return rval
}
} }
c.Ui.Info("Successfully changed primary key!") c.Ui.Info("Successfully changed primary key!")
return 0 return 0
} }
if removeKey != "" { if removeKey != "" {
c.Ui.Info("Removing WAN gossip encryption key...") if wan {
if rval := c.keyOperation(removeKey, client.RemoveKeyWAN); rval != 0 { c.Ui.Info("Removing WAN gossip encryption key...")
return rval if rval := c.keyOperation(removeKey, client.RemoveKeyWAN); rval != 0 {
} return rval
c.Ui.Info("Removing LAN gossip encryption key...") }
if rval := c.keyOperation(removeKey, client.RemoveKeyLAN); rval != 0 { } else {
return rval c.Ui.Info("Removing LAN gossip encryption key...")
if rval := c.keyOperation(removeKey, client.RemoveKeyLAN); rval != 0 {
return rval
}
} }
c.Ui.Info("Successfully removed key!") c.Ui.Info("Successfully removed key!")
return 0 return 0
@ -258,8 +265,9 @@ Usage: consul keyring [options]
functionality provides the ability to perform key rotation cluster-wide, functionality provides the ability to perform key rotation cluster-wide,
without disrupting the cluster. without disrupting the cluster.
With the exception of the -init argument, all other operations performed by With the exception of the -init argument, all operations performed by this
this command can only be run against server nodes. command can only be run against server nodes. All operations default to the
LAN gossip pool.
Options: Options:
@ -275,6 +283,8 @@ Options:
-init=<key> Create the initial keyring files for Consul to use -init=<key> Create the initial keyring files for Consul to use
containing the provided key. The -data-dir argument containing the provided key. The -data-dir argument
is required with this option. is required with this option.
-wan Operate on the WAN keyring instead of the LAN
keyring (default).
-rpc-addr=127.0.0.1:8400 RPC address of the Consul agent. -rpc-addr=127.0.0.1:8400 RPC address of the Consul agent.
` `
return strings.TrimSpace(helpText) return strings.TrimSpace(helpText)

View File

@ -25,7 +25,7 @@ func TestKeyringCommandRun(t *testing.T) {
defer a1.Shutdown() defer a1.Shutdown()
// The keyring was initialized with only the provided key // The keyring was initialized with only the provided key
out := listKeys(t, a1.addr) out := listKeys(t, a1.addr, false)
if !strings.Contains(out, key1) { if !strings.Contains(out, key1) {
t.Fatalf("bad: %#v", out) t.Fatalf("bad: %#v", out)
} }
@ -34,30 +34,56 @@ func TestKeyringCommandRun(t *testing.T) {
} }
// Install the second key onto the keyring // Install the second key onto the keyring
installKey(t, a1.addr, key2) installKey(t, a1.addr, key2, false)
// Both keys should be present // Both keys should be present
out = listKeys(t, a1.addr) out = listKeys(t, a1.addr, false)
for _, key := range []string{key1, key2} { for _, key := range []string{key1, key2} {
if !strings.Contains(out, key) { if !strings.Contains(out, key) {
t.Fatalf("bad: %#v", out) t.Fatalf("bad: %#v", out)
} }
} }
// WAN keyring is untouched
out = listKeys(t, a1.addr, true)
if strings.Contains(out, key2) {
t.Fatalf("bad: %#v", out)
}
// Change out the primary key // Change out the primary key
useKey(t, a1.addr, key2) useKey(t, a1.addr, key2, false)
// Remove the original key // Remove the original key
removeKey(t, a1.addr, key1) removeKey(t, a1.addr, key1, false)
// Make sure only the new key is present // Make sure only the new key is present
out = listKeys(t, a1.addr) out = listKeys(t, a1.addr, false)
if strings.Contains(out, key1) { if strings.Contains(out, key1) {
t.Fatalf("bad: %#v", out) t.Fatalf("bad: %#v", out)
} }
if !strings.Contains(out, key2) { if !strings.Contains(out, key2) {
t.Fatalf("bad: %#v", out) t.Fatalf("bad: %#v", out)
} }
// WAN keyring is still untouched
out = listKeys(t, a1.addr, true)
if !strings.Contains(out, key1) {
t.Fatalf("bad: %#v", out)
}
// Rotate out the WAN key
installKey(t, a1.addr, key2, true)
useKey(t, a1.addr, key2, true)
removeKey(t, a1.addr, key1, true)
// WAN keyring now has only the proper key
out = listKeys(t, a1.addr, true)
if !strings.Contains(out, key2) {
t.Fatalf("bad: %#v", out)
}
if strings.Contains(out, key1) {
t.Fatalf("bad: %#v", out)
}
} }
func TestKeyringCommandRun_help(t *testing.T) { func TestKeyringCommandRun_help(t *testing.T) {
@ -87,7 +113,7 @@ func TestKeyringCommandRun_failedConnection(t *testing.T) {
} }
} }
func TestKeyCommandRun_initKeyringFail(t *testing.T) { func TestKeyringCommandRun_initKeyringFail(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &KeyringCommand{Ui: ui} c := &KeyringCommand{Ui: ui}
@ -106,7 +132,7 @@ func TestKeyCommandRun_initKeyringFail(t *testing.T) {
} }
} }
func TestKeyCommandRun_initKeyring(t *testing.T) { func TestKeyringCommandRun_initKeyring(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &KeyringCommand{Ui: ui} c := &KeyringCommand{Ui: ui}
@ -153,11 +179,14 @@ func TestKeyCommandRun_initKeyring(t *testing.T) {
} }
} }
func listKeys(t *testing.T, addr string) string { func listKeys(t *testing.T, addr string, wan bool) string {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &KeyringCommand{Ui: ui} c := &KeyringCommand{Ui: ui}
args := []string{"-list", "-rpc-addr=" + addr} args := []string{"-list", "-rpc-addr=" + addr}
if wan {
args = append(args, "-wan")
}
code := c.Run(args) code := c.Run(args)
if code != 0 { if code != 0 {
@ -167,33 +196,45 @@ func listKeys(t *testing.T, addr string) string {
return ui.OutputWriter.String() return ui.OutputWriter.String()
} }
func installKey(t *testing.T, addr string, key string) { func installKey(t *testing.T, addr string, key string, wan bool) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &KeyringCommand{Ui: ui} c := &KeyringCommand{Ui: ui}
args := []string{"-install=" + key, "-rpc-addr=" + addr} args := []string{"-install=" + key, "-rpc-addr=" + addr}
if wan {
args = append(args, "-wan")
}
code := c.Run(args) code := c.Run(args)
if code != 0 { if code != 0 {
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String()) t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
} }
} }
func useKey(t *testing.T, addr string, key string) { func useKey(t *testing.T, addr string, key string, wan bool) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &KeyringCommand{Ui: ui} c := &KeyringCommand{Ui: ui}
args := []string{"-use=" + key, "-rpc-addr=" + addr} args := []string{"-use=" + key, "-rpc-addr=" + addr}
if wan {
args = append(args, "-wan")
}
code := c.Run(args) code := c.Run(args)
if code != 0 { if code != 0 {
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String()) t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
} }
} }
func removeKey(t *testing.T, addr string, key string) { func removeKey(t *testing.T, addr string, key string, wan bool) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &KeyringCommand{Ui: ui} c := &KeyringCommand{Ui: ui}
args := []string{"-remove=" + key, "-rpc-addr=" + addr} args := []string{"-remove=" + key, "-rpc-addr=" + addr}
if wan {
args = append(args, "-wan")
}
code := c.Run(args) code := c.Run(args)
if code != 0 { if code != 0 {
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String()) t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())

View File

@ -14,10 +14,9 @@ distributing new encryption keys to the cluster, retiring old encryption keys,
and changing the keys used by the cluster to encrypt messages. and changing the keys used by the cluster to encrypt messages.
Because Consul utilizes multiple gossip pools, this command will only operate Because Consul utilizes multiple gossip pools, this command will only operate
against a server node for most operations. All members in a Consul cluster, against a server node for most operations. By default, all operations carried
regardless of operational mode (client or server) or datacenter, will be out by this command are run against the LAN gossip pool in the datacenter of the
modified/queried each time this command is run. This helps maintain operational agent.
simplicity by managing the multiple pools as a single unit.
Consul allows multiple encryption keys to be in use simultaneously. This is Consul allows multiple encryption keys to be in use simultaneously. This is
intended to provide a transition state while the cluster converges. It is the intended to provide a transition state while the cluster converges. It is the
@ -60,4 +59,6 @@ The list of available flags are:
* `-list` - List all keys currently in use within the cluster. * `-list` - List all keys currently in use within the cluster.
* `-wan` - Operate on the WAN keyring instead of the LAN keyring (default)
* `-rpc-addr` - RPC address of the Consul agent. * `-rpc-addr` - RPC address of the Consul agent.