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

mendersoftware / mender-server / 1899590412

01 Jul 2025 09:26AM UTC coverage: 65.694% (-0.04%) from 65.731%
1899590412

push

gitlab-ci

bahaa-ghazal
refactor: Remove unused ant0ine/go-json-rest utilities from deployments

Signed-off-by: Bahaa Aldeen Ghazal <bahaa.ghazal@northern.tech>

32420 of 49350 relevant lines covered (65.69%)

1.39 hits per line

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

94.91
/backend/services/deployments/api/http/routing.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
        "net/url"
21
        "strings"
22

23
        "github.com/gin-gonic/gin"
24

25
        "github.com/mendersoftware/mender-server/pkg/accesslog"
26
        "github.com/mendersoftware/mender-server/pkg/contenttype"
27
        "github.com/mendersoftware/mender-server/pkg/identity"
28
        "github.com/mendersoftware/mender-server/pkg/log"
29
        "github.com/mendersoftware/mender-server/pkg/requestid"
30

31
        "github.com/mendersoftware/mender-server/services/deployments/app"
32
        "github.com/mendersoftware/mender-server/services/deployments/store"
33
        "github.com/mendersoftware/mender-server/services/deployments/utils/restutil"
34
        "github.com/mendersoftware/mender-server/services/deployments/utils/restutil/view"
35
)
36

37
const (
38
        ApiUrlInternal   = "/api/internal/v1/deployments"
39
        ApiUrlManagement = "/api/management/v1/deployments"
40
        ApiUrlDevices    = "/api/devices/v1/deployments"
41

42
        ApiUrlManagementArtifacts               = "/artifacts"
43
        ApiUrlManagementArtifactsList           = "/artifacts/list"
44
        ApiUrlManagementArtifactsGenerate       = "/artifacts/generate"
45
        ApiUrlManagementArtifactsDirectUpload   = "/artifacts/directupload"
46
        ApiUrlManagementArtifactsCompleteUpload = ApiUrlManagementArtifactsDirectUpload +
47
                "/:id/complete"
48
        ApiUrlManagementArtifactsId         = "/artifacts/:id"
49
        ApiUrlManagementArtifactsIdDownload = "/artifacts/:id/download"
50

51
        ApiUrlManagementDeployments                   = "/deployments"
52
        ApiUrlManagementMultipleDeploymentsStatistics = "/deployments/statistics/list"
53
        ApiUrlManagementDeploymentsGroup              = "/deployments/group/:name"
54
        ApiUrlManagementDeploymentsId                 = "/deployments/:id"
55
        ApiUrlManagementDeploymentsStatistics         = "/deployments/:id/statistics"
56
        ApiUrlManagementDeploymentsStatus             = "/deployments/:id/status"
57
        ApiUrlManagementDeploymentsDevices            = "/deployments/:id/devices"
58
        ApiUrlManagementDeploymentsDevicesList        = "/deployments/:id/devices/list"
59
        ApiUrlManagementDeploymentsLog                = "/deployments/:id/devices/:devid/log"
60
        ApiUrlManagementDeploymentsDeviceId           = "/deployments/devices/:id"
61
        ApiUrlManagementDeploymentsDeviceHistory      = "/deployments/devices/:id/history"
62
        ApiUrlManagementDeploymentsDeviceList         = "/deployments/:id/device_list"
63

64
        ApiUrlManagementReleases     = "/deployments/releases"
65
        ApiUrlManagementReleasesList = "/deployments/releases/list"
66

67
        ApiUrlManagementLimitsName = "/limits/:name"
68

69
        ApiUrlManagementV2                      = "/api/management/v2/deployments"
70
        ApiUrlManagementV2Releases              = "/deployments/releases"
71
        ApiUrlManagementV2ReleasesName          = ApiUrlManagementV2Releases + "/:name"
72
        ApiUrlManagementV2ReleaseTags           = ApiUrlManagementV2Releases + "/:name/tags"
73
        ApiUrlManagementV2ReleaseAllTags        = "/releases/all/tags"
74
        ApiUrlManagementV2ReleaseAllUpdateTypes = "/releases/all/types"
75
        ApiUrlManagementV2Deployments           = "/deployments"
76

77
        ApiUrlDevicesDeploymentsNext  = "/device/deployments/next"
78
        ApiUrlDevicesDeploymentStatus = "/device/deployments/:id/status"
79
        ApiUrlDevicesDeploymentsLog   = "/device/deployments/:id/log"
80
        ApiUrlDevicesDownloadConfig   = "/download/configuration" +
81
                "/:deployment_id/:device_type/:device_id"
82

83
        ApiUrlInternalAlive                          = "/alive"
84
        ApiUrlInternalHealth                         = "/health"
85
        ApiUrlInternalTenants                        = "/tenants"
86
        ApiUrlInternalTenantDeployments              = "/tenants/:tenant/deployments"
87
        ApiUrlInternalTenantDeploymentsDevices       = "/tenants/:tenant/deployments/devices"
88
        ApiUrlInternalTenantDeploymentsDevice        = "/tenants/:tenant/deployments/devices/:id"
89
        ApiUrlInternalTenantArtifacts                = "/tenants/:tenant/artifacts"
90
        ApiUrlInternalTenantStorageSettings          = "/tenants/:tenant/storage/settings"
91
        ApiUrlInternalDeviceConfigurationDeployments = "/tenants/:tenant/configuration/deployments" +
92
                "/:deployment_id/devices/:device_id"
93
        ApiUrlInternalDeviceDeploymentLastStatusDeployments = "/tenants/:tenant/devices/deployments" +
94
                "/last"
95
)
96

