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

mendersoftware / mender-server / 1622978334

13 Jan 2025 03:51PM UTC coverage: 72.802% (-3.8%) from 76.608%
1622978334

Pull #300

gitlab-ci

alfrunes
fix: Deployment device count should not exceed max devices

Added a condition to skip deployments when the device count reaches max
devices.

Changelog: Title
Ticket: MEN-7847
Signed-off-by: Alf-Rune Siqveland <alf.rune@northern.tech>
Pull Request #300: fix: Deployment device count should not exceed max devices

4251 of 6164 branches covered (68.96%)

Branch coverage included in aggregate %.

0 of 18 new or added lines in 1 file covered. (0.0%)

2544 existing lines in 83 files now uncovered.

42741 of 58384 relevant lines covered (73.21%)

21.49 hits per line

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

63.19
/backend/services/deviceauth/main.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
package main
15

16
import (
17
        "context"
18
        "encoding/json"
19
        "fmt"
20
        "os"
21
        "strings"
22
        "time"
23

24
        "github.com/pkg/errors"
25
        "github.com/urfave/cli"
26

27
        "github.com/mendersoftware/mender-server/pkg/config"
28
        "github.com/mendersoftware/mender-server/pkg/log"
29
        "github.com/mendersoftware/mender-server/pkg/version"
30

31
        cinv "github.com/mendersoftware/mender-server/services/deviceauth/client/inventory"
32
        "github.com/mendersoftware/mender-server/services/deviceauth/client/orchestrator"
33
        "github.com/mendersoftware/mender-server/services/deviceauth/client/tenant"
34
        "github.com/mendersoftware/mender-server/services/deviceauth/cmd"
35
        dconfig "github.com/mendersoftware/mender-server/services/deviceauth/config"
36
        "github.com/mendersoftware/mender-server/services/deviceauth/store/mongo"
37
)
38

39
const (
40
        cliDefaultRateLimit = 50
41
)
42

43
var appVersion = version.Get()
44

45
func main() {
2✔
46
        doMain(os.Args)
2✔
47
}
2✔
48

