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
9 changes: 9 additions & 0 deletions src/ServiceFabric/ServiceFabric/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@
-->
## Upcoming Release
* Updated SFMC to latest api general version "2026-02-01"
* Fixed `Set-AzServiceFabricManagedClusterApplication` to use correct resource completer for managed clusters instead of classic clusters.
* Added parameters `-IdentityType`, `-UserAssignedIdentityId`, and `-ApplicationManagedIdentity` to `New-AzServiceFabricManagedClusterApplication` to support managed identity configuration on applications.
* Added parameters `-IdentityType`, `-UserAssignedIdentityId`, and `-ApplicationManagedIdentity` to `Set-AzServiceFabricManagedClusterApplication` to support managed identity configuration on applications.
* Added parameters `-AzureActiveDirectoryClientApplication`, `-AzureActiveDirectoryClusterApplication`, `-AzureActiveDirectoryTenantId`, `-EnableHttpGatewayExclusiveAuthMode`, `-HttpGatewayTokenAuthConnectionPort`, `-MaxPercentUnhealthyApplications`, `-MaxPercentUnhealthyNodes`, `-MaxUnusedVersionsToKeep`, `-AddonFeature`, `-DdosProtectionPlanId`, `-EnableIpv6`, `-EnableServicePublicIP`, `-PublicIPPrefixId`, `-PublicIPv6PrefixId`, `-SubnetId`, `-UseCustomVnet`, `-VMImage`, `-AllocatedOutboundPort`, `-EnableOutboundOnlyNodeTypes`, and `-SkipManagedNsgAssignment` to `New-AzServiceFabricManagedCluster`.
* Added parameters `-AzureActiveDirectoryClientApplication`, `-AzureActiveDirectoryClusterApplication`, `-AzureActiveDirectoryTenantId`, `-EnableHttpGatewayExclusiveAuthMode`, `-HttpGatewayTokenAuthConnectionPort`, `-MaxPercentUnhealthyApplications`, `-MaxPercentUnhealthyNodes`, `-MaxUnusedVersionsToKeep`, `-AddonFeature`, `-DdosProtectionPlanId`, `-PublicIPPrefixId`, `-PublicIPv6PrefixId`, `-VMImage`, `-AllocatedOutboundPort`, `-EnableOutboundOnlyNodeTypes`, and `-SkipManagedNsgAssignment` to `Set-AzServiceFabricManagedCluster`.
* Enabled `Manual` option for the `-UpgradeMode` parameter in `Set-AzServiceFabricManagedCluster`.
* Added parameters `-IsOutboundOnly`, `-EnableResilientEphemeralOSDisk`, `-EnableAcceleratedNetworking`, `-EnableEncryptionAtHost`, `-EnableNodePublicIP`, `-EnableNodePublicIPv6`, `-SecureBootEnabled`, and `-UseEphemeralOSDisk` to `New-AzServiceFabricManagedNodeType`.
* Added parameters `-IsOutboundOnly`, `-EnableResilientEphemeralOSDisk`, `-EnableAcceleratedNetworking`, `-EnableEncryptionAtHost`, `-EnableNodePublicIP`, `-EnableNodePublicIPv6`, `-SecureBootEnabled`, and `-UseEphemeralOSDisk` to `Set-AzServiceFabricManagedNodeType`.
* Added parameter `-ServiceDnsName` to `New-AzServiceFabricManagedClusterService` for DNS-based service discovery.

## Version 5.0.0
* Removed `ReimageByName`, `ReimageById`, and `ReimageByObj` parameter sets from `Set-AzServiceFabricManagedNodeType`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters;
using Microsoft.Azure.Commands.ServiceFabric.Common;
using Microsoft.Azure.Commands.ServiceFabric.Models;
using Microsoft.Azure.Management.ServiceFabricManagedClusters;
using Microsoft.Azure.Management.ServiceFabricManagedClusters.Models;
using Microsoft.WindowsAzure.Commands.Utilities.Common;

