Gateway Device Client

The device-client python package is a separate component from any other Exosite gateway technology. By using the modularity principle in its design, this protocol layer can be modified or replaced with the consumers needing no modification. The gwe product consumes the device-client as a library for all communications with the Exosite HTTP Device API. This means the device-client library is globally available for other programs like custom gateway applications.

@startuml
!include ../../gateway-engine/docs/gwe-style.iuml

title Gateway Engine Communication Topology

rectangle "Linux" #EFEFEF {
    rectangle "Python" PYTHON {
        rectangle "device-client" as DC MURANOCOM
        rectangle "Gateway Engine" as GWE GATEWAYENGINE {
            rectangle gwe
            rectangle gmq
            rectangle supervisord SUPERVSR

            DC <-[MURANOCOM]do- gwe : Solid\nlines\nmandatory\nroutes.
            DC <-[MURANOCOM]do- gmq
        }
    }
    rectangle "Custom\nGateway\nApplication" as CGA CUSTOMAPP {

    }
}

cloud Exosite {
    rectangle Murano GATEWAYENGINE {
        rectangle Product ONEP {
            rectangle Device PYTHON
        }
    }
}
gwe o-[SUPERVSR]- supervisord : Supervisor\nMonitoring\nand\nControl
gmq o-[SUPERVSR]- supervisord
CGA o-[SUPERVSR]- supervisord

DC <.[MURANOCOM]do. CGA : Dashed\nlines\noptional\nroutes.
gmq <.[MURANOCOM]do. CGA
Device <.[MURANOCOM]do. CGA
Device <.[MURANOCOM]do. DC

@enduml

The purpose of the device-client package is to provide a library to the Exosite HTTP Device API as well as providing some other gateway-centric services.

Overview

The Gateway Device Client (GDC) can be referred to as the protocol layer of the gateway. It is a python package that can be used as a common entry point for all requests to Exosite. Though other Exosite API libraries exist, GDC is used by Gateway Engine and other Exosite gateway technologies to format and process all Exosite API requests. The GDC library has a few features that make it extremely useful for development, debugging and telemetry purposes.

Response handlers

Writing code that handles HTTP(S) responses can quickly add to the overhead of writing a gateway IoT application. Utilizing the built-in response handlers can simplify things.

from exo.api import ExositeAPI

api = ExositeAPI(
    host='98dujkrofujk.m2.exosite.io',
    cik='7f091cf4b16de3fb3172c253eb35109a6992d76b'
)

resp_handler = api.http_write('hello_dataport', 'World')
if resp_handler.success:
    pass
else:
    print('Unable to send message: {}'.format(resp_handler))

Interface Auditing

When using objects of either the ExositeAPI or Device classes, all requests to Exosite will be logged for gathering statistics and telemetrics. The log is in the form of an sqlite3 database located in /tmp/ifaces.db (default) for efficient queries.

sqlite3 /tmp/ifaces.db ".dump"

Support for Custom Interfaces

The interfaces log is meant to capture meta data of all outgoing requests during. If a reboot occurs, the database is cleared due to the fact that it is located in /tmp, which is typically a tmpfs.

The Interfaces class has the following configuration options. All options should be defined in /opt/exosite/gdc/gdc.cfg, section ‘gdc’

Currently defined configuration parameters
Parameter Description  
ifaces A comma-separated list of interfaces for which you want reports.  
flush_db_after_report A boolean that, when true, ensures the ifaces.db log is flushed when exo.ifaces.Interfaces.interface_report() function is executed. Typically this function is only used by Gateway Engine. By setting this option to false, the ifaces.db log will only be flushed when manually deleted or during a gateway power-cycle.  

Example

$ cat /opt/exosite/gdc/gdc.cfg
[gdc]
ifaces = eth0,wlan0
flush_db_after_report = true

Though you can edit the gdc.cfg file manually with tools like vim and nano, the gdc command-line tool is built with an INI configuration file editor and parser. For more information on how to use gdc to configure any INI configuration file (e.g. gwe, gmq, gdc), see the section on the gdc CLI tool. TODO: create link for the cli tool here.

Connect to Custom Servers

Sometimes your IoT solution is in development and you need to point your data originator (i.e. device, simulator script, etc.) at some host other than <VENDOR>.m2.exosite.com, the device-client library supports custom servers with the host constructor parameter.

from exo.api import ExositeAPI

PORT = '443'

api = ExositeAPI(
    cik='7f091cf4b16de3fb3172c253eb35109a6992d76b',
    host='192.168.10.242:'+PORT
)

resp_handler = api.http_write('hello_dataport', 'World')
if resp_handler.success:
    pass
else:
    print('Unable to send message: {}'.format(resp_handler))

Using with Gateway Message Queue (gmq)

You can also use the Device() and ExositeAPI() classes to interface with gmq when/where the APIs are supported in GMQ:

import time
from exo.api import ExositeAPI