97
// NewRouter defines all REST API routes.
98
func NewRouter(
99
        ctx context.Context,
100
        app app.App,
101
        ds store.DataStore,
102
        cfg *Config,
103
) http.Handler {
3✔
104
        router := gin.New()
3✔
105
        router.Use(requestid.Middleware())
3✔
106
        // Create and configure API handlers
3✔
107
        //
3✔
108
        // Encode base64 secret in either std or URL encoding ignoring padding.
3✔
109
        deploymentsHandlers := NewDeploymentsApiHandlers(
3✔
110
                ds, new(view.RESTView), app, cfg,
3✔
111
        )
3✔
112

3✔
113
        // Routing
3✔
114
        internalAPIs := router.Group(ApiUrlInternal)
3✔
115

3✔
116
        publicAPIs := router.Group(".")
3✔
117
        publicAPIs.Use(accesslog.Middleware())
3✔
118

3✔
119
        withAuth := publicAPIs.Group(".")
3✔
120
        withAuth.Use(identity.Middleware())
3✔
121

3✔
122
        NewImagesResourceRoutes(withAuth, deploymentsHandlers, cfg)
3✔
123
        NewDeploymentsResourceRoutes(publicAPIs, deploymentsHandlers)
3✔
124
        NewLimitsResourceRoutes(withAuth, deploymentsHandlers)
3✔
125
        InternalRoutes(internalAPIs, deploymentsHandlers)
3✔
126
        ReleasesRoutes(withAuth, deploymentsHandlers)
3✔
127

3✔
128
        restutil.AutogenOptionsRoutes(
3✔
129
                restutil.NewOptionsHandler,
3✔
130
                router)
3✔
131

3✔
132
        return router
3✔
133
}
3✔
134

