• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / iot-manager / 1336988003

18 Jun 2024 09:38AM UTC coverage: 87.602%. Remained the same
1336988003

Pull #288

gitlab-ci

alfrunes
test(accpetance): Infer Docker compose service name from host

Remove hard-coded host name from config and actually use the `--host`
pytest config.

Signed-off-by: Alf-Rune Siqveland <alf.rune@northern.tech>
Pull Request #288: test(accpetance): Infer Docker compose service name from host

3229 of 3686 relevant lines covered (87.6%)

11.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.64
/app/app_iot_core.go
1
// Copyright 2022 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
package app
16

17
import (
18
        "context"
19

20
        "github.com/mendersoftware/go-lib-micro/log"
21
        "github.com/pkg/errors"
22

23
        "github.com/mendersoftware/iot-manager/client/iotcore"
24
        "github.com/mendersoftware/iot-manager/model"
25
)
26

27
func assertAWSIntegration(integration model.Integration) error {
43✔
28
        if err := integration.Validate(); err != nil {
48✔
29
                return ErrNoCredentials
5✔
30
        } else if integration.Credentials.Type != model.CredentialTypeAWS {
43✔
31
                return ErrNoCredentials
×
32
        }
×
33
        return nil
38✔
34
}
35

36
func (a *app) provisionIoTCoreDevice(
37
        ctx context.Context,
38
        deviceID string,
39
        integration model.Integration,
40
        device *iotcore.Device,
41
) error {
6✔
42
        if err := assertAWSIntegration(integration); err != nil {
7✔
43
                return err
1✔
44
        }
1✔
45

46
        dev, err := a.iotcoreClient.UpsertDevice(ctx,
5✔
47
                *integration.Credentials.AWSCredentials,
5✔
48
                deviceID,
5✔
49
                device,
5✔
50
                *integration.Credentials.AWSCredentials.DevicePolicyName)
5✔
51
        if err != nil {
7✔
52
                return errors.Wrap(err, "failed to update iotcore devices")
2✔
53
        }
2✔
54

55
        err = a.deployConfiguration(ctx, deviceID, dev)
3✔
56
        return err
3✔
57
}
58

59
func (a *app) setDeviceStatusIoTCore(ctx context.Context, deviceID string, status model.Status,
60
        integration model.Integration) error {
9✔
61
        if err := assertAWSIntegration(integration); err != nil {
10✔
62
                return err
1✔
63
        }
1✔
64
        _, err := a.iotcoreClient.UpsertDevice(
8✔
65
                ctx,
8✔
66
                *integration.Credentials.AWSCredentials,
8✔
67
                deviceID,
8✔
68
                &iotcore.Device{
8✔
69
                        Status: iotcore.NewStatusFromMenderStatus(status),
8✔
70
                },
8✔
71
                *integration.Credentials.AWSCredentials.DevicePolicyName,
8✔
72
        )
8✔
73
        return err
8✔
74

75
}
76

77
func (a *app) deployConfiguration(ctx context.Context, deviceID string, dev *iotcore.Device) error {
3✔
78
        if dev.Certificate != "" && dev.PrivateKey != "" && *dev.Endpoint != "" {
6✔
79
                err := a.wf.ProvisionExternalDevice(ctx, deviceID, map[string]string{
3✔
80
                        confKeyAWSCertificate: dev.Certificate,
3✔
81
                        confKeyAWSPrivateKey:  dev.PrivateKey,
3✔
82
                        confKeyAWSEndpoint:    *dev.Endpoint,
3✔
83
                })
3✔
84
                if err != nil {
4✔
85
                        return errors.Wrap(err, "failed to submit iotcore credentials to deviceconfig")
1✔
86
                }
1✔
87
        }
88
        return nil
2✔
89
}
90

91
func (a *app) decommissionIoTCoreDevice(ctx context.Context, deviceID string,
92
        integration model.Integration) error {
10✔
93
        if err := assertAWSIntegration(integration); err != nil {
11✔
94
                return err
1✔
95
        }
1✔
96
        err := a.iotcoreClient.DeleteDevice(ctx, *integration.Credentials.AWSCredentials, deviceID)
9✔
97
        if err != nil && err != iotcore.ErrDeviceNotFound {
14✔
98
                return errors.Wrap(err, "failed to delete IoT Core device")
5✔
99
        }
5✔
100
        return nil
4✔
101
}
102

