Developer Reference

Message Bus Library

Message Bus

Message bus allows the containers in Edge Insights for Industrial (EII) to communicate with each other.

Dependency Installation

The Message bus depends on CMake version 3.11+. For Ubuntu 18.04, this is not the default version that is installed via apt-get. To install the correct version of CMake, run the following commands:

# Remove old CMake version
sudo apt -y purge cmake
sudo apt -y autoremove

# Download CMake
wget https://cmake.org/files/v3.15/cmake-3.15.0-Linux-x86_64.sh

# Installation CMake
sudo mkdir /opt/cmake
sudo cmake-3.15.0-Linux-x86_64.sh --prefix=/opt/cmake --skip-license

# Make the command available to all users
sudo update-alternatives --install /usr/bin/cmake cmake /opt/cmake/bin/cmake 1 --force

To install the remaining dependencies for the Message bus, run the following command:

Note: To avoid alterations to the Python installation in the system, it is recommended to use a Python virtual environment to install Python packages. Refer the following link for more details on setting up and using the python virtual environment https://www.geeksforgeeks.org/python-virtual-environment/.

sudo apt install libcjson-dev libzmq3-dev

Note

For Fedora, the packages should be cjson-devel zeromq-devel and for Alpine it is cjson-dev zeromq-dev.

If you wish to compile the Python binding as well, then you must also install the Python requirements. To do this, execute the following pip command:

pip3 install --user -r ./python/requirements.txt

Compilation

The Message bus utilizes CMake as the build tool for compiling the library. The simplest sequence of commands for building the library are as follows:

mkdir build
cd build
cmake ..
make

These commands will compile only the C library for the Message bus. To build with Python binding, specify the WITH_PYTHON flag while running the cmake command as follows:

cmake -DWITH_PYTHON=ON ..

To include installation of the GO binding with the installation of the EII library, specify the WITH_GO flag while running the cmake command as follows:

cmake -DWITH_GO=ON ..

Note: This command only copies the GO binding library to your system’s $GOPATH. Specify the $GOPATH in your system’s environmental variables to avoid the error while running the cmake command.

In addition to the WITH_PYTHON and WITH_GO flags, the Message bus CMake files, add flags for building the C examples and the unit tests associated with the library. The following table specifies the flags that you can set with the cmake command for building the Message bus.

Flag

Default

Description

WITH_TESTS

OFF

If set to ON, builds the C unit tests with the Message Bus compilation

WITH_EXAMPLES

OFF

If set to ON, then CMake will compile the C examples in addition to the library

WITH_DOCS

OFF

If set to ON, then CMake will add a docs build target to generate documentation

Note

  • These flags are in addition to any flags that are available for the cmake command. Refer to the CMake documentation for more information on additional flags.

  • Refer to the Generating Documentation section.

To compile the Message bus in debug mode, set the the CMAKE_BUILD_TYPE to Debug when executing the cmake command as follows:

cmake -DCMAKE_BUILD_TYPE=Debug ..

Generating Documentation

Generating the documentation has several dependencies that are not installed by the install.sh script. You must install the following packages to generate the documentation:

sudo apt install doxygen texlive-full

WARNING: Packages of size more than 4 GB is installed during the installation. This process may take a long time.

If you are building the Python binding using the WITH_PYTHON flag, then you must also install Sphinx and an extension for Sphinx. To do this, run the following commands:

sudo apt install python3-sphinx
sudo -H -E pip3 install m2r

Note

As a prerequistes for these commands, you should have Python 3.6 and pip installed on your system.

GO documentation generation is work in progress (WIP).

After completing these steps, run the following command to generate the documentation:

make docs && make docs

Note

You need to run the make docs command two times so that the Table of Contents is generated correctly for each document. This will be fixed in the future.

The PDF documents is available in the docs/pdfs/ directory within your build directory. Ignore other log files and output files associated with the building of the PDFs in the docs/pdfs/ directory.

Potential Compilation Issues

You can encounter the following issues during compilation:

  • CMake Python Version Issue: If you get CMake error related to incorrect Python version, then add the following flag to the CMake command: -DPYTHON_EXECUTABLE=/usr/bin/python3

  • Python Binding Changes Not Compiling: If the Python binding is changed, and the make command has been executed run previously, then you must run the make clean before running the make command to compile the changes in the Python binding. This will be fixed later.

Packaging

This library supports being packaged as a Debian, RPM, or Alpine APK packages. You can do this using the the cmake command. By default, packaging is disabled. To enable packaging, add the -DPACKAGING=ON flag to the cmake command. Refer to the Compilation section. This command will look something like:

cmake -DPACKAGING=ON ..

By default, the packaging utilities will scan the system for the required toolchains it needs to build each package type (Deb, RPM, and APK). If it does not find the required toolsets, then it will disable that form of packaging. The packaging utilities provide CMake flags to force packaging as any of the supported package types. If a given package type, ex. APK, is set to be enabled manually by its CMake flag and its required packaging toolchain does not exist, then CMake will raise a fatal error.

The following table provides the required toolchains for each package type as well as the CMake flag to set to ON to manually enable a packaging type:

Package Type

Required Tools

Manual Package Flag

deb

dpkg-deb

PACKAGE_DEB

rpm

rpmbuild

PACKAGE_RPM

apk

docker

PACKAGE_APK

Note

Manually setting a given package type to be built (e.g. setting -DPACKAGE_DEB=ON) still requires that the -DPACKAGING=ON to be set.

After the required toolchains have been installed and CMake has been run with some combination of the packaging flags, the library can be packaged with the following commands:

make package

The command above will build the Debian and RPM packages (depending on the specified CMake flags).

To build the Alpine APK package, execute the following command:

make package-apk

IMPORTANT:

The Message bus depends on the EII Utils library. To compile the Alpine APK package for the Message bus it must have the APK package for the EII Utils module. To provide this, you must first build or download the Alpine APK package for the EII Utils library (Refer to the repo here([WORK_DIR]/IEdgeInsights/common/util/c/) to obtain the library). After you have the APK, create apks directory at the top level of this repository.

mkdir apks/

Next, place the EII Utils APK package into the apks directory. Then run the make package-apk command. The build will fail if don’t do this.

A Note on Alpine APK Packaging

To package the library as an Alpine APK package, the packaging utility must use a Docker container to have access to the proper Alpine APK toolchains. This container will automatically be built when the CMake command is ran to configure your build environment.

By default, Alpine 3.14 is used to build the package. However, this version can be changed by setting the APKBUILD_ALPINE_VERSION CMake flag to the version of Alpine you wish to use For example, -DAPKBUILD_ALPINE_VERSION=3.12.

Installation

The Messsage bus library can be installed in two different ways.

  1. Through published Debian, Fedora, or Alpine APK packages

  2. Installing from source

If you are installing from one of the packages, select the package you wish to install from the releases assets, and then run one of the following depending on the OS you are installing on:

# Debian
sudo apt install libcjson1 libzmq5
sudo dpkg -i <debian package>

# Fedora
sudo dnf install cjson zeromq
sudo rpm -i <rpm package>

# Alpine (NOTE: the depencies get automatically installed by the apk command)
sudo apk add --allow-untrusted <apk package>

In the following commands, installing the cJSON and ZeroMQ dependencies is required, however, in general, installation of the dev module is not required (i.e. the OS packages which include all of the headers for the libraries). If you are compiling an application that is linking to this library, then it is recommended that you install the dev versions of the libraries. For Ubuntu this would mean installing libcjson-dev libzmq3-dev. For Fedora the packages would be cjson-devel zeromq-devel. In Alpine, the packages would be cjson-dev zeromq-dev.

