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  }