NOISSUE - Add new endpoint to retrieve configuration to be used as a template. (#1242)
* add provision service Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix code style Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * fix test for provision Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * extra line Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com> * return map[string]interface instead of interface Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>
This commit is contained in:
parent
8ea26c5ab7
commit
9ed5f8334f
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
func doProvision(svc provision.Service) endpoint.Endpoint {
|
||||
return func(_ context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(addThingReq)
|
||||
req := request.(provisionReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -34,3 +34,13 @@ func doProvision(svc provision.Service) endpoint.Endpoint {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
func getMapping(svc provision.Service) endpoint.Endpoint {
|
||||
return func(_ context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(mappingReq)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return svc.Mapping(req.token)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,10 +24,10 @@ func (lm *loggingMiddleware) Provision(token, name, externalID, externalKey stri
|
|||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method provision for token: %s and things: %v took %s to complete", token, res.Things, time.Since(begin))
|
||||
if err != nil {
|
||||
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
|
||||
lm.logger.Warn(fmt.Sprintf("%s with error: %s", message, err))
|
||||
return
|
||||
}
|
||||
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
|
||||
lm.logger.Info(fmt.Sprintf("%s without errors", message))
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.Provision(token, name, externalID, externalKey)
|
||||
|
@ -37,11 +37,24 @@ func (lm *loggingMiddleware) Cert(token, thingID, duration string, keyBits int)
|
|||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method cert for token: %s and thing: %v took %s to complete", token, thingID, time.Since(begin))
|
||||
if err != nil {
|
||||
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
|
||||
lm.logger.Warn(fmt.Sprintf("%s with error: %s", message, err))
|
||||
return
|
||||
}
|
||||
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
|
||||
lm.logger.Info(fmt.Sprintf("%s without errors", message))
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.Cert(token, thingID, duration, keyBits)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) Mapping(token string) (res map[string]interface{}, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method mapping for token: %s took %s to complete", token, time.Since(begin))
|
||||
if err != nil {
|
||||
lm.logger.Warn(fmt.Sprintf("%s with error: %s", message, err))
|
||||
return
|
||||
}
|
||||
lm.logger.Info(fmt.Sprintf("%s without errors", message))
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.Mapping(token)
|
||||
}
|
||||
|
|
|
@ -1,14 +1,25 @@
|
|||
package api
|
||||
|
||||
type addThingReq struct {
|
||||
type provisionReq struct {
|
||||
token string
|
||||
Name string `json:"name"`
|
||||
ExternalID string `json:"external_id"`
|
||||
ExternalKey string `json:"external_key"`
|
||||
}
|
||||
|
||||
func (req addThingReq) validate() error {
|
||||
func (req provisionReq) validate() error {
|
||||
if req.ExternalID == "" || req.ExternalKey == "" {
|
||||
return errMalformedEntity
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type mappingReq struct {
|
||||
token string
|
||||
}
|
||||
|
||||
func (req mappingReq) validate() error {
|
||||
if req.token == "" {
|
||||
return errUnauthorized
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -21,17 +21,17 @@ func TestValidate(t *testing.T) {
|
|||
err: nil,
|
||||
},
|
||||
"external id for device empty": {
|
||||
err: errUnauthorized,
|
||||
err: errMalformedEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for desc, tc := range cases {
|
||||
req := addThingReq{
|
||||
req := provisionReq{
|
||||
ExternalID: tc.ExternalID,
|
||||
ExternalKey: tc.ExternalKey,
|
||||
}
|
||||
|
||||
err := req.validate()
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected `%v` got `%v`", desc, err, tc.err))
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected `%v` got `%v`", desc, tc.err, err))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,14 @@ func MakeHandler(svc provision.Service) http.Handler {
|
|||
|
||||
r.Post("/mapping", kithttp.NewServer(
|
||||
doProvision(svc),
|
||||
decodeThingCreation,
|
||||
decodeProvisionRequest,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
))
|
||||
|
||||
r.Get("/mapping", kithttp.NewServer(
|
||||
getMapping(svc),
|
||||
decodeMappingRequest,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
))
|
||||
|
@ -66,12 +73,12 @@ func encodeResponse(_ context.Context, w http.ResponseWriter, response interface
|
|||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
func decodeThingCreation(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
func decodeProvisionRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if r.Header.Get("Content-Type") != contentType {
|
||||
return nil, errUnsupportedContentType
|
||||
}
|
||||
|
||||
req := addThingReq{token: r.Header.Get("Authorization")}
|
||||
req := provisionReq{token: r.Header.Get("Authorization")}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -79,6 +86,16 @@ func decodeThingCreation(_ context.Context, r *http.Request) (interface{}, error
|
|||
return req, nil
|
||||
}
|
||||
|
||||
func decodeMappingRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if r.Header.Get("Content-Type") != contentType {
|
||||
return nil, errUnsupportedContentType
|
||||
}
|
||||
|
||||
req := mappingReq{token: r.Header.Get("Authorization")}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
ErrUnauthorized = errors.New("unauthorized access")
|
||||
ErrFailedToCreateToken = errors.New("failed to create access token")
|
||||
ErrEmptyThingsList = errors.New("things list in configuration empty")
|
||||
ErrEmptyChannelsList = errors.New("channels list in configuration is empty")
|
||||
|
@ -47,6 +48,11 @@ type Service interface {
|
|||
// - whitelist Thing in Bootstrap configuration == connect Thing to Channels
|
||||
Provision(token, name, externalID, externalKey string) (Result, error)
|
||||
|
||||
// Mapping returns current configuration used for provision
|
||||
// useful for using in ui to create configuration that matches
|
||||
// one created with Provision method.
|
||||
Mapping(token string) (map[string]interface{}, error)
|
||||
|
||||
// Certs creates certificate for things that communicate over mTLS
|
||||
// A duration string is a possibly signed sequence of decimal numbers,
|
||||
// each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m".
|
||||
|
@ -81,6 +87,14 @@ func New(cfg Config, sdk SDK.SDK, logger logger.Logger) Service {
|
|||
}
|
||||
}
|
||||
|
||||
// Mapping retrieves current configuration
|
||||
func (ps *provisionService) Mapping(token string) (map[string]interface{}, error) {
|
||||
if _, err := ps.sdk.User(token); err != nil {
|
||||
return map[string]interface{}{}, errors.Wrap(ErrUnauthorized, err)
|
||||
}
|
||||
return ps.conf.Bootstrap.Content, nil
|
||||
}
|
||||
|
||||
// Provision is provision method for creating setup according to
|
||||
// provision layout specified in config.toml
|
||||
func (ps *provisionService) Provision(token, name, externalID, externalKey string) (res Result, err error) {
|
||||
|
@ -118,6 +132,7 @@ func (ps *provisionService) Provision(token, name, externalID, externalKey strin
|
|||
res.Error = err.Error()
|
||||
return res, errors.Wrap(ErrFailedThingCreation, err)
|
||||
}
|
||||
|
||||
// Get newly created thing (in order to get the key).
|
||||
th, err = ps.sdk.Thing(thID, token)
|
||||
if err != nil {
|
||||
|
|
|
@ -15,7 +15,7 @@ paths:
|
|||
summary: Adds new device to proxy
|
||||
description: Adds new device to proxy
|
||||
tags:
|
||||
- Thing to proxy
|
||||
- provision
|
||||
parameters:
|
||||
- $ref: "#/parameters/Authorization"
|
||||
- in: body
|
||||
|
@ -38,8 +38,35 @@ paths:
|
|||
description: Created
|
||||
400:
|
||||
description: Failed due to malformed JSON.
|
||||
403:
|
||||
description: Unauthorized.
|
||||
500:
|
||||
description: Unexpected server-side error ocurred.
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
summary: Gets current mapping.
|
||||
description: Gets current mapping. This can be used in UI
|
||||
so that when bootstrap config is created from UI matches
|
||||
configuration created with provision service.
|
||||
tags:
|
||||
- provision
|
||||
parameters:
|
||||
- $ref: "#/parameters/Authorization"
|
||||
responses:
|
||||
200:
|
||||
schema:
|
||||
$ref: "#/definitions/Content"
|
||||
description: retrieved
|
||||
403:
|
||||
description: Unauthorized.
|
||||
500:
|
||||
description: Unexpected server-side error ocurred.
|
||||
|
||||
definitions:
|
||||
Content:
|
||||
type: object
|
||||
|
||||
parameters:
|
||||
Authorization:
|
||||
name: Authorization
|
||||
|
|
Loading…
Reference in New Issue