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

mendersoftware / iot-manager / 1445709825

09 Sep 2024 11:23AM UTC coverage: 86.917% (-0.3%) from 87.172%
1445709825

Pull #303

gitlab-ci

alfrunes
ci: update gitlab runner

Moving to deprecated docker gitlab public runner, to a self-hosted runner

Ticket: SEC-1133
Changelog: none

Signed-off-by: Roberto Giovanardi <roberto.giovanardi@northern.tech>
(cherry picked from commit bb026f77c)
Pull Request #303: Cherry-pick MEN-7478 to 1.3.x (3.7.x)

42 of 54 new or added lines in 2 files covered. (77.78%)

128 existing lines in 10 files now uncovered.

3169 of 3646 relevant lines covered (86.92%)

9.75 hits per line

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

93.75
/api/http/internal.go
1
// Copyright 2023 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 http
16

17
import (
18
        "encoding/json"
19
        "net/http"
20
        "strings"
21

22
        "github.com/mendersoftware/iot-manager/app"
23
        "github.com/mendersoftware/iot-manager/client"
24
        "github.com/mendersoftware/iot-manager/model"
25

26
        "github.com/gin-gonic/gin"
27
        "github.com/mendersoftware/go-lib-micro/identity"
28
        "github.com/mendersoftware/go-lib-micro/rest.utils"
29
        "github.com/pkg/errors"
30
)
31

32
const (
33
        ParamTenantID = "tenant_id"
34
        ParamDeviceID = "device_id"
35
)
36

37
type InternalHandler APIHandler
38

39
type internalDevice model.DeviceEvent
40

41
func (dev *internalDevice) UnmarshalJSON(b []byte) error {
7✔
42
        type deviceAlias struct {
7✔
43
                // device_id kept for backward compatibility
7✔
44
                ID string `json:"device_id"`
7✔
45
                model.DeviceEvent
7✔
46
        }
7✔
47
        var aDev deviceAlias
7✔
48
        err := json.Unmarshal(b, &aDev)
7✔
49
        if err != nil {
8✔
50
                return err
1✔
51
        }
1✔
52
        if aDev.ID != "" {
7✔
53
                aDev.DeviceEvent.ID = aDev.ID
1✔
54
        }
1✔
55
        *dev = internalDevice(aDev.DeviceEvent)
6✔
56
        return nil
6✔
57
}
58

59
// POST /tenants/:tenant_id/devices
60
// code: 204 - device provisioned to iothub
61
//
62
//        500 - internal server error
63
func (h *InternalHandler) ProvisionDevice(c *gin.Context) {
8✔
64
        tenantID := c.Param(ParamTenantID)
8✔
65
        var device internalDevice
8✔
66
        if err := c.ShouldBindJSON(&device); err != nil {
10✔
67
                rest.RenderError(c,
2✔
68
                        http.StatusBadRequest,
2✔
69
                        errors.Wrap(err, "malformed request body"))
2✔
70
                return
2✔
71
        }
2✔
72
        if device.ID == "" {
7✔
73
                rest.RenderError(c, http.StatusBadRequest, errors.New("missing device ID"))
1✔
74
                return
1✔
75
        }
1✔
76

77
        ctx := identity.WithContext(c.Request.Context(), &identity.Identity{
5✔
78
                Subject: device.ID,
5✔
79
                Tenant:  tenantID,
5✔
80
        })
5✔
81
        err := h.app.ProvisionDevice(ctx, model.DeviceEvent(device))
5✔
82
        switch cause := errors.Cause(err); cause {
5✔
83
        case nil, app.ErrNoCredentials:
3✔
84
                c.Status(http.StatusNoContent)
3✔
85
        case app.ErrDeviceAlreadyExists:
1✔
86
                rest.RenderError(c, http.StatusConflict, cause)
1✔
87
        default:
1✔
88
                rest.RenderError(c, http.StatusInternalServerError, err)
1✔
89
        }
90
}
91

92
func (h *InternalHandler) DecommissionDevice(c *gin.Context) {
5✔
93
        deviceID := c.Param(ParamDeviceID)
5✔
94
        tenantID := c.Param(ParamTenantID)
5✔
95

5✔
96
        ctx := identity.WithContext(c.Request.Context(), &identity.Identity{
5✔
97
                Subject: deviceID,
5✔
98
                Tenant:  tenantID,
5✔
99
        })
5✔
100
        err := h.app.DecommissionDevice(ctx, deviceID)
5✔
101
        switch errors.Cause(err) {
5✔
102
        case nil, app.ErrNoCredentials:
2✔
103
                c.Status(http.StatusNoContent)
2✔
104
        case app.ErrDeviceNotFound:
2✔
105
                rest.RenderError(c, http.StatusNotFound, err)
2✔
106
        default:
1✔
107
                rest.RenderError(c, http.StatusInternalServerError, err)
1✔
108
        }
109
}
110

111
type BulkResult struct {
112
        Error bool       `json:"error"`
113
        Items []BulkItem `json:"items"`
114
}
115

