• 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

86.61
/backend/services/deployments/store/mongo/datastore_mongo_releases.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 mongo
15

16
import (
17
        "context"
18
        "time"
19

20
        "github.com/pkg/errors"
21
        "go.mongodb.org/mongo-driver/bson"
22
        "go.mongodb.org/mongo-driver/mongo"
23
        mopts "go.mongodb.org/mongo-driver/mongo/options"
24

25
        "github.com/mendersoftware/mender-server/pkg/identity"
26
        "github.com/mendersoftware/mender-server/pkg/log"
27
        mstore "github.com/mendersoftware/mender-server/pkg/store"
28

29
        "github.com/mendersoftware/mender-server/services/deployments/model"
30
        "github.com/mendersoftware/mender-server/services/deployments/store"
31
)
32

33
func (db *DataStoreMongo) UpdateReleaseArtifactDescription(
34
        ctx context.Context,
35
        artifactToEdit *model.Image,
36
        releaseName string,
37
) error {
×
38
        database := db.client.Database(mstore.DbFromContext(ctx, DatabaseName))
×
39
        collReleases := database.Collection(CollectionReleases)
×
40

×
41
        update := bson.M{
×
42
                "$set": bson.M{
×
43
                        StorageKeyReleaseArtifactsIndexDescription: artifactToEdit.ImageMeta.Description,
×
44
                        StorageKeyReleaseArtifactsIndexModified:    artifactToEdit.Modified,
×
45
                        StorageKeyReleaseModified:                  time.Now(),
×
46
                },
×
47
        }
×
48
        _, err := collReleases.UpdateOne(
×
49
                ctx,
×
50
                bson.M{
×
51
                        StorageKeyReleaseName:        releaseName,
×
52
                        StorageKeyReleaseArtifactsId: artifactToEdit.Id,
×
53
                },
×
54
                update,
×
55
        )
×
56
        if err != nil {
×
57
                return err
×
58
        }
×
59
        return nil
×
60
}
61

62
func (db *DataStoreMongo) UpdateReleaseArtifacts(
63
        ctx context.Context,
64
        artifactToAdd *model.Image,
65
        artifactToRemove *model.Image,
66
        releaseName string,
67
) error {
1✔
68
        database := db.client.Database(mstore.DbFromContext(ctx, DatabaseName))
1✔
69
        collReleases := database.Collection(CollectionReleases)
1✔
70

1✔
71
        opt := &mopts.UpdateOptions{}
1✔
72
        update := bson.M{
1✔
73
                "$set": bson.M{
1✔
74
                        StorageKeyReleaseName:     releaseName,
1✔
75
                        StorageKeyReleaseModified: time.Now(),
1✔
76
                },
1✔
77
        }
1✔
78
        if artifactToRemove != nil {
2✔
79
                update["$pull"] = bson.M{
1✔
80
                        StorageKeyReleaseArtifacts: bson.M{StorageKeyId: artifactToRemove.Id},
1✔
81
                }
1✔
82
                update["$inc"] = bson.M{
1✔
83
                        StorageKeyReleaseArtifactsCount: -1,
1✔
84
                }
1✔
85
        }
1✔
86
        if artifactToAdd != nil {
2✔
87
                upsert := true
1✔
88
                opt.Upsert = &upsert
1✔
89
                update["$push"] = bson.M{StorageKeyReleaseArtifacts: artifactToAdd}
1✔
90
                update["$inc"] = bson.M{
1✔
91
                        StorageKeyReleaseArtifactsCount: 1,
1✔
92
                }
1✔
93
        }
1✔
94
        _, err := collReleases.UpdateOne(
1✔
95
                ctx,
1✔
96
                bson.M{StorageKeyReleaseName: releaseName},
1✔
97
                update,
1✔
98
                opt,
1✔
99
        )
1✔
100
        if err != nil {
1✔
101
                return err
×
102
        }
×
103
        if artifactToRemove != nil {
2✔
104
                r := collReleases.FindOneAndDelete(
1✔
105
                        ctx,
1✔
106
                        bson.M{
1✔
107
                                StorageKeyReleaseName:      releaseName,
1✔
108
                                StorageKeyReleaseArtifacts: bson.M{"$size": 0},
1✔
109
                        },
1✔
110
                )
1✔
111
                if r.Err() != nil {
2✔
112
                        return err
1✔
113
                }
1✔
114
        }
115
        return nil
1✔
116
}
117

118
func (db *DataStoreMongo) ListReleaseTags(ctx context.Context) (model.Tags, error) {
1✔
119
        l := log.FromContext(ctx)
1✔
120
        tagKeys, err := db.client.
1✔
121
                Database(mstore.DbFromContext(ctx, DatabaseName)).
1✔
122
                Collection(CollectionReleases).
1✔
123
                Distinct(ctx, StorageKeyReleaseTags, bson.D{})
1✔
124
        if err != nil {
2✔
125
                return nil, errors.WithMessage(err,
1✔
126
                        "mongo: failed to retrieve distinct tags")
1✔
127
        }
1✔
128
        ret := make([]model.Tag, 0, len(tagKeys))
1✔
129
        for _, elem := range tagKeys {
2✔
130
                if key, ok := elem.(string); ok {
2✔
131
                        ret = append(ret, model.Tag(key))
1✔
132
                } else {
2✔
133
                        l.Warnf("unexpected data type (%T) received from distinct call: "+
1✔
134
                                "ignoring result", elem)
1✔
135
                }
1✔
136
        }
137

138
        return ret, err
1✔
139
}
140

141
func (db *DataStoreMongo) ReplaceReleaseTags(
142
        ctx context.Context,
143
        releaseName string,
144
        tags model.Tags,
145
) error {
1✔
146
        // Check preconditions
1✔
147
        if len(tags) > model.TagsMaxUnique {
2✔
148
                return model.ErrTooManyUniqueTags
1✔
149
        }
1✔
150

151
        collReleases := db.client.
1✔
152
                Database(mstore.DbFromContext(ctx, DatabaseName)).
1✔
153
                Collection(CollectionReleases)
1✔
154

1✔
155
        // Check if added tags will exceed limits
1✔
156
        if len(tags) > 0 {
2✔
157
                inUseTags, err := db.ListReleaseTags(ctx)
1✔
158
                if err != nil {
2✔
159
                        return errors.WithMessage(err, "mongo: failed to count in-use tags")
1✔
160
                }
1✔
161
                tagSet := make(map[model.Tag]struct{}, len(inUseTags))
1✔
162
                for _, tagKey := range inUseTags {
2✔
163
                        tagSet[tagKey] = struct{}{}
1✔
164
                }
1✔
165
                for _, tag := range tags {
2✔
166
                        delete(tagSet, tag)
1✔
167
                }
1✔
168
                if len(tags)+len(tagSet) > model.TagsMaxUnique {
2✔
169
                        return model.ErrTooManyUniqueTags
1✔
170
                }
1✔
171
        }
172

173
        // Update release tags
174
        res, err := collReleases.UpdateOne(ctx, bson.D{{
1✔
175
                Key: StorageKeyReleaseName, Value: releaseName,
1✔
176
        }}, bson.D{{
1✔
177
                Key:   mongoOpSet,
1✔
178
                Value: bson.D{{Key: StorageKeyReleaseTags, Value: tags}},
1✔
179
        }})
1✔
180
        if err != nil {
2✔
181
                return errors.WithMessage(err, "mongo: failed to update release tags")
1✔
182
        } else if res.MatchedCount <= 0 {
3✔
183
                return store.ErrNotFound
1✔
184
        }
1✔
185
        return nil
1✔
186
}
187

188
func (db *DataStoreMongo) UpdateRelease(
189
        ctx context.Context,
190
        releaseName string,
191
        release model.ReleasePatch,
192
) error {
1✔
193
        collReleases := db.client.
1✔
194
                Database(mstore.DbFromContext(ctx, DatabaseName)).
1✔
195
                Collection(CollectionReleases)
1✔
196

1✔
197
        err := release.Validate()
1✔
198
        if err != nil {
2✔
199
                return errors.Wrap(err, "cant update release due to validation errors")
1✔
200
        }
1✔
201

202
        // Update release, at the moment we update only the notes,
203
        // it is on purpose that we take only this field explicitly,
204
        // once there is a need we can extend
205
        res, err := collReleases.UpdateOne(
1✔
206
                ctx,
1✔
207
                bson.D{
1✔
208
                        {
1✔
209
                                Key: StorageKeyReleaseName, Value: releaseName,
1✔
210
                        },
1✔
211
                },
1✔
212
                bson.D{
1✔
213
                        {
1✔
214
                                Key: mongoOpSet,
1✔
215
                                Value: bson.D{
1✔
216
                                        {
1✔
217
                                                Key: StorageKeyReleaseNotes, Value: release.Notes,
1✔
218
                                        },
1✔
219
                                },
1✔
220
                        },
1✔
221
                },
1✔
222
        )
1✔
223
        if err != nil {
1✔
224
                return errors.WithMessage(err, "mongo: failed to update release")
×
225
        } else if res.MatchedCount <= 0 {
1✔
226
                return store.ErrNotFound
×
227
        }
×
228
        return nil
1✔
229
}
230

