Dear team,
we have used a script from the els repository to set up a watcher for free disc space ratio, unfortunately script execution ends with errors but watcher interface show all is ok, we got an NPE:
"script_stack": [
"return ctx.payload.aggregations.nodes.buckets.stream().anyMatch(",
" ^---- HERE"
],
"script": "return ctx.payload.aggregations.nodes.buckets.stream().anyMatch(it -> it.free_ratio.value < ctx.metadata.lower_bound);",
"lang": "painless",
"position": {
"offset": 31,
"start": 0,
"end": 64
},
"caused_by": {
"type": "null_pointer_exception",
"reason": null,
"stack_trace": "java.lang.NullPointerException\n\tat org.elasticsearch.painless.DefBootstrap$PIC.fallback(DefBootstrap.java:206)\n\tat org.elasticsearch.painless.PainlessScript$Script.execute(return ctx.payload.aggregations.nodes.buckets.stream().anyMatch(it -> it.free_ratio.value < ctx.metadata.lower_bound);:32)\n\tat org.elasticsearch.xpack.watcher.condition.ScriptCondition.doExecute(ScriptCondition.java:60)\n\tat org.elasticsearch.xpack.watcher.condition.ScriptCondition.execute(ScriptCondition.java:55)\n\tat org.elasticsearch.xpack.watcher.execution.ExecutionService.executeInner(ExecutionService.java:512)\n\tat org.elasticsearch.xpack.watcher.execution.ExecutionService.execute(ExecutionService.java:319)\n\tat org.elasticsearch.xpack.watcher.execution.ExecutionService.lambda$executeAsync$5(ExecutionService.java:420)\n\tat org.elasticsearch.xpack.watcher.execution.ExecutionService$WatchExecutionTask.run(ExecutionService.java:626)\n\tat org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingRunnable.run(ThreadContext.java:678)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)\n\tat java.base/java.lang.Thread.run(Thread.java:834)\n"
},
"stack_trace": "ScriptException[runtime error]; nested: NullPointerException;\n\tat org.elasticsearch.painless.PainlessScript.convertToScriptException(PainlessScript.java:96)\n\tat org.elasticsearch.painless.PainlessScript$Script.execute(return ctx.payload.aggregations.nodes.buckets.stream().anyMatch(it -> it.free_ratio.value < ctx.metadata.lower_bound);:65)\n\tat org.elasticsearch.xpack.watcher.condition.ScriptCondition.doExecute(ScriptCondition.java:60)\n\tat org.elasticsearch.xpack.watcher.condition.ScriptCondition.execute(ScriptCondition.java:55)\n\tat org.elasticsearch.xpack.watcher.execution.ExecutionService.executeInner(ExecutionService.java:512)\n\tat org.elasticsearch.xpack.watcher.execution.ExecutionService.execute(ExecutionService.java:319)\n\tat org.elasticsearch.xpack.watcher.execution.ExecutionService.lambda$executeAsync$5(ExecutionService.java:420)\n\tat org.elasticsearch.xpack.watcher.execution.ExecutionService$WatchExecutionTask.run(ExecutionService.java:626)\n\tat org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingRunnable.run(ThreadContext.java:678)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)\n\tat java.base/java.lang.Thread.run(Thread.java:834)\nCaused by: java.lang.NullPointerException\n\tat org.elasticsearch.painless.DefBootstrap$PIC.fallback(DefBootstrap.java:206)\n\tat org.elasticsearch.painless.PainlessScript$Script.execute(return ctx.payload.aggregations.nodes.buckets.stream().anyMatch(it -> it.free_ratio.value < ctx.metadata.lower_bound);:32)\n\t... 10 more\n"
}
}
Used script:
{
"trigger": {
"schedule": {
"interval": "60m"
}
},
"input": {
"search": {
"request": {
"search_type": "query_then_fetch",
"indices": [
"<.monitoring-es-7-{now/M{YYYY.MM.dd}}>"
],
"rest_total_hits_as_int": true,
"body": {
"query": {
"bool": {
"filter": [
{
"range": {
"timestamp": {
"gte": "{{ctx.trigger.scheduled_time}}||-60m"
}
}
},
{
"term": {
"type": "node_stats"
}
}
]
}
},
"aggs": {
"nodes": {
"terms": {
"field": "source_node.name",
"size": 100
},
"aggs": {
"total_in_bytes": {
"max": {
"field": "node_stats.fs.total.total_in_bytes"
}
},
"available_in_bytes": {
"max": {
"field": "node_stats.fs.total.available_in_bytes"
}
},
"free_ratio": {
"bucket_script": {
"buckets_path": {
"available_in_bytes": "available_in_bytes",
"total_in_bytes": "total_in_bytes"
},
"script": "params.available_in_bytes / params.total_in_bytes"
}
}
}
}
},
"size": 0
}
}
}
},
"condition": {
"script": {
"source": "return ctx.payload.aggregations.nodes.buckets.stream().anyMatch(it -> it.free_ratio.value < ctx.metadata.lower_bound);",
"lang": "painless"
}
},
"actions": {
"email_support": {
"email": {
"profile": "standard",
"to": [
"vaclav.schmuttermeier@erstegroup.com"
],
"subject": "Space is getting full!",
"body": {
"text": "Available space on Filesystem is below recommended ratio of {{ctx.metadata.lower_bound}} for following nodes: {{#ctx.payload._value}}For node {{node_name}}: {{available_in_gb}}gb of {{total_in_gb}}gb is available.{{/ctx.payload._value}} Action: We have to gather some space by deleting old indices, advice with your colleagues!"
}
}
}
},
"metadata": {
"lower_bound": 0.2
},
"transform": {
"script": {
"source": "ctx.payload.aggregations.nodes.buckets.stream().filter(it -> it.free_ratio.value < ctx.metadata.lower_bound).map(it -> ['node_name':it.key,'available_in_gb':Math.round((it.available_in_bytes.value/1073741824) * 100)/100,'total_in_gb':Math.round((it.total_in_bytes.value/1073741824)* 100)/100]).collect(Collectors.toList());",
"lang": "painless"
}
},
"throttle_period_in_millis": 1800000
}