This fixes issue #4881 by adding an option to fetch the Chef SSL
certificates.
This commit is contained in:
Sander van Harmelen 2016-02-04 15:31:24 +01:00
parent da927fcd08
commit 79e2642dab
3 changed files with 139 additions and 38 deletions

View File

@ -24,16 +24,18 @@ import (
) )
const ( const (
clienrb = "client.rb" clienrb = "client.rb"
defaultEnv = "_default" defaultEnv = "_default"
firstBoot = "first-boot.json" firstBoot = "first-boot.json"
logfileDir = "logfiles" logfileDir = "logfiles"
linuxChefCmd = "chef-client" linuxChefCmd = "chef-client"
linuxConfDir = "/etc/chef" linuxKnifeCmd = "knife"
secretKey = "encrypted_data_bag_secret" linuxConfDir = "/etc/chef"
validationKey = "validation.pem" secretKey = "encrypted_data_bag_secret"
windowsChefCmd = "cmd /c chef-client" validationKey = "validation.pem"
windowsConfDir = "C:/chef" windowsChefCmd = "cmd /c chef-client"
windowsKnifeCmd = "cmd /c knife"
windowsConfDir = "C:/chef"
) )
const clientConf = ` const clientConf = `
@ -74,34 +76,36 @@ ENV['no_proxy'] = "{{ join .NOProxy "," }}"
// Provisioner represents a specificly configured chef provisioner // Provisioner represents a specificly configured chef provisioner
type Provisioner struct { type Provisioner struct {
Attributes interface{} `mapstructure:"attributes"` Attributes interface{} `mapstructure:"attributes"`
ClientOptions []string `mapstructure:"client_options"` ClientOptions []string `mapstructure:"client_options"`
DisableReporting bool `mapstructure:"disable_reporting"` DisableReporting bool `mapstructure:"disable_reporting"`
Environment string `mapstructure:"environment"` Environment string `mapstructure:"environment"`
LogToFile bool `mapstructure:"log_to_file"` FetchChefCertificates bool `mapstructure:"fetch_chef_certificates"`
UsePolicyfile bool `mapstructure:"use_policyfile"` LogToFile bool `mapstructure:"log_to_file"`
PolicyGroup string `mapstructure:"policy_group"` UsePolicyfile bool `mapstructure:"use_policyfile"`
PolicyName string `mapstructure:"policy_name"` PolicyGroup string `mapstructure:"policy_group"`
HTTPProxy string `mapstructure:"http_proxy"` PolicyName string `mapstructure:"policy_name"`
HTTPSProxy string `mapstructure:"https_proxy"` HTTPProxy string `mapstructure:"http_proxy"`
NOProxy []string `mapstructure:"no_proxy"` HTTPSProxy string `mapstructure:"https_proxy"`
NodeName string `mapstructure:"node_name"` NOProxy []string `mapstructure:"no_proxy"`
OhaiHints []string `mapstructure:"ohai_hints"` NodeName string `mapstructure:"node_name"`
OSType string `mapstructure:"os_type"` OhaiHints []string `mapstructure:"ohai_hints"`
PreventSudo bool `mapstructure:"prevent_sudo"` OSType string `mapstructure:"os_type"`
RunList []string `mapstructure:"run_list"` PreventSudo bool `mapstructure:"prevent_sudo"`
SecretKey string `mapstructure:"secret_key"` RunList []string `mapstructure:"run_list"`
ServerURL string `mapstructure:"server_url"` SecretKey string `mapstructure:"secret_key"`
SkipInstall bool `mapstructure:"skip_install"` ServerURL string `mapstructure:"server_url"`
SSLVerifyMode string `mapstructure:"ssl_verify_mode"` SkipInstall bool `mapstructure:"skip_install"`
ValidationClientName string `mapstructure:"validation_client_name"` SSLVerifyMode string `mapstructure:"ssl_verify_mode"`
ValidationKey string `mapstructure:"validation_key"` ValidationClientName string `mapstructure:"validation_client_name"`
Version string `mapstructure:"version"` ValidationKey string `mapstructure:"validation_key"`
Version string `mapstructure:"version"`
installChefClient func(terraform.UIOutput, communicator.Communicator) error installChefClient func(terraform.UIOutput, communicator.Communicator) error
createConfigFiles func(terraform.UIOutput, communicator.Communicator) error createConfigFiles func(terraform.UIOutput, communicator.Communicator) error
runChefClient func(terraform.UIOutput, communicator.Communicator) error fetchChefCertificates func(terraform.UIOutput, communicator.Communicator) error
useSudo bool runChefClient func(terraform.UIOutput, communicator.Communicator) error
useSudo bool
// Deprecated Fields // Deprecated Fields
SecretKeyPath string `mapstructure:"secret_key_path"` SecretKeyPath string `mapstructure:"secret_key_path"`
@ -138,11 +142,13 @@ func (r *ResourceProvisioner) Apply(
case "linux": case "linux":
p.installChefClient = p.linuxInstallChefClient p.installChefClient = p.linuxInstallChefClient
p.createConfigFiles = p.linuxCreateConfigFiles p.createConfigFiles = p.linuxCreateConfigFiles
p.fetchChefCertificates = p.fetchChefCertificatesFunc(linuxChefCmd, linuxConfDir)
p.runChefClient = p.runChefClientFunc(linuxChefCmd, linuxConfDir) p.runChefClient = p.runChefClientFunc(linuxChefCmd, linuxConfDir)
p.useSudo = !p.PreventSudo && s.Ephemeral.ConnInfo["user"] != "root" p.useSudo = !p.PreventSudo && s.Ephemeral.ConnInfo["user"] != "root"
case "windows": case "windows":
p.installChefClient = p.windowsInstallChefClient p.installChefClient = p.windowsInstallChefClient
p.createConfigFiles = p.windowsCreateConfigFiles p.createConfigFiles = p.windowsCreateConfigFiles
p.fetchChefCertificates = p.fetchChefCertificatesFunc(windowsChefCmd, windowsConfDir)
p.runChefClient = p.runChefClientFunc(windowsChefCmd, windowsConfDir) p.runChefClient = p.runChefClientFunc(windowsChefCmd, windowsConfDir)
p.useSudo = false p.useSudo = false
default: default:
@ -176,6 +182,13 @@ func (r *ResourceProvisioner) Apply(
return err return err
} }
if p.FetchChefCertificates {
o.Output("Fetch Chef certificates...")
if err := p.fetchChefCertificates(o, comm); err != nil {
return err
}
}
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
@ -343,6 +356,17 @@ func retryFunc(timeout time.Duration, f func() error) error {
} }
} }
func (p *Provisioner) fetchChefCertificatesFunc(
knifeCmd string,
confDir string) func(terraform.UIOutput, communicator.Communicator) error {
return func(o terraform.UIOutput, comm communicator.Communicator) error {
clientrb := path.Join(confDir, clienrb)
cmd := fmt.Sprintf("%s ssl fetch -c %s", knifeCmd, clientrb)
return p.runCommand(o, comm, cmd)
}
}
func (p *Provisioner) runChefClientFunc( func (p *Provisioner) runChefClientFunc(
chefCmd string, chefCmd string,
confDir string) func(terraform.UIOutput, communicator.Communicator) error { confDir string) func(terraform.UIOutput, communicator.Communicator) error {

View File

@ -148,3 +148,76 @@ func TestResourceProvider_runChefClient(t *testing.T) {
} }
} }
} }
func TestResourceProvider_fetchChefCertificates(t *testing.T) {
cases := map[string]struct {
Config *terraform.ResourceConfig
KnifeCmd string
ConfDir string
Commands map[string]bool
}{
"Sudo": {
Config: testConfig(t, map[string]interface{}{
"fetch_chef_certificates": true,
"node_name": "nodename1",
"run_list": []interface{}{"cookbook::recipe"},
"server_url": "https://chef.local",
"validation_client_name": "validator",
"validation_key_path": "test-fixtures/validator.pem",
}),
KnifeCmd: linuxKnifeCmd,
ConfDir: linuxConfDir,
Commands: map[string]bool{
fmt.Sprintf(`sudo %s ssl fetch -c %s`,
linuxKnifeCmd,
path.Join(linuxConfDir, "client.rb")): true,
},
},
"NoSudo": {
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",
"validation_client_name": "validator",
"validation_key_path": "test-fixtures/validator.pem",
}),
KnifeCmd: windowsKnifeCmd,
ConfDir: windowsConfDir,
Commands: map[string]bool{
fmt.Sprintf(`%s ssl fetch -c %s`,
windowsKnifeCmd,
path.Join(windowsConfDir, "client.rb")): 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.fetchChefCertificates = p.fetchChefCertificatesFunc(tc.KnifeCmd, tc.ConfDir)
p.useSudo = !p.PreventSudo
err = p.fetchChefCertificates(o, c)
if err != nil {
t.Fatalf("Test %q failed: %v", k, err)
}
}
}