49
func doMain(args []string) {
2✔
50
        var configPath string
2✔
51
        var debug bool
2✔
52

2✔
53
        app := cli.NewApp()
2✔
54
        app.Usage = "Device Authentication Service"
2✔
55

2✔
56
        app.Flags = []cli.Flag{
2✔
57
                cli.StringFlag{
2✔
58
                        Name: "config",
2✔
59
                        Usage: "Configuration `FILE`." +
2✔
60
                                " Supports JSON, TOML, YAML and HCL formatted configs.",
2✔
61
                        Destination: &configPath,
2✔
62
                },
2✔
63
                cli.BoolFlag{
2✔
64
                        Name:        "debug",
2✔
65
                        Usage:       "Enable debug logging",
2✔
66
                        Destination: &debug,
2✔
67
                },
2✔
68
        }
2✔
69

2✔
70
        app.Commands = []cli.Command{
2✔
71
                {
2✔
72
                        Name:  "server",
2✔
73
                        Usage: "Run the service as a server",
2✔
74
                        Flags: []cli.Flag{
2✔
75
                                cli.BoolFlag{
2✔
76
                                        Name:  "automigrate",
2✔
77
                                        Usage: "Run database migrations before starting.",
2✔
78
                                },
2✔
79
                        },
2✔
80

2✔
81
                        Action: cmdServer,
2✔
82
                },
2✔
83
                {
2✔
84
                        Name:  "migrate",
2✔
85
                        Usage: "Run migrations and exit",
2✔
86
                        Flags: []cli.Flag{
2✔
87
                                cli.StringFlag{
2✔
88
                                        Name:  "tenant",
2✔
89
                                        Usage: "Tenant ID (optional).",
2✔
90
                                },
2✔
91
                                cli.BoolFlag{
2✔
92
                                        Name:  "list-tenants",
2✔
93
                                        Usage: "List Tenant IDs. Not performing migrations.",
2✔
94
                                },
2✔
95
                        },
2✔
96

2✔
97
                        Action: cmdMigrate,
2✔
98
                },
2✔
99
                {
2✔
100
                        Name:  "propagate-inventory-statuses",
2✔
101
                        Usage: "Push device statuses to inventory",
2✔
102
                        Flags: []cli.Flag{
2✔
103
                                cli.StringFlag{
2✔
104
                                        Name:  "tenant_id",
2✔
105
                                        Usage: "Tenant ID (optional) - propagate for just a single tenant.",
2✔
106
                                },
2✔
107
                                cli.StringFlag{
2✔
108
                                        Name:  "force-set-migration",
2✔
109
                                        Usage: "Migration version to be stored in migration_info collection.",
2✔
110
                                },
2✔
111
                                cli.BoolFlag{
2✔
112
                                        Name: "dry-run",
2✔
113
                                        Usage: "Do not perform any inventory modifications," +
2✔
114
                                                " just scan and print devices.",
2✔
115
                                },
2✔
116
                        },
2✔
117

2✔
118
                        Action: cmdPropagateStatusesInventory,
2✔
119
                },
2✔
120
                {
2✔
121
                        Name:  "propagate-inventory-id-data",
2✔
122
                        Usage: "Push device id_data to inventory",
2✔
123
                        Flags: []cli.Flag{
2✔
124
                                cli.StringFlag{
2✔
125
                                        Name:  "tenant_id",
2✔
126
                                        Usage: "Tenant ID (optional) - propagate for just a single tenant.",
2✔
127
                                },
2✔
128
                                cli.BoolFlag{
2✔
129
                                        Name: "dry-run",
2✔
130
                                        Usage: "Do not perform any inventory modifications," +
2✔
131
                                                " just scan and print devices.",
2✔
132
                                },
2✔
133
                        },
2✔
134

2✔
135
                        Action: cmdPropagateIdDataInventory,
2✔
136
                },
2✔
137
                {
2✔
138
                        Name:  "propagate-reporting",
2✔
139
                        Usage: "Trigger a reindex of all the devices in the reporting services ",
2✔
140
                        Flags: []cli.Flag{
2✔
141
                                cli.StringFlag{
2✔
142
                                        Name:  "tenant_id",
2✔
143
                                        Usage: "Tenant ID (optional) - propagate for just a single tenant.",
2✔
144
                                },
2✔
145
                                cli.UintFlag{
2✔
146
                                        Name:  "rate-limit",
2✔
147
                                        Usage: "`N`umber of reindexing batch requests per second.",
2✔
148
                                        Value: cliDefaultRateLimit,
2✔
149
                                },
2✔
150
                                cli.BoolFlag{
2✔
151
                                        Name: "dry-run",
2✔
152
                                        Usage: "Do not perform any inventory modifications," +
2✔
153
                                                " just scan and print devices.",
2✔
154
                                },
2✔
155
                        },
2✔
156

2✔
157
                        Action: cmdPropagateReporting,
2✔
158
                },
2✔
159
                {
2✔
160
                        Name:  "maintenance",
2✔
161
                        Usage: "Run maintenance operations and exit",
2✔
162
                        Flags: []cli.Flag{
2✔
163
                                cli.BoolFlag{
2✔
164
                                        Name:  "decommissioning-cleanup",
2✔
165
                                        Usage: "Cleanup devauth database from leftovers after failed decommissioning",
2✔
166
                                },
2✔
167
                                cli.StringFlag{
2✔
168
                                        Name:  "tenant",
2✔
169
                                        Usage: "Tenant ID (optional).",
2✔
170
                                },
2✔
171
                                cli.BoolFlag{
2✔
172
                                        Name: "dry-run",
2✔
173
                                        Usage: "Do not perform any modifications and serves" +
2✔
174
                                                " only as a way to inspect changes and detect if any are necessary",
2✔
175
                                },
2✔
176
                        },
2✔
177

2✔
178
                        Action: cmdMaintenance,
2✔
179
                }, {
2✔
180
                        Name:  "check-device-limits",
2✔
181
                        Usage: "Warn users if user is approaching device limit",
2✔
182
                        Description: "Loops through all tenant databases and " +
2✔
183
                                "checks if the number of devices is over a " +
2✔
184
                                "threshold of the allowed limit and sends an " +
2✔
185
                                "email asking the user to upgrade or decomission" +
2✔
186
                                "unused devices.",
2✔
187
                        Flags: []cli.Flag{
2✔
188
                                cli.Float64Flag{
2✔
189
                                        Name:  "threshold, t",
2✔
190
                                        Value: 90.0,
2✔
191
                                        Usage: "Threshold in percent (%) of " +
2✔
192
                                                "device limit that trigger " +
2✔
193
                                                "email event.",
2✔
194
                                },
2✔
195
                        },
2✔
196
                        Action: cmdCheckDeviceLimits,
2✔
197
                },
2✔
198
                {
2✔
199
                        Name:  "version",
2✔
200
                        Usage: "Show version information",
2✔
201
                        Flags: []cli.Flag{
2✔
202
                                cli.StringFlag{
2✔
203
                                        Name:  "output",
2✔
204
                                        Usage: "Output format <json|text>",
2✔
205
                                        Value: "text",
2✔
206
                                },
2✔
207
                        },
2✔
208
                        Action: func(args *cli.Context) error {
2✔
209
                                switch strings.ToLower(args.String("output")) {
×
210
                                case "text":
×
211
                                        fmt.Print(appVersion)
×
212
                                case "json":
×
213
                                        _ = json.NewEncoder(os.Stdout).Encode(appVersion)
×
214
                                default:
×
215
                                        return fmt.Errorf("Unknown output format %q", args.String("output"))
×
216
                                }
217
                                return nil
×
218
                        },
219
                },
220
        }
221

222
        app.Version = appVersion.Version
2✔
223
        app.Action = cmdServer
2✔
224
        app.Before = func(args *cli.Context) error {
4✔
225
                log.Setup(debug)
2✔
226

2✔
227
                err := config.FromConfigFile(configPath, dconfig.Defaults)
2✔
228
                if err != nil {
2✔
229
                        return cli.NewExitError(
×
230
                                fmt.Sprintf("error loading configuration: %s", err),
×
231
                                1)
×
232
                }
×
233

234
                // Enable setting config values by environment variables
235
                config.Config.SetEnvPrefix("DEVICEAUTH")
2✔
236
                config.Config.AutomaticEnv()
2✔
237

2✔
238
                return nil
2✔
239
        }
240

241
        _ = app.Run(args)
2✔
242
}
243

