Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 73f98cf

Browse files
committedJul 3, 2024·
Resolve net config
1 parent 380ed39 commit 73f98cf

File tree

3 files changed

+105
-35
lines changed

3 files changed

+105
-35
lines changed
 

‎cli/template/apply.go

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// This file is part of arduino-cloud-cli.
22
//
3-
// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/)
3+
// Copyright (C) 2024 ARDUINO SA (http://www.arduino.cc/)
44
//
55
// This program is free software: you can redistribute it and/or modify
66
// it under the terms of the GNU Affero General Public License as published
@@ -20,6 +20,7 @@ package template
2020
import (
2121
"fmt"
2222
"os"
23+
"strings"
2324

2425
"github.com/arduino/arduino-cli/cli/errorcodes"
2526
"github.com/arduino/arduino-cli/cli/feedback"
@@ -29,8 +30,10 @@ import (
2930
)
3031

3132
type applyFlags struct {
32-
templateId string
33-
templateName string
33+
templateId string
34+
templatePrefix string
35+
deviceId string
36+
netCredentials string
3437
}
3538

3639
func initTemplateApplyCommand() *cobra.Command {
@@ -47,11 +50,14 @@ func initTemplateApplyCommand() *cobra.Command {
4750
},
4851
}
4952

50-
applyCommand.Flags().StringVarP(&flags.templateId, "template-id", "t", "", "Template id")
51-
applyCommand.Flags().StringVarP(&flags.templateName, "name", "n", "", "Name")
53+
applyCommand.Flags().StringVarP(&flags.templateId, "template-id", "t", "", "Template ID")
54+
applyCommand.Flags().StringVarP(&flags.templatePrefix, "prefix", "p", "", "Prefix to apply to the name of created resources")
55+
applyCommand.Flags().StringVarP(&flags.deviceId, "device-id", "d", "", "Device ID")
56+
applyCommand.Flags().StringVarP(&flags.netCredentials, "network-credentials", "n", "", "Network credentials")
5257

5358
applyCommand.MarkFlagRequired("template-id")
54-
applyCommand.MarkFlagRequired("name")
59+
applyCommand.MarkFlagRequired("prefix")
60+
applyCommand.MarkFlagRequired("device-id")
5561

5662
return applyCommand
5763
}
@@ -61,27 +67,18 @@ func runTemplateApplyCommand(flags *applyFlags) error {
6167
if err != nil {
6268
return fmt.Errorf("retrieving credentials: %w", err)
6369
}
64-
return template.ApplyCustomTemplates(cred, flags.templateId)
65-
}
66-
67-
/*
6870

69-
curl --location --request PUT 'http://localhost:9000/iot/v1/templates' \
70-
--header 'Accept: application/yaml' \
71-
--header 'Content-Type: application/json' \
72-
--header 'Authorization: ' \
73-
--data '{
74-
"template_name": "home",
75-
"custom_template_id": "d864f20e-dcf4-4c8a-b3e7-f1bfffe86f60",
76-
"things_options": {
77-
"home-3a06e": {
78-
"device_id": "08d75172-335e-4cb9-b401-83eb4db213fb",
79-
"secrets": {
80-
"SECRET_SSID": "asdas",
81-
"SECRET_OPTIONAL_PASS": "asdsad"
82-
}
83-
}
84-
}
85-
}'
71+
deviceNetCredentials := make(map[string]string)
72+
if flags.netCredentials != "" {
73+
configNetArray := strings.Split(strings.Trim(flags.netCredentials, " "), ",")
74+
for _, netConfig := range configNetArray {
75+
netConfigArray := strings.Split(netConfig, "=")
76+
if len(netConfigArray) != 2 {
77+
return fmt.Errorf("invalid network configuration: %s", netConfig)
78+
}
79+
deviceNetCredentials[netConfigArray[0]] = netConfigArray[1]
80+
}
81+
}
8682

87-
*/
83+
return template.ApplyCustomTemplates(cred, flags.templateId, flags.deviceId, flags.templatePrefix, deviceNetCredentials)
84+
}

‎command/template/apply.go

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// This file is part of arduino-cloud-cli.
22
//
3-
// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/)
3+
// Copyright (C) 2024 ARDUINO SA (http://www.arduino.cc/)
44
//
55
// This program is free software: you can redistribute it and/or modify
66
// it under the terms of the GNU Affero General Public License as published
@@ -18,34 +18,90 @@
1818
package template
1919

2020
import (
21+
"context"
2122
"fmt"
2223

2324
"github.com/arduino/arduino-cli/cli/feedback"
2425
"github.com/arduino/arduino-cloud-cli/config"
26+
"github.com/arduino/arduino-cloud-cli/internal/iot"
2527
storageapi "github.com/arduino/arduino-cloud-cli/internal/storage-api"
28+
iotclient "github.com/arduino/iot-client-go/v2"
2629
"github.com/gofrs/uuid"
2730
"github.com/sirupsen/logrus"
2831
)
2932

