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  }