namespace Microsoft.Azure.Commands.ServiceFabric.Commands
{
Expand Down Expand Up @@ -87,6 +89,30 @@ public class NewAzServiceFabricManagedClusterApplication : ManagedApplicationCmd
[Parameter(Mandatory = false, ValueFromPipeline = true, ParameterSetName = CreateAppTypeVersion, HelpMessage = "Specify the tags as key/value pairs.")]
public Hashtable Tag { get; set; }

#region Identity params

[Parameter(Mandatory = false, ParameterSetName = SkipAppTypeVersion,
HelpMessage = "Specify the type of managed identity for the application. Options are None, SystemAssigned, UserAssigned, and SystemAssigned,UserAssigned.")]
[Parameter(Mandatory = false, ParameterSetName = CreateAppTypeVersion,
HelpMessage = "Specify the type of managed identity for the application. Options are None, SystemAssigned, UserAssigned, and SystemAssigned,UserAssigned.")]
public ManagedIdentityType IdentityType { get; set; }
Comment on lines +94 to +98
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New identity parameters are added to New-AzServiceFabricManagedClusterApplication, but existing scenario tests don't cover identity creation paths. Add scenario coverage that creates an application with identity settings and validates the resulting identity fields.

Copilot generated this review using guidance from repository custom instructions.

[Parameter(Mandatory = false, ParameterSetName = SkipAppTypeVersion,
HelpMessage = "Specify the list of user assigned identity ARM resource IDs for the application.")]
[Parameter(Mandatory = false, ParameterSetName = CreateAppTypeVersion,
HelpMessage = "Specify the list of user assigned identity ARM resource IDs for the application.")]
[ValidateNotNullOrEmpty]
public string[] UserAssignedIdentityId { get; set; }

[Parameter(Mandatory = false, ParameterSetName = SkipAppTypeVersion,
HelpMessage = "Specify the application managed identities as key/value pairs. The key is the friendly identity name, and the value is the principal id.")]
[Parameter(Mandatory = false, ParameterSetName = CreateAppTypeVersion,
HelpMessage = "Specify the application managed identities as key/value pairs. The key is the friendly identity name, and the value is the principal id.")]
[ValidateNotNullOrEmpty]
public Hashtable ApplicationManagedIdentity { get; set; }

#endregion

[Parameter(Mandatory = false, HelpMessage = "Continue without prompts")]
public SwitchParameter Force { get; set; }

Expand Down Expand Up @@ -168,9 +194,43 @@ private ApplicationResource GetNewAppParameters(string location)
version: this.GetAppTypeArmResourceId(this.DefaultContext.Subscription.Id, this.ResourceGroupName, this.ClusterName, this.ApplicationTypeName, this.ApplicationTypeVersion),
parameters: this.ApplicationParameter?.Cast<DictionaryEntry>().ToDictionary(d => d.Key as string, d => d.Value as string),
location: location,
identity: this.GetManagedIdentity(),
managedIdentities: this.GetApplicationManagedIdentities(),
tags: this.Tag?.Cast<DictionaryEntry>().ToDictionary(d => d.Key as string, d => d.Value as string));
}