PID = 'v8ivigky4z589f6r'
UUID = 'asdf'

api = ExositeAPI(
    host='localhost:8090',
    custom_auth={'X-Exosite-VMS': '{} {} {}'.format(PID, PID, UUID)},
    product_domain=False,
    use_ssl=False,
    form_encode=False);

api.set_http_debug(True) # optional

# a record api example
resp_handler = api.http_record(
    { 'test':
        { time.time()+1: 'This was recorded via device-client.'}
    }
)
print(resp_handler)

# continually write data
while True:
    resp_handler = api.http_write(
        'test', 'GMQ will attempt to write this data. If the "write" operation fails, GMQ will try to "record" it later.'
    )
    print(resp_handler)
    time.sleep(1)

Example

Here is an example print-out of one of the requests from the example code, above.

send: 'POST /onep:v1/stack/alias HTTP/1.1\r\nHost: localhost:8090\r\nContent-Length: 23\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nUser-Agent: Device-Client-V1.4.\r\nConnection: keep-alive\r\nX-Exosite-VMS: v8ivigky4z589f6r v8ivigky4z589f6r asdf\r\nContent-Type: application/x-www-form-urlencoded; charset=utf-8\r\n\r\ntest=test+data+from+gmq'
reply: 'HTTP/1.1 204 No Content\r\n'
header: Date: Wed, 30 Nov 2016 17:48:25 GMT
header: Content-Length: 0
header: Content-Type: text/html
header: Server: TwistedWeb/14.0.2
Response code: 204, Response body: u'', success: True, authorized: True

Provisioning Options

There are two methods available to you when provisioning your devices with Murano: * token * TLS Client Certificate.

The sections that follow show usage examples of both of these methods with both Device and ExositeAPI classes.

Device Class Authentication Examples

Token

$ cat my-device.cfg
[device]
cik = ''
vendor = 098ujkityuhji8
model = 098ujkityuhji8
uuid = 001
$ cat my-gateway-program.py
#!/usr/bin/env python

from exo.device import Device
d = Device('My-Gateway-Program-v1', 'my-device.cfg')

d._activate()
d.http_write('test', 'My auth token has been saved in my-device.cfg.')

$ cat my-device.cfg
[device]
cik = B06JEc1Vga4POdMba9Zw751vSu9SdDHeQ4E8pjBQ
vendor = 098ujkityuhji8
model = 098ujkityuhji8
uuid = 001

TLS Client Certificate

$ cat my-device.cfg
[device]
cik = ''
vendor = 098ujkityuhji8
model = 098ujkityuhji8
uuid = 001

[tls_provision]
certfile = /path/to/certfile.crt
keyfile = /path/to/keyfile.key

$ cat my-gateway-program.py
#!/usr/bin/env python

from exo.device import Device
d = Device('My-Gateway-Program-v1', 'my-device.cfg')

d.http_write('test', 'No tokens are exchanged when using TLS Client Auth.')

$ cat my-device.cfg
[device]
cik = ''
vendor = 098ujkityuhji8
model = 098ujkityuhji8
uuid = 001
host = 098ujkityuhji8.m2.exosite.io

[tls_provision]
certfile = /path/to/certfile.crt
keyfile = /path/to/keyfile.key

ExositeAPI Class Authentication Examples

Token

#!/usr/bin/env python

import os
from exo.api import ExositeAPI

if os.path.exists('my-token.txt'):
    token = open('my-token.txt', 'r').read()
else:
    token = ''

a = ExositeAPI(
    host='098ujkityuhji8.m2.exosite.io',
    cik = token
)

if not a.activated():
    a._activate()
    if a.activated():
        open('my-token.txt', 'wb').write(a.cik())
d.http_write('test', 'My auth token has been saved in my-token.txt.')

TLS Client Certificate

#!/usr/bin/env python

from exo.api import ExositeAPI
a = ExositeAPI(
    host='098ujkityuhji8.m2.exosite.io',
    tls_provision = {
        'certfile': '/path/to/certfile.crt',
        'keyfile': '/path/to/keyfile.key'
    }
)

assert True == a.activated(), "Objects using TLS Client Cert auth initialize as 'activated'."
d.http_write('test', 'Tokens are not exchanged when using TLS Client Cert auth.')

Connection Reuse

The device-client objects Device() and ExositeAPI() now support requests sessions to better manage TCP connections to Exosite. By instantiating Device() or ExositeAPI() object, the requests module will keep the connection alive as long as possible to minimize TLS handshaking, resulting in less overall network bandwidth consumption.

Command Line Interface

A light-weight cli is provided for common tasks like checking the version number and install path as well as activate, read, poll, write and record functions.

Example

Gateway Device Client (GDC) Command-Line interface.

GDC is a light-weight cli for common tasks using the device-client library.