135
func NewImagesResourceRoutes(router *gin.RouterGroup,
136
        controller *DeploymentsApiHandlers, cfg *Config) {
3✔
137

3✔
138
        if controller == nil {
3✔
139
                return
×
140
        }
×
141
        mgmtV1 := router.Group(ApiUrlManagement)
3✔
142

3✔
143
        artifcatType := contenttype.Middleware("multipart/form-data", "multipart/mixed")
3✔
144

3✔
145
        mgmtV1.GET(ApiUrlManagementArtifacts, controller.GetImages)
3✔
146
        mgmtV1.GET(ApiUrlManagementArtifactsList, controller.ListImages)
3✔
147
        mgmtV1.GET(ApiUrlManagementArtifactsId, controller.GetImage)
3✔
148
        mgmtV1.GET(ApiUrlManagementArtifactsIdDownload, controller.DownloadLink)
3✔
149
        if !controller.config.DisableNewReleasesFeature {
6✔
150
                mgmtV1.DELETE(ApiUrlManagementArtifactsId, controller.DeleteImage)
3✔
151
                mgmtV1.Group(".").Use(artifcatType).
3✔
152
                        POST(ApiUrlManagementArtifacts, controller.NewImage).
3✔
153
                        POST(ApiUrlManagementArtifactsGenerate, controller.GenerateImage)
3✔
154
                mgmtV1.Group(".").Use(contenttype.CheckJSON()).
3✔
155
                        PUT(ApiUrlManagementArtifactsId, controller.EditImage)
3✔
156

3✔
157
        } else {
4✔
158
                mgmtV1.DELETE(ApiUrlManagementArtifactsId, ServiceUnavailable)
1✔
159

1✔
160
                mgmtV1.Group(".").Use(artifcatType).
1✔
161
                        POST(ApiUrlManagementArtifacts, ServiceUnavailable).
1✔
162
                        POST(ApiUrlManagementArtifactsGenerate, ServiceUnavailable)
1✔
163
                mgmtV1.PUT(ApiUrlManagementArtifactsId, ServiceUnavailable)
1✔
164

1✔
165
        }
1✔
166
        if !controller.config.DisableNewReleasesFeature && cfg.EnableDirectUpload {
5✔
167
                log.NewEmpty().Infof(
2✔
168
                        "direct upload enabled: POST %s",
2✔
169
                        ApiUrlManagementArtifactsDirectUpload,
2✔
170
                )
2✔
171
                if cfg.EnableDirectUploadSkipVerify {
3✔
172
                        log.NewEmpty().Info(
1✔
173
                                "direct upload enabled SkipVerify",
1✔
174
                        )
1✔
175
                }
1✔
176
                mgmtV1.Group(".").Use(contenttype.CheckJSON()).
2✔
177
                        POST(ApiUrlManagementArtifactsDirectUpload,
2✔
178
                                controller.UploadLink).
2✔
179
                        POST(ApiUrlManagementArtifactsCompleteUpload,
2✔
180
                                controller.CompleteUpload)
2✔
181
        }
182
}
183