103
func (a *app) syncIoTCoreDevices(
104
        ctx context.Context,
105
        deviceIDs []string,
106
        integration model.Integration,
107
        failEarly bool,
108
) error {
11✔
109
        if err := assertAWSIntegration(integration); err != nil {
12✔
110
                return err
1✔
111
        }
1✔
112
        l := log.FromContext(ctx)
10✔
113

10✔
114
        // Get device authentication
10✔
115
        devAuths, err := a.devauth.GetDevices(ctx, deviceIDs)
10✔
116
        if err != nil {
11✔
117
                return errors.Wrap(err, "app: failed to lookup device authentication")
1✔
118
        }
1✔
119

120
        statuses := make(map[string]model.Status, len(deviceIDs))
9✔
121
        for _, auth := range devAuths {
48✔
122
                statuses[auth.ID] = auth.Status
39✔
123
        }
39✔
124

125
        // Find devices that shouldn't exist
126
        var (
9✔
127
                i int
9✔
128
                j int = len(deviceIDs)
9✔
129
        )
9✔
130
        for i < j {
54✔
131
                id := deviceIDs[i]
45✔
132
                if _, ok := statuses[id]; !ok {
51✔
133
                        l.Warnf("Device '%s' does not have an auth set: deleting device", id)
6✔
134
                        err := a.decommissionDevice(ctx, id)
6✔
135
                        if err != nil && !errors.Is(err, ErrDeviceNotFound) {
7✔
136
                                err = errors.Wrap(err, "app: failed to decommission device")
1✔
137
                                if failEarly {
2✔
138
                                        return err
1✔
139
                                }
1✔
140
                                l.Error(err)
×
141
                        }
142
                        // swap(deviceIDs[i], deviceIDs[j])
143
                        j--
5✔
144
                        tmp := deviceIDs[i]
5✔
145
                        deviceIDs[i] = deviceIDs[j]
5✔
146
                        deviceIDs[j] = tmp
5✔
147
                        deviceIDs = deviceIDs[:j]
5✔
148
                } else {
39✔
149
                        i++
39✔
150
                }
39✔
151
        }
152
        for _, deviceID := range deviceIDs {
47✔
153
                // Check if device exists in IoT Core
39✔
154
                dev, err := a.iotcoreClient.GetDevice(
39✔
155
                        ctx,
39✔
156
                        *integration.Credentials.AWSCredentials,
39✔
157
                        deviceID,
39✔
158
                )
39✔
159
                status, ok := statuses[deviceID]
39✔
160
                if err == iotcore.ErrDeviceNotFound {
41✔
161
                        if ok {
4✔
162
                                // Device should exist, let's provision the device.
2✔
163
                                err := a.provisionIoTCoreDevice(ctx, deviceID, integration, &iotcore.Device{
2✔
164
                                        Status: iotcore.NewStatusFromMenderStatus(status),
2✔
165
                                })
2✔
166
                                if err != nil {
3✔
167
                                        err = errors.Wrap(err, "failed to provision missing device")
1✔
168
                                        if failEarly {
2✔
169
                                                return err
1✔
170
                                        }
1✔
171
                                        l.Warn(err)
×
172
                                }
173
                        }
174
                } else if err != nil {
39✔
175
                        err = errors.Wrap(err, "app: failed to get Thing from IoT Core")
2✔
176
                        if failEarly {
3✔
177
                                return err
1✔
178
                        }
1✔
179
                        l.Warn(err)
1✔
180

181
                } else if dev.Status != iotcore.NewStatusFromMenderStatus(status) {
40✔
182
                        // Upsert device
5✔
183
                        err := a.setDeviceStatusIoTCore(ctx, dev.ID, status, integration)
5✔
184
                        if err != nil {
6✔
185
                                err = errors.Wrap(err, "failed to update device status")
1✔
186
                                if failEarly {
2✔
187
                                        return err
1✔
188
                                }
1✔
189
                                l.Warn(err)
×
190
                        }
191
                }
192
        }
193

194
        return nil
5✔
195
}
196

197
func (a *app) GetDeviceStateIoTCore(
198
        ctx context.Context,
199
        deviceID string,
200
        integration *model.Integration,
201
) (*model.DeviceState, error) {
4✔
202
        if err := assertAWSIntegration(*integration); err != nil {
5✔
203
                return nil, err
1✔
204
        }
1✔
205
        shadow, err := a.iotcoreClient.GetDeviceShadow(
3✔
206
                ctx,
3✔
207
                *integration.Credentials.AWSCredentials,
3✔
208
                deviceID,
3✔
209
        )
3✔
210
        if err != nil {
5✔
211
                if err == iotcore.ErrDeviceNotFound {
3✔
212
                        return nil, nil
1✔
213
                } else {
2✔
214
                        return nil, errors.Wrap(err, "failed to get the device shadow")
1✔
215
                }
1✔
216
        }
217
        return &shadow.Payload, nil
1✔
218
}
219

220
func (a *app) SetDeviceStateIoTCore(
221
        ctx context.Context,
222
        deviceID string,
223
        integration *model.Integration,
224
        state *model.DeviceState,
225
) (*model.DeviceState, error) {
3✔
226
        if state == nil {
3✔
227
                return nil, nil
×
228
        }
×
229
        if err := assertAWSIntegration(*integration); err != nil {
3✔
230
                return nil, err
×
231
        }
×
232
        shadow, err := a.iotcoreClient.UpdateDeviceShadow(
3✔
233
                ctx,
3✔
234
                *integration.Credentials.AWSCredentials,
3✔
235
                deviceID,
3✔
236
                iotcore.DeviceShadowUpdate{
3✔
237
                        State: iotcore.DesiredState{
3✔
238
                                Desired: state.Desired,
3✔
239
                        },
3✔
240
                },
3✔
241
        )
3✔
242
        if err != nil {
5✔
243
                if err == iotcore.ErrDeviceNotFound {
3✔
244
                        return nil, nil
1✔
245
                }
1✔
246
                return nil, err
1✔
247
        }
248
        return &shadow.Payload, nil
1✔
249
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc