115
132
return executed, nil
118
// addSupportedSeries adds the supported-series field
119
// to entities that don't have it. Note that it does not
120
// need to work for multi-series charms because support
121
// for those has not been implemented before this migration.
122
func addSupportedSeries(db StoreDatabase) error {
135
func addPreV5CompatBlob(db StoreDatabase) error {
136
blobStore := blobstore.New(db.Database, "entitystore")
123
137
entities := db.Entities()
138
iter := entities.Find(nil).Select(map[string]int{
143
"charmmeta.series": 1,
124
145
var entity mongodoc.Entity
146
for iter.Next(&entity) {
147
var info *preV5CompatibilityHackBlobInfo
149
if entity.CharmMeta == nil || len(entity.CharmMeta.Series) == 0 {
150
info = &preV5CompatibilityHackBlobInfo{
151
hash: entity.BlobHash,
152
hash256: entity.BlobHash256,
156
r, _, err := blobStore.Open(entity.BlobName)
158
return errgo.Notef(err, "cannot open original blob")
160
info, err = addPreV5CompatibilityHackBlob(blobStore, r, entity.BlobName, entity.Size)
163
return errgo.Mask(err)
166
err := entities.UpdateId(entity.URL, bson.D{{
168
"prev5blobhash", info.hash,
170
"prev5blobhash256", info.hash256,
172
"prev5blobsize", info.size,
176
return errgo.Notef(err, "cannot update pre-v5 info")
179
if err := iter.Err(); err != nil {
180
return errgo.Notef(err, "cannot iterate through entities")
185
func migrateToNewChannelsModel(db StoreDatabase) error {
186
if err := ncmUpdateDevelopmentAndStable(db); err != nil {
187
return errgo.Mask(err)
189
if err := ncmUpdateBaseEntities(db); err != nil {
190
return errgo.Mask(err)
195
// ncmUpdateDevelopmentAndStable updates the Development and Stable
196
// entity fields to conform to the new channels model.
197
// All entities are treated as if they're in development; entities
198
// without the development field set are treated as stable.
199
func ncmUpdateDevelopmentAndStable(db StoreDatabase) error {
200
entities := db.Entities()
125
201
iter := entities.Find(bson.D{{
126
// Use the supportedseries field to collect not migrated entities.
127
"supportedseries", bson.D{{"$exists", false}},
129
"series", bson.D{{"$ne", "bundle"}},
130
}}).Select(bson.D{{"_id", 1}}).Iter()
202
"stable", bson.D{{"$exists", false}},
203
}}).Select(map[string]int{
208
// For every entity without a stable field, update
209
// its development and stable fields appropriately.
210
var entity mongodoc.Entity
133
211
for iter.Next(&entity) {
134
logger.Infof("updating %s", entity.URL)
135
if err := entities.UpdateId(entity.URL, bson.D{{
212
err := entities.UpdateId(entity.URL, bson.D{{
137
{"supportedseries", []string{entity.URL.Series}},
214
{"development", true},
215
{"stable", !entity.Development},
140
return errgo.Notef(err, "cannot denormalize entity id %s", entity.URL)
219
return errgo.Notef(err, "cannot update entity")
143
if err := iter.Close(); err != nil {
144
return errgo.Notef(err, "cannot iterate entities")
149
// addDevelopment adds the Development field to all entities on which that
150
// field is not present.
151
func addDevelopment(db StoreDatabase) error {
152
logger.Infof("adding development field to all entities")
153
if _, err := db.Entities().UpdateAll(bson.D{{
154
"development", bson.D{{"$exists", false}},
156
"$set", bson.D{{"development", false}},
158
return errgo.Notef(err, "cannot add development field to all entities")
163
// addDevelopmentACLs sets up ACLs on base entities for development revisions.
164
func addDevelopmentACLs(db StoreDatabase) error {
165
logger.Infof("adding development ACLs to all base entities")
222
if err := iter.Err(); err != nil {
223
return errgo.Notef(err, "cannot iterate through entities")
228
// preNCMBaseEntity holds the type of a base entity just before
229
// the new channels model migration.
230
type preNCMBaseEntity struct {
231
// URL holds the reference URL of of charm on bundle
232
// regardless of its revision, series or promulgation status
233
// (this omits the revision and series from URL).
234
// e.g., cs:~user/collection/foo
235
URL *charm.URL `bson:"_id"`
237
// User holds the user part of the entity URL (for instance, "joe").
240
// Name holds the name of the entity (for instance "wordpress").
243
// Public specifies whether the charm or bundle
244
// is available to all users. If this is true, the ACLs will
245
// be ignored when reading a charm.
248
// ACLs holds permission information relevant to the base entity.
249
// The permissions apply to all revisions.
252
// DevelopmentACLs is similar to ACLs but applies to all development
254
DevelopmentACLs mongodoc.ACL
256
// Promulgated specifies whether the charm or bundle should be
258
Promulgated mongodoc.IntBool
260
// CommonInfo holds arbitrary common extra metadata associated with
261
// the base entity. Thhose data apply to all revisions.
262
// The byte slices hold JSON-encoded data.
263
CommonInfo map[string][]byte `bson:",omitempty" json:",omitempty"`
266
// ncmUpdateBaseEntities updates all the base entities to conform to
267
// the new channels model. It assumes that ncmUpdateDevelopmentAndStable
268
// has been run already.
269
func ncmUpdateBaseEntities(db StoreDatabase) error {
166
270
baseEntities := db.BaseEntities()
167
var baseEntity mongodoc.BaseEntity
168
271
iter := baseEntities.Find(bson.D{{
169
"developmentacls", bson.D{{"$exists", false}},
170
}}).Select(bson.D{{"_id", 1}, {"acls", 1}}).Iter()
272
"channelentities", bson.D{{"$exists", false}},
274
// For every base entity without a ChannelEntities field, update
275
// its ChannelEntities and and ChannelACLs field appropriately.
276
var baseEntity preNCMBaseEntity
172
277
for iter.Next(&baseEntity) {
173
if err := baseEntities.UpdateId(baseEntity.URL, bson.D{{
174
"$set", bson.D{{"developmentacls", baseEntity.ACLs}},
176
return errgo.Notef(err, "cannot add development ACLs to base entity id %s", baseEntity.URL)
179
if err := iter.Close(); err != nil {
180
return errgo.Notef(err, "cannot iterate base entities")
278
if err := ncmUpdateBaseEntity(db, &baseEntity); err != nil {
279
return errgo.Mask(err)
282
if err := iter.Err(); err != nil {
283
return errgo.Notef(err, "cannot iterate through base entities")
288
// ncmUpdateBaseEntity updates a single base entity to conform to
289
// the new channels model.
290
func ncmUpdateBaseEntity(db StoreDatabase, baseEntity *preNCMBaseEntity) error {
291
channelEntities := make(map[params.Channel]map[string]*charm.URL)
293
updateChannelURL := func(url *charm.URL, ch params.Channel, series string) {
294
if channelEntities[ch] == nil {
295
channelEntities[ch] = make(map[string]*charm.URL)
297
if oldURL := channelEntities[ch][series]; oldURL == nil || oldURL.Revision < url.Revision {
298
channelEntities[ch][series] = url
301
// updateChannelEntity updates the series entries in channelEntities
302
// for the given entity, setting the entity URL entry if the revision
303
// is greater than any already found.
304
updateChannelEntity := func(entity *mongodoc.Entity, ch params.Channel) {
305
if entity.URL.Series == "" {
306
for _, series := range entity.SupportedSeries {
307
updateChannelURL(entity.URL, ch, series)
310
updateChannelURL(entity.URL, ch, entity.URL.Series)
314
// Iterate through all the entities associated with the base entity
315
// to find the most recent "published" entities so that we can
316
// populate the ChannelEntities field.
317
var entity mongodoc.Entity
318
iter := db.Entities().Find(bson.D{{"baseurl", baseEntity.URL}}).Iter()
319
for iter.Next(&entity) {
320
if entity.Development {
321
updateChannelEntity(&entity, params.DevelopmentChannel)
324
updateChannelEntity(&entity, params.StableChannel)
327
if err := iter.Err(); err != nil {
328
return errgo.Notef(err, "cannot iterate through entities")
330
err := db.BaseEntities().UpdateId(baseEntity.URL, bson.D{{
332
"channelentities", channelEntities,
334
"channelacls", map[params.Channel]mongodoc.ACL{
335
params.UnpublishedChannel: baseEntity.DevelopmentACLs,
336
params.DevelopmentChannel: baseEntity.DevelopmentACLs,
337
params.StableChannel: baseEntity.ACLs,
342
"developmentacls", nil,
348
return errgo.Notef(err, "cannot update base entity")