]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
doc: initial drafts of internal architecture explainers
authorVasek Sraier <git@vakabus.cz>
Mon, 13 Feb 2023 22:04:47 +0000 (23:04 +0100)
committerAleš Mrázek <ales.mrazek@nic.cz>
Mon, 5 Jun 2023 13:34:21 +0000 (15:34 +0200)
doc/architecture-gc.rst [new file with mode: 0644]
doc/architecture-kresd.rst [new file with mode: 0644]
doc/architecture-manager.drawio [new file with mode: 0644]
doc/architecture-manager.rst [new file with mode: 0644]
doc/architecture-manager.svg [new file with mode: 0644]
doc/architecture-schema.drawio [new file with mode: 0644]
doc/architecture-schema.svg [new file with mode: 0644]
doc/architecture.rst
manager/knot_resolver_manager/kresd_controller/interface.py

diff --git a/doc/architecture-gc.rst b/doc/architecture-gc.rst
new file mode 100644 (file)
index 0000000..257a480
--- /dev/null
@@ -0,0 +1,3 @@
+*****************
+``kres-cache-gc``
+*****************
\ No newline at end of file
diff --git a/doc/architecture-kresd.rst b/doc/architecture-kresd.rst
new file mode 100644 (file)
index 0000000..783fbb8
--- /dev/null
@@ -0,0 +1,3 @@
+*********
+``kresd``
+*********
\ No newline at end of file
diff --git a/doc/architecture-manager.drawio b/doc/architecture-manager.drawio
new file mode 100644 (file)
index 0000000..aa8c4e7
--- /dev/null
@@ -0,0 +1 @@
+<mxfile host="Electron" modified="2023-02-13T14:53:19.113Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.8.16 Chrome/106.0.5249.199 Electron/21.4.0 Safari/537.36" etag="AMbarg0B8e5MX17HW2UZ" version="20.8.16" type="device"><diagram name="Page-1" id="veOfMoMBw9sVscwcjaa1">5ZhbU6MwFMc/TR91gADWx17cVUdnnNGZ3fUtQgrRwMEQevHT76GEUqBWdre2dfZFk39Obuf8TkjTI6No/l3SJLwFn4meZfjzHhn3LMs0+w7+y5VFoZxZdiEEkvvaqBLu+RvToqHVjPssrRkqAKF4Uhc9iGPmqZpGpYRZ3WwCoj5rQgPWEu49KtrqD+6rsFD7jlHpl4wHYTmzaeiWiJbGWkhD6sNsTSIXPTKSAKooRfMRE7nzSr8U/b6907pamGSx6tLh+eHx4bb/OibXl9cW4dGgf+Wf6FGmVGR6wxGNcU9Sr1ktSkdIyGKf5WMZPTKchVyx+4R6eesMQ49aqCKBNROLEy7ECARIrMcQo9EwRWMeBw+Q6CEEfWLiDlKuOMSoebgPnJcMp0wqjhG4aRiovOuQCh5sNB/ohidQCqJqRpROLAfreqtozubv+tBcRQaRZhAxJRdoUnY408HUNJtlcGcVG26phWtcWCUWVPMYrMauQoYFHbU/ieBZK4SYCxMe5EkR0hjxtlyByxg+YVDdIC9J9pqxVLVizHxkX1dBqhACiKm4qNRhnYLK5gaWcc1j/8yUWuhEppmCOhnoaLn4qfsvK7/yyqlTVsfz9cbxYp2WIfVeguUSGnAVO8mXvz2wuFvIpMe2+NPShwyVAVNb7MhWUE6MU8N1dWgkE1TxaX1tm0DQw90Bx1VXJjCZpEy1SFnN+vfwWC12WkzgsZXkxSwSA0/BtgRdZV4zJYvMXaMAMiV4zEarQ9vYfGjsIGWtRsaetzOWbEhY97Py9fwrZd0O84p0zCt7czQ759A/BYe08mFwd7XzT+FOqP4Ya3ufWJf3tf1yvUM+7Y58Oofk027xiVtN80vOMTLa/5hRd6+Mki/OqNORUdM6JKROC1Iscp8ubwn559il0fImv/yLSgwyQos3bXF8JJMOJJubrv2fhnK/5eM0S5ic8hSkf4wudO2GC+1Du9C0v/hpYHb9qdI/5Glguv+Lm82DXg3KZe7hKWcHx4HTPA4Ofjdof7VeJEv93vJpsXhOCVjM5NF+pJonrPWJJyxWq4fL4jGiev4lF78B</diagram></mxfile>
\ No newline at end of file
diff --git a/doc/architecture-manager.rst b/doc/architecture-manager.rst
new file mode 100644 (file)
index 0000000..bf663ed
--- /dev/null
@@ -0,0 +1,57 @@
+****************
+``kres-manager``
+****************
+
+.. note::
+    This guide is intended for advanced users and developers. You don't have to know and understand any of this to use Knot Resolver.
+
+The manager is a component written in Python and a bit of C used for native extension modules. The main goal of the manager is to ensure the system is set up according to a given configuration, provide a user-friendly interface. Performance is only secondary to correctness.
+
+The manager is mostly modelled around config processing pipeline:
+
+.. image:: architecture-manager.svg
+    :width: 100%
+    :alt: Diagram showing a configuration change request processing pipeline inside of the manager. The request goes first through an API server, then through parsing, validation and normalization steps, then into an actual system manager, which commands supervisord and other system components such as kresd.
+
+
+API
+===
+
+The API server is implemented using `aiohttp <https://docs.aiohttp.org/en/stable>`_. This framework provides the application skeleton and manages application runtime. The manager is actually a normal web application with the slight difference that we don't save the data in a database but rather modify state of other processes.
+
+Code of the API server is located only in a `single source code file <https://gitlab.nic.cz/knot/knot-resolver/-/blob/manager/manager/knot_resolver_manager/server.py>`_. It also contains description of the manager's startup procedure.
+
+Config processing
+=================
+
+From the web framework, we receive data as simple strings and we need to parse and validate them. Due to packaging issues in distros, we rolled our own solution not disimilar to Python library `Pydantic <https://docs.pydantic.dev/>`_.
+
+Our tool lets us model config schema similarly to how Python's native dataclasses are constructed. As input, it takes Python's dicts taken from PyYAML or JSON parser. The dict is mapped onto predefined Python classes while enforcing typing rules. If desired, the mapping step is performed multiple times onto different classes, which allows us to process intermediary values such as ``auto``.
+
+There are two relevant places in the source code - `our generic modelling tools <https://gitlab.nic.cz/knot/knot-resolver/-/tree/manager/manager/knot_resolver_manager/utils/modeling>`_ and the actual `configuration data model <https://gitlab.nic.cz/knot/knot-resolver/-/tree/manager/manager/knot_resolver_manager/datamodel>`_. Just next to the data model in the ``templates`` directory, there are Jinja2 templates for generating Lua code from the configuration.
+
+
+Actual manager
+==============
+
+The actual core of the whole application is originally named the manager. It keeps a high-level view of the systems state and performs all necessary operations to change the state to the desired one. In other words, manager is the component handling rolling restarts, config update logic and more.
+
+The code is contained mainly in a `single source code file <https://gitlab.nic.cz/knot/knot-resolver/-/blob/manager/manager/knot_resolver_manager/kres_manager.py>`_.
+
+
+Interactions with supervisord
+=============================
+
+.. note::
+    Let's make a sidestep and let's talk about abstractions. The manager component mentioned above interacts with a general backend (or as we call sometimes call it - a subprocess manager). The idea is that the interactions with the backend are not dependent on the backend's implementation and we can choose which one we want to use. Historically, we had two different backend implementations - systemd and supervisord. However, systemd turned out to be inappropriate, it did not fit our needs, so we removed it. The `abstraction remains <https://gitlab.nic.cz/knot/knot-resolver/-/blob/manager/manager/knot_resolver_manager/kresd_controller/interface.py>`_ though and it should be possible to implement a different subprocess manager if it turns out useful. Please note though, the abstraction might be somewhat leaky in practice as there is only one implementation.
+
+Communication with supervisord happens on pretty much all possible levels. We edit its configuration file, we use its XMLRPC API, we use Unix signals and we even attach to it from within its Python runtime. The interface is honestly a bit messy and we had to use all we could to make it user friendly.
+
+First, we `generate supervisord's configuration file <https://gitlab.nic.cz/knot/knot-resolver/-/blob/manager/manager/knot_resolver_manager/kresd_controller/supervisord/supervisord.conf.j2>`_. The configuration file sets stage for further communication by specifying location of the pidfile and API Unix socket. It prepares configuration for subprocesses and most significantly, it loads our custom extensions.
+
+`The extensions <https://gitlab.nic.cz/knot/knot-resolver/-/tree/manager/manager/knot_resolver_manager/kresd_controller/supervisord/plugin>`_ don't use a lot of code. There are four of them - the simplest one provides a speedier XMLRPC API for starting processes, it removes delays that are not necessary for our usecase. Another one implements systemd's ``sd_notify()`` API for supervisord, so we can track the lifecycle of ``kresd``s more precisely. Another extension changes the way logging works and the last extension monitors the lifecycle of the manager and forwards some signals.
+
+.. note::
+    The extensions mentioned above use monkeypatching to achieve their design goals. We settled for this approach, because supervisord's codebase appears mostly stable. The code we patch has not been changed for years. Other option would be forking supervisord and vendoring it. We decided against that mainly due to packaging complications it would cause with major Linux distributions.
+
+For executing subprocesses, we don't actually change the configuration file, we only use XMLRPC API and tell supervisord to start already configured programs. For one specific call though, we use our extension instead of the build-in method of starting processes as it is significantly faster.
\ No newline at end of file
diff --git a/doc/architecture-manager.svg b/doc/architecture-manager.svg
new file mode 100644 (file)
index 0000000..4408bfb
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="771px" height="201px" viewBox="-0.5 -0.5 771 201"><defs/><g><rect x="150" y="0" width="620" height="200" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 672px; height: 1px; padding-top: 24px; margin-left: 124px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">manager</div></div></div></foreignObject><text x="460" y="24" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">manager</text></switch></g><path d="M 30 100 L 173.63 100" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 178.88 100 L 171.88 103.5 L 173.63 100 L 171.88 96.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 100px; margin-left: 100px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">config change<br />request</div></div></div></foreignObject><text x="100" y="103" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">config change...</text></switch></g><ellipse cx="15" cy="77.5" rx="7.5" ry="7.5" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 15 85 L 15 110 M 15 90 L 0 90 M 15 90 L 30 90 M 15 110 L 0 130 M 15 110 L 30 130" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 220 100 L 253.63 100" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 258.88 100 L 251.88 103.5 L 253.63 100 L 251.88 96.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="180" y="70" width="40" height="60" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 100px; margin-left: 181px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">API</div></div></div></foreignObject><text x="200" y="104" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">API</text></switch></g><path d="M 320 100 L 353.63 100" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 358.88 100 L 351.88 103.5 L 353.63 100 L 351.88 96.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="260" y="70" width="60" height="60" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 100px; margin-left: 261px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">parsing</div></div></div></foreignObject><text x="290" y="104" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">parsing</text></switch></g><path d="M 480 100 L 513.63 100" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 518.88 100 L 511.88 103.5 L 513.63 100 L 511.88 96.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="360" y="70" width="120" height="60" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 100px; margin-left: 361px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">validation &amp; normalization</div></div></div></foreignObject><text x="420" y="104" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">validation &amp; normali...</text></switch></g><rect x="620" y="20" width="120" height="60" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 50px; margin-left: 621px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">supervisord</div></div></div></foreignObject><text x="680" y="54" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">supervisord</text></switch></g><path d="M 580 100 L 600.03 100 L 600.03 50 L 613.63 50" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 618.88 50 L 611.88 53.5 L 613.63 50 L 611.88 46.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 580 100 L 600.03 100 L 600.03 150 L 613.63 150" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 618.88 150 L 611.88 153.5 L 613.63 150 L 611.88 146.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="520" y="70" width="60" height="60" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 100px; margin-left: 521px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">manager</div></div></div></foreignObject><text x="550" y="104" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">manager</text></switch></g><rect x="620" y="120" width="120" height="60" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 150px; margin-left: 621px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">kresd config generation</div></div></div></foreignObject><text x="680" y="154" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">kresd config generat...</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg>
\ No newline at end of file
diff --git a/doc/architecture-schema.drawio b/doc/architecture-schema.drawio
new file mode 100644 (file)
index 0000000..c58a4b9
--- /dev/null
@@ -0,0 +1 @@
+<mxfile host="www.diagrameditor.com" modified="2023-02-13T13:13:34.892Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36" etag="Tj-oP8z-b8JEGXK27IVH" version="12.1.3" type="device" pages="1"><diagram id="fziuQaxv5VFMaYUHGL-k" name="Page-1">7Vlbb5swGP01eezENSGPbZptmlZpUqXu8uaAA14MRsaQsF8/G0zAkNIkLQlaF1WKffwZ2+ccm8/NxFyEu08UxMED8SCeGJq3m5j3E8PQ9emcfwkkLxF7apeAT5Eng2rgEf2BEtQkmiIPJkogIwQzFKugS6IIukzBAKVkq4atCVZHjYEPO8CjC3AX/Y48FpSoY8xq/DNEfsDaCw5BFSxXkgTAI9sGZC4n5oISwspSuFtALMireCn7fXymdT8xCiN2TIdsY66fwiewZpuHmy9LB/7arm4cOTeWVwuGHl+/rBLKAuKTCOBljd5RkkYeFE/VeO13GsZVfEQiEVB3+0pIzHFdxEHGcqkvSBnhUMBCLFu7i5HrS0hKXdizgsoUgPqQ9cSZZZxYXmMASdUnSELIaM4DKMSAoUyVH0gX+fs42fWWUpA3AmKCIpY0nvxNADxAbgjDkm6Q22HW0uykcF4ox69qjYXUUGGDEywxfzeWsEZhCXN6kiX6w4exRHUYvwNP2KPwhOWoIs/7PdEfPpAn9HfjCWMUntA1VWSn3xP94QN5ohwxAziVJCRpDGmGEkK9jl1UM2wDxOBjDArFtjyZPFLlDFIGd726VLtEJaTKy7Z1WmfJw1QLGild1e2QkA06z2DLGMkOclOaFY8UlTXCeEEwocWMzPUaTl2X4wmjZAMbLd5svtLEJDyQBPvu5+9G48jdqI9jN1onndCGdoUT2jzDX4oXhjCb4pbTzTa8v8ZxUWj7S3/ppmD0xg/kMOsfdBg3Fs1/iBl9MOyq/lM+rqjc7+R8y1oua8Nbc5gLS/eK0fae3XoFlhOVvWqTvdrjL6Q0nXldJKex/3v8kh4f5gLWvTK1rtG6Pr+Mx1+6ytm98cN4XGrTyNtDEAEf0o71r5yz6weS9j12kaTd7FA1MaaYiS2JMl70RXFDYeLpVQMfp9F2dUrbqeghTp1LUmodTakxUkrNdvJ1bUrtDqW+e3WWLHNkLOmzZ523JuJQLu3l8jIlOKnaVrQ23t6OzQ4dpjlBTKVTfTXLPID/AYz8iCMup5kfv+adoBe5AN/KhhB5XpFiHNJLVVRM6dDLH4MVxHfA3fhFfHsSrxdab73D5gf+03JAZ2MwnZ2OzjElLkwSkZBQCM8VrJl4SegtBewXqiWvVnzeRsCWfs5g+vFq/QNomc3UPyOby78=</diagram></mxfile>
\ No newline at end of file
diff --git a/doc/architecture-schema.svg b/doc/architecture-schema.svg
new file mode 100644 (file)
index 0000000..e32251b
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="472px" height="172px" viewBox="-0.5 -0.5 472 172"><defs/><g><path d="M 200 40 L 200 50 L 200 93.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 200 98.88 L 196.5 91.88 L 200 93.63 L 203.5 91.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 320 40 L 320 50 L 320 93.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 320 98.88 L 316.5 91.88 L 320 93.63 L 323.5 91.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 440 40 L 440 70 L 440 93.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 440 98.88 L 436.5 91.88 L 440 93.63 L 443.5 91.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 60 40 L 60 60 L 60 93.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 60 98.88 L 56.5 91.88 L 60 93.63 L 63.5 91.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="0" y="0" width="470" height="40" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 468px; height: 1px; padding-top: 20px; margin-left: 1px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">supervisord</div></div></div></foreignObject><text x="235" y="24" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">supervisord</text></switch></g><path d="M 100 100 Q 100 70 130 70 Q 160 70 160 46.37" fill="none" stroke="#d79b00" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 160 41.12 L 163.5 48.12 L 160 46.37 L 156.5 48.12 Z" fill="#d79b00" stroke="#d79b00" stroke-miterlimit="10" pointer-events="all"/><path d="M 100 140 Q 100 150 140 150 Q 180 150 180 146.37" fill="none" stroke="#d79b00" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 180 141.12 L 183.5 148.12 L 180 146.37 L 176.5 148.12 Z" fill="#d79b00" stroke="#d79b00" stroke-miterlimit="10" pointer-events="all"/><path d="M 100 140 Q 100 160 200 160 Q 300 160 300 146.37" fill="none" stroke="#d79b00" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 300 141.12 L 303.5 148.12 L 300 146.37 L 296.5 148.12 Z" fill="#d79b00" stroke="#d79b00" stroke-miterlimit="10" pointer-events="all"/><path d="M 100 140 Q 100 170 255 170 Q 410 170 410 146.37" fill="none" stroke="#d79b00" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 410 141.12 L 413.5 148.12 L 410 146.37 L 406.5 148.12 Z" fill="#d79b00" stroke="#d79b00" stroke-miterlimit="10" pointer-events="all"/><rect x="0" y="100" width="120" height="40" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 120px; margin-left: 1px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">manager</div></div></div></foreignObject><text x="60" y="124" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">manager</text></switch></g><rect x="160" y="100" width="80" height="40" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 120px; margin-left: 161px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div>kresd1</div></div></div></div></foreignObject><text x="200" y="124" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">kresd1</text></switch></g><rect x="280" y="100" width="80" height="40" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 120px; margin-left: 281px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div>kresd2</div></div></div></div></foreignObject><text x="320" y="124" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">kresd2</text></switch></g><rect x="390" y="100" width="80" height="40" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 120px; margin-left: 391px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">gc</div></div></div></foreignObject><text x="430" y="124" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">gc</text></switch></g><rect x="110" y="70" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 80px; margin-left: 111px;"><div data-drawio-colors="color: #d79b00; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(215, 155, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><font>controls<br /></font></div></div></div></foreignObject><text x="130" y="84" fill="#d79b00" font-family="Helvetica" font-size="12px" text-anchor="middle">control...</text></switch></g><rect x="10" y="60" width="40" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 70px; margin-left: 11px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">process tree</div></div></div></foreignObject><text x="30" y="74" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">process...</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg>
\ No newline at end of file
index f07ed57f64047f216de6432441f4060309529b4e..10fadf6216ebe99c55f0230830e22fcb9024f655 100644 (file)
@@ -1,5 +1,48 @@
+*******************
+System architecture
+*******************
 