Usage:
  gdc [-h|-v|-p|-c]
  gdc cfg get [<section> <option> -f <file>]
  gdc cfg set <section> [<option> <value> -f <file> -U]
  gdc [-d <lvl> -t <secs> -H <host>] timestamp (-i <id> | -f <file>) [-C <cert> -K <pkey>]
  gdc [-N -F -P -i <id> -d <lvl> -t <secs> -H <host>]  activate  (<pid> <uuid> | -f <file> | -C <cert> -K <pkey>)
  gdc [-N -F -P -i <id> -d <lvl> -t <secs> -H <host>]  read      (-f <file> | -C <cert> -K <pkey> | <cik>) <alias> [<alias>]...
  gdc [-N -F -P -i <id> -d <lvl> -t <secs> -H <host>]  poll      (-f <file> | -C <cert> -K <pkey> | <cik>) <alias> <request-timeout> [<if-modified-since>]
  gdc [-N -F -P -i <id> -d <lvl> -t <secs> -H <host>]  write     (-f <file> | -C <cert> -K <pkey> | <cik>) <alias> <data> [<alias> <data>]...
  gdc [-N -F -P -i <id> -d <lvl> -t <secs> -H <host>]  record    (-f <file> | -C <cert> -K <pkey> | <cik>) <timestamp> <alias> <data>

Commands:
    cfg             Interface for viewing and modifying gdc configuration settings.
    timestamp       Get the Murano timestamp.
    activate        Use the HTTP Device API to activate client described by Product
                    and Device IDs. Prints the CIK to STDOUT if successful. If -f
                    option is used, the Device config file is used.
    read            Read resource described by <alias>.
    poll            Long poll <alias> for <request-timeout> since <if-modified-since>.
    write           Write <value> to <alias> resource.
    record          Record <value> to <alias> at time <timestamp>.

Info Options:
    -h --help                   Show this screen.
    -v --version                Print the current version of device-client.
    -p --path                   Print the installation path to the device-client python package.
    -c --cfg-file               Print the path to the gdc configuration file.

API Options:
    -N --no-ssl                 If provided, SSL/TLS will not be used in HTTP(S) comms.
    -F --no-form-encode         If provided, POST data will not be form-encoded.
    -P --no-product-domain      If provided, project domains (i.e. your project ID).
    -i --pid <id>               The Project/Product ID.
    -t --timeout <secs>         If provided, <secs> is used as HTTP Timeout (in seconds).
    -H --host <host>            If provided, <host> is used as the server hostname for HTTP requests.
    -d --debug <lvl>            Turn on verbose debug output. Also logs curl commands.

Auth Options:
    -f --file <file>            All operations will use <file> as the Device state file. This file
                                is compatible with Device class objects. Will store <cik> and
                                provision as the Murano client described in its options. This
                                option has special support for configuring the GWE config file
                                by using 'gwe' as the <file> argument.
    <cik>                       A CIK (Client Interface Key).
    -C --cert <cert>            Use <cert> for Murano Provisioning of client described in
                                the certificate subject.
    -K --pkey <pkey>            Use <pkey> in TLS communication with Murano.

Config Options:
    -U --unset                  If provided, remove this section or option.

Arguments:
    <id>                        A Murano Project ID.
    <secs>                      Set the HTTP timeout in seconds of your request.
    <host>                      The Exosite server the HTTP Device API calls will be
                                directed to.
    <section>                   An INI file section.
    <option>                    An INI section option.
    <value>                     An INI option value.
    <file>                      Path to a Device() class INI-style configuration file.
    <cert>                      Path to an X509 certificate.
    <pkey>                      Path to an X509 private key.
    <alias>                     A Murano Product resource.
    <data>                      The data to write or record.
    <request-timeout>           The amount of time, in milliseconds, to long-poll on <alias>.
    <if-modified-since>         The timestamp (unix epoch) from which to check for new data on <alias>.

Building

The device-client library is built for installation via Gateway Engine.

Example

$ cd device-client
$ source gwe.build && gwe_build
Creating __build_id__: device-client.v1_f97dd97
a exo
a exo/__build_id__.py
a exo/__init__.py
a exo/api.py
a exo/constants.py
a exo/device.py
a exo/handlers.py
a exo/ifaces.py
a README.md
a requirements.txt
a setup.py
/Users/willcharlton/sandbox/GatewayEngine/device-client/device-client.v1_f97dd97.tar.gz

The resultant tarball is installable with the Gateway Engine OTAU feature. This is the same process that creates the production version of device-client that Gateway Engine installs and utilizes.

Installation

Currently, installing the device-client library is only supported via a Gateway Engine release tarball.

First, download a release tarball, then use the following commands to install the device-client library and gain access to gdc and Python imports.

Commands

tar zxvf GatewayEngine.v*.tar.gz
cd gateway-engine
python setup.py gdc

Another way to install it (not-recommended), is to unpack the device-client library in the Gateway Engine release tarball manually and install with python setup.py install.

Release Notes

Notes on current and past releases of device-client.
Release Notes  
1.4.26 Fixed bug in exo.api.ExositeAPI.http_record where alias=<dataport> strings appeared in <dataport> when multiple datapoints were recorded.  
1.4.25 Added missing otau.py script which broke OTAUs. Added gdc.cfg config file to /opt/exosite.  
1.4.24 Fixed issue that raw data was appearing in the /tmp/ifaces.db audit records.  
1.4.23 Added HTTP Record API ‘conflict’ handling and test coverage to exo.handlers.RecordHandler.  
1.4.22 Added support for Python requests.Sessions for better bandwidth usage on gateways.  
1.4.20 Now passing requests.request.response object through exo.handlers.Requests_Response objects.  
1.4.19 Better conflict handling in gdc.cfg, README and other docs updates. Updated http_record function.  
1.4.18 Obfuscate CIKs in logging. Refactored CLI for docopt support. Added form_encode flag to ExositeAPI object constructor for gmq support. Fixed and updated some tests.  
1.4.17 Added unit tests. Introduce gdc.cfg config file. Docs updates.  

Documentation

The documentation for device-client can built with the Sphinx Documentation tool. The Makefile has been modified to include the creation of a single PDF.

To create the docs, simply run:

Commands

cd device-client
mkvirtualenv device-client-sphinx
python setup.py install
pip install -r requirements-docs.txt
make html

To create a PDF file of all of the documentation, simply run:

Commands

make singlepdf

Test Coverage

There are a number of unit tests that are executed when features are added and bugs are fixed. These tests are made with the Python unittest framework and executed against Python 2.7.9 in a Jenkins CI environment. Tests marked as “system test” require specific credentialed environments.

In addition to the tests in this repository, there is additional test coverage of this library available in the dqa-gwe project which is a Docker environment powered by Robotframework that, in addition to having automated tests, provides instant access to a full Gateway Engine run-time environment.

Test Coverage Summary

Device() Testing

  • CIK management in config file and instance state.
  • Various configuration file sections/options support.
  • Configuration file support for product_domain.
  • Custom hostname support (i.e. Pixie, GMQ).
  • Default hostname.
  • No configuration file.
  • Incorrect sections in configuration file.
  • Usage of http_record API (system test).
  • Usage of http_read API (system test).
  • Activation status variations.
  • Device activation.
  • Response handlers.

ExositeAPI() Testing

  • Custom authorization header.
  • Add Arbitrary custom headers.
  • Guard http_read against improper inputs (regression test).
  • Usage of http_write API (system test).
  • Hostname support of product_domain constructor parameter.
  • Default http timeout.

Interfaces() Testing

  • Basic request logging.
  • Basic reporting.
  • Custom interfaces support.
  • Default interfaces.

Python Package Documentation

Submodules

exo.api module

This module contains all HTTP Device API and HTTP Provision Management methods for IoT gatewayss.

class exo.api.ExositeAPI(**kwargs)[source]

Bases: exo.ifaces.Interfaces, object

Instances of the ExositeAPI class contain all methods and members needed to interface with the Exosite HTTP Data API. ExositeAPI objects are very versatile and are used in a multitude of Gateway Engine components like gwe and gmq. It is also the base-class for the Device class which is a INI-style configuration file based class.

__init__(**kwargs)[source]
Parameters:
  • vendor (string) – Specify the One Platform VENDOR name or the Murano PRODUCT.ID.
  • model (string) – Specify the One Platform MODEL name or the Murano PRODUCT.ID.
  • uuid (string) – Specify the serial number.
  • user_agent (string) – Specify a value for a custom User-Agent HTTP header (default: Device-Client-V<M>.<m>.<B>).
  • cik (string) – Specify a cik.
  • host (string) – Optionally specifying a host directs all requests to a host other than m2.exosite.io. Use this parameter to direct API calls to an Exosite Edge server. (i.e. 192.168.11.146:1987).
  • use_ssl (bool) – When False, takes the ‘s’ out of https.
  • no_product_domain (bool) – By default, API calls are directed to <vendor>.m2.exosite.io. Setting this parameter to True will direct API calls to m2.exosite.io, bypassing the VENDOR (1P) or PRODUCT.ID (Murano) domain.
  • custom_auth (dict) – Using this parameter uses the dict.update() method to replace the standard X-Exosite-CIK HTTP header. Use this parameter to provide the X-Exosite-VMS as well as any other headers.
  • ifaces_cfg_path (string) – Full path to optional Interfaces class configuration file (i.e. /path/to/gdc.cfg).
  • form_encode (bool) – Optionally disable form-encoding POST data.
  • tls_provision – If provided, ExositeAPI instances will use this configuration dictionary to force the use of Advanced Device Connectivity TLS Provisioning.
  • tls_provision.certfile – Filesystem path to your certfile.
  • tls_provision.keyfile – Filesystem path to your keyfile.
  • tls_provision.reprovision_certfile – Filesystem path to the certfile you plan to reprovision with.
  • tls_provision.reprovision_keyfile – Filesystem path to the keyfile you plan to reprovision with.
__str__()[source]

So we can print self representation by calling str(self).

_activate()[source]

Instead of over-riding http_activate(), here is logic to deal with activating self.

_http_activate()[source]

Method to activate device. Returns ActivationHandler() object.

_http_getContent(content_id)[source]

Method to retrieve specific content from Content area.

_http_getContentInfo(content_id)[source]

Method to retrieve information on Content area content.

_http_listContent()[source]

Method for retrieving a list of Content area contents.

_http_long_poll(dataport, timeout_ms, modify_ts=None)[source]

readList: List of data sources to read from

_http_read(readList, stream=None)[source]

readList: List of data sources to read from

_http_readwrite(readList, writeDict)[source]

readList: List of data source to read from writeDict: Dictionary of k,v to write to. (Do not url encode)

_http_record(recordDict)[source]

Method to record to a device dataport.

The POST data must look like the following:

alias=<alias 1>&<timestamp 1>=<value 1>&<timestamp 2>=<value 2>&alias=<alias 2>&<timestamp 3>=<value 3>&<timestamp 4>=<value 4>

Since this can’t be easily decoded with a Python dictionary, the schema for the input dictionary must be as follows:

{‘alias1’: {‘ts1’: ‘some data’, ‘ts2’: ‘some more data’}, ‘alias2’: {‘ts2’: ‘data data data’, ‘ts3’: ‘datum dateo’‘}}
_http_regen(vendor_token)[source]

Method to regenerate CIK for a given device, deactivate client, and open 24 hour window for device to call activate.

This method is really only here for testing and development purposes because we NEVER ship a unit with the Vendor Token.

_http_write(body)[source]

Method to write to a device dataport.

_http_write_dict(writeDict)[source]

Wrapper function for http_write. url_encodes a python dictionary and calls http_write. Cannot handle nested dicts.

_set_activated(val)[source]

Protected member setter.

_set_activation_retry_interval(interval)[source]

Protected member setter.

_set_host(host)[source]

Protected member setter.

_set_model(model)[source]

Protected member setter.

_set_no_product_domain(boolean)[source]

Protected member setter.

_set_timeout_secs(timeout)[source]

Protected member setter.

_set_uuid(uuid)[source]

Protected member setter.

_set_vendor(vendor)[source]

Protected member setter.

activated()[source]

Returns protected self._activated boolean used to track activation status.

activation_retry_interval()[source]

The self._activation_retry_interval member is used to throttle the frequency of activation attempts an ExositeAPI instance will attempt to activate. This can be overridden after the instance is created.

cik()[source]

returns self._cik

exosite_timestamp()[source]

Gets the exosite server timestamp from m2.exosite.io/timestamp.

Returns:
Timestamp as int.
form_encode()[source]

Turns on the usage of SSL in HTTP API.

host()[source]

returns self._host

self._base_url is stored as the url parameter used in Device() constructor.

http_read(readList, stream=None)[source]

Member function that utilizes ReadHandler().

http_read_write(readList, writeDict)[source]

Member function that utilizes ReadWriteHandler().

http_record(record_dict, back_compat=None)[source]

Member function that returns WriteHandler().

http_write(dataport, value)[source]

Member function that returns WriteHandler().

http_write_multiple(write_dict)[source]

Member function that returns WriteHandler().

model()[source]

returns self._model

no_form_encode()[source]

Turns off the usage of SSL in HTTP API.

no_product_domain()[source]

returns self._no_product_domain

This boolean determines whether or not the PRODUCT_ID exists in the host of the url for API calls to Exosite.

no_ssl()[source]

Turns off the usage of SSL in HTTP API.

send_get(url, headers, req_info, stream=None, timeout=None)[source]

Method wrapper for requests.get(). Input req_info: a tuple describing the type of request. Used for data usage logging and statistics collection.

send_post(url, headers, body, req_info)[source]

Method wrapper for requests.post(). Input req_info: a tuple describing the type of request. Used for data usage logging and statistics collection.

set_http_debug(enable)[source]

Sets httplib debug level when ‘enable’ is set to True.

timeout()[source]

returns self._TIMEOUT_SECS

udp_write(write_dict)[source]

Only use this function if Implementation of the soon-to-be-deprecated udp API.

Input: a dictionary. Keys are the dataport names and the value
are the values to write to the given dataport.
Example:
D = exo.device.Device(‘A-User-Agent’, ‘/path/to/cfg.file’) D.udp_write( { ‘my_dataport’: json.dumps(some_data_i_need) } )
url_decode(obj)[source]

Helper function to urllib.url_decode objects read from dataports.

use_ssl()[source]

Turns on the usage of SSL in HTTP API.

uuid()[source]

returns self._uuid

vendor()[source]

returns self._vendor

