• 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

0.0
/backend/services/deployments/server.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 main
16

17
import (
18
        "context"
19
        "encoding/base64"
20
        "net/http"
21
        "net/url"
22
        "strings"
23
        "time"
24

25
        "github.com/pkg/errors"
26

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

30
        api "github.com/mendersoftware/mender-server/services/deployments/api/http"
31
        "github.com/mendersoftware/mender-server/services/deployments/app"
32
        "github.com/mendersoftware/mender-server/services/deployments/client/reporting"
33
        dconfig "github.com/mendersoftware/mender-server/services/deployments/config"
34
        "github.com/mendersoftware/mender-server/services/deployments/storage"
35
        "github.com/mendersoftware/mender-server/services/deployments/storage/azblob"
36
        "github.com/mendersoftware/mender-server/services/deployments/storage/manager"
37
        "github.com/mendersoftware/mender-server/services/deployments/storage/s3"
38
        mstore "github.com/mendersoftware/mender-server/services/deployments/store/mongo"
39
)
40

UNCOV
41
func SetupS3(ctx context.Context, defaultOptions *s3.Options) (storage.ObjectStorage, error) {
×
UNCOV
42
        c := config.Config
×
UNCOV
43

×
UNCOV
44
        bucket := c.GetString(dconfig.SettingStorageBucket)
×
UNCOV
45

×
UNCOV
46
        // Copy / merge defaultOptions
×
UNCOV
47
        options := s3.NewOptions(defaultOptions).
×
UNCOV
48
                SetBucketName(bucket).
×
UNCOV
49
                SetForcePathStyle(c.GetBool(dconfig.SettingAwsS3ForcePathStyle))
×
UNCOV
50

×
UNCOV
51
        // The following parameters falls back on AWS_* environment if not set
×
UNCOV
52
        if c.IsSet(dconfig.SettingAwsS3Region) {
×
UNCOV
53
                options.SetRegion(c.GetString(dconfig.SettingAwsS3Region))
×
UNCOV
54
        }
×
UNCOV
55
        if c.IsSet(dconfig.SettingsAwsAuth) ||
×
UNCOV
56
                (c.IsSet(dconfig.SettingAwsAuthKeyId) &&
×
UNCOV
57
                        c.IsSet(dconfig.SettingAwsAuthSecret)) {
×
UNCOV
58
                options.SetStaticCredentials(
×
UNCOV
59
                        c.GetString(dconfig.SettingAwsAuthKeyId),
×
UNCOV
60
                        c.GetString(dconfig.SettingAwsAuthSecret),
×
UNCOV
61
                        c.GetString(dconfig.SettingAwsAuthToken),
×
UNCOV
62
                )
×
UNCOV
63
        }
×
UNCOV
64
        useAccelerate := c.GetBool(dconfig.SettingAwsS3UseAccelerate)
×
UNCOV
65
        if c.IsSet(dconfig.SettingAwsURI) {
×
UNCOV
66
                options.SetURI(c.GetString(dconfig.SettingAwsURI))
×
UNCOV
67
                if useAccelerate {
×
UNCOV
68
                        log.FromContext(ctx).
×
UNCOV
69
                                Warn(`cannot use s3 transfer acceleration with custom "uri": ` +
×
UNCOV
70
                                        "disabling transfer acceleration")
×
71
                }
×
72
        } else {
×
73
                options.SetUseAccelerate(c.GetBool(dconfig.SettingAwsS3UseAccelerate))
×
74
        }
×
75
        if c.IsSet(dconfig.SettingAwsExternalURI) {
×
76
                options.SetExternalURI(c.GetString(dconfig.SettingAwsExternalURI))
×
77
        }
×
UNCOV
78
        if c.IsSet(dconfig.SettingStorageProxyURI) {
×
UNCOV
79
                rawURL := c.GetString(dconfig.SettingStorageProxyURI)
×
UNCOV
80
                proxyURL, err := url.Parse(rawURL)
×
UNCOV
81
                if err != nil {
×
82
                        return nil, errors.WithMessage(err, "invalid setting `storage.proxy_uri`")
×
83
                }
×
84
                options.SetProxyURI(proxyURL)
×
85
        }
86
        if c.IsSet(dconfig.SettingAwsUnsignedHeaders) {
×
87
                options.SetUnsignedHeaders(c.GetStringSlice(dconfig.SettingAwsUnsignedHeaders))
×
UNCOV
88
        }
×
89

UNCOV
90
        storage, err := s3.New(ctx, options)
×
UNCOV
91
        return storage, err
×
92
}
93