View File

@ -59,7 +59,7 @@ The following arguments are supported:
interpolation function](/docs/configuration/interpolation.html#file_path_). interpolation function](/docs/configuration/interpolation.html#file_path_).
* `client_options (array)` - (Optional) A list of optional Chef Client configuration * `client_options (array)` - (Optional) A list of optional Chef Client configuration
options. See the Chef Client [documentation](https://docs.chef.io/config_rb_client.html) for all available options. options. See the [Chef Client ](https://docs.chef.io/config_rb_client.html) documentation for all available options.
* `disable_reporting (boolean)` - (Optional) If true the Chef Client will not try to send * `disable_reporting (boolean)` - (Optional) If true the Chef Client will not try to send
reporting data (used by Chef Reporting) to the Chef Server (defaults false) reporting data (used by Chef Reporting) to the Chef Server (defaults false)
@ -67,6 +67,10 @@ The following arguments are supported:
* `environment (string)` - (Optional) The Chef environment the new node will be joining * `environment (string)` - (Optional) The Chef environment the new node will be joining
(defaults `_default`). (defaults `_default`).
* `fetch_chef_certificates (boolean)` (Optional) If true the SSL certificates configured
on your Chef server will be fetched and trusted. See the knife [ssl_fetch](https://docs.chef.io/knife_ssl_fetch.html)
documentation for more details.
* `log_to_file (boolean)` - (Optional) If true, the output of the initial Chef Client run * `log_to_file (boolean)` - (Optional) If true, the output of the initial Chef Client run
will be logged to a local file instead of the console. The file will be created in a will be logged to a local file instead of the console. The file will be created in a
subdirectory called `logfiles` created in your current directory. The filename will be subdirectory called `logfiles` created in your current directory. The filename will be