diff mbox series

[7/7] suricatta/lua: Add suricatta Lua module documentation

Message ID 20220602091807.54031-1-christian.storm@siemens.com
State Accepted
Delegated to: Stefano Babic
Headers show
Series [1/7] channel_curl: Map response code for file:// protocol | expand

Commit Message

Storm, Christian June 2, 2022, 9:18 a.m. UTC
Document the Lua suricatta module.

Signed-off-by: Christian Storm <christian.storm@siemens.com>
---
 doc/source/suricatta.rst | 241 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 230 insertions(+), 11 deletions(-)
diff mbox series

Patch

diff --git a/doc/source/suricatta.rst b/doc/source/suricatta.rst
index 6c8715c..e207597 100644
--- a/doc/source/suricatta.rst
+++ b/doc/source/suricatta.rst
@@ -21,9 +21,12 @@  failure in case booting the newly flashed root file system has failed
 and a switchback had to be performed.
 
 Suricatta is designed to be extensible in terms of the servers supported
-as described in Section `Supporting different Servers`_. Currently,
+as described in Section `The Suricatta Interface`_. Currently,
 support for the `hawkBit`_ server is implemented via the `hawkBit Direct
 Device Integration API`_ alongside a simple general purpose HTTP server.
+The support for suricatta modules written in Lua is not a particular server
+support implementation but rather an option for writing such in Lua instead
+of C.
 
 .. _hawkBit Direct Device Integration API:  http://sp.apps.bosch-iot-cloud.com/documentation/developerguide/apispecifications/directdeviceintegrationapi.html
 .. _hawkBit:  https://projects.eclipse.org/projects/iot.hawkbit
@@ -76,17 +79,17 @@  upstream server are skipped with an according message until a restart of
 SWUpdate has happened in order to not install the same update again.
 
 
-Supporting different Servers
-----------------------------
+The Suricatta Interface
+-----------------------
 
-Support for servers other than hawkBit can be realized by implementing
-the "interfaces" described in ``include/channel.h`` and
-``include/suricatta/server.h``. The former abstracts a particular
-connection to the server, e.g., HTTP-based in case of hawkBit, while
-the latter implements the logics to poll and install updates.
-See ``corelib/channel_curl.c``/``include/channel_curl.h`` and
-``suricatta/server_hawkbit.{c,h}`` for an example implementation
-targeted towards hawkBit.
+Support for servers other than hawkBit or the general purpose HTTP server can be
+realized by implementing the "interfaces" described in ``include/channel.h`` and
+``include/suricatta/server.h``, the latter either in C or in Lua.
+The channel interface abstracts a particular connection to the server, e.g.,
+HTTP-based in case of hawkBit. The server interface defines the logics to poll
+and install updates. See ``corelib/channel_curl.c`` / ``include/channel_curl.h``
+and ``suricatta/server_hawkbit.{c,h}`` for an example implementation in C targeted
+towards hawkBit.
 
 ``include/channel.h`` describes the functionality a channel
 has to implement:
@@ -267,3 +270,219 @@  with the events set as above, the formatted text in case of "success" will be:
 ::
 
         Formatted log: #13,Mon, 17 Sep 2018 10:55:18 CEST,1.0,ipse,333
