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 }