private ManagedIdentity GetManagedIdentity()
{
if (!this.IsParameterBound(c => c.IdentityType))
{
return null;
}

var identity = new ManagedIdentity(type: this.IdentityType);

Comment on lines +204 to +210
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetManagedIdentity() only checks whether IdentityType is bound; if a user supplies -UserAssignedIdentityId without -IdentityType, the identities are silently ignored (identity returns null). Validate that UserAssignedIdentityId implies an IdentityType including UserAssigned (or infer the IdentityType) so the parameter behaves as expected.

Suggested change
if (!this.IsParameterBound(c => c.IdentityType))
{
return null;
}
var identity = new ManagedIdentity(type: this.IdentityType);
// If neither an identity type nor any user-assigned identities are provided,
// there is no managed identity configuration to apply.
if (!this.IsParameterBound(c => c.IdentityType) &&
(this.UserAssignedIdentityId == null || this.UserAssignedIdentityId.Length == 0))
{
return null;
}
// Start from the provided identity type (if any).
var identityType = this.IdentityType;
// If user-assigned identities are specified but IdentityType is not explicitly bound,
// infer an appropriate type so that the parameter behaves as expected.
if (!this.IsParameterBound(c => c.IdentityType) &&
this.UserAssignedIdentityId != null &&
this.UserAssignedIdentityId.Length > 0)
{
identityType = "UserAssigned";
}
else if (this.IsParameterBound(c => c.IdentityType) &&
this.UserAssignedIdentityId != null &&
this.UserAssignedIdentityId.Length > 0)
{
// Validate that the explicitly provided IdentityType is compatible with
// the presence of user-assigned identities.
var identityTypeString = identityType != null ? identityType.ToString() : string.Empty;
if (identityTypeString.IndexOf("UserAssigned", StringComparison.OrdinalIgnoreCase) < 0)
{
throw new PSArgumentException("UserAssignedIdentityId is specified, but IdentityType does not include 'UserAssigned'.");
}
}
var identity = new ManagedIdentity(type: identityType);

Copilot uses AI. Check for mistakes.
if (this.UserAssignedIdentityId != null && this.UserAssignedIdentityId.Length > 0)
{
identity.UserAssignedIdentities = this.UserAssignedIdentityId
.ToDictionary(id => id, id => new UserAssignedIdentity());
}

return identity;
}

private IList<ApplicationUserAssignedIdentity> GetApplicationManagedIdentities()
{
if (this.ApplicationManagedIdentity == null)
{
return null;
}

return this.ApplicationManagedIdentity.Cast<DictionaryEntry>()
.Select(entry => new ApplicationUserAssignedIdentity(
name: entry.Key as string,
principalId: entry.Value as string))
.ToList();
}

private string GetAppTypeArmResourceId(string subscriptionId, string resourceGroup, string clusterName, string appTypeName, string appTypeVersion)
{
return string.Format(AppTypeArmResourceIdFormat, subscriptionId, resourceGroup, clusterName, appTypeName, appTypeVersion);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public class SetAzServiceFabricManagedClusterApplication : ManagedApplicationCmd

[Parameter(Mandatory = true, Position = 1, ParameterSetName = ByResourceGroup, ValueFromPipelineByPropertyName = true,
HelpMessage = "Specify the name of the cluster.")]
[ResourceNameCompleter("Microsoft.ServiceFabric/clusters", nameof(ResourceGroupName))]
[ResourceNameCompleter(Constants.ManagedClustersFullType, nameof(ResourceGroupName))]
[ValidateNotNullOrEmpty]
public override string ClusterName { get; set; }

Expand Down Expand Up @@ -244,6 +244,36 @@ public class SetAzServiceFabricManagedClusterApplication : ManagedApplicationCmd
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "Specify the tags as key/value pairs.")]
public Hashtable Tag { get; set; }

#region Identity params

[Parameter(Mandatory = false, ParameterSetName = ByResourceGroup,
HelpMessage = "Specify the type of managed identity for the application. Options are None, SystemAssigned, UserAssigned, and SystemAssigned,UserAssigned.")]
[Parameter(Mandatory = false, ParameterSetName = ByResourceId,
HelpMessage = "Specify the type of managed identity for the application. Options are None, SystemAssigned, UserAssigned, and SystemAssigned,UserAssigned.")]
[Parameter(Mandatory = false, ParameterSetName = ByInputObject,
Comment on lines +249 to +253
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New identity parameters introduce new behavior for managed cluster applications, but existing scenario tests for Set-AzServiceFabricManagedClusterApplication don't cover identity updates. Add/update tests to exercise setting identity type and user-assigned identities and validate the resulting properties.

Copilot generated this review using guidance from repository custom instructions.
HelpMessage = "Specify the type of managed identity for the application. Options are None, SystemAssigned, UserAssigned, and SystemAssigned,UserAssigned.")]
public ManagedIdentityType IdentityType { get; set; }

