Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -190,5 +190,12 @@ public void TestSimpleGalleryCrossTenant()
{
TestRunner.RunTestScript("Test-SimpleGalleryCrossTenant");
}

[Fact]
[Trait(Category.AcceptanceType, Category.CheckIn)]
public void TestSimpleNewVmDeprecatedImageWarning()
{
TestRunner.RunTestScript("Test-SimpleNewVmDeprecatedImageWarning");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -695,3 +695,40 @@ function Test-SimpleGalleryCrossTenant
Clean-ResourceGroup $vmname
}
}


<#
.SYNOPSIS
Test that creating a VM with a deprecated marketplace image emits a deprecation warning
and still successfully creates the VM.
#>
function Test-SimpleNewVmDeprecatedImageWarning
{
# Setup
$vmname = Get-ResourceName

try
{
$username = "admin01"
$password = Get-PasswordForVM | ConvertTo-SecureString -AsPlainText -Force
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $password
[string]$domainNameLabel = "$vmname-$vmname".tolower();
$stnd = "Standard";

# Use a specific image version format (publisher:offer:sku:version) to exercise the
# deprecation check code path. The image used here should be a deprecated image
# to verify that a warning is emitted but VM creation proceeds successfully.
# Note: Replace the image below with a known deprecated image when recording this test.
$image = "MicrosoftWindowsServer:WindowsServer:2022-datacenter:latest"

$x = New-AzVM -Name $vmname -Credential $cred -DomainNameLabel $domainNameLabel -Image $image -SecurityType $stnd

Assert-AreEqual $vmname $x.Name;
Assert-NotNull $x.Id;
}
finally
{
# Cleanup
Clean-ResourceGroup $vmname
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,5 +137,12 @@ public void SimpleNewVmssSkipExtOverprovision()
{
TestRunner.RunTestScript("Test-SimpleNewVmssSkipExtOverprovision");
}

[Fact]
[Trait(Category.AcceptanceType, Category.CheckIn)]
public void TestSimpleNewVmssDeprecatedImageWarning()
{
TestRunner.RunTestScript("Test-SimpleNewVmssDeprecatedImageWarning");
}
}
}
38 changes: 38 additions & 0 deletions src/Compute/Compute.Test/ScenarioTests/StrategiesVmssTests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -551,3 +551,41 @@ function Test-SimpleNewVmssSkipExtOverprovision
Clean-ResourceGroup $vmssname
}
}

<#
.SYNOPSIS
Test that creating a VMSS with a deprecated marketplace image emits a deprecation warning
and still successfully creates the VMSS.
#>
function Test-SimpleNewVmssDeprecatedImageWarning
{
# Setup
$vmssname = Get-ResourceName

try
{
$lbName = $vmssname + "LoadBalancer"
$username = "admin01"
$password = Get-PasswordForVM | ConvertTo-SecureString -AsPlainText -Force
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $password
[string]$domainNameLabel = "$vmssname$vmssname".tolower();
$stnd = "Standard";

# Use a specific image version format (publisher:offer:sku:version) to exercise the
# deprecation check code path. The image used here should be a deprecated image
# to verify that a warning is emitted but VMSS creation proceeds successfully.
# Note: Replace the image below with a known deprecated image when recording this test.
$image = "MicrosoftWindowsServer:WindowsServer:2022-datacenter:latest"

$x = New-AzVmss -Name $vmssname -Credential $cred -DomainNameLabel $domainNameLabel -LoadBalancerName $lbName -ImageName $image -SecurityType $stnd

Assert-AreEqual $vmssname $x.Name;
Assert-AreEqual $vmssname $x.ResourceGroupName;
Assert-NotNull $x.Id;
}
finally
{
# Cleanup
Clean-ResourceGroup $vmssname
}
}
3 changes: 3 additions & 0 deletions src/Compute/Compute/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@

-->
## Upcoming Release
* Added deprecation warning for `New-AzVM` and `New-AzVmss` when the specified marketplace image is deprecated or scheduled for deprecation
- A warning is emitted when the image state is 'Deprecated' or 'ScheduledForDeprecation'
- VM and VMSS creation proceeds normally after the warning

