Azure ARM copyIndex() - json

I am trying to create an ARM template that will allow my to deploy VMs that may or may not need additional data disks. However when I test my template, I get the error below.
What is weird is that if the vmDataDisk parameter has a value of 0 or 1, all works perfectly. If that parameter has anything greater than 1, I get the error below.
For example the following works great: vmDataDisk = 1 and vmDataDiskSizesInGb = 30
However, the following values throw error below: vmDataDisk = 3, vmDataDiskSizesInGb = 10,20,30
Parameters Element - ARM json
"parameters": {
...
"vmDataDisks": {
"type": "int",
"defaultValue": 0,
"allowedValues": [
0,
1,
2,
3,
4,
5
],
"metadata": {
"description": "Select the number of data disks (in addition to OS disk) needed for this VM."
}
},
"vmDataDiskSizesInGb": {
"type": "string",
"defaultValue": 0,
"metadata": {
"description": "Enter string of comma separated values for the size of each data disk. For example, if the VmDataDisks parameter is set to '3', the VmDataDiskSizesInGb parameter might have a value of '10,25,50' and the template will deploy 3 data disks that are 10, 25 and 50 GB in size respectively."
}
}
}
Variables Element - ARM json
"variables": {
...
"diskSizes": "[split(parameters('vmDataDiskSizesInGb'), ',')]",
"copy": [
{
"name": "dataDisks",
"count": "[if(equals(parameters('vmDataDisks'),0), 1, parameters('vmDataDisks'))]",
"input": {
"name": "[concat(parameters('vmName'), '_DataDisk_', copyIndex('dataDisks'))]",
"lun": "[copyIndex('dataDisks')]",
"createOption": "Empty",
"diskSizeGB": "[if(equals(parameters('vmDataDisks'),0), 1, int(variables('diskSizes')[copyIndex()]))]",
"caching": "[if(startsWith(parameters('vmType'), 'SQL'), 'ReadOnly', 'None')]",
"managedDisk": {
"storageAccountType": "Premium_LRS"
}
}
}
]
}
Resources Element - ARM json
"resources": [
{
"type": "Microsoft.Compute/virtualMachines",
"name": "[parameters('vmName')]",
"apiVersion": "2017-03-30",
"location": "[parameters('location')]",
"dependsOn": [],
"properties": {
"hardwareProfile": {},
"osProfile": {},
"storageProfile": {
"imageReference": {},
"osDisk": {},
"dataDisks": "[if(equals(parameters('vmDataDisks'),0), json('null'), variables('dataDisks'))]"
},
"networkProfile": {},
"diagnosticsProfile": {}
}
}
]
Test-AzureRmResourceGroupDeployment Error
Code : InvalidTemplateMessage : Deployment template language
expression evaluation failed: 'The language expression property '0'
can't be evaluated.'. Please see
https://aka.ms/arm-template-expressions for usage details.Details :

The error says that the language expression you used in your template cannot be evaluated. For other words, the language expression you used does not meet the rules of the template. And the wrong expression property is ‘0’.
So you should check all your expression with property ‘0’ compared with the document that the error post: https://aka.ms/arm-template-expressions.
update
In the template code you post, the parameter "vmDataDiskSizesInGb" type is string and your "defaultValue" is 0, it's not correct, you should give "0" to it.
But I'm not sure if you have any other error,so I suggest you check all your expression with property ‘0’ compared with the document that the error post: https://aka.ms/arm-template-expressions.

Related

Zabbix JSONpath LLD

