terraform/builtin/provisioners/puppet/windows_provisioner_test.go

394 lines
9.8 KiB
Go

package puppet
import (
"fmt"
"io"
"strings"
"testing"
"time"
"github.com/hashicorp/terraform/communicator"
"github.com/hashicorp/terraform/communicator/remote"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
)
const (
getHostByNameCmd = `powershell -Command "& {([System.Net.Dns]::GetHostByName(($env:computerName))).Hostname}"`
domainQueryCmd = `powershell -Command "& {(Get-WmiObject -Query 'select DNSDomain from Win32_NetworkAdapterConfiguration where IPEnabled = True').DNSDomain}"`
downloadInstallerCmd = `powershell -Command "& {[Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}; (New-Object System.Net.WebClient).DownloadFile('https://puppet.test.com:8140/packages/current/install.ps1', 'install.ps1')}"`
runInstallerCmd = `powershell -Command "& .\install.ps1 -PuppetServiceEnsure stopped"`
runPuppetCmd = "puppet agent --test --server puppet.test.com --environment production"
)
func TestResourceProvisioner_windowsUploadFile(t *testing.T) {
cases := map[string]struct {
Config map[string]interface{}
Commands map[string]bool
CommandFunc func(*remote.Cmd) error
ExpectedError bool
Uploads map[string]string
File io.Reader
Dir string
Filename string
}{
"Successful upload": {
Config: map[string]interface{}{
"server": "puppet.test.com",
"use_sudo": false,
},
Commands: map[string]bool{
`powershell.exe new-item -itemtype directory -force -path C:\ProgramData\PuppetLabs\puppet\etc`: true,
},
Uploads: map[string]string{
`C:\ProgramData\PuppetLabs\puppet\etc\csr_attributes.yaml`: "",
},
Dir: `C:\ProgramData\PuppetLabs\puppet\etc`,
Filename: "csr_attributes.yaml",
File: strings.NewReader(""),
},
"Failure when creating the directory": {
Config: map[string]interface{}{
"server": "puppet.test.com",
"use_sudo": false,
},
Commands: map[string]bool{
`powershell.exe new-item -itemtype directory -force -path C:\ProgramData\PuppetLabs\puppet\etc`: true,
},
Dir: `C:\ProgramData\PuppetLabs\puppet\etc`,
Filename: "csr_attributes.yaml",
File: strings.NewReader(""),
CommandFunc: func(r *remote.Cmd) error {
r.SetExitStatus(1, &remote.ExitError{
Command: `powershell.exe new-item -itemtype directory -force -path C:\ProgramData\PuppetLabs\puppet\etc`,
ExitStatus: 1,
Err: nil,
})
return nil
},
ExpectedError: true,
},
}
for k, tc := range cases {
p, err := decodeConfig(
schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, tc.Config),
)
if err != nil {
t.Fatalf("Error: %v", err)
}
c := new(communicator.MockCommunicator)
c.Commands = tc.Commands
c.Uploads = tc.Uploads
if tc.CommandFunc != nil {
c.CommandFunc = tc.CommandFunc
}
p.comm = c
p.output = new(terraform.MockUIOutput)
err = p.windowsUploadFile(tc.File, tc.Dir, tc.Filename)
if tc.ExpectedError {
if err == nil {
t.Fatalf("Expected error, but no error returned")
}
} else {
if err != nil {
t.Fatalf("Test %q failed: %v", k, err)
}
}
}
}
func TestResourceProvisioner_windowsDefaultCertname(t *testing.T) {
cases := map[string]struct {
Config map[string]interface{}
Commands map[string]bool
CommandFunc func(*remote.Cmd) error
ExpectedError bool
}{
"GetHostByName failure": {
Config: map[string]interface{}{
"server": "puppet.test.com",
"use_sudo": false,
},
CommandFunc: func(r *remote.Cmd) error {
switch r.Command {
case getHostByNameCmd:
r.SetExitStatus(1, &remote.ExitError{
Command: getHostByNameCmd,
ExitStatus: 1,
Err: nil,
})
default:
return fmt.Errorf("Command not found!")
}
return nil
},
ExpectedError: true,
},
"GetHostByName returns FQDN": {
Config: map[string]interface{}{
"server": "puppet.test.com",
"use_sudo": false,
},
CommandFunc: func(r *remote.Cmd) error {
switch r.Command {
case getHostByNameCmd:
r.Stdout.Write([]byte("example.test.com\n"))
time.Sleep(200 * time.Millisecond)
r.SetExitStatus(0, nil)
default:
return fmt.Errorf("Command not found!")
}
return nil
},
},
"GetHostByName returns hostname, DNSDomain query succeeds": {
Config: map[string]interface{}{
"server": "puppet.test.com",
"use_sudo": false,
},
CommandFunc: func(r *remote.Cmd) error {
switch r.Command {
case getHostByNameCmd:
r.Stdout.Write([]byte("example\n"))
time.Sleep(200 * time.Millisecond)
r.SetExitStatus(0, nil)
case domainQueryCmd:
r.Stdout.Write([]byte("test.com\n"))
time.Sleep(200 * time.Millisecond)
r.SetExitStatus(0, nil)
default:
return fmt.Errorf("Command not found!")
}
return nil
},
},
"GetHostByName returns hostname, DNSDomain query fails": {
Config: map[string]interface{}{
"server": "puppet.test.com",
"use_sudo": false,
},
CommandFunc: func(r *remote.Cmd) error {
switch r.Command {
case getHostByNameCmd:
r.Stdout.Write([]byte("example\n"))
time.Sleep(200 * time.Millisecond)
r.SetExitStatus(0, nil)
case domainQueryCmd:
r.SetExitStatus(1, &remote.ExitError{
Command: domainQueryCmd,
ExitStatus: 1,
Err: nil,
})
default:
return fmt.Errorf("Command not found!")
}
return nil
},
ExpectedError: true,
},
}
for k, tc := range cases {
p, err := decodeConfig(
schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, tc.Config),
)
if err != nil {
t.Fatalf("Error: %v", err)
}
c := new(communicator.MockCommunicator)
c.Commands = tc.Commands
if tc.CommandFunc != nil {
c.CommandFunc = tc.CommandFunc
}
p.comm = c
p.output = new(terraform.MockUIOutput)
_, err = p.windowsDefaultCertname()
if tc.ExpectedError {
if err == nil {
t.Fatalf("Expected error, but no error returned")
}
} else {
if err != nil {
t.Fatalf("Test %q failed: %v", k, err)
}
}
}
}
func TestResourceProvisioner_windowsInstallPuppetAgent(t *testing.T) {
cases := map[string]struct {
Config map[string]interface{}
Commands map[string]bool
CommandFunc func(*remote.Cmd) error
ExpectedError bool
}{
"Everything runs succcessfully": {
Config: map[string]interface{}{
"server": "puppet.test.com",
"use_sudo": false,
},
Commands: map[string]bool{
downloadInstallerCmd: true,
runInstallerCmd: true,
},
},
"Installer download fails": {
Config: map[string]interface{}{
"server": "puppet.test.com",
"use_sudo": true,
},
CommandFunc: func(r *remote.Cmd) error {
switch r.Command {
case downloadInstallerCmd:
r.SetExitStatus(1, &remote.ExitError{
Command: downloadInstallerCmd,
ExitStatus: 1,
Err: nil,
})
default:
return fmt.Errorf("Command not found!")
}
return nil
},
ExpectedError: true,
},
"Install script fails": {
Config: map[string]interface{}{
"server": "puppet.test.com",
"use_sudo": false,
},
CommandFunc: func(r *remote.Cmd) error {
switch r.Command {
case downloadInstallerCmd:
r.SetExitStatus(0, nil)
case runInstallerCmd:
r.SetExitStatus(1, &remote.ExitError{
Command: runInstallerCmd,
ExitStatus: 1,
Err: nil,
})
default:
return fmt.Errorf("Command not found!")
}
return nil
},
ExpectedError: true,
},
}
for k, tc := range cases {
p, err := decodeConfig(
schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, tc.Config),
)
if err != nil {
t.Fatalf("Error: %v", err)
}
c := new(communicator.MockCommunicator)
c.Commands = tc.Commands
if tc.CommandFunc != nil {
c.CommandFunc = tc.CommandFunc
}
p.comm = c
p.output = new(terraform.MockUIOutput)
err = p.windowsInstallPuppetAgent()
if tc.ExpectedError {
if err == nil {
t.Fatalf("Expected error, but no error returned")
}
} else {
if err != nil {
t.Fatalf("Test %q failed: %v", k, err)
}
}
}
}
func TestResourceProvisioner_windowsRunPuppetAgent(t *testing.T) {
cases := map[string]struct {
Config map[string]interface{}
Commands map[string]bool
CommandFunc func(*remote.Cmd) error
ExpectedError bool
}{
"When puppet returns 0": {
Config: map[string]interface{}{
"server": "puppet.test.com",
"use_sudo": false,
},
Commands: map[string]bool{
runPuppetCmd: true,
},
},
"When puppet returns 2 (changes applied without error)": {
Config: map[string]interface{}{
"server": "puppet.test.com",
"use_sudo": false,
},
CommandFunc: func(r *remote.Cmd) error {
r.SetExitStatus(2, &remote.ExitError{
Command: runPuppetCmd,
ExitStatus: 2,
Err: nil,
})
return nil
},
},
"When puppet returns something not 0 or 2": {
Config: map[string]interface{}{
"server": "puppet.test.com",
"use_sudo": false,
},
CommandFunc: func(r *remote.Cmd) error {
r.SetExitStatus(1, &remote.ExitError{
Command: runPuppetCmd,
ExitStatus: 1,
Err: nil,
})
return nil
},
ExpectedError: true,
},
}
for k, tc := range cases {
p, err := decodeConfig(
schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, tc.Config),
)
if err != nil {
t.Fatalf("Error: %v", err)
}
c := new(communicator.MockCommunicator)
c.Commands = tc.Commands
if tc.CommandFunc != nil {
c.CommandFunc = tc.CommandFunc
}
p.comm = c
p.output = new(terraform.MockUIOutput)
err = p.windowsRunPuppetAgent()
if tc.ExpectedError {
if err == nil {
t.Fatalf("Expected error, but no error returned")
}
} else {
if err != nil {
t.Fatalf("Test %q failed: %v", k, err)
}
}
}
}