1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-04-26 13:48:53 +08:00

MF-539 - Improve Bootstrap Service documentation (#646)

* Fix infinte loop in Subscribe method

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Update API docs

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Update service README

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Update docs

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Add bootstrapping flow gif

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Update bootstrapping flow gif

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
This commit is contained in:
Dušan Borovčanin 2019-03-15 19:11:26 +01:00 committed by Drasko DRASKOVIC
parent 61b2d6b87b
commit 2ed1471d5f
7 changed files with 133 additions and 25 deletions

View File

@ -1,22 +1,22 @@
# BOOTSTRAP SERVICE
New devices need to be configured properly and connected to the Mainflux. Bootstrap service is used in order to accomplish that. This service provides the following features:
1) Creating new Mainflux Things
2) Providing basic configuration for the newly created Things
3) Enabling/disabling Things
1) Creating new Mainflux Things
2) Providing basic configuration for the newly created Things
3) Enabling/disabling Things
Pre-provisioning a new Thing is as simple as sending Thing data to the Bootstrap service. Once the Thing is active, it sends a request for initial config to Bootstrap service. Once the Thing is bootstrapped, its possible to add it to the whitelist, so that it can exchange messages using Mainflux. Bootstrapping does not implicitly enable Things, it has to be done manually.
Pre-provisioning a new Thing is as simple as sending Configuration data to the Bootstrap service. Once the Thing is online, it sends a request for initial config to Bootstrap service. Bootstrap service provides an API for enabling and disabling Things. Only enabled Things can exchange messages over Mainflux. Bootstrapping does not implicitly enable Things, it has to be done manually.
In order to bootstrap successfully, the Thing needs to send bootstrapping request to the specific URL, as well as a secret key. This key and URL are pre-provisioned during manufacturing process. If the Thing is provisioned on the Bootstrap service side, corresponding configuration will be sent as a response. Otherwise, the Thing will be saved so that it can be provisioned later.
In order to bootstrap successfully, the Thing needs to send bootstrapping request to the specific URL, as well as a secret key. This key and URL are pre-provisioned during the manufacturing process. If the Thing is provisioned on the Bootstrap service side, the corresponding configuration will be sent as a response. Otherwise, the Thing will be saved so that it can be provisioned later.
***Thing Configuration***
Thing Configuration consists of two logical parts: custom configuration (that can be interpreted by the Thing itself) and Mainflux-related configuration. Mainflux config contains:
1) corresponding Mainflux Thing ID
2) corresponding Mainflux Thing key
3) list of the Mainflux channels the Thing is connected to
Thing Configuration consists of two logical parts: the custom configuration that can be interpreted by the Thing itself and Mainflux-related configuration. Mainflux config contains:
1) corresponding Mainflux Thing ID
2) corresponding Mainflux Thing key
3) list of the Mainflux channels the Thing is connected to
>Note: list of channels contains IDs of the Mainflux channels. These channels are _pre-provisioned_ on the Mainflux side and, unlike corresponding Mainflux Thing, Bootstrap service does not create Mainflux Channels.
>Note: list of channels contains IDs of the Mainflux channels. These channels are _pre-provisioned_ on the Mainflux side and, unlike corresponding Mainflux Thing, Bootstrap service is not able to create Mainflux Channels.
Enabling and disabling Thing (adding Thing to/from whitelist) is as simple as connecting corresponding Mainflux Thing to the given list of Channels. Configuration keeps _state_ of the Thing:
@ -51,6 +51,10 @@ The service is configured using the environment variables presented in the follo
| MF_SDK_BASE_URL | Base url for Mainflux SDK | http://localhost |
| MF_SDK_THINGS_PREFIX | SDK prefix for Things service | |
| MF_USERS_URL | Users service URL | localhost:8181 |
| MF_THINGS_ES_URL | Things service event source URL | localhost:6379 |
| MF_THINGS_ES_PASS | Things service event source password | |
| MF_THINGS_ES_DB | Things service event source database | 0 |
| MF_BOOTSTRAP_INSTANCE_NAME | Bootstrap service instance name | bootstrap |
## Deployment
@ -87,7 +91,11 @@ version: "2"
MF_SDK_BASE_URL: [Base SDK URL for the Mainflux services]
MF_SDK_THINGS_PREFIX: [SDK prefix for Things service]
MF_USERS_URL: [Users service URL]
```
MF_THINGS_ES_URL: [Things service event source URL]
MF_THINGS_ES_PASS: [Things service event source password]
MF_THINGS_ES_DB: [Things service event source database]
MF_BOOTSTRAP_INSTANCE_NAME: [Bootstrap service instance name]
```
To start the service outside of the container, execute the following shell script:

View File

@ -19,12 +19,14 @@ const (
channelPrefix = "channel."
channelUpdate = channelPrefix + "update"
channelRemove = channelPrefix + "remove"
exists = "BUSYGROUP Consumer Group name already exists"
)
// EventStore represents event source for things and channels provisioning.
type EventStore interface {
// Subscribes to given subject and receives events.
Subscribe(string)
Subscribe(string) error
}
type eventStore struct {
@ -44,8 +46,12 @@ func NewEventStore(svc bootstrap.Service, client *redis.Client, consumer string,
}
}
func (es eventStore) Subscribe(subject string) {
es.client.XGroupCreateMkStream(stream, group, "$").Err()
func (es eventStore) Subscribe(subject string) error {
err := es.client.XGroupCreateMkStream(stream, group, "$").Err()
if err != nil && err.Error() != exists {
return err
}
for {
streams, err := es.client.XReadGroup(&redis.XReadGroupArgs{
Group: group,

View File

@ -408,6 +408,9 @@ definitions:
external_key:
type: string
description: External key.
thing_id:
type: string
description: ID of the corresponding Mainflux Thing.
channels:
type: array
minItems: 0

View File

@ -50,11 +50,10 @@ const (
defBaseURL = "http://localhost"
defThingsPrefix = ""
defUsersURL = "localhost:8181"
defESURL = "localhost:6379"
defESPass = ""
defESDB = "0"
defInstanceName = "bootstrap"
defESURL = "localhost:6379"
defESPass = ""
defESDB = "0"
defInstanceName = "bootstrap"
envLogLevel = "MF_BOOTSTRAP_LOG_LEVEL"
envDBHost = "MF_BOOTSTRAP_DB_HOST"
@ -74,11 +73,10 @@ const (
envBaseURL = "MF_SDK_BASE_URL"
envThingsPrefix = "MF_SDK_THINGS_PREFIX"
envUsersURL = "MF_USERS_URL"
envESURL = "MF_THINGS_ES_URL"
envESPass = "MF_THINGS_ES_PASS"
envESDB = "MF_THINGS_ES_DB"
envInstanceName = "MF_BOOTSTRAP_INSTANCE_NAME"
envESURL = "MF_THINGS_ES_URL"
envESPass = "MF_THINGS_ES_PASS"
envESDB = "MF_THINGS_ES_DB"
envInstanceName = "MF_BOOTSTRAP_INSTANCE_NAME"
)
type config struct {
@ -262,5 +260,7 @@ func startHTTPServer(svc bootstrap.Service, cfg config, logger logger.Logger, er
func subscribeToThingsES(svc bootstrap.Service, client *r.Client, consumer string, logger logger.Logger) {
eventStore := redis.NewEventStore(svc, client, consumer, logger)
logger.Info("Subscribed to Redis Event Store")
eventStore.Subscribe("mainflux.things")
if err := eventStore.Subscribe("mainflux.things"); err != nil {
logger.Warn(fmt.Sprintf("Botstrap service failed to subscribe to event sourcing: %s", err))
}
}

90
docs/bootstrap.md Normal file
View File

@ -0,0 +1,90 @@
## Bootstrap
`Bootstrapping` refers to a self-starting process that is supposed to proceed without external input.
Mainflux platform supports bootstrapping process, but some of the preconditions need to be fulfilled in advance. The device can trigger a bootstrap when:
- device contains only bootstrap credentials and no Mainflux credentials
- device, for any reason, fails to start a communication with the configured Mainflux services (server not responding, authentication failure, etc..).
- device, for any reason, wants to update its configuration
> Bootstrapping and provisioning are two different procedures. Provisioning refers to entities management while bootstrapping is related to entity configuration.
![bootstrapping flow](img/bs_flow.gif)
### Configuration
The configuration of Mainflux thing consists of two major parts:
- The list of Mainflux channels the thing is connected to
- Custom configuration related to the specific thing
Also, the configuration contains an external ID and external key, which will be explained later.
In order to enable the thing to start bootstrapping process, the user needs to upload a valid configuration for that specific thing. This can be done using the following HTTP request:
```
curl -s -S -i -X POST -H "Authorization: <user_token>" -H "Content-Type: application/json" http://localhost:8900/things/configs -d '{
"external_id":"09:6:0:sb:sa",
"thing_id": "1b9b8fae-9035-4969-a240-7fe5bdc0ed28",
"external_key":"key",
"name":"some",
"channels":[
"c3642289-501d-4974-82f2-ecccc71b2d83",
"cd4ce940-9173-43e3-86f7-f788e055eb14",
"ff13ca9c-7322-4c28-a25c-4fe5c7b753fc",
"c3642289-501d-4974-82f2-ecccc71b2d82"
],
"content": "config..."
}'
```
In this example, `channels` field represents the list of Mainflux channel IDs the thing is connected to. These channels need to be provisioned before the configuration is uploaded. Field `content` represents custom configuration. This custom configuration contains parameters that can be used to set up the thing. It can also be empty if no additional set up is needed. Field `name` is human readable name and `thing_id` is an ID of the Mainflux thing. This field is not required. If `thing_id` is empty, corresponding Mainflux thing will be created implicitly and its ID will be sent as a part of `Location` header of the response.
There are two more fields: `external_id` and `external_key`. External ID represents an ID of the device that corresponds to the given thing. For example, this can be a MAC address or the serial number of the device. The external key represents the device key. This is the secret key that's safely stored on the device and it is used to authorize the thing during the bootstrapping process. Please note that external ID and external key and Mainflux ID and Mainflux key are _completely different concepts_. External id and key are only used to authenticate a device that corresponds to the specific Mainflux thing during the bootstrapping procedure.
### Bootstrapping
Currently, the bootstrapping procedure is executed over the HTTP protocol. Bootstrapping is nothing else but fetching and applying the configuration that corresponds to the given Mainflux thing. In order to fetch the configuration, _the thing_ needs to send a bootstrapping request:
```
curl -s -S -i -H "Authorization: <external_key>" http://localhost:8900/things/bootstrap/<external_id>
```
The response body should look something like:
```
{
"mainflux_id":"7c9df5eb-d06b-4402-8c1a-df476e4394c8",
"mainflux_key":"86a4f870-eba4-46a0-bef9-d94db2b64392",
"mainflux_channels":[
{
"id":"ff13ca9c-7322-4c28-a25c-4fe5c7b753fc",
"name":"some channel",
"metadata":{
"operation":"someop",
"type":"metadata"
}
},
{
"id":"925461e6-edfb-4755-9242-8a57199b90a5",
"name":"channel1",
"metadata":{
"type":"control"
}
}
],
"content":"config..."
}
```
The response consists of an ID and key of the Mainflux thing, the list of channels and custom configuration (`content` field). The list of channels contains not just channel IDs, but the additional Mainflux channel data (`name` and `metadata` fields), as well.
### Enabling and disabling things
Uploading configuration does not automatically connect thing to the given list of channels. In order to connect the thing to the channels, user needs to send the following HTTP request:
```
curl -s -S -i -X PUT -H "Authorization: <user_token>" -H "Content-Type: application/json" http://localhost:8900/things/state/<thing_id> -d '{"state": 1}'
```
In order to disconnect, the same request should be sent with the value of `state` set to 0.
For more information about Bootstrap API, please check out the [API documentation](https://github.com/mainflux/mainflux/blob/master/bootstrap/swagger.yml).

BIN
docs/img/bs_flow.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 KiB

View File

@ -35,5 +35,6 @@ pages:
- LoRa: lora.md
- TLS: tls.md
- CLI: cli.md
- Bootstrap: bootstrap.md
- Developer's Guide: dev-guide.md
- Load Test: load-test.md