184
func NewDeploymentsResourceRoutes(router *gin.RouterGroup, controller *DeploymentsApiHandlers) {
3✔
185

3✔
186
        if controller == nil {
3✔
187
                return
×
188
        }
×
189
        mgmtV1 := router.Group(ApiUrlManagement)
3✔
190
        mgmtV1.Use(identity.Middleware())
3✔
191
        mgmtV2 := router.Group(ApiUrlManagementV2)
3✔
192
        mgmtV2.Use(identity.Middleware())
3✔
193

3✔
194
        mgmtV1.GET(ApiUrlManagementDeployments, controller.LookupDeployment)
3✔
195
        mgmtV2.GET(ApiUrlManagementV2Deployments, controller.LookupDeploymentV2)
3✔
196
        mgmtV1.GET(ApiUrlManagementDeploymentsId, controller.GetDeployment)
3✔
197
        mgmtV1.GET(ApiUrlManagementDeploymentsStatistics, controller.GetDeploymentStats)
3✔
198
        mgmtV1.GET(ApiUrlManagementDeploymentsDevices,
3✔
199
                controller.GetDeviceStatusesForDeployment)
3✔
200
        mgmtV1.GET(ApiUrlManagementDeploymentsDevicesList,
3✔
201
                controller.GetDevicesListForDeployment)
3✔
202
        mgmtV1.GET(ApiUrlManagementDeploymentsLog,
3✔
203
                controller.GetDeploymentLogForDevice)
3✔
204
        mgmtV1.GET(ApiUrlManagementDeploymentsDeviceId,
3✔
205
                controller.ListDeviceDeployments)
3✔
206
        mgmtV1.GET(ApiUrlManagementDeploymentsDeviceList,
3✔
207
                controller.GetDeploymentDeviceList)
3✔
208

3✔
209
        mgmtV1.DELETE(ApiUrlManagementDeploymentsDeviceId,
3✔
210
                controller.AbortDeviceDeployments)
3✔
211
        mgmtV1.DELETE(ApiUrlManagementDeploymentsDeviceHistory,
3✔
212
                controller.DeleteDeviceDeploymentsHistory)
3✔
213

3✔
214
        mgmtV1.Group(".").Use(contenttype.CheckJSON()).
3✔
215
                POST(ApiUrlManagementDeployments, controller.PostDeployment).
3✔
216
                POST(ApiUrlManagementDeploymentsGroup, controller.DeployToGroup).
3✔
217
                POST(ApiUrlManagementMultipleDeploymentsStatistics,
3✔
218
                        controller.GetDeploymentsStats).
3✔
219
                PUT(ApiUrlManagementDeploymentsStatus, controller.AbortDeployment)
3✔
220

3✔
221
        // Devices
3✔
222
        devices := router.Group(ApiUrlDevices)
3✔
223

3✔
224
        devices.GET(ApiUrlDevicesDownloadConfig,
3✔
225
                controller.DownloadConfiguration)
3✔
226

3✔
227
        devices.Use(identity.Middleware())
3✔
228

3✔
229
        devices.GET(ApiUrlDevicesDeploymentsNext, controller.GetDeploymentForDevice)
3✔
230
        devices.Group(".").Use(contenttype.CheckJSON()).
3✔
231
                POST(ApiUrlDevicesDeploymentsNext,
3✔
232
                        controller.GetDeploymentForDevice).
3✔
233
                PUT(ApiUrlDevicesDeploymentStatus,
3✔
234
                        controller.PutDeploymentStatusForDevice).
3✔
235
                PUT(ApiUrlDevicesDeploymentsLog,
3✔
236
                        controller.PutDeploymentLogForDevice)
3✔
237

238
}
239

240
func NewLimitsResourceRoutes(router *gin.RouterGroup, controller *DeploymentsApiHandlers) {
3✔
241

3✔
242
        if controller == nil {
3✔
243
                return
×
244
        }
×
245
        mgmtV1 := router.Group(ApiUrlManagement)
3✔
246

3✔
247
        mgmtV1.GET(ApiUrlManagementLimitsName, controller.GetLimit)
3✔
248

249
}
250

251
func InternalRoutes(router *gin.RouterGroup, controller *DeploymentsApiHandlers) {
3✔
252
        if controller == nil {
3✔
253
                return
×
254
        }
×
255
        accesslogErrorsOnly := accesslog.AccessLogger{
3✔
256
                DisableLog: func(c *gin.Context) bool {
4✔
257
                        if c.Writer.Status()/100 == 2 {
2✔
258
                                // 2XX
1✔
259
                                return true
1✔
260
                        }
1✔
261
                        return false
×
262
                },
263
        }
264
        // Health Check
265
        // Skiping logging 2XX status code requests to decrease        noise
266
        router.GET(ApiUrlInternalAlive, accesslogErrorsOnly.Middleware,
3✔
267
                controller.AliveHandler)
3✔
268
        router.GET(ApiUrlInternalHealth, accesslogErrorsOnly.Middleware,
3✔
269
                controller.HealthHandler)
3✔
270

3✔
271
        router.Use(accesslog.Middleware())
3✔
272

3✔
273
        router.POST(ApiUrlInternalTenants, controller.ProvisionTenantsHandler)
3✔
274
        router.GET(ApiUrlInternalTenantDeployments, controller.DeploymentsPerTenantHandler)
3✔
275
        router.GET(ApiUrlInternalTenantDeploymentsDevices,
3✔
276
                controller.ListDeviceDeploymentsByIDsInternal)
3✔
277
        router.GET(ApiUrlInternalTenantDeploymentsDevice,
3✔
278
                controller.ListDeviceDeploymentsInternal)
3✔
279
        router.DELETE(ApiUrlInternalTenantDeploymentsDevice,
3✔
280
                controller.AbortDeviceDeploymentsInternal)
3✔
281
        // per-tenant storage settings
3✔
282
        router.GET(ApiUrlInternalTenantStorageSettings, controller.GetTenantStorageSettingsHandler)
3✔
283
        router.PUT(ApiUrlInternalTenantStorageSettings, controller.PutTenantStorageSettingsHandler)
3✔
284

3✔
285
        // Configuration deployments (internal)
3✔
286
        router.POST(ApiUrlInternalDeviceConfigurationDeployments,
3✔
287
                controller.PostDeviceConfigurationDeployment)
3✔
288

3✔
289
        // Last device deployment status deployments (internal)
3✔
290
        router.POST(ApiUrlInternalDeviceDeploymentLastStatusDeployments,
3✔
291
                controller.GetDeviceDeploymentLastStatus)
3✔
292

3✔
293
        if !controller.config.DisableNewReleasesFeature {
6✔
294
                router.POST(ApiUrlInternalTenantArtifacts, controller.NewImageForTenantHandler)
3✔
295
        } else {
4✔
296
                router.POST(ApiUrlInternalTenantArtifacts, ServiceUnavailable)
1✔
297
        }
1✔
298
}
299

