.. include:: ../../global.rst ############### ELK Interaction ############### We're System Administrators and we want to interrogate our local :strike:`ELK` :strike:`ElasticSearch` ElasticStack instance. :lname:`Idio` doesn't have any immediate HTTP capabilities so we'll use `curl `_. This example will use non-TLS connections. We're going to use using the JSON output so remember to put ``import json5`` at the top of the script (or type it in at the console). Elastic Basic Security ====================== A little digression. Later releases of v7 have encouraged even the free tier to use authentication to connect. That's good but we don't want to use a :samp:`http://{user}:{pass}@{host}:9200/{path}` format because we can't guarantee that :program:`curl` can successfully prevent other users from seeing :samp:`{user}` and :samp:`{pass}`. :program:`curl` does support the use of both ``--netrc`` and, more usefully, ``--netrc-file`` for which we can make use of *Process Substitution*. Our command line will therefore include: .. code-block:: idio curl --netrc --netrc-file (named-pipe-from print-netrc) ... where the function ``print-netrc`` can be set up along the lines of: .. code-block:: idio ELK-HOST := "elk1.example.com" ELK-USER := "elk-username" ELK-PASS := "elk-password" define* (print-netrc (:host host ELK-HOST) (:user user ELK-USER) (:pass pass ELK-PASS)) { printf #S{ machine ${host} login ${user} password ${pass} } } which gives us a bit of wiggle-room to alter the ``host``, ``user`` and ``pass`` by passing optional parameters (see :ref:`define* `). Calling curl ============ We can create a similar function for parameterising the call the curl: .. code-block:: idio define* (CURL (res "") (:method method "GET") (:host host ELK-HOST) (:user user ELK-USER) (:pass pass ELK-PASS)) { (collect-output curl -sX method --netrc --netrc-file (named-pipe-from print-netrc :host host :user user :pass pass) #S{http://${ELK-HOST}:9200/${res}}) } ELK APIs ======== Looking at some simple APIs, we can check we successfully talk to ELK at all by invoking ``CURL`` with no :var:`res` option: .. code-block:: idio printf "%s\n" (CURL) to get something like: .. code-block:: text { "name" : "elk2.example.com", ... "version" : { "number" : "7.15.1", ... }, "tagline" : "You Know, for Search" } _cat/nodes ---------- .. aside:: The "cat nodes" API is "compact and aligned text", deliberately designed for humans. We should be using the `nodes API `_ but that gives us thousands of lines of JSON which distracts from the idea of handling data interchange. The `cat nodes API `_ can give us some JSON output: .. code-block:: idio ;; nodes is an array nodes := parse-string (CURL "_cat/nodes?format=json") ``parse-string``, here, is ``json5/parse-string`` from the ``import json5`` line you added. :var:`nodes` is an array of as many objects as you have ElasticSearch nodes in your cluster. For interest, we can get the member names of the first object: .. code-block:: idio hash-keys (array-ref nodes 0) which will result in a list, something like: .. code-block:: text ("ip" "master" "load_15m" "load_5m" "heap.percent" "cpu" "node.role" "name" "load_1m" "ram.percent") based on which, we should be able to iterate over the array printing out the name, IP address and cpu usage: .. code-block:: idio for-each (function (n) { printf "%-30s %15s %s\n" n."name" n."ip" n."cpu" }) nodes to get: .. code-block:: text elk1.example.com 192.0.2.101 8 elk2.example.com 192.0.2.102 17 .. include:: ../../commit.rst