Scaling multiple kubernetes node pools on azure - azure

I am in the middle of creating a function to schedule node pool scaling on azure.
This was fairly easy using the AKS Module and creating a function to scale the nodepool, but now the development team has started using multuple node pools in the same kubernetes service, usually i would just use the Set-AzAks as follow
Set-AzAks -Name <name> -ResourceGroupName <rgname> -NodeCount 1
But i seem unable to specify individual node pools in the command. I have been able to use the az CLI tool to get the functionality i want doing it manually, but I really want to use the azure automation account to do this.
Any help would be appreciated

This is an issue which already existed in the Github. So I think it's not a good way to use the PowerShell command Set-AzAks to scale the AKS nodes count in the current situation.
For this, I recommend you to use the Azure REST API Managed Clusters - Create Or Update through PowerShell, it will also work perfectly as the Azure CLI commands for you.
Update:
As you wish, I will show you the example below:
$body = '{
"location": "eastus",
"properties": {
"kubernetesVersion": "1.14.6",
"dnsPrefix": "xxxxx",
"agentPoolProfiles": [
{
"count": 2,
"vmSize": "Standard_DS2_v2",
"osDiskSizeGB": 100,
"vnetSubnetID": "xxxxxxxx",
"maxPods": 30,
"osType": "Linux",
"type": "AvailabilitySet",
"orchestratorVersion": "1.14.6",
"name": "agentpool"
}
],
"addonProfiles": {
"httpapplicationrouting": {
"enabled": false,
"config": {}
},
"omsagent": {
"enabled": true,
"config": {
"loganalyticsworkspaceresourceid": "xxxxxxxx"
}
}
},
"nodeResourceGroup": "xxxxxxxxx",
"enableRBAC": true,
"networkProfile": {
"networkPlugin": "azure",
"serviceCidr": "10.1.0.0/16",
"dnsServiceIP": "10.1.0.10",
"dockerBridgeCidr": "172.17.0.1/16",
"loadBalancerSku": "Basic"
}
}
}'
$requestUri = "https://management.azure.com/subscriptions/{subscription_id}/resourceGroups/{your_group_name}/providers/Microsoft.ContainerService/managedClusters/{your_cluster_name}?api-version=2019-08-01"
$accessToken = "xxxxxxx"
Invoke-RestMethod -Headers #{Authorization = "Bearer $accessToken"} -Uri $requestUri -Method PUT -ContentType 'application/json' -Body $body
You can change the context in the body as you need and the properties describe in the REST API.

Related

Get properties for an object returned by Get-AzResource on Azure

