1
// Copyright 2015 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
9
"github.com/juju/utils/set"
10
gc "gopkg.in/check.v1"
11
"gopkg.in/juju/charm.v6-unstable"
14
type MigrationSuite struct{}
16
var _ = gc.Suite(&MigrationSuite{})
18
func (s *MigrationSuite) TestKnownCollections(c *gc.C) {
19
completedCollections := set.NewStrings(
25
modelUserLastConnectionC,
40
meterStatusC, // red / green status for metrics of units
42
// settings reference counts are only used for services
50
ignoredCollections := set.NewStrings(
51
// Precheck ensures that there are no cleanup docs.
53
// We don't export the controller model at this stage.
55
// This is controller global, and related to the system state of the
58
// Users aren't migrated.
61
// userenvnameC is just to provide a unique key constraint.
63
// Metrics aren't migrated.
65
// leaseC is deprecated in favour of leasesC.
67
// Backup and restore information is not migrated.
69
// upgradeInfoC is used to coordinate upgrades and schema migrations,
70
// and aren't needed for model migrations.
72
// Not exported, but the tools will possibly need to be either bundled
73
// with the representation or sent separately.
79
// We don't import any of the migration collections.
81
modelMigrationStatusC,
82
modelMigrationsActiveC,
84
// The container ref document is primarily there to keep track
85
// of a particular machine's containers. The migration format
86
// uses object containment for this purpose.
88
// The min units collection is only used to trigger a watcher
89
// in order to have the service add or remove units if the minimum
90
// number of units is changed. The Service doc has all we need
93
// This is a transitory collection of units that need to be assigned
97
// This has been deprecated in 2.0, and should not contain any data
98
// we actually care about migrating.
102
// THIS SET WILL BE REMOVED WHEN MIGRATIONS ARE COMPLETE
103
todoCollections := set.NewStrings(
119
filesystemAttachmentsC,
129
linkLayerDevicesRefsC,
138
actionNotificationsC,
142
metricsManagerC, // should really be copied across
145
envCollections := set.NewStrings()
146
for name := range allCollections() {
147
envCollections.Add(name)
150
known := completedCollections.Union(ignoredCollections)
152
remainder := envCollections.Difference(known)
153
remainder = remainder.Difference(todoCollections)
155
// If this test fails, it means that a new collection has been added
156
// but migrations for it has not been done. This is a Bad Thing™.
157
c.Assert(remainder, gc.HasLen, 0)
160
func (s *MigrationSuite) TestModelDocFields(c *gc.C) {
161
fields := set.NewStrings(
162
// UUID and Mame are constructed from the model config.
165
// Life will always be alive, or we won't be migrating.
168
"LatestAvailableTools",
169
// ServerUUID is recreated when the new model is created in the
170
// new controller (yay name changes).
172
// Both of the times for dying and death are empty as the model
177
s.AssertExportedFields(c, modelDoc{}, fields)
180
func (s *MigrationSuite) TestEnvUserDocFields(c *gc.C) {
181
fields := set.NewStrings(
182
// ID is the same as UserName (but lowercased)
184
// ModelUUID shouldn't be exported, and is inherited
185
// from the model definition.
194
s.AssertExportedFields(c, modelUserDoc{}, fields)
197
func (s *MigrationSuite) TestEnvUserLastConnectionDocFields(c *gc.C) {
198
fields := set.NewStrings(
199
// ID is the same as UserName (but lowercased)
201
// ModelUUID shouldn't be exported, and is inherited
202
// from the model definition.
204
// UserName is captured in the migration.User.
208
s.AssertExportedFields(c, modelUserLastConnectionDoc{}, fields)
211
func (s *MigrationSuite) TestMachineDocFields(c *gc.C) {
212
fields := set.NewStrings(
213
// DocID is the env + machine id
215
// ID is the machine id
217
// ModelUUID shouldn't be exported, and is inherited
218
// from the model definition.
220
// Life is always alive, confirmed by export precheck.
230
"PreferredPrivateAddress",
231
"PreferredPublicAddress",
233
"SupportedContainers",
234
"SupportedContainersKnown",
237
// Ignored at this stage, could be an issue if mongo 3.0 isn't
239
"StopMongoUntilVersion",
241
todo := set.NewStrings(
249
s.AssertExportedFields(c, machineDoc{}, fields.Union(todo))
252
func (s *MigrationSuite) TestInstanceDataFields(c *gc.C) {
253
fields := set.NewStrings(
254
// DocID is the env + machine id
257
// ModelUUID shouldn't be exported, and is inherited
258
// from the model definition.
271
s.AssertExportedFields(c, instanceData{}, fields)
274
func (s *MigrationSuite) TestServiceDocFields(c *gc.C) {
275
ignored := set.NewStrings(
276
// DocID is the env + name
278
// ModelUUID shouldn't be exported, and is inherited
279
// from the model definition.
281
// Always alive, not explicitly exported.
283
// OwnerTag is deprecated and should be deleted.
285
// TxnRevno is mgo internals and should not be migrated.
287
// UnitCount is handled by the number of units for the exported service.
289
// RelationCount is handled by the number of times the service name
290
// appears in relation endpoints.
293
migrated := set.NewStrings(
298
"CharmModifiedVersion",
304
s.AssertExportedFields(c, serviceDoc{}, migrated.Union(ignored))
307
func (s *MigrationSuite) TestSettingsRefsDocFields(c *gc.C) {
308
fields := set.NewStrings(
309
// ModelUUID shouldn't be exported, and is inherited
310
// from the model definition.
315
s.AssertExportedFields(c, settingsRefsDoc{}, fields)
318
func (s *MigrationSuite) TestUnitDocFields(c *gc.C) {
319
fields := set.NewStrings(
320
// DocID itself isn't migrated
323
// ModelUUID shouldn't be exported, and is inherited
324
// from the model definition.
326
// Service is implicit in the migration structure through containment.
328
// Series and CharmURL also come from the service.
334
// Resolved is not migrated as we check that all is good before we start.
337
// Life isn't migrated as we only migrate live things.
339
// TxnRevno isn't migrated.
342
// Obsolete and not migrated.
347
todo := set.NewStrings(
348
"StorageAttachmentCount",
351
s.AssertExportedFields(c, unitDoc{}, fields.Union(todo))
354
func (s *MigrationSuite) TestPortsDocFields(c *gc.C) {
355
fields := set.NewStrings(
356
// DocID itself isn't migrated
358
// ModelUUID shouldn't be exported, and is inherited
359
// from the model definition.
361
// MachineId is implicit in the migration structure through containment.
365
// TxnRevno isn't migrated.
368
s.AssertExportedFields(c, portsDoc{}, fields)
371
func (s *MigrationSuite) TestMeterStatusDocFields(c *gc.C) {
372
fields := set.NewStrings(
373
// DocID itself isn't migrated
375
// ModelUUID shouldn't be exported, and is inherited
376
// from the model definition.
381
s.AssertExportedFields(c, meterStatusDoc{}, fields)
384
func (s *MigrationSuite) TestRelationDocFields(c *gc.C) {
385
fields := set.NewStrings(
386
// DocID itself isn't migrated
388
// ModelUUID shouldn't be exported, and is inherited
389
// from the model definition.
394
// Life isn't exported, only alive.
396
// UnitCount isn't explicitly exported, but defined by the stored
397
// unit settings data for the relation endpoint.
400
s.AssertExportedFields(c, relationDoc{}, fields)
401
// We also need to check the Endpoint and nested charm.Relation field.
402
endpointFields := set.NewStrings("ServiceName", "Relation")
403
s.AssertExportedFields(c, Endpoint{}, endpointFields)
404
charmRelationFields := set.NewStrings(
412
s.AssertExportedFields(c, charm.Relation{}, charmRelationFields)
415
func (s *MigrationSuite) TestRelationScopeDocFields(c *gc.C) {
416
fields := set.NewStrings(
417
// DocID itself isn't migrated
419
// ModelUUID shouldn't be exported, and is inherited
420
// from the model definition.
423
// Departing isn't exported as we only deal with live, stable systems.
426
s.AssertExportedFields(c, relationScopeDoc{}, fields)
429
func (s *MigrationSuite) TestAnnatatorDocFields(c *gc.C) {
430
fields := set.NewStrings(
431
// ModelUUID shouldn't be exported, and is inherited
432
// from the model definition.
438
s.AssertExportedFields(c, annotatorDoc{}, fields)
441
func (s *MigrationSuite) TestBlockDocFields(c *gc.C) {
442
ignored := set.NewStrings(
443
// The doc id is a sequence value that has no meaning.
444
// It really doesn't need to be a sequence.
446
// ModelUUID shouldn't be exported, and is inherited
447
// from the model definition.
449
// Tag is just string representation of the model tag,
450
// which also contains the model-uuid.
453
migrated := set.NewStrings(
457
fields := migrated.Union(ignored)
458
s.AssertExportedFields(c, blockDoc{}, fields)
461
func (s *MigrationSuite) TestSequenceDocFields(c *gc.C) {
462
fields := set.NewStrings(
463
// ModelUUID shouldn't be exported, and is inherited
464
// from the model definition.
470
s.AssertExportedFields(c, sequenceDoc{}, fields)
473
func (s *MigrationSuite) TestConstraintsDocFields(c *gc.C) {
474
fields := set.NewStrings(
475
// ModelUUID shouldn't be exported, and is inherited
476
// from the model definition.
487
// Networks is a deprecated constraint and not exported.
490
s.AssertExportedFields(c, constraintsDoc{}, fields)
493
func (s *MigrationSuite) TestHistoricalStatusDocFields(c *gc.C) {
494
fields := set.NewStrings(
495
// ModelUUID shouldn't be exported, and is inherited
496
// from the model definition.
504
s.AssertExportedFields(c, historicalStatusDoc{}, fields)
507
func (s *MigrationSuite) AssertExportedFields(c *gc.C, doc interface{}, fields set.Strings) {
508
expected := getExportedFields(doc)
509
unknown := expected.Difference(fields)
510
removed := fields.Difference(expected)
511
// If this test fails, it means that extra fields have been added to the
512
// doc without thinking about the migration implications.
513
c.Check(unknown, gc.HasLen, 0)
514
c.Assert(removed, gc.HasLen, 0)
517
func getExportedFields(arg interface{}) set.Strings {
518
t := reflect.TypeOf(arg)
519
result := set.NewStrings()
521
count := t.NumField()
522
for i := 0; i < count; i++ {
524
// empty PkgPath means exported field.
525
// see https://golang.org/pkg/reflect/#StructField