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