I am trying get the properties of an Azure Disk Resource. When I run the command in my subscription
$R=Get-AzResource -Name <ResourceName>
It provides a list of properties given here I am specifically interested getting the Properties PSobject. However running the following command:
$R.Properties -eq $null
does returns true. When I look at this resource from Azure Portal (Same user principal as in Powershell command) in Json format I am given a selection of schemas to choose from and lots of properties are provided. Below is a sample:
"properties": {
"osType": "Linux",
"hyperVGeneration": "V2",
"supportsHibernation": true,
"supportedCapabilities": {
"acceleratedNetwork": true,
"architecture": "x64"
},
"creationData": {
"createOption": "FromImage",
"imageReference": {
"id": "xxx"
}
},
"diskSizeGB": 30,
"diskIOPSReadWrite": 500,
"diskMBpsReadWrite": 60,
"encryption": {
"type": "EncryptionAtRestWithPlatformKey"
},
"networkAccessPolicy": "AllowAll",
"publicNetworkAccess": "Enabled",
"timeCreated": "2023-01-09T13:38:24.500223+00:00",
"provisioningState": "Succeeded",
"diskState": "Attached",
"diskSizeBytes": 32213303296,
"uniqueId": "xxx"
What is the proper command to get this information using PowerShell?
You should set the ExpandProperties switch
https://learn.microsoft.com/en-us/powershell/module/az.resources/get-azresource?view=azps-9.3.0#-expandproperties
$resourceWithProperties = Get-AzResource -Name <ResourceName> -ExpandProperties
You can the access the properties with
$resourceWithProperties.Properties
You can get all properties using -ExapandProperties command and Alternative way of getting all properties is by using below commands:
Connect-AzAccount
$disk = Get-AzResource -ResourceId "/subscriptions/<subscriptionId>/resourceGroups/<Rg name>/providers/Microsoft.Compute/disks/<Diskname>"
$disk.Properties | Format-List *
Output:

Azure DevTest Labs: how to parametrize resources

I am trying to create a PowerShell script that would deploy an instance of Azure DevTest lab, create an environment there, and such resources as databricks, azure data factory, etc. This is part of my lab template responsible for that.
"resources":[
{
"apiVersion":"2018-09-15",
"name":"LabVmsShutdown",
"location":"[parameters('location')]",
"type":"schedules",
"dependsOn":[
"[resourceId('Microsoft.DevTestLab/labs', parameters('labResourceName'))]"
],
"properties":{
"status":"Enabled",
"timeZoneId":"GMT Standard Time",
"dailyRecurrence":{
"time":"0100"
},
"taskType":"LabVmsShutdownTask",
"notificationSettings":{
"status":"Disabled",
"timeInMinutes":30
}
}
},
{
"apiVersion":"2018-09-15",
"name":"[concat('Dtl', parameters('labResourceName'))]",
"type":"virtualNetworks",
"location":"[parameters('location')]",
"dependsOn":[
"[resourceId('Microsoft.DevTestLab/labs', parameters('labResourceName'))]"
]
},
{
"apiVersion":"2018-09-15",
"name":"Public Environment Repo",
"type":"artifactSources",
"location":"[parameters('location')]",
"dependsOn":[
"[resourceId('Microsoft.DevTestLab/labs', parameters('labResourceName'))]"
],
"properties":{
"status":"Enabled"
}
},
{
"apiVersion":"2018-09-15",
"name":"[parameters('repositoryName')]",
"type":"artifactSources",
"dependsOn":[
"[resourceId('Microsoft.DevTestLab/labs', parameters('labResourceName'))]"
],
"properties":{
"uri":"MY_URL",
"armTemplateFolderPath":"MY_PATH",
"displayName":"DevTestLab",
"branchRef":"features/devops-development",
"securityToken":"MY_TOKEN",
"sourceType":"VsoGit",
"status":"Enabled"
}
},
{
"apiVersion":"2018-09-15",
"name":"[parameters('userId')]",
"type":"users",
"location":"[parameters('location')]",
"dependsOn":[
"[resourceId('Microsoft.DevTestLab/labs', parameters('labResourceName'))]"
],
"properties":{
"status":"Enabled"
},
"resources":[
{
"name":"devtestlaab",
"type":"environments",
"apiVersion":"2018-09-15",
"location":"[parameters('location')]",
"properties":{
"deploymentProperties":{
"armTemplateId":"[concat(resourceId('Microsoft.DevTestLab/labs/artifactsources', parameters('labResourceName'), parameters('repositoryName')), '/armTemplates/DevTestLab')]"
},
"armTemplateDisplayName":"DevLab Deployment Script"
},
"dependsOn":[
"[resourceId('Microsoft.DevTestLab/labs/users', parameters('labResourceName'), parameters('userId'))]"
]
}
]
}
]
}
]
It works fine for the most part. However, I am not able to pass parameters for my inner templates. It just takes whatever is hardcoded inside of those templates on my ref_branch at a given moment and deploys it.
I have tried to follow the following template and add the parameters part but it's being completely ignored.
{
"name": "string",
"type": "Microsoft.DevTestLab/labs/users/environments",
"apiVersion": "2018-09-15",
"location": "string",
"tags": {},
"properties": {
"deploymentProperties": {
"armTemplateId": "string",
"parameters": [
{
"name": "string",
"value": "string"
}
]
},
"armTemplateDisplayName": "string"
}
}
So to summarize, I am able to deploy:
Lab
Environment
Resources inside of this lab.
I am not able to:
Pass any parameters to the resources within my lab environment.
The documentation is very scarce and so I am not really sure what the problem could be.
AFAI understand, your template looks wrong. Pls check out A quick guide on writing your Azure Resource Manager (ARM) Templates for understanding how to use parameters.
And, for PowerShell script deployment, you can use below command to deploy ARM template with parameters:
New-AzResourceGroupDeployment -Name ExampleDeployment -ResourceGroupName ExampleResourceGroup `
-TemplateFile <path-to-template-or-bicep> `
-TemplateParameterFile c:\MyTemplates\storage.parameters.json
OR
New-AzResourceGroupDeployment -Name ExampleDeployment -ResourceGroupName ExampleResourceGroup `
-TemplateUri https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/101-storage-account-create/azuredeploy.json `
-TemplateParameterUri https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/101-storage-account-create/azuredeploy.parameters.json
Let me know if this helps.
Generally in TFS pipelines, you would define variables and pass them to the scripts as arguments. See examples here.
However since you are dealing specifically with ARM templates and thinking about control flow (outer/inner loops, etc.) you can look at a couple of other options as well
Have you looked at Azure Bicep (git repo) ?
You could also use Terraform if your organization wants to go this route.

how to create an azure function key in ARM template?

I have been struggling with this one all day, I am trying to create a Function App function key from an ARM template.
So far I have been able to create my function key on the Host level using the following template:
{
"type": "Microsoft.Web/sites/host/functionKeys",
"apiVersion": "2018-11-01",
"name": "[concat(parameters('appServiceName'), '/default/PortalFunctionKey')]",
"properties": {
"name": "PortalFunctionKey"
}
then I found a couple of articles and link showing it is possible via API:
https://github.com/Azure/azure-functions-host/wiki/Key-management-API
And I was able to generate it via this API posting to:
https://{myfunctionapp}.azurewebsites.net/admin/functions/{MyFunctionName}/keys/{NewKeyName}?code={_masterKey}
But I can't for the sake of me figure out how to do that in my ARM template!
I have tried various combinations of type and name, for example:
{
"type": "Microsoft.Web/sites/host/functionKeys",
"apiVersion": "2018-11-01",
"name": "[concat(parameters('appServiceName'), '/{myfunctionName}/PortalFunctionKey')]",
"properties": {
"name": "PortalFunctionKey"
}
or /functions/{myfunctionName}/PortalFunctionKey
as suggested in some articles, and i just can't get any to work, can't find much documentation on ARM Microsoft.Web/sites/host/functionKeys either.
Did anyone succeed to create a FUNCTION key (not host) in ARM template? I would gladly hear how you got there :)!
Basically:
Many thanks in advance,
Emmanuel
This might solve the problem now: https://learn.microsoft.com/en-us/azure/templates/microsoft.web/2020-06-01/sites/functions/keys
I was able to create a function key by passing an ARM template resource that looked like this:
{
"type": "Microsoft.Web/sites/functions/keys",
"apiVersion": "2020-06-01",
"name": "{Site Name}/{Function App Name}/{Key Name}",
"properties": {
"value": "(optional)-key-value-can-be-passed-here"
}
}
It seems that even if you don't have 'value' in the properties, then you have to at least pass an empty properties object.
To solve this problem , you could refer to this github issue. First issue and second issue, these issues all have the problem about how to get the function key in the ARM template.
For now the sample to get the key value as the below shows:
"properties": {
"contentType": "text/plain",
"value": "[listkeys(concat(variables('functionAppId'), '/host/default/'),'2016-08-01').functionKeys.default]"
}
or with below to get the key object.
"functionkeys": {
"type": "object",
"value": "[listkeys(concat(variables('functionAppId'), '/host/default'), '2018-11-01')]" }
}
You could have a try, hope this could help you.
So it is not possible to create a Function level Function key in ARM template at the moment.
I therefore created a feature request you can vote on if you are interested in it:
https://feedback.azure.com/forums/169385-web-apps/suggestions/39789043-create-function-level-keys-for-azure-functions-in
For now though, we are creating function level function keys via a powershell deployment task step. here is how.
add output parameter to your ARM template:
"outputs": {
"masterKey": {
"type": "string",
"value": "[listkeys(concat(resourceId(resourceGroup().name, 'Microsoft.Web/sites', parameters('appServiceName')), '/host/default'), '2018-11-01').masterKey]"
},
"appServiceName": {
"type": "string",
"value": "[parameters('appServiceName')]"
},
"functionKeys": {
"type": "array",
"value": [
{
"functionName": "myFunctionName",
"keys": [ "FunctionKeyName1", "FunctionKeyName2" ]
}
]
}
}
Add the following PS script file to your deploy project:
param (
[Parameter(Mandatory=$true)]
[string]
$armOutputString
)
Write-Host $armOutputString
$armOutputObj = $armOutputString | convertfrom-json
Write-Host $armOutputObj
$masterKey = $armOutputObj.masterKey.value
$appServiceName = $armOutputObj.appServiceName.value
$httpHeaders = #{
"x-functions-key" = $masterKey
}
$contentType = "application/json; charset=utf-8"
foreach($function in $armOutputObj.functionKeys.value){
$retryCount = 5;
while ($true) {
try {
$uriBase = "https://$($appServiceName).azurewebsites.net/admin/functions/$($function.functionName)/keys"
$existingKeys = Invoke-RestMethod -Method Get -Uri $uriBase -Headers $httpHeaders -ContentType $contentType
break;
}
catch {
if ($_.Exception.Response.StatusCode.value__ -eq 502) {
if ($retryCount-- -eq 0) {
throw;
}
else {
Write-Output ("Retry" + ": " + $_.Exception.Response.StatusCode + "; attempts=$retryCount")
[System.Threading.Thread]::Sleep(1000);
continue;
}
}
else {
throw;
}
}
}
foreach ($keyname in $function.keys){
$keyExists = 0
foreach($exstingKey in $existingKeys.keys){
if($exstingKey.name -eq $keyname){
$keyExists = 1
Write-Host "key $($keyname) already exists"
}
}
if($keyExists -eq 0){
$uri = "$($uriBase)/$($keyname)?code=$($masterKey)";
Write-Host "Adding $($keyname) key"
Invoke-RestMethod -Method Post -Uri "$($uriBase)/$($keyname)" -Headers $httpHeaders -ContentType $contentType;
}
}
}
The script ensures that the key will not be overwritten if it already exists, and will retry if it fails (the function MUST exist and be running for the API to work).
In your "Azure resource group deployment" task, under "Advanced" set "Deployment outputs" to "armDeployOutput".
Add a Powershell task, your script path to the powershell file in your deploy project, and set "Arguments" as "-armOutputString '$(armDeployOutput)'".
And that's it.

