Passing all files in a folder via Terraform - terraform

I'm building a monitoring stack for our internal projects. I would like for them to be able to design their own monitoring dashboards to be used inside Grafana so I cannot predict what those will be called.
I created a folder called grafana_dashboard, where I will be instructing them to store their dashboard as JSON files and I want to pass all the contents of that folder to the Grafana instance.
I have tried a number of variations of this :
resource "grafana_dashboard" "dashboards" {
for_each = fileset(path.module, "grafana_dashboard/*.json")
config_json = "${each.key}"
depends_on = [aiven_service.grafana]
}
But keep getting this error:
Error: invalid character 'g' looking for beginning of value
on ../modules/monitoring/grafana.tf line 139, in resource "grafana_dashboard" "dashboards":
139: resource "grafana_dashboard" "dashboards" {
Can any of you see what I'm doing wrong?
Here's an example of one of the .json files i'm trying to pass:
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
},
{
"datasource": "Prometheus",
"enable": true,
"expr": "sum(changes(nginx_ingress_controller_config_last_reload_successful_timestamp_seconds{instance!=\"unknown\",controller_class=~\"$controller_class\",namespace=~\"$namespace\"}[30s])) by (controller_class)",
"hide": false,
"iconColor": "rgba(255, 96, 96, 1)",
"limit": 100,
"name": "Config Reloads",
"showIn": 0,
"step": "30s",
"tagKeys": "controller_class",
"tags": [],
"titleFormat": "Config Reloaded",
"type": "tags"
}
]
},
"description": "Ingress-nginx supports a rich collection of prometheus metrics. If you have prometheus and grafana installed on your cluster then prometheus will already be scraping this data due to the scrape annotation on the deployment.",
"editable": false,
"gnetId": 9614,
"graphTooltip": 0,
"id": 18,
"iteration": 1574177838584,
"links": [],
"panels": [
{
"columns": [
{
"text": "Current",
"value": "current"
}
],
"datasource": "Prometheus",
"fontSize": "100%",
"gridPos": {
"h": 15,
"w": 24,
"x": 0,
"y": 0
},
"height": "1024",
"id": 85,
"links": [],
"options": {},
"pageSize": 15,
"scroll": true,
"showHeader": true,
"sort": {
"col": 1,
"desc": false
},
"styles": [
{
"alias": "Time",
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "Time",
"type": "date"
},
{
"alias": "TTL",
"colorMode": "cell",
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 0,
"pattern": "Current",
"thresholds": [
"0",
"691200"
],
"type": "number",
"unit": "s"
},
{
"alias": "",
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"decimals": 2,
"pattern": "/.*/",
"thresholds": [],
"type": "number",
"unit": "short"
}
],
"targets": [
{
"expr": "avg(nginx_ingress_controller_ssl_expire_time_seconds{kubernetes_pod_name=~\"$controller\",namespace=~\"$namespace\",ingress=~\"$ingress\"}) by (host) - time()",
"format": "time_series",
"instant": false,
"intervalFactor": 1,
"legendFormat": "{{ host }}",
"metric": "gke_letsencrypt_cert_expiration",
"refId": "A",
"step": 1
}
],
"title": "Ingress Certificate Expiry",
"transform": "timeseries_aggregations",
"type": "table"
}
],
"refresh": "5s",
"schemaVersion": 19,
"style": "dark",
"tags": [
"nginx"
],
"templating": {
"list": [
{
"allValue": ".*",
"current": {
"text": "All",
"value": "$__all"
},
"datasource": "Prometheus",
"definition": "",
"hide": 0,
"includeAll": true,
"label": "Namespace",
"multi": false,
"name": "namespace",
"options": [],
"query": "label_values(nginx_ingress_controller_config_hash, controller_namespace)",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"allValue": ".*",
"current": {
"text": "All",
"value": "$__all"
},
"datasource": "Prometheus",
"definition": "",
"hide": 0,
"includeAll": true,
"label": "Controller Class",
"multi": false,
"name": "controller_class",
"options": [],
"query": "label_values(nginx_ingress_controller_config_hash{namespace=~\"$namespace\"}, controller_class) ",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"allValue": ".*",
"current": {
"text": "All",
"value": "$__all"
},
"datasource": "Prometheus",
"definition": "",
"hide": 0,
"includeAll": true,
"label": "Controller",
"multi": false,
"name": "controller",
"options": [],
"query": "label_values(nginx_ingress_controller_config_hash{namespace=~\"$namespace\",controller_class=~\"$controller_class\"}, controller_pod) ",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
},
{
"allValue": ".*",
"current": {
"text": "All",
"value": "$__all"
},
"datasource": "Prometheus",
"definition": "",
"hide": 0,
"includeAll": true,
"label": "Ingress",
"multi": false,
"name": "ingress",
"options": [],
"query": "label_values(nginx_ingress_controller_requests{namespace=~\"$namespace\",controller_class=~\"$controller_class\",controller=~\"$controller\"}, ingress) ",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 2,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
}
]
},
"time": {
"from": "now-5m",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"2m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "browser",
"title": "Cert-manager",
"uid": "nginx",
"version": 12
}
This works, so I know that I can do it, but doesn't suit my needs as I'd need to hardcode the name of each file:
resource "grafana_dashboard" "nginx_ingress_controller" {
config_json = templatefile("${path.module}/grafana_dashboard/nginx-ingress-controller.json", { DS_PROMETHEUS = local.prometheus_datasource_name })
depends_on = [aiven_service.grafana]
}

You need to actually use the file contents in your config_json parameter to the grafana_dashboard.
Switching your resource definition to the following should be enough:
resource "grafana_dashboard" "dashboards" {
for_each = fileset(path.module, "grafana_dashboard/*.json")
config_json = file("${path.module}/${each.key}")
depends_on = [aiven_service.grafana]
}

Related

IIOT OPCUA Alarms and Events node-red

I am working on OPC DA & AE. For that, I am using the IIOT OPCUA node in Node-red.
With the IIOT OPCUA node in Node-red I am able to connect and access data but for accessing the alarms and events not getting what to do.
I have tested my OPCAE server with the OPC expert tool and it's working fine but I want to execute alarms and events with Node-red.
Please help me out regarding this issue.
Thank you.
I havenĀ“t worked with alarms and events yet but you or other people interessted may have a look on this discusion.
OPCUA-TEST-NODES.json contains an examples for testing events:
[
{
"id": "6413368d70ce7daa",
"type": "tab",
"label": "Test Nodes",
"disabled": false
},
{
"id": "42ce521b1148624d",
"type": "OpcUa-Event",
"z": "6413368d70ce7daa",
"root": "ns=0;i=2253",
"eventtype": "i=2041",
"name": "Events",
"x": 570,
"y": 480,
"wires": [
[
"59e10624d8d6798b",
"7bc93ab21da004f4"
]
]
},
{
"id": "50afc9882c32c9b1",
"type": "inject",
"z": "6413368d70ce7daa",
"name": "Test Events",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": "",
"topic": "",
"payload": "",
"payloadType": "str",
"x": 370,
"y": 480,
"wires": [
[
"42ce521b1148624d"
]
]
},
{
"id": "59e10624d8d6798b",
"type": "OpcUa-Client",
"z": "6413368d70ce7daa",
"endpoint": "bb039652.dcf5a8",
"action": "events",
"deadbandvalue": "",
"time": 10,
"timeUnit": "s",
"localfile": "",
"localkeyfile": "",
"securitymode": "None",
"securitypolicy": "None",
"folderName4PKI": "",
"name": "A & C",
"x": 730,
"y": 480,
"wires": [
[
"47d20f3e7618f5db"
]
]
},
{
"id": "9598544e1e208e0c",
"type": "OpcUa-Client",
"z": "6413368d70ce7daa",
"endpoint": "bb039652.dcf5a8",
"action": "acknowledge",
"deadbandtype": "a",
"deadbandvalue": "5",
"time": "1",
"timeUnit": "s",
"localfile": "",
"localkeyfile": "",
"securitymode": "None",
"securitypolicy": "None",
"name": "ProSys NONE",
"x": 1060,
"y": 580,
"wires": [
[]
]
},
{
"id": "47d20f3e7618f5db",
"type": "debug",
"z": "6413368d70ce7daa",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 890,
"y": 480,
"wires": []
},
{
"id": "9a7458deff86b3b0",
"type": "inject",
"z": "6413368d70ce7daa",
"name": "Test Events",
"repeat": "",
"crontab": "",
"once": false,
"topic": "",
"payload": "",
"payloadType": "str",
"x": 370,
"y": 580,
"wires": [
[
"d02ed4a7087a2cd8"
]
]
},
{
"id": "d02ed4a7087a2cd8",
"type": "function",
"z": "6413368d70ce7daa",
"name": "AlarmID and EventID",
"func": "var msg;\nmsg.topic = \"ns=6;s=MyLevel.Alarm\";\nmsg.conditionId = \"ns=6;s=MyLevel.Alarm/0:EventId\";\nmsg.comment = \"Node-RED OPCUA Ack\";\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 630,
"y": 580,
"wires": [
[
"9598544e1e208e0c"
]
]
},
{
"id": "7bc93ab21da004f4",
"type": "debug",
"z": "6413368d70ce7daa",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 730,
"y": 440,
"wires": []
},
{
"id": "bb039652.dcf5a8",
"type": "OpcUa-Endpoint",
"endpoint": "opc.tcp://H7Q8Q13.vstage.co:53530/OPCUA/SimulationServer",
"secpol": "None",
"secmode": "None",
"login": false
}
]
{
"id": "7bc93ab21da004f4",
"type": "debug",
"z": "6413368d70ce7daa",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 730,
"y": 440,
"wires": []
},
{
"id": "bb039652.dcf5a8",
"type": "OpcUa-Endpoint",
"endpoint": "opc.tcp://H7Q8Q13.vstage.co:53530/OPCUA/SimulationServer",
"secpol": "None",
"secmode": "None",
"login": false
},
{
"id": "85144921.8931b8",
"type": "ui_group",
"name": "OPCUA",
"tab": "440c46c6.769ab8",
"order": 1,
"disp": true,
"width": "6",
"collapse": false
},
{
"id": "440c46c6.769ab8",
"type": "ui_tab",
"name": "Home",
"icon": "dashboard",
"disabled": false,
"hidden": false
}
]

get metadata, ForEach and copy activity in Azure Data Factory

I want to copy 2 tables from blob storage to SQL Database.
I created pipeline like this:-
Get MetaData:- For capturing the files (2 csv files) in the input container
ForEach:- For iterating the files in input container
Copy activity:- Inside the ForEach. Copy both of the files in SQL database.
Now, when I started debugging, I got the error 2200 and it says userBlobDoesNotExists.
Here is the error code for the copy activity:-
"copyDuration": 3,
"errors": [
{
"Code": 9013,
"Message": "ErrorCode=UserErrorSourceBlobNotExist,'Type=Microsoft.DataTransfer.Common.Shared.HybridDeliveryException,Message=The required Blob is missing. ContainerName: https://employeestorage1.blob.core.windows.net/employeeinput, path: employeeinput/workdetail.csv.,Source=Microsoft.DataTransfer.ClientLibrary,'",
"EventType": 0,
"Category": 5,
"Data": {},
"MsgId": null,
"ExceptionType": null,
"Source": null,
"StackTrace": null,
"InnerEventInfos": []
}
],
"effectiveIntegrationRuntime": "DefaultIntegrationRuntime (East US)",
"usedDataIntegrationUnits": 4,
"billingReference": {
"activityType": "DataMovement",
"billableDuration": [
{
"meterType": "AzureIR",
"duration": 0.06666666666666667,
"unit": "DIUHours"
}
]
},
"usedParallelCopies": 1,
"executionDetails": [
{
"source": {
"type": "AzureBlobStorage",
"region": "East US"
},
"sink": {
"type": "AzureSqlDatabase",
"region": "East US"
},
"status": "Failed",
"start": "2021-06-24T17:28:09.4507134Z",
"duration": 3,
"usedDataIntegrationUnits": 4,
"usedParallelCopies": 1,
"profile": {
"queue": {
"status": "Completed",
"duration": 2
},
"transfer": {
"status": "Completed",
"duration": 0
}
},
"detailedDurations": {
"queuingDuration": 2,
"transferDuration": 0
}
}
],
"dataConsistencyVerification": {
"VerificationResult": "Unsupported"
},
"durationInQueue": {
"integrationRuntimeQueue": 0
}
}
And here is the code for the pipeline:-
{
"name": "pipeline1",
"properties": {
"activities": [
{
"name": "inputfolder",
"type": "GetMetadata",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"dataset": {
"referenceName": "employeeinputdataset",
"type": "DatasetReference"
},
"fieldList": [
"childItems"
],
"storeSettings": {
"type": "AzureBlobStorageReadSettings",
"enablePartitionDiscovery": false
},
"formatSettings": {
"type": "DelimitedTextReadSettings"
}
}
},
{
"name": "for each table in input folder",
"type": "ForEach",
"dependsOn": [
{
"activity": "inputfolder",
"dependencyConditions": [
"Succeeded"
]
}
],
"userProperties": [],
"typeProperties": {
"items": {
"value": "#activity('inputfolder').output.Childitems",
"type": "Expression"
},
"activities": [
{
"name": "Copy data1",
"type": "Copy",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"source": {
"type": "DelimitedTextSource",
"storeSettings": {
"type": "AzureBlobStorageReadSettings",
"recursive": true,
"wildcardFolderPath": "employeeinput",
"wildcardFileName": {
"value": "#item().name",
"type": "Expression"
},
"enablePartitionDiscovery": false
},
"formatSettings": {
"type": "DelimitedTextReadSettings"
}
},
"sink": {
"type": "AzureSqlSink",
"tableOption": "autoCreate",
"disableMetricsCollection": false
},
"enableStaging": false,
"translator": {
"type": "TabularTranslator",
"typeConversion": true,
"typeConversionSettings": {
"allowDataTruncation": true,
"treatBooleanAsNumber": false
}
}
},
"inputs": [
{
"referenceName": "employeeinputdataset",
"type": "DatasetReference"
}
],
"outputs": [
{
"referenceName": "employeeoutputsql",
"type": "DatasetReference",
"parameters": {
"OutputTableName": {
"value": "#item().name",
"type": "Expression"
}
}
}
]
}
]
}
}
],
"annotations": []
}
}
Don't choose Wildcard file path in the File path type setting, please choose File path in dataset to have a try.
And you need to create a parameter in your Source dataset. In the File path of Source dataset, type the #dataset().fileName expression. Finally, pass #item().name to the parameter of dataset is ok.
Screenshots:

Creating a website-popup in Node-RED Dashboard

I'm creating an Interactive Floor Plan using Node-RED (with Dashboard and "node-red-contrib-ui-svg"
My problem: I want a Website-popup in the Node-RED Dashboard by clicking on an information icon but i don't know how to create the popup. I tryed it with the "http in", "http request", "http response" and function nodes, but it didn't work. Maybe i just don't get the payload right?
By clicking on the SVG, a event is starting and the SVG Node sends a payload to the output.
Later there should be multiple events with different SVGs opening different URL-popups
Does someone know, if it is possible to create a popup in the Node-RED Dashboard and if yes, tell me how i can do it?
Here is a small example flow of what i tried:
[
{
"id": "213370b.a1a7e9",
"type": "tab",
"label": "Floorplan",
"disabled": false,
"info": ""
},
{
"id": "3a8acfc1.2d033",
"type": "debug",
"z": "213370b.a1a7e9",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 570,
"y": 100,
"wires": []
},
{
"id": "3d085e29.713452",
"type": "http in",
"z": "213370b.a1a7e9",
"name": "googl",
"url": "svg",
"method": "get",
"upload": false,
"swaggerDoc": "",
"x": 90,
"y": 100,
"wires": [
[
"3e9f0610.1b40da"
]
]
},
{
"id": "7e8c6b26.c6b194",
"type": "http response",
"z": "213370b.a1a7e9",
"name": "",
"statusCode": "",
"headers": {},
"x": 570,
"y": 60,
"wires": []
},
{
"id": "e6a43abb.2208c8",
"type": "function",
"z": "213370b.a1a7e9",
"name": "",
"func": "msg.responseUrl=msg.payload;\nmsg.payload=msg.payload\n\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 450,
"y": 80,
"wires": [
[
"7e8c6b26.c6b194",
"3a8acfc1.2d033"
]
]
},
{
"id": "3e9f0610.1b40da",
"type": "http request",
"z": "213370b.a1a7e9",
"name": "",
"method": "GET",
"ret": "txt",
"paytoqs": false,
"url": "nodered.org",
"tls": "",
"persist": false,
"proxy": "",
"authType": "",
"x": 270,
"y": 100,
"wires": [
[
"e6a43abb.2208c8"
]
]
},
{
"id": "2360d5fd.e4dc9a",
"type": "ui_svg_graphics",
"z": "213370b.a1a7e9",
"group": "ff128f4a.e252",
"order": 1,
"width": 0,
"height": 0,
"svgString": "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0\" y=\"0\" height=\"100\" viewBox=\"0 0 100 100\" width=\"100\"><rect id=\"svgEditorBackground\" x=\"0\" y=\"0\" width=\"100\" height=\"100\" style=\"fill:none; stroke: none;\"/><defs id=\"svgEditorDefs\"><symbol id=\"2139\" viewBox=\"0 0 64 64\" preserveAspectRatio=\"xMidYMid meet\"><rect x=\"0\" y=\"0\" width=\"64\" height=\"64\" style=\"stroke:none;fill:none;\"/><g xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"32\" cy=\"32\" fill=\"#42ade2\" r=\"30\"/><g fill=\"#fff\"><path d=\"m36.51 25h-6.992c-2.633 0-5.145 1.05-5.584 2.333-.436 1.284.447 2.334 1.965 2.334s2.072 2.02 1.23 4.492l-4.889 14.349c-.844 2.471.619 4.492 3.252 4.492h6.992c2.633 0 5.143-1.051 5.582-2.333.436-1.283-.447-2.335-1.963-2.335-1.518 0-2.072-2.02-1.23-4.491l4.889-14.349c.843-2.47-.619-4.492-3.252-4.492\"/><path d=\"m36.29 11c-2.666 0-5.406 2.238-6.121 5-.717 2.761.869 4.999 3.533 4.999 2.668 0 5.408-2.238 6.123-4.999.717-2.763-.867-5-3.535-5\"/></g></g></symbol><polygon id=\"svgEditorIconDefs\" style=\"fill:rosybrown;\"/></defs><use xlink:href=\"#2139\" x=\"4.410\" y=\"4.552\" width=\"19.061\" height=\"19.061\" id=\"svg_i\" transform=\"matrix(1.87014 0 0 1.87014 -2.59955 -2.72311)\"/></svg>",
"clickableShapes": [
{
"targetId": "#svg_i",
"action": "click",
"payload": "http://www.google.com",
"payloadType": "str",
"topic": "#svg_i"
}
],
"smilAnimations": [],
"bindings": [],
"showCoordinates": false,
"autoFormatAfterEdit": false,
"showBrowserErrors": false,
"outputField": "payload",
"editorUrl": "//drawsvg.org/drawsvg.html",
"directory": "",
"panning": "disabled",
"zooming": "disabled",
"panOnlyWhenZoomed": false,
"doubleClickZoomEnabled": false,
"mouseWheelZoomEnabled": false,
"name": "",
"x": 120,
"y": 60,
"wires": [
[
"e6a43abb.2208c8"
]
]
},
{
"id": "ff128f4a.e252",
"type": "ui_group",
"z": "",
"name": "SVG",
"tab": "9f9846f6.57ce98",
"order": 1,
"disp": true,
"width": "23",
"collapse": false
},
{
"id": "9f9846f6.57ce98",
"type": "ui_tab",
"z": "",
"name": "Background",
"icon": "dashboard",
"disabled": false,
"hidden": false
}
]
If you are still searching a solution, "modal dialog" is what you are looking for. Try this:
https://discourse.nodered.org/t/how-to-show-modal-dialog-in-template-node/611/8

node-red Mqtt, how to close socket connection

red-contrib-mqtt-broker` as mqtt broker. connection/disconnection of clients, are happening fine but in backend sockets are not getting closed immediately so sockets getting pileup.and its leading to server down.
please help me how to resolve this issue.
here is my node-red flow
[
{
"checkall": "false",
"id": "75e2813d.1200d",
"name": "chkTopic",
"outputs": 3,
"property": "topic",
"propertyType": "msg",
"repair": false,
"rules": [
{
"t": "eq",
"v": "clientConnected",
"vt": "str"
},
{
"t": "eq",
"v": "published",
"vt": "str"
},
{
"t": "eq",
"v": "clientDisconnected",
"vt": "str"
}
],
"type": "switch",
"wires": [
[
"e44d3fd.601fcc"
],
[
"b0cbe2f0.fdf51"
],
[
"352b1527.c0382a"
]
],
"x": 340,
"y": 120,
"z": "9207591e.000228"
},
{
"dburl": "",
"id": "169a1574.037e8b",
"mqtt_port": "6883",
"mqtt_ws_port": "6889",
"name": "Silsung ST Connector",
"password": "ajay1234",
"type": "mosca in",
"username": "admin",
"wires": [
[
"75e2813d.1200d"
]
],
"x": 140,
"y": 120,
"z": "9207591e.000228"
},
{
"active": true,
"complete": "payload",
"console": false,
"id": "b0cbe2f0.fdf51",
"name": "",
"tosidebar": true,
"tostatus": false,
"type": "debug",
"wires": [],
"x": 530,
"y": 120,
"z": "9207591e.000228"
},
{
"active": true,
"complete": "payload",
"console": false,
"id": "352b1527.c0382a",
"name": "",
"tosidebar": true,
"tostatus": false,
"type": "debug",
"wires": [],
"x": 530,
"y": 180,
"z": "9207591e.000228"
},
{
"active": true,
"complete": "payload",
"console": false,
"id": "e44d3fd.601fcc",
"name": "",
"tosidebar": true,
"tostatus": false,
"type": "debug",
"wires": [],
"x": 510,
"y": 60,
"z": "9207591e.000228"
}
]

Copyindex in deploying dashboard resources Azure ARM

I am deploying a custom Azure Dashboard with a tile that makes use of a resource.
To call the resource I use following code
"[resourceId(parameters('analysisServiceResourceGroup'), '/Microsoft.AnalysisServices/servers', parameters('analysisServiceName'))]"
But in one of the tiles I need multiple resources so I tried something out to make a parameter file with following value
"analysisService": {
"value": [
{
"ResourceGroup": "RG",
"Name": "analysis1",
"Color": "#47BDF5"
},
{
"ResourceGroup": "RG",
"Name": "analysis2",
"Color": "#7E58FF"
},
{
"ResourceGroup": "RG",
"Name": "analysis3",
"Color": "#EB9371"
}
]
},
In my dashboard template i use following code to get the name and resource group.
"resourceId": "[resourceId(parameters('analysisService')[copyIndex()].ResourceGroup, '/Microsoft.AnalysisServices/servers', parameters('analysisService')[copyIndex()].Name)]"
The problem I got at the moment my copy object is not placed in the right place. I got this error
'The template function 'copyIndex' is not expected at this location. The function can only be used in a resource with copy specified. Please see https://aka.ms/arm-copy for usage details.'"
This says that my copy index block is not used in the right resource bracelet but I don't know where i can place this copy Index , tried to put this in every possible place where the copy index can access this but nothing works does anyone know what I do wrong or what I do wrong. It may be possible that copyindex doesn't work inside a dashboard resource.
Code
"12": {
"position": {
"x": 12,
"y": 9,
"colSpan": 6,
"rowSpan": 4
},
"metadata": {
"inputs": [
{
"name": "sharedTimeRange",
"isOptional": true
},
{
"name": "options",
"value": {
"charts": [
{
"metrics": [
{
"name": "CurrentUserSessions",
"resourceMetadata": {
"resourceId": "[resourceId(parameters('analysisService')[copyIndex()].ResourceGroup, '/Microsoft.AnalysisServices/servers', parameters('analysisService')[copyIndex()].Name)]"
},
"aggregationType": 1,
"copy": {
"name": "AnalysisServiceCopy",
"count": "[length(parameters('analysisService'))]"
},
}
],
"title": "Avg Current User Sessions for analysis1, analysis1, and analysis1",
"visualization": {
"chartType": 2,
"legend": {
"isVisible": true,
"position": 2,
"hideSubtitle": false
},
"axis": {
"x": {
"isVisible": true,
"axisType": 2,
"min": 1546508634047,
"max": 1546595034047
},
"y": {
"isVisible": true,
"axisType": 1
}
},
"timeBrushEnable": false
},
"itemDataModel": {
"id": "3464BA29-9AF2-4EAE-9CF4-A246059DDF46",
"chartHeight": 1,
"metrics": [
{
"id": {
"resourceDefinition": {
"id": "[resourceId(parameters('analysisService')[copyIndex()].ResourceGroup, '/Microsoft.AnalysisServices/servers', parameters('analysisService')[copyIndex()].Name)]"
},
"name": {
"id": "CurrentUserSessions",
"displayName": "Current User Sessions"
},
"namespace": {
"name": "microsoft.analysisservices/servers"
}
},
"metricAggregation": 4,
"color": "[parameters('analysisService')[copyIndex()].Color]"
,
"copy": {
"name": "AnalysisServiceCopy",
"count": "[length(parameters('analysisService'))]"
},
}
],
"priorPeriod": false,
"horizontalBars": true,
"showOther": false,
"aggregation": 1,
"palette": "multiColor",
"jsonDefinitionId": "59DCE403-7D8D-4E9F-9CDA-7AE7AC9D9220",
"version": {
"major": 1,
"minor": 0,
"build": 0
},
"filters": {
"filterType": 0,
"id": "C81486BB-3934-48C7-9251-A4EE633DB2BB",
"OperandFilters": [],
"LogicalOperator": 0
},
"yAxisOptions": {
"options": 1
},
"title": "Avg Current User Sessions for analysis1, analysis1, and analysis1",
"titleKind": "Auto",
"visualization": {
"chartType": 2,
"legend": {
"isVisible": true,
"position": 2,
"hideSubtitle": false
},
"axis": {
"x": {
"isVisible": true,
"axisType": 2,
"min": 1546508634047,
"max": 1546595034047
},
"y": {
"isVisible": true,
"axisType": 1
}
},
"timeBrushEnable": false
}
}
}
],
"v2charts": true,
"version": 1
},
"isOptional": true
}
],
"type": "Extension/HubsExtension/PartType/MonitorChartPart",
"settings": {
"content": {
"options": {
"charts": [
{
"metrics": [
{
"name": "CurrentUserSessions",
"resourceMetadata": {
"resourceId": "[resourceId(parameters('analysisService')[copyIndex()].ResourceGroup, '/Microsoft.AnalysisServices/servers', parameters('analysisService')[copyIndex()].Name)]"
},
"aggregationType": 1
,
"copy": {
"name": "AnalysisServiceCopy",
"count": "[length(parameters('analysisService'))]"
},
}
],
"title": "Avg Current User Sessions for analysis1, analysis1, and analysis1",
"visualization": {
"chartType": 2,
"legend": {
"isVisible": true,
"position": 2,
"hideSubtitle": false
},
"axis": {
"x": {
"isVisible": true,
"axisType": 2,
"min": 1546508634047,
"max": 1546595034047
},
"y": {
"isVisible": true,
"axisType": 1
}
},
"timeBrushEnable": false
},
"itemDataModel": {
"id": "3464BA29-9AF2-4EAE-9CF4-A246059DDF46",
"chartHeight": 1,
"metrics": [
{
"id": {
"resourceDefinition": {
"id": "[resourceId(parameters('analysisService')[copyIndex()].ResourceGroup, '/Microsoft.AnalysisServices/servers', parameters('analysisService')[copyIndex()].Name)]"
},
"name": {
"id": "CurrentUserSessions",
"displayName": "Current User Sessions"
},
"namespace": {
"name": "microsoft.analysisservices/servers"
}
},
"metricAggregation": 4,
"color": "[parameters('analysisService')[copyIndex()].Color]"
,
"copy": {
"name": "AnalysisServiceCopy",
"count": "[length(parameters('analysisService'))]"
},
}
],
"priorPeriod": false,
"horizontalBars": true,
"showOther": false,
"aggregation": 1,
"palette": "multiColor",
"jsonDefinitionId": "59DCE403-7D8D-4E9F-9CDA-7AE7AC9D9220",
"version": {
"major": 1,
"minor": 0,
"build": 0
},
"filters": {
"filterType": 0,
"id": "C81486BB-3934-48C7-9251-A4EE633DB2BB",
"OperandFilters": [],
"LogicalOperator": 0
},
"yAxisOptions": {
"options": 1
},
"title": "Avg Current User Sessions for analysis1, analysis1, and analysis1",
"titleKind": "Auto",
"visualization": {
"chartType": 2,
"legend": {
"isVisible": true,
"position": 2,
"hideSubtitle": false
},
"axis": {
"x": {
"isVisible": true,
"axisType": 2,
"min": 1546508634047,
"max": 1546595034047
},
"y": {
"isVisible": true,
"axisType": 1
}
},
"timeBrushEnable": false
}
},
"disablePinning": true
}
],
"v2charts": true,
"version": 1
}
}
}
}
},
"copy": {
"name": "AnalysisServiceCopy",
"count": "[length(parameters('analysisService'))]"
},
so, as a general rule, you can only use copy loop to create arrays, not object, so to construct you metrics array you would do something like this:
"charts": [
{
"copy": [
{
"name": "metrics",
"count": "[length(parameters('analysisService'))]",
"input": {
"name": "CurrentUserSessions",
"resourceMetadata": {
"resourceId": "[resourceId(parameters('analysisService')[copyIndex('metrics')].ResourceGroup, '/Microsoft.AnalysisServices/servers', parameters('analysisService')[copyIndex('metrics')].Name)]"
},
"aggregationType": 1
}
}
],
"title": "Avg Current User Sessions for analysis1, analysis1, and analysis1",
"visualization": { redacted for brievity },
"itemDataModel": { redacted for brievity },
"disablePinning": true
}
],
you would need to do this everywhere you need to construct an array. as a workaround (if they are identical) you can use the same construct to create a variable and use that variable:
"variables": {
"copy": [
{
"name": "metrics",
"count": "[length(parameters('analysisService'))]",
"input": {
"name": "CurrentUserSessions",
"resourceMetadata": {
"resourceId": "[resourceId(parameters('analysisService')[copyIndex('metrics')].ResourceGroup, '/Microsoft.AnalysisServices/servers', parameters('analysisService')[copyIndex('metrics')].Name)]"
},
"aggregationType": 1
}
}
],
}
the above will create a variable called "metrics" which you can use anywhere in the template like so:
"[variables('metrics')]"
#4c74356b41
I tried it like this , I directly get an green error line beneath copy that this varbiable never is used.
"variables": {
"copy": [
{
"name": "metrics",
"count": "[length(parameters('analysisService'))]",
"input": {
"name": "qpu_metric",
"resourceMetadata": {
"resourceId": "[resourceId(parameters('analysisService')[copyIndex('metrics')].ResourceGroup, 'Microsoft.AnalysisServices/servers', parameters('analysisService')[copyIndex('metrics')].Name)]"
},
"aggregationType": 1
}
}
]
},
In my code I call the variable like this
"charts": [
{
"metrics" : "[variables('metrics')]",
"title": "Avg QPU",
"visualization": {

Resources