If you wish to install the Message Bus on your system from source, execute the following command after building the library:

sudo make install

By default, this command will install the Message Bus C library into /opt/intel/eii/lib. On some platforms this is not included in the LD_LIBRARY_PATH by default. As a result, you must add this directory to you LD_LIBRARY_PATH, otherwise you will encounter issues using the Message Bus. This can be accomplished with the following export:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/intel/eii/lib

Note

You can also specify a different library prefix to CMake through the CMAKE_INSTALL_PREFIX flag. If different installation path is given via CMAKE_INSTALL_PREFIX, then $LD_LIBRARY_PATH should be appended by $CMAKE_INSTALL_PREFIX/lib.

Install Python Binding

To install the Python binding for the Message Bus execute the following commands:

# Change directories into the python/ directory
cd python/

# Install the Python package
sudo python3 setup.py install

Note

In order for the installation to be successful, you must have run the install.sh script with the --cython flag when installing the message bus dependencies.

Install Golang Binding

To install the Golang binding for the Message Bus execute the following command:

# Copy the Golang source to your $GOPATH/src directory
cp -a go/EIIMessageBus/ $GOPATH/src/

Note

The command assumes Golang is installed and configured on the target system.

Running Unit Tests

Note

The unit tests will only be compiled if the WITH_TESTS=ON option is specified when running CMake.

Execute one of the following commands from the build/tests folder to execute the message bus unit tests.

./msgbus-tests
./msg-envelope-tests
./crc32-tests

It is important to note that the msgbus-tests executable has an extra CLI option which the other unit test binaries do not have. This option allows for running the message bus tests to run over TCP rather than the IPC.

To run the message bus tests over TCP, execute the following command:

./msgbus-tests --tcp

Configuration

The Message Bus is configured through a key, value pair interface. The values can be objects, arrays, integers, floating point, boolean, or strings. The keys that are required to be available in the configuration are largly determined by the underlying protocol which the message bus will use. The protocol is specified via the type key and currently must be one of the following:

  • zmq_ipc - ZeroMQ over IPC protocol

  • zmq_tcp - ZeroMQ over TCP protocol

The following sections specify the configuration attributes expected for the TCP and IPC ZeroMQ protocols.

ZeroMQ IPC Configuration

The ZeroMQ IPC protocol implementation only requires one configuration attribute: socket_dir. The value of this attribute specifies the directory where the message bus should create the Unix socket files to establish the IPC based communication.

The ZeroMQ IPC protocol also supports a few optional configuration properties. For all communication patterns (request/response and publisher/subscribe), the socket_file property can be specified for any service name or publish/subscribe topic. This makes it so that all communication happens over the specified socket file, instead of the default, which is for the message bus to use the topic/service name for the socket file name. This enables two specific use cases:

  1. Having a single application publish multiple topics over a single IPC socket

    file

  2. Connecting ZeroMQ IPC publishers to the ZeroMQ Broker

For the second use case, there is an additional property which must be specified; the brokered configuration value. This is a boolean value, with true telling the publisher to connect to the broker and false for not connecting. Note that this value is not required. If it is false or is not specified, then the publisher will not connect to a broker and will bind to the given socket_file value.

IMPORTANT NOTE:

The socket_file value should only be the name of a file. The socket itself will still be created in the specified socket_dir directory.

Also, both the socket_file and brokered values must be specified in the

configuration under an object with its key being the topic or service name. An example of this is as follows: main

{
    // Specifies the ZeroMQ IPC protocol
    "type": "zmq_ipc",

    // Specifies the socket directory
    "socket_dir": "/tmp/socks",

    // The key, "example-topic", is the topic which the publisher shall publish
    // on. This could also be a service name.
    "example-topic": {
        // For the example-topic, the following property specifies the socket file
        // to use
        "socket_file": "socket-filename",

        // The following property is only supported by publishers, this specifies
        // that the given publisher will be brokered through the ZeroMQ Broker
        "brokered": true
    }
}

The previous example uses JSON to represent the Message Bus configuration. refer to the “Examples”, section for more details and more examples.

ZeroMQ TCP Configuration

The ZeroMQ TCP protocol has several configuration attributes which must be specified based on the communication pattern the application is using and based on the security the application wishes to enable for its communication.

Publishers

For an application which wishes to publish messages over specific topics, the configuration must contain the key zmq_tcp_publish. This attribute must be an object which has the following keys:

Key

Type

Required

Description

host

string

Yes

Specifies the host to publish as

port

int

Yes

Specifies the port to publish messages on

server_secret_key

string

No

Specifies the secret key for the port for authentication

brokered

boolean

No

Specifies whether or not to connect to the ZeroMQ Broker

The server_secret_key must be a Curve Z85 encoded string value that is specified if the application wishes to use CurveZMQ authentication with to secure incoming connections from subscribers.

The brokered key must be a boolean value. This will determine whether or not the publishers attempt to bind or connect to the given TCP (host, port) combination.

Subscribers

To subscribe to messages coming from a publisher over TCP, the configuration must contain a key for the topic you wish to subscribe to. For example, if Application 1 were publishing on topic sensor-1, then the subscribing application Application 2 would need to contain a configuration key sensor-1 which contains the keys required to configure the TCP connection to Application 1.

The key that can be specified for a subscribers configuration are outline in the following table: main

Key

Type

Required

Description

host

string

Yes

Specifies the host of the publisher

port

int

Yes

Specifies the port of the publisher

server_public_key

string

No

Specifies the publisher’s public key for authentication

client_secret_key

string

No

Specifies the subscribers’s secret key for authentication

client_public_key

string

No

Specifies the subcribers’s public key for authentication

Note

If one of the *_key values is specified, then all of them must be specified.

Services

The configuration to host a service to receive and respond to requests is similar to the configuration for doing publications on a message bus context. The only difference, is the configuration for a service is placed under a key which is the name of the service.

For example, if Application 1 wishes to host a service named example-service, then the configuration must contain a key called example-service. The value for that key must be an object containing the keys listed in the table of the Publishers section.

Requesters

The configuration to issue requests to a service is the exact same as a subscriber. In the case of a requester, instead of the configuration being under the name of the topic, the configuration is placed under the name of the service it wishes to connect to. For the details of the allowed values, Refer to the table in the Subscribers section.

Using ZAP Authentication

For services and publishers’ additional security can be enabled for all incoming connections (i.e. requesters and subscribers). This method utilizes the ZMQ ZAP protocol to verify the incoming client public keys against a list of whitelisted clients.

The list of allowed clients is given to the message bus via the allowed_clients key. This key must be a list of Z85 encoded CurveZMQ keys.

Additional ZeroMQ Configuration Properties

The configuration interface for the ZeroMQ protocol exposes additional socket

properties. The following table specifies each of the supported properties.

Configuration

Type

Default

Description

zmq_recv_hwm

int

1000

Sets ZMQ_RCVHWM socket property (queue size for pending received messages)

zmq_connect_retries

int

1000

Sets number of connect failures before recreating ZMQ socket object

Example Usage

IMPORTANT NOTE: Some of the example configurations contain public/private keys for the purpose of show how to use the message bus with security enabled. Never use these keys in production.

Note: The examples will only be compiled if the WITH_EXAMPLES=ON option is set when CMake is executed during compilation.

All of the examples provided for the Message Bus use a JSON configuration file to configure the Message Bus. There are several example configurations provided with the message bus for running in IPC and TCP mode across the various different messaging patterns (i.e. Publish/Subscribe and Request/Response). All of these example configurations are in the examples/configs/ directory. However, all of them are copied into the examples/build/configs/ directory as well when build the examples.

