Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actions/spelling/expect.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
aab

Check warning on line 1 in .github/actions/spelling/expect.txt

View workflow job for this annotation

GitHub Actions / Check Spelling

Skipping `.github/actions/spelling/expect.txt` because it seems to have more noise (376) than unique words (1) (total: 377 / 1). (noisy-file)
AAFFBB
aarch
abe
Expand Down Expand Up @@ -146,6 +146,7 @@
Ioctl
iusr
jetbrains
jqlang
JOBOBJECT
jobsjob
joutvhu
Expand Down Expand Up @@ -374,3 +375,3 @@
xxxx
xxxxxxxx
xxxxxxxxxxx
Expand Down
4 changes: 2 additions & 2 deletions e2etest/GuestProxyAgentTest/GuestProxyAgentTest.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

<ItemGroup>
<PackageReference Include="Azure.Identity" Version="1.11.4" />
<PackageReference Include="Azure.ResourceManager" Version="1.13.0" />
<PackageReference Include="Azure.ResourceManager.Compute" Version="1.9" />
<PackageReference Include="Azure.ResourceManager" Version="1.13.2" />
<PackageReference Include="Azure.ResourceManager.Compute" Version="1.13.0" />
<PackageReference Include="Azure.ResourceManager.Network" Version="1.9" />
<PackageReference Include="Azure.ResourceManager.Resources" Version="1.9" />
<PackageReference Include="Azure.ResourceManager.Storage" Version="1.1.1" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
# SPDX-License-Identifier: MIT

customOutputJsonUrl=$(echo $customOutputJsonSAS | base64 -d)
expectedSecureChannelState=$(echo $expectedSecureChannelState)

echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - Start Guest Proxy Agent Validation"
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - expectedSecureChannelState=$expectedSecureChannelState"

currentDir=$(pwd)
customOutputJsonPath=$currentDir/proxyagentvalidation.json

Expand Down Expand Up @@ -47,12 +50,104 @@ else
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - logdir does not exist"
fi

echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - detecting os and installing jq"
os=$(hostnamectl | grep "Operating System")
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - os=$os"
if [[ $os == *"Ubuntu"* ]]; then
for i in {1..3}; do
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - start installing jq via apt-get $i"
sudo apt update
sudo apt-get install -y jq
sleep 10
install=$(apt list --installed jq)
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - install=$install"
if [[ $install == *"jq"* ]]; then
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - jq installed successfully"
break
fi
done
elif [[ $os == *"SUSE"* ]]; then
# SUSE repo does not have jq package, so we download jq binary directly
# Detect architecture
arch=$(uname -m)
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - detected architecture: $arch"
if [[ $arch == "x86_64" ]]; then
jq_binary="jq-linux-amd64"
elif [[ $arch == "aarch64" ]] || [[ $arch == "arm64" ]]; then
jq_binary="jq-linux-arm64"
else
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - unsupported architecture: $arch"
jq_binary="jq-linux64"
fi
# Download jq binary directly from GitHub
for i in {1..3}; do
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - downloading $jq_binary binary (attempt $i)"
sudo curl -L https://github.com/jqlang/jq/releases/download/jq-1.8.1/$jq_binary -o /usr/local/bin/jq
if [ $? -eq 0 ]; then
sudo chmod +x /usr/local/bin/jq
if command -v jq &> /dev/null; then
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - jq installed successfully"
jq --version
break
fi
fi
sleep 5
done
else
for i in {1..3}; do
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - start installing jq via dnf $i"
sudo dnf -y install jq
sleep 10
install=$(dnf list --installed jq)
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - install=$install"
if [[ $install == *"jq"* ]]; then
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - jq installed successfully"
break
fi
done
fi

# check status.json file Content
## check timestamp of last entry in status.json file
## check the secure channel status
timeout=300
elapsed=0
statusFile=$logdir/status.json
secureChannelState=""

