diff --git a/builtin/provisioners/chef-client/resource_provisioner_test.go b/builtin/provisioners/chef-client/resource_provisioner_test.go index 7c798c7e3..6dfd33916 100644 --- a/builtin/provisioners/chef-client/resource_provisioner_test.go +++ b/builtin/provisioners/chef-client/resource_provisioner_test.go @@ -3,6 +3,7 @@ package chefclient import ( "testing" + "github.com/hashicorp/terraform/communicator" "github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/terraform" ) @@ -13,17 +14,16 @@ func TestResourceProvisioner_impl(t *testing.T) { func TestResourceProvider_Validate_good(t *testing.T) { c := testConfig(t, map[string]interface{}{ - "package": "https://opscode-omnibus-packages.s3.amazonaws.com/el/6/x86_64/chef-11.18.6-1.el6.x86_64.rpm", - "run_list": []interface{}{"cookbook::recipe"}, - "node_name": "nodename1", + "attributes": []interface{}{"key1 { subkey1 = value1 }"}, "environment": "_default", + "node_name": "nodename1", + "run_list": []interface{}{"cookbook::recipe"}, "server_url": "https://chef.local", "validation_client_name": "validator", "validation_key_path": "validator.pem", - "attributes": []interface{}{"key1 { subkey1 = value1 }"}, }) - p := new(ResourceProvisioner) - warn, errs := p.Validate(c) + r := new(ResourceProvisioner) + warn, errs := r.Validate(c) if len(warn) > 0 { t.Fatalf("Warnings: %v", warn) } @@ -34,7 +34,7 @@ func TestResourceProvider_Validate_good(t *testing.T) { func TestResourceProvider_Validate_bad(t *testing.T) { c := testConfig(t, map[string]interface{}{ - "package": "nope", + "invalid": "nope", }) p := new(ResourceProvisioner) warn, errs := p.Validate(c) @@ -54,3 +54,82 @@ func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfi return terraform.NewResourceConfig(r) } + +func TestResourceProvider_runChefClient(t *testing.T) { + cases := map[string]struct { + Config *terraform.ResourceConfig + ConfDir string + Commands map[string]bool + }{ + "Sudo": { + Config: testConfig(t, map[string]interface{}{ + "node_name": "nodename1", + "run_list": []interface{}{"cookbook::recipe"}, + "server_url": "https://chef.local", + "validation_client_name": "validator", + "validation_key_path": "test-fixtures/validator.pem", + }), + + ConfDir: linuxConfDir, + + Commands: map[string]bool{ + `sudo chef-client -j "/etc/chef/first-boot.json" -E "_default"`: true, + }, + }, + + "NoSudo": { + Config: testConfig(t, map[string]interface{}{ + "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", + }), + + ConfDir: linuxConfDir, + + Commands: map[string]bool{ + `chef-client -j "/etc/chef/first-boot.json" -E "_default"`: true, + }, + }, + + "Environment": { + Config: testConfig(t, map[string]interface{}{ + "environment": "production", + "node_name": "nodename1", + "prevent_sudo": true, // Needs to be set for ALL WinRM tests! + "run_list": []interface{}{"cookbook::recipe"}, + "server_url": "https://chef.local", + "validation_client_name": "validator", + "validation_key_path": "test-fixtures/validator.pem", + }), + + ConfDir: windowsConfDir, + + Commands: map[string]bool{ + `chef-client -j "C:/chef/first-boot.json" -E "production"`: 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.runChefClient = p.runChefClientFunc(tc.ConfDir) + + err = p.runChefClient(o, c) + if err != nil { + t.Fatalf("Test %q failed: %v", k, err) + } + } +} diff --git a/builtin/provisioners/chef-client/ssh_provisioner.go b/builtin/provisioners/chef-client/ssh_provisioner.go index 2f95f7cc4..9efea5a7b 100644 --- a/builtin/provisioners/chef-client/ssh_provisioner.go +++ b/builtin/provisioners/chef-client/ssh_provisioner.go @@ -2,7 +2,6 @@ package chefclient import ( "bytes" - "fmt" "strings" "github.com/hashicorp/terraform/communicator" @@ -30,7 +29,11 @@ func (p *Provisioner) sshInstallChefClient( if p.Version != "" { installCmd.WriteString(" -v " + p.Version) } - installCmd.WriteString(" && rm -f install.sh") + installCmd.WriteString(" &&") + if !p.PreventSudo { + installCmd.WriteString(" sudo") + } + installCmd.WriteString(" rm -f install.sh") // Execute the command to install Chef Client return p.runCommand(o, comm, installCmd.String()) @@ -40,8 +43,7 @@ func (p *Provisioner) sshCreateConfigFiles( o terraform.UIOutput, comm communicator.Communicator) error { // Make sure the config directory exists - cmd := fmt.Sprintf("mkdir -p %q", linuxConfDir) - if err := p.runCommand(o, comm, cmd); err != nil { + if err := p.runCommand(o, comm, "mkdir -p "+linuxConfDir); err != nil { return err } diff --git a/builtin/provisioners/chef-client/ssh_provisioner_test.go b/builtin/provisioners/chef-client/ssh_provisioner_test.go index 9378abfe0..7e7389d21 100644 --- a/builtin/provisioners/chef-client/ssh_provisioner_test.go +++ b/builtin/provisioners/chef-client/ssh_provisioner_test.go @@ -1 +1,279 @@ package chefclient + +import ( + "testing" + + "github.com/hashicorp/terraform/communicator" + "github.com/hashicorp/terraform/terraform" +) + +func TestResourceProvider_sshInstallChefClient(t *testing.T) { + cases := map[string]struct { + Config *terraform.ResourceConfig + Commands map[string]bool + }{ + "Sudo": { + Config: testConfig(t, map[string]interface{}{ + "node_name": "nodename1", + "run_list": []interface{}{"cookbook::recipe"}, + "server_url": "https://chef.local", + "validation_client_name": "validator", + "validation_key_path": "validator.pem", + }), + + Commands: map[string]bool{ + "sudo curl -LO https://www.chef.io/chef/install.sh 2>/dev/null && " + + "sudo bash ./install.sh && sudo rm -f install.sh": true, + }, + }, + + "NoSudo": { + Config: testConfig(t, map[string]interface{}{ + "node_name": "nodename1", + "prevent_sudo": true, + "run_list": []interface{}{"cookbook::recipe"}, + "server_url": "https://chef.local", + "validation_client_name": "validator", + "validation_key_path": "validator.pem", + }), + + Commands: map[string]bool{ + "curl -LO https://www.chef.io/chef/install.sh 2>/dev/null && " + + "bash ./install.sh && rm -f install.sh": true, + }, + }, + + "HTTPProxy": { + Config: testConfig(t, map[string]interface{}{ + "http_proxy": "http://proxy.local", + "node_name": "nodename1", + "prevent_sudo": true, + "run_list": []interface{}{"cookbook::recipe"}, + "server_url": "https://chef.local", + "validation_client_name": "validator", + "validation_key_path": "validator.pem", + }), + + Commands: map[string]bool{ + "curl --proxy http://proxy.local -LO https://www.chef.io/chef/install.sh 2>/dev/null && " + + "bash ./install.sh && rm -f install.sh": true, + }, + }, + + "NOProxy": { + Config: testConfig(t, map[string]interface{}{ + "http_proxy": "http://proxy.local", + "no_proxy": []interface{}{"http://local.local", "http://local.org"}, + "node_name": "nodename1", + "prevent_sudo": true, + "run_list": []interface{}{"cookbook::recipe"}, + "server_url": "https://chef.local", + "validation_client_name": "validator", + "validation_key_path": "validator.pem", + }), + + Commands: map[string]bool{ + "curl --proxy http://proxy.local --noproxy http://local.local,http://local.org -LO " + + "https://www.chef.io/chef/install.sh 2>/dev/null && bash ./install.sh && " + + "rm -f install.sh": true, + }, + }, + + "Version": { + Config: testConfig(t, map[string]interface{}{ + "node_name": "nodename1", + "prevent_sudo": true, + "run_list": []interface{}{"cookbook::recipe"}, + "server_url": "https://chef.local", + "validation_client_name": "validator", + "validation_key_path": "validator.pem", + "version": "11.18.6", + }), + + Commands: map[string]bool{ + "curl -LO https://www.chef.io/chef/install.sh 2>/dev/null && " + + "bash ./install.sh -v 11.18.6 && rm -f install.sh": 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) + } + + err = p.sshInstallChefClient(o, c) + if err != nil { + t.Fatalf("Test %q failed: %v", k, err) + } + } +} + +func TestResourceProvider_sshCreateConfigFiles(t *testing.T) { + cases := map[string]struct { + Config *terraform.ResourceConfig + Commands map[string]bool + Uploads map[string]string + }{ + "Sudo": { + Config: testConfig(t, map[string]interface{}{ + "node_name": "nodename1", + "run_list": []interface{}{"cookbook::recipe"}, + "server_url": "https://chef.local", + "validation_client_name": "validator", + "validation_key_path": "test-fixtures/validator.pem", + }), + + 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, + }, + + Uploads: map[string]string{ + "/etc/chef/validation.pem": "VALIDATOR-PEM-FILE", + "/etc/chef/client.rb": defaultSSHClientConf, + "/etc/chef/first-boot.json": `{"run_list":["cookbook::recipe"]}`, + }, + }, + + "NoSudo": { + Config: testConfig(t, map[string]interface{}{ + "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", + }), + + Commands: map[string]bool{ + "mkdir -p " + linuxConfDir: true, + }, + + Uploads: map[string]string{ + "/etc/chef/validation.pem": "VALIDATOR-PEM-FILE", + "/etc/chef/client.rb": defaultSSHClientConf, + "/etc/chef/first-boot.json": `{"run_list":["cookbook::recipe"]}`, + }, + }, + + "Proxy": { + Config: testConfig(t, map[string]interface{}{ + "http_proxy": "http://proxy.local", + "https_proxy": "https://proxy.local", + "no_proxy": []interface{}{"http://local.local", "https://local.local"}, + "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", + }), + + Commands: map[string]bool{ + "mkdir -p " + linuxConfDir: true, + }, + + Uploads: map[string]string{ + "/etc/chef/validation.pem": "VALIDATOR-PEM-FILE", + "/etc/chef/client.rb": proxySSHClientConf, + "/etc/chef/first-boot.json": `{"run_list":["cookbook::recipe"]}`, + }, + }, + + "Attributes": { + Config: testConfig(t, map[string]interface{}{ + "attributes": []map[string]interface{}{ + map[string]interface{}{ + "key1": []map[string]interface{}{ + map[string]interface{}{ + "subkey1": []map[string]interface{}{ + map[string]interface{}{ + "subkey2a": []interface{}{ + "val1", "val2", "val3", + }, + "subkey2b": []map[string]interface{}{ + map[string]interface{}{ + "subkey3": "value3", + }, + }, + }, + }, + }, + }, + "key2": "value2", + }, + }, + "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", + }), + + Commands: map[string]bool{ + "mkdir -p " + linuxConfDir: true, + }, + + Uploads: map[string]string{ + "/etc/chef/validation.pem": "VALIDATOR-PEM-FILE", + "/etc/chef/client.rb": defaultSSHClientConf, + "/etc/chef/first-boot.json": `{"key1":{"subkey1":{"subkey2a":["val1","val2","val3"],` + + `"subkey2b":{"subkey3":"value3"}}},"key2":"value2","run_list":["cookbook::recipe"]}`, + }, + }, + } + + r := new(ResourceProvisioner) + o := new(terraform.MockUIOutput) + c := new(communicator.MockCommunicator) + + for k, tc := range cases { + c.Commands = tc.Commands + c.Uploads = tc.Uploads + + p, err := r.decodeConfig(tc.Config) + if err != nil { + t.Fatalf("Error: %v", err) + } + + err = p.sshCreateConfigFiles(o, c) + if err != nil { + t.Fatalf("Test %q failed: %v", k, err) + } + } +} + +const defaultSSHClientConf = `log_location STDOUT +chef_server_url "https://chef.local" +validation_client_name "validator" +node_name "nodename1"` + +const proxySSHClientConf = `log_location STDOUT +chef_server_url "https://chef.local" +validation_client_name "validator" +node_name "nodename1" + + +http_proxy "http://proxy.local" +ENV['http_proxy'] = "http://proxy.local" +ENV['HTTP_PROXY'] = "http://proxy.local" + + + +https_proxy "https://proxy.local" +ENV['https_proxy'] = "https://proxy.local" +ENV['HTTPS_PROXY'] = "https://proxy.local" + + +no_proxy "http://local.local,https://local.local"` diff --git a/builtin/provisioners/chef-client/test-fixtures/validator.pem b/builtin/provisioners/chef-client/test-fixtures/validator.pem new file mode 100644 index 000000000..03e6d6de7 --- /dev/null +++ b/builtin/provisioners/chef-client/test-fixtures/validator.pem @@ -0,0 +1 @@ +VALIDATOR-PEM-FILE diff --git a/builtin/provisioners/chef-client/winrm_provisioner.go b/builtin/provisioners/chef-client/winrm_provisioner.go index 6b4edcf5f..7f3426e76 100644 --- a/builtin/provisioners/chef-client/winrm_provisioner.go +++ b/builtin/provisioners/chef-client/winrm_provisioner.go @@ -49,7 +49,7 @@ Start-Process -FilePath msiexec -ArgumentList /qn, /i, $dest -Wait func (p *Provisioner) winrmInstallChefClient( o terraform.UIOutput, comm communicator.Communicator) error { - script := path.Join(path.Dir(comm.ScriptPath()), "chefclient.ps1") + script := path.Join(path.Dir(comm.ScriptPath()), "ChefClient.ps1") content := fmt.Sprintf(installScript, p.Version, p.HTTPProxy, strings.Join(p.NOProxy, ",")) // Copy the script to the new instance diff --git a/builtin/provisioners/chef-client/winrm_provisioner_test.go b/builtin/provisioners/chef-client/winrm_provisioner_test.go index 9378abfe0..95fb38773 100644 --- a/builtin/provisioners/chef-client/winrm_provisioner_test.go +++ b/builtin/provisioners/chef-client/winrm_provisioner_test.go @@ -1 +1,346 @@ package chefclient + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/communicator" + "github.com/hashicorp/terraform/terraform" +) + +func TestResourceProvider_winrmInstallChefClient(t *testing.T) { + cases := map[string]struct { + Config *terraform.ResourceConfig + Commands map[string]bool + UploadScripts map[string]string + }{ + "Default": { + Config: testConfig(t, map[string]interface{}{ + "node_name": "nodename1", + "prevent_sudo": true, // Needs to be set for ALL WinRM tests! + "run_list": []interface{}{"cookbook::recipe"}, + "server_url": "https://chef.local", + "validation_client_name": "validator", + "validation_key_path": "validator.pem", + }), + + Commands: map[string]bool{ + "powershell -NoProfile -ExecutionPolicy Bypass -File ChefClient.ps1": true, + }, + + UploadScripts: map[string]string{ + "ChefClient.ps1": defaultWinRMInstallScript, + }, + }, + + "Proxy": { + Config: testConfig(t, map[string]interface{}{ + "http_proxy": "http://proxy.local", + "no_proxy": []interface{}{"http://local.local", "http://local.org"}, + "node_name": "nodename1", + "prevent_sudo": true, // Needs to be set for ALL WinRM tests! + "run_list": []interface{}{"cookbook::recipe"}, + "server_url": "https://chef.local", + "validation_client_name": "validator", + "validation_key_path": "validator.pem", + }), + + Commands: map[string]bool{ + "powershell -NoProfile -ExecutionPolicy Bypass -File ChefClient.ps1": true, + }, + + UploadScripts: map[string]string{ + "ChefClient.ps1": proxyWinRMInstallScript, + }, + }, + + "Version": { + Config: testConfig(t, map[string]interface{}{ + "node_name": "nodename1", + "prevent_sudo": true, // Needs to be set for ALL WinRM tests! + "run_list": []interface{}{"cookbook::recipe"}, + "server_url": "https://chef.local", + "validation_client_name": "validator", + "validation_key_path": "validator.pem", + "version": "11.18.6", + }), + + Commands: map[string]bool{ + "powershell -NoProfile -ExecutionPolicy Bypass -File ChefClient.ps1": true, + }, + + UploadScripts: map[string]string{ + "ChefClient.ps1": versionWinRMInstallScript, + }, + }, + } + + r := new(ResourceProvisioner) + o := new(terraform.MockUIOutput) + c := new(communicator.MockCommunicator) + + for k, tc := range cases { + c.Commands = tc.Commands + c.UploadScripts = tc.UploadScripts + + p, err := r.decodeConfig(tc.Config) + if err != nil { + t.Fatalf("Error: %v", err) + } + + err = p.winrmInstallChefClient(o, c) + if err != nil { + t.Fatalf("Test %q failed: %v", k, err) + } + } +} + +func TestResourceProvider_winrmCreateConfigFiles(t *testing.T) { + cases := map[string]struct { + Config *terraform.ResourceConfig + Commands map[string]bool + Uploads map[string]string + }{ + "Default": { + Config: testConfig(t, map[string]interface{}{ + "node_name": "nodename1", + "prevent_sudo": true, // Needs to be set for ALL WinRM tests! + "run_list": []interface{}{"cookbook::recipe"}, + "server_url": "https://chef.local", + "validation_client_name": "validator", + "validation_key_path": "test-fixtures/validator.pem", + }), + + Commands: map[string]bool{ + fmt.Sprintf("if not exist %q mkdir %q", windowsConfDir, windowsConfDir): true, + }, + + Uploads: map[string]string{ + "C:/chef/validation.pem": "VALIDATOR-PEM-FILE", + "C:/chef/client.rb": defaultWinRMClientConf, + "C:/chef/first-boot.json": `{"run_list":["cookbook::recipe"]}`, + }, + }, + + "Proxy": { + Config: testConfig(t, map[string]interface{}{ + "http_proxy": "http://proxy.local", + "https_proxy": "https://proxy.local", + "no_proxy": []interface{}{"http://local.local", "https://local.local"}, + "node_name": "nodename1", + "prevent_sudo": true, // Needs to be set for ALL WinRM tests! + "run_list": []interface{}{"cookbook::recipe"}, + "server_url": "https://chef.local", + "validation_client_name": "validator", + "validation_key_path": "test-fixtures/validator.pem", + }), + + Commands: map[string]bool{ + fmt.Sprintf("if not exist %q mkdir %q", windowsConfDir, windowsConfDir): true, + }, + + Uploads: map[string]string{ + "C:/chef/validation.pem": "VALIDATOR-PEM-FILE", + "C:/chef/client.rb": proxyWinRMClientConf, + "C:/chef/first-boot.json": `{"run_list":["cookbook::recipe"]}`, + }, + }, + + "Attributes": { + Config: testConfig(t, map[string]interface{}{ + "attributes": []map[string]interface{}{ + map[string]interface{}{ + "key1": []map[string]interface{}{ + map[string]interface{}{ + "subkey1": []map[string]interface{}{ + map[string]interface{}{ + "subkey2a": []interface{}{ + "val1", "val2", "val3", + }, + "subkey2b": []map[string]interface{}{ + map[string]interface{}{ + "subkey3": "value3", + }, + }, + }, + }, + }, + }, + "key2": "value2", + }, + }, + "node_name": "nodename1", + "prevent_sudo": true, // Needs to be set for ALL WinRM tests! + "run_list": []interface{}{"cookbook::recipe"}, + "server_url": "https://chef.local", + "validation_client_name": "validator", + "validation_key_path": "test-fixtures/validator.pem", + }), + + Commands: map[string]bool{ + fmt.Sprintf("if not exist %q mkdir %q", windowsConfDir, windowsConfDir): true, + }, + + Uploads: map[string]string{ + "C:/chef/validation.pem": "VALIDATOR-PEM-FILE", + "C:/chef/client.rb": defaultWinRMClientConf, + "C:/chef/first-boot.json": `{"key1":{"subkey1":{"subkey2a":["val1","val2","val3"],` + + `"subkey2b":{"subkey3":"value3"}}},"key2":"value2","run_list":["cookbook::recipe"]}`, + }, + }, + } + + r := new(ResourceProvisioner) + o := new(terraform.MockUIOutput) + c := new(communicator.MockCommunicator) + + for k, tc := range cases { + c.Commands = tc.Commands + c.Uploads = tc.Uploads + + p, err := r.decodeConfig(tc.Config) + if err != nil { + t.Fatalf("Error: %v", err) + } + + err = p.winrmCreateConfigFiles(o, c) + if err != nil { + t.Fatalf("Test %q failed: %v", k, err) + } + } +} + +const defaultWinRMInstallScript = ` +$winver = [System.Environment]::OSVersion.Version | % {"{0}.{1}" -f $_.Major,$_.Minor} + +switch ($winver) +{ + "6.0" {$machine_os = "2008"} + "6.1" {$machine_os = "2008r2"} + "6.2" {$machine_os = "2012"} + "6.3" {$machine_os = "2012"} + default {$machine_os = "2008r2"} +} + +if ([System.IntPtr]::Size -eq 4) {$machine_arch = "i686"} else {$machine_arch = "x86_64"} + +$url = "http://www.chef.io/chef/download?p=windows&pv=$machine_os&m=$machine_arch&v=" +$dest = [System.IO.Path]::GetTempFileName() +$dest = [System.IO.Path]::ChangeExtension($dest, ".msi") +$downloader = New-Object System.Net.WebClient + +$http_proxy = '' +if ($http_proxy -ne '') { + $no_proxy = '' + if ($no_proxy -eq ''){ + $no_proxy = "127.0.0.1" + } + + $proxy = New-Object System.Net.WebProxy($http_proxy, $true, ,$no_proxy.Split(',')) + $downloader.proxy = $proxy +} + +Write-Host 'Downloading Chef Client...' +$downloader.DownloadFile($url, $dest) + +Write-Host 'Installing Chef Client...' +Start-Process -FilePath msiexec -ArgumentList /qn, /i, $dest -Wait +` + +const proxyWinRMInstallScript = ` +$winver = [System.Environment]::OSVersion.Version | % {"{0}.{1}" -f $_.Major,$_.Minor} + +switch ($winver) +{ + "6.0" {$machine_os = "2008"} + "6.1" {$machine_os = "2008r2"} + "6.2" {$machine_os = "2012"} + "6.3" {$machine_os = "2012"} + default {$machine_os = "2008r2"} +} + +if ([System.IntPtr]::Size -eq 4) {$machine_arch = "i686"} else {$machine_arch = "x86_64"} + +$url = "http://www.chef.io/chef/download?p=windows&pv=$machine_os&m=$machine_arch&v=" +$dest = [System.IO.Path]::GetTempFileName() +$dest = [System.IO.Path]::ChangeExtension($dest, ".msi") +$downloader = New-Object System.Net.WebClient + +$http_proxy = 'http://proxy.local' +if ($http_proxy -ne '') { + $no_proxy = 'http://local.local,http://local.org' + if ($no_proxy -eq ''){ + $no_proxy = "127.0.0.1" + } + + $proxy = New-Object System.Net.WebProxy($http_proxy, $true, ,$no_proxy.Split(',')) + $downloader.proxy = $proxy +} + +Write-Host 'Downloading Chef Client...' +$downloader.DownloadFile($url, $dest) + +Write-Host 'Installing Chef Client...' +Start-Process -FilePath msiexec -ArgumentList /qn, /i, $dest -Wait +` + +const versionWinRMInstallScript = ` +$winver = [System.Environment]::OSVersion.Version | % {"{0}.{1}" -f $_.Major,$_.Minor} + +switch ($winver) +{ + "6.0" {$machine_os = "2008"} + "6.1" {$machine_os = "2008r2"} + "6.2" {$machine_os = "2012"} + "6.3" {$machine_os = "2012"} + default {$machine_os = "2008r2"} +} + +if ([System.IntPtr]::Size -eq 4) {$machine_arch = "i686"} else {$machine_arch = "x86_64"} + +$url = "http://www.chef.io/chef/download?p=windows&pv=$machine_os&m=$machine_arch&v=11.18.6" +$dest = [System.IO.Path]::GetTempFileName() +$dest = [System.IO.Path]::ChangeExtension($dest, ".msi") +$downloader = New-Object System.Net.WebClient + +$http_proxy = '' +if ($http_proxy -ne '') { + $no_proxy = '' + if ($no_proxy -eq ''){ + $no_proxy = "127.0.0.1" + } + + $proxy = New-Object System.Net.WebProxy($http_proxy, $true, ,$no_proxy.Split(',')) + $downloader.proxy = $proxy +} + +Write-Host 'Downloading Chef Client...' +$downloader.DownloadFile($url, $dest) + +Write-Host 'Installing Chef Client...' +Start-Process -FilePath msiexec -ArgumentList /qn, /i, $dest -Wait +` + +const defaultWinRMClientConf = `log_location STDOUT +chef_server_url "https://chef.local" +validation_client_name "validator" +node_name "nodename1"` + +const proxyWinRMClientConf = `log_location STDOUT +chef_server_url "https://chef.local" +validation_client_name "validator" +node_name "nodename1" + + +http_proxy "http://proxy.local" +ENV['http_proxy'] = "http://proxy.local" +ENV['HTTP_PROXY'] = "http://proxy.local" + + + +https_proxy "https://proxy.local" +ENV['https_proxy'] = "https://proxy.local" +ENV['HTTPS_PROXY'] = "https://proxy.local" + + +no_proxy "http://local.local,https://local.local"` diff --git a/communicator/communicator_mock.go b/communicator/communicator_mock.go new file mode 100644 index 000000000..f1c5ad5e6 --- /dev/null +++ b/communicator/communicator_mock.go @@ -0,0 +1,91 @@ +package communicator + +import ( + "bytes" + "fmt" + "io" + "strings" + "time" + + "github.com/hashicorp/terraform/communicator/remote" + "github.com/hashicorp/terraform/terraform" +) + +// MockCommunicator is an implementation of Communicator that can be used for tests. +type MockCommunicator struct { + RemoteScriptPath string + Commands map[string]bool + Uploads map[string]string + UploadScripts map[string]string + UploadDirs map[string]string +} + +// Connect implementation of communicator.Communicator interface +func (c *MockCommunicator) Connect(o terraform.UIOutput) error { + return nil +} + +// Disconnect implementation of communicator.Communicator interface +func (c *MockCommunicator) Disconnect() error { + return nil +} + +// Timeout implementation of communicator.Communicator interface +func (c *MockCommunicator) Timeout() time.Duration { + return time.Duration(5 * time.Second) +} + +// ScriptPath implementation of communicator.Communicator interface +func (c *MockCommunicator) ScriptPath() string { + return c.RemoteScriptPath +} + +// Start implementation of communicator.Communicator interface +func (c *MockCommunicator) Start(r *remote.Cmd) error { + if !c.Commands[r.Command] { + return fmt.Errorf("Command not found!") + } + + r.SetExited(0) + + return nil +} + +// Upload implementation of communicator.Communicator interface +func (c *MockCommunicator) Upload(path string, input io.Reader) error { + f, ok := c.Uploads[path] + if !ok { + return fmt.Errorf("Path %q not found!", path) + } + + var buf bytes.Buffer + buf.ReadFrom(input) + content := strings.TrimSpace(buf.String()) + + f = strings.TrimSpace(f) + if f != content { + return fmt.Errorf("expected: %q\n\ngot: %q\n", f, content) + } + + return nil +} + +// UploadScript implementation of communicator.Communicator interface +func (c *MockCommunicator) UploadScript(path string, input io.Reader) error { + c.Uploads = c.UploadScripts + return c.Upload(path, input) +} + +// UploadDir implementation of communicator.Communicator interface +func (c *MockCommunicator) UploadDir(dst string, src string) error { + v, ok := c.UploadDirs[src] + if !ok { + return fmt.Errorf("Directory not found!") + } + + if v != dst { + return fmt.Errorf("expected: %q\n\ngot: %q\n", v, dst) + } + + return nil +}