The following table specifies all of the provided example configurations.

Configuration

Description

ipc_example_config.json

Configuration for IPC based communication. Works with all examples.

ipc_example_config_multi_topics.json

Configuration for IPC based communication to be used with multi-topic publishing/subscribing. Works with publisher-many & subscriber examples.

ipc_publisher_brokered.json

Publisher configuration for IPC based communication using the ZeroMQ Broker.

ipc_subscriber_brokered.json

Subscriber configuration for IPC based communication using the ZeroMQ Broker.

tcp_publisher_brokered_no_security.json

TCP configuration for publishing with no security through the ZeroMQ Broker.

tcp_publisher_no_security.json

TCP configuration for publishing with no security.

tcp_publisher_with_security_no_auth.json

TCP configuration for publishing with key based auth without ZAP auth.

tcp_publisher_with_security_with_auth.json

TCP configuration for publishing with key based auth and ZAP auth.

tcp_subscriber_no_security.json

TCP configuration for subscribing to a topic with no security.

tcp_subscriber_no_security_prefix_match.json

TCP configuration for subscribing to multiple topics which share a common prefix, with no security.

tcp_subscriber_with_security.json

TCP configuration for subscribing to a topic with security enabled.

tcp_subscriber_with_security_prefix_match.json

TCP configuration for subscribing to multiple topics which share a common prefix, with security.

tcp_service_server_no_security.json

TCP configuration for a service server side (i.e. echo-service) without security.

tcp_service_server_with_security_no_auth.json

TCP configuration for a service server side with key based auth without ZAP auth.

tcp_service_server_with_security_with_auth.json

TCP configuration for a service server side with key based auth and ZAP auth.

tcp_service_client_no_security.json

TCP configuration for a service client side (i.e. echo-client) with no security.

tcp_service_client_with_security.json

TCP configuration for a service client side with security enabled.

Note

When using the brokered examples, you must also launch the broker first. For more information on the broker and how to use it, Refer to the ZmqBroker/README.md.

You will notice that for the publisher configurations and service server side configurations there are 3 configurations each, whereas subscribers and service client side configurations only have 2. This is because for publishers and service server side applications there are two forms of security to enable: with ZAP authentication, and no ZAP authentication. In the configurations with ZAP authentication, an additional configuration value is provided which specifies the list of clients (that is subscribers or service client side connections) which are allowed to connect to the specified port. This list operates as a whitelist of allowed client public keys. If a connection is attempted with a key not in that list, then the connection is denied.

C Examples

There are currently 5 C examples:

  1. examples/publisher.c

  2. examples/subscriber.c

  3. examples/echo_server.c

  4. examples/echo_client.c

  5. examples/publisher_many.c

All of the C example executables are in the build/examples/ directory. To run them, execute the following command:

./publisher ./configs/ipc_example_config.json

Note

The tcp_example_config.json can also be used in lieu of the IPC configuration file.

All of the examples follow the command structure, that is <command> <json-config-file>.json, except for the publisher_many.c example. This example is explained more in-depth in the next section.

Publisher Many Example

The examples/publisher_many.c example serves as a reference for implementing an application which contains many publishers. This also serves as a way of testing this functionality in the Message Bus.

The example can be run with the following command (from the build/examples/ directory):

./publisher-many ./configs/ipc_example_config.json 5

In this case, the example will create five publishers where the topic strings follow the pattern pub-{0,N-1} where N is the number of publishers specified through the CLI. Can replace this JSON config file with any other JSON config as mentioned in the table.

The behavior of how these topics are published depends on if the configuration is IPC or TCP (that is if type is set to zmq_ipc vs. zmq_tcp in the JSON configuration file).

If IPC communication is being used, then each topic will be a different Unix socket file in the socket_dir directory specified in the configuration, if default IPC config file ipc_example_config.json is used. If the IPC config file ipc_example_config_multi_topics.json is used then each topic is published over the socket file that is mentioned in the configuration file. For example, in the default file ipc_example_config_multi_topics.json, all topics publish & subscribe over the same socket file “multi-topics”. However, we can have each topic or a set of topics publish/subscribe over a different socket file.

If TCP communication is being used, then each message will be published over the host and port specified under the zmq_tcp_publish JSON object in the configuration.

To subscribe to the topics published by this example, use the subscriber.c example. If you are using TCP or even IPC with multiple topics subscription, then you will need to specify the topic in your configuration. For example, your JSON configuration will need to contain the following to subscribe to the pub-0 topic:

{
    "pub-0": {
        "host": "127.0.0.1",
        "port": 5569
    }
}

Note

The host and port are assumed, they may be different.

To simplify the creation of the configuration for subscribing to topics over TCP, the gen_tcp_sub_conf.py helper script is provided. This Python script will generate a JSON file for you based on your TCP JSON configuration for the publisher-many example which contains all of the topics specified so you can subscribe to any of them.

This helper script can be ran as follows:

python3 ./gen_tcp_sub_conf.py <CONFIG-FILE-PATH>/tcp_publisher_no_security.json output.json 5

The command uses the tcp_publisher_no_security.json for the publisher-many configuration. Then it generates all 5 topics and outputs them into the output.json file.

After generating this configuration, you can use the subscriber.c example to subscribe to the pub-1 topic:

./subscriber output.json pub-1

Similiarly for IPC mode of communicatin with multi topics, the sample JSON configuration is as follows:

    {
    "type": "zmq_ipc",
    "socket_dir": "${CMAKE_CURRENT_BINARY_DIR}/.socks",
    "pub-0": {
        "socket_file": "multi-topics"
    },
    "pub-1": {
       "socket_file": "multi-topics"
    },
    "pub-": {
       "socket_file": "multi-topics"
    }
}

Here, pub-0 & pub-1 are the PUB topics & pub- is the SUB topics, where we have given just the prefix name. If we don’t intend to give the SUB topic prefix, we can as well give the entire SUB topic name. In this example all these topics communicate over a common socket file multi-topics.

Python Examples

Note

The Python examples will only be present if the WITH_EXAMPLES=ON and WITH_PYTHON=ON flags are set when CMake is executed during compilation.

There are currently 4 Python examples:

  1. python/examples/publisher.py

  2. python/examples/subscriber.py

  3. python/examples/echo_server.py

  4. python/examples/echo_client.py

To run the Python examples, go to the build/examples/ directory. Then source the source.sh script that is in the examples directory.

source ./source.sh

Then, execute one of the following commands:

python3 ./publisher.py <CONFIG-FILE-PATH>/ipc_example_config.json

Note

The tcp_example_config.json can also be used in lieu of the IPC configuration file.

All of the examples follow the same command structure as the publisher.py script, i.e. python3 <python-script>.py <json-config-file>.json.

Go Examples

IMPORANT NOTE: It is assumed that when compiling the C library prior to running the examples that the WITH_GO=ON flag was specified when executing the cmake command. It is also assumed that, sudo make install has been ran. If it has not and you do not wish to install the library, Refer to the “Running Go Examples without Installing” section.

When the sudo make install command is executed on your system, the Go binding will be copied to your system’s $GOPATH. To execute the examples provided with the Message Bus Go binding go to the $GOPATH/src/EIIMessageBus/examples directory on your system in a terminal window.

Once you are in this directory choose an example (i.e. publisher, subscriber, etc.) and cd into that directory. Then, to run the example execute the following command:

go run main.go -configFile <CONFIG-FILE>.json -topic publish_test

The example command will run either the subscriber or publisher examples. For the echo-client and echo-server examples the -topic flag should be -serviceName.

Additionally, there are example configurations provided in the build/examples/configs/ directory after building the Message Bus library.

Running Go Examples without Installing

If you wish to run the Go binding examples with out installing the Message Bus library, then this can be accomplished by either copying or creating a soft-link to the go/EIIMessageBus directory in your $GOPATH. This can be accomplished with one of the commands as mentioned:

cp -r go/EIIMessageBus/ $GOPATH/src

# OR

ln -s go/EIIMessageBus/ $GOPATH/src

Note

The command above assumes that you are currently in the EIIMessageBus source root directory.

Since it is assumed you have not ran the sudo make install command to install the Message Bus library, you must set the environmental variables specified prior to running the examples.

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MSGBUS_DIR/build
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$MSGBUS_DIR/build

Note that in the export commands above the $MSGBUS_DIR variable represents the absolute path to the libs/EIIMessageBus directory. It is very important that this is the absolute path.

Once you have exported these variables, once you have done these steps, you can run any of the Go examples as specified in the previous section.

Brokered Publish/Subscribe

EII provides a ZeroMQ Broker. Any of the publisher and subscriber examples can be used with this broker. There are three example JSON configuration provided to showcase the required configuration of the publishers/subscribers to connect to the broker. Following examples are listed:

  1. ipc_publisher_brokered.json - IPC brokered publisher configuration

  2. ipc_subscriber_brokered.json - IPC brokered subscriber configuration

  3. tcp_publisher_brokered_no_security.json - TCP brokered publisher configuration

Note that there is not TCP brokered subscriber configuration. This is because no configuration change is needed to connect a subscriber to the broker.

For the publisher side of the configuration, it is important to note that in the IPC configuration, under the publish-test JSON object the configuration key brokered is set to true. Similarly, in the TCP configuration, under the zmq_tcp_publish JSON object the key brokered is also set to true. This tells the publisher to connect to the broker (vs. binding to the given socket configuration).

Since there is no code change to use a brokered publisher or subscriber, the examples can be ran the same as before, just with these brokered configurations. An example of this is as follows:

IPC Example:

# Start the publisher
./publisher ./configs/ipc_publisher_brokered.json

# Start the subscriber
./subscriber ./configs/ipc_subscriber_brokered.json

Note

These configurations work with the, “examples/ipc_frontend_example.json”, and, “examples/ipc_backend_example.json”, examples provided with the EII ZeroMQ Broker.

TCP Example:

# Start the publisher
./publisher ./configs/tcp_publisher_brokered_with_security.json

# Start the subscriber
./subscriber ./configs/tcp_subscriber_with_security.json

Note

These configurations work with the, “examples/tcp_frontend_example.json”, and, “examples/tcp_backend_example.json”, examples provided with the EII ZeroMQ Broker.

IMPORTANT NOTE:

Before running the examples, you must start the ZeroMQ Broker. Refer to the ZmqBroker/README.md for more details on configuring/launching the broker. Keep in mind that your broker configuration will impact the configuration needed for these examples.

For example, in the ipc_publisher_brokered.json configuration file, if the socket for publishers to connect to is not named frontend-sock then this configuration file needs to be changed to reflect the different socket file name.

To make this easy, the ZeroMQ Broker provides example configurations for TCP and IPC which use the same socket directory / files and (host, port) combinations to easily try out this feature.

Security

IMPORTANT NOTE: Security is only available for TCP communications. If IPC is being used, then all access must be controlled using Linux file permissions.

Note: Example configurations using for enabling security in the examples are provided in the examples directory.

The ZeroMQ protocol for the Message Bus enables to usage of CurveZMQ for encryption and authentication where the ZAP protocol is used for the authentication.

The ZeroMQ protocol for the message bus allows for using both CurveZMQ and ZAP together, only CurveZMQ encryption, or no encryption/authentication for TCP communication.

Enabling the security features is done through the configuration object which is given to the msgbus_initialize() method. The example configurations showcase how to use the security features enabled in the message bus. It is is given to the msgbus_initialize() method.

important to note that although the examples use JSON to convey the configurations it is not required that you use a JSON configuration for the message bus. However, utilities are provided in the C library for the message bus for using a JSON file to configure the bus.

Using Only CurveZMQ Encryption

If you wish to use the message bus with only CurveZMQ encryption, then you specify the following keys for the communication types specified in the following sections:

IMPORTANT NOTE: All keys must be Z85 encoded (Refer to the ZeroMQ documentation for more information).

Publish/Subscribe

For publications over TCP, the configuration must contain a server_secret_key value which the secret key of the Curve key pair that is Z85 encoded (Refer to the ZeroMQ documentation for more information).

Additionally, every subscriber configuration object (which is specified under the key for the topic it is subscribing to) must contain the following three keys: server_public_key, client_public_key, and client_secret_key.

Example:

Following is an example configuration in JSON (note: the keys are not Z85 encoded, but are more clear text to help the example).

Publisher Config:

{
    "type": "zmq_tcp",
    "zmq_tcp_publish": {
        "host": "127.0.0.1",
        "port": 3000,
        "server_secret_key": "publishers-secret-key"
    }
}

Subscriber Config:

{
    "type": "zmq_tcp",
    "pub-sub-topic": {
        "host": "127.0.0.1",
        "port": 3000,
        "server_public_key": "publishers-public-key",
        "client_secret_key": "subscriber-secret-key",
        "client_public_key": "subscriber-public-key"
    }
}

In the example configurations above, it is assumed that the publisher is sending messages on the pub-sub-topic topic.

Request/Response

For every service which is going to accept and respond to requests, there must exist the server_secret_key in the configuration object for the service. The key for the configuration of the service is its service name.

For every service which is going to issue requests to another service, there must exist a configuration object for the destination service name which contains the following three keys: server_public_key, client_public_key, and client_secret_key.

Example:

Service Config:

{
    "type": "zmq_tcp",
    "example-service": {
        "host": "127.0.0.1",
        "port": 3000,
        "server_secret_key": "service-secret-key"
    }
}

Service Requester Config:

{
    "type": "zmq_tcp",
    "example-service": {
        "host": "127.0.0.1",
        "port": 3000,
        "server_public_key": "service-public-key",
        "client_secret_key": "service-requester-secret_key",
        "client_public_key": "service-requester-public-key"
    }
}

In the example above, the service requester will connect to the example-service and issue requests to it on the port: 127.0.0.1:3000.

Using ZAP Authentication

To enable ZAP authentication protocol using CurveZMQ on top of the encryption, then in the configuration specify the key allowed_clients. This key must have a value which is a list of Z85 encoded strings which are the public keys of the clients which are allowed to connect to the application.

For example, using the publish/subscribe example from before, to make it so that only the subscriber client can connect to the publisher the publisher’s configuration would be modified to be the following:

{
    "type": "zmq_tcp",
    "allowed_clients": ["subscriber-public-key"],
    "zmq_tcp_publish": {
        "host": "127.0.0.1",
        "port": 3000,
        "server_secret_key": "publishers-secret-key"
    }
}
Disabling Security

To disable all encryption and authentication for TCP communication do not specify any of the configuration keys documented above. This will cause the message bus to initialize the ZeroMQ protocol without any of the CurveZMQ security primitives.

Known issues

Due to certain limitations imposed by cJSON, there is no proper distinction between an integer and a floating point in EIIMsgEnv. As a result of this limitation, the floating point values defined as whole numbers(1.0, 50.00 etc) are always deserialized as integers(1, 50 etc) on the subscriber’s end in C, Python & Go APIs.