exo.constants module

Defines some constants, such as logging formatter, for use across all modules.

exo.device module

Module containing Exosite and HTTP classes, variables, and methods for use in APtivator applications.

class exo.device.Device(user_agent, cfg_file)[source]

Bases: exo.api.ExositeAPI, object

The Device class is a wrapper class around the ExositeAPI. Objects of this class need a INI configuration file with a [device] section that contains, at minimum, four options

  • cik
  • model
  • vendor
  • uuid

These options must be populated with valid values except for the ‘cik’ option. This is populated by the Device() object after a successful activation call.

Other options are supported, but are not required:

  • activation_retry_interval
  • host
  • no_product_domain
  • http_timeout
__init__(user_agent, cfg_file)[source]
Parameters:
  • vendor (string) – Specify the One Platform VENDOR name or the Murano PRODUCT.ID.
  • model (string) – Specify the One Platform MODEL name or the Murano PRODUCT.ID.
  • uuid (string) – Specify the serial number.
  • user_agent (string) – Specify a value for a custom User-Agent HTTP header (default: Device-Client-V<M>.<m>.<B>).
  • cik (string) – Specify a cik.
  • host (string) – Optionally specifying a host directs all requests to a host other than m2.exosite.io. Use this parameter to direct API calls to an Exosite Edge server. (i.e. 192.168.11.146:1987).
  • use_ssl (bool) – When False, takes the ‘s’ out of https.
  • no_product_domain (bool) – By default, API calls are directed to <vendor>.m2.exosite.io. Setting this parameter to True will direct API calls to m2.exosite.io, bypassing the VENDOR (1P) or PRODUCT.ID (Murano) domain.
  • custom_auth (dict) – Using this parameter uses the dict.update() method to replace the standard X-Exosite-CIK HTTP header. Use this parameter to provide the X-Exosite-VMS as well as any other headers.
  • ifaces_cfg_path (string) – Full path to optional Interfaces class configuration file (i.e. /path/to/gdc.cfg).
  • form_encode (bool) – Optionally disable form-encoding POST data.
  • tls_provision – If provided, ExositeAPI instances will use this configuration dictionary to force the use of Advanced Device Connectivity TLS Provisioning.
  • tls_provision.certfile – Filesystem path to your certfile.
  • tls_provision.keyfile – Filesystem path to your keyfile.
  • tls_provision.reprovision_certfile – Filesystem path to the certfile you plan to reprovision with.
  • tls_provision.reprovision_keyfile – Filesystem path to the keyfile you plan to reprovision with.
cfg_file()[source]

Protected member getter.

dump_to_device_cfg(section, option, value)[source]

Utility to dump configuration data to the instance cfg file.

get_config_from_cfg_file()[source]

Reads INI config files and converts them to a dictionary.

set_activation_retry_interval(interval)[source]

Protected member setter.

set_cik(cik)[source]

Protected member setter. Sets instance member and cfg file.

set_host(host)[source]

Protected member setter.

set_model(model)[source]

Protected member setter. Sets instance member and cfg file.

set_uuid(uuid)[source]

Protected member setter. Sets instance member and cfg file.

set_vendor(vendor)[source]

Protected member setter. Sets instance member and cfg file.

update_device_from_cfg()[source]

Updates Device instance with values from cfg.

class exo.device.DeviceCfgOpt[source]

This is an ‘enum’ class for defining supported Device class configuration file options.

ActRtryInt = 'activation_retry_interval'

Optional for Device class, time (seconds) between retries of activation calls for objects of parent class ExositeAPI.

Cik = 'cik'

Required for Device class, an Exosite CIK. Can be empty string (i.e. ‘’).

HTTPTimeout = 'http_timeout'

Optional for Device class, specify a non-default HTTP timeout for requests.

Host = 'host'

Optional for Device class, the optional host name for API calls for objects of parent class ExositeAPI.

Model = 'model'

Required for Device class, either the MODEL (1P) or the PRODUCT.ID (Murano).

NoFormEncode = 'no_form_encode'

Don’t form encode POST data.

NoProductDomain = 'no_product_domain'

Optional for Device class, if present in config file, API calls will bypass optional VENDOR (1P) or PRODUCT.ID (Murano) in the hostname, using m2.exosite.io as the full hostname.

NoSSL = 'use_ssl'

Do not use SSL/TLS in HTTP.

Uuid = 'uuid'

Required for Device class, the serial number. Can be empty string (i.e. ‘’).

Vendor = 'vendor'

Required for Device class, either the VENDOR (1P) or the PRODUCT.ID (Murano).

class exo.device.DeviceCfgSect[source]

Enum for cfg file sections.

Device = 'device'

The main section for a Device() object parameters.

exception exo.device.ExoDeviceException(message)[source]

Bases: exceptions.Exception

Custom exception class for validating user input and improper usage of ExoTLS class.

__init__(message)[source]