94
func SetupBlobStorage(
95
        ctx context.Context,
96
        defaultOptions *azblob.Options,
UNCOV
97
) (storage.ObjectStorage, error) {
×
UNCOV
98
        c := config.Config
×
UNCOV
99

×
100
        // Copy / merge options
×
101
        options := azblob.NewOptions(defaultOptions)
×
102

×
103
        if c.IsSet(dconfig.SettingAzureConnectionString) {
×
104
                options.SetConnectionString(c.GetString(dconfig.SettingAzureConnectionString))
×
105
        } else if c.IsSet(dconfig.SettingAzureSharedKeyAccount) &&
×
106
                c.IsSet(dconfig.SettingAzureSharedKeyAccountKey) {
×
107
                creds := azblob.SharedKeyCredentials{
×
108
                        AccountName: c.GetString(dconfig.SettingAzureSharedKeyAccount),
×
109
                        AccountKey:  c.GetString(dconfig.SettingAzureSharedKeyAccountKey),
×
110
                }
×
111
                if c.IsSet(dconfig.SettingAzureSharedKeyURI) {
×
112
                        uri := c.GetString(dconfig.SettingAzureSharedKeyURI)
×
113
                        creds.URI = &uri
×
114
                }
×
115
                options.SetSharedKey(creds)
×
116
        }
117
        if c.IsSet(dconfig.SettingStorageProxyURI) {
×
118
                rawURL := c.GetString(dconfig.SettingStorageProxyURI)
×
UNCOV
119
                proxyURL, err := url.Parse(rawURL)
×
120
                if err != nil {
×
121
                        return nil, errors.WithMessage(err, `invalid setting "storage.proxy_uri"`)
×
122
                }
×
123
                if !strings.HasPrefix(strings.ToLower(proxyURL.Scheme), "https") {
×
124
                        log.FromContext(ctx).
×
125
                                Warnf(`setting "storage.proxy_uri" (%s) is not using https`, rawURL)
×
126
                }
×
127
                options.SetProxyURI(proxyURL)
×
128
        }
129
        return azblob.New(ctx, c.GetString(dconfig.SettingStorageBucket), options)
×
130
}
131

132
func SetupObjectStorage(ctx context.Context) (objManager storage.ObjectStorage, err error) {
×
UNCOV
133
        c := config.Config
×
UNCOV
134

×
UNCOV
135
        // Calculate s3 multipart buffer size: the minimum buffer size that
×
UNCOV
136
        // covers the maximum image size aligned to multiple of 5MiB.
×
UNCOV
137
        maxImageSize := c.GetInt64(dconfig.SettingStorageMaxImageSize)
×
UNCOV
138
        bufferSize := (((maxImageSize - 1) /
×
UNCOV
139
                (s3.MultipartMaxParts * s3.MultipartMinSize)) + 1) *
×
UNCOV
140
                s3.MultipartMinSize
×
UNCOV
141
        var (
×
UNCOV
142
                s3Options = s3.NewOptions().
×
UNCOV
143
                                SetContentType(app.ArtifactContentType).
×
UNCOV
144
                                SetBufferSize(int(bufferSize))
×
UNCOV
145
                azOptions = azblob.NewOptions().
×
UNCOV
146
                                SetContentType(app.ArtifactContentType)
×
UNCOV
147
        )
×
UNCOV
148
        var defaultStorage storage.ObjectStorage
×
UNCOV
149
        switch defType := c.GetString(dconfig.SettingDefaultStorage); defType {
×
UNCOV
150
        case dconfig.StorageTypeAWS:
×
UNCOV
151
                defaultStorage, err = SetupS3(ctx, s3Options)
×
UNCOV
152
        case dconfig.StorageTypeAzure:
×
UNCOV
153
                defaultStorage, err = SetupBlobStorage(ctx, azOptions)
×
UNCOV
154
        default:
×
155
                err = errors.Errorf(
×
156
                        `storage type must be one of %q or %q, received value %q`,
×
157
                        dconfig.StorageTypeAWS, dconfig.StorageTypeAzure, defType,
×
158
                )
×
159
        }
160
        if err != nil {
×
161
                return nil, err
×
UNCOV
162
        }
×
UNCOV
163
        return manager.New(ctx, defaultStorage, s3Options, azOptions)
×
164
}
165

