Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MF-1125 - Document Provision service #1143

Merged
merged 12 commits into from
Apr 30, 2020
Merged

Conversation

mteodor
Copy link
Contributor

@mteodor mteodor commented Apr 26, 2020

Closes #1143

@mteodor mteodor requested a review from a team as a code owner April 26, 2020 11:17
Copy link
Contributor

@drasko drasko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does service Swagger file exists?

```

## Authentication
In order to create necessary entities provision service needs to authenticate against Mainflux api. To provide authentication credentials to the provision service you can pass it in an environment variable or in a config file as Mainflux user and password or as api token (that can be issued on users/keys endpoint). Additionally users or api token can be passed in Authorization header, this authentication takes precedence over others.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mainflux API


## Authentication
In order to create necessary entities provision service needs to authenticate against Mainflux api. To provide authentication credentials to the provision service you can pass it in an environment variable or in a config file as Mainflux user and password or as api token (that can be issued on users/keys endpoint). Additionally users or api token can be passed in Authorization header, this authentication takes precedence over others.
* MFUser, MFPass in config or environment
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verbatim these MFUser but it is confusing - what are these? Some variables?

## Authentication
In order to create necessary entities provision service needs to authenticate against Mainflux api. To provide authentication credentials to the provision service you can pass it in an environment variable or in a config file as Mainflux user and password or as api token (that can be issued on users/keys endpoint). Additionally users or api token can be passed in Authorization header, this authentication takes precedence over others.
* MFUser, MFPass in config or environment
* MFAPiKEy in config or environment
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo?

Provision service provides an HTTP API to interact with Mainflux.
Provision service is used to setup initial applications configuration i.e. things, channels, connections and certificates that will be required for the specific use case.
For example lets say you are using a Mainflux and connecting gateways to it. Gateways need an easy way to configure itself for communication with Mainflux (receiving and sending controls and data) and for that you will use bootstrap service but before gateway connects to the bootstrap service configuration needs to be created (things, channels, connections, bootstrap configuration and certificates if mtls is being used). Provision service should provide an easy way of provisioning your gateways. On a gateway there can be many services running and you may require more than one thing and channel to establish all the required means of representing a gateway in your application. Let's say that you are using an [Agent](https://github.com/mainflux/agent) and [Export](https://github.com/mainflux/export) service and you use mtls you will need to provision two things and certificates for those things for access to Mainflux, or you may want to create any number of things and channels for your application, this kind of setup we can call provision layout.
Provision service provides this feature on a “/mapping” endpoint. Provision layout is configured in [config.toml](configs/config.toml)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use syntax highlighting /mapping

PROVISION service provides an HTTP API to interact with Mainflux.
Provision service provides an HTTP API to interact with Mainflux.
Provision service is used to setup initial applications configuration i.e. things, channels, connections and certificates that will be required for the specific use case.
For example lets say you are using a Mainflux and connecting gateways to it. Gateways need an easy way to configure itself for communication with Mainflux (receiving and sending controls and data) and for that you will use bootstrap service but before gateway connects to the bootstrap service configuration needs to be created (things, channels, connections, bootstrap configuration and certificates if mtls is being used). Provision service should provide an easy way of provisioning your gateways. On a gateway there can be many services running and you may require more than one thing and channel to establish all the required means of representing a gateway in your application. Let's say that you are using an [Agent](https://github.com/mainflux/agent) and [Export](https://github.com/mainflux/export) service and you use mtls you will need to provision two things and certificates for those things for access to Mainflux, or you may want to create any number of things and channels for your application, this kind of setup we can call provision layout.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that this is correct. and you use mtls you will need to provision two things and certificates for those things for access to Mainflux

| ----------------------------------- | ------------------------------------------------- | -------------------------------- |
| MF_PROVISION_USER | User (email) for accessing Mainflux | [email protected] |
| MF_PROVISION_PASS | Mainflux password | user123 |
| MF_PROVISION_API_KEY | Mainflux authentication token | "" |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove "" from default value

Comment on lines 18 to 19
| MF_PROVISION_API_KEY | Mainflux authentication token | "" |
| MF_PROVISION_CONFIG_FILE | Provision config file | "config.toml" |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here and for all others

Comment on lines 110 to 115
"ID": "c22b0c0f-8c03-40da-a06b-37ed3a72c8d1",
"Owner": "",
"Name": "thing",
"Key": "007cce56-e0eb-40d6-b2b9-ed348a97d1eb",
"Metadata": {
"externalID": "33:52:79:C3:43"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

id, owner, name etc etc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is result of marshalling things.Thing should we add json tags to that structure maybe?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you need JSON tags. We don't use camelCase for JSON keys

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

`/mapping` endpoint provision layout can be configured.

In `config.toml` we can enlist array of things and channels that we want to create and make connections between them which we call provision layout.
Metadata can be whatever suits your needs except that at least one thing needs to have `externalID` (which is populated with value from [request](#example)).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

external_id

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this how it is in thing metadata

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then it have to be also fixed in thing metadata

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this requires additional issue since bootstrap service needs to be changed as well

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

```
docker-compose -f docker/addons/provision/docker-compose.yml up
```
or
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or what?

MF_PROVISION_BS_SVC_URL=http://localhost:8202/things MF_PROVISION_THINGS_LOCATION=http://localhost:8182 MF_PROVISION_USERS_LOCATION=http://localhost:8180 MF_PROVISION_CONFIG_FILE=docker/addons/provision/configs/config.toml build/mainflux-provision
```