x.__init__(…) initializes x; see help(type(x)) for signature

__weakref__

list of weak references to the object (if defined)

exo.gdc module

Example

Gateway Device Client (GDC) Command-Line interface.

GDC is a light-weight cli for common tasks using the device-client library.

Usage:
  gdc [-h|-v|-p|-c]
  gdc cfg get [<section> <option> -f <file>]
  gdc cfg set <section> [<option> <value> -f <file> -U]
  gdc [-d <lvl> -t <secs> -H <host>] timestamp (-i <id> | -f <file>) [-C <cert> -K <pkey>]
  gdc [-N -F -P -i <id> -d <lvl> -t <secs> -H <host>]  activate  (<pid> <uuid> | -f <file> | -C <cert> -K <pkey>)
  gdc [-N -F -P -i <id> -d <lvl> -t <secs> -H <host>]  read      (-f <file> | -C <cert> -K <pkey> | <cik>) <alias> [<alias>]...
  gdc [-N -F -P -i <id> -d <lvl> -t <secs> -H <host>]  poll      (-f <file> | -C <cert> -K <pkey> | <cik>) <alias> <request-timeout> [<if-modified-since>]
  gdc [-N -F -P -i <id> -d <lvl> -t <secs> -H <host>]  write     (-f <file> | -C <cert> -K <pkey> | <cik>) <alias> <data> [<alias> <data>]...
  gdc [-N -F -P -i <id> -d <lvl> -t <secs> -H <host>]  record    (-f <file> | -C <cert> -K <pkey> | <cik>) <timestamp> <alias> <data>

Commands:
    cfg             Interface for viewing and modifying gdc configuration settings.
    timestamp       Get the Murano timestamp.
    activate        Use the HTTP Device API to activate client described by Product
                    and Device IDs. Prints the CIK to STDOUT if successful. If -f
                    option is used, the Device config file is used.
    read            Read resource described by <alias>.
    poll            Long poll <alias> for <request-timeout> since <if-modified-since>.
    write           Write <value> to <alias> resource.
    record          Record <value> to <alias> at time <timestamp>.

Info Options:
    -h --help                   Show this screen.
    -v --version                Print the current version of device-client.
    -p --path                   Print the installation path to the device-client python package.
    -c --cfg-file               Print the path to the gdc configuration file.

API Options:
    -N --no-ssl                 If provided, SSL/TLS will not be used in HTTP(S) comms.
    -F --no-form-encode         If provided, POST data will not be form-encoded.
    -P --no-product-domain      If provided, project domains (i.e. your project ID).
    -i --pid <id>               The Project/Product ID.
    -t --timeout <secs>         If provided, <secs> is used as HTTP Timeout (in seconds).
    -H --host <host>            If provided, <host> is used as the server hostname for HTTP requests.
    -d --debug <lvl>            Turn on verbose debug output. Also logs curl commands.

Auth Options:
    -f --file <file>            All operations will use <file> as the Device state file. This file
                                is compatible with Device class objects. Will store <cik> and
                                provision as the Murano client described in its options. This
                                option has special support for configuring the GWE config file
                                by using 'gwe' as the <file> argument.
    <cik>                       A CIK (Client Interface Key).
    -C --cert <cert>            Use <cert> for Murano Provisioning of client described in
                                the certificate subject.
    -K --pkey <pkey>            Use <pkey> in TLS communication with Murano.

Config Options:
    -U --unset                  If provided, remove this section or option.

Arguments:
    <id>                        A Murano Project ID.
    <secs>                      Set the HTTP timeout in seconds of your request.
    <host>                      The Exosite server the HTTP Device API calls will be
                                directed to.
    <section>                   An INI file section.
    <option>                    An INI section option.
    <value>                     An INI option value.
    <file>                      Path to a Device() class INI-style configuration file.
    <cert>                      Path to an X509 certificate.
    <pkey>                      Path to an X509 private key.
    <alias>                     A Murano Product resource.
    <data>                      The data to write or record.
    <request-timeout>           The amount of time, in milliseconds, to long-poll on <alias>.
    <if-modified-since>         The timestamp (unix epoch) from which to check for new data on <alias>.

exo.handlers module

Container module for HTTP and other API handler classes.

class exo.handlers.ActivationHandler(http_response)[source]

Bases: object

Class to handle Device() activations.

Input: Requests_Response() object generated from Exosite Activation Request.

Object contains ‘code’, ‘body’, and ‘activated’ member variables.

  • If successfully Activated, member variables will contain:
    • code = 200
    • body = ‘<cik>’
    • activated = True
  • If successfully Activated, but got a bad cik, member variables will contain:
    • code = 200
    • body = ‘<bad cik>’
    • activated = False
  • Otherwise:
    • code = <http response code>
    • body = ‘an informative message’
    • activated = False

Example usage:

act_resp = exo.handlers.ActivationHandler(
    exo.Exo().exosite_activate(
        uuid,
        vendor,
        msg.model
    )
)

