NETWAYS / NETWAYS/icingaweb2-module-grafana

[Bug]: Repeating Panel is not working

Open
#64 3 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
PHP
Stars
39
Forks
10
Avg merge
2m
Merged PRs (30d)
1

Description

Please try to fill out as much of the information below as you can. Thank you!
  • Yes, I've searched similar issues on GitHub and didn't find any.
Which version contains the bug?

3.0.0 and 3.1.0

Describe the bug

I've created a repeating panel in Grafana (Version 11.6.0) (for disk-usage of every partition) Datasource is an influxdb2 when I try to view the data in icinga, and set the graph to repeatable it shows the coreect panel and multiple panels (with a higher id)

the repeating panel-id is 16 and the subpanels are named 16-clone-0 to 16-clone-
the module seems to think that the id of the repeating panels would increase like 16,17,18... which explains the wrong pannels being shown.

How to recreate the bug?

Graph:

  "id": 16,
  "maxPerRow": 12,
  "options": {
    "legend": {
      "calcs": [],
      "displayMode": "list",
      "placement": "bottom",
      "showLegend": true
    },
    "tooltip": {
      "hideZeros": false,
      "mode": "single",
      "sort": "none"
    }
  },
  "pluginVersion": "11.5.1",
  "repeat": "disk",
  "repeatDirection": "h",
  "targets": [
    {
      "datasource": {
        "type": "influxdb",
        "uid": "xxx"
      },
      "hide": false,
      "query": "import \"types\"\nimport \"experimental\"\n// Declaration of buckets and retention periods\nbucket0=\"icinga2\"\nbucket1=\"icinga2_5m_samples\"\nbucket2=\"icinga2_30min_samples\"\nretention0=7d\nretention1=90d\n// handling of diffrent timepicker modes e.g. \"-3d\" vs \"From 03.07.1980 17:00:00 To 07.09.1980 19:35:00\"\nisduration = if types.isType(v: v.timeRangeStart, type: \"duration\") then\ntrue else false\nret0=if isduration then uint(v: -retention0) else uint(v:\nexperimental.subDuration(d: retention0, from: now()))\nret1=if isduration then uint(v: -retention1) else uint(v:\nexperimental.subDuration(d: retention1, from: now()))\n// if start date is before retention0 then bucket1, if start date is before retention1 then bucket2\nbuckett=if uint(v: v.timeRangeStart) > ret0 then\n bucket0\nelse if uint(v: v.timeRangeStart) > ret1 then\n bucket1\nelse\n bucket2\n// the actual query with host/service filter\nfrom(bucket: buckett)\n  |> range(start: v.timeRangeStart, stop:v.timeRangeStop)\n  |> filter(fn: (r) =>\n    r._measurement == \"disk\" and\n    r._field == \"value\" and\n    r.hostname == \"${hostname}\" and\n    r.metric == \"${disk}\"\n  )\n  |> filter(\n    fn: (r) => if buckett != \"icinga2\" then \n        r.aggregate == \"mean\"\n    else\n      true,\n  )\n  |> map(fn: (r) => ({ _value:r._value, _time:r._time, _field: r.metric }))",
      "refId": "A"
    },
    {
      "datasource": {
        "type": "influxdb",
        "uid": "xxx"
      },
      "hide": false,
      "query": "import \"types\"\nimport \"experimental\"\n// Declaration of buckets and retention periods\nbucket0=\"icinga2\"\nbucket1=\"icinga2_5m_samples\"\nbucket2=\"icinga2_30min_samples\"\nretention0=7d\nretention1=90d\n// handling of diffrent timepicker modes e.g. \"-3d\" vs \"From 03.07.1980 17:00:00 To 07.09.1980 19:35:00\"\nisduration = if types.isType(v: v.timeRangeStart, type: \"duration\") then\ntrue else false\nret0=if isduration then uint(v: -retention0) else uint(v:\nexperimental.subDuration(d: retention0, from: now()))\nret1=if isduration then uint(v: -retention1) else uint(v:\nexperimental.subDuration(d: retention1, from: now()))\n// if start date is before retention0 then bucket1, if start date is before retention1 then bucket2\nbuckett=if uint(v: v.timeRangeStart) > ret0 then\n bucket0\nelse if uint(v: v.timeRangeStart) > ret1 then\n bucket1\nelse\n bucket2\n// the actual query with host/service filter\nfrom(bucket: buckett)\n  |> range(start: v.timeRangeStart, stop:v.timeRangeStop)\n  |> filter(fn: (r) =>\n    r._measurement == \"disk\" and\n    r.hostname == \"${hostname}\" and\n    r.metric == \"${disk}\" and\n    r._field == \"warn\"\n  )\n  |> filter(\n    fn: (r) => if buckett != \"icinga2\" then \n        r.aggregate == \"mean\"\n    else\n      true,\n  )\n  |> map(fn: (r) => ({ _value:r._value, _time:r._time, _field: r._field}))",
      "refId": "B"
    },
    {
      "datasource": {
        "type": "influxdb",
        "uid": "xxx"
      },
      "hide": false,
      "query": "import \"types\"\nimport \"experimental\"\n// Declaration of buckets and retention periods\nbucket0=\"icinga2\"\nbucket1=\"icinga2_5m_samples\"\nbucket2=\"icinga2_30min_samples\"\nretention0=7d\nretention1=90d\n// handling of diffrent timepicker modes e.g. \"-3d\" vs \"From 03.07.1980 17:00:00 To 07.09.1980 19:35:00\"\nisduration = if types.isType(v: v.timeRangeStart, type: \"duration\") then\ntrue else false\nret0=if isduration then uint(v: -retention0) else uint(v:\nexperimental.subDuration(d: retention0, from: now()))\nret1=if isduration then uint(v: -retention1) else uint(v:\nexperimental.subDuration(d: retention1, from: now()))\n// if start date is before retention0 then bucket1, if start date is before retention1 then bucket2\nbuckett=if uint(v: v.timeRangeStart) > ret0 then\n bucket0\nelse if uint(v: v.timeRangeStart) > ret1 then\n bucket1\nelse\n bucket2\n// the actual query with host/service filter\nfrom(bucket: buckett)\n  |> range(start: v.timeRangeStart, stop:v.timeRangeStop)\n  |> filter(fn: (r) =>\n    r._measurement == \"disk\" and\n    r.hostname == \"${hostname}\" and\n    r.metric == \"${disk}\" and\n    r._field == \"crit\"\n  )\n  |> filter(\n    fn: (r) => if buckett != \"icinga2\" then \n        r.aggregate == \"mean\"\n    else\n      true,\n  )\n  |> map(fn: (r) => ({ _value:r._value, _time:r._time, _field: r._field}))",
      "refId": "C"
    },
    {
      "datasource": {
        "type": "influxdb",
        "uid": "xxx"
      },
      "hide": false,
      "query": "import \"types\"\nimport \"experimental\"\n// Declaration of buckets and retention periods\nbucket0=\"icinga2\"\nbucket1=\"icinga2_5m_samples\"\nbucket2=\"icinga2_30min_samples\"\nretention0=7d\nretention1=90d\n// handling of diffrent timepicker modes e.g. \"-3d\" vs \"From 03.07.1980 17:00:00 To 07.09.1980 19:35:00\"\nisduration = if types.isType(v: v.timeRangeStart, type: \"duration\") then\ntrue else false\nret0=if isduration then uint(v: -retention0) else uint(v:\nexperimental.subDuration(d: retention0, from: now()))\nret1=if isduration then uint(v: -retention1) else uint(v:\nexperimental.subDuration(d: retention1, from: now()))\n// if start date is before retention0 then bucket1, if start date is before retention1 then bucket2\nbuckett=if uint(v: v.timeRangeStart) > ret0 then\n bucket0\nelse if uint(v: v.timeRangeStart) > ret1 then\n bucket1\nelse\n bucket2\n// the actual query with host/service filter\nfrom(bucket: buckett)\n  |> range(start: v.timeRangeStart, stop:v.timeRangeStop)\n  |> filter(fn: (r) =>\n    r._measurement == \"disk\" and\n    r.hostname == \"${hostname}\" and\n    r.metric == \"${disk}\" and\n    r._field == \"max\"\n  )\n  |> filter(\n    fn: (r) => if buckett != \"icinga2\" then \n        r.aggregate == \"mean\"\n    else\n      true,\n  )\n  |> map(fn: (r) => ({ _value:r._value, _time:r._time, _field: r._field}))",
      "refId": "D"
    }
  ],
  "title": "Disk $disk",
  "type": "timeseries"
},
{
  "datasource": {
    "type": "influxdb",
    "uid": "xxx"
  },
  "fieldConfig": {
    "defaults": {
      "color": {
        "mode": "palette-classic"
      },
      "custom": {
        "axisBorderShow": false,
        "axisCenteredZero": false,
        "axisColorMode": "text",
        "axisLabel": "",
        "axisPlacement": "auto",
        "barAlignment": 0,
        "barWidthFactor": 0.6,
        "drawStyle": "line",
        "fillOpacity": 0,
        "gradientMode": "none",
        "hideFrom": {
          "legend": false,
          "tooltip": false,
          "viz": false
        },
        "insertNulls": false,
        "lineInterpolation": "linear",
        "lineWidth": 1,
        "pointSize": 5,
        "scaleDistribution": {
          "type": "linear"
        },
        "showPoints": "auto",
        "spanNulls": false,
        "stacking": {
          "group": "A",
          "mode": "none"
        },
        "thresholdsStyle": {
          "mode": "off"
        }
      },
      "mappings": [],
      "thresholds": {
        "mode": "absolute",
        "steps": [
          {
            "color": "green"
          },
          {
            "color": "red",
            "value": 80
          }
        ]
      },
      "unit": "binBps"
    },
    "overrides": []
  },
  "gridPos": {
    "h": 8,
    "w": 12,
    "x": 0,
    "y": 21
  },

Variable for the graph.

  {
    "allowCustomValue": false,
    "current": {
      "text": "All",
      "value": "$__all"
    },
    "definition": "import \"influxdata/influxdb/schema\"\r\nschema.tagValues(\r\n bucket: v.bucket,\r\n tag: \"metric\",\r\n predicate: (r) => r.hostname == \"${hostname}\" and r._measurement == \"disk\",\r\n start: -1d\r\n)",
    "hide": 2,
    "includeAll": true,
    "name": "disk",
    "options": [],
    "query": {
      "query": "import \"influxdata/influxdb/schema\"\r\nschema.tagValues(\r\n bucket: v.bucket,\r\n tag: \"metric\",\r\n predicate: (r) => r.hostname == \"${hostname}\" and r._measurement == \"disk\",\r\n start: -1d\r\n)"
    },
    "refresh": 1,
    "regex": "",
    "type": "query"
  }

Module config:

[disk]
dashboard = "Disk"
panelId = "16"
orgId = "1"
repeatable = "yes"
dashboarduid = "xxx"
nmetrics = "1"

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the module configuration shown in the report, especially panelId=16 and repeatable=yes, then trace how the Grafana dashboard's repeated panels are located and mapped. Reproduce with Grafana 11.6.0 and the supplied dashboard, and confirm that cloned IDs such as 16-clone-0 through 16-clone-n display the intended panels rather than panels selected by incrementing numeric IDs.

Written by the indexing model from the issue text.

Assessment

Tech stack
grafana, php
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.