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

mendersoftware / iot-manager / 1457622833

13 Sep 2024 11:01AM UTC coverage: 87.172%. Remained the same
1457622833

push

gitlab-ci

web-flow
Merge pull request #304 from mzedel/chore/deprecate

Chore/deprecate

3255 of 3734 relevant lines covered (87.17%)

11.38 hits per line

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

92.14
/api/http/internal.go
1
// Copyright 2024 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/model"
24

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

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

36
type InternalHandler APIHandler
37

38
type internalDevice model.DeviceEvent
39

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

58
// DELETE /tenants/:tenant_id
59
// code: 204 - all tenant data removed
60
//
61
//        500 - internal server error on removal
62
func (h *InternalHandler) DeleteTenant(c *gin.Context) {
2✔
63
        tenantID := c.Param(ParamTenantID)
2✔
64

2✔
65
        ctx := identity.WithContext(
2✔
66
                c.Request.Context(),
2✔
67
                &identity.Identity{
2✔
68
                        Tenant: tenantID,
2✔
69
                },
2✔
70
        )
2✔
71
        err := h.app.DeleteTenant(ctx)
2✔
72
        if err != nil {
2✔
73
                rest.RenderError(c, http.StatusInternalServerError, err)
×
74
        }
×
75
        c.Status(http.StatusNoContent)
1✔
76
}
77

78
// POST /tenants/:tenant_id/devices
79
// code: 204 - device provisioned to iothub
80
//
81
//        500 - internal server error
82
func (h *InternalHandler) ProvisionDevice(c *gin.Context) {
8✔
83
        tenantID := c.Param(ParamTenantID)
8✔
84
        var device internalDevice
8✔
85
        if err := c.ShouldBindJSON(&device); err != nil {
10✔
86
                rest.RenderError(c,
2✔
87
                        http.StatusBadRequest,
2✔
88
                        errors.Wrap(err, "malformed request body"))
2✔
89
                return
2✔
90
        }
2✔
91
        if device.ID == "" {
7✔
92
                rest.RenderError(c, http.StatusBadRequest, errors.New("missing device ID"))
1✔
93
                return
1✔
94
        }
1✔
95

96
        ctx := identity.WithContext(c.Request.Context(), &identity.Identity{
5✔
97
                Subject: device.ID,
5✔
98
                Tenant:  tenantID,
5✔
99
        })
5✔
100
        err := h.app.ProvisionDevice(ctx, model.DeviceEvent(device))
5✔
101
        switch cause := errors.Cause(err); cause {
5✔
102
        case nil, app.ErrNoCredentials:
3✔
103
                c.Status(http.StatusAccepted)
3✔
104
        case app.ErrDeviceAlreadyExists:
1✔
105
                rest.RenderError(c, http.StatusConflict, cause)
1✔
106
        default:
1✔
107
                rest.RenderError(c, http.StatusInternalServerError, err)
1✔
108
        }
109
}
110

111
func (h *InternalHandler) DecommissionDevice(c *gin.Context) {
5✔
112
        deviceID := c.Param(ParamDeviceID)
5✔
113
        tenantID := c.Param(ParamTenantID)
5✔
114

5✔
115
        ctx := identity.WithContext(c.Request.Context(), &identity.Identity{
5✔
116
                Subject: deviceID,
5✔
117
                Tenant:  tenantID,
5✔
118
        })
5✔
119
        err := h.app.DecommissionDevice(ctx, deviceID)
5✔
120
        switch errors.Cause(err) {
5✔
121
        case nil, app.ErrNoCredentials:
3✔
122
                c.Status(http.StatusAccepted)
3✔
123
        case app.ErrDeviceNotFound:
1✔
124
                rest.RenderError(c, http.StatusNotFound, err)
1✔
125
        default:
1✔
126
                rest.RenderError(c, http.StatusInternalServerError, err)
1✔
127
        }
128
}
129

130
const (
131
        maxBulkItems = 100
132
)
133

134
// PUT /tenants/:tenant_id/devices/status/{status}
135
func (h *InternalHandler) BulkSetDeviceStatus(c *gin.Context) {
7✔
136
        var schema []struct {
7✔
137
                DeviceID string `json:"id"`
7✔
138
        }
7✔
139
        status := model.Status(c.Param("status"))
7✔
140
        if err := status.Validate(); err != nil {
8✔
141
                rest.RenderError(c, http.StatusBadRequest, err)
1✔
142
                return
1✔
143
        }
1✔
144
        if err := c.ShouldBindJSON(&schema); err != nil {
7✔
145
                rest.RenderError(c,
1✔
146
                        http.StatusBadRequest,
1✔
147
                        errors.Wrap(err, "invalid request body"),
1✔
148
                )
1✔
149
                return
1✔
150
        } else if len(schema) > maxBulkItems {
7✔
151
                rest.RenderError(c,
1✔
152
                        http.StatusBadRequest,
1✔
153
                        errors.New("too many bulk items: max 100 items per request"),
1✔
154
                )
1✔
155
                return
1✔
156
        }
1✔
157
        ctx := identity.WithContext(
4✔
158
                c.Request.Context(),
4✔
159
                &identity.Identity{
4✔
160
                        Tenant: c.Param("tenant_id"),
4✔
161
                },
4✔
162
        )
4✔
163
        for _, item := range schema {
11✔
164
                _ = h.app.SetDeviceStatus(ctx, item.DeviceID, status)
7✔
165
        }
7✔
166
        c.Status(http.StatusAccepted)
4✔
167
}
168

169
// POST /tenants/:tenant_id/auth
170
func (h *InternalHandler) PreauthorizeHandler(c *gin.Context) {
3✔
171
        tenantID, okTenant := c.Params.Get("tenant_id")
3✔
172
        if !(okTenant) {
3✔
173
                (*APIHandler)(h).NoRoute(c)
×
174
                return
×
175
        }
×
176
        var req model.PreauthRequest
3✔
177
        if err := c.BindJSON(&req); err != nil {
3✔
178
                _ = c.AbortWithError(http.StatusBadRequest, err)
×
179
                return
×
180
        }
×
181
        sepIdx := strings.Index(req.DeviceID, " ")
3✔
182
        if sepIdx < 0 {
3✔
183
                _ = c.AbortWithError(http.StatusBadRequest, errors.New("invalid parameter `external_id`"))
×
184
                return
×
185
        }
×
186
        // DeviceID is formatted accordingly: {provider:[iot-hub]}
187
        provider := req.DeviceID[:sepIdx]
3✔
188
        req.DeviceID = req.DeviceID[sepIdx+1:]
3✔
189

3✔
190
        ctx := identity.WithContext(c.Request.Context(), &identity.Identity{
3✔
191
                IsDevice: true,
3✔
192
                Subject:  req.DeviceID,
3✔
193
                Tenant:   tenantID,
3✔
194
        })
3✔
195
        var err error
3✔
196
        switch provider {
3✔
197
        case string(model.ProviderIoTHub):
2✔
198
                err = h.app.VerifyDeviceTwin(ctx, req)
2✔
199
        default:
1✔
200
                _ = c.AbortWithError(http.StatusBadRequest, errors.New("external provider not supported"))
1✔
201
                return
1✔
202
        }
203
        if err != nil {
3✔
204
                _ = c.Error(err)
1✔
205
                c.Status(http.StatusUnauthorized)
1✔
206
                return
1✔
207
        }
1✔
208
        c.Status(http.StatusNoContent)
1✔
209
}
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