• 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

96.91
/api/http/router.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
        "context"
19
        "net/http"
20
        "time"
21

22
        "github.com/gin-gonic/gin"
23
        "github.com/gin-gonic/gin/binding"
24
        "github.com/pkg/errors"
25

26
        "github.com/mendersoftware/go-lib-micro/accesslog"
27
        "github.com/mendersoftware/go-lib-micro/identity"
28
        "github.com/mendersoftware/go-lib-micro/log"
29
        "github.com/mendersoftware/go-lib-micro/requestid"
30
        "github.com/mendersoftware/go-lib-micro/rest.utils"
31

32
        "github.com/mendersoftware/iot-manager/app"
33
)
34

35
// API URL used by the HTTP router
36
const (
37
        APIURLInternal = "/api/internal/v1/iot-manager"
38

39
        APIURLAlive             = "/alive"
40
        APIURLHealth            = "/health"
41
        APIURLTenants           = "/tenants"
42
        APIURLTenant            = APIURLTenants + "/:tenant_id"
43
        APIURLTenantAuth        = APIURLTenant + "/auth"
44
        APIURLTenantDevices     = APIURLTenant + "/devices"
45
        APIURLTenantDevice      = APIURLTenantDevices + "/:device_id"
46
        APIURLTenantBulkDevices = APIURLTenant + "/bulk/devices"
47
        APIURLTenantBulkStatus  = APIURLTenantBulkDevices + "/status/:status"
48

49
        APIURLManagement = "/api/management/v1/iot-manager"
50

51
        APIURLIntegrations           = "/integrations"
52
        APIURLIntegration            = "/integrations/:id"
53
        APIURLIntegrationCredentials = APIURLIntegration + "/credentials"
54

55
        APIURLDevice                 = "/devices/:id"
56
        APIURLDeviceState            = APIURLDevice + "/state"
57
        APIURLDeviceStateIntegration = APIURLDevice + "/state/:integrationId"
58

59
        APIURLEvents = "/events"
60
)
61

62
const (
63
        defaultTimeout = time.Second * 10
64
)
65

66
type Config struct {
67
        Client *http.Client
68
}
69

70
// NewConfig initializes a new empty config and optionally merges the
71
// configurations provided as argument.
72
func NewConfig(configs ...*Config) *Config {
155✔
73
        var config = new(Config)
155✔
74
        for _, conf := range configs {
234✔
75
                if conf == nil {
80✔
76
                        continue
1✔
77
                }
78
                if conf.Client != nil {
80✔
79
                        config.Client = conf.Client
2✔
80
                }
2✔
81
        }
82
        return config
155✔
83
}
84

85
func (conf *Config) SetClient(client *http.Client) *Config {
1✔
86
        conf.Client = client
1✔
87
        return conf
1✔
88
}
1✔
89

