How to Bulk update Synthesis ICMP monitor frequency?

Our ELK is 8.19 We are using Synthetics monitoring. We have about 5000 ICMP monitors.

The current ICMP Ping frequency is currently 3 minutes.

Our customer have a request to update all to 1 minute.

What’s our best option to do it? If via API can only share an example of the script.

How can I run a query or report to check which monitor is not updated to 1 minute

Also in terms of load. How can we monitor that this is not having an impact?

KIndly advice

Hi @Whoami1980,

For 5000 monitors I would recommend scripting the updates via the below APIs:

  1. You can get a hold of all ICMP monitors using the Get monitors API filtering using the monitorType attribute to filter for icmp monitors.
  2. Then you can loop through each one, using the id in a subsequent call to the Update monitors API, specifying the schedule value as 1.
  3. You should be able to track the HTTP response calls for failure. Alternatively the Get monitors API can be invoked again using the monitorType and schedules filters.

I'm not sure of the load impact of running for 5000 monitors on your cluster. I would recommend you consider batching the update requests. You can also leverage AutoOps and Stack Monitoring to track the load.

Hope that helps!

1 Like

@carly.richmond

Can I clarify if this is what you want me to do?

Kibana REST APIs
GET kbn:/api/synthetics/monitors?filter=synthetics-monitor.attributes.type:icmp

Is it better or easier for me to do this instead?

Query DSL

### GET QUERY ###


GET synthetics-*/_search
{
  "_source": ["monitor.name", "config_id", "schedule", "monitor.type"],
  "track_total_hits": true,
  "size": 50,
  "query": {
    "bool": {
      "must": [
        { "term": { "monitor.type": "icmp" } },
        { "term": { "schedule.number": 3 } },
        { "term": { "schedule.unit": "m" } }
      ]
    }
  },
  "collapse": {
    "field": "monitor.name.keyword",
    "inner_hits": {
      "name": "latest_check",
      "size": 1,
      "sort": [{ "@timestamp": "desc" }]
    }
  },
  "sort": [
    { "@timestamp": "desc" }
  ]
}



### UPDATE QUERY ###


POST synthetics-*/_update_by_query
{
  "script": {
    "source": """
      if (ctx._source.monitor.type == 'icmp' &&
          ctx._source.schedule.number == 3 &&
          ctx._source.schedule.unit == 'm') {
        ctx._source.schedule.number = 1;
      }
    """,
    "lang": "painless"
  },
  "query": {
    "bool": {
      "must": [
        { "term": { "monitor.type": "icmp" } },
        { "term": { "schedule.number": 3 } },
        { "term": { "schedule.unit": "m" } }
      ]
    }
  }
}

Hello @Whoami1980

I tried above queries but it did not work via Dev Tools..Used below 2 shell scripts to update the records & it worked :

fetch-synthetics-icmp.sh

#!/bin/bash

KIBANA_URL="Kibana_URL"
API_KEY="API_Key"
PER_PAGE=1000
PAGE=1

while : ; do
  RESPONSE=$(curl -s -X GET \
    "$KIBANA_URL/api/synthetics/monitors?monitorTypes=icmp&page=$PAGE&perPage=$PER_PAGE" \
    -H "kbn-xsrf: true" \
    -H "Authorization: ApiKey $API_KEY")

  COUNT=$(echo "$RESPONSE" | jq '.monitors | length')

  if [ "$COUNT" -eq 0 ]; then
    break
  fi

  echo "$RESPONSE" | jq -r '.monitors[]
  | select(.schedule.number=="3" and .schedule.unit=="m")
  | "\(.id) | \(.name) | \(.schedule.number)\(.schedule.unit) | space=\(.spaceId)"'

  PAGE=$((PAGE + 1))
done

update-synthetics-icmp.sh

#!/bin/bash

KIBANA_URL="Kibana_URL"
API_KEY="API_Key"

SPACE="default"   # change if using another space
PER_PAGE=1000
PAGE=1

echo "Updating ICMP monitors from 3m to 1m..."
echo "-----------------------------------------"

