From 61517f68b1996ba122675f485cb0c27655ef6aba Mon Sep 17 00:00:00 2001 From: Sander van Harmelen Date: Thu, 25 Jun 2015 15:48:54 +0200 Subject: [PATCH] Add an `ohai_hints` option to upload hint files This option takes a list of hints that will be uploaded to the new node before starting the initial Chef run. --- .../provisioners/chef/linux_provisioner.go | 13 +++++++ .../chef/linux_provisioner_test.go | 36 ++++++++++--------- .../provisioners/chef/resource_provisioner.go | 30 ++++++++++++++++ .../chef/resource_provisioner_test.go | 2 +- .../chef/test-fixtures/ohaihint.json | 1 + .../provisioners/chef/windows_provisioner.go | 13 +++++++ .../chef/windows_provisioner_test.go | 24 ++++++++----- .../docs/provisioners/chef.html.markdown | 5 ++- 8 files changed, 97 insertions(+), 27 deletions(-) create mode 100644 builtin/provisioners/chef/test-fixtures/ohaihint.json diff --git a/builtin/provisioners/chef/linux_provisioner.go b/builtin/provisioners/chef/linux_provisioner.go index f4f0d7373a9a..84126fd451a1 100644 --- a/builtin/provisioners/chef/linux_provisioner.go +++ b/builtin/provisioners/chef/linux_provisioner.go @@ -2,6 +2,7 @@ package chef import ( "fmt" + "path" "strings" "github.com/hashicorp/terraform/communicator" @@ -60,6 +61,18 @@ func (p *Provisioner) linuxCreateConfigFiles( return err } + if len(p.OhaiHints) > 0 { + // Make sure the hits directory exists + hintsDir := path.Join(linuxConfDir, "ohai/hints") + if err := p.runCommand(o, comm, "mkdir -p "+hintsDir); err != nil { + return err + } + + if err := p.deployOhaiHints(o, comm, hintsDir); err != nil { + return err + } + } + // When done copying the files restore the rights and make sure root is owner if p.useSudo { if err := p.runCommand(o, comm, "chmod 755 "+linuxConfDir); err != nil { diff --git a/builtin/provisioners/chef/linux_provisioner_test.go b/builtin/provisioners/chef/linux_provisioner_test.go index 264599123441..4daa5e534d6f 100644 --- a/builtin/provisioners/chef/linux_provisioner_test.go +++ b/builtin/provisioners/chef/linux_provisioner_test.go @@ -1,6 +1,7 @@ package chef import ( + "path" "testing" "github.com/hashicorp/terraform/communicator" @@ -133,6 +134,7 @@ func TestResourceProvider_linuxCreateConfigFiles(t *testing.T) { }{ "Sudo": { Config: testConfig(t, map[string]interface{}{ + "ohai_hints": []interface{}{"test-fixtures/ohaihint.json"}, "node_name": "nodename1", "run_list": []interface{}{"cookbook::recipe"}, "server_url": "https://chef.local", @@ -141,16 +143,18 @@ func TestResourceProvider_linuxCreateConfigFiles(t *testing.T) { }), Commands: map[string]bool{ - "sudo mkdir -p " + linuxConfDir: true, - "sudo chmod 777 " + linuxConfDir: true, - "sudo chmod 755 " + linuxConfDir: true, - "sudo chown -R root.root " + linuxConfDir: true, + "sudo mkdir -p " + linuxConfDir: true, + "sudo chmod 777 " + linuxConfDir: true, + "sudo mkdir -p " + path.Join(linuxConfDir, "ohai/hints"): true, + "sudo chmod 755 " + linuxConfDir: true, + "sudo chown -R root.root " + linuxConfDir: true, }, Uploads: map[string]string{ - "/etc/chef/validation.pem": "VALIDATOR-PEM-FILE", - "/etc/chef/client.rb": defaultLinuxClientConf, - "/etc/chef/first-boot.json": `{"run_list":["cookbook::recipe"]}`, + linuxConfDir + "/validation.pem": "VALIDATOR-PEM-FILE", + linuxConfDir + "/ohai/hints/ohaihint.json": "OHAI-HINT-FILE", + linuxConfDir + "/client.rb": defaultLinuxClientConf, + linuxConfDir + "/first-boot.json": `{"run_list":["cookbook::recipe"]}`, }, }, @@ -169,9 +173,9 @@ func TestResourceProvider_linuxCreateConfigFiles(t *testing.T) { }, Uploads: map[string]string{ - "/etc/chef/validation.pem": "VALIDATOR-PEM-FILE", - "/etc/chef/client.rb": defaultLinuxClientConf, - "/etc/chef/first-boot.json": `{"run_list":["cookbook::recipe"]}`, + linuxConfDir + "/validation.pem": "VALIDATOR-PEM-FILE", + linuxConfDir + "/client.rb": defaultLinuxClientConf, + linuxConfDir + "/first-boot.json": `{"run_list":["cookbook::recipe"]}`, }, }, @@ -193,9 +197,9 @@ func TestResourceProvider_linuxCreateConfigFiles(t *testing.T) { }, Uploads: map[string]string{ - "/etc/chef/validation.pem": "VALIDATOR-PEM-FILE", - "/etc/chef/client.rb": proxyLinuxClientConf, - "/etc/chef/first-boot.json": `{"run_list":["cookbook::recipe"]}`, + linuxConfDir + "/validation.pem": "VALIDATOR-PEM-FILE", + linuxConfDir + "/client.rb": proxyLinuxClientConf, + linuxConfDir + "/first-boot.json": `{"run_list":["cookbook::recipe"]}`, }, }, @@ -235,9 +239,9 @@ func TestResourceProvider_linuxCreateConfigFiles(t *testing.T) { }, Uploads: map[string]string{ - "/etc/chef/validation.pem": "VALIDATOR-PEM-FILE", - "/etc/chef/client.rb": defaultLinuxClientConf, - "/etc/chef/first-boot.json": `{"key1":{"subkey1":{"subkey2a":["val1","val2","val3"],` + + linuxConfDir + "/validation.pem": "VALIDATOR-PEM-FILE", + linuxConfDir + "/client.rb": defaultLinuxClientConf, + linuxConfDir + "/first-boot.json": `{"key1":{"subkey1":{"subkey2a":["val1","val2","val3"],` + `"subkey2b":{"subkey3":"value3"}}},"key2":"value2","run_list":["cookbook::recipe"]}`, }, }, diff --git a/builtin/provisioners/chef/resource_provisioner.go b/builtin/provisioners/chef/resource_provisioner.go index c0e8d3401318..3e3cb8abce4f 100644 --- a/builtin/provisioners/chef/resource_provisioner.go +++ b/builtin/provisioners/chef/resource_provisioner.go @@ -63,6 +63,7 @@ type Provisioner struct { HTTPSProxy string `mapstructure:"https_proxy"` NOProxy []string `mapstructure:"no_proxy"` NodeName string `mapstructure:"node_name"` + OhaiHints []string `mapstructure:"ohai_hints"` OSType string `mapstructure:"os_type"` PreventSudo bool `mapstructure:"prevent_sudo"` RunList []string `mapstructure:"run_list"` @@ -212,6 +213,14 @@ func (r *ResourceProvisioner) decodeConfig(c *terraform.ResourceConfig) (*Provis p.Environment = defaultEnv } + for i, hint := range p.OhaiHints { + hintPath, err := homedir.Expand(hint) + if err != nil { + return nil, fmt.Errorf("Error expanding the path %s: %v", hint, err) + } + p.OhaiHints[i] = hintPath + } + if p.ValidationKeyPath != "" { keyPath, err := homedir.Expand(p.ValidationKeyPath) if err != nil { @@ -386,6 +395,27 @@ func (p *Provisioner) deployConfigFiles( return nil } +func (p *Provisioner) deployOhaiHints( + o terraform.UIOutput, + comm communicator.Communicator, + hintDir string) error { + for _, hint := range p.OhaiHints { + // Open the hint file + f, err := os.Open(hint) + if err != nil { + return err + } + defer f.Close() + + // Copy the hint to the new instance + if err := comm.Upload(path.Join(hintDir, path.Base(hint)), f); err != nil { + return fmt.Errorf("Uploading %s failed: %v", path.Base(hint), err) + } + } + + return nil +} + // runCommand is used to run already prepared commands func (p *Provisioner) runCommand( o terraform.UIOutput, diff --git a/builtin/provisioners/chef/resource_provisioner_test.go b/builtin/provisioners/chef/resource_provisioner_test.go index 84a34351398d..45fc8a21199c 100644 --- a/builtin/provisioners/chef/resource_provisioner_test.go +++ b/builtin/provisioners/chef/resource_provisioner_test.go @@ -98,7 +98,7 @@ func TestResourceProvider_runChefClient(t *testing.T) { Config: testConfig(t, map[string]interface{}{ "environment": "production", "node_name": "nodename1", - "prevent_sudo": true, // Needs to be set for ALL WinRM tests! + "prevent_sudo": true, "run_list": []interface{}{"cookbook::recipe"}, "server_url": "https://chef.local", "validation_client_name": "validator", diff --git a/builtin/provisioners/chef/test-fixtures/ohaihint.json b/builtin/provisioners/chef/test-fixtures/ohaihint.json new file mode 100644 index 000000000000..9aabc32874a5 --- /dev/null +++ b/builtin/provisioners/chef/test-fixtures/ohaihint.json @@ -0,0 +1 @@ +OHAI-HINT-FILE diff --git a/builtin/provisioners/chef/windows_provisioner.go b/builtin/provisioners/chef/windows_provisioner.go index b4ac60e436a8..236bc6a9f9ff 100644 --- a/builtin/provisioners/chef/windows_provisioner.go +++ b/builtin/provisioners/chef/windows_provisioner.go @@ -71,5 +71,18 @@ func (p *Provisioner) windowsCreateConfigFiles( return err } + if len(p.OhaiHints) > 0 { + // Make sure the hits directory exists + hintsDir := path.Join(windowsConfDir, "ohai/hints") + cmd := fmt.Sprintf("if not exist %q mkdir %q", hintsDir, hintsDir) + if err := p.runCommand(o, comm, cmd); err != nil { + return err + } + + if err := p.deployOhaiHints(o, comm, hintsDir); err != nil { + return err + } + } + return p.deployConfigFiles(o, comm, windowsConfDir) } diff --git a/builtin/provisioners/chef/windows_provisioner_test.go b/builtin/provisioners/chef/windows_provisioner_test.go index 7d93b412973a..159e7be55e87 100644 --- a/builtin/provisioners/chef/windows_provisioner_test.go +++ b/builtin/provisioners/chef/windows_provisioner_test.go @@ -2,6 +2,7 @@ package chef import ( "fmt" + "path" "testing" "github.com/hashicorp/terraform/communicator" @@ -102,6 +103,7 @@ func TestResourceProvider_windowsCreateConfigFiles(t *testing.T) { }{ "Default": { Config: testConfig(t, map[string]interface{}{ + "ohai_hints": []interface{}{"test-fixtures/ohaihint.json"}, "node_name": "nodename1", "run_list": []interface{}{"cookbook::recipe"}, "server_url": "https://chef.local", @@ -111,12 +113,16 @@ func TestResourceProvider_windowsCreateConfigFiles(t *testing.T) { Commands: map[string]bool{ fmt.Sprintf("if not exist %q mkdir %q", windowsConfDir, windowsConfDir): true, + fmt.Sprintf("if not exist %q mkdir %q", + path.Join(windowsConfDir, "ohai/hints"), + path.Join(windowsConfDir, "ohai/hints")): true, }, Uploads: map[string]string{ - "C:/chef/validation.pem": "VALIDATOR-PEM-FILE", - "C:/chef/client.rb": defaultWindowsClientConf, - "C:/chef/first-boot.json": `{"run_list":["cookbook::recipe"]}`, + windowsConfDir + "/validation.pem": "VALIDATOR-PEM-FILE", + windowsConfDir + "/ohai/hints/ohaihint.json": "OHAI-HINT-FILE", + windowsConfDir + "/client.rb": defaultWindowsClientConf, + windowsConfDir + "/first-boot.json": `{"run_list":["cookbook::recipe"]}`, }, }, @@ -137,9 +143,9 @@ func TestResourceProvider_windowsCreateConfigFiles(t *testing.T) { }, Uploads: map[string]string{ - "C:/chef/validation.pem": "VALIDATOR-PEM-FILE", - "C:/chef/client.rb": proxyWindowsClientConf, - "C:/chef/first-boot.json": `{"run_list":["cookbook::recipe"]}`, + windowsConfDir + "/validation.pem": "VALIDATOR-PEM-FILE", + windowsConfDir + "/client.rb": proxyWindowsClientConf, + windowsConfDir + "/first-boot.json": `{"run_list":["cookbook::recipe"]}`, }, }, @@ -178,9 +184,9 @@ func TestResourceProvider_windowsCreateConfigFiles(t *testing.T) { }, Uploads: map[string]string{ - "C:/chef/validation.pem": "VALIDATOR-PEM-FILE", - "C:/chef/client.rb": defaultWindowsClientConf, - "C:/chef/first-boot.json": `{"key1":{"subkey1":{"subkey2a":["val1","val2","val3"],` + + windowsConfDir + "/validation.pem": "VALIDATOR-PEM-FILE", + windowsConfDir + "/client.rb": defaultWindowsClientConf, + windowsConfDir + "/first-boot.json": `{"key1":{"subkey1":{"subkey2a":["val1","val2","val3"],` + `"subkey2b":{"subkey3":"value3"}}},"key2":"value2","run_list":["cookbook::recipe"]}`, }, }, diff --git a/website/source/docs/provisioners/chef.html.markdown b/website/source/docs/provisioners/chef.html.markdown index 4cbd61c533de..24a682b55e63 100644 --- a/website/source/docs/provisioners/chef.html.markdown +++ b/website/source/docs/provisioners/chef.html.markdown @@ -67,9 +67,12 @@ The following arguments are supported: * `node_name (string)` - (Required) The name of the node to register with the Chef Server. +* `ohai_hints (array)` - (Optional) A list with + [Ohai hints](https://docs.chef.io/ohai.html#hints) to upload to the node. + * `os_type (string)` - (Optional) The OS type of the node. Valid options are: `linux` and `windows`. If not supplied the connection type will be used to determine the OS type (`ssh` - will asume `linux` and `winrm` will assume `windows`). + will asume `linux` and `winrm` will assume `windows`). * `prevent_sudo (boolean)` - (Optional) Prevent the use of sudo while installing, configuring and running the initial Chef Client run. This option is only used with `ssh` type