IoT Agent
The IoT Agent enrolls a device with the IoT Identity service and
receives credentials to access the MQTT broker. Via MQTT, it establishes communication with
an IoT Management service, so the device can be remotely monitored and managed over a
secure connection. The state of the device is mirrored in the cloud by the IoT Device Twin service.
The agent is intended to operate on a device running Ubuntu or Ubuntu Core with snapd enabled.
The device management features are implemented using the snapd REST API.
Build
The project uses vendorized dependencies using govendor. Development has been done on minimum Go version 1.12.1.
$ go get github.com/CanonicalLtd/iot-agent
$ cd iot-agent
$ ./get-deps.sh
$ go build ./...
daemons
agent
The agent runs as a simple daemon in the snap. It uses the snap config value nats.snapd.password
to protect
a partially implemented snapd NATS API that closely mirrors the snapd REST API. The details can be found in
the AsyncAPI here.
The NATS configuration currently needs to be setup separately on the server to support this.
required snaps install (agent internal / sub-service)
Internal to the agent process there is a service now that is responsible for receiving commands
from DMS instructing it to install required snaps. This happens on a new topic
tree that is filtered by serial, devices/actions/<sanitized serial>/#
. An example would be
devices/actions/ABC123/required-install
.
The command can be a single snap or an array of snaps.
watchdog
The watchdog service runs and looks for snap changes that have taken too long. The default is one hour. If a
snap change is not completed within 1-hour then the watchdog will create a document with the details of all changes
that are currently known and then reboot the device. The document will be in $SNAP_DATA and will be named
snap_changes_X.json where X is the id of the change that caused the watchdog to reboot the device.
snap change logger
The watchdog daemon includes a sub-service that logs each snap change that is made to the system log. It also logs
each snap change known to the system when it restarts (changes less than 24 hours old, equivalent to snap changes
).
Additionally all known changes over the lifetime of the system are stored in a sqlite database in $SNAP_DATA
.
The maximum number of changes stored here by default is 1000. If that threshold is exceeded older changes will be
removed as newer changes are added.
Configuration keys
Parent key: snaplogger
database.location
- (default: $SNAP_DATA/changes.db
) - location to store the changes database, environment variables expanded
maximum.changes.keep
- (default: 1000
) - the maximum number of changes to store in the database
duration.between.checks
- (default: 1h
) - the duration between checks for new changes to log / store; specified as a Go duration string
log.changes.startup
- (default: true
) - specifies whether the service should log each known change when it starts up
log.level
- (default: info
) - The log level specifically for the snap changes service, lower than info will
effectively disable change logging but they will still be stored in the sqlite database
apps
unregister
unregister is a separate app in the snap that can be used to clear the configuration of the agent related
to a Device Management Service it was previously registered/enrolled with. It will:
- Stop the agent
- Remove .secret
- Remove params
- Restart the agent
Encrypted snapd
subject tree
** CURRENTLY, TEMPORARILY DISABLED **
By default, the snapd.>
subject tree is encrypted and only accessible with the correct username and password. By default, (and with no snap configuration set) the password is accept solve carbon atmosphere
. To change to a different password,
snap set everactive-iot-agent nats.snapd.password="a very long password indeed"
Note that this password must match what is set in everactive-nats
.
Run single test
go test -v github.com/everactive/iot-agent/pkg/server -testify.m ^Test_NewServer$
Tasks
A top level Taskfile taskfile.dev is included and drives common tasks.
initialize
If you haven't previously installed dependencies, this will install Mockery for you. It will then
execute the prebuild task.
prebuild
Will do all necessary pre-build tasks that are not one-time (like regenerating mocks). Regenerating messages
structs is excluded do to manual editing necessary. See generate-message-structs
for more information.
generate-message-structs
NOTE: The current pkg/messages/messages.go has to be hand edited to perserve some types. If you regenerate the file you will need to diff it to identify types
that are translated as string or float64 when their types are time.Time or int64. import "time"
also needs to
be preserved and the empty interface generated is meaningless and is dropped.