mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-27 13:48:49 +08:00
MF-862 - Add boostrap CRUD to SDK and CLI (#1114)
* MF-862 - Add boostrap CRUD to SDK and CLI Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Revert ReaderPrefix Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix reviews Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com> * Fix typo Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>
This commit is contained in:
parent
b8bd011f9d
commit
4c970a8079
137
cli/bootstrap.go
Normal file
137
cli/bootstrap.go
Normal file
@ -0,0 +1,137 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
mfxsdk "github.com/mainflux/mainflux/sdk/go"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var cmdBootstrap = []cobra.Command{
|
||||
cobra.Command{
|
||||
Use: "add",
|
||||
Short: "add <JSON_config> <user_auth_token>",
|
||||
Long: `Adds new Thing Bootstrap Config to the user identified by the provided key`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
var cfg mfxsdk.BoostrapConfig
|
||||
if err := json.Unmarshal([]byte(args[0]), &cfg); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := sdk.AddBootstrap(args[1], cfg)
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logCreated(id)
|
||||
},
|
||||
},
|
||||
cobra.Command{
|
||||
Use: "view",
|
||||
Short: "view <thing_id> <user_auth_token>",
|
||||
Long: `Returns Thing Config with given ID belonging to the user identified by the given key`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
c, err := sdk.ViewBoostrap(args[1], args[0])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSON(c)
|
||||
},
|
||||
},
|
||||
cobra.Command{
|
||||
Use: "update",
|
||||
Short: "update <JSON_config> <user_auth_token>",
|
||||
Long: `Updates editable fields of the provided Config`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
var cfg mfxsdk.BoostrapConfig
|
||||
if err := json.Unmarshal([]byte(args[0]), &cfg); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.UpdateBoostrap(args[1], cfg); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
cobra.Command{
|
||||
Use: "remove",
|
||||
Short: "remove <thing_id> <user_auth_token>",
|
||||
Long: `Removes Config with specified key that belongs to the user identified by the given key`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.RemoveBoostrap(args[1], args[0]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
cobra.Command{
|
||||
Use: "bootstrap",
|
||||
Short: "bootstrap <external_id> <external_key>",
|
||||
Long: `Returns Config to the Thing with provided external ID using external key`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
c, err := sdk.Boostrap(args[1], args[0])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSON(c)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// NewBootstrapCmd returns bootstrap command.
|
||||
func NewBootstrapCmd() *cobra.Command {
|
||||
cmd := cobra.Command{
|
||||
Use: "bootstrap",
|
||||
Short: "Bootstrap management",
|
||||
Long: `Bootstrap management: create, get, update or delete Bootstrap config`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
logUsage("bootstrap [add | view | update | remove | bootstrap]")
|
||||
},
|
||||
}
|
||||
|
||||
for i := range cmdBootstrap {
|
||||
cmd.AddCommand(&cmdBootstrap[i])
|
||||
}
|
||||
|
||||
return &cmd
|
||||
}
|
@ -16,10 +16,12 @@ func main() {
|
||||
sdkConf := sdk.Config{
|
||||
BaseURL: "http://localhost",
|
||||
ReaderURL: "http://localhost:8905",
|
||||
BootstrapURL: "http://localhost:8202",
|
||||
ReaderPrefix: "",
|
||||
UsersPrefix: "",
|
||||
ThingsPrefix: "",
|
||||
HTTPAdapterPrefix: "http",
|
||||
BootstrapPrefix: "things",
|
||||
MsgContentType: sdk.ContentType(msgContentType),
|
||||
TLSVerification: false,
|
||||
}
|
||||
@ -41,6 +43,7 @@ func main() {
|
||||
channelsCmd := cli.NewChannelsCmd()
|
||||
messagesCmd := cli.NewMessagesCmd()
|
||||
provisionCmd := cli.NewProvisionCmd()
|
||||
bootstrapCmd := cli.NewBootstrapCmd()
|
||||
|
||||
// Root Commands
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
@ -49,6 +52,7 @@ func main() {
|
||||
rootCmd.AddCommand(channelsCmd)
|
||||
rootCmd.AddCommand(messagesCmd)
|
||||
rootCmd.AddCommand(provisionCmd)
|
||||
rootCmd.AddCommand(bootstrapCmd)
|
||||
|
||||
// Root Flags
|
||||
rootCmd.PersistentFlags().StringVarP(
|
||||
|
192
sdk/go/bootstrap.go
Normal file
192
sdk/go/bootstrap.go
Normal file
@ -0,0 +1,192 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/mainflux/mainflux/errors"
|
||||
)
|
||||
|
||||
const configsEndpoint = "configs"
|
||||
const bootstrapEndpoint = "bootstrap"
|
||||
|
||||
// BoostrapConfig represents Configuration entity. It wraps information about external entity
|
||||
// as well as info about corresponding Mainflux entities.
|
||||
// MFThing represents corresponding Mainflux Thing ID.
|
||||
// MFKey is key of corresponding Mainflux Thing.
|
||||
// MFChannels is a list of Mainflux Channels corresponding Mainflux Thing connects to.
|
||||
type BoostrapConfig struct {
|
||||
ThingID string `json:"thing_id,omitempty"`
|
||||
Channels []string `json:"channels,omitempty"`
|
||||
ExternalID string `json:"external_id,omitempty"`
|
||||
ExternalKey string `json:"external_key,omitempty"`
|
||||
MFThing string `json:"mainflux_id,omitempty"`
|
||||
MFChannels []Channel `json:"mainflux_channels,omitempty"`
|
||||
MFKey string `json:"mainflux_key,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
ClientKey string `json:"client_key,omitempty"`
|
||||
CACert string `json:"ca_cert,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
State int `json:"state,omitempty"`
|
||||
}
|
||||
|
||||
func (sdk mfSDK) AddBootstrap(key string, cfg BoostrapConfig) (string, error) {
|
||||
data, err := json.Marshal(cfg)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(ErrInvalidArgs, err)
|
||||
}
|
||||
|
||||
url := createURL(sdk.bootstrapURL, sdk.bootstrapPrefix, configsEndpoint)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, key, string(CTJSON))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
|
||||
if err := encodeError(resp.StatusCode); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "", ErrFailedCreation
|
||||
}
|
||||
|
||||
id := strings.TrimPrefix(resp.Header.Get("Location"), "/things/configs/")
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ViewBoostrap(key, id string) (BoostrapConfig, error) {
|
||||
endpoint := fmt.Sprintf("%s/%s", configsEndpoint, id)
|
||||
url := createURL(sdk.bootstrapURL, sdk.bootstrapPrefix, endpoint)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return BoostrapConfig{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, key, string(CTJSON))
|
||||
if err != nil {
|
||||
return BoostrapConfig{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return BoostrapConfig{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
if err := encodeError(resp.StatusCode); err != nil {
|
||||
return BoostrapConfig{}, err
|
||||
}
|
||||
return BoostrapConfig{}, ErrFetchFailed
|
||||
}
|
||||
|
||||
var bc BoostrapConfig
|
||||
if err := json.Unmarshal(body, &bc); err != nil {
|
||||
return BoostrapConfig{}, err
|
||||
}
|
||||
|
||||
return bc, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) UpdateBoostrap(key string, cfg BoostrapConfig) error {
|
||||
data, err := json.Marshal(cfg)
|
||||
if err != nil {
|
||||
return errors.Wrap(ErrInvalidArgs, err)
|
||||
}
|
||||
|
||||
endpoint := fmt.Sprintf("%s/%s", configsEndpoint, cfg.MFThing)
|
||||
url := createURL(sdk.bootstrapURL, sdk.bootstrapPrefix, endpoint)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPut, url, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, key, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
if err := encodeError(resp.StatusCode); err != nil {
|
||||
return err
|
||||
}
|
||||
return ErrFailedUpdate
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) RemoveBoostrap(key, id string) error {
|
||||
endpoint := fmt.Sprintf("%s/%s", configsEndpoint, id)
|
||||
url := createURL(sdk.bootstrapURL, sdk.bootstrapPrefix, endpoint)
|
||||
|
||||
req, err := http.NewRequest(http.MethodDelete, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, key, string(CTJSON))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusNoContent {
|
||||
if err := encodeError(resp.StatusCode); err != nil {
|
||||
return err
|
||||
}
|
||||
return ErrFailedRemoval
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Boostrap(key, id string) (BoostrapConfig, error) {
|
||||
endpoint := fmt.Sprintf("%s/%s", bootstrapEndpoint, id)
|
||||
url := createURL(sdk.bootstrapURL, sdk.bootstrapPrefix, endpoint)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return BoostrapConfig{}, err
|
||||
}
|
||||
|
||||
resp, err := sdk.sendRequest(req, key, string(CTJSON))
|
||||
if err != nil {
|
||||
return BoostrapConfig{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return BoostrapConfig{}, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
if err := encodeError(resp.StatusCode); err != nil {
|
||||
return BoostrapConfig{}, err
|
||||
}
|
||||
return BoostrapConfig{}, ErrFetchFailed
|
||||
}
|
||||
|
||||
var bc BoostrapConfig
|
||||
if err := json.Unmarshal(body, &bc); err != nil {
|
||||
return BoostrapConfig{}, err
|
||||
}
|
||||
|
||||
return bc, nil
|
||||
}
|
@ -175,16 +175,33 @@ type SDK interface {
|
||||
|
||||
// Version returns used mainflux version.
|
||||
Version() (string, error)
|
||||
|
||||
// AddBootstrap add boostrap configuration
|
||||
AddBootstrap(key string, cfg BoostrapConfig) (string, error)
|
||||
|
||||
// View returns Thing Config with given ID belonging to the user identified by the given key.
|
||||
ViewBoostrap(key, id string) (BoostrapConfig, error)
|
||||
|
||||
// Update updates editable fields of the provided Config.
|
||||
UpdateBoostrap(key string, cfg BoostrapConfig) error
|
||||
|
||||
// Remove removes Config with specified key that belongs to the user identified by the given key.
|
||||
RemoveBoostrap(key, id string) error
|
||||
|
||||
// View returns Thing Config with given ID belonging to the user identified by the given key.
|
||||
Boostrap(key, id string) (BoostrapConfig, error)
|
||||
}
|
||||
|
||||
type mfSDK struct {
|
||||
baseURL string
|
||||
readerURL string
|
||||
bootstrapURL string
|
||||
readerPrefix string
|
||||
usersPrefix string
|
||||
thingsPrefix string
|
||||
channelsPrefix string
|
||||
httpAdapterPrefix string
|
||||
bootstrapPrefix string
|
||||
msgContentType ContentType
|
||||
client *http.Client
|
||||
}
|
||||
@ -193,10 +210,12 @@ type mfSDK struct {
|
||||
type Config struct {
|
||||
BaseURL string
|
||||
ReaderURL string
|
||||
BootstrapURL string
|
||||
ReaderPrefix string
|
||||
UsersPrefix string
|
||||
ThingsPrefix string
|
||||
HTTPAdapterPrefix string
|
||||
BootstrapPrefix string
|
||||
MsgContentType ContentType
|
||||
TLSVerification bool
|
||||
}
|
||||
@ -206,10 +225,12 @@ func NewSDK(conf Config) SDK {
|
||||
return &mfSDK{
|
||||
baseURL: conf.BaseURL,
|
||||
readerURL: conf.ReaderURL,
|
||||
bootstrapURL: conf.BootstrapURL,
|
||||
readerPrefix: conf.ReaderPrefix,
|
||||
usersPrefix: conf.UsersPrefix,
|
||||
thingsPrefix: conf.ThingsPrefix,
|
||||
httpAdapterPrefix: conf.HTTPAdapterPrefix,
|
||||
bootstrapPrefix: conf.BootstrapPrefix,
|
||||
msgContentType: conf.MsgContentType,
|
||||
client: &http.Client{
|
||||
Transport: &http.Transport{
|
||||
|
Loading…
x
Reference in New Issue
Block a user