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

mendersoftware / deployments / 1280684078

06 May 2024 08:13PM UTC coverage: 79.689% (+0.08%) from 79.606%
1280684078

Pull #1018

gitlab-ci

tranchitella
feat: return 409 on conflicts where creating a deployment with the same parameters as an already existing and active deployment

Changelog: none
Ticket: MEN-6622

Signed-off-by: Fabio Tranchitella <fabio.tranchitella@northern.tech>
Pull Request #1018: feat: prevent the creation of deployments if there is already an active deployment with the same constructor parameters

61 of 66 new or added lines in 7 files covered. (92.42%)

12 existing lines in 2 files now uncovered.

8102 of 10167 relevant lines covered (79.69%)

34.63 hits per line

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

89.71
/store/mongo/migration_1_2_15.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 mongo
16

17
import (
18
        "context"
19
        "fmt"
20
        "time"
21

22
        "github.com/mendersoftware/go-lib-micro/mongo/migrate"
23
        "github.com/pkg/errors"
24
        "go.mongodb.org/mongo-driver/bson"
25
        "go.mongodb.org/mongo-driver/mongo"
26
        mopts "go.mongodb.org/mongo-driver/mongo/options"
27

28
        "github.com/mendersoftware/deployments/model"
29
)
30

31
type migration_1_2_15 struct {
32
        client *mongo.Client
33
        db     string
34
}
35

36
func (m *migration_1_2_15) Up(from migrate.Version) error {
24✔
37
        err := m.createCollectionReleases()
24✔
38
        if err == nil {
48✔
39
                err = m.indexReleaseTags()
24✔
40
        }
24✔
41
        if err == nil {
47✔
42
                err = m.indexReleaseUpdateType()
23✔
43
        }
23✔
44
        if err == nil {
47✔
45
                err = m.indexUpdateTypes()
23✔
46
        }
23✔
47
        if err == nil {
47✔
48
                err = m.indexReleaseArtifactsCount()
23✔
49
        }
23✔
50
        return err
24✔
51
}
52

53
func (m *migration_1_2_15) createCollectionReleases() error {
24✔
54
        ctx := context.Background()
24✔
55
        c := m.client.Database(m.db).Collection(CollectionImages)
24✔
56
        cr := m.client.Database(m.db).Collection(CollectionReleases)
24✔
57

24✔
58
        cursor, err := c.Find(ctx, bson.M{})
24✔
59
        if err != nil {
24✔
60
                return err
×
61
        }
×
62
        defer cursor.Close(ctx)
24✔
63
        for cursor.Next(ctx) {
27✔
64
                var a model.Image
3✔
65
                err = cursor.Decode(&a)
3✔
66
                if err != nil {
3✔
67
                        break
×
68
                }
69

70
                opt := &mopts.UpdateOptions{}
3✔
71
                upsert := true
3✔
72
                opt.Upsert = &upsert
3✔
73
                update := bson.M{
3✔
74
                        "$set": bson.M{
3✔
75
                                StorageKeyReleaseName:     a.ArtifactMeta.Name,
3✔
76
                                StorageKeyReleaseModified: time.Now(),
3✔
77
                        },
3✔
78
                        "$push": bson.M{StorageKeyReleaseArtifacts: a},
3✔
79
                }
3✔
80

3✔
81
                res, err := cr.UpdateOne(
3✔
82
                        ctx,
3✔
83
                        bson.M{
3✔
84
                                "$and": []bson.M{
3✔
85
                                        {
3✔
86
                                                StorageKeyReleaseName: a.ArtifactMeta.Name,
3✔
87
                                        },
3✔
88
                                        {
3✔
89
                                                StorageKeyReleaseArtifactsId: bson.M{
3✔
90
                                                        "$ne": a.Id,
3✔
91
                                                },
3✔
92
                                        },
3✔
93
                                }},
3✔
94
                        update,
3✔
95
                        opt,
3✔
96
                )
3✔
97
                if err != nil {
3✔
98
                        if mongo.IsDuplicateKeyError(err) {
×
99
                                continue
×
100
                        }
101
                        return err
×
102
                }
103

104
                if res.ModifiedCount != 1 && res.UpsertedCount != 1 {
3✔
105
                        return errors.New(fmt.Sprintf("failed to update release %s", a.ArtifactMeta.Name))
×
106
                }
×
107
        }
108
        if err = cursor.Err(); err != nil {
24✔
109
                return errors.WithMessage(err, "failed to decode artifact")
×
110
        }
×
111
        return nil
24✔
112
}
113

114
func (m *migration_1_2_15) indexReleaseArtifactsCount() error {
23✔
115
        ctx := context.Background()
23✔
116
        idxReleases := m.client.
23✔
117
                Database(m.db).
23✔
118
                Collection(CollectionReleases).
23✔
119
                Indexes()
23✔
120

23✔
121
        _, err := idxReleases.CreateOne(ctx, mongo.IndexModel{
23✔
122
                Keys: bson.D{
23✔
123
                        {
23✔
124
                                Key:   StorageKeyReleaseArtifactsCount,
23✔
125
                                Value: 1,
23✔
126
                        },
23✔
127
                },
23✔
128
                Options: mopts.Index().SetName(IndexNameReleaseArtifactsCount),
23✔
129
        })
23✔
130
        if err != nil {
23✔
131
                return fmt.Errorf("mongo(1.2.15): failed to create index: %w", err)
×
132
        }
×
133

134
        collectionReleases := m.client.
23✔
135
                Database(m.db).
23✔
136
                Collection(CollectionReleases)
23✔
137
        _, err = collectionReleases.UpdateMany(
23✔
138
                ctx,
23✔
139
                bson.M{},
23✔
140
                []bson.M{
23✔
141
                        {
23✔
142
                                "$set": bson.M{
23✔
143
                                        "artifacts_count": bson.M{
23✔
144
                                                "$size": "$artifacts",
23✔
145
                                        },
23✔
146
                                },
23✔
147
                        },
23✔
148
                },
23✔
149
        )
23✔
150
        if err != nil {
23✔
151
                return fmt.Errorf("mongo(1.2.15): failed to update adrtifact counts: %w", err)
×
152
        }
×
153

154
        return nil
23✔
155
}
156

157
func (m *migration_1_2_15) indexReleaseTags() error {
24✔
158
        ctx := context.Background()
24✔
159
        idxReleases := m.client.
24✔
160
                Database(m.db).
24✔
161
                Collection(CollectionReleases).
24✔
162
                Indexes()
24✔
163

24✔
164
        _, err := idxReleases.CreateOne(ctx, mongo.IndexModel{
24✔
165
                Keys: bson.D{{
24✔
166
                        Key:   StorageKeyReleaseTags,
24✔
167
                        Value: 1,
24✔
168
                }, {
24✔
169
                        // Sort by modified date by default when querying by tags
24✔
170
                        Key:   StorageKeyReleaseModified,
24✔
171
                        Value: -1,
24✔
172
                }},
24✔
173
                Options: mopts.Index().
24✔
174
                        SetName(IndexNameReleaseTags),
24✔
175
        })
24✔
176
        if err != nil {
25✔
177
                return fmt.Errorf("mongo(1.2.15): failed to create index: %w", err)
1✔
178
        }
1✔
179
        return nil
23✔
180
}
181

182
func (m *migration_1_2_15) indexReleaseUpdateType() error {
23✔
183
        ctx := context.Background()
23✔
184
        idxReleases := m.client.
23✔
185
                Database(m.db).
23✔
186
                Collection(CollectionReleases).
23✔
187
                Indexes()
23✔
188

23✔
189
        _, err := idxReleases.CreateOne(ctx, mongo.IndexModel{
23✔
190
                Keys: bson.D{
23✔
191
                        {
23✔
192
                                Key:   StorageKeyReleaseArtifactsUpdateTypes,
23✔
193
                                Value: 1,
23✔
194
                        },
23✔
195
                },
23✔
196
                Options: mopts.Index().
23✔
197
                        SetName(IndexNameReleaseUpdateTypes).
23✔
198
                        SetSparse(true),
23✔
199
        })
23✔
200
        if err != nil {
23✔
NEW
201
                return fmt.Errorf("mongo(1.2.15): failed to create index: %w", err)
×
202
        }
×
203
        return nil
23✔
204
}
205

206
func (m *migration_1_2_15) indexUpdateTypes() error {
23✔
207
        ctx := context.Background()
23✔
208
        idxReleases := m.client.
23✔
209
                Database(m.db).
23✔
210
                Collection(CollectionUpdateTypes).
23✔
211
                Indexes()
23✔
212

23✔
213
        _, err := idxReleases.CreateOne(ctx, mongo.IndexModel{
23✔
214
                Keys: bson.D{
23✔
215
                        {
23✔
216
                                Key:   StorageKeyTenantId,
23✔
217
                                Value: 1,
23✔
218
                        },
23✔
219
                },
23✔
220
                Options: mopts.Index().SetName(IndexNameAggregatedUpdateTypes).SetUnique(true),
23✔
221
        })
23✔
222
        if err != nil {
23✔
NEW
223
                return fmt.Errorf("mongo(1.2.15): failed to create index: %w", err)
×
224
        }
×
225
        return nil
23✔
226
}
227

228
func (m *migration_1_2_15) Version() migrate.Version {
83✔
229
        return migrate.MakeVersion(1, 2, 15)
83✔
230
}
83✔
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