UNCOV
166
func RunServer(ctx context.Context) error {
×
UNCOV
167
        c := config.Config
×
UNCOV
168
        dbClient, err := mstore.NewMongoClient(ctx, c)
×
UNCOV
169
        if err != nil {
×
UNCOV
170
                return err
×
UNCOV
171
        }
×
UNCOV
172
        defer func() {
×
UNCOV
173
                _ = dbClient.Disconnect(context.Background())
×
174
        }()
×
175

UNCOV
176
        ds := mstore.NewDataStoreMongoWithClient(dbClient)
×
UNCOV
177

×
UNCOV
178
        // Storage Layer
×
UNCOV
179
        objStore, err := SetupObjectStorage(ctx)
×
UNCOV
180
        if err != nil {
×
UNCOV
181
                return errors.WithMessage(err, "main: failed to setup storage client")
×
UNCOV
182
        }
×
183

UNCOV
184
        app := app.NewDeployments(ds, objStore, 0, false)
×
185
        if addr := c.GetString(dconfig.SettingReportingAddr); addr != "" {
×
186
                c := reporting.NewClient(addr)
×
UNCOV
187
                app = app.WithReporting(c)
×
UNCOV
188
        }
×
189

190
        // Setup API Router configuration
191
        base64Repl := strings.NewReplacer("-", "+", "_", "/", "=", "")
×
192
        expireSec := c.GetDuration(dconfig.SettingPresignExpireSeconds)
×
UNCOV
193
        apiConf := api.NewConfig().
×
UNCOV
194
                SetPresignExpire(time.Second * expireSec).
×
UNCOV
195
                SetPresignHostname(c.GetString(dconfig.SettingPresignHost)).
×
UNCOV
196
                SetPresignScheme(c.GetString(dconfig.SettingPresignScheme)).
×
UNCOV
197
                SetMaxImageSize(c.GetInt64(dconfig.SettingStorageMaxImageSize)).
×
UNCOV
198
                SetMaxGenerateDataSize(c.GetInt64(dconfig.SettingStorageMaxGenerateSize)).
×
UNCOV
199
                SetEnableDirectUpload(c.GetBool(dconfig.SettingStorageEnableDirectUpload)).
×
UNCOV
200
                SetEnableDirectUploadSkipVerify(c.GetBool(dconfig.SettingStorageDirectUploadSkipVerify)).
×
UNCOV
201
                SetDisableNewReleasesFeature(c.GetBool(dconfig.SettingDisableNewReleasesFeature))
×
UNCOV
202
        if key, err := base64.RawStdEncoding.DecodeString(
×
UNCOV
203
                base64Repl.Replace(
×
UNCOV
204
                        c.GetString(dconfig.SettingPresignSecret),
×
UNCOV
205
                ),
×
UNCOV
206
        ); err == nil {
×
UNCOV
207
                apiConf.SetPresignSecret(key)
×
UNCOV
208
        }
×
UNCOV
209
        handler, err := api.NewHandler(ctx, app, ds, apiConf)
×
UNCOV
210
        if err != nil {
×
UNCOV
211
                return err
×
UNCOV
212
        }
×
213

UNCOV
214
        listen := c.GetString(dconfig.SettingListen)
×
215

×
216
        if c.IsSet(dconfig.SettingHttps) {
×
UNCOV
217

×
UNCOV
218
                cert := c.GetString(dconfig.SettingHttpsCertificate)
×
UNCOV
219
                key := c.GetString(dconfig.SettingHttpsKey)
×
UNCOV
220

×
221
                return http.ListenAndServeTLS(listen, cert, key, handler)
×
222
        }
×
223

224
        return http.ListenAndServe(listen, handler)
×
225
}
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