github.com/cloudfoundry-incubator/stembuild@v0.0.0-20211223202937-5b61d62226c6/integration/construct/construct_suite_test.go (about)

     1  package construct_test
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"runtime"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/cloudfoundry-incubator/stembuild/remotemanager"
    14  
    15  	"github.com/cloudfoundry-incubator/stembuild/test/helpers"
    16  
    17  	"github.com/concourse/pool-resource/out"
    18  
    19  	. "github.com/onsi/ginkgo"
    20  	. "github.com/onsi/gomega"
    21  
    22  	"github.com/vmware/govmomi/govc/cli"
    23  	_ "github.com/vmware/govmomi/govc/device"
    24  	_ "github.com/vmware/govmomi/govc/importx"
    25  	_ "github.com/vmware/govmomi/govc/vm"
    26  	_ "github.com/vmware/govmomi/govc/vm/guest"
    27  	_ "github.com/vmware/govmomi/govc/vm/snapshot"
    28  
    29  	"syscall"
    30  )
    31  
    32  func TestConstruct(t *testing.T) {
    33  	RegisterFailHandler(Fail)
    34  	RunSpecs(t, "Construct Suite")
    35  }
    36  
    37  const (
    38  	VMNameVariable                    = "VM_NAME"
    39  	VMUsernameVariable                = "VM_USERNAME"
    40  	VMPasswordVariable                = "VM_PASSWORD"
    41  	TargetVmIPVariable                = "TARGET_VM_IP"
    42  	SkipCleanupVariable               = "SKIP_CLEANUP"
    43  	vcenterFolderVariable             = "VM_FOLDER"
    44  	vcenterAdminCredentialUrlVariable = "VCENTER_ADMIN_CREDENTIAL_URL"
    45  	vcenterBaseURLVariable            = "VCENTER_BASE_URL"
    46  	VcenterCACert                     = "VCENTER_CA_CERT"
    47  	vcenterStembuildUsernameVariable  = "VCENTER_USERNAME"
    48  	vcenterStembuildPasswordVariable  = "VCENTER_PASSWORD"
    49  	StembuildVersionVariable          = "STEMBUILD_VERSION"
    50  	VmSnapshotName                    = "integration-test-snapshot"
    51  	LoggedInVmIpVariable              = "LOGOUT_INTEGRATION_TEST_VM_IP"
    52  	LoggedInVmIpathVariable           = "LOGOUT_INTEGRATION_TEST_VM_INVENTORY_PATH"
    53  	LoggedInVmSnapshotName            = "logged-in-winrm-enabled"
    54  	powershell                        = "C:\\Windows\\System32\\WindowsPowerShell\\V1.0\\powershell.exe"
    55  )
    56  
    57  var (
    58  	conf                      config
    59  	tmpDir                    string
    60  	lockParentDir             string
    61  	lockPool                  out.LockPool
    62  	lockDir                   string
    63  	stembuildExecutable       string
    64  	vcenterAdminCredentialUrl string
    65  	pathToCACert              string
    66  )
    67  
    68  type config struct {
    69  	TargetIP           string
    70  	NetworkGateway     string
    71  	SubnetMask         string
    72  	VMUsername         string
    73  	VMPassword         string
    74  	VMName             string
    75  	VMNetwork          string
    76  	VCenterURL         string
    77  	VCenterCACert      string
    78  	VCenterUsername    string
    79  	VCenterPassword    string
    80  	VMInventoryPath    string
    81  	LoggedInVMIP       string
    82  	LoggedInVMIpath    string
    83  	LoggedInVMSnapshot string
    84  }
    85  
    86  var _ = SynchronizedBeforeSuite(func() []byte {
    87  	var err error
    88  
    89  	stembuildVersion := envMustExist(StembuildVersionVariable)
    90  	stembuildExecutable, err = helpers.BuildStembuild(stembuildVersion)
    91  	Expect(err).NotTo(HaveOccurred())
    92  
    93  	vmUsername := envMustExist(VMUsernameVariable)
    94  	vmPassword := envMustExist(VMPasswordVariable)
    95  	targetVMIP := envMustExist(TargetVmIPVariable)
    96  	vmName := envMustExist(VMNameVariable)
    97  
    98  	loggedInVmIp := envMustExist(LoggedInVmIpVariable)
    99  	loggedInVmInventoryPath := envMustExist(LoggedInVmIpathVariable)
   100  	loggedInVmSnapshot := LoggedInVmSnapshotName
   101  	vCenterUrl := envMustExist(vcenterBaseURLVariable)
   102  	vcenterFolder := envMustExist(vcenterFolderVariable)
   103  	vmInventoryPath := strings.Join([]string{vcenterFolder, vmName}, "/")
   104  	vcenterAdminCredentialUrl = envMustExist(vcenterAdminCredentialUrlVariable)
   105  
   106  	vCenterStembuildUser := envMustExist(vcenterStembuildUsernameVariable)
   107  	vCenterStembuildPassword := envMustExist(vcenterStembuildPasswordVariable)
   108  
   109  	rawCA := envMustExist(VcenterCACert)
   110  	t, err := ioutil.TempFile("", "ca-cert")
   111  	Expect(err).ToNot(HaveOccurred())
   112  	pathToCACert = t.Name()
   113  	Expect(t.Close()).To(Succeed())
   114  	err = ioutil.WriteFile(pathToCACert, []byte(rawCA), 0666)
   115  	Expect(err).ToNot(HaveOccurred())
   116  
   117  	wd, err := os.Getwd()
   118  	Expect(err).NotTo(HaveOccurred())
   119  	tmpDir, err = ioutil.TempDir(wd, "construct-integration")
   120  	Expect(err).NotTo(HaveOccurred())
   121  
   122  	err = os.MkdirAll(tmpDir, 0755)
   123  	Expect(err).NotTo(HaveOccurred())
   124  
   125  	conf = config{
   126  		TargetIP:           targetVMIP,
   127  		VMUsername:         vmUsername,
   128  		VMPassword:         vmPassword,
   129  		VCenterCACert:      pathToCACert,
   130  		VCenterURL:         vCenterUrl,
   131  		VCenterUsername:    vCenterStembuildUser,
   132  		VCenterPassword:    vCenterStembuildPassword,
   133  		LoggedInVMIP:       loggedInVmIp,
   134  		LoggedInVMIpath:    loggedInVmInventoryPath,
   135  		LoggedInVMSnapshot: loggedInVmSnapshot,
   136  		VMName:             vmName,
   137  		VMInventoryPath:    vmInventoryPath,
   138  	}
   139  
   140  	enableWinRM()
   141  	powerOnVM()
   142  	createVMSnapshot(VmSnapshotName)
   143  
   144  	return nil
   145  }, func(_ []byte) {
   146  })
   147  
   148  var _ = BeforeEach(func() {
   149  	revertSnapshot(conf.VMInventoryPath, VmSnapshotName)
   150  	waitForVmToBeReady(conf.TargetIP, conf.VMUsername, conf.VMPassword)
   151  })
   152  
   153  var _ = SynchronizedAfterSuite(func() {
   154  	skipCleanup := strings.ToUpper(os.Getenv(SkipCleanupVariable))
   155  
   156  	if skipCleanup != "TRUE" {
   157  		deleteCommand := []string{
   158  			"vm.destroy",
   159  			fmt.Sprintf("-vm.ipath=%s", conf.VMInventoryPath),
   160  			fmt.Sprintf("-u=%s", vcenterAdminCredentialUrl),
   161  			fmt.Sprintf("-tls-ca-certs=%s", pathToCACert),
   162  		}
   163  		Eventually(func() int {
   164  			return cli.Run(deleteCommand)
   165  		}, 3*time.Minute, 10*time.Second).Should(BeZero())
   166  		fmt.Println("VM destroyed")
   167  		if lockDir != "" {
   168  			_, _, err := lockPool.ReleaseLock(lockDir)
   169  			Expect(err).NotTo(HaveOccurred())
   170  
   171  			childItems, err := ioutil.ReadDir(lockParentDir)
   172  			Expect(err).NotTo(HaveOccurred())
   173  
   174  			for _, item := range childItems {
   175  				if item.IsDir() && strings.HasPrefix(filepath.Base(item.Name()), "pool-resource") {
   176  					fmt.Printf("Cleaning up temporary pool resource %s\n", item.Name())
   177  					_ = os.RemoveAll(item.Name())
   178  				}
   179  			}
   180  		}
   181  	}
   182  
   183  	_ = os.RemoveAll(tmpDir)
   184  }, func() {
   185  	if pathToCACert != "" {
   186  		os.RemoveAll(pathToCACert)
   187  	}
   188  })
   189  
   190  func revertSnapshot(vmIpath string, snapshotName string) {
   191  	snapshotCommand := []string{
   192  		"snapshot.revert",
   193  		fmt.Sprintf("-vm.ipath=%s", vmIpath),
   194  		fmt.Sprintf("-u=%s", vcenterAdminCredentialUrl),
   195  		fmt.Sprintf("-tls-ca-certs=%s", pathToCACert),
   196  		snapshotName,
   197  	}
   198  	fmt.Printf("Reverting VM Snapshot: %s\n", snapshotName)
   199  	exitCode := runIgnoringOutput(snapshotCommand)
   200  	if exitCode != 0 {
   201  		fmt.Print("There was an error reverting the snapshot.")
   202  	} else {
   203  		fmt.Println("Revert started.")
   204  	}
   205  	time.Sleep(30 * time.Second)
   206  }
   207  
   208  func waitForVmToBeReady(vmIp string, vmUsername string, vmPassword string) {
   209  	fmt.Print("Waiting for reverting snapshot to finish...")
   210  	clientFactory := remotemanager.NewWinRmClientFactory(vmIp, vmUsername, vmPassword)
   211  	rm := remotemanager.NewWinRM(vmIp, vmUsername, vmPassword, clientFactory)
   212  	Expect(rm).ToNot(BeNil())
   213  
   214  	start := time.Now()
   215  	vmReady := false
   216  	for !vmReady {
   217  		if time.Since(start) > time.Hour {
   218  			Fail(fmt.Sprintf("VM at %s failed to start", vmIp))
   219  		}
   220  		time.Sleep(5 * time.Second)
   221  		_, err := rm.ExecuteCommand(`powershell.exe "ls c:\windows 1>$null"`)
   222  		if err != nil {
   223  			fmt.Println("VM not yet ready:", err)
   224  		}
   225  		vmReady = err == nil
   226  	}
   227  	fmt.Println("done.")
   228  }
   229  
   230  func envMustExist(variableName string) string {
   231  	result := os.Getenv(variableName)
   232  	if result == "" {
   233  		Fail(fmt.Sprintf("%s must be set", variableName))
   234  	}
   235  
   236  	return result
   237  }
   238  
   239  func enableWinRM() {
   240  	_, b, _, _ := runtime.Caller(0)
   241  	root := filepath.Dir(filepath.Dir(filepath.Dir(b)))
   242  
   243  	fmt.Println("Enabling WinRM on the base image before integration tests...")
   244  	uploadCommand := []string{
   245  		"guest.upload",
   246  		fmt.Sprintf("-vm.ipath=%s", conf.VMInventoryPath),
   247  		fmt.Sprintf("-u=%s", vcenterAdminCredentialUrl),
   248  		fmt.Sprintf("-l=%s:%s", conf.VMUsername, conf.VMPassword),
   249  		fmt.Sprintf("-tls-ca-certs=%s", pathToCACert),
   250  		filepath.Join(root, "modules", "BOSH.WinRM", "BOSH.WinRM.psm1"),
   251  		"C:\\Windows\\Temp\\BOSH.WinRM.psm1",
   252  	}
   253  
   254  	exitCode := runIgnoringOutput(uploadCommand)
   255  	if exitCode != 0 {
   256  		fmt.Print("There was an error uploading WinRM psmodule.")
   257  	}
   258  
   259  	enableCommand := []string{
   260  		"guest.start",
   261  		fmt.Sprintf("-vm.ipath=%s", conf.VMInventoryPath),
   262  		fmt.Sprintf("-u=%s", vcenterAdminCredentialUrl),
   263  		fmt.Sprintf("-l=%s:%s", conf.VMUsername, conf.VMPassword),
   264  		fmt.Sprintf("-tls-ca-certs=%s", pathToCACert),
   265  		powershell,
   266  		`-command`,
   267  		`&{Import-Module C:\Windows\Temp\BOSH.WinRM.psm1; Enable-WinRM}`,
   268  	}
   269  	exitCode = runIgnoringOutput(enableCommand)
   270  	if exitCode != 0 {
   271  		fmt.Print("There was an error enabling WinRM.")
   272  	} else {
   273  		fmt.Println("WinRM enabled.")
   274  	}
   275  }
   276  
   277  func createVMSnapshot(snapshotName string) {
   278  	snapshotCommand := []string{
   279  		"snapshot.create",
   280  		fmt.Sprintf("-vm.ipath=%s", conf.VMInventoryPath),
   281  		fmt.Sprintf("-u=%s", vcenterAdminCredentialUrl),
   282  		fmt.Sprintf("-tls-ca-certs=%s", pathToCACert),
   283  		snapshotName,
   284  	}
   285  	fmt.Printf("Creating VM Snapshot: %s on VM: %s\n", snapshotName, conf.VMInventoryPath)
   286  	exitCode := cli.Run(snapshotCommand)
   287  	Expect(exitCode).To(Equal(0), "Creating the snapshot failed")
   288  
   289  	fmt.Println("Snapshot command started.")
   290  	fmt.Print("Waiting for snapshot to finish...")
   291  	time.Sleep(30 * time.Second)
   292  	fmt.Print("done.\n")
   293  }
   294  
   295  func powerOnVM() {
   296  	powerOnCommand := []string{
   297  		"vm.power",
   298  		fmt.Sprintf("-vm.ipath=%s", conf.VMInventoryPath),
   299  		fmt.Sprintf("-u=%s", vcenterAdminCredentialUrl),
   300  		fmt.Sprintf("-tls-ca-certs=%s", pathToCACert),
   301  		"-on",
   302  	}
   303  	runIgnoringOutput(powerOnCommand)
   304  }
   305  
   306  func runIgnoringOutput(args []string) int {
   307  	oldStderr := os.Stderr
   308  	oldStdout := os.Stdout
   309  
   310  	_, w, _ := os.Pipe()
   311  
   312  	defer w.Close()
   313  
   314  	os.Stderr = w
   315  	os.Stdout = w
   316  
   317  	os.Stderr = os.NewFile(uintptr(syscall.Stderr), "/dev/null")
   318  
   319  	exitCode := cli.Run(args)
   320  
   321  	os.Stderr = oldStderr
   322  	os.Stdout = oldStdout
   323  
   324  	return exitCode
   325  }