30-
func ApplyCustomTemplates(cred *config.Credentials, templateId string) error {
33+
func ApplyCustomTemplates(cred *config.Credentials, templateId, deviceId, prefix string, networkCredentials map[string]string) error {
3134

35+
ctx := context.Background()
36+
37+
// Open clients
3238
apiclient := storageapi.NewClient(cred)
39+
iotClient, err := iot.NewClient(cred)
40+
if err != nil {
41+
return err
42+
}
3343

34-
feedback.Printf("Applying template %s", templateId)
44+
feedback.Printf("Applying template %s to device %s", templateId, deviceId)
3545

3646
templateIdUUID, err := uuid.FromString(templateId)
3747
if err != nil {
3848
return fmt.Errorf("invalid template id: %s", templateId)
3949
}
50+
51+
// Get custom template and verify it is present
4052
cstTemplate, err := apiclient.GetCustomTemplate(templateIdUUID)
4153
if err != nil {
4254
return err
4355
}
44-
if len(cstTemplate.ThingTemplates) > 0 {
45-
mainThing := cstTemplate.ThingTemplates[0]
46-
logrus.Debug("Main thing template - id: ", mainThing.Id)
47-
//TODO check thing ID proceed
56+
if len(cstTemplate.ThingTemplates) <= 0 {
57+
return fmt.Errorf("template %s has no thing template", templateId)
4858
}
59+
mainThing := cstTemplate.ThingTemplates[0]
60+
logrus.Debug("Main thing template - id: ", mainThing.Id)
4961

62+
// Get device and check its connectivity
63+
secrets, err := resolveDeviceNetworkConfigurations(ctx, iotClient, deviceId, networkCredentials)
64+
if err != nil {
65+
return err
66+
}
67+
for key, value := range secrets {
68+
logrus.Info(fmt.Sprintf("Secret %s: %s", key, value))
69+
}
5070
return nil
5171
}
72+
73+
func resolveDeviceNetworkConfigurations(ctx context.Context, cl *iot.Client, deviceId string, networkCredentials map[string]string) (map[string]string, error) {
74+
device, err := cl.DeviceShow(ctx, deviceId)
75+
if err != nil {
76+
return nil, err
77+
}
78+
if device.Type == "" || device.ConnectionType == nil {
79+
logrus.Warnf("Device %s has no type or connection-type - type: %s", deviceId, device.Type)
80+
return nil, nil // cannot take a decision on this device, try to proceed
81+
}
82+
logrus.Infof("Device %s - type: %s - connection-type: %s", deviceId, device.Type, *device.ConnectionType)
83+
84+
credentials, err := cl.DeviceNetworkCredentials(ctx, device.Type, *device.ConnectionType)
85+
if err != nil {
86+
return nil, err
87+
}
88+
89+
// Check if the provided network credentials are valid. Verify if all the required credentials are present.
90+
discoveredCredentials := make(map[string]iotclient.ArduinoCredentialsv1)
91+
for _, credential := range credentials {
92+
discoveredCredentials[credential.GetSecretName()] = credential
93+
if credential.Required {
94+
if _, ok := networkCredentials[credential.GetSecretName()]; !ok {
95+
return nil, fmt.Errorf("missing mandatory network credential: %s", credential.GetSecretName())
96+
}
97+
}
98+
}
99+
// Remove any property that is not supported
100+
for key := range networkCredentials {
101+
if _, ok := discoveredCredentials[key]; !ok {
102+
delete(networkCredentials, key)
103+
}
104+
}
105+
106+
return networkCredentials, nil
107+
}

‎internal/iot/client.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,23 @@ func (cl *Client) DeviceShow(ctx context.Context, id string) (*iotclient.Arduino
195195
return dev, nil
196196
}
197197

198+
// DeviceNetworkCredentials allows to retrieve a specific device network credentials configuration options
199+
func (cl *Client) DeviceNetworkCredentials(ctx context.Context, deviceType, connection string) ([]iotclient.ArduinoCredentialsv1, error) {
200+
ctx, err := ctxWithToken(ctx, cl.token)
201+
if err != nil {
202+
return nil, err
203+
}
204+
205+
req := cl.api.NetworkCredentialsV1Api.NetworkCredentialsV1Show(ctx, deviceType)
206+
req = req.Connection(connection)
207+
dev, _, err := cl.api.NetworkCredentialsV1Api.NetworkCredentialsV1ShowExecute(req)
208+
if err != nil {
209+
err = fmt.Errorf("retrieving device network configuration, %w", errorDetail(err))
210+
return nil, err
211+
}
212+
return dev, nil
213+
}
214+
198215
// DeviceOTA performs an OTA upload request to Arduino IoT Cloud, passing
199216
// the ID of the device to be updated and the actual file containing the OTA firmware.
200217
func (cl *Client) DeviceOTA(ctx context.Context, id string, file *os.File, expireMins int) error {

0 commit comments

Comments
 (0)
Please sign in to comment.