mirror of
https://github.com/absmach/magistrala.git
synced 2026-06-23 04:10:28 +00:00
NOISSUE - Return certs on bootstrap view response (#1855)
* return certs on bootstrap view response Signed-off-by: SammyOina <sammyoina@gmail.com> * return updated certs when updated Signed-off-by: SammyOina <sammyoina@gmail.com> * fix test Signed-off-by: SammyOina <sammyoina@gmail.com> * fix test Signed-off-by: SammyOina <sammyoina@gmail.com> * fix test Signed-off-by: SammyOina <sammyoina@gmail.com> * fix test Signed-off-by: SammyOina <sammyoina@gmail.com> * fix tests Signed-off-by: SammyOina <sammyoina@gmail.com> * simplify tests Signed-off-by: SammyOina <sammyoina@gmail.com> * use named query Signed-off-by: SammyOina <sammyoina@gmail.com> * fix test Signed-off-by: SammyOina <sammyoina@gmail.com> * use named params Signed-off-by: SammyOina <sammyoina@gmail.com> * fix typo Signed-off-by: SammyOina <sammyoina@gmail.com> * use inline error checks remove unrequired conditions Signed-off-by: SammyOina <sammyoina@gmail.com> * sort slices before comparison Signed-off-by: SammyOina <sammyoina@gmail.com> * rename mainflux_id to thing_id rename MFThing to ThingID rename MFKey to ThingKey rename mainflux_key to thing_key Signed-off-by: SammyOina <sammyoina@gmail.com> * remove mainflux_channels Signed-off-by: SammyOina <sammyoina@gmail.com> * simplify unmarshaller Signed-off-by: SammyOina <sammyoina@gmail.com> --------- Signed-off-by: SammyOina <sammyoina@gmail.com>
This commit is contained in:
committed by
GitHub
parent
57d47fea66
commit
b7b14cc8b6
@@ -123,6 +123,7 @@ paths:
|
||||
responses:
|
||||
'200':
|
||||
description: Config updated.
|
||||
$ref: "#/components/responses/ConfigUpdateCertsRes"
|
||||
'400':
|
||||
description: Failed due to malformed JSON.
|
||||
'401':
|
||||
@@ -239,7 +240,7 @@ components:
|
||||
Config:
|
||||
type: object
|
||||
properties:
|
||||
mainflux_id:
|
||||
thing_id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Corresponding Mainflux Thing ID.
|
||||
@@ -247,7 +248,7 @@ components:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Corresponding Mainflux Thing key.
|
||||
mainflux_channels:
|
||||
channels:
|
||||
type: array
|
||||
minItems: 0
|
||||
items:
|
||||
@@ -274,6 +275,12 @@ components:
|
||||
description: Free-form custom configuration.
|
||||
state:
|
||||
$ref: "#/components/schemas/State"
|
||||
client_cert:
|
||||
type: string
|
||||
description: Client certificate.
|
||||
ca_cert:
|
||||
type: string
|
||||
description: Issuing CA certificate.
|
||||
required:
|
||||
- external_id
|
||||
- external_key
|
||||
@@ -305,15 +312,15 @@ components:
|
||||
BootstrapConfig:
|
||||
type: object
|
||||
properties:
|
||||
mainflux_id:
|
||||
thing_id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Corresponding Mainflux Thing ID.
|
||||
mainflux_key:
|
||||
thing_key:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Corresponding Mainflux Thing key.
|
||||
mainflux_channels:
|
||||
channels:
|
||||
type: array
|
||||
minItems: 0
|
||||
items:
|
||||
@@ -331,9 +338,30 @@ components:
|
||||
type: string
|
||||
description: Issuing CA certificate.
|
||||
required:
|
||||
- mainflux_id
|
||||
- mainflux_key
|
||||
- mainflux_channels
|
||||
- thing_id
|
||||
- thing_key
|
||||
- channels
|
||||
- content
|
||||
ConfigUpdateCerts:
|
||||
type: object
|
||||
properties:
|
||||
thing_id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Corresponding Mainflux Thing ID.
|
||||
client_cert:
|
||||
type: string
|
||||
description: Client certificate.
|
||||
client_key:
|
||||
type: string
|
||||
description: Key for the client_cert.
|
||||
ca_cert:
|
||||
type: string
|
||||
description: Issuing CA certificate.
|
||||
required:
|
||||
- thing_id
|
||||
- thing_key
|
||||
- channels
|
||||
- content
|
||||
|
||||
parameters:
|
||||
@@ -511,6 +539,12 @@ components:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
ConfigUpdateCertsRes:
|
||||
description: Data retrieved. Config certs updated.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ConfigUpdateCerts"
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
|
||||
+19
-13
@@ -23,10 +23,10 @@ func addEndpoint(svc bootstrap.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
config := bootstrap.Config{
|
||||
MFThing: req.ThingID,
|
||||
ThingID: req.ThingID,
|
||||
ExternalID: req.ExternalID,
|
||||
ExternalKey: req.ExternalKey,
|
||||
MFChannels: channels,
|
||||
Channels: channels,
|
||||
Name: req.Name,
|
||||
ClientCert: req.ClientCert,
|
||||
ClientKey: req.ClientKey,
|
||||
@@ -40,7 +40,7 @@ func addEndpoint(svc bootstrap.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
res := configRes{
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
created: true,
|
||||
}
|
||||
|
||||
@@ -55,11 +55,17 @@ func updateCertEndpoint(svc bootstrap.Service) endpoint.Endpoint {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := svc.UpdateCert(ctx, req.token, req.thingID, req.ClientCert, req.ClientKey, req.CACert); err != nil {
|
||||
cfg, err := svc.UpdateCert(ctx, req.token, req.thingID, req.ClientCert, req.ClientKey, req.CACert)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := configRes{}
|
||||
res := updateConfigRes{
|
||||
ThingID: cfg.ThingID,
|
||||
ClientCert: cfg.ClientCert,
|
||||
CACert: cfg.CACert,
|
||||
ClientKey: cfg.ClientKey,
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
@@ -79,7 +85,7 @@ func viewEndpoint(svc bootstrap.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
var channels []channelRes
|
||||
for _, ch := range config.MFChannels {
|
||||
for _, ch := range config.Channels {
|
||||
channels = append(channels, channelRes{
|
||||
ID: ch.ID,
|
||||
Name: ch.Name,
|
||||
@@ -88,8 +94,8 @@ func viewEndpoint(svc bootstrap.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
res := viewRes{
|
||||
MFThing: config.MFThing,
|
||||
MFKey: config.MFKey,
|
||||
ThingID: config.ThingID,
|
||||
ThingKey: config.ThingKey,
|
||||
Channels: channels,
|
||||
ExternalID: config.ExternalID,
|
||||
ExternalKey: config.ExternalKey,
|
||||
@@ -111,7 +117,7 @@ func updateEndpoint(svc bootstrap.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
config := bootstrap.Config{
|
||||
MFThing: req.id,
|
||||
ThingID: req.id,
|
||||
Name: req.Name,
|
||||
Content: req.Content,
|
||||
}
|
||||
@@ -121,7 +127,7 @@ func updateEndpoint(svc bootstrap.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
res := configRes{
|
||||
id: config.MFThing,
|
||||
id: config.ThingID,
|
||||
created: false,
|
||||
}
|
||||
|
||||
@@ -171,7 +177,7 @@ func listEndpoint(svc bootstrap.Service) endpoint.Endpoint {
|
||||
|
||||
for _, cfg := range page.Configs {
|
||||
var channels []channelRes
|
||||
for _, ch := range cfg.MFChannels {
|
||||
for _, ch := range cfg.Channels {
|
||||
channels = append(channels, channelRes{
|
||||
ID: ch.ID,
|
||||
Name: ch.Name,
|
||||
@@ -180,8 +186,8 @@ func listEndpoint(svc bootstrap.Service) endpoint.Endpoint {
|
||||
}
|
||||
|
||||
view := viewRes{
|
||||
MFThing: cfg.MFThing,
|
||||
MFKey: cfg.MFKey,
|
||||
ThingID: cfg.ThingID,
|
||||
ThingKey: cfg.ThingKey,
|
||||
Channels: channels,
|
||||
ExternalID: cfg.ExternalID,
|
||||
ExternalKey: cfg.ExternalKey,
|
||||
|
||||
@@ -109,7 +109,7 @@ func newConfig(channels []bootstrap.Channel) bootstrap.Config {
|
||||
return bootstrap.Config{
|
||||
ExternalID: addExternalID,
|
||||
ExternalKey: addExternalKey,
|
||||
MFChannels: channels,
|
||||
Channels: channels,
|
||||
Name: addName,
|
||||
Content: addContent,
|
||||
ClientCert: "newcert",
|
||||
@@ -355,7 +355,7 @@ func TestView(t *testing.T) {
|
||||
|
||||
mfChs := generateChannels()
|
||||
for id, ch := range mfChs {
|
||||
c.MFChannels = append(c.MFChannels, bootstrap.Channel{
|
||||
c.Channels = append(c.Channels, bootstrap.Channel{
|
||||
ID: ch.ID,
|
||||
Name: fmt.Sprintf("%s%s", "name ", id),
|
||||
Metadata: map[string]interface{}{"type": fmt.Sprintf("some type %s", id)},
|
||||
@@ -366,13 +366,13 @@ func TestView(t *testing.T) {
|
||||
assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err))
|
||||
|
||||
var channels []channel
|
||||
for _, ch := range saved.MFChannels {
|
||||
for _, ch := range saved.Channels {
|
||||
channels = append(channels, channel{ID: ch.ID, Name: ch.Name, Metadata: ch.Metadata})
|
||||
}
|
||||
|
||||
data := config{
|
||||
MFThing: saved.MFThing,
|
||||
MFKey: saved.MFKey,
|
||||
ThingID: saved.ThingID,
|
||||
ThingKey: saved.ThingKey,
|
||||
State: saved.State,
|
||||
Channels: channels,
|
||||
ExternalID: saved.ExternalID,
|
||||
@@ -391,14 +391,14 @@ func TestView(t *testing.T) {
|
||||
{
|
||||
desc: "view a config with invalid token",
|
||||
auth: invalidToken,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
status: http.StatusUnauthorized,
|
||||
res: config{},
|
||||
},
|
||||
{
|
||||
desc: "view a config",
|
||||
auth: validToken,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
status: http.StatusOK,
|
||||
res: data,
|
||||
},
|
||||
@@ -412,7 +412,7 @@ func TestView(t *testing.T) {
|
||||
{
|
||||
desc: "view a config with an empty token",
|
||||
auth: "",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
status: http.StatusUnauthorized,
|
||||
res: config{},
|
||||
},
|
||||
@@ -467,7 +467,7 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
desc: "update with invalid token",
|
||||
req: data,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: invalidToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusUnauthorized,
|
||||
@@ -475,7 +475,7 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
desc: "update with an empty token",
|
||||
req: data,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: "",
|
||||
contentType: contentType,
|
||||
status: http.StatusUnauthorized,
|
||||
@@ -483,7 +483,7 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
desc: "update a valid config",
|
||||
req: data,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusOK,
|
||||
@@ -491,7 +491,7 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
desc: "update a config with wrong content type",
|
||||
req: data,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: validToken,
|
||||
contentType: "",
|
||||
status: http.StatusUnsupportedMediaType,
|
||||
@@ -507,14 +507,14 @@ func TestUpdate(t *testing.T) {
|
||||
{
|
||||
desc: "update a config with invalid request format",
|
||||
req: "}",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "update a config with an empty request",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
req: "",
|
||||
auth: validToken,
|
||||
contentType: contentType,
|
||||
@@ -561,7 +561,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
{
|
||||
desc: "update with invalid token",
|
||||
req: data,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: invalidToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusUnauthorized,
|
||||
@@ -569,7 +569,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
{
|
||||
desc: "update with an empty token",
|
||||
req: data,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: "",
|
||||
contentType: contentType,
|
||||
status: http.StatusUnauthorized,
|
||||
@@ -577,7 +577,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
{
|
||||
desc: "update a valid config",
|
||||
req: data,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusOK,
|
||||
@@ -585,7 +585,7 @@ func TestUpdateCert(t *testing.T) {
|
||||
{
|
||||
desc: "update a config with wrong content type",
|
||||
req: data,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: validToken,
|
||||
contentType: "",
|
||||
status: http.StatusUnsupportedMediaType,
|
||||
@@ -601,14 +601,14 @@ func TestUpdateCert(t *testing.T) {
|
||||
{
|
||||
desc: "update a config with invalid request format",
|
||||
req: "}",
|
||||
id: saved.MFKey,
|
||||
id: saved.ThingKey,
|
||||
auth: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "update a config with an empty request",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
req: "",
|
||||
auth: validToken,
|
||||
contentType: contentType,
|
||||
@@ -661,7 +661,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update connections with invalid token",
|
||||
req: data,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: invalidToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusUnauthorized,
|
||||
@@ -669,7 +669,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update connections with an empty token",
|
||||
req: data,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: "",
|
||||
contentType: contentType,
|
||||
status: http.StatusUnauthorized,
|
||||
@@ -677,7 +677,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update connections valid config",
|
||||
req: data,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusOK,
|
||||
@@ -685,7 +685,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update connections with wrong content type",
|
||||
req: data,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: validToken,
|
||||
contentType: "",
|
||||
status: http.StatusUnsupportedMediaType,
|
||||
@@ -701,7 +701,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update connections with invalid channels",
|
||||
req: wrongData,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusBadRequest,
|
||||
@@ -709,14 +709,14 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update a config with invalid request format",
|
||||
req: "}",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: validToken,
|
||||
contentType: contentType,
|
||||
status: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
desc: "update a config with an empty request",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
req: "",
|
||||
auth: validToken,
|
||||
contentType: contentType,
|
||||
@@ -755,7 +755,7 @@ func TestList(t *testing.T) {
|
||||
|
||||
for i := 0; i < configNum; i++ {
|
||||
c.ExternalID = strconv.Itoa(i)
|
||||
c.MFKey = c.ExternalID
|
||||
c.ThingKey = c.ExternalID
|
||||
c.Name = fmt.Sprintf("%s-%d", addName, i)
|
||||
c.ExternalKey = fmt.Sprintf("%s%s", addExternalKey, strconv.Itoa(i))
|
||||
|
||||
@@ -763,12 +763,12 @@ func TestList(t *testing.T) {
|
||||
assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err))
|
||||
|
||||
var channels []channel
|
||||
for _, ch := range saved.MFChannels {
|
||||
for _, ch := range saved.Channels {
|
||||
channels = append(channels, channel{ID: ch.ID, Name: ch.Name, Metadata: ch.Metadata})
|
||||
}
|
||||
s := config{
|
||||
MFThing: saved.MFThing,
|
||||
MFKey: saved.MFKey,
|
||||
ThingID: saved.ThingID,
|
||||
ThingKey: saved.ThingKey,
|
||||
Channels: channels,
|
||||
ExternalID: saved.ExternalID,
|
||||
ExternalKey: saved.ExternalKey,
|
||||
@@ -785,7 +785,7 @@ func TestList(t *testing.T) {
|
||||
if i%2 == 0 {
|
||||
state = bootstrap.Inactive
|
||||
}
|
||||
err := svc.ChangeState(context.Background(), validToken, list[i].MFThing, state)
|
||||
err := svc.ChangeState(context.Background(), validToken, list[i].ThingID, state)
|
||||
assert.Nil(t, err, fmt.Sprintf("Changing state expected to succeed: %s.\n", err))
|
||||
list[i].State = state
|
||||
if state == bootstrap.Inactive {
|
||||
@@ -1009,12 +1009,12 @@ func TestRemove(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "remove with invalid token",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: invalidToken,
|
||||
status: http.StatusUnauthorized,
|
||||
}, {
|
||||
desc: "remove with an empty token",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: "",
|
||||
status: http.StatusUnauthorized,
|
||||
},
|
||||
@@ -1026,7 +1026,7 @@ func TestRemove(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "remove config",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: validToken,
|
||||
status: http.StatusNoContent,
|
||||
},
|
||||
@@ -1067,22 +1067,22 @@ func TestBootstrap(t *testing.T) {
|
||||
assert.Nil(t, err, fmt.Sprintf("Encrypting config expected to succeed: %s.\n", err))
|
||||
|
||||
var channels []channel
|
||||
for _, ch := range saved.MFChannels {
|
||||
for _, ch := range saved.Channels {
|
||||
channels = append(channels, channel{ID: ch.ID, Name: ch.Name, Metadata: ch.Metadata})
|
||||
}
|
||||
|
||||
s := struct {
|
||||
MFThing string `json:"mainflux_id"`
|
||||
MFKey string `json:"mainflux_key"`
|
||||
MFChannels []channel `json:"mainflux_channels"`
|
||||
ThingID string `json:"thing_id"`
|
||||
ThingKey string `json:"thing_key"`
|
||||
Channels []channel `json:"channels"`
|
||||
Content string `json:"content"`
|
||||
ClientCert string `json:"client_cert"`
|
||||
ClientKey string `json:"client_key"`
|
||||
CACert string `json:"ca_cert"`
|
||||
}{
|
||||
MFThing: saved.MFThing,
|
||||
MFKey: saved.MFKey,
|
||||
MFChannels: channels,
|
||||
ThingID: saved.ThingID,
|
||||
ThingKey: saved.ThingKey,
|
||||
Channels: channels,
|
||||
Content: saved.Content,
|
||||
ClientCert: saved.ClientCert,
|
||||
ClientKey: saved.ClientKey,
|
||||
@@ -1205,7 +1205,7 @@ func TestChangeState(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "change state with invalid token",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: invalidToken,
|
||||
state: active,
|
||||
contentType: contentType,
|
||||
@@ -1213,7 +1213,7 @@ func TestChangeState(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "change state with an empty token",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: "",
|
||||
state: active,
|
||||
contentType: contentType,
|
||||
@@ -1221,7 +1221,7 @@ func TestChangeState(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "change state with invalid content type",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: validToken,
|
||||
state: active,
|
||||
contentType: "",
|
||||
@@ -1229,7 +1229,7 @@ func TestChangeState(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "change state to active",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: validToken,
|
||||
state: active,
|
||||
contentType: contentType,
|
||||
@@ -1237,7 +1237,7 @@ func TestChangeState(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "change state to inactive",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: validToken,
|
||||
state: inactive,
|
||||
contentType: contentType,
|
||||
@@ -1253,7 +1253,7 @@ func TestChangeState(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "change state to invalid value",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: validToken,
|
||||
state: fmt.Sprintf("{\"state\": %d}", -3),
|
||||
contentType: contentType,
|
||||
@@ -1261,7 +1261,7 @@ func TestChangeState(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "change state with invalid data",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
auth: validToken,
|
||||
state: "",
|
||||
contentType: contentType,
|
||||
@@ -1291,9 +1291,9 @@ type channel struct {
|
||||
}
|
||||
|
||||
type config struct {
|
||||
MFThing string `json:"mainflux_id,omitempty"`
|
||||
MFKey string `json:"mainflux_key,omitempty"`
|
||||
Channels []channel `json:"mainflux_channels,omitempty"`
|
||||
ThingID string `json:"thing_id,omitempty"`
|
||||
ThingKey string `json:"thing_key,omitempty"`
|
||||
Channels []channel `json:"channels,omitempty"`
|
||||
ExternalID string `json:"external_id"`
|
||||
ExternalKey string `json:"external_key,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
|
||||
@@ -30,7 +30,7 @@ func LoggingMiddleware(svc bootstrap.Service, logger mflog.Logger) bootstrap.Ser
|
||||
// If the request fails, it logs the error.
|
||||
func (lm *loggingMiddleware) Add(ctx context.Context, token string, cfg bootstrap.Config) (saved bootstrap.Config, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method add using token %s with thing %s took %s to complete", token, saved.MFThing, time.Since(begin))
|
||||
message := fmt.Sprintf("Method add using token %s with thing %s took %s to complete", token, saved.ThingID, time.Since(begin))
|
||||
if err != nil {
|
||||
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
|
||||
return
|
||||
@@ -45,7 +45,7 @@ func (lm *loggingMiddleware) Add(ctx context.Context, token string, cfg bootstra
|
||||
// If the request fails, it logs the error.
|
||||
func (lm *loggingMiddleware) View(ctx context.Context, token, id string) (saved bootstrap.Config, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method view using token %s with thing %s took %s to complete", token, saved.MFThing, time.Since(begin))
|
||||
message := fmt.Sprintf("Method view using token %s with thing %s took %s to complete", token, saved.ThingID, time.Since(begin))
|
||||
if err != nil {
|
||||
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
|
||||
return
|
||||
@@ -60,7 +60,7 @@ func (lm *loggingMiddleware) View(ctx context.Context, token, id string) (saved
|
||||
// If the request fails, it logs the error.
|
||||
func (lm *loggingMiddleware) Update(ctx context.Context, token string, cfg bootstrap.Config) (err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method update using token %s with thing %s took %s to complete", token, cfg.MFThing, time.Since(begin))
|
||||
message := fmt.Sprintf("Method update using token %s with thing %s took %s to complete", token, cfg.ThingID, time.Since(begin))
|
||||
if err != nil {
|
||||
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
|
||||
return
|
||||
@@ -73,7 +73,7 @@ func (lm *loggingMiddleware) Update(ctx context.Context, token string, cfg boots
|
||||
|
||||
// UpdateCert logs the update_cert request. It logs token, thing ID and the time it took to complete the request.
|
||||
// If the request fails, it logs the error.
|
||||
func (lm *loggingMiddleware) UpdateCert(ctx context.Context, token, thingID, clientCert, clientKey, caCert string) (err error) {
|
||||
func (lm *loggingMiddleware) UpdateCert(ctx context.Context, token, thingID, clientCert, clientKey, caCert string) (cfg bootstrap.Config, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method update_cert using token %s with thing id %s took %s to complete", token, thingID, time.Since(begin))
|
||||
if err != nil {
|
||||
|
||||
@@ -61,7 +61,7 @@ func (mm *metricsMiddleware) Update(ctx context.Context, token string, cfg boots
|
||||
}
|
||||
|
||||
// UpdateCert instruments UpdateCert method with metrics.
|
||||
func (mm *metricsMiddleware) UpdateCert(ctx context.Context, token, thingKey, clientCert, clientKey, caCert string) (err error) {
|
||||
func (mm *metricsMiddleware) UpdateCert(ctx context.Context, token, thingKey, clientCert, clientKey, caCert string) (cfg bootstrap.Config, err error) {
|
||||
defer func(begin time.Time) {
|
||||
mm.counter.With("method", "update_cert").Add(1)
|
||||
mm.latency.With("method", "update_cert").Observe(time.Since(begin).Seconds())
|
||||
|
||||
@@ -67,14 +67,16 @@ type channelRes struct {
|
||||
}
|
||||
|
||||
type viewRes struct {
|
||||
MFThing string `json:"mainflux_id,omitempty"`
|
||||
MFKey string `json:"mainflux_key,omitempty"`
|
||||
Channels []channelRes `json:"mainflux_channels,omitempty"`
|
||||
ThingID string `json:"thing_id,omitempty"`
|
||||
ThingKey string `json:"thing_key,omitempty"`
|
||||
Channels []channelRes `json:"channels,omitempty"`
|
||||
ExternalID string `json:"external_id"`
|
||||
ExternalKey string `json:"external_key,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
State bootstrap.State `json:"state"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
CACert string `json:"ca_cert,omitempty"`
|
||||
}
|
||||
|
||||
func (res viewRes) Code() int {
|
||||
@@ -121,3 +123,22 @@ func (res stateRes) Headers() map[string]string {
|
||||
func (res stateRes) Empty() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type updateConfigRes struct {
|
||||
ThingID string `json:"thing_id,omitempty"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
CACert string `json:"ca_cert,omitempty"`
|
||||
ClientKey string `json:"client_key,omitempty"`
|
||||
}
|
||||
|
||||
func (res updateConfigRes) Code() int {
|
||||
return http.StatusOK
|
||||
}
|
||||
|
||||
func (res updateConfigRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res updateConfigRes) Empty() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
fullMatch = []string{"state", "external_id", "mainflux_id", "mainflux_key"}
|
||||
fullMatch = []string{"state", "external_id", "thing_id", "thing_key"}
|
||||
partialMatch = []string{"name"}
|
||||
)
|
||||
|
||||
|
||||
@@ -16,14 +16,14 @@ import (
|
||||
// MFKey is key of corresponding Mainflux Thing.
|
||||
// MFChannels is a list of Mainflux Channels corresponding Mainflux Thing connects to.
|
||||
type Config struct {
|
||||
MFThing string `json:"mainflux_thing"`
|
||||
ThingID string `json:"thing_id"`
|
||||
Owner string `json:"owner,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
ClientKey string `json:"client_key,omitempty"`
|
||||
CACert string `json:"ca_cert,omitempty"`
|
||||
MFKey string `json:"mainflux_key"`
|
||||
MFChannels []Channel `json:"mainflux_channels,omitempty"`
|
||||
ThingKey string `json:"thing_key"`
|
||||
Channels []Channel `json:"channels,omitempty"`
|
||||
ExternalID string `json:"external_id"`
|
||||
ExternalKey string `json:"external_key"`
|
||||
Content string `json:"content,omitempty"`
|
||||
@@ -80,9 +80,9 @@ type ConfigRepository interface {
|
||||
// to indicate operation failure.
|
||||
Update(ctx context.Context, cfg Config) error
|
||||
|
||||
// UpdateCerts updates an existing Config certificate and owner.
|
||||
// UpdateCerts updates and returns an existing Config certificate and owner.
|
||||
// A non-nil error is returned to indicate operation failure.
|
||||
UpdateCert(ctx context.Context, owner, thingID, clientCert, clientKey, caCert string) error
|
||||
UpdateCert(ctx context.Context, owner, thingID, clientCert, clientKey, caCert string) (Config, error)
|
||||
|
||||
// UpdateConnections updates a list of Channels the Config is connected to
|
||||
// adding new Channels if needed.
|
||||
|
||||
+22
-22
@@ -38,28 +38,28 @@ func (crm *configRepositoryMock) Save(_ context.Context, config bootstrap.Config
|
||||
defer crm.mu.Unlock()
|
||||
|
||||
for _, v := range crm.configs {
|
||||
if v.MFThing == config.MFThing || v.ExternalID == config.ExternalID {
|
||||
if v.ThingID == config.ThingID || v.ExternalID == config.ExternalID {
|
||||
return "", errors.ErrConflict
|
||||
}
|
||||
}
|
||||
|
||||
crm.counter++
|
||||
config.MFThing = strconv.FormatUint(crm.counter, 10)
|
||||
crm.configs[config.MFThing] = config
|
||||
config.ThingID = strconv.FormatUint(crm.counter, 10)
|
||||
crm.configs[config.ThingID] = config
|
||||
|
||||
for _, ch := range config.MFChannels {
|
||||
for _, ch := range config.Channels {
|
||||
crm.channels[ch.ID] = ch
|
||||
}
|
||||
|
||||
config.MFChannels = []bootstrap.Channel{}
|
||||
config.Channels = []bootstrap.Channel{}
|
||||
|
||||
for _, ch := range connections {
|
||||
config.MFChannels = append(config.MFChannels, crm.channels[ch])
|
||||
config.Channels = append(config.Channels, crm.channels[ch])
|
||||
}
|
||||
|
||||
crm.configs[config.MFThing] = config
|
||||
crm.configs[config.ThingID] = config
|
||||
|
||||
return config.MFThing, nil
|
||||
return config.ThingID, nil
|
||||
}
|
||||
|
||||
func (crm *configRepositoryMock) RetrieveByID(_ context.Context, token, id string) (bootstrap.Config, error) {
|
||||
@@ -99,7 +99,7 @@ func (crm *configRepositoryMock) RetrieveAll(_ context.Context, token string, fi
|
||||
|
||||
var total uint64
|
||||
for _, v := range crm.configs {
|
||||
id, _ := strconv.ParseUint(v.MFThing, 10, 64)
|
||||
id, _ := strconv.ParseUint(v.ThingID, 10, 64)
|
||||
if (state == emptyState || v.State == state) &&
|
||||
(name == "" || strings.Contains(strings.ToLower(v.Name), name)) &&
|
||||
v.Owner == token {
|
||||
@@ -111,7 +111,7 @@ func (crm *configRepositoryMock) RetrieveAll(_ context.Context, token string, fi
|
||||
}
|
||||
|
||||
sort.SliceStable(configs, func(i, j int) bool {
|
||||
return configs[i].MFThing < configs[j].MFThing
|
||||
return configs[i].ThingID < configs[j].ThingID
|
||||
})
|
||||
|
||||
return bootstrap.ConfigsPage{
|
||||
@@ -139,37 +139,37 @@ func (crm *configRepositoryMock) Update(_ context.Context, config bootstrap.Conf
|
||||
crm.mu.Lock()
|
||||
defer crm.mu.Unlock()
|
||||
|
||||
cfg, ok := crm.configs[config.MFThing]
|
||||
cfg, ok := crm.configs[config.ThingID]
|
||||
if !ok || cfg.Owner != config.Owner {
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
|
||||
cfg.Name = config.Name
|
||||
cfg.Content = config.Content
|
||||
crm.configs[config.MFThing] = cfg
|
||||
crm.configs[config.ThingID] = cfg
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (crm *configRepositoryMock) UpdateCert(_ context.Context, owner, thingID, clientCert, clientKey, caCert string) error {
|
||||
func (crm *configRepositoryMock) UpdateCert(_ context.Context, owner, thingID, clientCert, clientKey, caCert string) (bootstrap.Config, error) {
|
||||
crm.mu.Lock()
|
||||
defer crm.mu.Unlock()
|
||||
var forUpdate bootstrap.Config
|
||||
for _, v := range crm.configs {
|
||||
if v.MFThing == thingID && v.Owner == owner {
|
||||
if v.ThingID == thingID && v.Owner == owner {
|
||||
forUpdate = v
|
||||
break
|
||||
}
|
||||
}
|
||||
if _, ok := crm.configs[forUpdate.MFThing]; !ok {
|
||||
return errors.ErrNotFound
|
||||
if _, ok := crm.configs[forUpdate.ThingID]; !ok {
|
||||
return bootstrap.Config{}, errors.ErrNotFound
|
||||
}
|
||||
forUpdate.ClientCert = clientCert
|
||||
forUpdate.ClientKey = clientKey
|
||||
forUpdate.CACert = caCert
|
||||
crm.configs[forUpdate.MFThing] = forUpdate
|
||||
crm.configs[forUpdate.ThingID] = forUpdate
|
||||
|
||||
return nil
|
||||
return forUpdate, nil
|
||||
}
|
||||
|
||||
func (crm *configRepositoryMock) UpdateConnections(_ context.Context, token, id string, channels []bootstrap.Channel, connections []string) error {
|
||||
@@ -185,13 +185,13 @@ func (crm *configRepositoryMock) UpdateConnections(_ context.Context, token, id
|
||||
crm.channels[ch.ID] = ch
|
||||
}
|
||||
|
||||
config.MFChannels = []bootstrap.Channel{}
|
||||
config.Channels = []bootstrap.Channel{}
|
||||
for _, conn := range connections {
|
||||
ch, ok := crm.channels[conn]
|
||||
if !ok {
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
config.MFChannels = append(config.MFChannels, ch)
|
||||
config.Channels = append(config.Channels, ch)
|
||||
}
|
||||
crm.configs[id] = config
|
||||
|
||||
@@ -284,7 +284,7 @@ func (crm *configRepositoryMock) DisconnectThing(_ context.Context, channelID, t
|
||||
|
||||
idx := -1
|
||||
if config, ok := crm.configs[thingID]; ok {
|
||||
for i, ch := range config.MFChannels {
|
||||
for i, ch := range config.Channels {
|
||||
if ch.ID == channelID {
|
||||
idx = i
|
||||
break
|
||||
@@ -292,7 +292,7 @@ func (crm *configRepositoryMock) DisconnectThing(_ context.Context, channelID, t
|
||||
}
|
||||
|
||||
if idx != -1 {
|
||||
config.MFChannels = append(config.MFChannels[0:idx], config.MFChannels[idx:]...)
|
||||
config.Channels = append(config.Channels[0:idx], config.Channels[idx:]...)
|
||||
}
|
||||
crm.configs[thingID] = config
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ func (cr configRepository) Save(ctx context.Context, cfg bootstrap.Config, chsCo
|
||||
return "", errors.Wrap(errors.ErrCreateEntity, e)
|
||||
}
|
||||
|
||||
if err := insertChannels(ctx, cfg.Owner, cfg.MFChannels, tx); err != nil {
|
||||
if err := insertChannels(ctx, cfg.Owner, cfg.Channels, tx); err != nil {
|
||||
cr.rollback("Failed to insert Channels", tx)
|
||||
return "", errors.Wrap(errSaveChannels, err)
|
||||
}
|
||||
@@ -82,26 +82,33 @@ func (cr configRepository) Save(ctx context.Context, cfg bootstrap.Config, chsCo
|
||||
return "", err
|
||||
}
|
||||
|
||||
return cfg.MFThing, nil
|
||||
return cfg.ThingID, nil
|
||||
}
|
||||
|
||||
func (cr configRepository) RetrieveByID(ctx context.Context, owner, id string) (bootstrap.Config, error) {
|
||||
q := `SELECT mainflux_thing, mainflux_key, external_id, external_key, name, content, state
|
||||
q := `SELECT mainflux_thing, mainflux_key, external_id, external_key, name, content, state, client_cert, ca_cert
|
||||
FROM configs
|
||||
WHERE mainflux_thing = $1 AND owner = $2`
|
||||
WHERE mainflux_thing = :mainflux_thing AND owner = :owner`
|
||||
|
||||
dbcfg := dbConfig{
|
||||
MFThing: id,
|
||||
Owner: owner,
|
||||
}
|
||||
|
||||
if err := cr.db.QueryRowxContext(ctx, q, id, owner).StructScan(&dbcfg); err != nil {
|
||||
empty := bootstrap.Config{}
|
||||
row, err := cr.db.NamedQueryContext(ctx, q, dbcfg)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return empty, errors.Wrap(errors.ErrNotFound, err)
|
||||
return bootstrap.Config{}, errors.Wrap(errors.ErrNotFound, err)
|
||||
}
|
||||
|
||||
return empty, errors.Wrap(errors.ErrViewEntity, err)
|
||||
return bootstrap.Config{}, errors.Wrap(errors.ErrViewEntity, err)
|
||||
}
|
||||
|
||||
if ok := row.Next(); !ok {
|
||||
return bootstrap.Config{}, errors.Wrap(errors.ErrNotFound, row.Err())
|
||||
}
|
||||
|
||||
if err := row.StructScan(&dbcfg); err != nil {
|
||||
return bootstrap.Config{}, err
|
||||
}
|
||||
|
||||
q = `SELECT mainflux_channel, name, metadata FROM channels ch
|
||||
@@ -133,7 +140,7 @@ func (cr configRepository) RetrieveByID(ctx context.Context, owner, id string) (
|
||||
}
|
||||
|
||||
cfg := toConfig(dbcfg)
|
||||
cfg.MFChannels = chans
|
||||
cfg.Channels = chans
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
@@ -158,7 +165,7 @@ func (cr configRepository) RetrieveAll(ctx context.Context, owner string, filter
|
||||
|
||||
for rows.Next() {
|
||||
c := bootstrap.Config{Owner: owner}
|
||||
if err := rows.Scan(&c.MFThing, &c.MFKey, &c.ExternalID, &c.ExternalKey, &name, &content, &c.State); err != nil {
|
||||
if err := rows.Scan(&c.ThingID, &c.ThingKey, &c.ExternalID, &c.ExternalKey, &name, &content, &c.State); err != nil {
|
||||
cr.log.Error(fmt.Sprintf("Failed to read retrieved config due to %s", err))
|
||||
return bootstrap.ConfigsPage{}
|
||||
}
|
||||
@@ -187,17 +194,25 @@ func (cr configRepository) RetrieveAll(ctx context.Context, owner string, filter
|
||||
func (cr configRepository) RetrieveByExternalID(ctx context.Context, externalID string) (bootstrap.Config, error) {
|
||||
q := `SELECT mainflux_thing, mainflux_key, external_key, owner, name, client_cert, client_key, ca_cert, content, state
|
||||
FROM configs
|
||||
WHERE external_id = $1`
|
||||
WHERE external_id = :external_id`
|
||||
dbcfg := dbConfig{
|
||||
ExternalID: externalID,
|
||||
}
|
||||
|
||||
if err := cr.db.QueryRowxContext(ctx, q, externalID).StructScan(&dbcfg); err != nil {
|
||||
empty := bootstrap.Config{}
|
||||
row, err := cr.db.NamedQueryContext(ctx, q, dbcfg)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return empty, errors.Wrap(errors.ErrNotFound, err)
|
||||
return bootstrap.Config{}, errors.Wrap(errors.ErrNotFound, err)
|
||||
}
|
||||
return empty, errors.Wrap(errors.ErrViewEntity, err)
|
||||
return bootstrap.Config{}, errors.Wrap(errors.ErrViewEntity, err)
|
||||
}
|
||||
|
||||
if ok := row.Next(); !ok {
|
||||
return bootstrap.Config{}, errors.Wrap(errors.ErrNotFound, row.Err())
|
||||
}
|
||||
|
||||
if err := row.StructScan(&dbcfg); err != nil {
|
||||
return bootstrap.Config{}, errors.Wrap(errors.ErrViewEntity, err)
|
||||
}
|
||||
|
||||
q = `SELECT mainflux_channel, name, metadata FROM channels ch
|
||||
@@ -230,18 +245,22 @@ func (cr configRepository) RetrieveByExternalID(ctx context.Context, externalID
|
||||
}
|
||||
|
||||
cfg := toConfig(dbcfg)
|
||||
cfg.MFChannels = channels
|
||||
cfg.Channels = channels
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func (cr configRepository) Update(ctx context.Context, cfg bootstrap.Config) error {
|
||||
q := `UPDATE configs SET name = $1, content = $2 WHERE mainflux_thing = $3 AND owner = $4`
|
||||
q := `UPDATE configs SET name = :name, content = :content WHERE mainflux_thing = :mainflux_thing AND owner = :owner `
|
||||
|
||||
content := nullString(cfg.Content)
|
||||
name := nullString(cfg.Name)
|
||||
dbcfg := dbConfig{
|
||||
Name: nullString(cfg.Name),
|
||||
Content: nullString(cfg.Content),
|
||||
MFThing: cfg.ThingID,
|
||||
Owner: cfg.Owner,
|
||||
}
|
||||
|
||||
res, err := cr.db.ExecContext(ctx, q, name, content, cfg.MFThing, cfg.Owner)
|
||||
res, err := cr.db.NamedExecContext(ctx, q, dbcfg)
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.ErrUpdateEntity, err)
|
||||
}
|
||||
@@ -258,24 +277,33 @@ func (cr configRepository) Update(ctx context.Context, cfg bootstrap.Config) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cr configRepository) UpdateCert(ctx context.Context, owner, thingID, clientCert, clientKey, caCert string) error {
|
||||
q := `UPDATE configs SET client_cert = $1, client_key = $2, ca_cert = $3 WHERE mainflux_thing = $4 AND owner = $5`
|
||||
func (cr configRepository) UpdateCert(ctx context.Context, owner, thingID, clientCert, clientKey, caCert string) (bootstrap.Config, error) {
|
||||
q := `UPDATE configs SET client_cert = :client_cert, client_key = :client_key, ca_cert = :ca_cert WHERE mainflux_thing = :mainflux_thing AND owner = :owner
|
||||
RETURNING mainflux_thing, client_cert, client_key, ca_cert`
|
||||
|
||||
res, err := cr.db.ExecContext(ctx, q, clientCert, clientKey, caCert, thingID, owner)
|
||||
dbcfg := dbConfig{
|
||||
MFThing: thingID,
|
||||
ClientCert: nullString(clientCert),
|
||||
Owner: owner,
|
||||
ClientKey: nullString(clientKey),
|
||||
CaCert: nullString(caCert),
|
||||
}
|
||||
|
||||
row, err := cr.db.NamedQueryContext(ctx, q, dbcfg)
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.ErrUpdateEntity, err)
|
||||
return bootstrap.Config{}, errors.Wrap(errors.ErrUpdateEntity, err)
|
||||
}
|
||||
defer row.Close()
|
||||
|
||||
if ok := row.Next(); !ok {
|
||||
return bootstrap.Config{}, errors.Wrap(errors.ErrNotFound, row.Err())
|
||||
}
|
||||
|
||||
cnt, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.ErrUpdateEntity, err)
|
||||
if err := row.StructScan(&dbcfg); err != nil {
|
||||
return bootstrap.Config{}, err
|
||||
}
|
||||
|
||||
if cnt == 0 {
|
||||
return errors.ErrNotFound
|
||||
}
|
||||
|
||||
return nil
|
||||
return toConfig(dbcfg), nil
|
||||
}
|
||||
|
||||
func (cr configRepository) UpdateConnections(ctx context.Context, owner, id string, channels []bootstrap.Channel, connections []string) error {
|
||||
@@ -308,8 +336,13 @@ func (cr configRepository) UpdateConnections(ctx context.Context, owner, id stri
|
||||
}
|
||||
|
||||
func (cr configRepository) Remove(ctx context.Context, owner, id string) error {
|
||||
q := `DELETE FROM configs WHERE mainflux_thing = $1 AND owner = $2`
|
||||
if _, err := cr.db.ExecContext(ctx, q, id, owner); err != nil {
|
||||
q := `DELETE FROM configs WHERE mainflux_thing = :mainflux_thing AND owner = :owner`
|
||||
dbcfg := dbConfig{
|
||||
MFThing: id,
|
||||
Owner: owner,
|
||||
}
|
||||
|
||||
if _, err := cr.db.NamedExecContext(ctx, q, dbcfg); err != nil {
|
||||
return errors.Wrap(errors.ErrRemoveEntity, err)
|
||||
}
|
||||
|
||||
@@ -321,9 +354,15 @@ func (cr configRepository) Remove(ctx context.Context, owner, id string) error {
|
||||
}
|
||||
|
||||
func (cr configRepository) ChangeState(ctx context.Context, owner, id string, state bootstrap.State) error {
|
||||
q := `UPDATE configs SET state = $1 WHERE mainflux_thing = $2 AND owner = $3;`
|
||||
q := `UPDATE configs SET state = :state WHERE mainflux_thing = :mainflux_thing AND owner = :owner;`
|
||||
|
||||
res, err := cr.db.ExecContext(ctx, q, state, id, owner)
|
||||
dbcfg := dbConfig{
|
||||
MFThing: id,
|
||||
State: state,
|
||||
Owner: owner,
|
||||
}
|
||||
|
||||
res, err := cr.db.NamedExecContext(ctx, q, dbcfg)
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.ErrUpdateEntity, err)
|
||||
}
|
||||
@@ -485,7 +524,7 @@ func insertConnections(ctx context.Context, cfg bootstrap.Config, connections []
|
||||
conns := []dbConnection{}
|
||||
for _, conn := range connections {
|
||||
dbconn := dbConnection{
|
||||
Config: cfg.MFThing,
|
||||
Config: cfg.ThingID,
|
||||
Channel: conn,
|
||||
ConfigOwner: cfg.Owner,
|
||||
ChannelOwner: cfg.Owner,
|
||||
@@ -586,13 +625,13 @@ type dbConfig struct {
|
||||
|
||||
func toDBConfig(cfg bootstrap.Config) dbConfig {
|
||||
return dbConfig{
|
||||
MFThing: cfg.MFThing,
|
||||
MFThing: cfg.ThingID,
|
||||
Owner: cfg.Owner,
|
||||
Name: nullString(cfg.Name),
|
||||
ClientCert: nullString(cfg.ClientCert),
|
||||
ClientKey: nullString(cfg.ClientKey),
|
||||
CaCert: nullString(cfg.CACert),
|
||||
MFKey: cfg.MFKey,
|
||||
MFKey: cfg.ThingKey,
|
||||
ExternalID: cfg.ExternalID,
|
||||
ExternalKey: cfg.ExternalKey,
|
||||
Content: nullString(cfg.Content),
|
||||
@@ -602,9 +641,9 @@ func toDBConfig(cfg bootstrap.Config) dbConfig {
|
||||
|
||||
func toConfig(dbcfg dbConfig) bootstrap.Config {
|
||||
cfg := bootstrap.Config{
|
||||
MFThing: dbcfg.MFThing,
|
||||
ThingID: dbcfg.MFThing,
|
||||
Owner: dbcfg.Owner,
|
||||
MFKey: dbcfg.MFKey,
|
||||
ThingKey: dbcfg.MFKey,
|
||||
ExternalID: dbcfg.ExternalID,
|
||||
ExternalKey: dbcfg.ExternalKey,
|
||||
State: dbcfg.State,
|
||||
|
||||
@@ -21,12 +21,12 @@ const numConfigs = 10
|
||||
|
||||
var (
|
||||
config = bootstrap.Config{
|
||||
MFThing: "mf-thing",
|
||||
MFKey: "mf-key",
|
||||
ThingID: "mf-thing",
|
||||
ThingKey: "mf-key",
|
||||
ExternalID: "external-id",
|
||||
ExternalKey: "external-key",
|
||||
Owner: "user@email.com",
|
||||
MFChannels: []bootstrap.Channel{
|
||||
Channels: []bootstrap.Channel{
|
||||
{ID: "1", Name: "name 1", Metadata: map[string]interface{}{"meta": 1.0}},
|
||||
{ID: "2", Name: "name 2", Metadata: map[string]interface{}{"meta": 2.0}},
|
||||
},
|
||||
@@ -46,18 +46,18 @@ func TestSave(t *testing.T) {
|
||||
|
||||
duplicateThing := config
|
||||
duplicateThing.ExternalID = diff
|
||||
duplicateThing.MFKey = diff
|
||||
duplicateThing.MFChannels = []bootstrap.Channel{}
|
||||
duplicateThing.ThingKey = diff
|
||||
duplicateThing.Channels = []bootstrap.Channel{}
|
||||
|
||||
duplicateExternal := config
|
||||
duplicateExternal.MFThing = diff
|
||||
duplicateExternal.MFKey = diff
|
||||
duplicateExternal.MFChannels = []bootstrap.Channel{}
|
||||
duplicateExternal.ThingID = diff
|
||||
duplicateExternal.ThingKey = diff
|
||||
duplicateExternal.Channels = []bootstrap.Channel{}
|
||||
|
||||
duplicateChannels := config
|
||||
duplicateChannels.ExternalID = diff
|
||||
duplicateChannels.MFKey = diff
|
||||
duplicateChannels.MFThing = diff
|
||||
duplicateChannels.ThingKey = diff
|
||||
duplicateChannels.ThingID = diff
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@@ -94,7 +94,7 @@ func TestSave(t *testing.T) {
|
||||
id, err := repo.Save(context.Background(), tc.config, tc.connections)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
if err == nil {
|
||||
assert.Equal(t, id, tc.config.MFThing, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.config.MFThing, id))
|
||||
assert.Equal(t, id, tc.config.ThingID, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.config.ThingID, id))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,8 +108,8 @@ func TestRetrieveByID(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
require.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.MFKey = uid.String()
|
||||
c.MFThing = uid.String()
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
id, err := repo.Save(context.Background(), c, channels)
|
||||
@@ -168,15 +168,15 @@ func TestRetrieveAll(t *testing.T) {
|
||||
require.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.ExternalID = uid.String()
|
||||
c.Name = fmt.Sprintf("name %d", i)
|
||||
c.MFThing = uid.String()
|
||||
c.MFKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ThingKey = uid.String()
|
||||
|
||||
if i%2 == 0 {
|
||||
c.State = bootstrap.Active
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
c.MFChannels = nil
|
||||
c.Channels = nil
|
||||
}
|
||||
|
||||
_, err = repo.Save(context.Background(), c, channels)
|
||||
@@ -245,8 +245,8 @@ func TestRetrieveByExternalID(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.MFKey = uid.String()
|
||||
c.MFThing = uid.String()
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
_, err = repo.Save(context.Background(), c, channels)
|
||||
@@ -283,8 +283,8 @@ func TestUpdate(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.MFKey = uid.String()
|
||||
c.MFThing = uid.String()
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
_, err = repo.Save(context.Background(), c, channels)
|
||||
@@ -328,8 +328,8 @@ func TestUpdateCert(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.MFKey = uid.String()
|
||||
c.MFThing = uid.String()
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
_, err = repo.Save(context.Background(), c, channels)
|
||||
@@ -342,36 +342,46 @@ func TestUpdateCert(t *testing.T) {
|
||||
wrongOwner.Owner = "3"
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
thingID string
|
||||
owner string
|
||||
cert string
|
||||
certKey string
|
||||
ca string
|
||||
err error
|
||||
desc string
|
||||
thingID string
|
||||
owner string
|
||||
cert string
|
||||
certKey string
|
||||
ca string
|
||||
expectedConfig bootstrap.Config
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "update with wrong owner",
|
||||
thingID: "",
|
||||
cert: "cert",
|
||||
certKey: "certKey",
|
||||
ca: "",
|
||||
owner: "wrong",
|
||||
err: errors.ErrNotFound,
|
||||
desc: "update with wrong owner",
|
||||
thingID: "",
|
||||
cert: "cert",
|
||||
certKey: "certKey",
|
||||
ca: "",
|
||||
owner: "wrong",
|
||||
expectedConfig: bootstrap.Config{},
|
||||
err: errors.ErrNotFound,
|
||||
},
|
||||
{
|
||||
desc: "update a config",
|
||||
thingID: c.MFThing,
|
||||
thingID: c.ThingID,
|
||||
cert: "cert",
|
||||
certKey: "certKey",
|
||||
ca: "ca",
|
||||
owner: c.Owner,
|
||||
err: nil,
|
||||
expectedConfig: bootstrap.Config{
|
||||
ThingID: c.ThingID,
|
||||
ClientCert: "cert",
|
||||
CACert: "ca",
|
||||
ClientKey: "certKey",
|
||||
Owner: c.Owner,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
err := repo.UpdateCert(context.Background(), tc.owner, tc.thingID, tc.cert, tc.certKey, tc.ca)
|
||||
cfg, err := repo.UpdateCert(context.Background(), tc.owner, tc.thingID, tc.cert, tc.certKey, tc.ca)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
assert.Equal(t, tc.expectedConfig, cfg, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.expectedConfig, cfg))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,8 +394,8 @@ func TestUpdateConnections(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.MFKey = uid.String()
|
||||
c.MFThing = uid.String()
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
_, err = repo.Save(context.Background(), c, channels)
|
||||
@@ -393,11 +403,11 @@ func TestUpdateConnections(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err = uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.MFKey = uid.String()
|
||||
c.MFThing = uid.String()
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
c.MFChannels = []bootstrap.Channel{}
|
||||
c.Channels = []bootstrap.Channel{}
|
||||
c2, err := repo.Save(context.Background(), c, []string{channels[0]})
|
||||
assert.Nil(t, err, fmt.Sprintf("Saving a config expected to succeed: %s.\n", err))
|
||||
|
||||
@@ -420,7 +430,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update connections",
|
||||
owner: config.Owner,
|
||||
id: c.MFThing,
|
||||
id: c.ThingID,
|
||||
channels: nil,
|
||||
connections: []string{channels[1]},
|
||||
err: nil,
|
||||
@@ -436,7 +446,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update connections no channels",
|
||||
owner: config.Owner,
|
||||
id: c.MFThing,
|
||||
id: c.ThingID,
|
||||
channels: nil,
|
||||
connections: nil,
|
||||
err: nil,
|
||||
@@ -457,8 +467,8 @@ func TestRemove(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.MFKey = uid.String()
|
||||
c.MFThing = uid.String()
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
id, err := repo.Save(context.Background(), c, channels)
|
||||
@@ -484,8 +494,8 @@ func TestChangeState(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.MFKey = uid.String()
|
||||
c.MFThing = uid.String()
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
saved, err := repo.Save(context.Background(), c, channels)
|
||||
@@ -540,15 +550,15 @@ func TestListExisting(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.MFKey = uid.String()
|
||||
c.MFThing = uid.String()
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
_, err = repo.Save(context.Background(), c, channels)
|
||||
assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err))
|
||||
|
||||
var chs []bootstrap.Channel
|
||||
chs = append(chs, config.MFChannels...)
|
||||
chs = append(chs, config.Channels...)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@@ -591,8 +601,8 @@ func TestRemoveThing(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.MFKey = uid.String()
|
||||
c.MFThing = uid.String()
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
saved, err := repo.Save(context.Background(), c, channels)
|
||||
@@ -612,14 +622,14 @@ func TestUpdateChannel(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.MFKey = uid.String()
|
||||
c.MFThing = uid.String()
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
_, err = repo.Save(context.Background(), c, channels)
|
||||
assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err))
|
||||
|
||||
id := c.MFChannels[0].ID
|
||||
id := c.Channels[0].ID
|
||||
update := bootstrap.Channel{
|
||||
ID: id,
|
||||
Name: "update name",
|
||||
@@ -628,10 +638,10 @@ func TestUpdateChannel(t *testing.T) {
|
||||
err = repo.UpdateChannel(context.Background(), update)
|
||||
assert.Nil(t, err, fmt.Sprintf("updating config expected to succeed: %s.\n", err))
|
||||
|
||||
cfg, err := repo.RetrieveByID(context.Background(), c.Owner, c.MFThing)
|
||||
cfg, err := repo.RetrieveByID(context.Background(), c.Owner, c.ThingID)
|
||||
assert.Nil(t, err, fmt.Sprintf("Retrieving config expected to succeed: %s.\n", err))
|
||||
var retreved bootstrap.Channel
|
||||
for _, c := range cfg.MFChannels {
|
||||
for _, c := range cfg.Channels {
|
||||
if c.ID == id {
|
||||
retreved = c
|
||||
break
|
||||
@@ -649,19 +659,19 @@ func TestRemoveChannel(t *testing.T) {
|
||||
c := config
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.MFKey = uid.String()
|
||||
c.MFThing = uid.String()
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
_, err = repo.Save(context.Background(), c, channels)
|
||||
assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err))
|
||||
|
||||
err = repo.RemoveChannel(context.Background(), c.MFChannels[0].ID)
|
||||
err = repo.RemoveChannel(context.Background(), c.Channels[0].ID)
|
||||
assert.Nil(t, err, fmt.Sprintf("Retrieving config expected to succeed: %s.\n", err))
|
||||
|
||||
cfg, err := repo.RetrieveByID(context.Background(), c.Owner, c.MFThing)
|
||||
cfg, err := repo.RetrieveByID(context.Background(), c.Owner, c.ThingID)
|
||||
assert.Nil(t, err, fmt.Sprintf("Retrieving config expected to succeed: %s.\n", err))
|
||||
assert.NotContains(t, cfg.MFChannels, c.MFChannels[0], fmt.Sprintf("expected to remove channel %s from %s", c.MFChannels[0], cfg.MFChannels))
|
||||
assert.NotContains(t, cfg.Channels, c.Channels[0], fmt.Sprintf("expected to remove channel %s from %s", c.Channels[0], cfg.Channels))
|
||||
}
|
||||
|
||||
func TestDisconnectThing(t *testing.T) {
|
||||
@@ -673,17 +683,17 @@ func TestDisconnectThing(t *testing.T) {
|
||||
// Use UUID to prevent conflicts.
|
||||
uid, err := uuid.NewV4()
|
||||
assert.Nil(t, err, fmt.Sprintf("Got unexpected error: %s.\n", err))
|
||||
c.MFKey = uid.String()
|
||||
c.MFThing = uid.String()
|
||||
c.ThingKey = uid.String()
|
||||
c.ThingID = uid.String()
|
||||
c.ExternalID = uid.String()
|
||||
c.ExternalKey = uid.String()
|
||||
saved, err := repo.Save(context.Background(), c, channels)
|
||||
assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err))
|
||||
|
||||
err = repo.DisconnectThing(context.Background(), c.MFChannels[0].ID, saved)
|
||||
err = repo.DisconnectThing(context.Background(), c.Channels[0].ID, saved)
|
||||
assert.Nil(t, err, fmt.Sprintf("Retrieving config expected to succeed: %s.\n", err))
|
||||
|
||||
cfg, err := repo.RetrieveByID(context.Background(), c.Owner, c.MFThing)
|
||||
cfg, err := repo.RetrieveByID(context.Background(), c.Owner, c.ThingID)
|
||||
assert.Nil(t, err, fmt.Sprintf("Retrieving config expected to succeed: %s.\n", err))
|
||||
assert.Equal(t, cfg.State, bootstrap.Inactive, fmt.Sprintf("expected ti be inactive when a connection is removed from %s", cfg))
|
||||
}
|
||||
|
||||
+7
-7
@@ -16,9 +16,9 @@ import (
|
||||
// This is used as a response from ConfigReader and can easily be
|
||||
// replace with any other response format.
|
||||
type bootstrapRes struct {
|
||||
MFThing string `json:"mainflux_id"`
|
||||
MFKey string `json:"mainflux_key"`
|
||||
MFChannels []channelRes `json:"mainflux_channels"`
|
||||
ThingID string `json:"thing_id"`
|
||||
ThingKey string `json:"thing_key"`
|
||||
Channels []channelRes `json:"channels"`
|
||||
Content string `json:"content,omitempty"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
ClientKey string `json:"client_key,omitempty"`
|
||||
@@ -55,14 +55,14 @@ func NewConfigReader(encKey []byte) ConfigReader {
|
||||
|
||||
func (r reader) ReadConfig(cfg Config, secure bool) (interface{}, error) {
|
||||
var channels []channelRes
|
||||
for _, ch := range cfg.MFChannels {
|
||||
for _, ch := range cfg.Channels {
|
||||
channels = append(channels, channelRes{ID: ch.ID, Name: ch.Name, Metadata: ch.Metadata})
|
||||
}
|
||||
|
||||
res := bootstrapRes{
|
||||
MFKey: cfg.MFKey,
|
||||
MFThing: cfg.MFThing,
|
||||
MFChannels: channels,
|
||||
ThingKey: cfg.ThingKey,
|
||||
ThingID: cfg.ThingID,
|
||||
Channels: channels,
|
||||
Content: cfg.Content,
|
||||
ClientCert: cfg.ClientCert,
|
||||
ClientKey: cfg.ClientKey,
|
||||
|
||||
@@ -24,9 +24,9 @@ type readChan struct {
|
||||
}
|
||||
|
||||
type readResp struct {
|
||||
MFThing string `json:"mainflux_id"`
|
||||
MFKey string `json:"mainflux_key"`
|
||||
MFChannels []readChan `json:"mainflux_channels"`
|
||||
ThingID string `json:"thing_id"`
|
||||
ThingKey string `json:"thing_key"`
|
||||
Channels []readChan `json:"channels"`
|
||||
Content string `json:"content,omitempty"`
|
||||
ClientCert string `json:"client_cert,omitempty"`
|
||||
ClientKey string `json:"client_key,omitempty"`
|
||||
@@ -50,12 +50,12 @@ func dec(in []byte) ([]byte, error) {
|
||||
|
||||
func TestReadConfig(t *testing.T) {
|
||||
cfg := bootstrap.Config{
|
||||
MFThing: "mf_id",
|
||||
ThingID: "mf_id",
|
||||
ClientCert: "client_cert",
|
||||
ClientKey: "client_key",
|
||||
CACert: "ca_cert",
|
||||
MFKey: "mf_key",
|
||||
MFChannels: []bootstrap.Channel{
|
||||
ThingKey: "mf_key",
|
||||
Channels: []bootstrap.Channel{
|
||||
{
|
||||
ID: "mf_id",
|
||||
Name: "mf_name",
|
||||
@@ -65,9 +65,9 @@ func TestReadConfig(t *testing.T) {
|
||||
Content: "content",
|
||||
}
|
||||
ret := readResp{
|
||||
MFThing: "mf_id",
|
||||
MFKey: "mf_key",
|
||||
MFChannels: []readChan{
|
||||
ThingID: "mf_id",
|
||||
ThingKey: "mf_key",
|
||||
Channels: []readChan{
|
||||
{
|
||||
ID: "mf_id",
|
||||
Name: "mf_name",
|
||||
|
||||
@@ -57,8 +57,8 @@ func (ce configEvent) encode() (map[string]interface{}, error) {
|
||||
"state": ce.State.String(),
|
||||
"operation": ce.operation,
|
||||
}
|
||||
if ce.MFThing != "" {
|
||||
val["mainflux_thing"] = ce.MFThing
|
||||
if ce.ThingID != "" {
|
||||
val["thing_id"] = ce.ThingID
|
||||
}
|
||||
if ce.Content != "" {
|
||||
val["content"] = ce.Content
|
||||
@@ -72,9 +72,9 @@ func (ce configEvent) encode() (map[string]interface{}, error) {
|
||||
if ce.ExternalID != "" {
|
||||
val["external_id"] = ce.ExternalID
|
||||
}
|
||||
if len(ce.MFChannels) > 0 {
|
||||
channels := make([]string, len(ce.MFChannels))
|
||||
for i, ch := range ce.MFChannels {
|
||||
if len(ce.Channels) > 0 {
|
||||
channels := make([]string, len(ce.Channels))
|
||||
for i, ch := range ce.Channels {
|
||||
channels[i] = ch.ID
|
||||
}
|
||||
val["channels"] = fmt.Sprintf("[%s]", strings.Join(channels, ", "))
|
||||
@@ -152,8 +152,8 @@ func (be bootstrapEvent) encode() (map[string]interface{}, error) {
|
||||
"operation": thingBootstrap,
|
||||
}
|
||||
|
||||
if be.MFThing != "" {
|
||||
val["mainflux_thing"] = be.MFThing
|
||||
if be.ThingID != "" {
|
||||
val["thing_id"] = be.ThingID
|
||||
}
|
||||
if be.Content != "" {
|
||||
val["content"] = be.Content
|
||||
@@ -167,9 +167,9 @@ func (be bootstrapEvent) encode() (map[string]interface{}, error) {
|
||||
if be.ExternalID != "" {
|
||||
val["external_id"] = be.ExternalID
|
||||
}
|
||||
if len(be.MFChannels) > 0 {
|
||||
channels := make([]string, len(be.MFChannels))
|
||||
for i, ch := range be.MFChannels {
|
||||
if len(be.Channels) > 0 {
|
||||
channels := make([]string, len(be.Channels))
|
||||
for i, ch := range be.Channels {
|
||||
channels[i] = ch.ID
|
||||
}
|
||||
val["channels"] = fmt.Sprintf("[%s]", strings.Join(channels, ", "))
|
||||
|
||||
@@ -77,9 +77,10 @@ func (es eventStore) Update(ctx context.Context, token string, cfg bootstrap.Con
|
||||
return es.add(ctx, ev)
|
||||
}
|
||||
|
||||
func (es eventStore) UpdateCert(ctx context.Context, token, thingKey, clientCert, clientKey, caCert string) error {
|
||||
if err := es.svc.UpdateCert(ctx, token, thingKey, clientCert, clientKey, caCert); err != nil {
|
||||
return err
|
||||
func (es eventStore) UpdateCert(ctx context.Context, token, thingKey, clientCert, clientKey, caCert string) (bootstrap.Config, error) {
|
||||
cfg, err := es.svc.UpdateCert(ctx, token, thingKey, clientCert, clientKey, caCert)
|
||||
if err != nil {
|
||||
return bootstrap.Config{}, err
|
||||
}
|
||||
|
||||
ev := updateCertEvent{
|
||||
@@ -89,7 +90,7 @@ func (es eventStore) UpdateCert(ctx context.Context, token, thingKey, clientCert
|
||||
caCert: caCert,
|
||||
}
|
||||
|
||||
return es.add(ctx, ev)
|
||||
return cfg, es.add(ctx, ev)
|
||||
}
|
||||
|
||||
func (es eventStore) UpdateConnections(ctx context.Context, token, id string, connections []string) error {
|
||||
|
||||
@@ -66,7 +66,7 @@ var (
|
||||
config = bootstrap.Config{
|
||||
ExternalID: "external_id",
|
||||
ExternalKey: "external_key",
|
||||
MFChannels: []bootstrap.Channel{channel},
|
||||
Channels: []bootstrap.Channel{channel},
|
||||
Content: "config",
|
||||
}
|
||||
)
|
||||
@@ -119,13 +119,13 @@ func TestAdd(t *testing.T) {
|
||||
svc = producer.NewEventStoreMiddleware(svc, redisClient)
|
||||
|
||||
var channels []string
|
||||
for _, ch := range config.MFChannels {
|
||||
for _, ch := range config.Channels {
|
||||
channels = append(channels, ch.ID)
|
||||
}
|
||||
|
||||
invalidConfig := config
|
||||
invalidConfig.MFChannels = []bootstrap.Channel{{ID: "empty"}}
|
||||
invalidConfig.MFChannels = []bootstrap.Channel{{ID: "empty"}}
|
||||
invalidConfig.Channels = []bootstrap.Channel{{ID: "empty"}}
|
||||
invalidConfig.Channels = []bootstrap.Channel{{ID: "empty"}}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@@ -188,10 +188,10 @@ func TestView(t *testing.T) {
|
||||
saved, err := svc.Add(context.Background(), validToken, config)
|
||||
assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err))
|
||||
|
||||
svcConfig, svcErr := svc.View(context.Background(), validToken, saved.MFThing)
|
||||
svcConfig, svcErr := svc.View(context.Background(), validToken, saved.ThingID)
|
||||
|
||||
svc = producer.NewEventStoreMiddleware(svc, redisClient)
|
||||
esConfig, esErr := svc.View(context.Background(), validToken, saved.MFThing)
|
||||
esConfig, esErr := svc.View(context.Background(), validToken, saved.ThingID)
|
||||
|
||||
assert.Equal(t, svcConfig, esConfig, fmt.Sprintf("event sourcing changed service behavior: expected %v got %v", svcConfig, esConfig))
|
||||
assert.Equal(t, svcErr, esErr, fmt.Sprintf("event sourcing changed service behavior: expected %v got %v", svcErr, esErr))
|
||||
@@ -210,7 +210,7 @@ func TestUpdate(t *testing.T) {
|
||||
|
||||
ch := channel
|
||||
ch.ID = "2"
|
||||
c.MFChannels = append(c.MFChannels, ch)
|
||||
c.Channels = append(c.Channels, ch)
|
||||
saved, err := svc.Add(context.Background(), validToken, c)
|
||||
require.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err))
|
||||
|
||||
@@ -222,7 +222,7 @@ func TestUpdate(t *testing.T) {
|
||||
modified.Name = "new name"
|
||||
|
||||
nonExisting := config
|
||||
nonExisting.MFThing = "unknown"
|
||||
nonExisting.ThingID = "unknown"
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@@ -237,15 +237,15 @@ func TestUpdate(t *testing.T) {
|
||||
token: validToken,
|
||||
err: nil,
|
||||
event: map[string]interface{}{
|
||||
"name": modified.Name,
|
||||
"content": modified.Content,
|
||||
"timestamp": time.Now().Unix(),
|
||||
"operation": configUpdate,
|
||||
"channels": "[1, 2]",
|
||||
"external_id": "external_id",
|
||||
"mainflux_thing": "1",
|
||||
"owner": email,
|
||||
"state": "0",
|
||||
"name": modified.Name,
|
||||
"content": modified.Content,
|
||||
"timestamp": time.Now().Unix(),
|
||||
"operation": configUpdate,
|
||||
"channels": "[1, 2]",
|
||||
"external_id": "external_id",
|
||||
"thing_id": "1",
|
||||
"owner": email,
|
||||
"state": "0",
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -304,12 +304,12 @@ func TestUpdateConnections(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "update connections successfully",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
token: validToken,
|
||||
connections: []string{"2"},
|
||||
err: nil,
|
||||
event: map[string]interface{}{
|
||||
"thing_id": saved.MFThing,
|
||||
"thing_id": saved.ThingID,
|
||||
"channels": "2",
|
||||
"timestamp": time.Now().Unix(),
|
||||
"operation": thingUpdateConnections,
|
||||
@@ -317,7 +317,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "update connections unsuccessfully",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
token: validToken,
|
||||
connections: []string{"256"},
|
||||
err: errors.ErrMalformedEntity,
|
||||
@@ -388,18 +388,18 @@ func TestRemove(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "remove config successfully",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
token: validToken,
|
||||
err: nil,
|
||||
event: map[string]interface{}{
|
||||
"thing_id": saved.MFThing,
|
||||
"thing_id": saved.ThingID,
|
||||
"timestamp": time.Now().Unix(),
|
||||
"operation": configRemove,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "remove config with invalid credentials",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
token: "",
|
||||
err: errors.ErrAuthentication,
|
||||
event: nil,
|
||||
@@ -522,12 +522,12 @@ func TestChangeState(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "change state to active",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
token: validToken,
|
||||
state: bootstrap.Active,
|
||||
err: nil,
|
||||
event: map[string]interface{}{
|
||||
"thing_id": saved.MFThing,
|
||||
"thing_id": saved.ThingID,
|
||||
"state": bootstrap.Active.String(),
|
||||
"timestamp": time.Now().Unix(),
|
||||
"operation": thingStateChange,
|
||||
@@ -535,7 +535,7 @@ func TestChangeState(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "change state invalid credentials",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
token: "",
|
||||
state: bootstrap.Inactive,
|
||||
err: errors.ErrAuthentication,
|
||||
|
||||
+22
-21
@@ -60,7 +60,7 @@ type Service interface {
|
||||
|
||||
// UpdateCert updates an existing Config certificate and token.
|
||||
// A non-nil error is returned to indicate operation failure.
|
||||
UpdateCert(ctx context.Context, token, thingID, clientCert, clientKey, caCert string) error
|
||||
UpdateCert(ctx context.Context, token, thingID, clientCert, clientKey, caCert string) (Config, error)
|
||||
|
||||
// UpdateConnections updates list of Channels related to given Config.
|
||||
UpdateConnections(ctx context.Context, token, id string, connections []string) error
|
||||
@@ -125,7 +125,7 @@ func (bs bootstrapService) Add(ctx context.Context, token string, cfg Config) (C
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
toConnect := bs.toIDList(cfg.MFChannels)
|
||||
toConnect := bs.toIDList(cfg.Channels)
|
||||
|
||||
// Check if channels exist. This is the way to prevent fetching channels that already exist.
|
||||
existing, err := bs.configs.ListExisting(ctx, owner, toConnect)
|
||||
@@ -133,35 +133,35 @@ func (bs bootstrapService) Add(ctx context.Context, token string, cfg Config) (C
|
||||
return Config{}, errors.Wrap(errCheckChannels, err)
|
||||
}
|
||||
|
||||
cfg.MFChannels, err = bs.connectionChannels(toConnect, bs.toIDList(existing), token)
|
||||
cfg.Channels, err = bs.connectionChannels(toConnect, bs.toIDList(existing), token)
|
||||
|
||||
if err != nil {
|
||||
return Config{}, errors.Wrap(errConnectionChannels, err)
|
||||
}
|
||||
|
||||
id := cfg.MFThing
|
||||
id := cfg.ThingID
|
||||
mfThing, err := bs.thing(id, token)
|
||||
if err != nil {
|
||||
return Config{}, errors.Wrap(errThingNotFound, err)
|
||||
}
|
||||
|
||||
cfg.MFThing = mfThing.ID
|
||||
cfg.ThingID = mfThing.ID
|
||||
cfg.Owner = owner
|
||||
cfg.State = Inactive
|
||||
cfg.MFKey = mfThing.Credentials.Secret
|
||||
cfg.ThingKey = mfThing.Credentials.Secret
|
||||
|
||||
saved, err := bs.configs.Save(ctx, cfg, toConnect)
|
||||
if err != nil {
|
||||
if id == "" {
|
||||
if _, errT := bs.sdk.DisableThing(cfg.MFThing, token); errT != nil {
|
||||
if _, errT := bs.sdk.DisableThing(cfg.ThingID, token); errT != nil {
|
||||
err = errors.Wrap(err, errT)
|
||||
}
|
||||
}
|
||||
return Config{}, errors.Wrap(errAddBootstrap, err)
|
||||
}
|
||||
|
||||
cfg.MFThing = saved
|
||||
cfg.MFChannels = append(cfg.MFChannels, existing...)
|
||||
cfg.ThingID = saved
|
||||
cfg.Channels = append(cfg.Channels, existing...)
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
@@ -186,15 +186,16 @@ func (bs bootstrapService) Update(ctx context.Context, token string, cfg Config)
|
||||
return bs.configs.Update(ctx, cfg)
|
||||
}
|
||||
|
||||
func (bs bootstrapService) UpdateCert(ctx context.Context, token, thingID, clientCert, clientKey, caCert string) error {
|
||||
func (bs bootstrapService) UpdateCert(ctx context.Context, token, thingID, clientCert, clientKey, caCert string) (Config, error) {
|
||||
owner, err := bs.identify(ctx, token)
|
||||
if err != nil {
|
||||
return err
|
||||
return Config{}, err
|
||||
}
|
||||
if err := bs.configs.UpdateCert(ctx, owner, thingID, clientCert, clientKey, caCert); err != nil {
|
||||
return errors.Wrap(errUpdateCert, err)
|
||||
cfg, err := bs.configs.UpdateCert(ctx, owner, thingID, clientCert, clientKey, caCert)
|
||||
if err != nil {
|
||||
return Config{}, errors.Wrap(errUpdateCert, err)
|
||||
}
|
||||
return nil
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func (bs bootstrapService) UpdateConnections(ctx context.Context, token, id string, connections []string) error {
|
||||
@@ -221,7 +222,7 @@ func (bs bootstrapService) UpdateConnections(ctx context.Context, token, id stri
|
||||
return errors.Wrap(errUpdateConnections, err)
|
||||
}
|
||||
|
||||
cfg.MFChannels = channels
|
||||
cfg.Channels = channels
|
||||
var connect, disconnect []string
|
||||
|
||||
if cfg.State == Active {
|
||||
@@ -307,18 +308,18 @@ func (bs bootstrapService) ChangeState(ctx context.Context, token, id string, st
|
||||
|
||||
switch state {
|
||||
case Active:
|
||||
for _, c := range cfg.MFChannels {
|
||||
for _, c := range cfg.Channels {
|
||||
conIDs := mfsdk.ConnectionIDs{
|
||||
ChannelIDs: []string{c.ID},
|
||||
ThingIDs: []string{cfg.MFThing},
|
||||
ThingIDs: []string{cfg.ThingID},
|
||||
}
|
||||
if err := bs.sdk.Connect(conIDs, token); err != nil {
|
||||
return ErrThings
|
||||
}
|
||||
}
|
||||
case Inactive:
|
||||
for _, c := range cfg.MFChannels {
|
||||
if err := bs.sdk.DisconnectThing(cfg.MFThing, c.ID, token); err != nil {
|
||||
for _, c := range cfg.Channels {
|
||||
if err := bs.sdk.DisconnectThing(cfg.ThingID, c.ID, token); err != nil {
|
||||
if errors.Contains(err, errors.ErrNotFound) {
|
||||
continue
|
||||
}
|
||||
@@ -433,8 +434,8 @@ func (bs bootstrapService) connectionChannels(channels, existing []string, token
|
||||
// 2) IDs of Channels to be removed
|
||||
// 3) IDs of common Channels for these two configs.
|
||||
func (bs bootstrapService) updateList(cfg Config, connections []string) (add, remove []string) {
|
||||
disconnect := make(map[string]bool, len(cfg.MFChannels))
|
||||
for _, c := range cfg.MFChannels {
|
||||
disconnect := make(map[string]bool, len(cfg.Channels))
|
||||
for _, c := range cfg.Channels {
|
||||
disconnect[c.ID] = true
|
||||
}
|
||||
|
||||
|
||||
+74
-50
@@ -12,6 +12,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http/httptest"
|
||||
"sort"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
@@ -57,7 +58,7 @@ var (
|
||||
config = bootstrap.Config{
|
||||
ExternalID: "external_id",
|
||||
ExternalKey: "external_key",
|
||||
MFChannels: []bootstrap.Channel{channel},
|
||||
Channels: []bootstrap.Channel{channel},
|
||||
Content: "config",
|
||||
}
|
||||
)
|
||||
@@ -122,12 +123,12 @@ func TestAdd(t *testing.T) {
|
||||
svc := newService(users, server.URL)
|
||||
|
||||
neID := config
|
||||
neID.MFThing = "non-existent"
|
||||
neID.ThingID = "non-existent"
|
||||
|
||||
wrongChannels := config
|
||||
ch := channel
|
||||
ch.ID = "invalid"
|
||||
wrongChannels.MFChannels = append(wrongChannels.MFChannels, ch)
|
||||
wrongChannels.Channels = append(wrongChannels.Channels, ch)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@@ -184,7 +185,7 @@ func TestView(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "view an existing config",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
token: validToken,
|
||||
err: nil,
|
||||
},
|
||||
@@ -196,7 +197,7 @@ func TestView(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "view a config with wrong credentials",
|
||||
id: config.MFThing,
|
||||
id: config.ThingID,
|
||||
token: invalidToken,
|
||||
err: errors.ErrAuthentication,
|
||||
},
|
||||
@@ -217,7 +218,7 @@ func TestUpdate(t *testing.T) {
|
||||
|
||||
ch := channel
|
||||
ch.ID = "2"
|
||||
c.MFChannels = append(c.MFChannels, ch)
|
||||
c.Channels = append(c.Channels, ch)
|
||||
saved, err := svc.Add(context.Background(), validToken, c)
|
||||
assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err))
|
||||
|
||||
@@ -226,7 +227,7 @@ func TestUpdate(t *testing.T) {
|
||||
modifiedCreated.Name = "new name"
|
||||
|
||||
nonExisting := config
|
||||
nonExisting.MFThing = unknown
|
||||
nonExisting.ThingID = unknown
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@@ -269,52 +270,75 @@ func TestUpdateCert(t *testing.T) {
|
||||
|
||||
ch := channel
|
||||
ch.ID = "2"
|
||||
c.MFChannels = append(c.MFChannels, ch)
|
||||
c.Channels = append(c.Channels, ch)
|
||||
saved, err := svc.Add(context.Background(), validToken, c)
|
||||
assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err))
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
thingKey string
|
||||
clientCert string
|
||||
clientKey string
|
||||
caCert string
|
||||
err error
|
||||
desc string
|
||||
token string
|
||||
thingKey string
|
||||
clientCert string
|
||||
clientKey string
|
||||
caCert string
|
||||
expectedConfig bootstrap.Config
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "update certs for the valid config",
|
||||
thingKey: saved.MFKey,
|
||||
thingKey: saved.ThingKey,
|
||||
clientCert: "newCert",
|
||||
clientKey: "newKey",
|
||||
caCert: "newCert",
|
||||
token: validToken,
|
||||
err: nil,
|
||||
expectedConfig: bootstrap.Config{
|
||||
Name: saved.Name,
|
||||
ThingKey: saved.ThingKey,
|
||||
Channels: saved.Channels,
|
||||
ExternalID: saved.ExternalID,
|
||||
ExternalKey: saved.ExternalKey,
|
||||
Content: saved.Content,
|
||||
State: saved.State,
|
||||
Owner: saved.Owner,
|
||||
ThingID: saved.ThingID,
|
||||
ClientCert: "newCert",
|
||||
CACert: "newCert",
|
||||
ClientKey: "newKey",
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update cert for a non-existing config",
|
||||
thingKey: "empty",
|
||||
clientCert: "newCert",
|
||||
clientKey: "newKey",
|
||||
caCert: "newCert",
|
||||
|
||||
token: validToken,
|
||||
err: errors.ErrNotFound,
|
||||
desc: "update cert for a non-existing config",
|
||||
thingKey: "empty",
|
||||
clientCert: "newCert",
|
||||
clientKey: "newKey",
|
||||
caCert: "newCert",
|
||||
token: validToken,
|
||||
expectedConfig: bootstrap.Config{},
|
||||
err: errors.ErrNotFound,
|
||||
},
|
||||
{
|
||||
desc: "update config cert with wrong credentials",
|
||||
thingKey: saved.MFKey,
|
||||
clientCert: "newCert",
|
||||
clientKey: "newKey",
|
||||
caCert: "newCert",
|
||||
token: invalidToken,
|
||||
err: errors.ErrAuthentication,
|
||||
desc: "update config cert with wrong credentials",
|
||||
thingKey: saved.ThingKey,
|
||||
clientCert: "newCert",
|
||||
clientKey: "newKey",
|
||||
caCert: "newCert",
|
||||
token: invalidToken,
|
||||
expectedConfig: bootstrap.Config{},
|
||||
err: errors.ErrAuthentication,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
err := svc.UpdateCert(context.Background(), tc.token, tc.thingKey, tc.clientCert, tc.clientKey, tc.caCert)
|
||||
cfg, err := svc.UpdateCert(context.Background(), tc.token, tc.thingKey, tc.clientCert, tc.clientKey, tc.caCert)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
sort.Slice(cfg.Channels, func(i, j int) bool {
|
||||
return cfg.Channels[i].ID < cfg.Channels[j].ID
|
||||
})
|
||||
sort.Slice(tc.expectedConfig.Channels, func(i, j int) bool {
|
||||
return tc.expectedConfig.Channels[i].ID < tc.expectedConfig.Channels[j].ID
|
||||
})
|
||||
assert.Equal(t, tc.expectedConfig, cfg, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.expectedConfig, cfg))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,7 +351,7 @@ func TestUpdateConnections(t *testing.T) {
|
||||
|
||||
ch := channel
|
||||
ch.ID = "2"
|
||||
c.MFChannels = append(c.MFChannels, ch)
|
||||
c.Channels = append(c.Channels, ch)
|
||||
created, err := svc.Add(context.Background(), validToken, c)
|
||||
assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err))
|
||||
|
||||
@@ -336,11 +360,11 @@ func TestUpdateConnections(t *testing.T) {
|
||||
c.ExternalID = externalID.String()
|
||||
active, err := svc.Add(context.Background(), validToken, c)
|
||||
assert.Nil(t, err, fmt.Sprintf("Saving config expected to succeed: %s.\n", err))
|
||||
err = svc.ChangeState(context.Background(), validToken, active.MFThing, bootstrap.Active)
|
||||
err = svc.ChangeState(context.Background(), validToken, active.ThingID, bootstrap.Active)
|
||||
assert.Nil(t, err, fmt.Sprintf("Changing state expected to succeed: %s.\n", err))
|
||||
|
||||
nonExisting := config
|
||||
nonExisting.MFThing = unknown
|
||||
nonExisting.ThingID = unknown
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
@@ -352,14 +376,14 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update connections for config with state Inactive",
|
||||
token: validToken,
|
||||
id: created.MFThing,
|
||||
id: created.ThingID,
|
||||
connections: []string{"2"},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "update connections for config with state Active",
|
||||
token: validToken,
|
||||
id: active.MFThing,
|
||||
id: active.ThingID,
|
||||
connections: []string{"3"},
|
||||
err: nil,
|
||||
},
|
||||
@@ -373,14 +397,14 @@ func TestUpdateConnections(t *testing.T) {
|
||||
{
|
||||
desc: "update connections with invalid channels",
|
||||
token: validToken,
|
||||
id: created.MFThing,
|
||||
id: created.ThingID,
|
||||
connections: []string{"wrong"},
|
||||
err: errors.ErrMalformedEntity,
|
||||
},
|
||||
{
|
||||
desc: "update connections a config with wrong credentials",
|
||||
token: invalidToken,
|
||||
id: created.MFKey,
|
||||
id: created.ThingKey,
|
||||
connections: []string{"2", "3"},
|
||||
err: errors.ErrAuthentication,
|
||||
},
|
||||
@@ -517,19 +541,19 @@ func TestRemove(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "view a config with wrong credentials",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
token: invalidToken,
|
||||
err: errors.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "remove an existing config",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
token: validToken,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "remove removed config",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
token: validToken,
|
||||
err: nil,
|
||||
},
|
||||
@@ -627,7 +651,7 @@ func TestChangeState(t *testing.T) {
|
||||
{
|
||||
desc: "change state with wrong credentials",
|
||||
state: bootstrap.Active,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
token: invalidToken,
|
||||
err: errors.ErrAuthentication,
|
||||
},
|
||||
@@ -641,21 +665,21 @@ func TestChangeState(t *testing.T) {
|
||||
{
|
||||
desc: "change state to Active",
|
||||
state: bootstrap.Active,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
token: validToken,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "change state to current state",
|
||||
state: bootstrap.Active,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
token: validToken,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "change state to Inactive",
|
||||
state: bootstrap.Inactive,
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
token: validToken,
|
||||
err: nil,
|
||||
},
|
||||
@@ -752,7 +776,7 @@ func TestRemoveCoinfigHandler(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
desc: "remove an existing config",
|
||||
id: saved.MFThing,
|
||||
id: saved.ThingID,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
@@ -786,13 +810,13 @@ func TestDisconnectThingsHandler(t *testing.T) {
|
||||
{
|
||||
desc: "disconnect",
|
||||
channelID: channel.ID,
|
||||
thingID: saved.MFThing,
|
||||
thingID: saved.ThingID,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "disconnect disconnected",
|
||||
channelID: channel.ID,
|
||||
thingID: saved.MFThing,
|
||||
thingID: saved.ThingID,
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ func New(svc bootstrap.Service, tracer trace.Tracer) bootstrap.Service {
|
||||
// Add traces the "Add" operation of the wrapped bootstrap.Service.
|
||||
func (tm *tracingMiddleware) Add(ctx context.Context, token string, cfg bootstrap.Config) (bootstrap.Config, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_register_client", trace.WithAttributes(
|
||||
attribute.String("mainflux_thing", cfg.MFThing),
|
||||
attribute.String("thing_id", cfg.ThingID),
|
||||
attribute.String("owner", cfg.Owner),
|
||||
attribute.String("name", cfg.Name),
|
||||
attribute.String("external_id", cfg.ExternalID),
|
||||
@@ -53,7 +53,7 @@ func (tm *tracingMiddleware) Update(ctx context.Context, token string, cfg boots
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_update_client", trace.WithAttributes(
|
||||
attribute.String("name", cfg.Name),
|
||||
attribute.String("content", cfg.Content),
|
||||
attribute.String("mainflux_thing", cfg.MFThing),
|
||||
attribute.String("thing_id", cfg.ThingID),
|
||||
attribute.String("owner", cfg.Owner),
|
||||
))
|
||||
defer span.End()
|
||||
@@ -62,7 +62,7 @@ func (tm *tracingMiddleware) Update(ctx context.Context, token string, cfg boots
|
||||
}
|
||||
|
||||
// UpdateCert traces the "UpdateCert" operation of the wrapped bootstrap.Service.
|
||||
func (tm *tracingMiddleware) UpdateCert(ctx context.Context, token, thingID, clientCert, clientKey, caCert string) error {
|
||||
func (tm *tracingMiddleware) UpdateCert(ctx context.Context, token, thingID, clientCert, clientKey, caCert string) (bootstrap.Config, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_update_cert", trace.WithAttributes(
|
||||
attribute.String("thing_id", thingID),
|
||||
))
|
||||
|
||||
+1
-1
@@ -343,7 +343,7 @@ mainflux-cli bootstrap get <thing_id> <user_token> -b <bootstrap-url>
|
||||
#### Update configuration
|
||||
|
||||
```bash
|
||||
mainflux-cli bootstrap update '{"mainflux_id":"<thing_id>", "name": "newName", "content": "newContent"}' <user_token> -b <bootstrap-url>
|
||||
mainflux-cli bootstrap update '{"thing_id":"<thing_id>", "name": "newName", "content": "newContent"}' <user_token> -b <bootstrap-url>
|
||||
```
|
||||
|
||||
#### Remove configuration
|
||||
|
||||
+3
-2
@@ -115,12 +115,13 @@ var cmdBootstrap = []cobra.Command{
|
||||
return
|
||||
}
|
||||
if args[0] == "certs" {
|
||||
if err := sdk.UpdateBootstrapCerts(args[0], args[1], args[2], args[3], args[4]); err != nil {
|
||||
cfg, err := sdk.UpdateBootstrapCerts(args[0], args[1], args[2], args[3], args[4])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logOK()
|
||||
logJSON(cfg)
|
||||
return
|
||||
}
|
||||
logUsage(cmd.Use)
|
||||
|
||||
+72
-25
@@ -27,25 +27,66 @@ const (
|
||||
// MFKey is key of corresponding Mainflux Thing.
|
||||
// MFChannels is a list of Mainflux Channels corresponding Mainflux Thing connects to.
|
||||
type BootstrapConfig 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"`
|
||||
Channels interface{} `json:"channels,omitempty"`
|
||||
ExternalID string `json:"external_id,omitempty"`
|
||||
ExternalKey string `json:"external_key,omitempty"`
|
||||
ThingID string `json:"thing_id,omitempty"`
|
||||
ThingKey string `json:"thing_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"`
|
||||
}
|
||||
|
||||
type ConfigUpdateCertReq struct {
|
||||
ClientCert string `json:"client_cert"`
|
||||
ClientKey string `json:"client_key"`
|
||||
CACert string `json:"ca_cert"`
|
||||
func (ts *BootstrapConfig) UnmarshalJSON(data []byte) error {
|
||||
var rawData map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &rawData); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if channelData, ok := rawData["channels"]; ok {
|
||||
var stringData []string
|
||||
if err := json.Unmarshal(channelData, &stringData); err == nil {
|
||||
ts.Channels = stringData
|
||||
} else {
|
||||
var channels []Channel
|
||||
if err := json.Unmarshal(channelData, &channels); err == nil {
|
||||
ts.Channels = channels
|
||||
} else {
|
||||
return fmt.Errorf("unsupported channel data type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &struct {
|
||||
ExternalID *string `json:"external_id,omitempty"`
|
||||
ExternalKey *string `json:"external_key,omitempty"`
|
||||
ThingID *string `json:"thing_id,omitempty"`
|
||||
ThingKey *string `json:"thing_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"`
|
||||
}{
|
||||
ExternalID: &ts.ExternalID,
|
||||
ExternalKey: &ts.ExternalKey,
|
||||
ThingID: &ts.ThingID,
|
||||
ThingKey: &ts.ThingKey,
|
||||
Name: &ts.Name,
|
||||
ClientCert: &ts.ClientCert,
|
||||
ClientKey: &ts.ClientKey,
|
||||
CACert: &ts.CACert,
|
||||
Content: &ts.Content,
|
||||
State: &ts.State,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) AddBootstrap(cfg BootstrapConfig, token string) (string, errors.SDKError) {
|
||||
@@ -91,11 +132,11 @@ func (sdk mfSDK) Whitelist(cfg BootstrapConfig, token string) errors.SDKError {
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
if cfg.MFThing == "" {
|
||||
if cfg.ThingID == "" {
|
||||
return errors.NewSDKError(errors.ErrNotFoundParam)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.bootstrapURL, whitelistEndpoint, cfg.MFThing)
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.bootstrapURL, whitelistEndpoint, cfg.ThingID)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPut, url, token, string(CTJSON), data, http.StatusCreated, http.StatusOK)
|
||||
|
||||
@@ -123,15 +164,15 @@ func (sdk mfSDK) UpdateBootstrap(cfg BootstrapConfig, token string) errors.SDKEr
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.bootstrapURL, configsEndpoint, cfg.MFThing)
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.bootstrapURL, configsEndpoint, cfg.ThingID)
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPut, url, token, string(CTJSON), data, http.StatusOK)
|
||||
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) UpdateBootstrapCerts(id, clientCert, clientKey, ca, token string) errors.SDKError {
|
||||
func (sdk mfSDK) UpdateBootstrapCerts(id, clientCert, clientKey, ca, token string) (BootstrapConfig, errors.SDKError) {
|
||||
url := fmt.Sprintf("%s/%s/%s", sdk.bootstrapURL, bootstrapCertsEndpoint, id)
|
||||
request := ConfigUpdateCertReq{
|
||||
request := BootstrapConfig{
|
||||
ClientCert: clientCert,
|
||||
ClientKey: clientKey,
|
||||
CACert: ca,
|
||||
@@ -139,11 +180,17 @@ func (sdk mfSDK) UpdateBootstrapCerts(id, clientCert, clientKey, ca, token strin
|
||||
|
||||
data, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return errors.NewSDKError(err)
|
||||
return BootstrapConfig{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPatch, url, token, string(CTJSON), data, http.StatusOK)
|
||||
return sdkerr
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodPatch, url, token, string(CTJSON), data, http.StatusOK)
|
||||
|
||||
var bc BootstrapConfig
|
||||
if err := json.Unmarshal(body, &bc); err != nil {
|
||||
return BootstrapConfig{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return bc, sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) UpdateBootstrapConnection(id string, channels []string, token string) errors.SDKError {
|
||||
|
||||
+1
-1
@@ -837,7 +837,7 @@ type SDK interface {
|
||||
// example:
|
||||
// err := sdk.UpdateBootstrapCerts("id", "clientCert", "clientKey", "ca", "token")
|
||||
// fmt.Println(err)
|
||||
UpdateBootstrapCerts(id string, clientCert, clientKey, ca string, token string) errors.SDKError
|
||||
UpdateBootstrapCerts(id string, clientCert, clientKey, ca string, token string) (BootstrapConfig, errors.SDKError)
|
||||
|
||||
// UpdateBootstrapConnection updates connections performs update of the channel list corresponding Thing is connected to.
|
||||
//
|
||||
|
||||
@@ -226,7 +226,7 @@ func (ps *provisionService) Provision(token, name, externalID, externalKey strin
|
||||
res.CACert = ""
|
||||
|
||||
if needsBootstrap(thing) {
|
||||
if err = ps.sdk.UpdateBootstrapCerts(bsConfig.MFThing, cert.ClientCert, cert.ClientKey, "", token); err != nil {
|
||||
if _, err = ps.sdk.UpdateBootstrapCerts(bsConfig.ThingID, cert.ClientCert, cert.ClientKey, "", token); err != nil {
|
||||
return Result{}, errors.Wrap(ErrFailedCertCreation, err)
|
||||
}
|
||||
}
|
||||
@@ -234,7 +234,7 @@ func (ps *provisionService) Provision(token, name, externalID, externalKey strin
|
||||
|
||||
if ps.conf.Bootstrap.AutoWhiteList {
|
||||
wlReq := SDK.BootstrapConfig{
|
||||
MFThing: thing.ID,
|
||||
ThingID: thing.ID,
|
||||
State: Active,
|
||||
}
|
||||
if err := ps.sdk.Whitelist(wlReq, token); err != nil {
|
||||
@@ -310,10 +310,10 @@ func (ps *provisionService) updateGateway(token string, bs SDK.BootstrapConfig,
|
||||
}
|
||||
gw.ExternalID = bs.ExternalID
|
||||
gw.ExternalKey = bs.ExternalKey
|
||||
gw.CfgID = bs.MFThing
|
||||
gw.CfgID = bs.ThingID
|
||||
gw.Type = gateway
|
||||
|
||||
th, sdkerr := ps.sdk.Thing(bs.MFThing, token)
|
||||
th, sdkerr := ps.sdk.Thing(bs.ThingID, token)
|
||||
if sdkerr != nil {
|
||||
return errors.Wrap(ErrGatewayUpdate, sdkerr)
|
||||
}
|
||||
@@ -383,7 +383,7 @@ func (ps *provisionService) recover(e *error, ths *[]SDK.Thing, chs *[]SDK.Chann
|
||||
if needsBootstrap(th) {
|
||||
bs, err := ps.sdk.ViewBootstrap(th.ID, token)
|
||||
ps.errLog(errors.Wrap(ErrFailedBootstrapRetrieval, err))
|
||||
ps.errLog(ps.sdk.RemoveBootstrap(bs.MFThing, token))
|
||||
ps.errLog(ps.sdk.RemoveBootstrap(bs.ThingID, token))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -398,7 +398,7 @@ func (ps *provisionService) recover(e *error, ths *[]SDK.Thing, chs *[]SDK.Chann
|
||||
if needsBootstrap(th) {
|
||||
bs, err := ps.sdk.ViewBootstrap(th.ID, token)
|
||||
ps.errLog(errors.Wrap(ErrFailedBootstrapRetrieval, err))
|
||||
ps.errLog(ps.sdk.RemoveBootstrap(bs.MFThing, token))
|
||||
ps.errLog(ps.sdk.RemoveBootstrap(bs.ThingID, token))
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user