The workaround for this limitation in the C APIs is to check for the type of msg_envelope_elem_body_t struct before accessing the respective type’s data. One such example is as follows:

msg_envelope_elem_body_t* data;
msgbus_ret_t ret = msgbus_msg_envelope_get(msg, "key", &data);
if (ret != MSG_SUCCESS) {
    LOG_ERROR_0("Failed to retreive message");
}
if (data->type == MSG_ENV_DT_INT) {
    LOG_INFO("Received integer: %d", data->body.integer);
} else if (data->type == MSG_ENV_DT_FLOATING) {
    LOG_INFO("Received float: %f", data->body.floating);
}

Generation of python .whl file (Optional)

Note: This is an optional as we have already hosted .whl file.

If user wants to create .whl file freshly, then follow the steps.

  1. Installation of wheel

    pip3 install –upgrade setuptools wheel
    
  2. Navigate to [WORKDIR]/IEdgeInsights/common/libs/EIIMessageBus/python and run the following command

    python3 setup_packaging.py sdist bdist_wheel --plat-name=manylinux2014_x86_64
    
  3. EIIMessageBus .whl package will be created in the folder dist as eii_msgbus-2.6-cp38-cp38-manylinux2014_x86_64.whl

API Documentation

Config Manager Library

ConfigMgr Overview

ConfigMgr or Config manager provides CPP, Python, and Golang APIs to:

  • fetch an application’s configs and interface values from the KV store (in the PROD and DEV mode) or from the config file (only in the DEV mode) based on your input “READ_CONFIG_FROM_FILE_ENV” for the pub, sub, server, and client.

  • monitor application’s config changes.

  • generate MessageBus config.

  • read and set the /config/logging env variables.

  • fetch the env variables: appname, dev_mode

All the ConfigMgr operations related data is stored in the KV store of Edge Insights for Industrial during the provisioning phase. The admin can dynamically change these data.

ConfigMgr Installation

You can install the EII Config Manager library in any of the following ways:

  • Through published Debian, Fedora, or Alpine APK packages

  • Installing from source

If you are installing from one of the packages then from the releases assets, select the package to install. Based on the OS that on which you are installing, run the following:

# Debian
sudo apt install libcjson1 libzmq5 zlib1g
sudo dpkg -i <debian package>

# Fedora
sudo dnf install cjson zeromq zlib
sudo rpm -i <rpm package>

# Alpine (NOTE: the depencies get automatically installed by the apk command)
sudo apk add --allow-untrusted <apk package>

In the above commands, installing the cJSON and ZeroMQ dependencies is required, however, in general, installation of the dev module is not required (i.e. the OS packages which include all of the headers for the libraries). If you are compiling an application that is linking to this library, then it is recommended that you install the dev versions of the libraries.

  • For Ubuntu, install libcjson-dev libzmq3-dev zlib1g-dev

  • For Fedora, install cjson-devel zeromq-devel zlib-devel

  • For Alpine, install cjson-dev zeromq-dev zlib-dev

If you want to compile the Config Manager from source, follow the intructions:

The ConfigMgr depends on CMake version 3.11+. For Ubuntu 18.04 this is not the default version installed via apt-get. To install the correct version of CMake and other ConfigMgr dependencies, refer to the eii_libs_installer README

To set CMAKE_INSTALL_PREFIX for the installation, run the following command:

export CMAKE_INSTALL_PREFIX="/opt/intel/eii"

ConfigMgr installs to /opt/intel/eii/lib/. On some platforms, this is not included in the LD_LIBRARY_PATH by default. As a result, you must add this directory to your LD_LIBRARY_PATH, otherwise you will encounter issues using the ConfigMgr. This can be accomplished with the following export:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/intel/eii/lib/

Note

You can also specify a different library prefix to CMake through the CMAKE_INSTALL_PREFIX flag. If different installation path is given via CMAKE_INSTALL_PREFIX, then $LD_LIBRARY_PATH should be appended by $CMAKE_INSTALL_PREFIX/lib.

To install the remaining dependencies for the Message bus, run the following command:

Note

: It is highly recommended that you use a python virtual environment to install the python packages, so that the system python installation doesn’t get altered. For details on setting up and using Python virtual environment, refer to `Python virtual environment <https://www.geeksforgeeks.org/python-virtual-environment/>>`_.

sudo apt install libcjson-dev libzmq5 zlib1g-dev

Note

For Fedora, the packages is cjson-devel zeromq-devel zlib-devel. For Alpine, the package is cjson-dev zeromq-dev zlib-dev.

If you wish to compile the Python binding as well, then you must also install the Python requirements. To do this, run the following pip command:

pip3 install --user -r ./python/requirements.txt
Using System gRPC

The ConfigMgr library can be built using the gRPC version already installed on the system. To do this, use the SYSTEM_GRPC flag when running the cmake command. Following is an example of the same.

cmake -DSYSTEM_GRPC=ON ..

Note

The ConfigMgr library depends on a specific gRPC version, 1.29.0. A debian package is provided for this in the grpc-package directory. To install this in Ubuntu run the following command:

sudo dpkg -i grpc-package/grpc-1.29.0-Linux.deb

Compilation

The Config Manager utilizes CMake as the build tool for compiling the library. The simplest sequence of commands for building the library are as follows.

mkdir build
cd build
cmake ..
make

This will compile only the C library for the ConfigMgr. To build with the Python binding, specify the WITH_PYTHON flag, when executing the cmake command. Refer to the following:

cmake -DWITH_PYTHON=ON ..

If you wish to include installation of the Go binding with the installation of the EII library, then specify the WITH_GO flag when executing the cmake command.

cmake -DWITH_GO=ON ..

Note

This only copies the Go binding library to your system’s $GOPATH. If you do not have your $GOPATH specified in your system’s environmental variables then an error will occur while executing the cmake command.

In addition to the WITH_PYTHON and WITH_GO flags, the ConfigMgr CMake files add flags for building the C examples and the unit tests associated with the library. The following table specifies all of the available flags that can be given to CMake for building the ConfigMgr.

Flag

Default

Description

WITH_TESTS

OFF

If set to ON, builds the C unit tests with the ConfigMgr compilation

WITH_EXAMPLES

OFF

If set to ON, then CMake will compile the C examples in addition to the library

WITH_DOCS

OFF

If set to ON, then CMake will add a docs build target to generate documentation

Note

  • These flags are in addition to any and all flags that are available for the cmake command. See the CMake documentation for additional flags.

  • See the Generating Documentation section.

If you wish to compile the ConfigMgr in debug mode, then you can set the the CMAKE_BUILD_TYPE to Debug when executing the cmake command. Refer to the following:

cmake -DCMAKE_BUILD_TYPE=Debug ..
Generating Documentation

Generating the documentation has several dependencies which are not installed by the install.sh script. You must install the following packages to generate the documentation:

sudo apt install doxygen texlive-full

Warning: This install way take a very long time. It will install more than 4GB of packages.

If you are building the Python binding by using the WITH_PYTHON flag, then you must also install Sphinx and an extension for Sphinx. This can be accomplished with the following commands:

sudo apt install python3-sphinx
sudo -H -E pip3 install m2r

Note

The commands above assume you already have Python 3.6 and pip installed on your system.

Go documentation generation is WIP.

Once you have completed these steps, the documentation can be generated by running the following make command:

make docs && make docs

Note

Currently you need to run make docs twice so that the table of contents is generated correctly for each of the documents. This will be fixed in the future.