+As mentioned in the :ref:`getting started section <gettingstarted-intro>`, Knot Resolver is split into several components, namely the manager, ``kresd`` and the garbage collector. In addition to these custom components, we also rely on `supervisord <http://supervisord.org/>`_.
 
-*********************
-Internal architecture
-*********************
\ No newline at end of file
+.. image:: architecture-schema.svg
+    :width: 100%
+    :alt: Diagram showing process tree and contol relationship between Knot Resolver components. Supervisord is a parent to all processes, namely manager, kresd instances and gc. Manager on the other hand controls every other component and what it does.
+
+
+There are two different control structures in place. Semantically, the manager controls every other component in Knot Resolver. It processes configuration and passes it onto every other component. As a user you will always interact with the manager (or kresd). At the same time though, the manager is not the root of the process hierarchy, Supervisord sits at the top of the process tree and runs everything else.
+
+.. note::
+    The rationale for this inverted process hierarchy is mainly stability. Supervisord sits at the top because it is a reliable and stable software we can depend upon. It also does not process user input and its therefore shielded from data processing bugs. This way, any component in Knot Resolver can crash and restart without impacting the rest of the system.
+
+
+Knot Resolver startup
+=====================
+
+The inverted process hierarchy complicates Resolver's launch procedure. You might notice it when reading manager's logs just after start. What happens on cold start is:
+
+1. Manager starts, reads its configuration and generates new supervisord configuration. Then, it starts supervisord by using ``exec``.
+2. Supervisord loads it's configuration, loads our extensions and start a new instance of manager.
+3. Manager starts again, this time as a child of supervisord. As this is desired state, it loads the configuration again and commands supervisord that it should start new instances of ``kresd``.
+
+
+Failure handling
+================
+
+Knot Resolver is designed to handle failures automatically. Anything except for supervisord will automatically restart. If a failure is irrecoverable, all processes will stop and nothing will be left behind in a half-broken state. While a total failure like this should never happen, it is possible and you should not rely on single instance of Knot Resolver for a highly-available system.
+
+.. note::
+    The ability to restart most of the components without downtime means, that Knot Resolver is able to transparently apply updates while running.
+
+
+Individual components
+=====================
+
+You can learn more about architecture of individual Resolver components in the following chapters.
+
+.. toctree::
+    :titlesonly:
+    :maxdepth: 1
+
+    architecture-manager
+    architecture-kresd
+    architecture-gc
\ No newline at end of file
index 081c3221224daae4eaca126aafef65bddd8cad76..cab754ae9485f332e17901770b671c224bc10df6 100644 (file)
@@ -2,6 +2,7 @@ import asyncio
 import itertools
 import logging
 import sys