## Version 11.4.0
* Added `-DiskIOPSReadWrite` and `-DiskMBpsReadWrite` parameters to `Add-AzVMDataDisk` cmdlet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,13 +342,37 @@ private VirtualMachineScaleSet BuildVirtualMachineScaleSetParameters()
ComputeAutomationAutoMapperProfile.Mapper.Map<PSVirtualMachineScaleSet, VirtualMachineScaleSet>(this.VirtualMachineScaleSet, parameters);

CheckImageVersionWarning(parameters);
CheckAndWarnMarketplaceImageDeprecation();
SetDefaultOrchestrationMode(parameters);
ConfigureFlexibleOrchestrationMode(parameters);
ConfigureSecuritySettings(parameters);

return parameters;
}

private void CheckAndWarnMarketplaceImageDeprecation()
{
var imageRef = this.VirtualMachineScaleSet?.VirtualMachineProfile?.StorageProfile?.ImageReference;
if (imageRef == null
|| string.IsNullOrEmpty(imageRef.Publisher)
|| string.IsNullOrEmpty(imageRef.Offer)
|| string.IsNullOrEmpty(imageRef.Sku)
|| string.IsNullOrEmpty(imageRef.Version))
{
return;
}

try
{
var imgResponse = retrieveSpecificImageFromNotId();
WarnIfImageDeprecated(imgResponse?.Body?.ImageDeprecationStatus);
}
catch
{
// Ignore errors during deprecation check to not block VMSS creation
}
}

private void CheckImageVersionWarning(VirtualMachineScaleSet parameters)
{
if (parameters?.VirtualMachineProfile?.StorageProfile?.ImageReference?.Version?.ToLower() != ImageVersions.Latest)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ private async Task<ResourceConfig<VirtualMachineScaleSet>> SimpleParameterSetNor
ImageAndOsType = await _client.UpdateImageAndOsTypeAsync(
ImageAndOsType, _cmdlet.ResourceGroupName, _cmdlet.ImageName, Location);

_cmdlet.WarnIfImageDeprecated(ImageAndOsType);

// generate a domain name label if it's not specified.
_cmdlet.DomainNameLabel = await PublicIPAddressStrategy.UpdateDomainNameLabelAsync(
Expand Down Expand Up @@ -604,6 +605,8 @@ private async Task<ResourceConfig<VirtualMachineScaleSet>> SimpleParameterSetOrc
ImageAndOsType = await _client.UpdateImageAndOsTypeAsync(
ImageAndOsType, _cmdlet.ResourceGroupName, _cmdlet.ImageName, Location);

_cmdlet.WarnIfImageDeprecated(ImageAndOsType);

// generate a domain name label if it's not specified.
_cmdlet.DomainNameLabel = await PublicIPAddressStrategy.UpdateDomainNameLabelAsync(
domainNameLabel: _cmdlet.DomainNameLabel,
Expand Down Expand Up @@ -886,5 +889,33 @@ private VirtualMachineScaleSetIdentity GetVmssIdentityFromArgs()
}
: null;
}

/// <summary>
/// Emits a warning if the provided ImageAndOsType indicates the image is deprecated or scheduled for deprecation.
/// </summary>
internal void WarnIfImageDeprecated(ImageAndOsType imageAndOsType)
{
WarnIfImageDeprecated(imageAndOsType?.ImageDeprecationStatus);
}

/// <summary>
/// Emits a warning if the provided ImageDeprecationStatus indicates the image is deprecated or scheduled for deprecation.
/// </summary>
internal void WarnIfImageDeprecated(ImageDeprecationStatus deprecationStatus)
{
if (deprecationStatus == null)
{
return;
}

if (string.Equals(deprecationStatus.ImageState, ImageState.Deprecated, StringComparison.OrdinalIgnoreCase))
{
WriteWarning("This image is deprecated. VM created from this image might not be supported and VM creation might be blocked in the near future. Please select the latest image that is supported instead.");
}
else if (string.Equals(deprecationStatus.ImageState, ImageState.ScheduledForDeprecation, StringComparison.OrdinalIgnoreCase))
{
WriteWarning("This image is scheduled for deprecation. VM created from this image might not be supported in the near future. Please consider selecting the latest supported image instead.");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@ sealed class ImageAndOsType

public IList<int> DataDiskLuns { get; }

public ImageAndOsType(OperatingSystemTypes osType, ImageReference image, IList<int> dataDiskLuns)
public ImageDeprecationStatus ImageDeprecationStatus { get; }

public ImageAndOsType(OperatingSystemTypes osType, ImageReference image, IList<int> dataDiskLuns, ImageDeprecationStatus imageDeprecationStatus = null)
{
OsType = osType;
Image = image;
DataDiskLuns = dataDiskLuns;
ImageDeprecationStatus = imageDeprecationStatus;
}
}
}
3 changes: 2 additions & 1 deletion src/Compute/Compute/Strategies/ComputeRp/ImageEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ public static async Task<ImageAndOsType> UpdateImageAndOsTypeAsync(
return new ImageAndOsType(
imageModel.OsDiskImage.OperatingSystem,
image,
imageModel.DataDiskImages.GetLuns());
imageModel.DataDiskImages.GetLuns(),
imageModel.ImageDeprecationStatus);
}
else if (imageName.Contains("/"))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,7 @@ public async Task<ResourceConfig<VirtualMachine>> CreateConfigAsync()
{
ImageAndOsType = await _client.UpdateImageAndOsTypeAsync(
ImageAndOsType, _cmdlet.ResourceGroupName, _cmdlet.Image, Location);
_cmdlet.WarnIfImageDeprecated(ImageAndOsType);
}

