Add test for listener reloading, and update website docs.
This commit is contained in:
parent
b3218d26d6
commit
0e3764832a
|
@ -2,8 +2,6 @@ package cli
|
|||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
auditFile "github.com/hashicorp/vault/builtin/audit/file"
|
||||
auditSyslog "github.com/hashicorp/vault/builtin/audit/syslog"
|
||||
|
@ -79,8 +77,8 @@ func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory {
|
|||
"mysql": mysql.Factory,
|
||||
"ssh": ssh.Factory,
|
||||
},
|
||||
ShutdownCh: makeShutdownCh(),
|
||||
SighupCh: makeSighupCh(),
|
||||
ShutdownCh: command.MakeShutdownCh(),
|
||||
SighupCh: command.MakeSighupCh(),
|
||||
ReloadFuncs: map[string][]server.ReloadFunc{},
|
||||
}, nil
|
||||
},
|
||||
|
@ -311,37 +309,3 @@ func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
// makeShutdownCh returns a channel that can be used for shutdown
|
||||
// notifications for commands. This channel will send a message for every
|
||||
// interrupt or SIGTERM received.
|
||||
func makeShutdownCh() <-chan struct{} {
|
||||
resultCh := make(chan struct{})
|
||||
|
||||
signalCh := make(chan os.Signal, 4)
|
||||
signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM)
|
||||
go func() {
|
||||
for {
|
||||
<-signalCh
|
||||
resultCh <- struct{}{}
|
||||
}
|
||||
}()
|
||||
return resultCh
|
||||
}
|
||||
|
||||
// makeSighupCh returns a channel that can be used for SIGHUP
|
||||
// reloading. This channel will send a message for every
|
||||
// SIGHUP received.
|
||||
func makeSighupCh() <-chan struct{} {
|
||||
resultCh := make(chan struct{})
|
||||
|
||||
signalCh := make(chan os.Signal, 4)
|
||||
signal.Notify(signalCh, os.Interrupt, syscall.SIGHUP)
|
||||
go func() {
|
||||
for {
|
||||
<-signalCh
|
||||
resultCh <- struct{}{}
|
||||
}
|
||||
}()
|
||||
return resultCh
|
||||
}
|
||||
|
|
|
@ -8,10 +8,12 @@ import (
|
|||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
|
@ -35,8 +37,8 @@ type ServerCommand struct {
|
|||
CredentialBackends map[string]logical.Factory
|
||||
LogicalBackends map[string]logical.Factory
|
||||
|
||||
ShutdownCh <-chan struct{}
|
||||
SighupCh <-chan struct{}
|
||||
ShutdownCh chan struct{}
|
||||
SighupCh chan struct{}
|
||||
|
||||
Meta
|
||||
|
||||
|
@ -637,3 +639,37 @@ General Options:
|
|||
`
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
// MakeShutdownCh returns a channel that can be used for shutdown
|
||||
// notifications for commands. This channel will send a message for every
|
||||
// interrupt or SIGTERM received.
|
||||
func MakeShutdownCh() chan struct{} {
|
||||
resultCh := make(chan struct{})
|
||||
|
||||
signalCh := make(chan os.Signal, 4)
|
||||
signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM)
|
||||
go func() {
|
||||
for {
|
||||
<-signalCh
|
||||
resultCh <- struct{}{}
|
||||
}
|
||||
}()
|
||||
return resultCh
|
||||
}
|
||||
|
||||
// MakeSighupCh returns a channel that can be used for SIGHUP
|
||||
// reloading. This channel will send a message for every
|
||||
// SIGHUP received.
|
||||
func MakeSighupCh() chan struct{} {
|
||||
resultCh := make(chan struct{})
|
||||
|
||||
signalCh := make(chan os.Signal, 4)
|
||||
signal.Notify(signalCh, os.Interrupt, syscall.SIGHUP)
|
||||
go func() {
|
||||
for {
|
||||
<-signalCh
|
||||
resultCh <- struct{}{}
|
||||
}
|
||||
}()
|
||||
return resultCh
|
||||
}
|
||||
|
|
|
@ -41,11 +41,7 @@ func TestTCPListener_tls(t *testing.T) {
|
|||
defer os.RemoveAll(td)
|
||||
|
||||
// Setup initial certs
|
||||
inBytes, _ := ioutil.ReadFile(wd + "reload_foo.pem")
|
||||
ioutil.WriteFile(td+"reload_curr.pem", inBytes, 0777)
|
||||
inBytes, _ = ioutil.ReadFile(wd + "reload_foo.key")
|
||||
ioutil.WriteFile(td+"reload_curr.key", inBytes, 0777)
|
||||
inBytes, _ = ioutil.ReadFile(wd + "reload_ca.pem")
|
||||
inBytes, _ := ioutil.ReadFile(wd + "reload_ca.pem")
|
||||
certPool := x509.NewCertPool()
|
||||
ok := certPool.AppendCertsFromPEM(inBytes)
|
||||
if !ok {
|
||||
|
@ -54,8 +50,8 @@ func TestTCPListener_tls(t *testing.T) {
|
|||
|
||||
ln, _, _, err := tcpListenerFactory(map[string]string{
|
||||
"address": "127.0.0.1:0",
|
||||
"tls_cert_file": td + "reload_curr.pem",
|
||||
"tls_key_file": td + "reload_curr.key",
|
||||
"tls_cert_file": wd + "reload_foo.pem",
|
||||
"tls_key_file": wd + "reload_foo.key",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
|
@ -75,22 +71,4 @@ func TestTCPListener_tls(t *testing.T) {
|
|||
}
|
||||
|
||||
testListenerImpl(t, ln, connFn, "foo.example.com")
|
||||
/*
|
||||
inBytes, _ = ioutil.ReadFile(wd + "reload_bar.pem")
|
||||
ioutil.WriteFile(td+"reload_curr.pem", inBytes, 0777)
|
||||
inBytes, _ = ioutil.ReadFile(wd + "reload_bar.key")
|
||||
ioutil.WriteFile(td+"reload_curr.key", inBytes, 0777)
|
||||
|
||||
req := logical.TestRequest(t, logical.UpdateOperation, "sys/reload")
|
||||
req.ClientToken = root
|
||||
resp, err := core.HandleRequest(req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if resp != nil {
|
||||
t.Fatal("expected nil response")
|
||||
}
|
||||
|
||||
testListenerImpl(t, ln, connFn, "bar.example.com")
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -3,11 +3,18 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/vault/command/server"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
|
@ -38,6 +45,20 @@ ha_backend "consul" {
|
|||
ha_backend "file" {
|
||||
path = "/dev/null"
|
||||
}
|
||||
`
|
||||
|
||||
reloadhcl = `
|
||||
backend "file" {
|
||||
path = "/dev/null"
|
||||
}
|
||||
|
||||
disable_mlock = true
|
||||
|
||||
listener "tcp" {
|
||||
address = "127.0.0.1:8203"
|
||||
tls_cert_file = "TMPDIR/reload_FILE.pem"
|
||||
tls_key_file = "TMPDIR/reload_FILE.key"
|
||||
}
|
||||
`
|
||||
)
|
||||
|
||||
|
@ -121,3 +142,111 @@ func TestServer_BadSeparateHA(t *testing.T) {
|
|||
t.Fatalf("bad: should have gotten an error on a bad HA config")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_ReloadListener(t *testing.T) {
|
||||
wd, _ := os.Getwd()
|
||||
wd += "/server/test-fixtures/reload/"
|
||||
|
||||
td, err := ioutil.TempDir("", fmt.Sprintf("vault-test-%d", rand.New(rand.NewSource(time.Now().Unix())).Int63))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(td)
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
|
||||
// Setup initial certs
|
||||
inBytes, _ := ioutil.ReadFile(wd + "reload_foo.pem")
|
||||
ioutil.WriteFile(td+"/reload_foo.pem", inBytes, 0777)
|
||||
inBytes, _ = ioutil.ReadFile(wd + "reload_foo.key")
|
||||
ioutil.WriteFile(td+"/reload_foo.key", inBytes, 0777)
|
||||
inBytes, _ = ioutil.ReadFile(wd + "reload_bar.pem")
|
||||
ioutil.WriteFile(td+"/reload_bar.pem", inBytes, 0777)
|
||||
inBytes, _ = ioutil.ReadFile(wd + "reload_bar.key")
|
||||
ioutil.WriteFile(td+"/reload_bar.key", inBytes, 0777)
|
||||
|
||||
relhcl := strings.Replace(strings.Replace(reloadhcl, "TMPDIR", td, -1), "FILE", "foo", -1)
|
||||
ioutil.WriteFile(td+"/reload.hcl", []byte(relhcl), 0777)
|
||||
|
||||
inBytes, _ = ioutil.ReadFile(wd + "reload_ca.pem")
|
||||
certPool := x509.NewCertPool()
|
||||
ok := certPool.AppendCertsFromPEM(inBytes)
|
||||
if !ok {
|
||||
t.Fatal("not ok when appending CA cert")
|
||||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &ServerCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
},
|
||||
ShutdownCh: MakeShutdownCh(),
|
||||
SighupCh: MakeSighupCh(),
|
||||
ReloadFuncs: map[string][]server.ReloadFunc{},
|
||||
}
|
||||
|
||||
finished := false
|
||||
finishedMutex := sync.Mutex{}
|
||||
|
||||
wg.Add(1)
|
||||
args := []string{"-config", td + "/reload.hcl"}
|
||||
go func() {
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Error("got a non-zero exit status")
|
||||
}
|
||||
finishedMutex.Lock()
|
||||
finished = true
|
||||
finishedMutex.Unlock()
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
checkFinished := func() {
|
||||
finishedMutex.Lock()
|
||||
if finished {
|
||||
t.Fatal(fmt.Sprintf("finished early; relhcl was\n%s\nstdout was\n%s\nstderr was\n%s\n", relhcl, ui.OutputWriter.String(), ui.ErrorWriter.String()))
|
||||
}
|
||||
finishedMutex.Unlock()
|
||||
}
|
||||
|
||||
testCertificateName := func(cn string) error {
|
||||
conn, err := tls.Dial("tcp", "127.0.0.1:8203", &tls.Config{
|
||||
RootCAs: certPool,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
if err = conn.Handshake(); err != nil {
|
||||
return err
|
||||
}
|
||||
servName := conn.ConnectionState().PeerCertificates[0].Subject.CommonName
|
||||
if servName != cn {
|
||||
return fmt.Errorf("expected %s, got %s", cn, servName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
checkFinished()
|
||||
time.Sleep(2 * time.Second)
|
||||
checkFinished()
|
||||
|
||||
if err := testCertificateName("foo.example.com"); err != nil {
|
||||
t.Fatalf("certificate name didn't check out: %s", err)
|
||||
}
|
||||
|
||||
relhcl = strings.Replace(strings.Replace(reloadhcl, "TMPDIR", td, -1), "FILE", "bar", -1)
|
||||
ioutil.WriteFile(td+"/reload.hcl", []byte(relhcl), 0777)
|
||||
|
||||
c.SighupCh <- struct{}{}
|
||||
checkFinished()
|
||||
time.Sleep(2 * time.Second)
|
||||
checkFinished()
|
||||
|
||||
if err := testCertificateName("bar.example.com"); err != nil {
|
||||
t.Fatalf("certificate name didn't check out: %s", err)
|
||||
}
|
||||
|
||||
c.ShutdownCh <- struct{}{}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
|
|
@ -32,6 +32,9 @@ telemetry {
|
|||
After the configuration is written, use the `-config` flag with `vault server`
|
||||
to specify where the configuration is.
|
||||
|
||||
Starting with 0.5.2, limited configuration options can be changed on-the-fly by
|
||||
sending a SIGHUP to the server process. These are denoted below.
|
||||
|
||||
## Reference
|
||||
|
||||
* `backend` (required) - Configures the storage backend where Vault data
|
||||
|
@ -93,10 +96,10 @@ The supported options are:
|
|||
by default that TLS will be used.
|
||||
|
||||
* `tls_cert_file` (required unless disabled) - The path to the certificate
|
||||
for TLS.
|
||||
for TLS. This is reloaded via SIGHUP.
|
||||
|
||||
* `tls_key_file` (required unless disabled) - The path to the private key
|
||||
for the certificate.
|
||||
for the certificate. This is reloaded via SIGHUP.
|
||||
|
||||
* `tls_min_version` (optional) - **(Vault > 0.2)** If provided, specifies
|
||||
the minimum supported version of TLS. Accepted values are "tls10", "tls11"
|
||||
|
|
Loading…
Reference in New Issue