This documentation describes the SZTPD design.
Some end user goals that greatly influenced the design.
Many opportunities are missed due to onerous installation procedures. Keeping installation as simple as possible seems good. Note, this is why SZTPD doesn’t use any configuration files, preferring instead to put all data into the database supplied on the command line.
Deployment environments vary, with many variations of Linux, BSD, and Windows to choose from, not to mention some niche systems. In the same desire to simplify installation, a highly portable product seems like goodness.
There seems to be a sweet spot of having a minimal footprint, e.g., on CPU, memory, etc.. A low footprint allows it to run as a micro-service within a larger framework, or as an ephemeral daemon in an SDN context.
Having everything available via a programmatic API enables many integration options. Not only can a deployment-specific GUI be layered on top of it, but it can also be called into by controller / NMS applications.
The immediate use-case is the network equipment vendors and, from their perspectives, they would need to expose a multi-tenant service to their customers. Supporting tenants with isolated data views is critical.
The ability to persist all SZTPD data into a RDBMS is needed to enable the use of a host of RDBMS management tools enabling, for instance, backup, recovery, and encryption.
Using Python as the programming language was made based on past experience. Python is known for its easy installs, high portability, and low footprint.
Previous experience suggests that a single process can handle the expected load with cycles to spare. The simplicity goal is further achieved by not having to worry about virtual machines or Docker containers.`
Using SQLAlchemy was selected for its ability to work with multiple database backends, including in-memory, file-based, and RDBMSs such as MariaDB, MySQL, Postgres, Oracle, etc.
A few “no SQL” databases were looked at. In particular, document and graph based databases, but all required setting up an external server (no built-in in-memory or file-based options.
It seems common to have distinct “enterprise” and “service provider” versions of a product, modes ‘1’ and ‘x’, respectively.
In anticipation of developing other products, it was desired to factor as much domain-independent code as possible into a generic application layer, on top of which a separate SZTPD-specific layer defines the SZTPD product.
YANG models define arbitrary N-ary trees. It was needed to map arbitrary N-ary trees to SQL tables and rows. Having a layer for this seemed prudent.
The options for how to validate YANG datastore were unclear. Decision to use Yangson, but integrating into DAL didn’t seem right. Currently a separate layer so can be swapped out with another option if ever need be.
The database itself only ever persists the
native view. This is why it is called the “native” view. The other views define “facades” on top of the native view. The
tenant view facade maps input/output as needed. The
rfc8572 view facade only responds to the two RPCs, though it internally writes to both the audit log and bootstrapping log.
The current SZTPD schema uses a single data tree in one namespace. This is achieved via heavy use of
grouping statements in the YANG modules.
In alternative way to have approached this would’ve been to use Schema Mount, which defines a way to mount a YANG schema at a particular location. This could’ve been used for the tenant views.
However, tooling support for schema mount doesn’t exist yet or, at least, isn’t available in common tool-chains.
Having a single namespace also simplifies the code, but does limit the kinds of data models the generic layer can support. That said, if its used for other products in mind, then it will have already paid itself back.
Python objects are nearly indistinguishable from JSON objects - they both print the same tree structures. Thus using JSON natively makes sense. This decision was/is further constrained by the fact that Yangson only supports JSON as well.
SZTPD supports “dynamic callouts” in order to interact with external systems (except an RDBMS). Notable uses are:
Each dynamic callout may be implemented via a plugin linked into the Python process or as a webhook (i.e., an HTTP POST request).
SZTPD has builtin support for webhooks (include optional TLS server auth, optional TLS client auth, and optional HTTP “basic” auth). Webhooks are easy for any external system to support. For each dynamic callout, an ordered list of webhooks may be configured, in order to enable delivery when the primary receiver is unreachable.
However, in order to support a specific protocol, a plugin may be implemented. Plugins are only excuted once, so any HA logic must be contained within them.
The following diagram illustrates how the various Python modules within SZTPD are composed.