I am trying to make discoverig instances from AWS Auto Scaling Group.
I have json like this:
{
"AutoScalingGroups": [
{
"AutoScalingGroupName": "xxx",
"AutoScalingGroupARN": "arn:aws:autoscaling:eu-central-1:xxx",
"LaunchTemplate": {
"LaunchTemplateId": "lt-xxx",
"LaunchTemplateName": "xxx",
"Version": "$Latest"
},
"MinSize": 2,
"MaxSize": 10,
"DesiredCapacity": 2,
"DefaultCooldown": 300,
"AvailabilityZones": [
"eu-central-1a",
"eu-central-1c",
"eu-central-1b"
],
"LoadBalancerNames": [],
"TargetGroupARNs": [],
"HealthCheckType": "EC2",
"HealthCheckGracePeriod": 0,
"Instances": [
{
"InstanceId": "i-xxx111",
"InstanceType": "c5.2xlarge",
"AvailabilityZone": "eu-central-1b",
"LifecycleState": "InService",
"HealthStatus": "Healthy",
"LaunchTemplate": {
"LaunchTemplateId": "lt-xxx",
"LaunchTemplateName": "xxx",
"Version": "11"
},
"ProtectedFromScaleIn": false
},
{
"InstanceId": "i-xxx222",
"InstanceType": "c5.2xlarge",
"AvailabilityZone": "eu-central-1a",
"LifecycleState": "InService",
"HealthStatus": "Healthy",
"LaunchTemplate": {
"LaunchTemplateId": "lt-xxx",
"LaunchTemplateName": "xxx",
"Version": "11"
},
"ProtectedFromScaleIn": false
}
]
}
]
}
And I want to create discovered items with name of instance id and values - healthstatus.
I created discovery rule with master item as previous json. And i got instance ids with item prototype that have next preprocessing JSONPath - $.AutoScalingGroups.[*].Instances.[*].InstanceId
This item has value next format ["i-xxx111","i-xxx222"], but i dont understand how to create next item prototype with names as each instance-id from this list.
So, can someone help me?
I am using zabbix version 6.2.4
You need to turn that object in the Zabbix LLD format. Using JSONpath won't help us in this case. You can use a JavaScript preprocessing in the Zabbix Item.
res = []
obj = JSON.parse(value)
for (asg in obj.AutoScalingGroups) {
for (i in obj.AutoScalingGroups[asg].Instances) {
res.push({"id": obj.AutoScalingGroups[asg].Instances[i].InstanceId})
}
}
return JSON.stringify(res)
result: [{"id":"i-xxx111"},{"id":"i-xxx222"}]
Don't forget to turn $.id in {#ID} in Zabbix LLD macro.
(Would be easier if we could use for (.. of ..) in ducktape...)
Here's a fiddle: https://jsfiddle.net/egch0vap/1/
See: https://www.zabbix.com/documentation/current/en/manual/config/items/preprocessing/javascript

Orion CB output regarding provisioned device

I have noticed that upon querying Orion CB, while it is working with provisioned devices and having IoT Agent receive HTTP and MQTT messages, it will always output all the values written in the quotation marks:
{
"id": "sensor_data",
"type": "Sensor",
"ActiveTime": {
"type": "Seconds",
"value": "17703",
"metadata": {
"TimeInstant": {
"type": "ISO8601",
"value": "2018-07-04T13:32:27.357Z"
}
}
},
"Distance": {
"type": "Number",
"value": "312",
"metadata": {
"TimeInstant": {
"type": "ISO8601",
"value": "2018-07-04T13:32:27.413Z"
}
}
}
}
However, if to work with only entities in Orion CB, it is possible to receive actual values (like in the example in the manual):
{
"id": "Room1",
"pressure": {
"metadata": {},
"type": "Integer",
"value": 720
},
"temperature": {
"metadata": {},
"type": "Float",
"value": 23
},
"type": "Room"
}
Sometimes, I need to receive the actual value from my sensor in order to format it and use in further applications, but they are in quotation marks, which makes it a little difficult.
Is it possible to somehow change?(maybe in device provisioning), or it really should be that way regarding devices?
Thanks in advance!
EDIT 1
This is the way I provisioned the device:
{
"devices": [
{
"device_id": "sensor_data",
"entity_name": "sensor_data",
"entity_type": "Sensor",
"transport": "MQTT",
"timezone": "Europe/Helsinki",
"attributes": [
{ "object_id": "act", "name": "ActiveTime", "type": "Seconds"},
{ "object_id": "dst", "name": "Distance", "type": "Number"}
]
}
]
}
And this is how the MQTT messages are sent from my sensor (I have set up the topics for IoT Agent to understand them)
/123456789/sensor_data/attrs/act 12
/123456789/sensor_data/attrs/dst 322
123456789 is the API Key I have set here.
This situation tipycally happens when IoT Agents uses NGSIv1 to push data to Context Broker, given that NGSIv1 always "string-fy" any attribute value. Recently, the ability to use NGSIv2 (which doesn't have this limitatino) was introduced in IoT Agents.
In order to solve your problem you have to:
Use a recent IOTA-UL version (the current one from master branch will work)
Enable NGSIv2 in configuration as explained in documentation. This is done in the config.js file:
config.iota = {
...
contextBroker: {
...
ngsiVersion: 'v2'
}
...
}
or using environament variable IOTA_CB_NGSI_VERSION=v2 for the IOTA-UL process.
Enable autocast as explained in documentation. This is done in config.js file:
config.iota = {
...
autocast: true,
...
}
or using environament variable IOTA_AUTOCAST=true for the IOTA-UL process.
Set the right type for each attribute at provision time. The documentation here) provides the right types:
Type "Number" for integer or float numbers
Type "Boolean" for boolean
Type "None" for null
Thus, in your case the provisioning for Distance is ok, but for ActiveTime you should use also Number as type.