# Current UTC time in epoch seconds
currentUtcTime=$(date -u +%s)
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - Checking GPA status file $statusFile with 5 minute timeout"
while :; do
timestamp=$(cat "$statusFile" | jq -r '.timestamp')
# Convert timestamp to epoch seconds
timestampEpoch=$(date -u -d "$timestamp" +%s)
if ((timestampEpoch > currentUtcTime)); then
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - The last entry timestamp '$timestamp' is valid."
## check secure channel status
secureChannelState=$(cat "$statusFile" | jq -r '.proxyAgentStatus.keyLatchStatus.states.secureChannelState')
if [[ "$secureChannelState" == "$expectedSecureChannelState" ]]; then
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - The secure channel status '$secureChannelState' matches the expected state: '$expectedSecureChannelState'."
break
else
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - The secure channel status '$secureChannelState' does not match the expected state: '$expectedSecureChannelState'."
fi
fi
((elapsed += 3))
if [[ $elapsed -ge $timeout ]]; then
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - Timeout reached. Error, The secureChannelState is '$secureChannelState'."
break
fi
sleep 3
done

echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - guestProxyAgentServiceExist=$guestProxyAgentServiceExist"
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - guestProxyAgentServiceStatus=$guestProxyAgentServiceStatus"
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - guestProxyProcessStarted=$guestProxyProcessStarted"
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - guestProxyAgentLogGenerated=$guestProxyAgentLogGenerated"
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - secureChannelState=$secureChannelState"

jsonString='{"guestProxyAgentServiceInstalled": "'$guestProxyAgentServiceExist'", "guestProxyAgentServiceStatus": "'$guestProxyAgentServiceStatus'", "guestProxyProcessStarted": "'$guestProxyProcessStarted'", "guestProxyAgentLogGenerated": "'$guestProxyAgentLogGenerated'"}'
jsonString='{"guestProxyAgentServiceInstalled": "'$guestProxyAgentServiceExist'", "guestProxyAgentServiceStatus": "'$guestProxyAgentServiceStatus'", "guestProxyProcessStarted": "'$guestProxyProcessStarted'", "secureChannelState": "'$secureChannelState'", "guestProxyAgentLogGenerated": "'$guestProxyAgentLogGenerated'"}'
echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - $jsonString"

# write to $customOutputJsonPath
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

param (
[Parameter(Mandatory=$true, Position=0)]
[string]$customOutputJsonSAS,
[string]$customOutputJsonSAS,
[string]$expectedProxyAgentVersion
)
Write-Output "$((Get-Date).ToUniversalTime()) - expectedProxyAgentVersion=$expectedProxyAgentVersion"
Expand Down
50 changes: 47 additions & 3 deletions e2etest/GuestProxyAgentTest/Scripts/GuestProxyAgentValidation.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@

param (
[Parameter(Mandatory=$true, Position=0)]
[string]$customOutputJsonSAS
[string]$customOutputJsonSAS,
[string]$expectedSecureChannelState
)

$decodedUrlBytes = [System.Convert]::FromBase64String($customOutputJsonSAS)
$decodedUrlString = [System.Text.Encoding]::UTF8.GetString($decodedUrlBytes)

Write-Output "$((Get-Date).ToUniversalTime()) - Start Guest Proxy Agent Validation"
Write-Output "$((Get-Date).ToUniversalTime()) - expectedSecureChannelState=$expectedSecureChannelState"

$currentFolder = $PWD.Path
$customOutputJsonPath = $currentFolder + "\proxyagentvalidation.json";
Expand All @@ -21,7 +23,7 @@ $guestProxyAgentServiceExist = $true
$guestProxyAgentServiceStatus = ""
$guestProxyAgentProcessExist = $true