+from abc import ABC, abstractmethod
 from enum import Enum, auto
 from typing import Dict, Iterable, Optional, Type, TypeVar
 from weakref import WeakValueDictionary
@@ -91,7 +92,7 @@ class KresID:
         return self._id
 
 
-class Subprocess:
+class Subprocess(ABC):
     """
     One SubprocessInstance corresponds to one manager's subprocess
     """
@@ -142,14 +143,17 @@ class Subprocess:
     def __hash__(self) -> int:
         return hash(type(self)) ^ hash(self.type) ^ hash(self.id)
 
+    @abstractmethod
     async def _start(self) -> None:
-        raise NotImplementedError()
+        pass
 
+    @abstractmethod
     async def _stop(self) -> None:
-        raise NotImplementedError()
+        pass
 
+    @abstractmethod
     async def _restart(self) -> None:
-        raise NotImplementedError()
+        pass
 
     @property
     def type(self) -> SubprocessType:
@@ -192,31 +196,32 @@ class SubprocessStatus(Enum):
     UNKNOWN = auto()
 
 
-class SubprocessController:
+class SubprocessController(ABC):
     """
     The common Subprocess Controller interface. This is what KresManager requires and what has to be implemented by all
     controllers.
     """
 
+    @abstractmethod
     async def is_controller_available(self, config: KresConfig) -> bool:
         """
         Returns bool, whether the controller is available with the given config
         """