How to check if name already exists? Azure Ressource Manager Template

is it possible to check, in an ARM Template, if the name for my Virtual Machine already exists?
I am developing a Solution Template for the Azure Marketplace. Maybe it is possible to set a paramter in the UiDefinition uniqe?
The goal is to reproduce this green Hook
A couple notes...
VM Names only need to be unique within a resourceGroup, not within the subscription
Solution Templates must be deployed to empty resourceGroups, so collisions with existing resources aren't possible
For solution templates the preference is that you simply name the VMs for the user, rather than asking - use something that is appropriate for the workload (e.g. jumpbox) - not all solutions do this but we're trying to improve that experience
Given that it's not likely we'll ever build a control that checks for naming collisions on resources without globally unique constraints.
That help?
This looks impossible, according to the documentation.
There are no validation scenarious.
I assume that you should be using the Microsoft.Common.TextBox UI element in your createUiDefinition.json.
I have tried to reproduce a green check by creating a simple createUiDefinition.json as below with a Microsoft.Common.TextBox UI element as shown below.
{
"$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json",
"handler": "Microsoft.Compute.MultiVm",
"version": "0.1.2-preview",
"parameters": {
"basics": [
{
"name": "textBoxA",
"type": "Microsoft.Common.TextBox",
"label": "VM Name",
"defaultValue": "",
"toolTip": "Please enter a VM name",
"constraints": {
"required": true
},
"visible": true
}
],
"steps": [],
"outputs": {}
}
}
I am able to reproduce the green check beside the VM Name textbox as shown below:
However, this green check DOES NOT imply the VM Name is Available.
This is because based on my testing, even if I use an existing VM Name in the same subscription, it is still showing the green check.
Based on the official documented constraints that are supported by the Microsoft.Common.TextBox UI element, it DOES NOT VALIDATE Name Availability.
Hope this helps!
While bmoore's point is correct that it's unlikely you would ever need this for a VM (nor is there an API for it), there are other compute resources that do have global naming requirements.
As of 2022 this concept is possible now with the use of the ArmApiControl UI element. It allows you to call ARM apis as part of validation in the createUiDefinition.json. Here is an example using the check name API for an Azure App service.
{
"$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#",
"handler": "Microsoft.Azure.CreateUIDef",
"version": "0.1.2-preview",
"parameters": {
"basics": [
{}
],
"steps": [
{
"name": "domain",
"label": "Domain Names",
"elements": [
{
"name": "domainInfo",
"type": "Microsoft.Common.InfoBox",
"visible": true,
"options": {
"icon": "Info",
"text": "Pick the domain name that you want to use for your app."
}
},
{
"name": "appServiceAvailabilityApi",
"type": "Microsoft.Solutions.ArmApiControl",
"request": {
"method": "POST",
"path": "[concat(subscription().id, '/providers/Microsoft.Web/checknameavailability?api-version=2021-02-01')]",
"body": "[parse(concat('{\"name\":\"', concat('', steps('domain').domainName), '\", \"type\": \"Microsoft.Web/sites\"}'))]"
}
},
{
"name": "domainName",
"type": "Microsoft.Common.TextBox",
"label": "Domain Name Word",
"toolTip": "The name of your app service",
"placeholder": "yourcompanyname",
"constraints": {
"validations": [
{
"regex": "^[a-zA-Z0-9]{4,30}$",
"message": "Alphanumeric, between 4 and 30 characters."
},
{
"isValid": "[not(equals(steps('domain').appServiceAvailabilityApi.nameAvailable, false))]",
"message": "[concat('Error with the url: ', steps('domain').domainName, '. Reason: ', steps('domain').appServiceAvailabilityApi.reason)]"
},
{
"isValid": "[greater(length(steps('domain').domainName), 4)]",
"message": "The unique domain suffix should be longer than 4 characters."
},
{
"isValid": "[less(length(steps('domain').domainName), 30)]",
"message": "The unique domain suffix should be shorter than 30 characters."
}
]
}
},
{
"name": "section1",
"type": "Microsoft.Common.Section",
"label": "URLs to be created:",
"elements": [
{
"name": "domainExamplePortal",
"type": "Microsoft.Common.TextBlock",
"visible": true,
"options": {
"text": "[concat('https://', steps('domain').domainName, '.azurewebsites.net - The main app service URL')]"
}
}
],
"visible": true
}
]
}
],
"outputs": {
"desiredDomainName": "[steps('domain').domainName]"
}
}
}
You can copy the above code and test it in the createUiDefinition.json sandbox azure provides.

Passing the output from one arm deployment resource linked template to another

I am using a series of json ARM templates to deploy Azure VMs, and am having issues passing information from one resource deployment to another.
I deploy two resources using linked templates from blob storage, one which in and of itself deploys nothing, but returns an object populated with configuration settings, and a second which then passes that output of configuration settings to another template as a parameter:
"resources": [
{
"name": "[concat(deployment().name, '-config')]",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2016-09-01",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[variables('configurationTemplate')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"subscriptionParameters": { "value": "[variables('subscriptionParameters')]" }
}
}
},
{
"name": "[concat(deployment().name, '-vm')]",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2016-09-01",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[variables('vmTemplate')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"configuration": { "value": "[reference(concat(deployment().name, '-config').outputs.configuration.value)]" },
"vmName": { "value": "[parameters('vmName')]" },
"vmSize": { "value": "[parameters('vmSize')]" },
"os": { "value": "[parameters('os')]" },
"managedDiskTier": { "value": "[parameters('managedDiskTier')]" },
"dataDisksToProvision": { "value": "[parameters('dataDisksToProvision')]" },
"dataDiskSizeGB": { "value": "[parameters('dataDiskSizeGB')]" },
"domainJoined": { "value": "[parameters('domainJoined')]" },
"localAdminUsername": { "value": "[parameters('localAdminUsername')]" },
"localAdminPassword": { "value": "[parameters('localAdminPassword')]" },
"numberOfNics": { "value": "[parameters('numberOfNics')]" },
"subnetName": { "value": "[parameters('subnetName')]" },
"highlyAvailable": { "value": "[parameters('highlyAvailable')]" },
"availabilitySetName": { "value": "[parameters('availabilitySetName')]" },
"availabilitySetUpdateDomains": { "value": "[parameters('availabilitySetUpdateDomains')]" },
"availabilitySetFaultDomains": { "value": "[parameters('availabilitySetFaultDomains')]" }
}
}
}
],
"outputs": {
"configuration": {
"type": "object",
"value": "[reference(concat(deployment().name, '-config')).outputs.configuration.value]"
}
}
Deploying the first resource on it's own succeeds, and the output [reference(concat(deployment().name, '-config')).outputs.configuration.value] is correctly returned, and contains all the correct information and is well formed.
If I then add the second resource into the mix, then the deployment fails with
the following error:
08:57:41 - [ERROR] New-AzureRmResourceGroupDeployment : 08:57:41 - Error: Code=InvalidTemplate;
08:57:41 - [ERROR] Message=Deployment template validation failed: 'The template resource
08:57:41 - [ERROR] 'rcss.test.vm-0502-0757-rcss-vm' at line '317' and column '6' is not valid:
08:57:41 - [ERROR] The language expression property 'Microsoft.WindowsAzure.ResourceStack.Frontdoo
08:57:41 - [ERROR] r.Expression.Expressions.JTokenExpression' can't be evaluated.. Please see
08:57:41 - [ERROR] https://aka.ms/arm-template-expressions for usage details.'.
If I remove the "configuration" parameter from both this parameter set and from the referenced template (the referenced template has all contents commented out to ensure we are testing only the pass-through of the parameters), then the deployment succeeds, indicating that the issue is related to the parsing of the parameter string "[reference(concat(deployment().name, '-config').outputs.configuration.value)]".
Can anyone offer any insight as to whether I need to refer to output objects from deployment resources in a specific way in the context of a linked template parameter set?
So after examining this more closely, I found that the syntax I was using was incorrect, but not reported by the parser:
"[reference(concat(deployment().name, '-config').outputs.configuration.value)]"
Should have been:
"[reference(concat(deployment().name, '-config')).outputs.configuration.value]"
Schoolboy error.