_cmdlet.DomainNameLabel = await PublicIPAddressStrategy.UpdateDomainNameLabelAsync(
Expand Down Expand Up @@ -968,6 +969,9 @@ public void DefaultExecuteCmdlet()
SetDefaultUefiSettings();
}

// Check if the marketplace image is deprecated and warn the user
CheckAndWarnMarketplaceImageDeprecation();

if (ShouldProcess(this.VM.Name, VerbsCommon.New))
{
ExecuteClientAction(() =>
Expand Down Expand Up @@ -1751,5 +1755,60 @@ private void ValidateVmParameters()
ValidateSshKeyConfiguration();
ValidateEncryptionIdentityConfiguration();
}

/// <summary>
/// Emits a warning if the provided ImageAndOsType indicates the image is deprecated or scheduled for deprecation.
/// </summary>
internal void WarnIfImageDeprecated(ImageAndOsType imageAndOsType)
{
WarnIfImageDeprecated(imageAndOsType?.ImageDeprecationStatus);
}

/// <summary>
/// Emits a warning if the provided ImageDeprecationStatus indicates the image is deprecated or scheduled for deprecation.
/// </summary>
internal void WarnIfImageDeprecated(ImageDeprecationStatus deprecationStatus)
{
if (deprecationStatus == null)
{
return;
}

if (string.Equals(deprecationStatus.ImageState, ImageState.Deprecated, StringComparison.OrdinalIgnoreCase))
{
WriteWarning("This image is deprecated. VM created from this image might not be supported and VM creation might be blocked in the near future. Please select the latest image that is supported instead.");
}
else if (string.Equals(deprecationStatus.ImageState, ImageState.ScheduledForDeprecation, StringComparison.OrdinalIgnoreCase))
{
WriteWarning("This image is scheduled for deprecation. VM created from this image might not be supported in the near future. Please consider selecting the latest supported image instead.");
}
}

/// <summary>
/// Checks the marketplace image reference for deprecation status and emits a warning if deprecated.
/// Used for the DefaultParameterSet where the image is specified via VM.StorageProfile.ImageReference.
/// </summary>
private void CheckAndWarnMarketplaceImageDeprecation()
{
var imageRef = this.VM?.StorageProfile?.ImageReference;
if (imageRef == null
|| string.IsNullOrEmpty(imageRef.Publisher)
|| string.IsNullOrEmpty(imageRef.Offer)
|| string.IsNullOrEmpty(imageRef.Sku)
|| string.IsNullOrEmpty(imageRef.Version))
{
return;
}

try
{
var imgResponse = retrieveSpecificImageFromNotId();
WarnIfImageDeprecated(imgResponse?.Body?.ImageDeprecationStatus);
}
catch
{
// Ignore errors during deprecation check to not block VM creation
}
}
}
}
Loading