231
// Save the possibly new update types
232
func (db *DataStoreMongo) SaveUpdateTypes(ctx context.Context, updateTypes []string) error {
1✔
233
        database := db.client.Database(DatabaseName)
1✔
234
        c := database.Collection(CollectionUpdateTypes)
1✔
235

1✔
236
        if len(updateTypes) < 1 {
2✔
237
                return nil
1✔
238
        }
1✔
239

240
        tenantId := ""
1✔
241
        if id := identity.FromContext(ctx); id != nil {
2✔
242
                tenantId = id.Tenant
1✔
243
        }
1✔
244
        options := mopts.UpdateOptions{}
1✔
245
        options.SetUpsert(true)
1✔
246
        _, err := c.UpdateOne(
1✔
247
                ctx,
1✔
248
                bson.M{
1✔
249
                        StorageKeyTenantId: tenantId,
1✔
250
                },
1✔
251
                bson.M{
1✔
252
                        "$addToSet": bson.M{
1✔
253
                                StorageKeyStorageReleaseUpdateTypes: bson.M{
1✔
254
                                        "$each": updateTypes,
1✔
255
                                },
1✔
256
                        },
1✔
257
                },
1✔
258
                &options,
1✔
259
        )
1✔
260
        return err
1✔
261
}
262

263
// Get the update types
264
func (db *DataStoreMongo) GetUpdateTypes(ctx context.Context) ([]string, error) {
1✔
265
        database := db.client.Database(DatabaseName)
1✔
266
        c := database.Collection(CollectionUpdateTypes)
1✔
267

1✔
268
        tenantId := ""
1✔
269
        if id := identity.FromContext(ctx); id != nil {
2✔
270
                tenantId = id.Tenant
1✔
271
        }
1✔
272
        result := c.FindOne(
1✔
273
                ctx,
1✔
274
                bson.M{
1✔
275
                        StorageKeyTenantId: tenantId,
1✔
276
                },
1✔
277
        )
1✔
278
        type updateType struct {
1✔
279
                UpdateTypes []string `bson:"update_types"`
1✔
280
        }
1✔
281
        var updateTypes updateType
1✔
282
        err := result.Decode(&updateTypes)
1✔
283
        if err == mongo.ErrNoDocuments {
1✔
UNCOV
284
                return []string{}, nil
×
UNCOV
285
        }
×
286
        if err != nil {
1✔
287
                return []string{}, err
×
288
        } else {
1✔
289
                return updateTypes.UpdateTypes, nil
1✔
290
        }
1✔
291
}
292

293
func (db *DataStoreMongo) DeleteReleasesByNames(ctx context.Context, names []string) error {
1✔
294
        database := db.client.Database(mstore.DbFromContext(ctx, DatabaseName))
1✔
295
        collDevs := database.Collection(CollectionReleases)
1✔
296
        query := bson.M{
1✔
297
                StorageKeyReleaseName: bson.M{
1✔
298
                        "$in": names,
1✔
299
                },
1✔
300
        }
1✔
301
        _, err := collDevs.DeleteMany(ctx, query)
1✔
302
        return err
1✔
303
}
1✔
304

305
func (db *DataStoreMongo) GetRelease(
306
        ctx context.Context,
307
        releaseName string,
308
) (*model.Release, error) {
1✔
309

1✔
310
        database := db.client.Database(mstore.DbFromContext(ctx, DatabaseName))
1✔
311
        collReleases := database.Collection(CollectionReleases)
1✔
312

1✔
313
        release := new(model.Release)
1✔
314
        if err := collReleases.FindOne(ctx, bson.M{StorageKeyId: releaseName}).
1✔
315
                Decode(release); err != nil {
2✔
316
                if err == mongo.ErrNoDocuments {
2✔
317
                        return nil, store.ErrNotFound
1✔
318
                }
1✔
319
                return nil, err
×
320
        }
321
        return release, nil
1✔
322
}
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