ARM Error: The Template Resource is not found using resource(), copyIndex()

I'm trying to conditionally provide resource property values through translation of runtime resource properties within a copyIndex loop..
Upon deploying the following ARM template, I receive the error:
Unable to process template language expressions for resource '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.Compute/virtualMachines/{vm-name}/extensions/Microsoft.EnterpriseCloud.Monitoring' at line '30' and column '10'. 'The template resource '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.Compute/virtualMachines/{vm-name}' is not found.' (Code: InvalidTemplate)
"type": "[variables('extensionType')[reference(concat('Microsoft.Compute/virtualMachines/', parameters('virtualMachines')[copyIndex()].name)).storageProfile.osDisk.osType]]",
However, the VM exists with the ID it provides, so it doesn't make sense that the engine cannot find it. If I hard-code the Extension Type, there are no errors and the Extension is installed on the VM with the same ID.
Unfortunately, I don't know if this is a bug within ARM or if I'm just doing something wrong..
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"workspaceResourceId": { "type": "string" },
"virtualMachines": { "type": "array" }
},
"variables": {
"extensionType": {
"Windows": "MicrosoftMonitoringAgent",
"Linux": "OmsAgentForLinux"
}
},
"resources": [
{
"copy": {
"name": "VMMonitoringExtensionsCopy",
"count": "[length(parameters('virtualMachines'))]"
},
"type": "Microsoft.Compute/virtualMachines/extensions",
"apiVersion": "2015-05-01-preview",
"location": "[parameters('virtualMachines')[copyIndex()].location]",
"name": "[concat(parameters('virtualMachines')[copyIndex()].name, '/Microsoft.EnterpriseCloud.Monitoring')]",
"properties": {
"publisher": "Microsoft.EnterpriseCloud.Monitoring",
"type": "[variables('extensionType')[reference(concat('Microsoft.Compute/virtualMachines/', parameters('virtualMachines')[copyIndex()].name)).storageProfile.osDisk.osType]]",
"typeHandlerVersion": "1.0",
"autoUpgradeMinorVersion": true,
"settings": {
"workspaceId": "[reference(parameters('workspaceResourceId'), '2015-11-01-preview').customerId]"
},
"protectedSettings": {
"workspaceKey": "[listKeys(parameters('workspaceResourceId'), '2015-11-01-preview').primarySharedKey]"
}
}
}
]
}
The object array being passed in for virtualMachines looks like this:
[
{ "name": "vm-name", "location": "azure-region" }
]
A couple things you can try:
1) Assuming the VM is not defined in the same template try using the "full" resourceId in the reference function. See the last example in this doc:
https://azure.microsoft.com/en-us/documentation/articles/resource-group-template-functions/#reference - it seems like the error already knows the full resourceId, but it's worth trying
2) the other thought is that the reference function is evaluated at runtime and the resource provider doesn't like the expression but that's a swag.
I will do some more poking and see if we can't nail this down.