-        raise NotImplementedError()
 
+    @abstractmethod
     async def initialize_controller(self, config: KresConfig) -> None:
         """
         Should be called when we want to really start using the controller with a specific configuration
         """
-        raise NotImplementedError()
 
+    @abstractmethod
     async def get_all_running_instances(self) -> Iterable[Subprocess]:
         """
 
         Must NOT be called before initialize_controller()
         """
-        raise NotImplementedError()
 
+    @abstractmethod
     async def shutdown_controller(self) -> None:
         """
         Called when the manager is gracefully shutting down. Allows us to stop
@@ -225,8 +230,8 @@ class SubprocessController:
 
         Must NOT be called before initialize_controller()
         """
-        raise NotImplementedError()
 
+    @abstractmethod
     async def create_subprocess(self, subprocess_config: KresConfig, subprocess_type: SubprocessType) -> Subprocess:
         """
         Return a Subprocess object which can be operated on. The subprocess is not
@@ -235,8 +240,8 @@ class SubprocessController:
 
         Must NOT be called before initialize_controller()
         """
-        raise NotImplementedError()
 
+    @abstractmethod
     async def get_subprocess_status(self) -> Dict[KresID, SubprocessStatus]:
         """
         Get a status of running subprocesses as seen by the controller. This method  actively polls
@@ -244,4 +249,3 @@ class SubprocessController:
 
         Must NOT be called before initialize_controller()
         """
-        raise NotImplementedError()