# determine whether or not provisioning/activation worked
if(act_resp.activated):
    my_cik = act_resp.body
else:
    print("Activation attempt FAILED: {!r}".format(act_resp.body))
__init__(http_response)[source]
Parameters:http_response (Requests_Response) – The response object that the handler intends to parse/process.
__repr__() <==> repr(x)[source]
__weakref__

list of weak references to the object (if defined)

class exo.handlers.Http_ActivationCodes[source]

Enum class for http response codes from Activation attempts.

Referenced on 04/16/2015

HTTP/1.1 200 OK
Date: <date>
Server: <server>
Connection: Keep-Alive
Content-Length: <length>
Content-Type: text/plain; charset=utf-8

On success, the response is the CIK.

Response may also be:

  • HTTP/1.1 404 Not Found if the client described by <vendor>, <model>, <sn> is not found on the system.
  • HTTP/1.1 409 Conflict if the serial number is not enabled for activation.

See HTTP Responses for a full list of responses

class exo.handlers.Http_ReadWriteCodes[source]

Enum class for http response codes from dataport Read, Write and ReadWrite attempts.

Copied from docs.exosite.com/data/#http 04/16/2015

Typical HTTP response codes include: Code Response Description 200 OK Successful request, returning requested values 204 No Content Successful request, nothing will be returned 4xx Client Error There was an error* with the request by the client 401 Unauthorized No or invalid CIK 5xx Server Error There way an error with the request on the server

  • Note: aliases that are not found are not considered errors in the request.

See the documentation for read, and write and Hybrid write/read for details.

class exo.handlers.Http_Response(responseCode, responseBody)[source]

Container class for http responses.

__init__(responseCode, responseBody)[source]
Parameters:
  • responseCode (int) – An HTTP server response code.
  • responseBody (string) – The body of the server response.
class exo.handlers.ReadHandler(http_response)[source]

Bases: object

Hard-wired to urllib.unquote(url).decode(‘utf-8’) all responses.

__init__(http_response)[source]

x.__init__(…) initializes x; see help(type(x)) for signature

__repr__() <==> repr(x)[source]
__weakref__

list of weak references to the object (if defined)

class exo.handlers.ReadWriteHandler(http_response)[source]

Bases: object

Hard-wired to urllib.unquote(url).decode(‘utf-8’) all responses.

__init__(http_response)[source]

x.__init__(…) initializes x; see help(type(x)) for signature

__repr__() <==> repr(x)[source]
__weakref__

list of weak references to the object (if defined)

class exo.handlers.RecordHandler(http_response)[source]

Bases: object

TODO

__init__(http_response)[source]

x.__init__(…) initializes x; see help(type(x)) for signature

__repr__() <==> repr(x)[source]
__weakref__

list of weak references to the object (if defined)

get_conflict_timestamps()[source]

Returns a list of timestamps that were marked as conflicting by Exosite from the body of the response.

class exo.handlers.Requests_Response(response)[source]

Container class for requests responses.

__init__(response)[source]
Parameters:response (<class 'requests.models.Response'>) – A Python requests response object.
class exo.handlers.WriteHandler(http_response)[source]

Bases: object

TODO

__init__(http_response)[source]

x.__init__(…) initializes x; see help(type(x)) for signature

__repr__() <==> repr(x)[source]
__weakref__

list of weak references to the object (if defined)

exo.ifaces module

Module for Interface() class. Revised by Prakash S on 7/5/2016 to incorporate sqlite database logging instead of flat file.

class exo.ifaces.ILC[source]

Enum class for specifying the meaning of each column in the ifaces log file. ILC stands for Ifaces Log Columns.

class exo.ifaces.Interfaces(cfg_path=None)[source]

Bases: object

The interfaces log is meant to capture all requests during the runtime of the OS. If a reboot occurs, the database is cleared due to the fact that it is located in /tmp, which is typically a tmpfs.

The Interfaces class has the following configuration options. All options should be defined in constants.IFACES_CFG_FILE_PATH, section ‘gdc’

  • ifaces: a comma-separated list of interfaces

    you want to reports for.

Example:
# /opt/exosite/gdc/gdc.cfg [gdc] ifaces = eth0,wlan0
LOG_request(cik, rq_type, req_source, before_request, after_request)[source]

TODO

__init__(cfg_path=None)[source]

x.__init__(…) initializes x; see help(type(x)) for signature

__weakref__

list of weak references to the object (if defined)

interface_report()[source]

Prepares report of network bandwidth consumed by every CIK and find the top comsumer among them.

interfaces()[source]

Parses self.proc_net_dev file to determine the amount of rx and tx bytes for the current time.

throttle_check()[source]

Read the ifaces log file and determine whether or not a given device needs to be denied access to making internet calls.

Returns a list of ciks that qualify for throttling.

Module contents

To view the source code, go to the github site.