Azure EventGrid on Azure Subscription - determine which tag has changed

I am trying to setup Azure EventGrid for an Azure Subscription to get notified when a certain tag for a ressource has changed.
This is how I created the EventGrid Subscription:
$includedEventTypes = , 'Microsoft.Resources.ResourceWriteSuccess'
New-AzEventGridSubscription `
-EventSubscriptionName mySubscriptionName `
-ResourceGroupName myResourceGroup `
-Endpoint myEndpoint `
-IncludedEventType $includedEventTypes
Now If I change a tag for example on an Azure Web App, I receive the following event:
{
"subject": "/subscriptions/mySubId/resourceGroups/eventgrid/providers/Microsoft.Web/sites/wd-eventgrid-viewer",
"eventType": "Microsoft.Resources.ResourceWriteSuccess",
"eventTime": "2019-06-03T08:50:47.7469859Z",
"id": "f193df79-6755-42c7-b663-91bc373a80e5",
"data": {
"authorization": {
"scope": "/subscriptions/mySubId/resourceGroups/eventgrid/providers/Microsoft.Web/sites/wd-eventgrid-viewer",
"action": "Microsoft.Web/sites/write",
"evidence": {
"role": "Subscription Admin"
}
},
"claims": {
....
},
"correlationId": "9a1bb49f-9f39-4e98-918c-dfe0655b895a",
"httpRequest": {
"clientRequestId": "8bf9bfdb-6e65-4c55-84f2-3f4e05b340d0",
"clientIpAddress": "......",
"method": "PATCH",
"url": "https://management.azure.com/subscriptions/mySubId/resourceGroups/eventgrid/providers/Microsoft.Web/sites/wd-eventgrid-viewer?api-version=2015-08-01"
},
"resourceProvider": "Microsoft.Web",
"resourceUri": "/subscriptions/mySubId/resourceGroups/eventgrid/providers/Microsoft.Web/sites/wd-eventgrid-viewer",
"operationName": "Microsoft.Web/sites/write",
"status": "Succeeded",
"subscriptionId": "mySubId",
"tenantId": "...."
},
"dataVersion": "2",
"metadataVersion": "1",
"topic": "/subscriptions/mySubId"
}
Unfortunately, I don't see that a tag has changed nor do I see which tag has changed. Is there any way to receive which tag for a resource has changed or do I have to query the tags manually after the event?
Azure Subscription Events are emitted either for Resource Actions, Deletes or Writes as documented.
You are only provided with the resource details which you will have to use to fetch the changes.
As you had thought, you would have to use these details with the Resources API to fetch the tags.
UPDATE: There is a new API to get resource changes which you can use to detect the exact changes made on a resource. Note that this feature is currently in public preview.

Azure RM Templates: Create multiple data disks of different sizes using copyIndex()