[Parameter(Mandatory = false, ParameterSetName = ByResourceGroup,
HelpMessage = "Specify the list of user assigned identity ARM resource IDs for the application.")]
[Parameter(Mandatory = false, ParameterSetName = ByResourceId,
HelpMessage = "Specify the list of user assigned identity ARM resource IDs for the application.")]
[Parameter(Mandatory = false, ParameterSetName = ByInputObject,
HelpMessage = "Specify the list of user assigned identity ARM resource IDs for the application.")]
[ValidateNotNullOrEmpty]
public string[] UserAssignedIdentityId { get; set; }

[Parameter(Mandatory = false, ParameterSetName = ByResourceGroup,
HelpMessage = "Specify the application managed identities as key/value pairs. The key is the friendly identity name, and the value is the principal id.")]
[Parameter(Mandatory = false, ParameterSetName = ByResourceId,
HelpMessage = "Specify the application managed identities as key/value pairs. The key is the friendly identity name, and the value is the principal id.")]
[Parameter(Mandatory = false, ParameterSetName = ByInputObject,
HelpMessage = "Specify the application managed identities as key/value pairs. The key is the friendly identity name, and the value is the principal id.")]
[ValidateNotNullOrEmpty]
public Hashtable ApplicationManagedIdentity { get; set; }

#endregion

[Parameter(Mandatory = true, ParameterSetName = ByResourceId, ValueFromPipelineByPropertyName = true,
HelpMessage = "Arm ResourceId of the managed application.")]
[ResourceIdCompleter(Constants.ManagedClustersFullType)]
Expand Down Expand Up @@ -337,6 +367,36 @@ private ApplicationResource GetUpdatedAppParams(ApplicationResource inputObject
currentApp.Tags = this.Tag?.Cast<DictionaryEntry>().ToDictionary(d => d.Key as string, d => d.Value as string);
}

if (this.IsParameterBound(c => c.IdentityType))
{
if (currentApp.Identity == null)
{
currentApp.Identity = new ManagedIdentity();
}

currentApp.Identity.Type = this.IdentityType;
}

if (this.IsParameterBound(c => c.UserAssignedIdentityId))
{
if (currentApp.Identity == null)
{
currentApp.Identity = new ManagedIdentity();
}

Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If -UserAssignedIdentityId is specified without also setting IdentityType to a value that includes UserAssigned, the cmdlet will set UserAssignedIdentities while leaving Identity.Type unchanged/unspecified, which can lead to an invalid request or ignored identities. Validate the dependency (require IdentityType include UserAssigned) or set Identity.Type automatically when UserAssignedIdentityId is provided.

Suggested change
// Ensure the identity type includes UserAssigned when user-assigned identities are specified
if (string.IsNullOrEmpty(currentApp.Identity.Type))
{
currentApp.Identity.Type = "UserAssigned";
}
else if (!currentApp.Identity.Type.Contains("UserAssigned", StringComparison.OrdinalIgnoreCase))
{
currentApp.Identity.Type = currentApp.Identity.Type + ", UserAssigned";
}

Copilot uses AI. Check for mistakes.
currentApp.Identity.UserAssignedIdentities = this.UserAssignedIdentityId
?.ToDictionary(id => id, id => new UserAssignedIdentity());
}

if (this.IsParameterBound(c => c.ApplicationManagedIdentity))
{
currentApp.ManagedIdentities = this.ApplicationManagedIdentity?.Cast<DictionaryEntry>()
.Select(entry => new ApplicationUserAssignedIdentity(
name: entry.Key as string,
principalId: entry.Value as string))
.ToList();
}

currentApp.UpgradePolicy = SetUpgradePolicy(currentApp.UpgradePolicy);

return currentApp;
Expand Down
Loading
Loading