300
func ReleasesRoutes(router *gin.RouterGroup, controller *DeploymentsApiHandlers) {
3✔
301
        if controller == nil {
3✔
302
                return
×
303
        }
×
304
        mgmtV1 := router.Group(ApiUrlManagement)
3✔
305
        mgmtV2 := router.Group(ApiUrlManagementV2)
3✔
306

3✔
307
        if controller.config.DisableNewReleasesFeature {
4✔
308
                mgmtV1.GET(ApiUrlManagementReleases, controller.GetReleases)
1✔
309
                mgmtV1.GET(ApiUrlManagementReleasesList, controller.ListReleases)
1✔
310

1✔
311
        } else {
4✔
312

3✔
313
                mgmtV1.GET(ApiUrlManagementReleases, controller.GetReleases)
3✔
314
                mgmtV1.GET(ApiUrlManagementReleasesList, controller.ListReleases)
3✔
315
                mgmtV2.GET(ApiUrlManagementV2Releases, controller.ListReleasesV2)
3✔
316
                mgmtV2.GET(ApiUrlManagementV2ReleasesName, controller.GetRelease)
3✔
317
                mgmtV2.GET(ApiUrlManagementV2ReleaseAllTags, controller.GetReleaseTagKeys)
3✔
318
                mgmtV2.GET(ApiUrlManagementV2ReleaseAllUpdateTypes, controller.GetReleasesUpdateTypes)
3✔
319
                mgmtV2.DELETE(ApiUrlManagementV2Releases, controller.DeleteReleases)
3✔
320
                mgmtV2.Group(".").Use(contenttype.CheckJSON()).
3✔
321
                        PUT(ApiUrlManagementV2ReleaseTags, controller.PutReleaseTags).
3✔
322
                        PATCH(ApiUrlManagementV2ReleasesName, controller.PatchRelease)
3✔
323

3✔
324
        }
3✔
325
}
326

327
func FMTConfigURL(scheme, hostname, deploymentID, deviceType, deviceID string) string {
2✔
328
        repl := strings.NewReplacer(
2✔
329
                ":"+ParamDeploymentID, url.PathEscape(deploymentID),
2✔
330
                ":"+ParamDeviceType, url.PathEscape(deviceType),
2✔
331
                ":"+ParamDeviceID, url.PathEscape(deviceID),
2✔
332
        )
2✔
333
        return scheme + "://" + hostname + ApiUrlDevices + repl.Replace(ApiUrlDevicesDownloadConfig)
2✔
334
}
2✔
335

336
func ServiceUnavailable(c *gin.Context) {
1✔
337
        c.Status(http.StatusServiceUnavailable)
1✔
338
}
1✔
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