The PDF documents will be in the docs/pdfs/ directory within your build directory. There will be other log files and output files associated with the building of the PDFs. Any file that does not end in .pdf can be ignored.

Packaging

Note

If the build is done using the system installed gRPC, then packaging cannot be done . This is due to the various linking issues that can occur in that scenario.

This library supports being packaged as a Debian, RPM, or Alpine APK packages. This is all accomplished via CMake. By default, packaging is disabled. To enable packaging, add the -DPACKAGING=ON flag to your CMake command (see Compilation section). This command will look something like:

cmake -DPACKAGING=ON ..

By default, the packaging utilities will scan the system for the required toolchains it needs to build each package type (Deb, RPM, and APK). If it does not find the required toolsets, then it will disable that form of packaging. The packaging utilities provide CMake flags to force packaging as any of the supported package types. If a given package type, ex. APK, is set to be enabled manually by its CMake flag and its required packaging toolchain does not exist, then CMake will raise a fatal error.

The table provides the required toolchains for each package type as well as the CMake flag to set to ON to manually enable a packaging type:

Package Type

Required Tools

Manual Package Flag

deb

dpkg-deb

PACKAGE_DEB

rpm

rpmbuild

PACKAGE_RPM

apk

docker

PACKAGE_APK

Note

Manually setting a given package type to be built (e.g. setting -DPACKAGE_DEB=ON) still requires that the -DPACKAGING=ON to be set.

After the required toolchains have been installed and CMake has been run with some combination of the packaging flags, the library can be packaged with the following commands:

make package

The command above will build the Debian and RPM packages (depending on the specified CMake flags).

To build the Alpine APK package, run the following command:

make package-apk

IMPORTANT:

The Config Manager depends on the EII Utils and Message bus libraries. To compile the Alpine APK package for the Config Manager it must have the APK packages for the EII Utils and Message bus modules.

To provide this, you must first build or download the Alpine APK package for the EII Utils library (see its repo here([WORK_DIR]/IEdgeInsights/common/util/c/) to obtain the library) and also for the Message bus (see it’s repo here([WORK_DIR]/IEdgeInsights/common/libs/EIIMessageBus/) to obtain the library).

After you have the APKs, create an apks directory at the top level of this repository.

mkdir apks/

Next, place the EII Utils and Message bus APK packages into the, apks, directory. Then run the make package-apk command. If this is not done, then the build will fail.

Note on Alpine APK Packaging

To package the library as an Alpine APK package, the packaging utility must use a Docker container to have access to the proper Alpine APK toolchains. This container will automatically be built when the CMake command is ran to configure your build environment.

By default, Alpine 3.14 is used to build the package. However, this version can be changed by setting the APKBUILD_ALPINE_VERSION CMake flag to the version of Alpine you wish to use (ex. -DAPKBUILD_ALPINE_VERSION=3.12).

Install ConfigMgr with Python bindings, Go bindings, Examples, Test suits, and Debug Build

rm -rf build
mkdir build
cd build
cmake -DCMAKE_INSTALL_INCLUDEDIR=$CMAKE_INSTALL_PREFIX/include -DCMAKE_INSTALL_PREFIX=$CMAKE_INSTALL_PREFIX -DWITH_PYTHON=ON -DWITH_GO=ON -DWITH_EXAMPLES=ON -DWITH_TESTS=ON -DCMAKE_BUILD_TYPE=Debug ..
make
sudo make install

WITH_PYTHON=ON, WITH_GO=ON, WITH_EXAMPLES=ON, WITH_TESTS=ON and CMAKE_BUILD_TYPE=Debug to compile ConfigMgr with Python bindings, Go bindings, Examples, Unit Tests and Debug mode respectively.

Interfaces

ConfigMgr parses the data from the kv store (eg: etcd) and the application environment variables for its functionality. It supports Publisher, Subscriber, Server and Client interfaces. Following are the examples for providing different interfaces and different usecases.

Refer to different ways of giving endpoints

Publisher Interface

{
    "Publishers": [
        {
            "Name": "default",
            "Type": "zmq_ipc",
            "EndPoint": "/EII/sockets",
            "Topics": [
                "camera1_stream"
            ],
            "AllowedClients": [
                "*"
            ]
        },
        {
            "Name": "example",
            "Type": "zmq_tcp",
            "EndPoint": "127.0.0.1:65015",
            "Topics": [
                "*"
            ],
            "AllowedClients": [
                "Visualizer", "VideoAnalytics"
            ]
        }
    ]
}

Key

Type

Required (Mandatory)

Description

Publishers

array

Yes

Entire publisher interface will be added with in the array. Multiple publish endpoints can be added by adding elements in the array.

Name

string

Yes

Name of different publisher interfaces

Type

string

Yes

Specifies ZeroMQ protocol (“zmq_tcp” or “zmq_ipc”) on which data will be published

EndPoint

string or object

Yes

In case of TCP or IPC (socket directory only), endpoint should be string as shown in the above examples. In case IPC explicitly specifying socket file, either object or string can be used for EndPoint. Refer to Different ways of specifying endpoint

Topics

array

Yes

Specifying the topics on which data will be published on. Multiple elements in this array can denote multiple topics published on the same endpoint

AllowedClients

array

Yes

Specifying who can subscribe to the the topic on which data is published. If AllowedClients is “*”, then all the provisioned services can receive the data published.

Subscriber Interface
{
    "Subscribers": [

        // tcp usecase
        {
            "Name": "example",
            "Type": "zmq_tcp",
            "EndPoint": "127.0.0.1:65013",
            "PublisherAppName": "VideoIngestion",
            "Topics": [
                "*"
            ]
        },

        // ipc usecase
        {
            "Name": "default",
            "Type": "zmq_ipc",
            "EndPoint": ".socks",
            "PublisherAppName": "VideoIngestion",
            // Topics cannot be "*", if the only IPC directory is given
            // if it Topics "*" to be used in ipc, then socket file should be given explicitly.
            "Topics": [
                "camera1_stream"
            ]
        }
    ]
}

Key

Type

Required (Mandatory)

Description

Subscribers

array

Yes

Entire subscriber interface will be added with in the array. Multiple subscribe endpoints can be added by adding elements in the array

Name

string

Yes

Name of different subscriber interfaces

Type

string

Yes

Specifies ZeroMQ protocol (“zmq_tcp” or “zmq_ipc”) through which subscription happens

EndPoint

string or object

Yes

In case of TCP or IPC (socket directory only), endpoint should be string as shown in the above examples. In Case IPC explicitly specifying socket file, either object or string can be used for EndPoint. Refer to Different ways of specifying endpoint

PublisherAppName

string

Yes

Specifies the publisher’s AppName through which data will be received

Topics

array

Yes

Specifying the topics on which data will be published on. If Topics is “*”, the subscriber receives all the data published on the endpoint, irrespective of the topic names data is published on. Multiple elements in this array can denote multiple topics subscribed on the same endpoint

Server Interface
{
    "Servers": [
        // tcp usecase
        {
            "Name": "default",
            "Type": "zmq_tcp",
            "EndPoint": "127.0.0.1:9006",
            "AllowedClients": [
                "VideoAnalytics"
            ]
        },
        //ipc usecase
        {
            "Name": "example",
            "Type": "zmq_ipc",
            "EndPoint": "/EII/sockets",
            "AllowedClients": [
                "VideoAnalytics"
            ]
        }
    ]
}

Key

Type

Required (Mandatory)

Description

Servers

array

Yes

