github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/builtin/provisioners/puppet/windows_provisioner_test.go (about) 1 package puppet 2 3 import ( 4 "fmt" 5 "io" 6 "strings" 7 "testing" 8 "time" 9 10 "github.com/hashicorp/terraform/communicator" 11 "github.com/hashicorp/terraform/communicator/remote" 12 "github.com/hashicorp/terraform/helper/schema" 13 "github.com/hashicorp/terraform/terraform" 14 ) 15 16 const ( 17 getHostByNameCmd = `powershell -Command "& {([System.Net.Dns]::GetHostByName(($env:computerName))).Hostname}"` 18 domainQueryCmd = `powershell -Command "& {(Get-WmiObject -Query 'select DNSDomain from Win32_NetworkAdapterConfiguration where IPEnabled = True').DNSDomain}"` 19 downloadInstallerCmd = `powershell -Command "& {[Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}; (New-Object System.Net.WebClient).DownloadFile('https://puppet.test.com:8140/packages/current/install.ps1', 'install.ps1')}"` 20 runInstallerCmd = `powershell -Command "& .\install.ps1 -PuppetServiceEnsure stopped"` 21 runPuppetCmd = "puppet agent --test --server puppet.test.com --environment production" 22 ) 23 24 func TestResourceProvisioner_windowsUploadFile(t *testing.T) { 25 cases := map[string]struct { 26 Config map[string]interface{} 27 Commands map[string]bool 28 CommandFunc func(*remote.Cmd) error 29 ExpectedError bool 30 Uploads map[string]string 31 File io.Reader 32 Dir string 33 Filename string 34 }{ 35 "Successful upload": { 36 Config: map[string]interface{}{ 37 "server": "puppet.test.com", 38 "use_sudo": false, 39 }, 40 Commands: map[string]bool{ 41 `powershell.exe new-item -itemtype directory -force -path C:\ProgramData\PuppetLabs\puppet\etc`: true, 42 }, 43 Uploads: map[string]string{ 44 `C:\ProgramData\PuppetLabs\puppet\etc\csr_attributes.yaml`: "", 45 }, 46 Dir: `C:\ProgramData\PuppetLabs\puppet\etc`, 47 Filename: "csr_attributes.yaml", 48 File: strings.NewReader(""), 49 }, 50 "Failure when creating the directory": { 51 Config: map[string]interface{}{ 52 "server": "puppet.test.com", 53 "use_sudo": false, 54 }, 55 Commands: map[string]bool{ 56 `powershell.exe new-item -itemtype directory -force -path C:\ProgramData\PuppetLabs\puppet\etc`: true, 57 }, 58 Dir: `C:\ProgramData\PuppetLabs\puppet\etc`, 59 Filename: "csr_attributes.yaml", 60 File: strings.NewReader(""), 61 CommandFunc: func(r *remote.Cmd) error { 62 r.SetExitStatus(1, &remote.ExitError{ 63 Command: `powershell.exe new-item -itemtype directory -force -path C:\ProgramData\PuppetLabs\puppet\etc`, 64 ExitStatus: 1, 65 Err: nil, 66 }) 67 return nil 68 }, 69 ExpectedError: true, 70 }, 71 } 72 73 for k, tc := range cases { 74 p, err := decodeConfig( 75 schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, tc.Config), 76 ) 77 if err != nil { 78 t.Fatalf("Error: %v", err) 79 } 80 81 c := new(communicator.MockCommunicator) 82 c.Commands = tc.Commands 83 c.Uploads = tc.Uploads 84 if tc.CommandFunc != nil { 85 c.CommandFunc = tc.CommandFunc 86 } 87 p.comm = c 88 p.output = new(terraform.MockUIOutput) 89 90 err = p.windowsUploadFile(tc.File, tc.Dir, tc.Filename) 91 if tc.ExpectedError { 92 if err == nil { 93 t.Fatalf("Expected error, but no error returned") 94 } 95 } else { 96 if err != nil { 97 t.Fatalf("Test %q failed: %v", k, err) 98 } 99 } 100 } 101 } 102 103 func TestResourceProvisioner_windowsDefaultCertname(t *testing.T) { 104 cases := map[string]struct { 105 Config map[string]interface{} 106 Commands map[string]bool 107 CommandFunc func(*remote.Cmd) error 108 ExpectedError bool 109 }{ 110 "GetHostByName failure": { 111 Config: map[string]interface{}{ 112 "server": "puppet.test.com", 113 "use_sudo": false, 114 }, 115 CommandFunc: func(r *remote.Cmd) error { 116 switch r.Command { 117 case getHostByNameCmd: 118 r.SetExitStatus(1, &remote.ExitError{ 119 Command: getHostByNameCmd, 120 ExitStatus: 1, 121 Err: nil, 122 }) 123 default: 124 return fmt.Errorf("Command not found!") 125 } 126 127 return nil 128 }, 129 ExpectedError: true, 130 }, 131 "GetHostByName returns FQDN": { 132 Config: map[string]interface{}{ 133 "server": "puppet.test.com", 134 "use_sudo": false, 135 }, 136 CommandFunc: func(r *remote.Cmd) error { 137 switch r.Command { 138 case getHostByNameCmd: 139 r.Stdout.Write([]byte("example.test.com\n")) 140 time.Sleep(200 * time.Millisecond) 141 r.SetExitStatus(0, nil) 142 default: 143 return fmt.Errorf("Command not found!") 144 } 145 146 return nil 147 }, 148 }, 149 "GetHostByName returns hostname, DNSDomain query succeeds": { 150 Config: map[string]interface{}{ 151 "server": "puppet.test.com", 152 "use_sudo": false, 153 }, 154 CommandFunc: func(r *remote.Cmd) error { 155 switch r.Command { 156 case getHostByNameCmd: 157 r.Stdout.Write([]byte("example\n")) 158 time.Sleep(200 * time.Millisecond) 159 r.SetExitStatus(0, nil) 160 case domainQueryCmd: 161 r.Stdout.Write([]byte("test.com\n")) 162 time.Sleep(200 * time.Millisecond) 163 r.SetExitStatus(0, nil) 164 default: 165 return fmt.Errorf("Command not found!") 166 } 167 168 return nil 169 }, 170 }, 171 "GetHostByName returns hostname, DNSDomain query fails": { 172 Config: map[string]interface{}{ 173 "server": "puppet.test.com", 174 "use_sudo": false, 175 }, 176 CommandFunc: func(r *remote.Cmd) error { 177 switch r.Command { 178 case getHostByNameCmd: 179 r.Stdout.Write([]byte("example\n")) 180 time.Sleep(200 * time.Millisecond) 181 r.SetExitStatus(0, nil) 182 case domainQueryCmd: 183 r.SetExitStatus(1, &remote.ExitError{ 184 Command: domainQueryCmd, 185 ExitStatus: 1, 186 Err: nil, 187 }) 188 default: 189 return fmt.Errorf("Command not found!") 190 } 191 192 return nil 193 }, 194 ExpectedError: true, 195 }, 196 } 197 198 for k, tc := range cases { 199 p, err := decodeConfig( 200 schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, tc.Config), 201 ) 202 if err != nil { 203 t.Fatalf("Error: %v", err) 204 } 205 206 c := new(communicator.MockCommunicator) 207 c.Commands = tc.Commands 208 if tc.CommandFunc != nil { 209 c.CommandFunc = tc.CommandFunc 210 } 211 p.comm = c 212 p.output = new(terraform.MockUIOutput) 213 214 _, err = p.windowsDefaultCertname() 215 if tc.ExpectedError { 216 if err == nil { 217 t.Fatalf("Expected error, but no error returned") 218 } 219 } else { 220 if err != nil { 221 t.Fatalf("Test %q failed: %v", k, err) 222 } 223 } 224 } 225 } 226 227 func TestResourceProvisioner_windowsInstallPuppetAgent(t *testing.T) { 228 cases := map[string]struct { 229 Config map[string]interface{} 230 Commands map[string]bool 231 CommandFunc func(*remote.Cmd) error 232 ExpectedError bool 233 }{ 234 "Everything runs succcessfully": { 235 Config: map[string]interface{}{ 236 "server": "puppet.test.com", 237 "use_sudo": false, 238 }, 239 Commands: map[string]bool{ 240 downloadInstallerCmd: true, 241 runInstallerCmd: true, 242 }, 243 }, 244 "Installer download fails": { 245 Config: map[string]interface{}{ 246 "server": "puppet.test.com", 247 "use_sudo": true, 248 }, 249 CommandFunc: func(r *remote.Cmd) error { 250 switch r.Command { 251 case downloadInstallerCmd: 252 r.SetExitStatus(1, &remote.ExitError{ 253 Command: downloadInstallerCmd, 254 ExitStatus: 1, 255 Err: nil, 256 }) 257 default: 258 return fmt.Errorf("Command not found!") 259 } 260 261 return nil 262 }, 263 ExpectedError: true, 264 }, 265 "Install script fails": { 266 Config: map[string]interface{}{ 267 "server": "puppet.test.com", 268 "use_sudo": false, 269 }, 270 CommandFunc: func(r *remote.Cmd) error { 271 switch r.Command { 272 case downloadInstallerCmd: 273 r.SetExitStatus(0, nil) 274 case runInstallerCmd: 275 r.SetExitStatus(1, &remote.ExitError{ 276 Command: runInstallerCmd, 277 ExitStatus: 1, 278 Err: nil, 279 }) 280 default: 281 return fmt.Errorf("Command not found!") 282 } 283 284 return nil 285 }, 286 ExpectedError: true, 287 }, 288 } 289 290 for k, tc := range cases { 291 p, err := decodeConfig( 292 schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, tc.Config), 293 ) 294 if err != nil { 295 t.Fatalf("Error: %v", err) 296 } 297 298 c := new(communicator.MockCommunicator) 299 c.Commands = tc.Commands 300 if tc.CommandFunc != nil { 301 c.CommandFunc = tc.CommandFunc 302 } 303 p.comm = c 304 p.output = new(terraform.MockUIOutput) 305 306 err = p.windowsInstallPuppetAgent() 307 if tc.ExpectedError { 308 if err == nil { 309 t.Fatalf("Expected error, but no error returned") 310 } 311 } else { 312 if err != nil { 313 t.Fatalf("Test %q failed: %v", k, err) 314 } 315 } 316 } 317 } 318 319 func TestResourceProvisioner_windowsRunPuppetAgent(t *testing.T) { 320 cases := map[string]struct { 321 Config map[string]interface{} 322 Commands map[string]bool 323 CommandFunc func(*remote.Cmd) error 324 ExpectedError bool 325 }{ 326 "When puppet returns 0": { 327 Config: map[string]interface{}{ 328 "server": "puppet.test.com", 329 "use_sudo": false, 330 }, 331 Commands: map[string]bool{ 332 runPuppetCmd: true, 333 }, 334 }, 335 "When puppet returns 2 (changes applied without error)": { 336 Config: map[string]interface{}{ 337 "server": "puppet.test.com", 338 "use_sudo": false, 339 }, 340 CommandFunc: func(r *remote.Cmd) error { 341 r.SetExitStatus(2, &remote.ExitError{ 342 Command: runPuppetCmd, 343 ExitStatus: 2, 344 Err: nil, 345 }) 346 return nil 347 }, 348 }, 349 "When puppet returns something not 0 or 2": { 350 Config: map[string]interface{}{ 351 "server": "puppet.test.com", 352 "use_sudo": false, 353 }, 354 CommandFunc: func(r *remote.Cmd) error { 355 r.SetExitStatus(1, &remote.ExitError{ 356 Command: runPuppetCmd, 357 ExitStatus: 1, 358 Err: nil, 359 }) 360 return nil 361 }, 362 ExpectedError: true, 363 }, 364 } 365 366 for k, tc := range cases { 367 p, err := decodeConfig( 368 schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, tc.Config), 369 ) 370 if err != nil { 371 t.Fatalf("Error: %v", err) 372 } 373 374 c := new(communicator.MockCommunicator) 375 c.Commands = tc.Commands 376 if tc.CommandFunc != nil { 377 c.CommandFunc = tc.CommandFunc 378 } 379 p.comm = c 380 p.output = new(terraform.MockUIOutput) 381 382 err = p.windowsRunPuppetAgent() 383 if tc.ExpectedError { 384 if err == nil { 385 t.Fatalf("Expected error, but no error returned") 386 } 387 } else { 388 if err != nil { 389 t.Fatalf("Test %q failed: %v", k, err) 390 } 391 } 392 } 393 }