116
type BulkItem struct {
117
        // Status code for the operation (translates to HTTP status)
118
        Status int `json:"status"`
119
        // Description in case of error
120
        Description string `json:"description,omitempty"`
121
        // Parameters used for producing BulkItem
122
        Parameters map[string]interface{} `json:"parameters"`
123
}
124

125
const (
126
        maxBulkItems = 100
127
)
128

129
// PUT /tenants/:tenant_id/devices/status/{status}
130
func (h *InternalHandler) BulkSetDeviceStatus(c *gin.Context) {
7✔
131
        var schema []struct {
7✔
132
                DeviceID string `json:"id"`
7✔
133
        }
7✔
134
        status := model.Status(c.Param("status"))
7✔
135
        if err := status.Validate(); err != nil {
8✔
136
                rest.RenderError(c, http.StatusBadRequest, err)
1✔
137
                return
1✔
138
        }
1✔
139
        if err := c.ShouldBindJSON(&schema); err != nil {
7✔
140
                rest.RenderError(c,
1✔
141
                        http.StatusBadRequest,
1✔
142
                        errors.Wrap(err, "invalid request body"),
1✔
143
                )
1✔
144
                return
1✔
145
        } else if len(schema) > maxBulkItems {
7✔
146
                rest.RenderError(c,
1✔
147
                        http.StatusBadRequest,
1✔
148
                        errors.New("too many bulk items: max 100 items per request"),
1✔
149
                )
1✔
150
                return
1✔
151
        }
1✔
152
        ctx := identity.WithContext(
4✔
153
                c.Request.Context(),
4✔
154
                &identity.Identity{
4✔
155
                        Tenant: c.Param("tenant_id"),
4✔
156
                },
4✔
157
        )
4✔
158
        res := BulkResult{
4✔
159
                Error: false,
4✔
160
                Items: make([]BulkItem, len(schema)),
4✔
161
        }
4✔
162
        for i, item := range schema {
11✔
163
                res.Items[i].Parameters = map[string]interface{}{
7✔
164
                        "id": item.DeviceID,
7✔
165
                }
7✔
166
                err := h.app.SetDeviceStatus(ctx, item.DeviceID, status)
7✔
167
                if err != nil {
9✔
168
                        res.Error = true
2✔
169
                        if e, ok := errors.Cause(err).(client.HTTPError); ok {
3✔
170
                                res.Items[i].Status = e.Code()
1✔
171
                                res.Items[i].Description = e.Error()
1✔
172
                        } else {
2✔
173
                                res.Items[i].Status = http.StatusInternalServerError
1✔
174
                                res.Items[i].Description = err.Error()
1✔
175
                        }
1✔
176
                } else {
5✔
177
                        res.Items[i].Status = http.StatusOK
5✔
178
                }
5✔
179
        }
180
        c.JSON(http.StatusOK, res)
4✔
181
}
182

183
// POST /tenants/:tenant_id/auth
184
func (h *InternalHandler) PreauthorizeHandler(c *gin.Context) {
3✔
185
        tenantID, okTenant := c.Params.Get("tenant_id")
3✔
186
        if !(okTenant) {
3✔
UNCOV
187
                (*APIHandler)(h).NoRoute(c)
×
UNCOV
188
                return
×
UNCOV
189
        }
×
190
        var req model.PreauthRequest
3✔
191
        if err := c.BindJSON(&req); err != nil {
3✔
UNCOV
192
                _ = c.AbortWithError(http.StatusBadRequest, err)
×
UNCOV
193
                return
×
UNCOV
194
        }
×
195
        sepIdx := strings.Index(req.DeviceID, " ")
3✔
196
        if sepIdx < 0 {
3✔
UNCOV
197
                _ = c.AbortWithError(http.StatusBadRequest, errors.New("invalid parameter `external_id`"))
×
UNCOV
198
                return
×
UNCOV
199
        }
×
200
        // DeviceID is formatted accordingly: {provider:[iot-hub]}
201
        provider := req.DeviceID[:sepIdx]
3✔
202
        req.DeviceID = req.DeviceID[sepIdx+1:]
3✔
203

3✔
204
        ctx := identity.WithContext(c.Request.Context(), &identity.Identity{
3✔
205
                IsDevice: true,
3✔
206
                Subject:  req.DeviceID,
3✔
207
                Tenant:   tenantID,
3✔
208
        })
3✔
209
        var err error
3✔
210
        switch provider {
3✔
211
        case string(model.ProviderIoTHub):
2✔
212
                err = h.app.VerifyDeviceTwin(ctx, req)
2✔
213
        default:
1✔
214
                _ = c.AbortWithError(http.StatusBadRequest, errors.New("external provider not supported"))
1✔
215
                return
1✔
216
        }
217
        if err != nil {
3✔
218
                _ = c.Error(err)
1✔
219
                c.Status(http.StatusUnauthorized)
1✔
220
                return
1✔
221
        }
1✔
222
        c.Status(http.StatusNoContent)
1✔
223
}
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