Accept both slices and strings in vault_json (#9114)
Fixes #9105 by allowing the `vault_json` to contain either slices or strings. And fixes #8932 by changing to way we cleanup the user key.
This commit is contained in:
parent
de3a7b5d20
commit
c307dc9557
|
@ -11,6 +11,7 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -110,7 +111,7 @@ type Provisioner struct {
|
||||||
Version string `mapstructure:"version"`
|
Version string `mapstructure:"version"`
|
||||||
|
|
||||||
attributes map[string]interface{}
|
attributes map[string]interface{}
|
||||||
vaults map[string]string
|
vaults map[string][]string
|
||||||
|
|
||||||
cleanupUserKeyCmd string
|
cleanupUserKeyCmd string
|
||||||
createConfigFiles func(terraform.UIOutput, communicator.Communicator) error
|
createConfigFiles func(terraform.UIOutput, communicator.Communicator) error
|
||||||
|
@ -192,12 +193,14 @@ func (r *ResourceProvisioner) Apply(
|
||||||
defer comm.Disconnect()
|
defer comm.Disconnect()
|
||||||
|
|
||||||
// Make sure we always delete the user key from the new node!
|
// Make sure we always delete the user key from the new node!
|
||||||
defer func() {
|
var once sync.Once
|
||||||
|
cleanupUserKey := func() {
|
||||||
o.Output("Cleanup user key...")
|
o.Output("Cleanup user key...")
|
||||||
if err := p.runCommand(o, comm, p.cleanupUserKeyCmd); err != nil {
|
if err := p.runCommand(o, comm, p.cleanupUserKeyCmd); err != nil {
|
||||||
o.Output("WARNING: Failed to cleanup user key on new node: " + err.Error())
|
o.Output("WARNING: Failed to cleanup user key on new node: " + err.Error())
|
||||||
}
|
}
|
||||||
}()
|
}
|
||||||
|
defer once.Do(cleanupUserKey)
|
||||||
|
|
||||||
if !p.SkipInstall {
|
if !p.SkipInstall {
|
||||||
if err := p.installChefClient(o, comm); err != nil {
|
if err := p.installChefClient(o, comm); err != nil {
|
||||||
|
@ -229,6 +232,10 @@ func (r *ResourceProvisioner) Apply(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cleanup the user key before we run Chef-Client to prevent issues
|
||||||
|
// with rights caused by changing settings during the run.
|
||||||
|
once.Do(cleanupUserKey)
|
||||||
|
|
||||||
o.Output("Starting initial Chef-Client run...")
|
o.Output("Starting initial Chef-Client run...")
|
||||||
if err := p.runChefClient(o, comm); err != nil {
|
if err := p.runChefClient(o, comm); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -352,11 +359,28 @@ func (r *ResourceProvisioner) decodeConfig(c *terraform.ResourceConfig) (*Provis
|
||||||
}
|
}
|
||||||
|
|
||||||
if vaults, ok := c.Config["vault_json"].(string); ok {
|
if vaults, ok := c.Config["vault_json"].(string); ok {
|
||||||
var m map[string]string
|
var m map[string]interface{}
|
||||||
if err := json.Unmarshal([]byte(vaults), &m); err != nil {
|
if err := json.Unmarshal([]byte(vaults), &m); err != nil {
|
||||||
return nil, fmt.Errorf("Error parsing vault_json: %v", err)
|
return nil, fmt.Errorf("Error parsing vault_json: %v", err)
|
||||||
}
|
}
|
||||||
p.vaults = m
|
|
||||||
|
v := make(map[string][]string)
|
||||||
|
for vault, items := range m {
|
||||||
|
switch items := items.(type) {
|
||||||
|
case []interface{}:
|
||||||
|
for _, item := range items {
|
||||||
|
if item, ok := item.(string); ok {
|
||||||
|
v[vault] = append(v[vault], item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case interface{}:
|
||||||
|
if item, ok := items.(string); ok {
|
||||||
|
v[vault] = append(v[vault], item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.vaults = v
|
||||||
}
|
}
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
|
@ -544,16 +568,18 @@ func (p *Provisioner) configureVaultsFunc(
|
||||||
path.Join(confDir, p.UserName+".pem"),
|
path.Join(confDir, p.UserName+".pem"),
|
||||||
)
|
)
|
||||||
|
|
||||||
for vault, item := range p.vaults {
|
for vault, items := range p.vaults {
|
||||||
updateCmd := fmt.Sprintf("%s vault update %s %s -A %s -M client %s",
|
for _, item := range items {
|
||||||
knifeCmd,
|
updateCmd := fmt.Sprintf("%s vault update %s %s -A %s -M client %s",
|
||||||
vault,
|
knifeCmd,
|
||||||
item,
|
vault,
|
||||||
p.NodeName,
|
item,
|
||||||
options,
|
p.NodeName,
|
||||||
)
|
options,
|
||||||
if err := p.runCommand(o, comm, updateCmd); err != nil {
|
)
|
||||||
return err
|
if err := p.runCommand(o, comm, updateCmd); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -221,3 +221,128 @@ func TestResourceProvider_fetchChefCertificates(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestResourceProvider_configureVaults(t *testing.T) {
|
||||||
|
cases := map[string]struct {
|
||||||
|
Config *terraform.ResourceConfig
|
||||||
|
GemCmd string
|
||||||
|
KnifeCmd string
|
||||||
|
ConfDir string
|
||||||
|
Commands map[string]bool
|
||||||
|
}{
|
||||||
|
"Linux Vault string": {
|
||||||
|
Config: testConfig(t, map[string]interface{}{
|
||||||
|
"node_name": "nodename1",
|
||||||
|
"prevent_sudo": true,
|
||||||
|
"run_list": []interface{}{"cookbook::recipe"},
|
||||||
|
"server_url": "https://chef.local",
|
||||||
|
"user_name": "bob",
|
||||||
|
"user_key": "USER-KEY",
|
||||||
|
"vault_json": `{"vault1": "item1"}`,
|
||||||
|
}),
|
||||||
|
|
||||||
|
GemCmd: linuxGemCmd,
|
||||||
|
KnifeCmd: linuxKnifeCmd,
|
||||||
|
ConfDir: linuxConfDir,
|
||||||
|
|
||||||
|
Commands: map[string]bool{
|
||||||
|
fmt.Sprintf("%s install chef-vault", linuxGemCmd): true,
|
||||||
|
fmt.Sprintf("%s vault update vault1 item1 -A nodename1 -M client -c %s/client.rb "+
|
||||||
|
"-u bob --key %s/bob.pem", linuxKnifeCmd, linuxConfDir, linuxConfDir): true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"Linux Vault []string": {
|
||||||
|
Config: testConfig(t, map[string]interface{}{
|
||||||
|
"fetch_chef_certificates": true,
|
||||||
|
"node_name": "nodename1",
|
||||||
|
"prevent_sudo": true,
|
||||||
|
"run_list": []interface{}{"cookbook::recipe"},
|
||||||
|
"server_url": "https://chef.local",
|
||||||
|
"user_name": "bob",
|
||||||
|
"user_key": "USER-KEY",
|
||||||
|
"vault_json": `{"vault1": ["item1", "item2"]}`,
|
||||||
|
}),
|
||||||
|
|
||||||
|
GemCmd: linuxGemCmd,
|
||||||
|
KnifeCmd: linuxKnifeCmd,
|
||||||
|
ConfDir: linuxConfDir,
|
||||||
|
|
||||||
|
Commands: map[string]bool{
|
||||||
|
fmt.Sprintf("%s install chef-vault", linuxGemCmd): true,
|
||||||
|
fmt.Sprintf("%s vault update vault1 item1 -A nodename1 -M client -c %s/client.rb "+
|
||||||
|
"-u bob --key %s/bob.pem", linuxKnifeCmd, linuxConfDir, linuxConfDir): true,
|
||||||
|
fmt.Sprintf("%s vault update vault1 item2 -A nodename1 -M client -c %s/client.rb "+
|
||||||
|
"-u bob --key %s/bob.pem", linuxKnifeCmd, linuxConfDir, linuxConfDir): true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"Windows Vault string": {
|
||||||
|
Config: testConfig(t, map[string]interface{}{
|
||||||
|
"node_name": "nodename1",
|
||||||
|
"prevent_sudo": true,
|
||||||
|
"run_list": []interface{}{"cookbook::recipe"},
|
||||||
|
"server_url": "https://chef.local",
|
||||||
|
"user_name": "bob",
|
||||||
|
"user_key": "USER-KEY",
|
||||||
|
"vault_json": `{"vault1": "item1"}`,
|
||||||
|
}),
|
||||||
|
|
||||||
|
GemCmd: windowsGemCmd,
|
||||||
|
KnifeCmd: windowsKnifeCmd,
|
||||||
|
ConfDir: windowsConfDir,
|
||||||
|
|
||||||
|
Commands: map[string]bool{
|
||||||
|
fmt.Sprintf("%s install chef-vault", windowsGemCmd): true,
|
||||||
|
fmt.Sprintf("%s vault update vault1 item1 -A nodename1 -M client -c %s/client.rb "+
|
||||||
|
"-u bob --key %s/bob.pem", windowsKnifeCmd, windowsConfDir, windowsConfDir): true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"Windows Vault []string": {
|
||||||
|
Config: testConfig(t, map[string]interface{}{
|
||||||
|
"fetch_chef_certificates": true,
|
||||||
|
"node_name": "nodename1",
|
||||||
|
"prevent_sudo": true,
|
||||||
|
"run_list": []interface{}{"cookbook::recipe"},
|
||||||
|
"server_url": "https://chef.local",
|
||||||
|
"user_name": "bob",
|
||||||
|
"user_key": "USER-KEY",
|
||||||
|
"vault_json": `{"vault1": ["item1", "item2"]}`,
|
||||||
|
}),
|
||||||
|
|
||||||
|
GemCmd: windowsGemCmd,
|
||||||
|
KnifeCmd: windowsKnifeCmd,
|
||||||
|
ConfDir: windowsConfDir,
|
||||||
|
|
||||||
|
Commands: map[string]bool{
|
||||||
|
fmt.Sprintf("%s install chef-vault", windowsGemCmd): true,
|
||||||
|
fmt.Sprintf("%s vault update vault1 item1 -A nodename1 -M client -c %s/client.rb "+
|
||||||
|
"-u bob --key %s/bob.pem", windowsKnifeCmd, windowsConfDir, windowsConfDir): true,
|
||||||
|
fmt.Sprintf("%s vault update vault1 item2 -A nodename1 -M client -c %s/client.rb "+
|
||||||
|
"-u bob --key %s/bob.pem", windowsKnifeCmd, windowsConfDir, windowsConfDir): true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
r := new(ResourceProvisioner)
|
||||||
|
o := new(terraform.MockUIOutput)
|
||||||
|
c := new(communicator.MockCommunicator)
|
||||||
|
|
||||||
|
for k, tc := range cases {
|
||||||
|
c.Commands = tc.Commands
|
||||||
|
|
||||||
|
p, err := r.decodeConfig(tc.Config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.configureVaults = p.configureVaultsFunc(tc.GemCmd, tc.KnifeCmd, tc.ConfDir)
|
||||||
|
p.useSudo = !p.PreventSudo
|
||||||
|
|
||||||
|
err = p.configureVaults(o, c)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Test %q failed: %v", k, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue