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

mendersoftware / deployments / 1069331446

12 Nov 2023 09:28AM UTC coverage: 77.424% (-2.8%) from 80.241%
1069331446

Pull #961

gitlab-ci

kjaskiewiczz
feat: endpoint for bulk removal of releases by names

Changelog: Title
Ticket: MEN-6354

Signed-off-by: Krzysztof Jaskiewicz <krzysztof.jaskiewicz@northern.tech>
Pull Request #961: add support for bulk removal of releases by names

0 of 97 new or added lines in 5 files covered. (0.0%)

11 existing lines in 1 file now uncovered.

4009 of 5178 relevant lines covered (77.42%)

55.17 hits per line

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

82.3
/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/go-lib-micro/identity"
26
        "github.com/mendersoftware/go-lib-micro/log"
27
        mstore "github.com/mendersoftware/go-lib-micro/store"
28

29
        "github.com/mendersoftware/deployments/model"
30
        "github.com/mendersoftware/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 {
187✔
68
        database := db.client.Database(mstore.DbFromContext(ctx, DatabaseName))
187✔
69
        collReleases := database.Collection(CollectionReleases)
187✔
70

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

118
func (db *DataStoreMongo) ListReleaseTags(ctx context.Context) (model.Tags, error) {
11✔
119
        l := log.FromContext(ctx)
11✔
120
        tagKeys, err := db.client.
11✔
121
                Database(mstore.DbFromContext(ctx, DatabaseName)).
11✔
122
                Collection(CollectionReleases).
11✔
123
                Distinct(ctx, StorageKeyReleaseTags, bson.D{})
11✔
124
        if err != nil {
12✔
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))
10✔
129
        for _, elem := range tagKeys {
123✔
130
                if key, ok := elem.(string); ok {
224✔
131
                        ret = append(ret, model.Tag(key))
111✔
132
                } else {
113✔
133
                        l.Warnf("unexpected data type (%T) received from distinct call: "+
2✔
134
                                "ignoring result", elem)
2✔
135
                }
2✔
136
        }
137

138
        return ret, err
10✔
139
}
140

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

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

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

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

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

6✔
197
        err := release.Validate()
6✔
198
        if err != nil {
7✔
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(
5✔
206
                ctx,
5✔
207
                bson.D{
5✔
208
                        {
5✔
209
                                Key: StorageKeyReleaseName, Value: releaseName,
5✔
210
                        },
5✔
211
                },
5✔
212
                bson.D{
5✔
213
                        {
5✔
214
                                Key: mongoOpSet,
5✔
215
                                Value: bson.D{
5✔
216
                                        {
5✔
217
                                                Key: StorageKeyReleaseNotes, Value: release.Notes,
5✔
218
                                        },
5✔
219
                                },
5✔
220
                        },
5✔
221
                },
5✔
222
        )
5✔
223
        if err != nil {
5✔
224
                return errors.WithMessage(err, "mongo: failed to update release")
×
225
        } else if res.MatchedCount <= 0 {
5✔
226
                return store.ErrNotFound
×
227
        }
×
228
        return nil
5✔
229
}
230

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

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

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

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

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

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