For the case that credentials or api token is passed in configuration
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API

curl -s -S -X POST http://localhost:8888/mapping -H 'Content-Type: application/json' -d '{ "external_id" : "33:52:77:99:43", "external_key":"223334fw2" }'
```

In the case that provision service is not deployed with credential or you want to use user other than default one being set in environment ( or config file)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the white space here: ( or config file)

@mteodor
Copy link
Contributor Author

mteodor commented Apr 27, 2020

docker-compose -f docker/addons/provision/docker-compose.yml up
```


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rm this blank line

Comment on lines 110 to 115
"ID": "c22b0c0f-8c03-40da-a06b-37ed3a72c8d1",
"Owner": "",
"Name": "thing",
"Key": "007cce56-e0eb-40d6-b2b9-ed348a97d1eb",
"Metadata": {
"externalID": "33:52:79:C3:43"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


In the case that provision service is not deployed with credential or you want to use user other than default one being set in environment (or config file)
```
curl -s -S -X POST http://localhost:8091/mapping -H "Authorization: $TOK" -H 'Content-Type: application/json' -d '{ "external_id" : "02:42:fE:65:D3:23", "external_key":"223334fw2" }'
Copy link
Contributor

@manuio manuio Apr 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the white space here: application/json' -d

| MF_PROVISION_USER | User (email) for accessing Mainflux | [email protected] |
| MF_PROVISION_PASS | Mainflux password | user123 |
| MF_PROVISION_API_KEY | Mainflux authentication token | |
| MF_PROVISION_CONFIG_FILE | Provision config file | "config.toml" |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

config.toml not "config.toml"



## Running

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kill this white line

```

Response contains created things and channels and certificates if any.
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add json label after ```

In order to create necessary entities provision service needs to authenticate against Mainflux API. To provide authentication credentials to the provision service you can pass it in an environment variable or in a config file as Mainflux user and password or as API token (that can be issued on users/keys endpoint). Additionally users or API token can be passed in Authorization header, this authentication takes precedence over others.
* `username`, `password` - (`MF_PROVISION_USER`, `MF_PROVISION_PASSWORD` in [.env](../.env), `mf_user`, `mf_pass` in [config.toml](../docker/addons/provision/configs/config.toml))
* API Key - (`MF_PROVISION_API_KEY` in [.env](../.env) or [config.toml](../docker/addons/provision/configs/config.toml))
* ```Authorization: Token|ApiKey``` - request authorization header containing either users token or API key
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why triple backticks?

For channels metadata `type` is reserved for `control` and `data` which we use with [Agent](https://github.com/mainflux/agent).

Example below
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add toml label after ```

Provision service can be run as a standalone or in docker composition as addon to the core docker composition.

Standalone:
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add bash label after ```

PROVISION service provides an HTTP API to interact with Mainflux.
Provision service provides an HTTP API to interact with Mainflux.
Provision service is used to setup initial applications configuration i.e. things, channels, connections and certificates that will be required for the specific use case.
For example lets say you are using a Mainflux and connecting gateways to it. Gateways need an easy way to configure itself for communication with Mainflux (receiving and sending controls and data) and for that you will use bootstrap service but before gateway connects to the bootstrap service configuration needs to be created (things, channels, connections, bootstrap configuration and certificates if mtls is being used). Provision service should provide an easy way of provisioning your gateways. On a gateway there can be many services running and you may require more than one thing and channel to establish all the required means of representing a gateway in your application. You may need to create any number of things and channels for your purposes, let's say that you are using services [Agent](https://github.com/mainflux/agent) and [Export](https://github.com/mainflux/export) on a gateway, if you enabled mtls each service will need a thing and certificate for access to Mainflux and you will need two channels for `Agent` (`data` and `control`) and for `Export` you could use as many as you find suitable, this kind of setup we can call `provision layout`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part is hard to understand. I would simplify it to something like:
For example, to connect Gateways to Mainflux you need an easy way to setup communication channels to send and receive data or control commands. Bootstrap service can be used in this cases but you must previously create Things, Channels, Connections, Bootstrap Config and mTLS certificates. Provision service provide a way to do it so. On a Gateway...
I'm not saying that my proposition is perfect. But your sentences are too long and with too much superfluous.

docker-compose -f docker/addons/provision/docker-compose.yml up
```

For the case that credentials or API token is passed in configuration call to endpoint is called:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I didn't understand

PROVISION service provides an HTTP API to interact with Mainflux.
Provision service provides an HTTP API to interact with [Mainflux](https://github.com/mainflux/mainflux).
Provision service is used to setup initial applications configuration i.e. things, channels, connections and certificates that will be required for the specific use case.
For example lets say you are connecting gateways to [Mainflux](https://github.com/mainflux/mainflux). Gateways need an easy way to configure itself for communication with [Mainflux](https://github.com/mainflux/mainflux) (receiving and sending controls and data). To get the authentication parameters gateway will send a request to [Bootstrap](../bootstrap/README.md) service. To get connection parameters gateway will provide `<external_id>` and `<external_key>` in request from [Bootstrap](../bootstrap/README.md). To make a request to [Bootstrap](../bootstrap/README.md) service you can use [Agent](https://github.com/mainflux/agent) service on a gateway. To create bootstrap configuration you can use [Bootstrap](../bootstrap/README.md) or `Provision` service. [Mainflux UI](https://github.com/mainflux/ui) uses [Bootstrap](../bootstrap/README.md) service for creating gateway configurations. `Provision` service should provide an easy way of provisioning your gateways i.e creating bootstrap configuration and as many things and channels that your setup requires. Also you may use provision service to create certificates for each thing. Each service running on gateway may require more than one thing and channel for communication. Let's say that you are using services [Agent](https://github.com/mainflux/agent) and [Export](https://github.com/mainflux/export) on a gateway, if you enabled mtls each service will need a thing and certificate for access to [Mainflux](https://github.com/mainflux/mainflux) and you will need two channels for `Agent` (`data` and `control`) and one for `Export` or you could use as many as you find suitable, this kind of setup we can call `provision layout`.
Copy link
Contributor

@manuio manuio Apr 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Define this link at the bottom of thee README. For example:

This is a [Mainflux][mainflux] link

[mainflux]: https://github.com/mainflux/mainflux

Also, probably better to use absolute path for this links

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw, I still not convinced about For example lets say you are connecting...

docker-compose -f docker/addons/provision/docker-compose.yml up
```

For the case that credentials or API token is passed in configuration or env, call to `/mapping` endpoint doesnt require `Authentication` header:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We understand or env but maybe better or as environment variable
Also, fix doesn't

@codecov-io
Copy link

codecov-io commented Apr 29, 2020

Codecov Report

Merging #1143 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##           master    #1143   +/-   ##
=======================================
  Coverage   74.18%   74.18%           
=======================================
  Files         102      102           
  Lines        6841     6841           
=======================================
  Hits         5075     5075           
  Misses       1413     1413           
  Partials      353      353           

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f872546...450dd87. Read the comment docs.

| MF_PROVISION_BS_AUTO_WHITEIST | Should thing be auto whitelisted | true |
| MF_PROVISION_BS_CONTENT | Bootstrap service content | {} |

By default, call to `/mapping` endpoint will create one thing and two channels (`control` and `data`) and connect it. If there is a requirement for different provision layout we can use [config](docker/configs/config.toml) file in addition to environment variables. For the purposes of running provision as an add-on in docker composition environment variables seems more suitable. Environoment variables are set in [.env](.env).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix typo Environoment.

`/mapping` endpoint provision layout can be configured.

In `config.toml` we can enlist array of things and channels that we want to create and make connections between them which we call provision layout.
Metadata can be whatever suits your needs except that at least one thing needs to have `external_id` (which is populated with value from [request](#example)). Thing that has `external_id` will be used for creating boostrap configuration which can be fetched with [Agent](https://github.com/mainflux/agent).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo boostrap.

PROVISION service provides an HTTP API to interact with Mainflux.
Provision service provides an HTTP API to interact with [Mainflux][mainflux].
Provision service is used to setup initial applications configuration i.e. things, channels, connections and certificates that will be required for the specific use case especially useful for gateway provision.
For gateways to communicate with [Mainflux][mainflux] connection params are required (mqtt host, thing, channels, certificates...). To get the connection parameters gateway will send a request to [Bootstrap](../bootstrap/README.md) service providing `<external_id>` and `<external_key>` in request. To make a request to [Bootstrap](../bootstrap/README.md) service you can use [Agent](https://github.com/mainflux/agent) service on a gateway. To create bootstrap configuration you can use [Bootstrap](../bootstrap/README.md) or `Provision` service. [Mainflux UI](https://github.com/mainflux/ui) uses [Bootstrap](../bootstrap/README.md) service for creating gateway configurations. `Provision` service should provide an easy way of provisioning your gateways i.e creating bootstrap configuration and as many things and channels that your setup requires. Also you may use provision service to create certificates for each thing. Each service running on gateway may require more than one thing and channel for communication. Let's say that you are using services [Agent](https://github.com/mainflux/agent) and [Export](https://github.com/mainflux/export) on a gateway, if you enabled mtls each service will need a thing and certificate for access to [Mainflux][mainflux] and you will need two channels for `Agent` (`data` and `control`) and one for `Export` or you could use as many as you find suitable, this kind of setup we can call `provision layout`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use configuration instead of connection params. Maybe also something like this:

To create a bootstrap configuration, you can use Bootstrap service API directly (bootstrap/README.md), or you can use UI or Provision service.

dborovcanin
dborovcanin previously approved these changes Apr 29, 2020

Standalone:
```bash
MF_PROVISION_BS_SVC_URL=http://localhost:8202/things MF_PROVISION_THINGS_LOCATION=http://localhost:8182 MF_PROVISION_USERS_LOCATION=http://localhost:8180 MF_PROVISION_CONFIG_FILE=docker/addons/provision/configs/config.toml build/mainflux-provision
Copy link
Contributor

@manuio manuio Apr 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, split this in multiple lines with \


PROVISION service provides an HTTP API to interact with Mainflux.
Provision service provides an HTTP API to interact with [Mainflux][mainflux].
Provision service is used to setup initial applications configuration i.e. things, channels, connections and certificates that will be required for the specific use case especially useful for gateway provision.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you can also create references for UI and export links

mteodor added 8 commits April 30, 2020 07:37
Signed-off-by: Mirko Teodorovic <[email protected]>
Signed-off-by: Mirko Teodorovic <[email protected]>
Signed-off-by: Mirko Teodorovic <[email protected]>
Signed-off-by: Mirko Teodorovic <[email protected]>
Signed-off-by: Mirko Teodorovic <[email protected]>
Signed-off-by: Mirko Teodorovic <[email protected]>
Signed-off-by: Mirko Teodorovic <[email protected]>
Signed-off-by: Mirko Teodorovic <[email protected]>

PROVISION service provides an HTTP API to interact with Mainflux.
Provision service provides an HTTP API to interact with [Mainflux][mainflux].
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General observation: break long chunks of text in paragraphs, separate paragraphs with whitelines - it will be much easier to read.

Signed-off-by: Mirko Teodorovic <[email protected]>
| MF_PROVISION_BS_AUTO_WHITEIST | Should thing be auto whitelisted | true |
| MF_PROVISION_BS_CONTENT | Bootstrap service content | {} |

By default, call to `/mapping` endpoint will create one thing and two channels (`control` and `data`) and connect it. If there is a requirement for different provision layout we can use [config](docker/configs/config.toml) file in addition to environment variables. For the purposes of running provision as an add-on in docker composition environment variables seems more suitable. Environment variables are set in [.env](.env).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Break chunk of text in paragraphs.


## Authentication
In order to create necessary entities provision service needs to authenticate against Mainflux. To provide authentication credentials to the provision service you can pass it in an environment variable or in a config file as Mainflux user and password or as API token (that can be issued on `/users` or `/keys` endpoint of [authn](../authn/README.md)). Additionally users or API token can be passed in Authorization header, this authentication takes precedence over others.
* `username`, `password` - (`MF_PROVISION_USER`, `MF_PROVISION_PASSWORD` in [.env](../.env), `mf_user`, `mf_pass` in [config.toml](../docker/addons/provision/configs/config.toml))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like whiteline missing to separate paragraphs.

mteodor added 3 commits April 30, 2020 14:01
Signed-off-by: Mirko Teodorovic <[email protected]>
Signed-off-by: Mirko Teodorovic <[email protected]>
Signed-off-by: Mirko Teodorovic <[email protected]>
Copy link
Contributor

@drasko drasko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@drasko drasko merged commit 0c016cd into absmach:master Apr 30, 2020
manuio pushed a commit that referenced this pull request Oct 12, 2020
* update readme

Signed-off-by: Mirko Teodorovic <[email protected]>

* update docs

Signed-off-by: Mirko Teodorovic <[email protected]>

* small changes

Signed-off-by: Mirko Teodorovic <[email protected]>

* update docs

Signed-off-by: Mirko Teodorovic <[email protected]>

* update docs

Signed-off-by: Mirko Teodorovic <[email protected]>

* update docs

Signed-off-by: Mirko Teodorovic <[email protected]>

* update docs

Signed-off-by: Mirko Teodorovic <[email protected]>

* minor changes

Signed-off-by: Mirko Teodorovic <[email protected]>

* additional paragraphs

Signed-off-by: Mirko Teodorovic <[email protected]>

* additional paragraphs

Signed-off-by: Mirko Teodorovic <[email protected]>

* additional paragraphs

Signed-off-by: Mirko Teodorovic <[email protected]>

* add some space

Signed-off-by: Mirko Teodorovic <[email protected]>
@mteodor mteodor deleted the docs-provision branch September 13, 2021 12:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants