elasticsearchkibanaelastic-stackotrselasticsearch-watcher

How to build a watcher in Elasticsearch for generating OTRS ticket?


I want to configure a elasticsearch webhook watcher , which will look for the keyword "error" in my indices and genarate an OTRS ticket, if found.

Right now I have following configuration :

{
  "trigger": {
    "schedule": {"interval": "1m"}
  },
  "input": {
    "search": {
      "request": {
        "body": {
          "size": 0,
          "query": {"match_all": "Error"}
        },
        "indices": ["*"]
      }
    }
  },
  "condition": {
    "compare": {
      "ctx.payload.hits.total": {
        "gte": 1
      }
    }
  },
  "actions" : {
  "create_otrs" : {
    "transform": {
      "script": """{"Ticket":{"Queue":"EngineeringTeam","Priority":"P3","CustomerUser":"root@localhost","Title":"RESTCreateTest","State":"new","Type":"Incident"},"Article":{"ContentType":"text/plain;charset=utf8","Subject":"RestCreateTest","Body":"Thisisonlyatest"}}"""
    },
    "webhook" : {
      "method" : "POST",
      "host" : "http://myotrs.com/otrs/nph-genericinterface.pl/Webservice/GenericTicketConnectorREST/Ticket?UserLogin=<user>&Password=<pass>",
      "port": 9200,
      "body": "{{#toJson}}ctx.payload{{/toJson}}",
      "auth" : {
        "basic" : {
          "username" : "elastic", 
          "password" : "<elasticsearch pass>"
        }
      }
    }
  }
}
}

This gives me Error saving watch : compile error and watcher will not simulate. There is no syntax error in the json by the way. What is wrong in the configuration? A curl operation successfully generates the OTRS ticket but I am getting a hard time configuring it with elasticsearch.


Solution

  • Tldr;

    Your transform script is wrong. As per the documentation:

    The executed script may either return a valid model that is the equivalent of a Java™ Map or a JSON object (you will need to consult the documentation of the specific scripting language to find out what this construct is).

    Solution

    You can do something as simple as, converting your json into a string

    {
      "Ticket": {
        "Queue": "EngineeringTeam",
        "Priority": "P3",
        "CustomerUser": "root@localhost",
        "Title": "RESTCreateTest",
        "State": "new",
        "Type": "Incident"
      },
      "Article": {
        "ContentType": "text/plain;charset=utf8",
        "Subject": "RestCreateTest",
        "Body": "Thisisonlyatest"
      }
    }
    

    Becomes:

    "{\"Ticket\":{\"Queue\":\"EngineeringTeam\",\"Priority\":\"P3\",\"CustomerUser\":\"root@localhost\",\"Title\":\"RESTCreateTest\",\"State\":\"new\",\"Type\":\"Incident\"},\"Article\":{\"ContentType\":\"text/plain;charset=utf8\",\"Subject\":\"RestCreateTest\",\"Body\":\"Thisisonlyatest\"}}"
    

    And use the Json.load function to convert the string into a proper object.

    Your watch will look like:

    {
      "watch" : {
        "trigger": {
          "schedule": {"interval": "1m"}
        },
        "input": {
          "search": {
            "request": {
              "body": {
                "size": 0,
                "query": {"match_all": "Error"}
              },
              "indices": ["*"]
            }
          }
        },
        "condition": {
          "compare": {
            "ctx.payload.hits.total": {
              "gte": 1
            }
          }
        },
        "actions" : {
          "create_otrs" : {
            "transform": {
              "script": """return Json.load("{\"Ticket\":{\"Queue\":\"EngineeringTeam\",\"Priority\":\"P3\",\"CustomerUser\":\"root@localhost\",\"Title\":\"RESTCreateTest\",\"State\":\"new\",\"Type\":\"Incident\"},\"Article\":{\"ContentType\":\"text/plain;charset=utf8\",\"Subject\":\"RestCreateTest\",\"Body\":\"Thisisonlyatest\"}}");"""
            },
            "webhook" : {
              "method" : "POST",
              "host" : "http://myotrs.com/otrs/nph-genericinterface.pl/Webservice/GenericTicketConnectorREST/Ticket?UserLogin=<user>&Password=<pass>",
              "port": 9200,
              "body": "{{#toJson}}ctx.payload{{/toJson}}",
              "auth" : {
                "basic" : {
                  "username" : "elastic", 
                  "password" : "<elasticsearch pass>"
                }
              }
            }
          }
        }
      }
    }
    

    Then another error you have in your watch is the query

    {
      "search": {
        "request": {
          "body": {
            "size": 0,
            "query": {"match_all": "Error"}
          },
          "indices": ["*"]
        }
      }
    }
    

    match_all should take an object such as {} so "Error" is not going to work.

    So in the end the watcher looks like:

    {
      "watch" : {
        "trigger": {
          "schedule": {"interval": "1m"}
        },
        "input": {
          "search": {
            "request": {
              "body": {
                "size": 0,
                "query": {"match_all": {}}
              },
              "indices": ["*"]
            }
          }
        },
        "condition": {
          "compare": {
            "ctx.payload.hits.total": {
              "gte": 1
            }
          }
        },
        "actions" : {
          "create_otrs" : {
            "transform": {
              "script": """return Json.load("{\"Ticket\":{\"Queue\":\"EngineeringTeam\",\"Priority\":\"P3\",\"CustomerUser\":\"root@localhost\",\"Title\":\"RESTCreateTest\",\"State\":\"new\",\"Type\":\"Incident\"},\"Article\":{\"ContentType\":\"text/plain;charset=utf8\",\"Subject\":\"RestCreateTest\",\"Body\":\"Thisisonlyatest\"}}");"""
            },
            "webhook" : {
              "method" : "POST",
              "host" : "http://myotrs.com/otrs/nph-genericinterface.pl/Webservice/GenericTicketConnectorREST/Ticket?UserLogin=<user>&Password=<pass>",
              "port": 9200,
              "body": "{{#toJson}}ctx.payload{{/toJson}}",
              "auth" : {
                "basic" : {
                  "username" : "elastic", 
                  "password" : "<elasticsearch pass>"
                }
              }
            }
          }
        }
      }
    }