UNCOV
244
func cmdServer(args *cli.Context) error {
×
UNCOV
245
        l := log.New(log.Ctx{})
×
UNCOV
246

×
UNCOV
247
        db, err := mongo.NewDataStoreMongo(makeDataStoreConfig())
×
UNCOV
248
        if err != nil {
×
249
                return cli.NewExitError(
×
250
                        fmt.Sprintf("failed to connect to db: %v", err),
×
251
                        2)
×
252
        }
×
253

UNCOV
254
        if args.Bool("automigrate") {
×
UNCOV
255
                db = db.WithAutomigrate().(*mongo.DataStoreMongo)
×
UNCOV
256
        }
×
257

UNCOV
258
        if config.Config.Get(dconfig.SettingTenantAdmAddr) != "" {
×
259
                db = db.WithMultitenant()
×
260
        }
×
261

UNCOV
262
        ctx := context.Background()
×
UNCOV
263
        err = db.Migrate(ctx, mongo.DbVersion)
×
UNCOV
264
        if err != nil {
×
265
                return cli.NewExitError(
×
266
                        fmt.Sprintf("failed to run migrations: %v", err),
×
267
                        3)
×
268
        }
×
269

UNCOV
270
        l.Print("Device Authentication Service starting up")
×
UNCOV
271

×
UNCOV
272
        err = RunServer(config.Config)
×
UNCOV
273
        if err != nil {
×
274
                return cli.NewExitError(err.Error(), 4)
×
275
        }
×
276

UNCOV
277
        return nil
×
278
}
279

280
func cmdMigrate(args *cli.Context) error {
2✔
281
        err := cmd.Migrate(config.Config, args.String("tenant"), args.Bool("list-tenants"))
2✔
282
        if err != nil {
3✔
283
                return cli.NewExitError(err, 5)
1✔
284
        }
1✔
285
        return nil
2✔
286
}
287

288
func cmdMaintenance(args *cli.Context) error {
×
289
        err := cmd.Maintenance(
×
290
                args.Bool("decommissioning-cleanup"),
×
291
                args.String("tenant"),
×
292
                args.Bool("dry-run"),
×
293
        )
×
294
        if err != nil {
×
295
                return cli.NewExitError(err, 6)
×
296
        }
×
297
        return nil
×
298
}
299

