Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 2 additions & 0 deletions src/Aks/Aks/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
- Additional information about change #1
-->
## Upcoming Release
* Added support `AcrNameToAttach` in `Set-AzAksCluster`. [#14692]
* Added support `AcrNameToDetach` in `Set-AzAksCluster`. [#14693]

## Version 2.0.2
* Refined error messages of cmdlet failure.
Expand Down
37 changes: 30 additions & 7 deletions src/Aks/Aks/Commands/CreateOrUpdateKubeBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ public abstract class CreateOrUpdateKubeBase : KubeCmdletBase
[Alias("SshKeyPath")]
public string SshKeyValue { get; set; }

[Parameter(Mandatory = false, HelpMessage = "Grant the 'acrpull' role of the specified ACR to AKS Service Principal, e.g. myacr")]
public string AcrNameToAttach { get; set; }

[Parameter(Mandatory = false, HelpMessage = "Run cmdlet in the background")]
public SwitchParameter AsJob { get; set; }

Expand Down Expand Up @@ -271,17 +274,15 @@ protected AcsServicePrincipal EnsureServicePrincipal(string spId = null, string
{
clientSecret = RandomBase64String(16);
}
var salt = RandomBase64String(3);
var url = $"http://{salt}.{DnsNamePrefix}.{Location}.cloudapp.azure.com";

acsServicePrincipal = BuildServicePrincipal(Name, url, clientSecret);
acsServicePrincipal = BuildServicePrincipal(Name, clientSecret);
WriteVerbose(Resources.CreatedANewServicePrincipalAndAssignedTheContributorRole);
StoreServicePrincipal(acsServicePrincipal);
}
return acsServicePrincipal;
}

private AcsServicePrincipal BuildServicePrincipal(string name, string url, string clientSecret)
private AcsServicePrincipal BuildServicePrincipal(string name, string clientSecret)
{
var pwCreds = new PasswordCredential(
value: clientSecret,
Expand All @@ -291,8 +292,8 @@ private AcsServicePrincipal BuildServicePrincipal(string name, string url, strin
var app = GraphClient.Applications.Create(new ApplicationCreateParameters(
false,
name,
new List<string> { url },
url,
new List<string> { },
null,
passwordCredentials: new List<PasswordCredential> { pwCreds }));

ServicePrincipal sp = null;
Expand All @@ -316,6 +317,22 @@ private AcsServicePrincipal BuildServicePrincipal(string name, string url, strin
return new AcsServicePrincipal { SpId = app.AppId, ClientSecret = clientSecret, ObjectId = app.ObjectId };
}

protected RoleAssignment GetRoleAssignmentWithRoleDefinitionId(string roleDefinitionId)
{
RoleAssignment roleAssignment = null;
var actionSuccess = RetryAction(() =>
{
roleAssignment = AuthClient.RoleAssignments.List().Where(x => x.Properties.RoleDefinitionId == roleDefinitionId).FirstOrDefault();
});
if (!actionSuccess)
{
throw new AzPSInvalidOperationException(
Resources.CouldNotGetAcrRoleAssignment,
desensitizedMessage: Resources.CouldNotGetAcrRoleAssignment);
}
return roleAssignment;
}

protected void AddAcrRoleAssignment(string acrName, string acrParameterName, AcsServicePrincipal acsServicePrincipal)
{
string acrResourceId = null;
Expand All @@ -335,8 +352,14 @@ protected void AddAcrRoleAssignment(string acrName, string acrParameterName, Acs
}

var roleId = GetRoleId("acrpull", acrResourceId);
RoleAssignment roleAssignment = GetRoleAssignmentWithRoleDefinitionId(roleId);
if (roleAssignment != null)
{
WriteWarning(string.Format(Resources.AcrRoleAssignmentIsAlreadyExist, acrResourceId));
return;
}
var spObjectId = acsServicePrincipal.ObjectId;
if(spObjectId == null)
if (spObjectId == null)
{
try
{
Expand Down
214 changes: 213 additions & 1 deletion src/Aks/Aks/Commands/NewAzureRmAks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,19 @@
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Security;

using Microsoft.Azure.Commands.Aks.Models;
using Microsoft.Azure.Commands.Aks.Properties;
using Microsoft.Azure.Commands.Aks.Utils;
using Microsoft.Azure.Commands.Common;
using Microsoft.Azure.Commands.Common.Exceptions;
using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters;
using Microsoft.Azure.Commands.ResourceManager.Common.Tags;
using Microsoft.Azure.Management.ContainerService;
using Microsoft.Azure.Management.ContainerService.Models;
using Microsoft.Rest;
using Microsoft.WindowsAzure.Commands.Common;
using Microsoft.WindowsAzure.Commands.Common.CustomAttributes;
using Microsoft.WindowsAzure.Commands.Utilities.Common;

Expand All @@ -35,8 +41,66 @@ namespace Microsoft.Azure.Commands.Aks
[Cmdlet("New", ResourceManager.Common.AzureRMConstants.AzureRMPrefix + "AksCluster", DefaultParameterSetName = DefaultParamSet, SupportsShouldProcess = true)]
[Alias("New-" + ResourceManager.Common.AzureRMConstants.AzureRMPrefix + "Aks")]
[OutputType(typeof(PSKubernetesCluster))]
public class NewAzureRmAks : NewKubeBase
public class NewAzureRmAks : CreateOrUpdateKubeBase
{
[Parameter(Mandatory = false, HelpMessage = "Represents types of an node pool. Possible values include: 'VirtualMachineScaleSets', 'AvailabilitySet'")]
[PSArgumentCompleter("AvailabilitySet", "VirtualMachineScaleSets")]
public string NodeVmSetType { get; set; }

[Parameter(Mandatory = false, HelpMessage = "VNet SubnetID specifies the VNet's subnet identifier.")]
public string NodeVnetSubnetID { get; set; }

[Parameter(Mandatory = false, HelpMessage = "Maximum number of pods that can run on node.")]
public int NodeMaxPodCount { get; set; }

[Parameter(Mandatory = false, HelpMessage = "ScaleSetPriority to be used to specify virtual machine scale set priority. Default to regular.")]
[PSArgumentCompleter("Low", "Regular")]
public string NodeSetPriority { get; set; }

[Parameter(Mandatory = false, HelpMessage = "NodePoolMode represents mode of an node pool.")]
[PSArgumentCompleter("System", "User")]
public string NodePoolMode { get; set; } = "System";

[Parameter(Mandatory = false, HelpMessage = "ScaleSetEvictionPolicy to be used to specify eviction policy for low priority virtual machine scale set. Default to Delete.")]
[PSArgumentCompleter("Delete", "Deallocate")]
public string NodeScaleSetEvictionPolicy { get; set; }

[Parameter(Mandatory = false, HelpMessage = "Add-on names to be enabled when cluster is created.")]
[ValidateNotNullOrEmpty()]
[PSArgumentCompleter("HttpApplicationRouting", "Monitoring", "VirtualNode", "AzurePolicy", "KubeDashboard")]
public string[] AddOnNameToBeEnabled { get; set; }

[Parameter(Mandatory = false,
ValueFromPipelineByPropertyName = true,
HelpMessage = "Resource Id of the workspace of Monitoring addon.")]
[ValidateNotNullOrEmpty]
public string WorkspaceResourceId { get; set; }

[Parameter(Mandatory = false,
ValueFromPipelineByPropertyName = true,
HelpMessage = "Subnet name of VirtualNode addon.")]
[ValidateNotNullOrEmpty]
public string SubnetName { get; set; }

[Parameter(Mandatory = false, HelpMessage = "Whether to enable Kubernetes Role-Based Access")]
public SwitchParameter EnableRbac { get; set; }

[Parameter(Mandatory = false, HelpMessage = "The administrator username to use for Windows VMs.")]
public string WindowsProfileAdminUserName { get; set; }

[Parameter(Mandatory = false, HelpMessage = "The administrator password to use for Windows VMs. Password requirement:"
+ "At least one lower case, one upper case, one special character !@#$%^&*(), the minimum lenth is 12.")]
[ValidateSecureString(RegularExpression = "^(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%\\^&\\*\\(\\)])[a-zA-Z\\d!@#$%\\^&\\*\\(\\)]{12,123}$", ParameterName = nameof(WindowsProfileAdminUserPassword))]
public SecureString WindowsProfileAdminUserPassword { get; set; }

[Parameter(Mandatory = false, HelpMessage = "Network plugin used for building Kubernetes network.")]
[PSArgumentCompleter("azure", "kubenet")]
public string NetworkPlugin { get; set; } = "azure";

[Parameter(Mandatory = false, HelpMessage = "The load balancer sku for the managed cluster.")]
[PSArgumentCompleter("basic", "standard")]
public string LoadBalancerSku { get; set; }

[Parameter(Mandatory = false, HelpMessage = "Create cluster even if it already exists")]
public SwitchParameter Force { get; set; }

Expand Down Expand Up @@ -190,5 +254,153 @@ protected void PrepareParameter()
SshKeyValue = GenerateSshKeyValue();
}
}
protected override ManagedCluster BuildNewCluster()
{
BeforeBuildNewCluster();

var pubKey =
new List<ContainerServiceSshPublicKey> { new ContainerServiceSshPublicKey(SshKeyValue) };

var linuxProfile =
new ContainerServiceLinuxProfile(LinuxProfileAdminUserName,
new ContainerServiceSshConfiguration(pubKey));

var acsServicePrincipal = EnsureServicePrincipal(ServicePrincipalIdAndSecret?.UserName, ServicePrincipalIdAndSecret?.Password?.ConvertToString());

var spProfile = new ManagedClusterServicePrincipalProfile(
acsServicePrincipal.SpId,
acsServicePrincipal.ClientSecret);

var aadProfile = GetAadProfile();

var defaultAgentPoolProfile = GetAgentPoolProfile();

var windowsProfile = GetWindowsProfile();

var networkProfile = GetNetworkProfile();

var addonProfiles = CreateAddonsProfiles();

WriteVerbose(string.Format(Resources.DeployingYourManagedKubeCluster, AcsSpFilePath));

var managedCluster = new ManagedCluster(
Location,
name: Name,
tags: TagsConversionHelper.CreateTagDictionary(Tag, true),
dnsPrefix: DnsNamePrefix,
kubernetesVersion: KubernetesVersion,
agentPoolProfiles: new List<ManagedClusterAgentPoolProfile> { defaultAgentPoolProfile },
linuxProfile: linuxProfile,
windowsProfile: windowsProfile,
servicePrincipalProfile: spProfile,
aadProfile: aadProfile,
addonProfiles: addonProfiles,
networkProfile: networkProfile);

if (EnableRbac.IsPresent)
{
managedCluster.EnableRBAC = EnableRbac;
}
//if(EnablePodSecurityPolicy.IsPresent)
//{
// managedCluster.EnablePodSecurityPolicy = EnablePodSecurityPolicy;
//}

if (this.IsParameterBound(c => c.AcrNameToAttach))
{
AddAcrRoleAssignment(AcrNameToAttach, nameof(AcrNameToAttach), acsServicePrincipal);
}

return managedCluster;
}

private ContainerServiceNetworkProfile GetNetworkProfile()
{
var networkProfile = new ContainerServiceNetworkProfile();
networkProfile.NetworkPlugin = NetworkPlugin;
networkProfile.LoadBalancerSku = LoadBalancerSku;
return networkProfile;
}

private ManagedClusterWindowsProfile GetWindowsProfile()
{
ManagedClusterWindowsProfile windowsProfile = null;

if (!string.IsNullOrEmpty(WindowsProfileAdminUserName) ||
WindowsProfileAdminUserPassword != null)
{
windowsProfile = new ManagedClusterWindowsProfile(WindowsProfileAdminUserName,
WindowsProfileAdminUserPassword?.ConvertToString());
}
return windowsProfile;
}

private ManagedClusterAgentPoolProfile GetAgentPoolProfile()
{
var defaultAgentPoolProfile = new ManagedClusterAgentPoolProfile(
name: NodeName ?? "default",
count: NodeCount,
vmSize: NodeVmSize,
osDiskSizeGB: NodeOsDiskSize,
type: NodeVmSetType ?? "VirtualMachineScaleSets",
vnetSubnetID: NodeVnetSubnetID);
defaultAgentPoolProfile.OsType = "Linux";
if (this.IsParameterBound(c => c.NodeMaxPodCount))
{
defaultAgentPoolProfile.MaxPods = NodeMaxPodCount;
}
if (this.IsParameterBound(c => c.NodeMinCount))
{
defaultAgentPoolProfile.MinCount = NodeMinCount;
}
if (this.IsParameterBound(c => c.NodeMaxCount))
{
defaultAgentPoolProfile.MaxCount = NodeMaxCount;
}
if (EnableNodeAutoScaling.IsPresent)
{
defaultAgentPoolProfile.EnableAutoScaling = EnableNodeAutoScaling.ToBool();
}
//if (EnableNodePublicIp.IsPresent)
//{
// defaultAgentPoolProfile.EnableNodePublicIP = EnableNodePublicIp.ToBool();
//}
if (this.IsParameterBound(c => c.NodeScaleSetEvictionPolicy))
{
defaultAgentPoolProfile.ScaleSetEvictionPolicy = NodeScaleSetEvictionPolicy;
}
if (this.IsParameterBound(c => c.NodeSetPriority))
{
defaultAgentPoolProfile.ScaleSetPriority = NodeSetPriority;
}
defaultAgentPoolProfile.Mode = NodePoolMode;

return defaultAgentPoolProfile;
}

private ManagedClusterAADProfile GetAadProfile()
{
ManagedClusterAADProfile aadProfile = null;
//if (!string.IsNullOrEmpty(AadProfileClientAppId) || !string.IsNullOrEmpty(AadProfileServerAppId) ||
// !string.IsNullOrEmpty(AadProfileServerAppSecret) || !string.IsNullOrEmpty(AadProfileTenantId))
//{
// aadProfile = new ManagedClusterAADProfile(clientAppID: AadProfileClientAppId, serverAppID: AadProfileServerAppId,
// serverAppSecret: AadProfileServerAppSecret, tenantID: AadProfileTenantId);
//}
return aadProfile;
}

private IDictionary<string, ManagedClusterAddonProfile> CreateAddonsProfiles()
{
if (this.IsParameterBound(c => c.AddOnNameToBeEnabled))
{
Dictionary<string, ManagedClusterAddonProfile> addonProfiles = new Dictionary<string, ManagedClusterAddonProfile>();
return AddonUtils.EnableAddonsProfile(addonProfiles, AddOnNameToBeEnabled, nameof(AddOnNameToBeEnabled), WorkspaceResourceId, nameof(WorkspaceResourceId), SubnetName, nameof(SubnetName));
}
else
{
return null;
}
}
}
}
Loading