diff --git a/Libraries/Azure.psm1 b/Libraries/Azure.psm1 index 0e43b2cf8..1d00de613 100644 --- a/Libraries/Azure.psm1 +++ b/Libraries/Azure.psm1 @@ -783,13 +783,35 @@ Function GenerateAzureDeployJSONFile ($RGName, $osImage, $osVHD, $RGXMLData, $Lo #Random Data $RGrandomWord = ([System.IO.Path]::GetRandomFileName() -replace '[^a-z]') $RGRandomNumber = Get-Random -Minimum 11111 -Maximum 99999 -if ( $CurrentTestData.AdditionalHWConfig.DiskType -eq "Managed" ) +if ( $CurrentTestData.AdditionalHWConfig.DiskType -eq "Managed" -or $UseManagedDisks ) { - $UseManageDiskForCurrentTest = $true + if ( $CurrentTestData.AdditionalHWConfig.DiskType -eq "Managed" ) + { + $UseManageDiskForCurrentTest = $true + } + $DiskType = "Managed" } else { $UseManageDiskForCurrentTest = $false + $DiskType = "Unmanaged" +} +if ( $CurrentTestData.AdditionalHWConfig.OSDiskType -eq "Ephemeral" ) +{ + if ( $UseManageDiskForCurrentTest ) + { + $UseEphemeralOSDisk = $true + $DiskType += "-Ephemeral" + } + else + { + Throw "Invalid VM configuration. Ephemeral disks can only be created using Managed disk option." + } +} +else +{ + $DiskType += "-Persistant" + $UseEphemeralOSDisk = $false } #Generate the initial data $numberOfVMs = 0 @@ -1816,7 +1838,7 @@ foreach ( $newVM in $RGXMLData.VirtualMachine) #region virtualMachines LogMsg "Adding Virtual Machine $vmName" Add-Content -Value "$($indents[2]){" -Path $jsonFile - Add-Content -Value "$($indents[3])^apiVersion^: ^2017-03-30^," -Path $jsonFile + Add-Content -Value "$($indents[3])^apiVersion^: ^2018-06-01^," -Path $jsonFile Add-Content -Value "$($indents[3])^type^: ^Microsoft.Compute/virtualMachines^," -Path $jsonFile Add-Content -Value "$($indents[3])^name^: ^$vmName^," -Path $jsonFile Add-Content -Value "$($indents[3])^location^: ^[variables('location')]^," -Path $jsonFile @@ -1946,7 +1968,18 @@ foreach ( $newVM in $RGXMLData.VirtualMachine) Add-Content -Value "$($indents[7])^storageAccountType^: ^$StorageAccountType^" -Path $jsonFile Add-Content -Value "$($indents[6])}," -Path $jsonFile + if ($UseEphemeralOSDisk) + { + Add-Content -Value "$($indents[6])^caching^: ^ReadOnly^," -Path $jsonFile + Add-Content -Value "$($indents[6])^diffDiskSettings^: " -Path $jsonFile + Add-Content -Value "$($indents[6]){" -Path $jsonFile + Add-Content -Value "$($indents[7])^option^: ^local^" -Path $jsonFile + Add-Content -Value "$($indents[6])}," -Path $jsonFile + } + else + { Add-Content -Value "$($indents[6])^caching^: ^ReadWrite^," -Path $jsonFile + } Add-Content -Value "$($indents[6])^createOption^: ^FromImage^" -Path $jsonFile } else @@ -1972,13 +2005,23 @@ foreach ( $newVM in $RGXMLData.VirtualMachine) if ($UseManagedDisks -or $UseManageDiskForCurrentTest) { Add-Content -Value "$($indents[6])^name^: ^$vmName-OSDisk^," -Path $jsonFile - Add-Content -Value "$($indents[6])^createOption^: ^FromImage^," -Path $jsonFile Add-Content -Value "$($indents[6])^managedDisk^: " -Path $jsonFile Add-Content -Value "$($indents[6]){" -Path $jsonFile Add-Content -Value "$($indents[7])^storageAccountType^: ^$StorageAccountType^" -Path $jsonFile - Add-Content -Value "$($indents[6])}" -Path $jsonFile - LogMsg "Added managed OS disk : $vmName-OSDisk" - + Add-Content -Value "$($indents[6])}," -Path $jsonFile + if ($UseEphemeralOSDisk) + { + Add-Content -Value "$($indents[6])^caching^: ^ReadOnly^," -Path $jsonFile + Add-Content -Value "$($indents[6])^diffDiskSettings^: " -Path $jsonFile + Add-Content -Value "$($indents[6]){" -Path $jsonFile + Add-Content -Value "$($indents[7])^option^: ^local^" -Path $jsonFile + Add-Content -Value "$($indents[6])}," -Path $jsonFile + } + else + { + Add-Content -Value "$($indents[6])^caching^: ^ReadWrite^," -Path $jsonFile + } + Add-Content -Value "$($indents[6])^createOption^: ^FromImage^" -Path $jsonFile } else { @@ -1992,6 +2035,7 @@ foreach ( $newVM in $RGXMLData.VirtualMachine) } } Add-Content -Value "$($indents[5])}," -Path $jsonFile + LogMsg "Added $DiskType OS disk : $vmName-OSDisk" $dataDiskAdded = $false Add-Content -Value "$($indents[5])^dataDisks^ : " -Path $jsonFile Add-Content -Value "$($indents[5])[" -Path $jsonFile diff --git a/Libraries/CommonFunctions.psm1 b/Libraries/CommonFunctions.psm1 index 140843979..3c731c9a4 100644 --- a/Libraries/CommonFunctions.psm1 +++ b/Libraries/CommonFunctions.psm1 @@ -1156,7 +1156,7 @@ Function RemoteCopy($uploadTo, $downloadFrom, $downloadTo, $port, $files, $usern if($usePrivateKey) { LogMsg "Uploading $tarFileName to $username : $uploadTo, port $port using PrivateKey authentication" - Write-Output y | .\tools\pscp -i .\ssh\$sshKey -q -P $port $tarFileName $username@${uploadTo}: + Write-Output "yes" | .\tools\pscp -i .\ssh\$sshKey -q -P $port $tarFileName $username@${uploadTo}: $returnCode = $LASTEXITCODE } else @@ -1165,7 +1165,7 @@ Function RemoteCopy($uploadTo, $downloadFrom, $downloadTo, $port, $files, $usern $curDir = $PWD $uploadStatusRandomFile = ".\Temp\UploadStatusFile" + (Get-Random -Maximum 9999 -Minimum 1111) + ".txt" $uploadStartTime = Get-Date - $uploadJob = Start-Job -ScriptBlock { Set-Location $args[0]; Write-Output $args; Set-Content -Value "1" -Path $args[6]; $username = $args[4]; $uploadTo = $args[5]; Write-Output y | .\tools\pscp -v -pw $args[1] -q -P $args[2] $args[3] $username@${uploadTo}: ; Set-Content -Value $LASTEXITCODE -Path $args[6];} -ArgumentList $curDir,$password,$port,$tarFileName,$username,${uploadTo},$uploadStatusRandomFile + $uploadJob = Start-Job -ScriptBlock { Set-Location $args[0]; Write-Output $args; Set-Content -Value "1" -Path $args[6]; $username = $args[4]; $uploadTo = $args[5]; Write-Output "yes" | .\tools\pscp -v -pw $args[1] -q -P $args[2] $args[3] $username@${uploadTo}: ; Set-Content -Value $LASTEXITCODE -Path $args[6];} -ArgumentList $curDir,$password,$port,$tarFileName,$username,${uploadTo},$uploadStatusRandomFile Start-Sleep -Milliseconds 100 $uploadJobStatus = Get-Job -Id $uploadJob.Id $uploadTimout = $false @@ -1238,7 +1238,7 @@ Function RemoteCopy($uploadTo, $downloadFrom, $downloadTo, $port, $files, $usern if($usePrivateKey) { LogMsg "Uploading $testFile to $username : $uploadTo, port $port using PrivateKey authentication" - Write-Output y | .\tools\pscp -i .\ssh\$sshKey -q -P $port $testFile $username@${uploadTo}: + Write-Output "yes" | .\tools\pscp -i .\ssh\$sshKey -q -P $port $testFile $username@${uploadTo}: $returnCode = $LASTEXITCODE } else @@ -1247,7 +1247,7 @@ Function RemoteCopy($uploadTo, $downloadFrom, $downloadTo, $port, $files, $usern $curDir = $PWD $uploadStatusRandomFile = ".\Temp\UploadStatusFile" + (Get-Random -Maximum 9999 -Minimum 1111) + ".txt" $uploadStartTime = Get-Date - $uploadJob = Start-Job -ScriptBlock { Set-Location $args[0]; Write-Output $args; Set-Content -Value "1" -Path $args[6]; $username = $args[4]; $uploadTo = $args[5]; Write-Output y | .\tools\pscp -v -pw $args[1] -q -P $args[2] $args[3] $username@${uploadTo}: ; Set-Content -Value $LASTEXITCODE -Path $args[6];} -ArgumentList $curDir,$password,$port,$testFile,$username,${uploadTo},$uploadStatusRandomFile + $uploadJob = Start-Job -ScriptBlock { Set-Location $args[0]; Write-Output $args; Set-Content -Value "1" -Path $args[6]; $username = $args[4]; $uploadTo = $args[5]; Write-Output "yes" | .\tools\pscp -v -pw $args[1] -q -P $args[2] $args[3] $username@${uploadTo}: ; Set-Content -Value $LASTEXITCODE -Path $args[6];} -ArgumentList $curDir,$password,$port,$testFile,$username,${uploadTo},$uploadStatusRandomFile Start-Sleep -Milliseconds 100 $uploadJobStatus = Get-Job -Id $uploadJob.Id $uploadTimout = $false @@ -1313,7 +1313,7 @@ Function RemoteCopy($uploadTo, $downloadFrom, $downloadTo, $port, $files, $usern $curDir = $PWD $downloadStatusRandomFile = ".\Temp\DownloadStatusFile" + (Get-Random -Maximum 9999 -Minimum 1111) + ".txt" $downloadStartTime = Get-Date - $downloadJob = Start-Job -ScriptBlock { $curDir=$args[0];$sshKey=$args[1];$port=$args[2];$testFile=$args[3];$username=$args[4];${downloadFrom}=$args[5];$downloadTo=$args[6];$downloadStatusRandomFile=$args[7]; Set-Location $curDir; Set-Content -Value "1" -Path $args[6]; Write-Output y | .\tools\pscp -i .\ssh\$sshKey -q -P $port $username@${downloadFrom}:$testFile $downloadTo; Set-Content -Value $LASTEXITCODE -Path $downloadStatusRandomFile;} -ArgumentList $curDir,$sshKey,$port,$testFile,$username,${downloadFrom},$downloadTo,$downloadStatusRandomFile + $downloadJob = Start-Job -ScriptBlock { $curDir=$args[0];$sshKey=$args[1];$port=$args[2];$testFile=$args[3];$username=$args[4];${downloadFrom}=$args[5];$downloadTo=$args[6];$downloadStatusRandomFile=$args[7]; Set-Location $curDir; Set-Content -Value "1" -Path $args[6]; Write-Output "yes" | .\tools\pscp -i .\ssh\$sshKey -q -P $port $username@${downloadFrom}:$testFile $downloadTo; Set-Content -Value $LASTEXITCODE -Path $downloadStatusRandomFile;} -ArgumentList $curDir,$sshKey,$port,$testFile,$username,${downloadFrom},$downloadTo,$downloadStatusRandomFile Start-Sleep -Milliseconds 100 $downloadJobStatus = Get-Job -Id $downloadJob.Id $downloadTimout = $false @@ -1350,7 +1350,7 @@ Function RemoteCopy($uploadTo, $downloadFrom, $downloadTo, $port, $files, $usern $downloadTo=$args[6]; $downloadStatusRandomFile=$args[7]; Set-Location $curDir; - Write-Output y | .\tools\pscp.exe -v -2 -unsafe -pw $password -q -P $port $username@${downloadFrom}:$testFile $downloadTo 2> $downloadStatusRandomFile; + Write-Output "yes" | .\tools\pscp.exe -v -2 -unsafe -pw $password -q -P $port $username@${downloadFrom}:$testFile $downloadTo 2> $downloadStatusRandomFile; Add-Content -Value "DownloadExtiCode_$LASTEXITCODE" -Path $downloadStatusRandomFile; } -ArgumentList $curDir,$password,$port,$testFile,$username,${downloadFrom},$downloadTo,$downloadStatusRandomFile Start-Sleep -Milliseconds 100 @@ -2687,12 +2687,12 @@ function Check-Systemd { $check1 = $true $check2 = $true - .\Tools\plink.exe -C -pw $Password -P $SSHPort $Username@$Ipv4 "ls -l /sbin/init | grep systemd" + Write-Output "yes" | .\Tools\plink.exe -C -pw $Password -P $SSHPort $Username@$Ipv4 "ls -l /sbin/init | grep systemd" if ($LASTEXITCODE -ne "True") { LogMsg "Systemd not found on VM" $check1 = $false } - .\Tools\plink.exe -C -pw $Password -P $SSHPort $Username@$Ipv4 "systemd-analyze --help" + Write-Output "yes" | .\Tools\plink.exe -C -pw $Password -P $SSHPort $Username@$Ipv4 "systemd-analyze --help" if ($LASTEXITCODE -ne "True") { LogMsg "Systemd-analyze not present on VM." $check2 = $false @@ -2732,8 +2732,8 @@ function Get-VMFeatureSupportStatus { [String] $SupportKernel ) - Write-Output y | .\Tools\plink.exe -C -pw $Password -P $SSHPort $Username@$Ipv4 'exit 0' - $currentKernel = .\Tools\plink.exe -C -pw $Password -P $SSHPort $Username@$Ipv4 "uname -r" + Write-Output "yes" | .\Tools\plink.exe -C -pw $Password -P $SSHPort $Username@$Ipv4 'exit 0' + $currentKernel = Write-Output "yes" | .\Tools\plink.exe -C -pw $Password -P $SSHPort $Username@$Ipv4 "uname -r" if( $LASTEXITCODE -eq $false){ LogMsg "Warning: Could not get kernel version". } @@ -2774,12 +2774,12 @@ function Get-SelinuxAVCLog() { $TEXT_HV = "hyperv" $TEXT_AVC = "type=avc" - Write-Output y | .\Tools\plink.exe -C -pw $Password -P $SSHPort $Username@$Ipv4 "ls /var/log/audit/audit.log > /dev/null 2>&1" + Write-Output "yes" | .\Tools\plink.exe -C -pw $Password -P $SSHPort $Username@$Ipv4 "ls /var/log/audit/audit.log > /dev/null 2>&1" if (-not $LASTEXITCODE) { LogErr "Warning: Unable to find audit.log from the VM, ignore audit log check" return $True } - .\Tools\pscp -C -pw $Password -P $SSHPort $Username@${Ipv4}:/var/log/audit/audit.log $filename + Write-Output "yes" | .\Tools\pscp -C -pw $Password -P $SSHPort $Username@${Ipv4}:/var/log/audit/audit.log $filename if (-not $LASTEXITCODE) { LogErr "ERROR: Unable to copy audit.log from the VM" return $False @@ -2806,7 +2806,7 @@ function Get-VMFeatureSupportStatus { [String] $SupportKernel ) - $currentKernel = .\Tools\plink.exe -C -pw $Password -P $VmPort $UserName@$VmIp "uname -r" + $currentKernel = Write-Output "yes" | .\Tools\plink.exe -C -pw $Password -P $VmPort $UserName@$VmIp "uname -r" if ($LASTEXITCODE -eq $False) { Write-Output "Warning: Could not get kernel version". } @@ -2935,10 +2935,10 @@ function Check-FileInLinuxGuest{ #> if ($checkSize) { - .\Tools\plink.exe -C -pw $vmPassword -P $vmPort $vmUserName@$ipv4 "wc -c < $fileName" + Write-Output "yes" | .\Tools\plink.exe -C -pw $vmPassword -P $vmPort $vmUserName@$ipv4 "wc -c < $fileName" } else { - .\Tools\plink.exe -C -pw $vmPassword -P $vmPort $vmUserName@$ipv4 "stat ${fileName} >/dev/null" + Write-Output "yes" | .\Tools\plink.exe -C -pw $vmPassword -P $vmPort $vmUserName@$ipv4 "stat ${fileName} >/dev/null" } if (-not $?) { @@ -2946,7 +2946,7 @@ function Check-FileInLinuxGuest{ } if ($checkContent) { - .\Tools\plink.exe -C -pw $vmPassword -P $vmPort $vmUserName@$ipv4 "cat ${fileName}" + Write-Output "yes" | .\Tools\plink.exe -C -pw $vmPassword -P $vmPort $vmUserName@$ipv4 "cat ${fileName}" if (-not $?) { return $False } @@ -2991,7 +2991,7 @@ function Send-CommandToVM { } # get around plink questions - Write-Output y | .\Tools\plink.exe -C -pw ${vmPassword} -P ${vmPort} root@$ipv4 'exit 0' + Write-Output "yes" | .\Tools\plink.exe -C -pw ${vmPassword} -P ${vmPort} root@$ipv4 'exit 0' $process = Start-Process .\Tools\plink.exe -ArgumentList "-C -pw ${vmPassword} -P ${vmPort} root@$ipv4 ${command}" -PassThru -NoNewWindow -Wait if ($process.ExitCode -eq 0) { @@ -3021,13 +3021,13 @@ function Check-FcopyDaemon{ $filename = ".\fcopy_present" - .\Tools\plink.exe -C -pw $vmPassword -P $vmPort $vmUserName@$ipv4 "ps -ef | grep '[h]v_fcopy_daemon\|[h]ypervfcopyd' > /tmp/fcopy_present" + Write-Output "yes" | .\Tools\plink.exe -C -pw $vmPassword -P $vmPort $vmUserName@$ipv4 "ps -ef | grep '[h]v_fcopy_daemon\|[h]ypervfcopyd' > /tmp/fcopy_present" if (-not $?) { LogErr "Unable to verify if the fcopy daemon is running" return $False } - .\tools\pscp.exe -v -2 -unsafe -pw $vmPassword -q -P ${vmPort} $vmUserName@${ipv4}:/tmp/fcopy_present . + Write-Output "yes" | .\tools\pscp.exe -v -2 -unsafe -pw $vmPassword -q -P ${vmPort} $vmUserName@${ipv4}:/tmp/fcopy_present . if (-not $?) { LogErr "Unable to copy the confirmation file from the VM" return $False @@ -3289,7 +3289,7 @@ function Check-Result{ while ($timeout -ne 0 ) { - .\tools\pscp.exe -v -2 -unsafe -pw $vmPassword -q -P ${vmPort} root@${ipv4}:${stateFile} ${localStateFile} #| out-null + Write-Output "yes" | .\tools\pscp.exe -v -2 -unsafe -pw $vmPassword -q -P ${vmPort} root@${ipv4}:${stateFile} ${localStateFile} #| out-null $sts = $? if ($sts) { @@ -3439,7 +3439,7 @@ function Stop-FcopyDaemon{ ) $sts = check_fcopy_daemon -vmPassword $vmPassword -vmPort $vmPort -vmUserName $vmUserName -ipv4 $ipv4 if ($sts[-1] -eq $True ){ - .\Tools\plink.exe -C -pw ${vmPassword} -P ${vmPort} ${vmUserName}@${ipv4} "pkill -f 'fcopy'" + Write-Output "yes" | .\Tools\plink.exe -C -pw ${vmPassword} -P ${vmPort} ${vmUserName}@${ipv4} "pkill -f 'fcopy'" if (-not $?) { LogErr "Unable to kill hypervfcopy daemon" return $False @@ -3526,12 +3526,12 @@ function Check-Systemd { $check1 = $true $check2 = $true - .\Tools\plink.exe -C -pw $Password -P $SSHPort $Username@$Ipv4 "ls -l /sbin/init | grep systemd" + Write-Output "yes" | .\Tools\plink.exe -C -pw $Password -P $SSHPort $Username@$Ipv4 "ls -l /sbin/init | grep systemd" if ($LASTEXITCODE -gt "0") { LogMsg "Systemd not found on VM" $check1 = $false } - .\Tools\plink.exe -C -pw $Password -P $SSHPort $Username@$Ipv4 "systemd-analyze --help" + Write-Output "yes" | .\Tools\plink.exe -C -pw $Password -P $SSHPort $Username@$Ipv4 "systemd-analyze --help" if ($LASTEXITCODE -gt "0") { LogMsg "Systemd-analyze not present on VM." $check2 = $false @@ -3630,7 +3630,7 @@ function Get-IPv4AndWaitForSSHStart { } # Cache fingerprint, Check ssh is functional after reboot - Write-Output y | .\Tools\plink.exe -C -pw $Password -P $VmPort $User@$new_ip 'exit 0' + Write-Output "yes" | .\Tools\plink.exe -C -pw $Password -P $VmPort $User@$new_ip 'exit 0' $TestConnection = .\Tools\plink.exe -C -pw $Password -P $VmPort $User@$new_ip "echo Connected" if ($TestConnection -ne "Connected") { LogErr "GetIPv4AndWaitForSSHStart: SSH is not working correctly after boot up" @@ -4278,6 +4278,259 @@ Function Remove-InvalidCharactersFromFileName $Regex = "[{0}]" -f [RegEx]::Escape($WindowsInvalidCharacters) return ($FileName -replace $Regex) } + +Function Check-VSSDemon { + param ( + [String] $VMName, + [String] $HvServer, + [String] $VMIpv4, + [String] $VMPort + ) + $remoteScript="STOR_VSS_Check_VSS_Daemon.sh" + $retval = Invoke-RemoteScriptAndCheckStateFile $remoteScript $user $password $VMIpv4 $VMPort + if ($retval -eq $False) { + LogErr "Running $remoteScript script failed on VM!" + return $False + } + LogMsg "VSS Daemon is running" + return $True +} + +Function New-BackupSetup { + param ( + [String] $VMName, + [String] $HvServer + ) + LogMsg "Removing old backups" + Remove-WBBackupSet -Force -WarningAction SilentlyContinue + if(-not $?) { + LogErr "Not able to remove existing backup" + return $False + } + # Check if the VM VHD in not on the same drive as the backup destination + $vm = Get-VM -Name $VMName -ComputerName $HvServer + # Get drive letter + $sts = Get-DriveLetter $VMName $HvServer + $driveletter = $global:driveletter + if (-not $sts[-1]) { + LogErr "Cannot get the drive letter" + return $False + } + foreach ($drive in $vm.HardDrives) { + if ( $drive.Path.StartsWith("$driveletter")) { + LogErr "Backup partition $driveletter is same as partition hosting the VMs disk $($drive.Path)" + return $False + } + } + return $True +} + +Function New-Backup { + param ( + [String] $VMName, + [String] $DriveLetter, + [String] $HvServer, + [String] $VMIpv4, + [String] $VMPort + ) + # Remove Existing Backup Policy + try { + Remove-WBPolicy -all -force + } + Catch { + LogMsg "No existing backup policy to remove" + } + # Set up a new Backup Policy + $policy = New-WBPolicy + # Set the backup location + $backupLocation = New-WBBackupTarget -VolumePath $DriveLetter + # Define VSS WBBackup type + Set-WBVssBackupOption -Policy $policy -VssCopyBackup + # Add the Virtual machines to the list + $VM = Get-WBVirtualMachine | Where-Object VMName -like $VMName + Add-WBVirtualMachine -Policy $policy -VirtualMachine $VM + Add-WBBackupTarget -Policy $policy -Target $backupLocation + # Start the backup + LogMsg "Backing to $DriveLetter" + Start-WBBackup -Policy $policy + # Review the results + $BackupTime = (New-Timespan -Start (Get-WBJob -Previous 1).StartTime -End (Get-WBJob -Previous 1).EndTime).Minutes + LogMsg "Backup duration: $BackupTime minutes" + $sts=Get-WBJob -Previous 1 + if ($sts.JobState -ne "Completed" -or $sts.HResult -ne 0) { + LogErr "VSS Backup failed" + return $False + } + LogMsg "Backup successful!" + # Let's wait a few Seconds + Start-Sleep -Seconds 5 + # Delete file on the VM + $vmState = $(Get-VM -name $VMName -ComputerName $HvServer).state + if (-not $vmState) { + RunLinuxCmd -username $user -password $password -ip $VMIpv4 -port $VMPort -command "rm /root/1" -runAsSudo + if (-not $?) { + LogErr "Cannot delete test file!" + return $False + } + LogMsg "File deleted on VM: $VMName" + } + return $backupLocation +} + +Function Restore-Backup { + param ( + $BackupLocation, + $HypervGroupName, + $VMName + ) + # Start the Restore + LogMsg "Now let's restore the VM from backup." + # Get BackupSet + $BackupSet = Get-WBBackupSet -BackupTarget $BackupLocation + # Start restore + Start-WBHyperVRecovery -BackupSet $BackupSet -VMInBackup $BackupSet.Application[0].Component[0] -Force -WarningAction SilentlyContinue + $sts=Get-WBJob -Previous 1 + if ($sts.JobState -ne "Completed" -or $sts.HResult -ne 0) { + LogErr "VSS Restore failed" + return $False + } + # Add VM to VMGroup + Add-VMGroupMember -Name $HypervGroupName -VM $(Get-VM -name $VMName) + return $True +} + +Function Check-VMStateAndFileStatus { + param ( + [String] $VMName, + [String] $HvServer, + [String] $VMIpv4, + [String] $VMPort + ) + + # Review the results + $RestoreTime = (New-Timespan -Start (Get-WBJob -Previous 1).StartTime -End (Get-WBJob -Previous 1).EndTime).Minutes + LogMsg "Restore duration: $RestoreTime minutes" + # Make sure VM exists after VSS backup/restore operation + $vm = Get-VM -Name $VMName -ComputerName $HvServer + if (-not $vm) { + LogErr "VM ${VMName} does not exist after restore" + return $False + } + LogMsg "Restore success!" + $vmState = (Get-VM -name $VMName -ComputerName $HvServer).state + LogMsg "VM state is $vmState" + $ip_address = Get-IPv4ViaKVP $VMName $HvServer + $timeout = 300 + if ($vmState -eq "Running") { + if ($null -eq $ip_address) { + LogMsg "Restarting VM ${VMName} to bring up network" + Restart-VM -vmName $VMName -ComputerName $HvServer + Wait-ForVMToStartKVP $VMName $HvServer $timeout + $ip_address = Get-IPv4ViaKVP $VMName $HvServer + } + } + elseif ($vmState -eq "Off" -or $vmState -eq "saved" ) { + LogMsg "Starting VM : ${VMName}" + Start-VM -vmName $VMName -ComputerName $HvServer + if (-not (Wait-ForVMToStartKVP $VMName $HvServer $timeout )) { + LogErr "${VMName} failed to start" + return $False + } + else { + $ip_address = Get-IPv4ViaKVP $VMName $HvServer + } + } + elseif ($vmState -eq "Paused") { + LogMsg "Resuming VM : ${VMName}" + Resume-VM -vmName $VMName -ComputerName $HvServer + if (-not (Wait-ForVMToStartKVP $VMName $HvServer $timeout )) { + LogErr "${VMName} failed to resume" + return $False + } + else { + $ip_address = Get-IPv4ViaKVP $VMName $HvServer + } + } + LogMsg "${VMName} IP is $ip_address" + # check selinux denied log after ip injection + $sts=Get-SelinuxAVCLog -ipv4 $VMIpv4 -SSHPort $VMPort -Username "root" -Password $password + if (-not $sts) { + return $False + } + # only check restore file when ip available + $stsipv4 = Test-NetConnection $VMIpv4 -Port 22 -WarningAction SilentlyContinue + if ($stsipv4.TcpTestSucceeded) { + $sts=Check-FileInLinuxGuest -VMPassword $password -VMPort $VMPort -VMUserName "root" -Ipv4 $VMIpv4 -fileName "/root/1" + if (-not $sts) { + LogErr "No /root/1 file after restore" + return $False + } + else { + LogMsg "there is /root/1 file after restore" + } + } + else { + LogMsg "Ignore checking file /root/1 when no network" + } + return $True +} + +Function Remove-Backup { + param ( + [String] $BackupLocation + ) + # Remove Created Backup + LogMsg "Removing old backups from $BackupLocation" + try { + Remove-WBBackupSet -BackupTarget $BackupLocation -Force -WarningAction SilentlyContinue + } + Catch { + LogMsg "No existing backups to remove" + } +} + +Function Get-BackupType() { + # check the latest successful job backup type, "online" or "offline" + $backupType = $null + $sts = Get-WBJob -Previous 1 + if ($sts.JobState -ne "Completed" -or $sts.HResult -ne 0) { + LogErr "Error: VSS Backup failed " + return $backupType + } + $contents = get-content $sts.SuccessLogPath + foreach ($line in $contents ) { + if ( $line -match "Caption" -and $line -match "online") { + LogMsg "VSS Backup type is online" + $backupType = "online" + } + elseif ($line -match "Caption" -and $line -match "offline") { + LogMsg "VSS Backup type is offline" + $backupType = "offline" + } + } + return $backupType +} + +Function Get-DriveLetter { + param ( + [string] $VMName, + [string] $HvServer + ) + if ($null -eq $VMName) { + LogErr "VM ${VMName} name was not specified." + return $False + } + # Get the letter of the mounted backup drive + $tempFile = (Get-VMHost -ComputerName $HvServer).VirtualHardDiskPath + "\" + $VMName + "_DRIVE_LETTER.txt" + if(Test-Path ($tempFile)) { + $global:driveletter = Get-Content -Path $tempFile + return $True + } + else { + return $False + } +} + #Check if stress-ng is installed Function Is-StressNgInstalled { param ( diff --git a/Libraries/Framework.psm1 b/Libraries/Framework.psm1 index 968249011..150efbc42 100644 --- a/Libraries/Framework.psm1 +++ b/Libraries/Framework.psm1 @@ -1062,7 +1062,7 @@ Function Get-LISAv2Tools($XMLSecretFile) $WebClient.DownloadFile("$toolFileAccessLocation/$_","$CurrentDirectory\Tools\$_") # Successfully downloaded files - LogMsg "File $_ successfully downloaded in Tools folder: $_." + LogMsg "File $_ successfully downloaded in Tools folder: $CurrentDirectory\Tools." } } } \ No newline at end of file diff --git a/Testscripts/Linux/NET-Ethtool-Check-Statistics.sh b/Testscripts/Linux/NET-Ethtool-Check-Statistics.sh index 3d741b537..2485a76e0 100644 --- a/Testscripts/Linux/NET-Ethtool-Check-Statistics.sh +++ b/Testscripts/Linux/NET-Ethtool-Check-Statistics.sh @@ -247,14 +247,6 @@ ChangeMTU(){ #Log the values LogMsg "Wake_queue start value: $wake_value" LogMsg "Wake_queue value after changing MTU: $new_wake_value" - - if [ $new_wake_value -eq 10 ]; then - LogMsg "Successfully test on wake_queue param." - return 0 - else - LogErr "test on wake_queue param failed." - return 1 - fi } # Main script body @@ -336,7 +328,7 @@ ip link show $test_iface ethtool --version if [ $? -ne 0 ]; then update_repos - install_package "ethtool" + install_package "ethtool" fi #Check if Statistics from ethtool are available @@ -346,7 +338,7 @@ if [[ $sts = *"no stats available"* ]]; then LogErr "Operation not supported. Test Skipped." SetTestStateAborted exit 0 -fi +fi #Make all bash scripts executable cd ~ diff --git a/Testscripts/Linux/customKernelInstall.sh b/Testscripts/Linux/customKernelInstall.sh index b7a5a4e9a..1ee8706ab 100644 --- a/Testscripts/Linux/customKernelInstall.sh +++ b/Testscripts/Linux/customKernelInstall.sh @@ -144,40 +144,44 @@ InstallKernel() sourceDir="net-next" elif [[ $CustomKernel == *.deb ]]; then LogMsg "Custom Kernel:$CustomKernel" + apt-get update + + LogMsg "Adding packages required by the kernel." + apt-get install -y binutils + + LogMsg "Removing packages that do not allow the kernel to be installed" + apt-get remove -y grub-legacy-ec2 + if [[ $CustomKernel =~ "http" ]];then - CheckInstallLockUbuntu - apt-get update - apt-get install wget -y - LogMsg "Debian package web link detected. Downloading $CustomKernel" - wget $CustomKernel - LogMsg "Installing ${CustomKernel##*/}" - dpkg -i "${CustomKernel##*/}" >> $logFolder/build-CustomKernel.txt 2>&1 - kernelInstallStatus=$? + CheckInstallLockUbuntu + LogMsg "Debian package web link detected. Downloading $CustomKernel" + apt-get install -y wget + wget $CustomKernel + LogMsg "Installing ${CustomKernel##*/}" + dpkg -i "${CustomKernel##*/}" >> $logFolder/build-CustomKernel.txt 2>&1 + kernelInstallStatus=$? else - CheckInstallLockUbuntu - customKernelFilesUnExpanded="${CustomKernel#$LOCAL_FILE_PREFIX}" - - LogMsg "Removing packages that do not allow the kernel to be installed" - apt-get remove -y grub-legacy-ec2 - if [[ "${customKernelFilesUnExpanded}" == *'*.deb'* ]]; then - apt-get remove -y linux-cloud-tools-common - fi + CheckInstallLockUbuntu + customKernelFilesUnExpanded="${CustomKernel#$LOCAL_FILE_PREFIX}" + if [[ "${customKernelFilesUnExpanded}" == *'*.deb'* ]]; then + apt-get remove -y linux-cloud-tools-common + fi - LogMsg "Installing ${customKernelFilesUnExpanded}" - eval "dpkg -i $customKernelFilesUnExpanded >> $logFolder/build-CustomKernel.txt 2>&1" + LogMsg "Installing ${customKernelFilesUnExpanded}" + eval "dpkg -i $customKernelFilesUnExpanded >> $logFolder/build-CustomKernel.txt 2>&1" - LogMsg "Configuring the correct kernel boot order" - image_file=$(ls -1 *image* | grep -v "dbg" | sed -n 1p) - if [[ "${image_file}" != '' ]]; then - kernel_identifier=$(dpkg-deb --info "${image_file}" | grep 'Package: ' | grep -o "image.*") - kernel_identifier=${kernel_identifier#image-} - sed -i.bak 's/GRUB_DEFAULT=.*/GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux '$kernel_identifier'"/g' /etc/default/grub - update-grub - else - msg="Kernel correct boot order could not be set." - LogErr "$msg" - fi - kernelInstallStatus=$? + LogMsg "Configuring the correct kernel boot order" + image_file=$(ls -1 *image* | grep -v "dbg" | sed -n 1p) + if [[ "${image_file}" != '' ]]; then + kernel_identifier=$(dpkg-deb --info "${image_file}" | grep 'Package: ' | grep -o "image.*") + kernel_identifier=${kernel_identifier#image-} + sed -i.bak 's/GRUB_DEFAULT=.*/GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux '$kernel_identifier'"/g' /etc/default/grub + update-grub + else + msg="Kernel correct boot order could not be set." + LogErr "$msg" + fi + kernelInstallStatus=$? fi UpdateTestState $ICA_TESTCOMPLETED diff --git a/Testscripts/Windows/CLEANUP-Backup-DISK.ps1 b/Testscripts/Windows/CLEANUP-Backup-DISK.ps1 new file mode 100644 index 000000000..f9280abe5 --- /dev/null +++ b/Testscripts/Windows/CLEANUP-Backup-DISK.ps1 @@ -0,0 +1,56 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the Apache License. +<# +.Synopsis + This script creates a disk to be used for backup and restore tests +.Description + This script will create a new VHD double the size of the VHD in the + given vm. The VHD will be mounted to a new partiton, initialized and + formatted with NTFS +#> +$ErrorActionPreference = "Stop" +function Main { + try { + $testResult = $null + $captureVMData = $allVMData + $VMName = $captureVMData.RoleName + $HvServer= $captureVMData.HyperVhost + # Change the working directory to where we need to be + Set-Location $WorkingDirectory + $backupdiskpath = (Get-VMHost).VirtualHardDiskPath + "\" + $VMName + "_VSS_DISK.vhdx" + $tempFile = (Get-VMHost).VirtualHardDiskPath + "\" + $VMName + "_DRIVE_LETTER.txt" + # This is used to set the $global:driveletter variable + Get-DriveLetter $VMName $HvServer + if ($global:driveletter) { + Dismount-VHD -Path $backupDiskPath -ErrorAction SilentlyContinue + if (-not $?) { + LogErr "Dismounting VHD has failed" + } + Remove-Item $backupdiskpath -Force -ErrorAction SilentlyContinue + if (-not $?) { + LogErr "Could not remove backup disk" + } + Remove-Item $tempFile -Force -ErrorAction SilentlyContinue + if (-not $?) { + LogErr "Could not remove temporary file" + } + LogMsg "Cleanup completed!" + $testResult=$resultPass + } + else { + LogErr "Drive letter isn't set" + } + } catch { + $ErrorMessage = $_.Exception.Message + $ErrorLine = $_.InvocationInfo.ScriptLineNumber + LogErr "$ErrorMessage at line: $ErrorLine" + } finally { + if (!$testResult) { + $testResult = $resultAborted + } + $resultArr += $testResult + } + $currentTestResult.TestResult = GetFinalResultHeader -resultarr $resultArr + return $currentTestResult.TestResult +} +Main diff --git a/Testscripts/Windows/SETUP-Backup-DISK.ps1 b/Testscripts/Windows/SETUP-Backup-DISK.ps1 new file mode 100644 index 000000000..66a4503ea --- /dev/null +++ b/Testscripts/Windows/SETUP-Backup-DISK.ps1 @@ -0,0 +1,72 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the Apache License. +<# +.Synopsis + This script creates a disk to be used for backup and restore tests +.Description + This scrip will create a new VHD double the size of the VHD in the + given vm. The VHD will be mounted to a new partiton, initialized and + formatted with NTFS +#> +$ErrorActionPreference = "Stop" +function Main { + try { + $testResult = $null + $captureVMData = $allVMData + $VMName = $captureVMData.RoleName + # Change the working directory to where we need to be + Set-Location $WorkingDirectory + $utilsScript = ".\Utilities\STOR-VSS-Utils.ps1" + $backupdisksize = 2*$(Get-VMHardDiskDrive -VMName $VMName |get-vhd)[0].size + $backupdiskpath = (Get-VMHost).VirtualHardDiskPath + "\" + $VMName + "_VSS_DISK.vhdx" + $driveletter = Get-ChildItem function:[g-y]: -n | Where-Object { !(test-path $_) } | Get-random + $originaldriveletter = $driveletter + [char]$driveletter = $driveletter.Replace(":","") + if ([string]::IsNullOrEmpty($driveletter)) { + throw "Setup: The driveletter variable is empty!" + } + $maxRetryCount=2 + $currentRetryCount = 0 + while ($currentRetryCount -lt $maxRetryCount){ + if (Test-Path ($backupdiskpath)) { + LogMsg "Disk already exists. Deleting old disk and creating new disk." + Dismount-VHD $backupdiskpath + Remove-Item $backupdiskpath + } + New-VHD -Path $backupdiskpath -Size $backupdisksize + Mount-VHD -Path $backupdiskpath + if($?) { + break + } + $currentRetryCount++ + } + if ($currentRetryCount -eq $maxRetryCount) { + throw "Mounting VHD Failed" + } + $backupdisk = Get-VHD -Path $backupdiskpath + Initialize-Disk $backupdisk.DiskNumber + $diskpartition = New-Partition -DriveLetter $driveletter -DiskNumber $backupdisk.DiskNumber -UseMaximumSize + $volume = Format-Volume -FileSystem NTFS -Confirm:$False -Force -Partition $diskpartition + LogMsg "Disk initialized with volume $volume $diskpartition" + New-PSDrive -Name $driveletter -PSProvider FileSystem -Root $originaldriveletter -Description "VSS" + $filePath = (Get-VMHost).VirtualHardDiskPath + "\" + "$VMName" + "_DRIVE_LETTER.txt" + if(Test-Path ($filePath)) { + LogMsg "Removing existing file." + Remove-Item $filePath + } + Write-Output "$originaldriveletter" >> $filePath + $testResult=$resultPass + } catch { + $ErrorMessage = $_.Exception.Message + $ErrorLine = $_.InvocationInfo.ScriptLineNumber + LogErr "$ErrorMessage at line: $ErrorLine" + } finally { + if (!$testResult) { + $testResult = $resultAborted + } + $resultArr += $testResult + } + $currentTestResult.TestResult = GetFinalResultHeader -resultarr $resultArr + return $currentTestResult.TestResult +} +Main diff --git a/Testscripts/Windows/STOR-VSS-BACKUP-RESTORE-PARTITION.ps1 b/Testscripts/Windows/STOR-VSS-BACKUP-RESTORE-PARTITION.ps1 new file mode 100644 index 000000000..d7129b6c7 --- /dev/null +++ b/Testscripts/Windows/STOR-VSS-BACKUP-RESTORE-PARTITION.ps1 @@ -0,0 +1,103 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the Apache License. +<# +.Synopsis + This script tests VSS backup functionality. +.Description + This script will format and mount connected disk in the VM. + After that it will proceed with backup/restore operation. + It uses a second partition as target. +#> +param([String] $TestParams) +$ErrorActionPreference = "Stop" +function Main { + param ( + $TestParams + ) + try { + $testResult = $null + $captureVMData = $allVMData + $VMName = $captureVMData.RoleName + $HvServer= $captureVMData.HyperVhost + $Ipv4=$captureVMData.PublicIP + $VMPort=$captureVMData.SSHPort + $HypervGroupName=$captureVMData.HyperVGroupName + # Change the working directory to where we need to be + Set-Location $WorkingDirectory + $sts = New-BackupSetup $VMName $HvServer + if (-not $sts[-1]) { + throw "Run setup failed" + } + # Check VSS Demon is running + $sts = Check-VSSDemon $VMName $HvServer $Ipv4 $VMPort + if (-not $sts){ + throw "VSS Daemon is not running" + } + # Create a file on the VM before backup + RunLinuxCmd -username $user -password $password -ip $Ipv4 -port $VMPort -command "touch /root/1" -runAsSudo + if (-not $?) { + throw "Cannot create test file" + } + # Check SecureBoot is enabled + if ( $TestParams.secureBootVM ) { + # Check if Secure boot settings are in place before the backup + $firmwareSettings = Get-VMFirmware -VMName $VMName + if ($firmwareSettings.SecureBoot -ne "On") { + $testResult = $resultFail + throw "Secure boot settings changed" + } + } + $driveletter = $global:driveletter + if ($null -eq $driveletter) { + $testResult = $resultFail + throw "Backup driveletter is not specified." + } + # Run the Partition Disk script + if (-not $TestParams.secureBootVM) { + $remoteScript="PartitionMultipleDisks.sh" + $retval = Invoke-RemoteScriptAndCheckStateFile $remoteScript $user $password $Ipv4 $VMPort + if ($retval -eq $False) { + throw "Running $remoteScript script failed on VM!" + } + } + $sts = New-Backup $VMName $driveletter $HvServer $Ipv4 $VMPort + if (-not $sts[-1]) { + throw "Could not retrieve Backup Location" + } + else { + $backupLocation = $sts[-1] + } + $sts = Restore-Backup $backupLocation $HypervGroupName $VMName + if (-not $sts[-1]) { + throw "Restore backup action failed" + } + $sts = Check-VMStateAndFileStatus $VMName $HvServer $Ipv4 $VMPort + if (-not $sts) { + throw "Backup evaluation failed" + } + if ( $TestParams.secureBootVM ) { + # Check if Secure boot settings are in place before the backup + $firmwareSettings = Get-VMFirmware -VMName $VMName + if ($firmwareSettings.SecureBoot -ne "On") { + $testResult = $resultFail + throw "Secure boot settings changed after restoring backup" + } + } + Remove-Backup $backupLocation + if( $testResult -ne $resultFail) { + $testResult=$resultPass + } + } catch { + $ErrorMessage = $_.Exception.Message + $ErrorLine = $_.InvocationInfo.ScriptLineNumber + LogErr "$ErrorMessage at line: $ErrorLine" + } finally { + if (!$testResult) { + $testResult = $resultAborted + } + $resultArr += $testResult + } + $currentTestResult.TestResult = GetFinalResultHeader -resultarr $resultArr + return $currentTestResult.TestResult +} +Main -TestParams (ConvertFrom-StringData $TestParams.Replace(";","`n")) diff --git a/XML/TestCases/FunctionalTests.xml b/XML/TestCases/FunctionalTests.xml index 2cce252ec..b0bd1f398 100644 --- a/XML/TestCases/FunctionalTests.xml +++ b/XML/TestCases/FunctionalTests.xml @@ -1202,6 +1202,21 @@ SECUREBOOT secureboot + + SECUREBOOT-VSS + .\TestScripts\Windows\SET-SECUREBOOT.ps1,.\Testscripts\Windows\SETUP-Backup-DISK.ps1 + STOR-VSS-BACKUP-RESTORE-PARTITION.ps1 + .\Testscripts\Linux\utils.sh,.\Testscripts\Linux\STOR_VSS_Check_VSS_Daemon.sh + SingleVM + + secureBootVM=True + + .\TestScripts\Windows\CLEANUP-Backup-DISK.ps1 + HyperV + Functional + SECUREBOOT + secureboot + PRODUCTION-CHECKPOINT-FAILBACK PRODUCTION-CHECKPOINT-FAILBACK.ps1 diff --git a/XML/TestCases/SmokeTests.xml b/XML/TestCases/SmokeTests.xml index 43099a752..e67289206 100644 --- a/XML/TestCases/SmokeTests.xml +++ b/XML/TestCases/SmokeTests.xml @@ -9,6 +9,21 @@ default bvt + + VERIFY-DEPLOYMENT-PROVISION-EPHEMERAL-MANAGED-DISK + BVT-VERIFY-DEPLOYMENT-PROVISION.ps1 + + SingleVM + Standard_DS1_v2 + + Managed + Ephemeral + + Azure + Smoke + default + ephemeral_os_disk + VERIFY-DEPLOYMENT-PROVISION-SRIOV BVT-VERIFY-DEPLOYMENT-PROVISION.ps1