90
// NewRouter returns the gin router
91
func NewRouter(
92
        app app.App,
93
        config ...*Config,
94
) *gin.Engine {
77✔
95
        conf := NewConfig(config...)
77✔
96
        gin.SetMode(gin.ReleaseMode)
77✔
97
        gin.DisableConsoleColor()
77✔
98
        handler := NewAPIHandler(app, conf)
77✔
99
        internal := (*InternalHandler)(handler)
77✔
100
        management := (*ManagementHandler)(handler)
77✔
101

77✔
102
        router := gin.New()
77✔
103
        router.Use(accesslog.Middleware())
77✔
104
        router.Use(requestid.Middleware())
77✔
105

77✔
106
        router.NoRoute(handler.NoRoute)
77✔
107

77✔
108
        internalAPI := router.Group(APIURLInternal)
77✔
109
        internalAPI.GET(APIURLAlive, handler.Alive)
77✔
110
        internalAPI.GET(APIURLHealth, handler.Health)
77✔
111

77✔
112
        internalAPI.DELETE(APIURLTenant, internal.DeleteTenant)
77✔
113
        internalAPI.POST(APIURLTenantDevices, internal.ProvisionDevice)
77✔
114
        internalAPI.DELETE(APIURLTenantDevice, internal.DecommissionDevice)
77✔
115
        internalAPI.PUT(APIURLTenantBulkStatus, internal.BulkSetDeviceStatus)
77✔
116

77✔
117
        internalAPI.POST(APIURLTenantAuth, internal.PreauthorizeHandler)
77✔
118

77✔
119
        managementAPI := router.Group(APIURLManagement, identity.Middleware())
77✔
120
        managementAPI.GET(APIURLIntegrations, management.GetIntegrations)
77✔
121
        managementAPI.GET(APIURLIntegration, management.GetIntegrationById)
77✔
122
        managementAPI.POST(APIURLIntegrations, management.CreateIntegration)
77✔
123
        managementAPI.PUT(APIURLIntegrationCredentials, management.SetIntegrationCredentials)
77✔
124
        managementAPI.DELETE(APIURLIntegration, management.RemoveIntegration)
77✔
125

77✔
126
        managementAPI.GET(APIURLDeviceState, management.GetDeviceState)
77✔
127
        managementAPI.GET(APIURLDeviceStateIntegration, management.GetDeviceStateIntegration)
77✔
128
        managementAPI.PUT(APIURLDeviceStateIntegration, management.SetDeviceStateIntegration)
77✔
129

77✔
130
        managementAPI.GET(APIURLEvents, management.GetEvents)
77✔
131

77✔
132
        return router
77✔
133
}
77✔
134

135
type APIHandler struct {
136
        *http.Client
137
        app app.App
138
}
139

140
func NewAPIHandler(app app.App, config ...*Config) *APIHandler {
77✔
141
        conf := NewConfig(config...)
77✔
142
        if conf.Client == nil {
153✔
143
                conf.Client = new(http.Client)
76✔
144
        }
76✔
145
        return &APIHandler{
77✔
146
                Client: conf.Client,
77✔
147
                app:    app,
77✔
148
        }
77✔
149
}
150

151
// Alive responds to GET /alive
152
func (h *APIHandler) Alive(c *gin.Context) {
1✔
153
        c.Writer.WriteHeader(http.StatusNoContent)
1✔
154
}
1✔
155

156
// Health responds to GET /health
157
func (h *APIHandler) Health(c *gin.Context) {
2✔
158
        ctx := c.Request.Context()
2✔
159
        l := log.FromContext(ctx)
2✔
160
        ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
2✔
161
        defer cancel()
2✔
162

2✔
163
        err := h.app.HealthCheck(ctx)
2✔
164
        if err != nil {
3✔
165
                l.Error(errors.Wrap(err, "health check failed"))
1✔
166
                c.JSON(http.StatusServiceUnavailable, gin.H{
1✔
167
                        "error": err.Error(),
1✔
168
                })
1✔
169
                return
1✔
170
        }
1✔
171

172
        c.Writer.WriteHeader(http.StatusNoContent)
1✔
173
}
174

175
func (h *APIHandler) NoRoute(c *gin.Context) {
1✔
176
        c.JSON(http.StatusNotFound, rest.Error{
1✔
177
                Err:       "not found",
1✔
178
                RequestID: requestid.FromContext(c.Request.Context()),
1✔
179
        })
1✔
180
}
1✔
181

182
// Make gin-gonic use validatable structs instead of relying on go-playground
183
// validator interface.
184
type validateValidatableValidator struct{}
185

186
func (validateValidatableValidator) ValidateStruct(obj interface{}) error {
31✔
187
        if v, ok := obj.(interface{ Validate() error }); ok {
45✔
188
                return v.Validate()
14✔
189
        }
14✔
190
        return nil
17✔
191
}
192

193
func (validateValidatableValidator) Engine() interface{} {
×
194
        return nil
×
195
}
×
196

197
func init() {
4✔
198
        binding.Validator = validateValidatableValidator{}
4✔
199
}
4✔
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