while true; do

  RESPONSE=$(curl -s -X GET \
    "$KIBANA_URL/s/$SPACE/api/synthetics/monitors?monitorTypes=icmp&page=$PAGE&perPage=$PER_PAGE" \
    -H "kbn-xsrf: true" \
    -H "Authorization: ApiKey $API_KEY")

  COUNT=$(echo "$RESPONSE" | jq '.monitors | length')

  if [ "$COUNT" -eq 0 ] || [ "$COUNT" = "null" ]; then
    break
  fi

  for ROW in $(echo "$RESPONSE" | jq -r '.monitors[] | @base64'); do

    _jq() {
      echo "$ROW" | base64 --decode | jq -r "$1"
    }

    NUMBER=$(_jq '.schedule.number')
    UNIT=$(_jq '.schedule.unit')

    if [[ "$NUMBER" == "3" && "$UNIT" == "m" ]]; then

      ID=$(_jq '.id')
      NAME=$(_jq '.name')

      echo "Updating $NAME ($ID) → 1m"

      UPDATED_BODY=$(echo "$ROW" | base64 --decode | jq '
      {
        type,
        name,
        enabled,
        schedule: {
          number: "1",
          unit: "m"
        },
        locations,
        timeout,
        max_attempts,
        wait,
        mode,
        ipv4,
        ipv6,
        host,
        retest_on_failure
      }')

      RESPONSE_UPDATE=$(curl -s -w "\n%{http_code}" -X PUT \
        "$KIBANA_URL/s/$SPACE/api/synthetics/monitors/$ID" \
        -H "kbn-xsrf: true" \
        -H "Authorization: ApiKey $API_KEY" \
        -H "Content-Type: application/json" \
        -d "$UPDATED_BODY")

      HTTP_BODY=$(echo "$RESPONSE_UPDATE" | head -n -1)
      HTTP_CODE=$(echo "$RESPONSE_UPDATE" | tail -n 1)

      if [ "$HTTP_CODE" -ne 200 ]; then
        echo "❌ Failed to update $NAME ($ID)"
        echo "$HTTP_BODY"
      else
        echo "✅ Updated $NAME ($ID)"
      fi

      sleep 0.2
    fi

  done

  PAGE=$((PAGE + 1))

done

echo "Update complete."

Script Execution :

./fetch-synthetics-icmp.sh
e79d4471-6c87-4f87-9724-f7affe843250 | Non-Host-ICMP | 3m | space=default
64ddc109-1309-464d-b749-75176edd6723 | Google-ICMP | 3m | space=default
590c738d-364b-415c-ac68-bf440c42d0ae | Cloudfare-ICMP | 3m | space=default

./update-synthetics-icmp.sh
Updating ICMP monitors from 3m to 1m...
-----------------------------------------
Updating Cloudfare-ICMP (590c738d-364b-415c-ac68-bf440c42d0ae) → 1m
✅ Updated Cloudfare-ICMP (590c738d-364b-415c-ac68-bf440c42d0ae)
Updating Google-ICMP (64ddc109-1309-464d-b749-75176edd6723) → 1m
✅ Updated Google-ICMP (64ddc109-1309-464d-b749-75176edd6723)
Updating Non-Host-ICMP (e79d4471-6c87-4f87-9724-f7affe843250) → 1m
✅ Updated Non-Host-ICMP (e79d4471-6c87-4f87-9724-f7affe843250)
Update complete.


./fetch-synthetics-icmp.sh
#

Need to update the script to take filter as 1 instead of 3 : 

./fetch-synthetics-icmp.sh
e79d4471-6c87-4f87-9724-f7affe843250 | Non-Host-ICMP | 1m | space=default
64ddc109-1309-464d-b749-75176edd6723 | Google-ICMP | 1m | space=default
590c738d-364b-415c-ac68-bf440c42d0ae | Cloudfare-ICMP | 1m | space=default

This was tested in v9.3.1

Thanks!!

1 Like

I would recommend using the specific synthetics API above rather than manipulating the indices itself. I'm not 100% sure that there are other operations taking place apart from updating the indices, but looking at the edit handler you would bypass some additional logic such as validation.

In terms of the get request to get all ICMP monitors, the HTTP request would be something like the below:

GET /api/synthetics/monitors?monitorTypes=icmp

Hope that helps!

@carly.richmond Thanks for the assistance.

Whats the difference between id and config_id?

Can we run bash shell script in the dev tools? I dont think so. correct me if I am wrong.

Do u have an example of using the loop from get to update the values in devtools?

"Then you can loop through each one, using the id in a subsequent call to the Update monitors API, specifying the schedule value as 1."

Thanks

@Whoami1980 you can't run bash scripts in DevTools. But you should be able to run the script logic provided above by @Tortoise in a Linux-based environment just like normal scripts. DevTools is intended for adhoc running of commands and not full scripting.

My guess is that id refers to the unique ID of a single monitor, meanwhile config_id will be the unique reference for the configuration. For example you may have a Playwright-based configuration used in several monitors.

Hope that helps!