- Using control socket driven by an external system
- Using Lua program embeded in Resolver's configuration file
-Both ways can also be combined: For example the configuration file can contain a little Lua function which gathers statistics and returns them in JSON string. This can be used by an external system which uses control socket to call this user-defined function and to retrieve its results.
+Both ways can also be combined: For example the configuration file can contain
+a little Lua function which gathers statistics and returns them in JSON string.
+This can be used by an external system which uses control socket to call this
+user-defined function and to retrieve its results.
Control sockets
---------------
-Control socket acts like "an interactive configuration file" so all actions available in configuration file can be executed interactively using the control socket. One possible use-case is reconfiguring Resolver instances from another program, e.g. a maintenance script.
+Control socket acts like "an interactive configuration file" so all actions
+available in configuration file can be executed interactively using the control
+socket. One possible use-case is reconfiguring Resolver instances from another
+program, e.g. a maintenance script.
.. note:: Each instance of Knot Resolver exposes its own control socket. Take
that into account when scripting deployments with
:ref:`systemd-multiple-instances`.
-When Knot Resolver is started using Systemd (see section :ref:`quickstart-startup`) it creates a control socket in path ``/run/knot-resolver/control@$INSTANCENAME``. Connection to the socket can be made from command line using e.g. ``netcat`` or ``socat``:
+When Knot Resolver is started using Systemd (see section
+:ref:`quickstart-startup`) it creates a control socket in path
+``/run/knot-resolver/control/$SYSTEMD_INSTANCE``. Connection to the socket can
+be made from command line using e.g. ``netcat`` or ``socat``:
.. code-block:: bash
- $ nc -U /run/knot-resolver/control@1
+ $ nc -U /run/knot-resolver/control/1
or
- $ socat - UNIX-CONNECT:/run/knot-resolver/control@1
+ $ socat - UNIX-CONNECT:/run/knot-resolver/control/1
-When successfully connected to a socket, the command line should change to something like ``>``.
-Then you can interact with kresd to see configuration or set a new one.
-There are some basic commands to start with.
+When successfully connected to a socket, the command line should change to
+something like ``>``. Then you can interact with kresd to see configuration or
+set a new one. There are some basic commands to start with.
.. code-block:: lua
> net.list() -- lists running network services
-The *direct output* of commands sent over socket is captured and sent back, while also printed to the daemon standard outputs (in :func:`verbose` mode). This gives you an immediate response on the outcome of your command.
-Error or debug logs aren't captured, but you can find them in the daemon standard outputs.
+The *direct output* of commands sent over socket is captured and sent back,
+while also printed to the daemon standard outputs (in :func:`verbose` mode).
+This gives you an immediate response on the outcome of your command. Error or
+debug logs aren't captured, but you can find them in the daemon standard
+outputs.
-Control sockets are also a way to enumerate and test running instances, the list of sockets corresponds to the list
-of processes, and you can test the process for liveliness by connecting to the UNIX socket.
+Control sockets are also a way to enumerate and test running instances, the
+list of sockets corresponds to the list of processes, and you can test the
+process for liveliness by connecting to the UNIX socket.
Lua scripts
-----------
-As it was mentioned in section :ref:`config-syntax`, Resolver's configuration file contains program in Lua programming language. This allows you to write dynamic rules and helps you to avoid repetitive templating that is unavoidable with static configuration. For example parts of configuration can depend on :func:`hostname` of the machine:
+As it was mentioned in section :ref:`config-syntax`, Resolver's configuration
+file contains program in Lua programming language. This allows you to write
+dynamic rules and helps you to avoid repetitive templating that is unavoidable
+with static configuration. For example parts of configuration can depend on
+:func:`hostname` of the machine:
.. code-block:: lua
net.listen(net.eth1.addr[1])
end
-Another example would show how it is possible to bind to all interfaces, using iteration.
+Another example would show how it is possible to bind to all interfaces, using
+iteration.
.. code-block:: lua
net.listen(addr_list)
end
-.. tip:: Some users observed a considerable, close to 100%, performance gain in Docker containers when they bound the daemon to a single interface:ip address pair. One may expand the aforementioned example with browsing available addresses as:
+.. tip:: Some users observed a considerable, close to 100%, performance gain in
+ Docker containers when they bound the daemon to a single interface:ip
+ address pair. One may expand the aforementioned example with browsing
+ available addresses as:
.. code-block:: lua
:param function init: Callback to be executed with the :c:type:`kr_request` before resolution starts.
:return: boolean, ``true`` if resolution was started
- The function can also be executed with a table of arguments instead. This is useful if you'd like to skip some arguments, for example:
+ The function can also be executed with a table of arguments instead. This is
+ useful if you'd like to skip some arguments, for example:
.. code-block:: lua
-------------------
Lua language used in configuration file allows you to script actions upon
-various events, for example publish statistics each minute. Following example uses built-in function :func:`event.recurrent()` which calls user-supplied anonymous function:
+various events, for example publish statistics each minute. Following example
+uses built-in function :func:`event.recurrent()` which calls user-supplied
+anonymous function:
.. code-block:: lua
- modules.load('stats')
+ modules.load('stats')
- -- log statistics every second
- local stat_id = event.recurrent(1 * second, function(evid)
- log(table_print(stats.list()))
- end)
+ -- log statistics every second
+ local stat_id = event.recurrent(1 * second, function(evid)
+ log(table_print(stats.list()))
+ end)
- -- stop printing statistics after first minute
- event.after(1 * minute, function(evid)
- event.cancel(stat_id)
- end)
+ -- stop printing statistics after first minute
+ event.after(1 * minute, function(evid)
+ event.cancel(stat_id)
+ end)
-Note that each scheduled event is identified by a number valid for the duration of the event, you may use it to cancel the event at any time.
+Note that each scheduled event is identified by a number valid for the duration
+of the event, you may use it to cancel the event at any time.
-To persist state between two invocations of a fuction Lua uses concept called closures_. In the following example function ``speed_monitor()`` is a closure function, which provides persistent variable called ``previous``.
+To persist state between two invocations of a fuction Lua uses concept called
+closures_. In the following example function ``speed_monitor()`` is a closure
+function, which provides persistent variable called ``previous``.
.. code-block:: lua
- modules.load('stats')
-
- -- make a closure, encapsulating counter
- function speed_monitor()
- local previous = stats.list()
- -- monitoring function
- return function(evid)
- local now = stats.list()
- local total_increment = now['answer.total'] - previous['answer.total']
- local slow_increment = now['answer.slow'] - previous['answer.slow']
- if slow_increment / total_increment > 0.05 then
- log('WARNING! More than 5 %% of queries was slow!')
- end
- previous = now -- store current value in closure
- end
+ modules.load('stats')
+
+ -- make a closure, encapsulating counter
+ function speed_monitor()
+ local previous = stats.list()
+ -- monitoring function
+ return function(evid)
+ local now = stats.list()
+ local total_increment = now['answer.total'] - previous['answer.total']
+ local slow_increment = now['answer.slow'] - previous['answer.slow']
+ if slow_increment / total_increment > 0.05 then
+ log('WARNING! More than 5 %% of queries was slow!')
+ end
+ previous = now -- store current value in closure
end
+ end
- -- monitor every minute
- local monitor_id = event.recurrent(1 * minute, speed_monitor())
-
-Another type of actionable event is activity on a file descriptor. This allows you to embed other event loops or monitor open files and then fire a callback when an activity is detected.
-This allows you to build persistent services like monitoring probes that cooperate well with the daemon internal operations. See :func:`event.socket()`.
+ -- monitor every minute
+ local monitor_id = event.recurrent(1 * minute, speed_monitor())
+Another type of actionable event is activity on a file descriptor. This allows
+you to embed other event loops or monitor open files and then fire a callback
+when an activity is detected. This allows you to build persistent services
+like monitoring probes that cooperate well with the daemon internal operations.
+See :func:`event.socket()`.
-Filesystem watchers are possible with :func:`worker.coroutine()` and cqueues_, see the cqueues documentation for more information. Here is an simple example:
+Filesystem watchers are possible with :func:`worker.coroutine()` and cqueues_,
+see the cqueues documentation for more information. Here is an simple example:
.. code-block:: lua