+
+
+Support for Suricatta Modules in Lua
+------------------------------------
+
+The ``server_lua.c`` C-to-Lua bridge enables writing suricatta modules in Lua. It
+provides the infrastructure in terms of the interface to SWUpdate "core" to the Lua
+realm, enabling the "business logic" such as handling update flows and communicating
+with backend server APIs to be modeled in Lua. To the Lua realm, the ``server_lua.c``
+C-to-Lua bridge provides the same functionality as the other suricatta modules
+written in C have, realizing a separation of means and control. Effectively, it lifts
+the interface outlined in Section `The Suricatta Interface`_ to the Lua realm.
+
+
+As an example server implementation, see ``examples/suricatta/server_general.py`` for
+a simple (mock) server of a backend that's modeled after the "General Purpose HTTP
+Server" (cf. Section `Support for general purpose HTTP server`_). The matching Lua
+suricatta module is found in ``examples/suricatta/swupdate_suricatta.lua``. Place it in
+Lua's path so that a ``require("swupdate_suricatta")`` can load it or embed it into the
+SWUpdate binary by enabling ``CONFIG_EMBEDDED_SURICATTA_LUA`` and setting
+``CONFIG_EMBEDDED_SURICATTA_LUA_SOURCE`` accordingly.
+
+The interface specification in terms of a Lua (suricatta) module is found in
+``suricatta/suricatta.lua``.
+
+
+`suricatta`
+...........
+
+The ``suricatta`` table is the module's main table housing the exposed functions and
+definitions via the sub-tables described below.
+In addition, the main functions ``suricatta.install()`` and ``suricatta.download()``
+as well as the convenience functions ``suricatta.getversion()``, ``suricatta.sleep()``,
+and ``suricatta.get_tmpdir()`` are exposed:
+
+The function ``suricatta.install(install_channel)`` installs an update artifact from
+a remote server or a local file. The ``install_channel`` table parameter designates
+the channel to be used for accessing the artifact plus channel options diverging
+from the defaults set at channel creation time. For example, an ``install_channel``
+table may look like this:
+
+.. code-block:: lua
+
+    { channel = chn, url = "https://artifacts.io/update.swu" }
+
+where ``chn`` is the return value of a call to ``channel.open()``. The other table
+attributes, like ``url`` in this example, are channel options diverging from or
+omitted while channel creation time, see :ref:`suricatta.channel`. For installing
+a local file, an ``install_channel`` table may look like this:
+
+.. code-block:: lua
+
+    { channel = chn, url = "file:///path/to/file.swu" }
+
+
+The function ``suricatta.download(download_channel, localpath)`` just downloads an
+update artifact. The parameter ``download_channel`` is as for ``suricatta.install()``.
+The parameter ``localpath`` designates the output path for the artifact. The
+``suricatta.get_tmpdir()`` function (see below) is in particular useful for this case
+to supply a temporary download location as ``localpath``. A just downloaded artifact
+may be installed later using ``suricata.install()`` with an appropriate ``file://``
+URL, realizing a deferred installation.
+
+Both, ``suricatta.install()`` and ``suricatta.download()`` return ``true``, or, in
+case of error, ``nil``, a ``suricatta.status`` value, and a table with messages in
+case of errors, else an empty table.
+
+|
+
+The function ``suricatta.getversion()`` returns a table with SWUpdate's ``version``
+and ``patchlevel`` fields. This information can be used to determine API
+(in-)compatibility of the Lua suricatta module with the SWUpdate version running it.
+
+The function ``suricatta.sleep(seconds)`` is a wrapper around `SLEEP(3)` for, e.g.,
+implementing a REST API call retry mechanism after a number of given seconds have
+elapsed.
+
+The function ``suricatta.get_tmpdir()`` returns the path to SWUpdate's temporary
+working directory where, e.g., the ``suricatta.download()`` function may place the
+downloaded artifacts.
+
+
+`suricatta.status`
+..................
+
+The ``suricatta.status`` table exposes the ``server_op_res_t`` enum values defined in
+``include/util.h`` to the Lua realm.
+
+
+`suricatta.notify`
+..................
+
+The ``suricatta.notify`` table provides the usual logging functions to the Lua
+suricatta module matching their uppercase-named pendants available in the C realm.
+
+One notable exception is ``suricatta.notify.progress(message)`` which dispatches the
+message to the progress interface (see :doc:`progress`). Custom progress client
+implementations listening and acting on custom progress messages can be realized
+using this function.
+
+All notify functions return ``nil``.
+
+
+`suricatta.pstate`
+..................
+
+The ``suricatta.pstate`` table provides a binding to SWUpdate's (persistent) state
+handling functions defined in ``include/state.h``, however, limited to the bootloader
+environment variable ``STATE_KEY`` defined by ``CONFIG_UPDATE_STATE_BOOTLOADER`` and
+defaulting to ``ustate``. In addition, it captures the ``update_state_t`` enum values.
+
+The function ``suricatta.pstate.save(state)`` requires one of ``suricatta.pstate``'s
+"enum" values as parameter and returns ``true``, or, in case of error, ``nil``.
+The function ``suricatta.pstate.get()`` returns ``true``, or, in case of error, ``nil``,
+plus one of ``suricatta.pstate``'s "enum" values in the former case.
+
+
+`suricatta.server`
+..................
+
+The ``suricatta.server`` table provides the sole function
+``suricatta.server.register(function_p, purpose)``. It registers a Lua function
+"pointed" to by ``function_p`` for the purpose ``purpose`` which is defined by
+``suricatta.server``'s "enum" values. Those enum values correspond to the functions
+defined in the interface outlined in the Section on `The Suricatta Interface`_.
+
+In addition to these functions, the two callback functions ``CALLBACK_PROGRESS`` and
+``CALLBACK_CHECK_CANCEL`` can be registered optionally: The former can be used to upload
+progress information to the server while the latter serves as ``dwlwrdata`` function
+(see ``include/channel_curl.h``) to decide on whether an installation should be aborted
+while the download phase.
+
+For details on the (callback) functions and their signatures, see the interface
+specification ``suricatta/suricatta.lua`` and the documented example Lua suricatta
+module found in ``examples/suricatta/swupdate_suricatta.lua``.
+
+The ``suricatta.server.register()`` function returns ``true``, or, in case of error,
+``nil``.
+
+
+.. _suricatta.channel:
+
+`suricatta.channel`
+...................
+
+The ``suricatta.channel`` table captures channel handling for suricatta Lua modules.
+The single function ``suricatta.channel.open(options)`` creates and opens a channel
+to a server. Its single parameter ``options`` is a table specifying the channel's
+default options such as `proxy`, `retries`, `usessl`, `strictssl`, or
+`headers_to_send`. For convenience, options that may change per request such as
+`url`, `content-type`, or `headers_to_send` may be set as defaults on channel
+creation time while being selectively overruled on a per request basis. The channel
+options currently supported to be set are listed in the ``suricatta.channel.options``
+table. In essence, the ``options`` parameter table is the Lua table equivalent of
+``include/channel_curl.h``'s ``channel_data_t``.
+
+
+The ``suricatta.channel.open(options)`` function returns a channel table which is
+either passed to the ``suricatta.install()`` and ``suricatta.download()`` functions
+or used directly for communication with a server. More specifically, it has the three
+functions
+
+* ``get(options)`` for retrieving information from the server,
+* ``put(options)`` for sending information to the server, and
+* ``close()`` for closing the channel.
+
+The ``get()`` and ``put()`` functions' single parameter ``options`` is a per-request
+channel option table as described above.
+
+The functions ``get()`` and ``put()`` return ``true``, or, in case of error, ``nil``,
+a ``suricatta.status`` value, and an operation result table.
+The latter contains the fields:
+
+* ``http_response_code`` carrying the HTTP error code,
+* ``format`` as one of ``suricatta.channel.content``'s options,
+* ``raw_reply`` if ``options`` contained ``format = suricatta.channel.content.RAW``,
+* ``json_reply`` if ``options`` contained ``format = suricatta.channel.content.JSON``, and
+* the HTTP headers received in the ``received_headers`` table, if any.
+
+
+The ``suricatta.channel.content`` "enum" table defines the "format", i.e., the response
+body content type and whether to parse it or not:
+
+* ``NONE`` means the response body is discarded.
+* ``RAW`` means the raw server's reply is available as ``raw_reply``.
+* ``JSON`` means the server's JSON reply is parsed into a Lua table and available
+  as ``json_reply``.
+
+
+The ``suricatta.channel.method`` "enum" table defines the HTTP method to use for
+a request issued with the ``put(options)`` function, i.e., `POST`, `PATCH`, or `PUT` as
+specified in the ``options`` parameter table via the ``method`` attribute.
+In addition to the HTTP method, the request body's content is set with the
+``request_body`` attribute in the ``options`` parameter table.
+
+
+As a contrived example, consider the following call to a channel's ``put()`` function
+
+.. code-block:: lua
+
+    ...
+    local res, _, data = channel.put({
+            url          = string.format("%s/%s", base_url, device_id),
+            content_type = "application/json",
+            method       = suricatta.channel.method.PATCH,
+            format       = suricatta.channel.content.NONE,
+            request_body = "{ ... }"
+        })
+    ...
+
+that issues a HTTP `PATCH` to some URL with a JSON content without having interest in
+the response body.
+
+More examples of how to use a channel can be found in the example suricatta Lua
+module ``examples/suricatta/swupdate_suricatta.lua``.
+