Following on from this question, I need to go a step further and be able to create multiple data disks of different sizes, where quantity and sizes are specified at deploy-time.
My latest incarnation is creating the (managed) disks in their own resource outside the VM resource and then trying to attach them.
It seems that the copyindex resets for each resource so I believe I need to create them all in one copy so the "attach" part in the VM resource can use the length function, but I cannot think of a way to change any property inside the copy loop when a certain iteration is reached (I would understand why this isn't possible).
I'm thinking I need to use something like:
"count": "[variables('numberOfDisks')[parameters('DiskSize')]]"
But unsure how to proceed.
I've also thought about nested templates, but again, this falls foul of not being able to change parameters inside a loop.
In programming, I could create a 2d array or dictionary object, but cannot find a way to do this in ARM templates, although, I have just found Intersection.
Datadisk configuration examples:
It is only the size and quantity that vary per deployment. All other properties are anticipated to be the same for all disks for any given VM.
VM 1: 2x # 256GB, 4x # 512GB, 4x # 1023GB
VM 2: 1x # 1023GB, 1x # 80GB
VM 3: 1x # 1023GB, 1x # 80GB, 2x # 256GB, 2x # 512GB
My template only deploys one VM, but the number and size of disks are unknown. The idea as that DSC will come along and create volumes, collating the disks based on their size.
I'm not going to paste my workings as they are long, wrong and bulk out this post. Hopefully the above is enough to prove I have been trying to work things out for myself.
So I've managed to achieve it. Possibly not the most elegant, but it works. Although Microsoft seem to suggest using a top-level resource to create the datadisks, I can't see how this will work as I don't know of a way to use copy[] inside DependsOn[] which is required if you are creating the disks and vm in the same template, they'll try and deploy simultaneously.
For those that may be interested, here is my solution:
Firstly, I am triggering the template using PowerShell's New-AzureRmResourceDeployment. I'm not using a parameters file. The parameters are generated in PS.
$RG = "ResourceGroup where VM resides"
$Disks = #(
#{name = "datadisk-001";diskSizeGB = "256";lun = 0}
#{name = "datadisk-002";diskSizeGB = "256";lun = 1}
#{name = "datadisk-003";diskSizeGB = "512";lun = 2}
#{name = "datadisk-004";diskSizeGB = "512";lun = 3}
#{name = "datadisk-005";diskSizeGB = "512";lun = 4}
#{name = "datadisk-006";diskSizeGB = "512";lun = 5}
)
$params = #{
diskConfig = $disks
storageAccounttype = "Standard_LRS"
vmName = "AUCADN102007006"
}
New-AzureRmResourceGroupDeployment -Name "SomeDeploymentName" `
-ResourceGroupName $RG `
-Mode Incremental `
-DeploymentDebugLogLevel All `
-TemplateFile C:\Temp\DiskTest.json" `
-Verbose `
#params
The template itself is seriously cut down, and doesn't actually create the VM. The referenced VM needs to exist. I've taken out as much as possible.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"vmName": {
"type": "string"
},
"diskConfig": {
"type": "array"
},
"storageAccountType": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Premium_LRS"
],
"metadata": {
"description": "Type of disk"
}
}
},
"variables": {
"vmSize": "Standard_DS4_v2",
"sharedVariables": {
"storageAccountType": "[parameters('storageAccountType')]"
}
},
"resources": [
{
"apiVersion": "2017-03-30",
"type": "Microsoft.Compute/virtualMachines",
"name": "[parameters('vmName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
],
"properties": {
"storageProfile": {
"copy": [
{
"name": "dataDisks",
"count": "[length(parameters('diskConfig'))]",
"input": {
"name": "[concat(parameters('vmName'),'-',parameters('diskConfig')[CopyIndex('dataDisks')].name)]",
"diskSizeGB": "[parameters('diskConfig')[CopyIndex('dataDisks')].diskSizeGB]",
"lun": "[parameters('diskConfig')[copyIndex('dataDisks')].lun]",
"createOption": "Empty",
"managedDisk": {
"storageAccountType": "[variables('sharedVariables').storageAccountType]"
}
}
}
]
}
}
}
],
"outputs": {
"arrayOutput1": {
"type": "array",
"value": "[parameters('diskConfig')]"
},
"arrayCount": {
"type": "int",
"value": "[length(parameters('diskConfig'))]"
}
}
}
Thanks to this post where the author demonstrates the use of indexing:
"properties": {
"accountType": " [parameters('storageAccountList')[copyIndex()].storageAccountType]"
}
Note how copyIndex() is in [ ]
ToDo: Do something better with $Disks, either using PS to create the hashtable or create it inside the template.
HTH

Resources