if ($service -ne $null) {
if ($null -ne $service) {
Write-Output "$((Get-Date).ToUniversalTime()) - The service $serviceName exists."
$guestProxyAgentServiceStatus = $service.Status
} else {
Expand All @@ -34,7 +36,7 @@ $processName = "GuestProxyAgent"

$process = Get-Process -Name $processName -ErrorAction SilentlyContinue

if ($process -ne $null) {
if ($null -ne $process) {
Write-Output "$((Get-Date).ToUniversalTime()) - The process $processName exists."
} else {
$guestProxyAgentProcessExist = $false
Expand All @@ -57,10 +59,52 @@ if (Test-Path -Path $folderPath -PathType Container) {
Write-Output "$((Get-Date).ToUniversalTime()) - The folder $folderPath does not exist."
}

# check status.json file Content
## check timestamp of last entry in status.json file
## check the secure channel status
$timeoutInSeconds = 300
$statusFilePath = [IO.Path]::Combine($folderPath, "status.json")
Write-Output "$((Get-Date).ToUniversalTime()) - Checking GPA status file $statusFilePath with 5 minute timeout"
$secureChannelState = ""
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$currentUtcTime = (Get-Date).ToUniversalTime()
do {
$boolStatus = Test-Path -Path $statusFilePath
if ($boolStatus) {
$json = Get-Content $statusFilePath | Out-String | ConvertFrom-Json
$timestamp = $json.timestamp
if ($null -ne $timestamp -and $timestamp -ne "") {
Write-Output "$((Get-Date).ToUniversalTime()) - The status.json file contains a valid timestamp: $timestamp"
# parse the timestamp to UTC DateTime object, if must later than $currentUtcTime
$timestampDateTime = [DateTime]::Parse($timestamp).ToUniversalTime()
if ($timestampDateTime -gt $currentUtcTime) {
Write-Output "$((Get-Date).ToUniversalTime()) - The status.json timestamp $timestampDateTime is later than $currentUtcTime."
## check secure channel status
$secureChannelState = $json.proxyAgentStatus.keyLatchStatus.states.secureChannelState
Write-Output "$((Get-Date).ToUniversalTime()) - The secure channel status is $secureChannelState."
if ($secureChannelState -eq $expectedSecureChannelState) {
Write-Output "$((Get-Date).ToUniversalTime()) - The secure channel status '$secureChannelState' matches the expected state: '$expectedSecureChannelState'."
# break
} else {
Write-Output "$((Get-Date).ToUniversalTime()) - The secure channel status '$secureChannelState' does not match the expected state: '$expectedSecureChannelState'."
}

if ($stopwatch.Elapsed.TotalSeconds -ge $timeoutInSeconds) {
Write-Output "$((Get-Date).ToUniversalTime()) - Timeout reached. Error, The secureChannelState is '$secureChannelState'."
break
}
}
} else {
Write-Output "$((Get-Date).ToUniversalTime()) - The status.json file does not contain a valid timestamp yet."
}
}
start-sleep -Seconds 3
} until ($false)

$jsonString = '{"guestProxyAgentServiceInstalled": ' + $guestProxyAgentServiceExist.ToString().ToLower() `
+ ', "guestProxyProcessStarted": ' + $guestProxyAgentProcessExist.ToString().ToLower() `
+ ', "guestProxyAgentServiceStatus": "' + $guestProxyAgentServiceStatus `
+ '", "secureChannelState": "' + $secureChannelState `
+ '", "guestProxyAgentLogGenerated": ' + $guestProxyAgentLogGenerated.ToString().ToLower() + '}'

Write-Output "$((Get-Date).ToUniversalTime()) - $jsonString"
Expand Down
3 changes: 0 additions & 3 deletions e2etest/GuestProxyAgentTest/Settings/TestSetting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
using Azure.Core;
using GuestProxyAgentTest.Models;
using GuestProxyAgentTest.Utilities;
using Newtonsoft.Json;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text.Json.Serialization;

namespace GuestProxyAgentTest.Settings
{
Expand Down
27 changes: 21 additions & 6 deletions e2etest/GuestProxyAgentTest/TestCases/EnableProxyAgentCase.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
using Azure.ResourceManager.Compute.Models;
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
//
using Azure.ResourceManager.Compute.Models;
using GuestProxyAgentTest.Models;
using GuestProxyAgentTest.Settings;
using GuestProxyAgentTest.TestScenarios;
using GuestProxyAgentTest.Utilities;
using Newtonsoft.Json;
using System.Xml.Linq;

namespace GuestProxyAgentTest.TestCases
{
internal class EnableProxyAgentCase : TestCaseBase
{
public EnableProxyAgentCase() : this("EnableProxyAgentCase", true)
public EnableProxyAgentCase() : this("EnableProxyAgentCase", true, false)
{ }
public EnableProxyAgentCase(string testCaseName) : this(testCaseName, true)
public EnableProxyAgentCase(string testCaseName) : this(testCaseName, true, false)
{ }

public EnableProxyAgentCase(string testCaseName, bool enableProxyAgent) : base(testCaseName)
public EnableProxyAgentCase(string testCaseName, bool enableProxyAgent, bool addProxyAgentExtensionForLinuxVM) : base(testCaseName)
{
EnableProxyAgent = enableProxyAgent;
AddProxyAgentVMExtension = addProxyAgentExtensionForLinuxVM;
}

internal bool EnableProxyAgent { get; set; }

internal bool AddProxyAgentVMExtension { get; set; } = false;

public override async Task StartAsync(TestCaseExecutionContext context)
{
var vmr = context.VirtualMachineResource;
Expand All @@ -34,16 +42,23 @@ public override async Task StartAsync(TestCaseExecutionContext context)
}
}
};
// Only Linux VMs support flag 'AddProxyAgentExtension',
// Windows VMs always have the GPA VM Extension installed when ProxyAgentSettings.Enabled is true.
if (!Constants.IS_WINDOWS())
{
patch.SecurityProfile.ProxyAgentSettings.AddProxyAgentExtension = AddProxyAgentVMExtension;
}

if (EnableProxyAgent)
{
// property 'inVMAccessControlProfileReferenceId' cannot be used together with property 'mode'
patch.SecurityProfile.ProxyAgentSettings.WireServer = new HostEndpointSettings
{
InVmAccessControlProfileReferenceId = TestSetting.Instance.InVmWireServerAccessControlProfileReferenceId
InVmAccessControlProfileReferenceId = TestSetting.Instance.InVmWireServerAccessControlProfileReferenceId,
};
patch.SecurityProfile.ProxyAgentSettings.Imds = new HostEndpointSettings
{
InVmAccessControlProfileReferenceId = TestSetting.Instance.InVmIMDSAccessControlProfileReferenceId
InVmAccessControlProfileReferenceId = TestSetting.Instance.InVmIMDSAccessControlProfileReferenceId,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class GuestProxyAgentValidationCase : TestCaseBase
{

private static readonly string EXPECTED_GUEST_PROXY_AGENT_SERVICE_STATUS;
private string expectedSecureChannelState = "disabled";
static GuestProxyAgentValidationCase()
{
if (Constants.IS_WINDOWS())
Expand All @@ -28,9 +29,16 @@ static GuestProxyAgentValidationCase()
public GuestProxyAgentValidationCase() : base("GuestProxyAgentValidationCase")
{ }

public GuestProxyAgentValidationCase(string testCaseName, string expectedSecureChannelState) : base(testCaseName)
{
this.expectedSecureChannelState = expectedSecureChannelState;
}

public override async Task StartAsync(TestCaseExecutionContext context)
{
context.TestResultDetails = (await RunScriptViaRunCommandV2Async(context, Constants.GUEST_PROXY_AGENT_VALIDATION_SCRIPT_NAME, null!)).ToTestResultDetails(ConsoleLog);
List<(string, string)> parameterList = new List<(string, string)>();
parameterList.Add(("expectedSecureChannelState", expectedSecureChannelState));
context.TestResultDetails = (await RunScriptViaRunCommandV2Async(context, Constants.GUEST_PROXY_AGENT_VALIDATION_SCRIPT_NAME, parameterList)).ToTestResultDetails(ConsoleLog);
if (context.TestResultDetails.Succeed && context.TestResultDetails.CustomOut != null)
{
var validationDetails = context.TestResultDetails.SafeDeserializedCustomOutAs<GuestProxyAgentValidationDetails>();
Expand All @@ -40,7 +48,8 @@ public override async Task StartAsync(TestCaseExecutionContext context)
&& validationDetails.GuestProxyAgentServiceInstalled
&& validationDetails.GuestProxyAgentServiceStatus.Equals(EXPECTED_GUEST_PROXY_AGENT_SERVICE_STATUS, StringComparison.OrdinalIgnoreCase)
&& validationDetails.GuestProxyProcessStarted
&& validationDetails.GuestProxyAgentLogGenerated)
&& validationDetails.GuestProxyAgentLogGenerated
&& validationDetails.SecureChannelState.Equals(expectedSecureChannelState, StringComparison.OrdinalIgnoreCase))
{
context.TestResultDetails.Succeed = true;
}
Expand All @@ -58,5 +67,6 @@ class GuestProxyAgentValidationDetails
public bool GuestProxyProcessStarted { get; set; }
public bool GuestProxyAgentLogGenerated { get; set; }
public string GuestProxyAgentServiceStatus { get; set; } = null!;
public string SecureChannelState { get; set; } = null!;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ scenarios:
- name: LinuxPackageScenario
className: GuestProxyAgentTest.TestScenarios.LinuxPackageScenario
- name: ProxyAgentExtension
className: GuestProxyAgentTest.TestScenarios.ProxyAgentExtension
className: GuestProxyAgentTest.TestScenarios.ProxyAgentExtension
- name: LinuxImplicitExtension
className: GuestProxyAgentTest.TestScenarios.LinuxImplicitExtension
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ scenarios:
- name: LinuxPackageScenario
className: GuestProxyAgentTest.TestScenarios.LinuxPackageScenario
- name: ProxyAgentExtension
className: GuestProxyAgentTest.TestScenarios.ProxyAgentExtension
className: GuestProxyAgentTest.TestScenarios.ProxyAgentExtension
- name: LinuxImplicitExtension
className: GuestProxyAgentTest.TestScenarios.LinuxImplicitExtension
1 change: 0 additions & 1 deletion e2etest/GuestProxyAgentTest/TestMap/Test-Map-Linux.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
testGroupList:
- include: AzureLinux3-Fips-TestGroup.yml
- include: Mariner2-Fips-TestGroup.yml
- include: Ubuntu24-TestGroup.yml
- include: Ubuntu22-TestGroup.yml
- include: Ubuntu20-TestGroup.yml
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ scenarios:
- name: LinuxPackageScenario
className: GuestProxyAgentTest.TestScenarios.LinuxPackageScenario
- name: ProxyAgentExtension
className: GuestProxyAgentTest.TestScenarios.ProxyAgentExtension
className: GuestProxyAgentTest.TestScenarios.ProxyAgentExtension
- name: LinuxImplicitExtension
className: GuestProxyAgentTest.TestScenarios.LinuxImplicitExtension
4 changes: 3 additions & 1 deletion e2etest/GuestProxyAgentTest/TestMap/Ubuntu24-TestGroup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ scenarios:
- name: LinuxPackageScenario
className: GuestProxyAgentTest.TestScenarios.LinuxPackageScenario
- name: ProxyAgentExtension
className: GuestProxyAgentTest.TestScenarios.ProxyAgentExtension
className: GuestProxyAgentTest.TestScenarios.ProxyAgentExtension
- name: LinuxImplicitExtension
className: GuestProxyAgentTest.TestScenarios.LinuxImplicitExtension
Loading
Loading