github.phpd.cn/hashicorp/packer@v1.3.2/provisioner/puppet-masterless/provisioner_test.go (about) 1 package puppetmasterless 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "log" 7 "os" 8 "path/filepath" 9 "strings" 10 "testing" 11 12 "github.com/hashicorp/packer/packer" 13 "github.com/hashicorp/packer/template/interpolate" 14 "github.com/stretchr/testify/assert" 15 ) 16 17 func testConfig() (config map[string]interface{}, tf *os.File) { 18 tf, err := ioutil.TempFile("", "packer") 19 if err != nil { 20 panic(err) 21 } 22 23 config = map[string]interface{}{ 24 "manifest_file": tf.Name(), 25 } 26 27 return config, tf 28 } 29 30 func TestProvisioner_Impl(t *testing.T) { 31 var raw interface{} 32 raw = &Provisioner{} 33 if _, ok := raw.(packer.Provisioner); !ok { 34 t.Fatalf("must be a Provisioner") 35 } 36 } 37 38 func TestGuestOSConfig_empty_unix(t *testing.T) { 39 config, tempfile := testConfig() 40 defer os.Remove(tempfile.Name()) 41 defer tempfile.Close() 42 43 p := new(Provisioner) 44 err := p.Prepare(config) 45 if err != nil { 46 t.Fatalf("err: %s", err) 47 } 48 // Execute Puppet 49 p.config.ctx.Data = &ExecuteTemplate{ 50 ManifestFile: "/r/m/f", 51 PuppetBinDir: p.config.PuppetBinDir, 52 Sudo: !p.config.PreventSudo, 53 WorkingDir: p.config.WorkingDir, 54 } 55 log.Println(p.config.ExecuteCommand) 56 command, err := interpolate.Render(p.config.ExecuteCommand, &p.config.ctx) 57 if err != nil { 58 t.Fatalf("err: %s", err) 59 } 60 61 expected := "cd /tmp/packer-puppet-masterless && " + 62 "sudo -E puppet apply --detailed-exitcodes /r/m/f" 63 assert.Equal(t, expected, command) 64 } 65 66 func TestGuestOSConfig_full_unix(t *testing.T) { 67 config, tempfile := testConfig() 68 defer os.Remove(tempfile.Name()) 69 defer tempfile.Close() 70 71 p := new(Provisioner) 72 err := p.Prepare(config) 73 if err != nil { 74 t.Fatalf("err: %s", err) 75 } 76 77 facterVars := []string{ 78 fmt.Sprintf(p.guestOSTypeConfig.facterVarsFmt, "lhs", "rhs"), 79 fmt.Sprintf(p.guestOSTypeConfig.facterVarsFmt, "foo", "bar"), 80 } 81 modulePaths := []string{"/m/p", "/a/b"} 82 // Execute Puppet 83 p.config.ctx.Data = &ExecuteTemplate{ 84 FacterVars: strings.Join(facterVars, p.guestOSTypeConfig.facterVarsJoiner), 85 HieraConfigPath: "/h/c/p", 86 ManifestDir: "/r/m/d", 87 ManifestFile: "/r/m/f", 88 ModulePath: strings.Join(modulePaths, p.guestOSTypeConfig.modulePathJoiner), 89 PuppetBinDir: p.config.PuppetBinDir, 90 Sudo: !p.config.PreventSudo, 91 WorkingDir: p.config.WorkingDir, 92 ExtraArguments: strings.Join(p.config.ExtraArguments, " "), 93 } 94 command, err := interpolate.Render(p.config.ExecuteCommand, &p.config.ctx) 95 if err != nil { 96 t.Fatalf("err: %s", err) 97 } 98 99 expected := "cd /tmp/packer-puppet-masterless && FACTER_lhs='rhs' FACTER_foo='bar' " + 100 "sudo -E puppet apply " + 101 "--detailed-exitcodes --modulepath='/m/p:/a/b' --hiera_config='/h/c/p' " + 102 "--manifestdir='/r/m/d' /r/m/f" 103 assert.Equal(t, expected, command) 104 } 105 106 func TestGuestOSConfig_empty_windows(t *testing.T) { 107 config, tempfile := testConfig() 108 defer os.Remove(tempfile.Name()) 109 defer tempfile.Close() 110 111 config["guest_os_type"] = "windows" 112 p := new(Provisioner) 113 err := p.Prepare(config) 114 if err != nil { 115 t.Fatalf("err: %s", err) 116 } 117 // Execute Puppet 118 p.config.ctx.Data = &ExecuteTemplate{ 119 ManifestFile: "/r/m/f", 120 PuppetBinDir: p.config.PuppetBinDir, 121 Sudo: !p.config.PreventSudo, 122 WorkingDir: p.config.WorkingDir, 123 } 124 log.Println(p.config.ExecuteCommand) 125 command, err := interpolate.Render(p.config.ExecuteCommand, &p.config.ctx) 126 if err != nil { 127 t.Fatalf("err: %s", err) 128 } 129 130 expected := "cd " + filepath.ToSlash(os.Getenv("SYSTEMROOT")) + "/Temp/packer-puppet-masterless && puppet apply --detailed-exitcodes /r/m/f" 131 assert.Equal(t, expected, command) 132 } 133 134 func TestGuestOSConfig_full_windows(t *testing.T) { 135 config, tempfile := testConfig() 136 defer os.Remove(tempfile.Name()) 137 defer tempfile.Close() 138 139 config["guest_os_type"] = "windows" 140 p := new(Provisioner) 141 err := p.Prepare(config) 142 if err != nil { 143 t.Fatalf("err: %s", err) 144 } 145 146 facterVars := []string{ 147 fmt.Sprintf(p.guestOSTypeConfig.facterVarsFmt, "lhs", "rhs"), 148 fmt.Sprintf(p.guestOSTypeConfig.facterVarsFmt, "foo", "bar"), 149 } 150 modulePaths := []string{"/m/p", "/a/b"} 151 // Execute Puppet 152 p.config.ctx.Data = &ExecuteTemplate{ 153 FacterVars: strings.Join(facterVars, p.guestOSTypeConfig.facterVarsJoiner), 154 HieraConfigPath: "/h/c/p", 155 ManifestDir: "/r/m/d", 156 ManifestFile: "/r/m/f", 157 ModulePath: strings.Join(modulePaths, p.guestOSTypeConfig.modulePathJoiner), 158 PuppetBinDir: p.config.PuppetBinDir, 159 Sudo: !p.config.PreventSudo, 160 WorkingDir: p.config.WorkingDir, 161 ExtraArguments: strings.Join(p.config.ExtraArguments, " "), 162 } 163 command, err := interpolate.Render(p.config.ExecuteCommand, &p.config.ctx) 164 if err != nil { 165 t.Fatalf("err: %s", err) 166 } 167 168 expected := "cd " + filepath.ToSlash(os.Getenv("SYSTEMROOT")) + "/Temp/packer-puppet-masterless && " + 169 "SET \"FACTER_lhs=rhs\" & SET \"FACTER_foo=bar\" && " + 170 "puppet apply --detailed-exitcodes --modulepath='/m/p;/a/b' --hiera_config='/h/c/p' " + 171 "--manifestdir='/r/m/d' /r/m/f" 172 assert.Equal(t, expected, command) 173 } 174 175 func TestProvisionerPrepare_puppetBinDir(t *testing.T) { 176 config, tempfile := testConfig() 177 defer os.Remove(tempfile.Name()) 178 defer tempfile.Close() 179 180 delete(config, "puppet_bin_dir") 181 p := new(Provisioner) 182 err := p.Prepare(config) 183 if err != nil { 184 t.Fatalf("err: %s", err) 185 } 186 187 // Test with a good one 188 tf, err := ioutil.TempFile("", "packer") 189 if err != nil { 190 t.Fatalf("error tempfile: %s", err) 191 } 192 defer os.Remove(tf.Name()) 193 194 config["puppet_bin_dir"] = tf.Name() 195 p = new(Provisioner) 196 err = p.Prepare(config) 197 if err != nil { 198 t.Fatalf("err: %s", err) 199 } 200 } 201 202 func TestProvisionerPrepare_hieraConfigPath(t *testing.T) { 203 config, tempfile := testConfig() 204 defer os.Remove(tempfile.Name()) 205 defer tempfile.Close() 206 207 delete(config, "hiera_config_path") 208 p := new(Provisioner) 209 err := p.Prepare(config) 210 if err != nil { 211 t.Fatalf("err: %s", err) 212 } 213 214 // Test with a good one 215 tf, err := ioutil.TempFile("", "packer") 216 if err != nil { 217 t.Fatalf("error tempfile: %s", err) 218 } 219 defer os.Remove(tf.Name()) 220 221 config["hiera_config_path"] = tf.Name() 222 p = new(Provisioner) 223 err = p.Prepare(config) 224 if err != nil { 225 t.Fatalf("err: %s", err) 226 } 227 } 228 229 func TestProvisionerPrepare_manifestFile(t *testing.T) { 230 config, tempfile := testConfig() 231 defer os.Remove(tempfile.Name()) 232 defer tempfile.Close() 233 234 delete(config, "manifest_file") 235 p := new(Provisioner) 236 err := p.Prepare(config) 237 if err == nil { 238 t.Fatal("should be an error") 239 } 240 241 // Test with a good one 242 tf, err := ioutil.TempFile("", "packer") 243 if err != nil { 244 t.Fatalf("error tempfile: %s", err) 245 } 246 defer os.Remove(tf.Name()) 247 248 config["manifest_file"] = tf.Name() 249 p = new(Provisioner) 250 err = p.Prepare(config) 251 if err != nil { 252 t.Fatalf("err: %s", err) 253 } 254 } 255 256 func TestProvisionerPrepare_manifestDir(t *testing.T) { 257 config, tempfile := testConfig() 258 defer os.Remove(tempfile.Name()) 259 defer tempfile.Close() 260 261 delete(config, "manifestdir") 262 p := new(Provisioner) 263 err := p.Prepare(config) 264 if err != nil { 265 t.Fatalf("err: %s", err) 266 } 267 268 // Test with a good one 269 td, err := ioutil.TempDir("", "packer") 270 if err != nil { 271 t.Fatalf("error: %s", err) 272 } 273 defer os.RemoveAll(td) 274 275 config["manifest_dir"] = td 276 p = new(Provisioner) 277 err = p.Prepare(config) 278 if err != nil { 279 t.Fatalf("err: %s", err) 280 } 281 } 282 283 func TestProvisionerPrepare_modulePaths(t *testing.T) { 284 config, tempfile := testConfig() 285 defer os.Remove(tempfile.Name()) 286 defer tempfile.Close() 287 288 delete(config, "module_paths") 289 p := new(Provisioner) 290 err := p.Prepare(config) 291 if err != nil { 292 t.Fatalf("err: %s", err) 293 } 294 295 // Test with bad paths 296 config["module_paths"] = []string{"i-should-not-exist"} 297 p = new(Provisioner) 298 err = p.Prepare(config) 299 if err == nil { 300 t.Fatal("should be an error") 301 } 302 303 // Test with a good one 304 td, err := ioutil.TempDir("", "packer") 305 if err != nil { 306 t.Fatalf("error: %s", err) 307 } 308 defer os.RemoveAll(td) 309 310 config["module_paths"] = []string{td} 311 p = new(Provisioner) 312 err = p.Prepare(config) 313 if err != nil { 314 t.Fatalf("err: %s", err) 315 } 316 } 317 318 func TestProvisionerPrepare_facterFacts(t *testing.T) { 319 config, tempfile := testConfig() 320 defer os.Remove(tempfile.Name()) 321 defer tempfile.Close() 322 323 delete(config, "facter") 324 p := new(Provisioner) 325 err := p.Prepare(config) 326 if err != nil { 327 t.Fatalf("err: %s", err) 328 } 329 330 // Test with malformed fact 331 config["facter"] = "fact=stringified" 332 p = new(Provisioner) 333 err = p.Prepare(config) 334 if err == nil { 335 t.Fatal("should be an error") 336 } 337 338 // Test with a good one 339 td, err := ioutil.TempDir("", "packer") 340 if err != nil { 341 t.Fatalf("error: %s", err) 342 } 343 defer os.RemoveAll(td) 344 345 facts := make(map[string]string) 346 facts["fact_name"] = "fact_value" 347 config["facter"] = facts 348 349 p = new(Provisioner) 350 err = p.Prepare(config) 351 if err != nil { 352 t.Fatalf("err: %s", err) 353 } 354 355 // Make sure the default facts are present 356 delete(config, "facter") 357 p = new(Provisioner) 358 err = p.Prepare(config) 359 if err != nil { 360 t.Fatalf("err: %s", err) 361 } 362 if p.config.Facter == nil { 363 t.Fatalf("err: Default facts are not set in the Puppet provisioner!") 364 } 365 366 if _, ok := p.config.Facter["packer_build_name"]; !ok { 367 t.Fatalf("err: packer_build_name fact not set in the Puppet provisioner!") 368 } 369 370 if _, ok := p.config.Facter["packer_builder_type"]; !ok { 371 t.Fatalf("err: packer_builder_type fact not set in the Puppet provisioner!") 372 } 373 } 374 375 func TestProvisionerPrepare_extraArguments(t *testing.T) { 376 config, tempfile := testConfig() 377 defer os.Remove(tempfile.Name()) 378 defer tempfile.Close() 379 380 // Test with missing parameter 381 delete(config, "extra_arguments") 382 p := new(Provisioner) 383 err := p.Prepare(config) 384 if err != nil { 385 t.Fatalf("err: %s", err) 386 } 387 388 // Test with malformed value 389 config["extra_arguments"] = "{{}}" 390 p = new(Provisioner) 391 err = p.Prepare(config) 392 if err == nil { 393 t.Fatal("should be an error") 394 } 395 396 // Test with valid values 397 config["extra_arguments"] = []string{ 398 "arg", 399 } 400 401 p = new(Provisioner) 402 err = p.Prepare(config) 403 if err != nil { 404 t.Fatalf("err: %s", err) 405 } 406 } 407 408 func TestProvisionerPrepare_stagingDir(t *testing.T) { 409 config, tempfile := testConfig() 410 defer os.Remove(tempfile.Name()) 411 defer tempfile.Close() 412 413 delete(config, "staging_directory") 414 p := new(Provisioner) 415 err := p.Prepare(config) 416 if err != nil { 417 t.Fatalf("err: %s", err) 418 } 419 420 // Make sure the default staging directory is correct 421 if p.config.StagingDir != "/tmp/packer-puppet-masterless" { 422 t.Fatalf("err: Default staging_directory is not set in the Puppet provisioner!") 423 } 424 425 // Make sure default staging directory can be overridden 426 config["staging_directory"] = "/tmp/override" 427 p = new(Provisioner) 428 err = p.Prepare(config) 429 if err != nil { 430 t.Fatalf("err: %s", err) 431 } 432 433 if p.config.StagingDir != "/tmp/override" { 434 t.Fatalf("err: Overridden staging_directory is not set correctly in the Puppet provisioner!") 435 } 436 } 437 438 func TestProvisionerPrepare_workingDir(t *testing.T) { 439 config, tempfile := testConfig() 440 defer os.Remove(tempfile.Name()) 441 defer tempfile.Close() 442 443 delete(config, "working_directory") 444 p := new(Provisioner) 445 err := p.Prepare(config) 446 if err != nil { 447 t.Fatalf("err: %s", err) 448 } 449 450 // Make sure default working dir and staging dir are the same 451 if p.config.WorkingDir != p.config.StagingDir { 452 t.Fatalf("err: Default working_directory is not set to the same value as default staging_directory in the Puppet provisioner!") 453 } 454 455 // Make sure the default working directory is correct 456 if p.config.WorkingDir != "/tmp/packer-puppet-masterless" { 457 t.Fatalf("err: Default working_directory is not set in the Puppet provisioner!") 458 } 459 460 // Make sure default working directory can be overridden 461 config["working_directory"] = "/tmp/override" 462 p = new(Provisioner) 463 err = p.Prepare(config) 464 if err != nil { 465 t.Fatalf("err: %s", err) 466 } 467 468 if p.config.WorkingDir != "/tmp/override" { 469 t.Fatalf("err: Overridden working_directory is not set correctly in the Puppet provisioner!") 470 } 471 } 472 473 func TestProvisionerProvision_extraArguments(t *testing.T) { 474 config, tempfile := testConfig() 475 defer os.Remove(tempfile.Name()) 476 defer tempfile.Close() 477 478 ui := &packer.MachineReadableUi{ 479 Writer: ioutil.Discard, 480 } 481 comm := new(packer.MockCommunicator) 482 483 extraArguments := []string{ 484 "--some-arg=yup", 485 "--some-other-arg", 486 } 487 config["extra_arguments"] = extraArguments 488 489 // Test with valid values 490 p := new(Provisioner) 491 err := p.Prepare(config) 492 if err != nil { 493 t.Fatalf("err: %s", err) 494 } 495 496 err = p.Provision(ui, comm) 497 if err != nil { 498 t.Fatalf("err: %s", err) 499 } 500 501 expectedArgs := strings.Join(extraArguments, " ") 502 503 if !strings.Contains(comm.StartCmd.Command, expectedArgs) { 504 t.Fatalf("Command %q doesn't contain the expected arguments %q", comm.StartCmd.Command, expectedArgs) 505 } 506 507 // Test with missing parameter 508 delete(config, "extra_arguments") 509 510 p = new(Provisioner) 511 err = p.Prepare(config) 512 if err != nil { 513 t.Fatalf("err: %s", err) 514 } 515 516 err = p.Provision(ui, comm) 517 if err != nil { 518 t.Fatalf("err: %s", err) 519 } 520 521 // Check the expected `extra_arguments` position for an empty value 522 splitCommand := strings.Split(comm.StartCmd.Command, " ") 523 if "" == splitCommand[len(splitCommand)-2] { 524 t.Fatalf("Command %q contains an extra-space which may cause arg parsing issues", comm.StartCmd.Command) 525 } 526 }