Entire server interface will be added with in the array. Multiple server endpoints can be added by adding elements in the array

Name

string

Yes

Name of different server interfaces

Type

string

Yes

Specifies ZeroMQ protocol (“zmq_tcp” or “zmq_ipc”) through which Server pushes data

EndPoint

string or object

Yes

In case of TCP or IPC (socket directory only), endpoint should be string as shown in the above examples. In case IPC explicitly specifying socket file, either object or string can be used for EndPoint. Refer to Different ways of specifying endpoint

AllowedClients

array

Yes

Specifying who can get data is from the Server. If AllowedClients is “*”, then all the provisioned services can connect to Server.

Client Interface
{
    "Clients": [
        // tcp usecase
        {
            "Name": "default",
            "ServerAppName": "VideoIngestion",
            "Type": "zmq_tcp",
            "EndPoint": "127.0.0.1:9006"
        },

        // ipc usecase
        {
            "Name": "example",
            "ServerAppName": "VideoIngestion",
            "Type": "zmq_ipc",
            "EndPoint": "/EII/sockets"
        }
    ]
}

Key

Type

Required (Mandatory)

Description

Clients

array

Yes

Entire client interface will be added with in the array. Multiple client endpoints can be added by adding elements in the array

Name

string

Yes

Name of different client interfaces

ServerAppName

string

Yes

Server’s AppName to which client connection is established

Type

string

Yes

Specifies ZeroMQ protocol (“zmq_tcp” or “zmq_ipc”) through which client connection is established

EndPoint

string or object

Yes

In case of TCP or IPC (socket directory only), endpoint should be string as shown in the above examples. In case IPC explicitly specifying socket file, either object or string can be used for EndPoint. Refer to Different ways of specifying endpoint

Overriding of Type and EndPoint

In a given publisher, subscriber, client or server interfaces, the “Type” and “Endpoint” values mentioned in the respective interfaces can be overridden by setting them as env variables.

Let’s take publisher as an example having multiple endpoints and its interface:

{
    "Publishers": [
        {
            "Name": "default",
            "Type": "zmq_ipc",
            "EndPoint": "/EII/sockets",
            "Topics": [
                "camera1_stream"
            ],
            "AllowedClients": [
                "*"
            ]
        },
        {
            "Name": "example",
            "Type": "zmq_tcp",
            "EndPoint": "127.0.0.1:65015",
            "Topics": [
                "*"
            ],
            "AllowedClients": [
                "Visualizer", "VideoAnalytics"
            ]
        }
    ]
}

Let’s say we want to override the Type (“zmq_ipc”) and Endpoint (“/EII/sockets”) of the first publisher’s interface (interface having “Name”:”default”), then env variable should be set with following syntax.

export PUBLISHER_default_TYPE="zmq_tcp"
export PUBLISHER_default_ENDPOINT="127.0.0.1:65013"

In the above command default is the Name of the interface.

Similarly, we can override subscriber’s, client’s and server’s Type and Endpoint.

export SUBSCRIBER_default_TYPE="zmq_tcp"
export SUBSCRIBER_default_ENDPOINT="127.0.0.1:65013"

export SERVER_default_TYPE="zmq_tcp"
export SERVER_default_ENDPOINT="127.0.0.1:65013"

export CLIENT_default_TYPE="zmq_tcp"
export CLIENT_default_ENDPOINT="127.0.0.1:65013"

Let’s take publisher as an example having single endpoint and following is its interface:

{
    "Publishers": [
        {
            "Name": "default",
            "Type": "zmq_ipc",
            "EndPoint": "/EII/sockets",
            "Topics": [
                "camera1_stream"
            ],
            "AllowedClients": [
                "*"
            ]
        }
}

If we want to override the Type (“zmq_ipc”) and Endpoint (“/EII/sockets”) of publisher’s interface, then env variable should be set following syntax.

export PUBLISHER_TYPE="zmq_tcp"
export PUBLISHER_ENDPOINT="127.0.0.1:65013"

Similarly, we can override subscriber’s, client’s and server’s Type and Endpoint.

export SUBSCRIBER_TYPE="zmq_tcp"
export SUBSCRIBER_ENDPOINT="127.0.0.1:65013"

export SERVER_TYPE="zmq_tcp"
export SERVER_ENDPOINT="127.0.0.1:65013"

export CLIENT_TYPE="zmq_tcp"
export CLIENT_ENDPOINT="127.0.0.1:65013"

Overriding feature of ConfigMgr will be used in orchestrated scenarios including Kubernetes.

Broker Use Case

If publisher and subscriber wants to communicate via broker(ZmqBroker), i.e., if publisher publish data to ZmqBroker and subscriber subscribes from ZmqBroker, then the interfaces of ZmqBroker, subscriber and publisher with respect to zmq_tcp and zmq_ipc protocol as follows.

zmq_tcp Protocol Use Case

ZmqBroker Use Case
{
    //X-PUB
    "Publishers": [
        {
            "AllowedClients": [
                "*"
            ],
            "EndPoint": "127.0.0.1:5568",
            "Name": "backend",
            "Topics": [
                "*"
            ],
            "Type": "zmq_tcp"
        }
    ],
    // X-SUB
    "Subscribers": [
        {
            "AllowedClients": [
                "*"
            ],
            "EndPoint": "127.0.0.1:5569",
            "Name": "frontend",
            "PublisherAppName": "*",
            "Topics": [
                "*"
            ],
            "Type": "zmq_tcp"
        }
    ]
}
Subscriber
{
    "Subscribers": [
        {
            "Name": "default",
            "Type": "zmq_tcp",
            "EndPoint": "127.0.0.1:5568",

            // PublisherAppName will be "ZmqBroker" in case of brokered usecase
            "PublisherAppName": "ZmqBroker",
            "Topics": [
                "*"
            ]
        }
    ]
}
Publisher
{
    "Publishers": [
        {
            "Name": "default",
            "Type": "zmq_tcp",
            "EndPoint": "127.0.0.1:5569",
            "Topics": [
                "camera1_stream"
            ],
            // With broker usecase, AllowedClients in Publisher's interface is not required, as it acts as a subscriber to X-SUB

            // "brokered" and "BrokerAppName" should be added for ZmqBroker usecase
            "brokered": true,
            "BrokerAppName" : "ZmqBroker"
        }
    ]
}

zmq_ipc Protocol usecase

ZmqBroker
{
    "Publishers": [
        {
            "Name": "backend",
            "Type": "zmq_ipc",
            "EndPoint": {
                "SocketDir": "/EII/sockets",
                "SocketFile": "backend-socket"
            },
            "Topics": ["*"],
            "AllowedClients": ["*"]
        }
    ],
    "Subscribers": [
        {
            "Name": "frontend",
            "Type": "zmq_ipc",
            "EndPoint": {
                "SocketDir": "/EII/sockets",
                "SocketFile": "frontend-socket"
            },
            "PublisherAppName": "*",
            "Topics": ["*"],
            "AllowedClients": ["*"]
        }
    ]
}
Subscriber Details
{
    "Subscribers": [
        {
            "Name": "default",
            "Type": "zmq_ipc",
            "EndPoint": {
                "SocketDir" : "/EII/sockets",
                "SocketFile": "backend-socket"
            },

            // PublisherAppName will be "ZmqBroker" in case of brokered usecase
            "PublisherAppName": "ZmqBroker",

            // Topics cannot be "*", if the only IPC directory is given
            // if it Topics "*" to be used in ipc, then socket file should be given explicitly.
            "Topics": [
                "*"
            ]
        }
    ]
}
Publisher Details
{
    "Publishers": [
        {
            "Name": "default",
            "Type": "zmq_ipc",
            "EndPoint": {
                "SocketDir" : "/EII/sockets",
                "SocketFile": "frontend-socket"
            },
            "Topics": [
                "camera1_stream"
            ],

            // With broker usecase, AllowedClients in Publisher's interface is not required, as it acts as a subscriber to X-SUB

            // "brokered" and "BrokerAppName" should be added for ZmqBroker usecase
            "brokered": true,
            "BrokerAppName" : "ZmqBroker"
        }
    ]
}

Key

Type

Required (Mandatory)

Description

brokered

boolean

Yes

(Required if publishing via ZmqBroker) Specifies if publisher is using broker or not. use “brokered”: true for use with broker.

BrokerAppName

string

Yes

(Required if publishing via ZmqBroker) Specifies ZeroMQ Broker app name

Note “Endpoint” can be given in different ways
  • zmq_tcp Endpoint is as follows:

    "Endpoint":"127.0.0.1:65013"
    
  • zmq_ipc Endpoint have different ways of giving.

    • Specifying just socket directory

      "Endpoint":"/EII/sockets"
      
    • Specifying socket directory and socket file

      "Endpoint":{
          "SocketDir" : "/EII/sockets",
          "SocketFile": "socketfile"
      }
      
      or
      
      "Endpoint":"/EII/sockets, socketfile"
      

Running Examples

The ConfigMgr library also supports Cpp APIs and Python & Go bindings. These APIs/bindings can be used in Cpp and Python/Go services in the EII stack to fetch required config/interfaces/msgbus config.

Examples will only be compiled if the WITH_EXAMPLES=ON option is specified while running CMake. Refer to Examples installation

Refer the interfaces of publisher and server in ./examples/configs/VideoIngestion_interfaces.json([WORK_DIR]/IEdgeInsights/common/libs/ConfigMgr/examples/configs/VideoIngestion_interfaces.json) and for subscriber and client, refer to ./examples/configs/VideoAnalytics_interfaces.json([WORK_DIR]/IEdgeInsights/common/libs/ConfigMgr/examples/configs/VideoAnalytics_interfaces.json)

Note : In the above json files, if the message communication type is zmq_ipc, You need to make sure the socket directory is present in the host machine.

Examples on demonstrating the usage of these APIs in the bindings have been given in respective sections.

CPP Examples
Navigate to [WORKDIR]/IEdgeInsights/common/libs/ConfigMgr
sudo rm -rf build
mkdir build
cd build
cmake -DCMAKE_INSTALL_INCLUDEDIR=$CMAKE_INSTALL_PREFIX/include -DCMAKE_INSTALL_PREFIX=$CMAKE_INSTALL_PREFIX -DWITH_EXAMPLES=ON ..
make
sudo make install

There are currently 5 CPP examples:

  1. examples/sample_pub.cpp

  2. examples/sample_sub.cpp

  3. examples/sample_server.cpp

  4. examples/sample_client.cpp

  5. examples/sample_getvalue.cpp

All of the CPP example executables are in the build/examples/ directory. To run them, run the following command:

Before executing any of the examples, run the following command from build/examples/

cd ../../examples/ && source ./env.sh && cd -

Publisher example.

./pub

Subscriber example.

./sub

Server example.

./server

Client example.

./client

Sample_getvalue used to get the values from application’s config

./sample_app
Python Examples
Navigate to [WORKDIR]/IEdgeInsights/common/libs/ConfigMgr
sudo rm -rf build
mkdir build
cd build
cmake -DCMAKE_INSTALL_INCLUDEDIR=$CMAKE_INSTALL_PREFIX/include -DCMAKE_INSTALL_PREFIX=$CMAKE_INSTALL_PREFIX -DWITH_PYTHON=ON ..
make
sudo make install

There are currently 5 Python examples:

  1. examples/publisher.py

  2. examples/subscriber.py

  3. examples/echo_service.py

  4. examples/echo_client.py

  5. examples/sample_get_value.py

All of the py examples are in python/examples/ directory. To run them, execute the following command:

Before executing any of the examples, run the following command from python/examples/

cd ../../examples/ && source ./env.sh && cd -

Publisher example.

python3 publisher.py

Subscriber example.

python3 subscriber.py

Server example.

python3 echo_service.py

Client example.

python3 echo_client.py

sample_get_value used to get the values from application’s config

python3 sample_get_value.py
Go Examples
Navigate to [WORKDIR]/IEdgeInsights/common/libs/ConfigMgr/go
cp -r ConfigMgr/ $GOPATH/src
cd ConfigMgr/examples
source go_env.sh

There are currently 5 Go examples:

  1. publisher.go

  2. subscriber.go

  3. echo_service.go

  4. echo_client.go

  5. app_config.go

All of the go examples are in the go/examples/ directory. To run them, execute the following command:

Note

Before executing any of the examples, run the following command from go/ConfigMgr/examples/

cd ../../../examples/ && source ./env.sh && cd -
source ./go_env.sh

The Publisher example is as follows:

go build publisher.go
./publisher

The Subscriber example is as follows:

go build subscriber.go
./subscriber

The Server example is as follows:

go build echo_service.go
./echo_service

The Client example is as follows:

go build echo_client.go
./echo_client

The app_config used to get the values from application’s config is as follows:

go build app_config.go
./app_config

Running Unit Tests

Note

  • The unit tests will only be compiled if the WITH_TESTS=ON option is specified when running CMake. Refer Unit Test installation installation.

  • Provisioning should be done to start etcd server in the Dev or the Prod mode and to generate application specific certificates (only in prod mode).

Before executing any of the test files, run the following command from build/tests/:

cd ../../examples/ && source ./env.sh && cd -
  • To run ConfigMgr unit tests

./config_manager_unit_tests
./kvstore_client-tests
  • To run ConfigMgr unit tests reading from config file:

Enable DEV_MODE=true and READ_CONFIG_FROM_FILE_ENV=true in ./examples/env.sh

export DEV_MODE=true
export CONFIGMGR_CERT=""
export CONFIGMGR_KEY=""
export CONFIGMGR_CACERT=""
# set READ_CONFIG_FROM_FILE_ENV to TRUE if config needs to be read from file or FALSE if config needs to be read from etcd.
export READ_CONFIG_FROM_FILE_ENV=true

Once READ_CONFIG_FROM_FILE_ENV is set in DEV_MODE, execute the following commands to test ConfigManager reading from file unit test cases:

./config_manager_from_file_unit_tests
./cfgmgr_from_file_c_apis_unit_tests

Creation of grpc .zip file (Optional)

Note

This is an optional as we have already created .zip file in the repo. If you want to create .zip file freshly, then one has to follow this step.

Navigate to [WORKDIR]/IEdgeInsights/common/libs/ConfigMgr/grpc-package and run the grpc_zip.sh

sudo ./grpc_zip.sh

By executing the above script, grpc zip package will be created in [WORKDIR]/IEdgeInsights/common/libs/ConfigMgr/grpc-package.

Generation of python .whl file (Optional)

Note: This is an optional as we have already hosted .whl file. If you want to create .whl file freshly, then complete the following steps.

  1. Installation of wheel

    pip3 install –upgrade setuptools wheel
    
  2. Navigate to [WORKDIR]/IEdgeInsights/common/libs/ConfigMgr/python and run the following command:

    python3 setup_packaging.py sdist bdist_wheel --plat-name=manylinux2014_x86_64
    
  3. ConfigMgr .whl package will be created in the dist folder.

API Documentation