Cisco IOx
How to use this page
Please read the instructions on this page in the order they are presented. A section may depend on a section before it and we will refrain from repeating information.
Prerequisites
It is assumed that you are familiar with Cisco IOx and have an IOx device, such as one of the 800 series devices, configured and ready.
You will also need to have gained access to a package which contains a distribution of the LoRaWAN Network Server of xDP.
Installing xDP
Overview
Installing xDP consists of the following major activities:
- Install
streambed-cli
. - Create Docker images by using
streambed install
. - Load
lora-server
into Docker. - Package/install/activate/start
jsaas
. - Package/install/activate/configure/start
fdp
. - Provision an initial user identity.
- Configure Network
- Provision an admin user
- Provision Control Center secrets
streambed-cli
is a suite of command line tools that communicate with xDP’s services, including control-center
and streambed-mqtt-gateway
, and can produce Docker images for xDP services. The tools are intended for use alongside the Cisco ioxclient
tools.
jsaas
is a service that xDP uses to evaluate custom JavaScript programs.
fdp
bundles all of the JVM-based xDP services into a single package for deployment to IOx. This consists of the following services:
streambed-durable-queue-server
is an application that persists and streams sensor and platform data using the MQTT protocol.lora-server
is xDP’s application that provides a LoRaWAN Network Server, soil moisture/temperature services (including a web app for observing sensors), sensor registration services (including a web app for provisioning) and an MQTT gateway for integration with Kinetic DCM.control-center
is a web application that serves as the primary interface for xDP. With it, you can visualize sensor data, create custom transformers and dashboards, and provision provision LoRaWAN sensors. The application can be interacted with either using thestreambed-cli
or via a web user interface.streambed-mqtt-gateway
enables xDP to send sensor data to and receive sensor data from Cisco Kinetic DCM. From DCM, data can be routed anywhere a customer desires, and vice-versa.fdp-soilstate-ui
is an optional reference web application that visualizes soil moisture/temperature observations. It also contains a transformer service that transforms LoRaWAN packets from soil moisture/temperature sensors into a domain representation.
1. streambed-cli
Note that if you’ve been through the getting started experience then you can skip this section as you’ve already installed the command line tools.
Please select the type of installation and follow the instructions.
- Debian/Ubuntu
-
# Setup Repository wget -qO - https://repositories.streambed.io/public.key | \ sudo apt-key add - && \ echo "deb [arch=amd64] https://repositories.streambed.io/apt/streambed stable main" | \ sudo tee /etc/apt/sources.list.d/streambed.list && \ sudo apt-get install apt-transport-https -y && \ sudo apt-get update # Install the streambed-cli sudo apt-get && sudo apt-get install streambed-cli
- RedHat/CentOS/Fedora
-
# Setup Repository sudo tee /etc/yum.repos.d/streambed.repo << EOT [streambed] name=streambed baseurl=https://repositories.streambed.io/yum gpgcheck=0 enabled=1 EOT # Install the streambed-cli sudo yum install streambed-cli
- macOS
-
# Setup Repository brew tap streambed/repository https://github.com/streambed/homebrew-repository # Install the streambed-cli (use `brew upgrade` if installed) brew install streambed/repository/streambed-cli
- Windows
-
Download the latest win-<arch>.zip file and extract it to a directory on your PATH. You can find the files here: https://repositories.streambed.io/packages/streambed-cli/
Two commands in particular are now at your disposal: streambed
and lora
. We’ll use these shortly.
2. Create Docker images
To download the latest application images, run the following command:
streambed install
This will ensure that the latest images have been pulled down and tagged with the appropriate tag.
Setup secrets
When packaging IOx applications, you must sign them with an application key. Refer to the Cisco documentation for how to set up app keys and trust certs.
This steps declares some environment variables that will be used to locate various keys and their certificates for signing your applications. Substitute the two /path-to
references with the actual path on your local system.
export APP_KEY_PATH=/path-to/app-key.pem
export APP_CERT_PATH=/path-to/app-cert.pem
An X.509 certificate used to configure an SSL connection for the Local Manager must be made available to each application that needs to communicate with various IOx services, such as the Secure Storage Service. The X.509 certificate must be in PEM format, have the name caf_cert.pem
and caf_key.pem
, and be signed for the following:
- localhost
- 192.168.1.2
- 192.168.1.3
- 192.168.1.4
- 192.168.1.253
- 192.168.1.254
The following commands will set the variables required by the rest of the guide. Be sure to substitute the /path-to
reference with the actual path on your local system.
export CAF_CERT_PATH=/path-to/caf_cert.pem
export CAF_KEY_PATH=/path-to/caf_key.pem
3. Load lora-server
lora-server
is provided as a separate download. Once acquired, you’ll need to load it into Docker. Be sure to substitute /path-to/lora-server.tar
with the actual path of the file on the system.
docker load < /path-to/lora-server.tar.gz
Tag the docker image with latest
for easy usage:
docker tag lora-server-iox-sss:<IMAGE-TAG> streambed-cli/amd64/lora-server-iox-sss:latest
4. Install JSaaS
JSaaS (jsaas
) is used to evaluate dynamically provisioned applications.
Packaging for IOx for JSaaS
First, change your current directory into its packaging directory:
mkdir -p ~/.streambed/cli/install/amd64/jsaas && cd ~/.streambed/cli/install/amd64/jsaas
Then, use streambed package
prepare a Docker image:
streambed package --name jsaas --base-image linux \
--label cisco.resources.profile=custom \
--label cisco.resources.cpu=100 \
--label cisco.resources.memory=64 \
--label cisco.resources.network.0.interface-name=eth0 \
--label cisco.resources.network.0.ports.tcp=[9880] \
--label cisco.env.JSAAS_TLS_PUBLIC_CERTIFICATE_PATH=/data/appdata/caf_cert.pem \
--label cisco.env.JSAAS_TLS_PRIVATE_KEY_PATH=/data/appdata/caf_key.pem \
--label cisco.env.JSAAS_BIND_ADDR=0.0.0.0:9880 \
--image streambed-cli/amd64/jsaas:latest
Then, use ioxclient
to create and install the package:
rm -f package.yaml && ioxclient docker package \
--rsa-key "$APP_KEY_PATH" \
--certificate "$APP_CERT_PATH" \
streambed-cli/amd64/jsaas:latest .
ioxclient app install jsaas package.tar
Activation for JSaaS
You’ll need to create an activation.json
file that configures the application so that it can be reached from other services:
cat > activation.json <<EOF
{
"resources": {
"network": [
{
"interface-name": "eth0",
"ipv4": {
"default": true,
"dns": "8.8.8.8",
"gateway": "192.168.1.1",
"ip": "192.168.1.253",
"prefix": "24"
},
"mode": "static",
"network-name": "iox-bridge0"
}
]
}
}
EOF
ioxclient app activate jsaas --payload activation.json
Install the IOx X.509 certificate for JSaaS
Install the certificates so that the application can communicate with IOx services over TLS.
ioxclient app appdata upload jsaas "$CAF_CERT_PATH" caf_cert.pem
Install the corresponding IOx X.509 key for JSaaS
The private key to the X.509 certificate used must thereby be provided:
ioxclient app appdata upload jsaas "$CAF_KEY_PATH" caf_key.pem
Start JSaaS
The service is now configured and ready to start. To start it:
ioxclient app start jsaas
5. Install xDP
xDP is installed as a single package on IOx that contains a number of services.
Packaging for IOx
First, change your current directory into its packaging directory:
mkdir -p ~/.streambed/cli/install/amd64/fdp && cd ~/.streambed/cli/install/amd64/fdp
Next, declare some environment variables pertaining to the site’s network and credentials. Be sure to substitute in the site’s id, username, and password.
export NETID=00000013
export CLOUD_SITE_ID=demo
export CLOUD_USERNAME=myclouduser
export CLOUD_PASSWORD=mycloudpassword
Note that
00000013
is as used by The Things Network. Yours may be different.
…then package xDP using its Docker image:
The following command bundles all services into an xDP package. If there are any other services that need to be installed, be sure to specify them with additional
--image
flags. In particular, note the xDP Soilstate UI section at the end of this document.
streambed package --name fdp --base-image linux-java \
--label cisco.resources.profile=custom \
--label cisco.resources.cpu=500 \
--label cisco.resources.memory=512 \
--label cisco.resources.network.0.interface-name=eth0 \
--label cisco.resources.network.0.ports.tcp=[5732,9870,9871,9872,9873,9874,9875,9876,9877,9878,9879] \
--label cisco.resources.network.0.ports.udp=[1690,1692] \
--label "cisco.resources.visualization=\"'true'\"" \
--label cisco.resources.devices.0.type=usbdev \
--label cisco.resources.devices.0.label=EXTERNAL_STORAGE \
--label cisco.resources.devices.0.function=storage \
--label "cisco.resources.devices.0.mandatory=\"'true'\"" \
--label cisco.resources.devices.0.mount-point=/external-storage \
--label cisco.env.FORCE_ROOT=1 \
--label cisco.env.FORCE_SSS_STUB=1 \
--label "cisco.env.JAVA_OPTS=\"'-Dstreambed.durable-queue.remote.client.host=127.0.0.1'\"" \
--image streambed-cli/amd64/streambed-durable-queue-server:latest \
--property streambed.durable-queue.remote.server.tcp.tls.bind.enabled=true \
--image streambed-cli/amd64/iox-sss-stub-server:latest \
--property streambed.http-server.tls.bind.enabled=true \
--readiness-check tcp://localhost:9878 \
--image streambed-cli/amd64/control-center-iox-sss:latest \
--property streambed.http-server.bind.host=0.0.0.0 \
--property streambed.http-server.bind.port=9871 \
--property streambed.http-server.tls.bind.enabled=on \
--property streambed.http-server.tls.bind.host=0.0.0.0 \
--property streambed.http-server.tls.bind.port=9870 \
--property control-center.jsaas.scheme=https \
--property control-center.jsaas.host=192.168.1.253 \
--property control-center.jsaas.port=9880 \
--property control-center.cloud-provisioner.credentials.host="https://$CLOUD_SITE_ID.titanclass.com.au:9870" \
--property control-center.cloud-provisioner.credentials.username="$CLOUD_USERNAME" \
--property control-center.cloud-provisioner.credentials.password="$CLOUD_PASSWORD" \
--property control-center.replicator.enabled=on \
--property control-center.replicator.scheme="https" \
--property control-center.replicator.host="xdp.titanclass.com.au" \
--property control-center.replicator.port=443 \
--property control-center.replicator.namespace="$CLOUD_SITE_ID" \
--property control-center.replicator.credentials.username="$CLOUD_USERNAME" \
--property control-center.replicator.credentials.password="$CLOUD_PASSWORD" \
--property akka.http.server.default-host-header="$CLOUD_SITE_ID" \
--readiness-check tcp://localhost:9876 \
--image streambed-cli/amd64/lora-server-iox-sss:latest \
--property lora-server.downlink.bind-host=0.0.0.0 \
--property lora-server.downlink.bind-port=1692 \
--property lora-server.uplink.bind-host=0.0.0.0 \
--property lora-server.uplink.bind-port=1690 \
--property "lora-server.netID=$NETID" \
--readiness-check tcp://localhost:9870
The streambed package
command above ensures that the image is entirely suitable for IOx by including an operating system (Alpine) and a JVM.
Finally, use ioxclient
to create and install the package:
rm -f package.yaml && ioxclient docker package \
--rsa-key "$APP_KEY_PATH" \
--certificate "$APP_CERT_PATH" \
streambed-cli/amd64/fdp:latest .
ioxclient app install fdp package.tar
If you run out of storage space on your IOx device then be sure to use the
ioxclient layer delete
command to remove all unused layers.
Activation
xDP requires external USB storage for its data so that the limited space of the internal flash file systems of IOx devices does not become full. Additionally, it requires binding to a specific IP so that its lora-server component can be discovered.
A single partition, FAT32 formatted USB device needs to be inserted into a port provided by the IOx device, and then its device details need to be located. Ensure that the USB device is plugged in. You can check for its availability using the following command:
ioxclient platform device list
Look for an entry similar to the following:
"usbdev": [
{
"available": true,
"bus": "1",
"dev": "5",
"device_class": "00\n",
"device_id": "/dev/bus/usb/001/005",
"device_name": "/dev/sdc1",
"device_path": "/sys/devices/pci0000:00/0000:00:09.0/usb1/1-1",
"generic_params": null,
"is_generic": false,
"is_storage": true,
"pid": "04a1",
"port": null,
"storage_params": {
"device_name": "/dev/sdc1",
"fstype": "vfat",
"model": "Nano",
"mount_point": "/mnt/host/usbstorage/sdc1",
"vendor": "Imation"
},
"support_fstype": [
"vfat"
],
"type": "usbdev",
"used_by": "streambeddurablequeueserver",
"vid": "0718"
}
]
In particular, you should note the device_id
, device_name
, pid
and vid
fields, and substitute them in a file named activation.json
as follows:
Note that the following assumes that IOx is running on the
192.168.1.0/24
subnet. If your IOx subnet is different then please subsitute it accordingly.
{
"resources": {
"devices": [
{
"type": "usbdev",
"label": "EXTERNAL_STORAGE",
"device-id": "/dev/bus/usb/001/002",
"device-name": "/dev/sdc1",
"vid": "0718",
"pid": "04a1"
}
],
"network": [
{
"interface-name": "eth0",
"ipv4": {
"default": true,
"dns": "8.8.8.8",
"gateway": "192.168.1.1",
"ip": "192.168.1.254",
"prefix": "24"
},
"mode": "static",
"network-name": "iox-bridge0"
}
]
}
}
Now that we have our activation configuration we can activate xDP:
ioxclient app activate fdp --payload activation.json
Install the IOx X.509 certificate
Install the certificates so that the application can communicate with IOx services over TLS.
ioxclient app appdata upload fdp "$CAF_CERT_PATH" caf_cert.pem
Install the corresponding IOx X.509 key
The private key to the X.509 certificate used must thereby be provided:
ioxclient app appdata upload fdp "$CAF_KEY_PATH" caf_key.pem
Start xDP
xDP is now configured and ready to start. To start it:
ioxclient app start fdp
6. Provision an initial user identity
At this stage there are no users who are able to authenticate with xDP. We must now create one. To do this we login to xDP’s container and create a user by sending a request directly to the IOx Secret Storage Service using its credentials.
We login using ioxclient
:
ioxclient app console fdp
Once logged in, we need to establish the environment variables that belong to the container so we can gain access the IOx Secret Storage Service:
source data/.env
We will need curl:
apk add --no-cache curl
The following commands are documented at DevNet.
Provision a master secret
Our Streambed applications use a proxy secret store to improve the performance of the IOx one, thus only a master secret is kept in the actual IOx Secret Storage Service. We need to set it with the following commands:
Note that if this is an upgrade, and not an installation then you should use the same key as last time, and not generate a new one. If you do not then you will not have access to the data that you had before.
SS_KEY=$(cat /dev/urandom | tr -dc 'A-F0-9' | fold -w 32 | head -n 1)
Note the key produced for performing subsequent upgrades. DO NOT LOSE THIS KEY!!! (use
echo $SS_KEY
to see the key)
curl -v -k \
"$CAF_SS_IP_ADDR:$CAF_SS_PORT/SS/$CAF_APP_ID/Object" \
-H 'Expect:' -H 'content-type:multipart/form-data' \
-F ss-token="$(curl -v -k "$CAF_SS_IP_ADDR:$CAF_SS_PORT/SS/TOKEN/$CAF_APP_ID/$CAF_SYSTEM_UUID")" \
-F object-type=Object \
-F object-name=secrets.iox-sss-stub-events.key \
-F ss-content="$SS_KEY"
You must receive an HTTP/1.1 200 OK
response. If you do not then please ensure that you copied the token and secret correctly. It can be easy to make a mistake.
Provision a temporary user
Next, we need to override the location of the IOx SSS to point to our proxy server:
export CAF_SS_IP_ADDR=localhost
export CAF_SS_PORT=9876
Now, obtain a token:
export SS_TOKEN=$(curl -v -k "$CAF_SS_IP_ADDR:$CAF_SS_PORT/SS/TOKEN/$CAF_APP_ID/$CAF_SYSTEM_UUID")
We now create a user named temp
with an insecure password of password
. We will shortly delete this user once a new one is setup.
curl -v -k \
"$CAF_SS_IP_ADDR:$CAF_SS_PORT/SS/$CAF_APP_ID/Object" \
-H 'Expect:' -H 'content-type:multipart/form-data' \
-F ss-token="$SS_TOKEN" \
-F object-type=Object \
-F object-name=default/secrets.users.temp.password \
-F ss-content=5bc0be4d1aaedb5b513449a59f85da3bd668c1e581d5a8a8129471f1b1b9521692ea588f8a7ec5a7884a7bfbe85875011d0c33d755541f0d2d91e51b08d40687ac02d8391466dac1cdb3a8ff
You must receive an HTTP/1.1 200 OK
response. If you do not then please ensure that you copied the token and secret correctly. It can be easy to make a mistake.
You have now provisioned a user named temp
.
Provision an application secret
Following on from provisioning a primary user, you must now associate a secret with the application. The secret is used to sign any tokens that may be issued and is done to prevent tampering.
export APP_SECRET=$(cat /dev/urandom | tr -dc 'A-F0-9' | fold -w 32 | head -n 1)
curl -v -k \
"$CAF_SS_IP_ADDR:$CAF_SS_PORT/SS/$CAF_APP_ID/Object" \
-H 'Expect:' -H 'content-type:multipart/form-data' \
-F ss-token="$SS_TOKEN" \
-F object-type=Object \
-F object-name=default/streambed.application-secret \
-F ss-content="$APP_SECRET"
Exit out of the console and back to your machine.
7. Configure Network
When configuring IOS, also consider allocating the maximum amount of CPU to IOx.
xDP presents services on TCP ports 9870 to 9879. IOS must be configured to NAT these ports to an interface that will be used to serve it up; typically an interface where the streambed
and lora
commands alongside the ioxclient
may reach it.
Use the
show run
command to show existing configuration
To NAT to the outside world assuming a 192.168.1.0/24
network (using IOS), assuming that the WAN port is assigned to VLAN 600:
config terminal
ip nat inside source static tcp 192.168.1.254 9870 interface vlan 600 9870
ip nat inside source static tcp 192.168.1.254 9871 interface vlan 600 9871
ip nat inside source static tcp 192.168.1.254 9872 interface vlan 600 9872
ip nat inside source static tcp 192.168.1.254 9873 interface vlan 600 9873
ip nat inside source static tcp 192.168.1.254 9874 interface vlan 600 9874
ip nat inside source static tcp 192.168.1.254 9875 interface vlan 600 9875
ip nat inside source static tcp 192.168.1.254 9876 interface vlan 600 9876
ip nat inside source static tcp 192.168.1.254 9877 interface vlan 600 9877
ip nat inside source static tcp 192.168.1.254 9878 interface vlan 600 9878
ip nat inside source static tcp 192.168.1.254 9879 interface vlan 600 9879
end
write mem
Exit IOS by typing exit
.
Additionally, we need to configure a packet forwarder to use the address of the Network Server (NS). The NS binds to two UDP ports which are 1690 and 1692 by default. Given this and that we configured the NS to bind to 192.168.1.254
, you should now able to configure your packet forwarder.
8. Provision an admin user
This step will use the temp
user with the insecure password we created earlier. We will create a new user and then remove the temp
one.
Note that it will take about 5 minutes for xDP to startup on an IR800 series router and similar resource constrained devices. If you experience connectivity issues then it is likely that the application is still starting up. To track the progress of startup, login to the GOS and use
virsh console fdp
to view the application’s output. When ready, you will see that various ports have been bound to.
We first establish an environment for streambed
command line tool communication. For example, if your router is at 10.0.1.75
then the commands will be:
export CONTROL_CENTER_HOST=10.0.1.75
export STREAMBED_MQTT_GATEWAY_HOST=10.0.1.75
Now login as the temp
user with as password of password
:
Note that we use the
--insecure
option as we are using a self-signed certificate.
streambed --insecure login
Supposing your user is cisco
, the following command will prompt you for a password:
streambed --insecure user add cisco
Now that you have that user setup, remove the insecure one we setup earlier.
streambed --insecure user rm temp
9. Provision Control Center secrets
xDP’s Control Center encrypts its transformers and dashboards using secrets that need to be created.
Additionally, the LoRa server needs a key to encrypt its end device data.
First, generate three random secrets:
export END_DEVICES_SECRET="$(LC_CTYPE=C tr -dc 'A-F0-9' < /dev/urandom | fold -w 32 | head -n 1)"
export TRANSFORMERS_SECRET="$(LC_CTYPE=C tr -dc 'A-F0-9' < /dev/urandom | fold -w 32 | head -n 1)"
export DASHBOARDS_SECRET="$(LC_CTYPE=C tr -dc 'A-F0-9' < /dev/urandom | fold -w 32 | head -n 1)"
export LAYERS_SECRET="$(LC_CTYPE=C tr -dc 'A-F0-9' < /dev/urandom | fold -w 32 | head -n 1)"
Then, create the secrets:
streambed --insecure secret add secrets.lora-server.end-devices.key "$END_DEVICES_SECRET"
streambed --insecure secret add secrets.dashboards-events.key "$DASHBOARDS_SECRET"
streambed --insecure secret add secrets.layer-events.key "$LAYERS_SECRET"
streambed --insecure secret add secrets.transformer-program-events.key "$TRANSFORMERS_SECRET"
Other applications - fdp-soilstate-ui (optional)
This application contains both a UI and a transformer for observing soil sensor moisture data.
A transformer is provided for every new type of sensor in the system. Substitute this section for sensors in your system. Soil moisture/temperature is a reference sensor and serves as a useful example. You will typically have more types of sensor and repeat this, and other parts of the remaining document for your sensors. The following assumes that the soilstate transformer has been published to your local Docker repository.
User interface services are required so that sensor data can be visualized. Repeat this section for each user interface to be installed (which is almost the same as installing any other type of service).
Other packaging for IOx
When creating the xDP package for IOx (noted above), you can include the Soilstate UI by adding an --image
flag, for example:
streambed package --name fdp \
<OTHER IMAGES HERE>
--image streambed-cli/amd64/fdp-soilstate-ui:latest --property streambed.http-server.bind.host=0.0.0.0 --property streambed.http-server.bind.port=9871 \
<OTHER FLAGS HERE>