300
func cmdPropagateStatusesInventory(args *cli.Context) error {
1✔
301
        db, err := mongo.NewDataStoreMongo(makeDataStoreConfig())
1✔
302
        if err != nil {
1✔
303
                return err
×
304
        }
×
305

306
        inv := config.Config.GetString(dconfig.SettingInventoryAddr)
1✔
307
        c := cinv.NewClient(inv, false)
1✔
308

1✔
309
        err = cmd.PropagateStatusesInventory(db,
1✔
310
                c,
1✔
311
                args.String("tenant_id"),
1✔
312
                args.String("force-set-migration"),
1✔
313
                args.Bool("dry-run"))
1✔
314
        if err != nil {
1✔
315
                return cli.NewExitError(err, 7)
×
316
        }
×
317
        return nil
1✔
318
}
319

320
func cmdPropagateIdDataInventory(args *cli.Context) error {
×
321
        db, err := mongo.NewDataStoreMongo(makeDataStoreConfig())
×
322
        if err != nil {
×
323
                return err
×
324
        }
×
325

326
        inv := config.Config.GetString(dconfig.SettingInventoryAddr)
×
327
        c := cinv.NewClient(inv, false)
×
328

×
329
        err = cmd.PropagateIdDataInventory(db,
×
330
                c,
×
331
                args.String("tenant_id"),
×
332
                args.Bool("dry-run"))
×
333
        if err != nil {
×
334
                return cli.NewExitError(err, 7)
×
335
        }
×
336
        return nil
×
337
}
338

339
func cmdPropagateReporting(args *cli.Context) error {
×
340
        if !config.Config.GetBool(dconfig.SettingEnableReporting) {
×
341
                return cli.NewExitError(errors.New("reporting support not enabled"), 1)
×
342
        }
×
343

344
        db, err := mongo.NewDataStoreMongo(makeDataStoreConfig())
×
345
        if err != nil {
×
346
                return err
×
347
        }
×
348

349
        wflows := orchestrator.NewClient(orchestrator.Config{
×
350
                OrchestratorAddr: config.Config.GetString(
×
351
                        dconfig.SettingOrchestratorAddr,
×
352
                ),
×
353
        })
×
354

×
355
        var requestPeriod time.Duration
×
356
        if rateLimit := args.Uint("rate-limit"); rateLimit > 0 {
×
357
                requestPeriod = time.Second / time.Duration(rateLimit)
×
358
        }
×
359

360
        err = cmd.PropagateReporting(
×
361
                db,
×
362
                wflows,
×
363
                args.String("tenant_id"),
×
364
                requestPeriod,
×
365
                args.Bool("dry-run"),
×
366
        )
×
367
        if err != nil {
×
368
                return cli.NewExitError(err, 7)
×
369
        }
×
370
        return nil
×
371
}
372

373
func makeDataStoreConfig() mongo.DataStoreMongoConfig {
1✔
374
        return mongo.DataStoreMongoConfig{
1✔
375
                ConnectionString: config.Config.GetString(dconfig.SettingDb),
1✔
376

1✔
377
                SSL:           config.Config.GetBool(dconfig.SettingDbSSL),
1✔
378
                SSLSkipVerify: config.Config.GetBool(dconfig.SettingDbSSLSkipVerify),
1✔
379

1✔
380
                Username: config.Config.GetString(dconfig.SettingDbUsername),
1✔
381
                Password: config.Config.GetString(dconfig.SettingDbPassword),
1✔
382
        }
1✔
383

1✔
384
}
1✔
385

386
func cmdCheckDeviceLimits(args *cli.Context) error {
×
387
        mgoConf := makeDataStoreConfig()
×
388
        ds, err := mongo.NewDataStoreMongo(mgoConf)
×
389
        if err != nil {
×
390
                return errors.Wrap(err, "cmd: failed to initialize DataStore client")
×
391
        }
×
392
        // Initialize tenantadm and workflows clients.
393
        tadm := tenant.NewClient(tenant.Config{
×
394
                TenantAdmAddr: config.Config.GetString(
×
395
                        dconfig.SettingTenantAdmAddr,
×
396
                ),
×
397
        })
×
398
        wflows := orchestrator.NewClient(orchestrator.Config{
×
399
                OrchestratorAddr: config.Config.GetString(
×
400
                        dconfig.SettingOrchestratorAddr,
×
401
                ),
×
402
        })
×
403
        return cmd.CheckDeviceLimits(
×
404
                args.Float64("threshold"),
×
405
                ds, tadm, wflows,
×
406
        )
×
407
}
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