github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/migration_import_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "fmt" 8 "time" // only uses time.Time values 9 10 "github.com/juju/errors" 11 jc "github.com/juju/testing/checkers" 12 "github.com/juju/utils" 13 "github.com/juju/version" 14 gc "gopkg.in/check.v1" 15 "gopkg.in/juju/charm.v6-unstable" 16 "gopkg.in/juju/names.v2" 17 18 "github.com/juju/juju/constraints" 19 "github.com/juju/juju/core/description" 20 "github.com/juju/juju/network" 21 "github.com/juju/juju/payload" 22 "github.com/juju/juju/permission" 23 "github.com/juju/juju/state" 24 "github.com/juju/juju/state/cloudimagemetadata" 25 "github.com/juju/juju/status" 26 "github.com/juju/juju/storage/poolmanager" 27 "github.com/juju/juju/storage/provider" 28 coretesting "github.com/juju/juju/testing" 29 "github.com/juju/juju/testing/factory" 30 ) 31 32 type MigrationImportSuite struct { 33 MigrationBaseSuite 34 } 35 36 var _ = gc.Suite(&MigrationImportSuite{}) 37 38 func (s *MigrationImportSuite) checkStatusHistory(c *gc.C, exported, imported status.StatusHistoryGetter, size int) { 39 exportedHistory, err := exported.StatusHistory(status.StatusHistoryFilter{Size: size}) 40 c.Assert(err, jc.ErrorIsNil) 41 importedHistory, err := imported.StatusHistory(status.StatusHistoryFilter{Size: size}) 42 c.Assert(err, jc.ErrorIsNil) 43 for i := 0; i < size; i++ { 44 c.Check(importedHistory[i].Status, gc.Equals, exportedHistory[i].Status) 45 c.Check(importedHistory[i].Message, gc.Equals, exportedHistory[i].Message) 46 c.Check(importedHistory[i].Data, jc.DeepEquals, exportedHistory[i].Data) 47 c.Check(importedHistory[i].Since, jc.DeepEquals, exportedHistory[i].Since) 48 } 49 } 50 51 func (s *MigrationImportSuite) TestExisting(c *gc.C) { 52 out, err := s.State.Export() 53 c.Assert(err, jc.ErrorIsNil) 54 55 _, _, err = s.State.Import(out) 56 c.Assert(err, jc.Satisfies, errors.IsAlreadyExists) 57 } 58 59 func (s *MigrationImportSuite) importModel(c *gc.C) (*state.Model, *state.State) { 60 out, err := s.State.Export() 61 c.Assert(err, jc.ErrorIsNil) 62 63 uuid := utils.MustNewUUID().String() 64 in := newModel(out, uuid, "new") 65 66 newModel, newSt, err := s.State.Import(in) 67 c.Assert(err, jc.ErrorIsNil) 68 // add the cleanup here to close the model. 69 s.AddCleanup(func(c *gc.C) { 70 c.Check(newSt.Close(), jc.ErrorIsNil) 71 }) 72 return newModel, newSt 73 } 74 75 func (s *MigrationImportSuite) assertAnnotations(c *gc.C, newSt *state.State, entity state.GlobalEntity) { 76 annotations, err := newSt.Annotations(entity) 77 c.Assert(err, jc.ErrorIsNil) 78 c.Assert(annotations, jc.DeepEquals, testAnnotations) 79 } 80 81 func (s *MigrationImportSuite) TestNewModel(c *gc.C) { 82 cons := constraints.MustParse("arch=amd64 mem=8G") 83 latestTools := version.MustParse("2.0.1") 84 s.setLatestTools(c, latestTools) 85 c.Assert(s.State.SetModelConstraints(cons), jc.ErrorIsNil) 86 machineSeq := s.setRandSequenceValue(c, "machine") 87 fooSeq := s.setRandSequenceValue(c, "application-foo") 88 s.State.SwitchBlockOn(state.ChangeBlock, "locked down") 89 90 original, err := s.State.Model() 91 c.Assert(err, jc.ErrorIsNil) 92 93 err = s.State.SetAnnotations(original, testAnnotations) 94 c.Assert(err, jc.ErrorIsNil) 95 96 out, err := s.State.Export() 97 c.Assert(err, jc.ErrorIsNil) 98 99 uuid := utils.MustNewUUID().String() 100 in := newModel(out, uuid, "new") 101 102 newModel, newSt, err := s.State.Import(in) 103 c.Assert(err, jc.ErrorIsNil) 104 defer newSt.Close() 105 106 c.Assert(newModel.Owner(), gc.Equals, original.Owner()) 107 c.Assert(newModel.LatestToolsVersion(), gc.Equals, latestTools) 108 c.Assert(newModel.MigrationMode(), gc.Equals, state.MigrationModeImporting) 109 s.assertAnnotations(c, newSt, newModel) 110 111 originalConfig, err := original.Config() 112 c.Assert(err, jc.ErrorIsNil) 113 originalAttrs := originalConfig.AllAttrs() 114 115 newConfig, err := newModel.Config() 116 c.Assert(err, jc.ErrorIsNil) 117 newAttrs := newConfig.AllAttrs() 118 119 c.Assert(newAttrs["uuid"], gc.Equals, uuid) 120 c.Assert(newAttrs["name"], gc.Equals, "new") 121 122 // Now drop the uuid and name and the rest of the attributes should match. 123 delete(newAttrs, "uuid") 124 delete(newAttrs, "name") 125 delete(originalAttrs, "uuid") 126 delete(originalAttrs, "name") 127 c.Assert(newAttrs, jc.DeepEquals, originalAttrs) 128 129 newCons, err := newSt.ModelConstraints() 130 c.Assert(err, jc.ErrorIsNil) 131 // Can't test the constraints directly, so go through the string repr. 132 c.Assert(newCons.String(), gc.Equals, cons.String()) 133 134 seq, err := state.Sequence(newSt, "machine") 135 c.Assert(err, jc.ErrorIsNil) 136 c.Assert(seq, gc.Equals, machineSeq) 137 seq, err = state.Sequence(newSt, "application-foo") 138 c.Assert(err, jc.ErrorIsNil) 139 c.Assert(seq, gc.Equals, fooSeq) 140 141 blocks, err := newSt.AllBlocks() 142 c.Assert(err, jc.ErrorIsNil) 143 c.Assert(blocks, gc.HasLen, 1) 144 c.Assert(blocks[0].Type(), gc.Equals, state.ChangeBlock) 145 c.Assert(blocks[0].Message(), gc.Equals, "locked down") 146 } 147 148 func (s *MigrationImportSuite) newModelUser(c *gc.C, name string, readOnly bool, lastConnection time.Time) permission.UserAccess { 149 access := permission.AdminAccess 150 if readOnly { 151 access = permission.ReadAccess 152 } 153 user, err := s.State.AddModelUser(s.State.ModelUUID(), state.UserAccessSpec{ 154 User: names.NewUserTag(name), 155 CreatedBy: s.Owner, 156 Access: access, 157 }) 158 c.Assert(err, jc.ErrorIsNil) 159 if !lastConnection.IsZero() { 160 err = state.UpdateModelUserLastConnection(s.State, user, lastConnection) 161 c.Assert(err, jc.ErrorIsNil) 162 } 163 return user 164 } 165 166 func (s *MigrationImportSuite) AssertUserEqual(c *gc.C, newUser, oldUser permission.UserAccess) { 167 c.Assert(newUser.UserName, gc.Equals, oldUser.UserName) 168 c.Assert(newUser.DisplayName, gc.Equals, oldUser.DisplayName) 169 c.Assert(newUser.CreatedBy, gc.Equals, oldUser.CreatedBy) 170 c.Assert(newUser.DateCreated, gc.Equals, oldUser.DateCreated) 171 c.Assert(newUser.Access, gc.Equals, newUser.Access) 172 173 connTime, err := s.State.LastModelConnection(oldUser.UserTag) 174 if state.IsNeverConnectedError(err) { 175 _, err := s.State.LastModelConnection(newUser.UserTag) 176 // The new user should also return an error for last connection. 177 c.Assert(err, jc.Satisfies, state.IsNeverConnectedError) 178 } else { 179 c.Assert(err, jc.ErrorIsNil) 180 newTime, err := s.State.LastModelConnection(newUser.UserTag) 181 c.Assert(err, jc.ErrorIsNil) 182 c.Assert(newTime, gc.Equals, connTime) 183 } 184 } 185 186 func (s *MigrationImportSuite) TestModelUsers(c *gc.C) { 187 // To be sure with this test, we create three env users, and remove 188 // the owner. 189 err := s.State.RemoveUserAccess(s.Owner, s.modelTag) 190 c.Assert(err, jc.ErrorIsNil) 191 192 lastConnection := s.State.NowToTheSecond() 193 194 bravo := s.newModelUser(c, "bravo@external", false, lastConnection) 195 charlie := s.newModelUser(c, "charlie@external", true, lastConnection) 196 delta := s.newModelUser(c, "delta@external", true, coretesting.ZeroTime()) 197 198 newModel, newSt := s.importModel(c) 199 200 // Check the import values of the users. 201 for _, user := range []permission.UserAccess{bravo, charlie, delta} { 202 newUser, err := newSt.UserAccess(user.UserTag, newModel.Tag()) 203 c.Assert(err, jc.ErrorIsNil) 204 s.AssertUserEqual(c, newUser, user) 205 } 206 207 // Also make sure that there aren't any more. 208 allUsers, err := newModel.Users() 209 c.Assert(err, jc.ErrorIsNil) 210 c.Assert(allUsers, gc.HasLen, 3) 211 } 212 213 func (s *MigrationImportSuite) AssertMachineEqual(c *gc.C, newMachine, oldMachine *state.Machine) { 214 c.Assert(newMachine.Id(), gc.Equals, oldMachine.Id()) 215 c.Assert(newMachine.Principals(), jc.DeepEquals, oldMachine.Principals()) 216 c.Assert(newMachine.Series(), gc.Equals, oldMachine.Series()) 217 c.Assert(newMachine.ContainerType(), gc.Equals, oldMachine.ContainerType()) 218 newHardware, err := newMachine.HardwareCharacteristics() 219 c.Assert(err, jc.ErrorIsNil) 220 oldHardware, err := oldMachine.HardwareCharacteristics() 221 c.Assert(err, jc.ErrorIsNil) 222 c.Assert(newHardware, jc.DeepEquals, oldHardware) 223 c.Assert(newMachine.Jobs(), jc.DeepEquals, oldMachine.Jobs()) 224 c.Assert(newMachine.Life(), gc.Equals, oldMachine.Life()) 225 newTools, err := newMachine.AgentTools() 226 c.Assert(err, jc.ErrorIsNil) 227 oldTools, err := oldMachine.AgentTools() 228 c.Assert(err, jc.ErrorIsNil) 229 c.Assert(newTools, jc.DeepEquals, oldTools) 230 } 231 232 func (s *MigrationImportSuite) TestMachines(c *gc.C) { 233 // Let's add a machine with an LXC container. 234 cons := constraints.MustParse("arch=amd64 mem=8G") 235 machine1 := s.Factory.MakeMachine(c, &factory.MachineParams{ 236 Constraints: cons, 237 }) 238 err := s.State.SetAnnotations(machine1, testAnnotations) 239 c.Assert(err, jc.ErrorIsNil) 240 s.primeStatusHistory(c, machine1, status.Started, 5) 241 242 // machine1 should have some instance data. 243 hardware, err := machine1.HardwareCharacteristics() 244 c.Assert(err, jc.ErrorIsNil) 245 c.Assert(hardware, gc.NotNil) 246 247 _ = s.Factory.MakeMachineNested(c, machine1.Id(), nil) 248 249 allMachines, err := s.State.AllMachines() 250 c.Assert(err, jc.ErrorIsNil) 251 c.Assert(allMachines, gc.HasLen, 2) 252 253 _, newSt := s.importModel(c) 254 255 importedMachines, err := newSt.AllMachines() 256 c.Assert(err, jc.ErrorIsNil) 257 c.Assert(importedMachines, gc.HasLen, 2) 258 259 // AllMachines returns the machines in the same order, yay us. 260 for i, newMachine := range importedMachines { 261 s.AssertMachineEqual(c, newMachine, allMachines[i]) 262 } 263 264 // And a few extra checks. 265 parent := importedMachines[0] 266 container := importedMachines[1] 267 containers, err := parent.Containers() 268 c.Assert(err, jc.ErrorIsNil) 269 c.Assert(containers, jc.DeepEquals, []string{container.Id()}) 270 parentId, isContainer := container.ParentId() 271 c.Assert(parentId, gc.Equals, parent.Id()) 272 c.Assert(isContainer, jc.IsTrue) 273 274 s.assertAnnotations(c, newSt, parent) 275 s.checkStatusHistory(c, machine1, parent, 5) 276 277 newCons, err := parent.Constraints() 278 c.Assert(err, jc.ErrorIsNil) 279 // Can't test the constraints directly, so go through the string repr. 280 c.Assert(newCons.String(), gc.Equals, cons.String()) 281 } 282 283 func (s *MigrationImportSuite) TestMachineDevices(c *gc.C) { 284 machine := s.Factory.MakeMachine(c, nil) 285 // Create two devices, first with all fields set, second just to show that 286 // we do both. 287 sda := state.BlockDeviceInfo{ 288 DeviceName: "sda", 289 DeviceLinks: []string{"some", "data"}, 290 Label: "sda-label", 291 UUID: "some-uuid", 292 HardwareId: "magic", 293 BusAddress: "bus stop", 294 Size: 16 * 1024 * 1024 * 1024, 295 FilesystemType: "ext4", 296 InUse: true, 297 MountPoint: "/", 298 } 299 sdb := state.BlockDeviceInfo{DeviceName: "sdb", MountPoint: "/var/lib/lxd"} 300 err := machine.SetMachineBlockDevices(sda, sdb) 301 c.Assert(err, jc.ErrorIsNil) 302 303 _, newSt := s.importModel(c) 304 305 imported, err := newSt.Machine(machine.Id()) 306 c.Assert(err, jc.ErrorIsNil) 307 308 devices, err := newSt.BlockDevices(imported.MachineTag()) 309 c.Assert(err, jc.ErrorIsNil) 310 311 c.Check(devices, jc.DeepEquals, []state.BlockDeviceInfo{sda, sdb}) 312 } 313 314 func (s *MigrationImportSuite) TestApplications(c *gc.C) { 315 // Add a application with both settings and leadership settings. 316 cons := constraints.MustParse("arch=amd64 mem=8G") 317 application := s.Factory.MakeApplication(c, &factory.ApplicationParams{ 318 Settings: map[string]interface{}{ 319 "foo": "bar", 320 }, 321 Constraints: cons, 322 }) 323 err := application.UpdateLeaderSettings(&goodToken{}, map[string]string{ 324 "leader": "true", 325 }) 326 c.Assert(err, jc.ErrorIsNil) 327 err = application.SetMetricCredentials([]byte("sekrit")) 328 c.Assert(err, jc.ErrorIsNil) 329 // Expose the application. 330 c.Assert(application.SetExposed(), jc.ErrorIsNil) 331 err = s.State.SetAnnotations(application, testAnnotations) 332 c.Assert(err, jc.ErrorIsNil) 333 s.primeStatusHistory(c, application, status.Active, 5) 334 335 allApplications, err := s.State.AllApplications() 336 c.Assert(err, jc.ErrorIsNil) 337 c.Assert(allApplications, gc.HasLen, 1) 338 339 _, newSt := s.importModel(c) 340 341 importedApplications, err := newSt.AllApplications() 342 c.Assert(err, jc.ErrorIsNil) 343 c.Assert(importedApplications, gc.HasLen, 1) 344 345 exported := allApplications[0] 346 imported := importedApplications[0] 347 348 c.Assert(imported.ApplicationTag(), gc.Equals, exported.ApplicationTag()) 349 c.Assert(imported.Series(), gc.Equals, exported.Series()) 350 c.Assert(imported.IsExposed(), gc.Equals, exported.IsExposed()) 351 c.Assert(imported.MetricCredentials(), jc.DeepEquals, exported.MetricCredentials()) 352 353 exportedConfig, err := exported.ConfigSettings() 354 c.Assert(err, jc.ErrorIsNil) 355 importedConfig, err := imported.ConfigSettings() 356 c.Assert(err, jc.ErrorIsNil) 357 c.Assert(importedConfig, jc.DeepEquals, exportedConfig) 358 359 exportedLeaderSettings, err := exported.LeaderSettings() 360 c.Assert(err, jc.ErrorIsNil) 361 importedLeaderSettings, err := imported.LeaderSettings() 362 c.Assert(err, jc.ErrorIsNil) 363 c.Assert(importedLeaderSettings, jc.DeepEquals, exportedLeaderSettings) 364 365 s.assertAnnotations(c, newSt, imported) 366 s.checkStatusHistory(c, application, imported, 5) 367 368 newCons, err := imported.Constraints() 369 c.Assert(err, jc.ErrorIsNil) 370 // Can't test the constraints directly, so go through the string repr. 371 c.Assert(newCons.String(), gc.Equals, cons.String()) 372 } 373 374 func (s *MigrationImportSuite) TestApplicationLeaders(c *gc.C) { 375 s.makeApplicationWithLeader(c, "mysql", 2, 1) 376 s.makeApplicationWithLeader(c, "wordpress", 4, 2) 377 378 _, newSt := s.importModel(c) 379 380 leaders := make(map[string]string) 381 leases, err := state.LeadershipLeases(newSt) 382 c.Assert(err, jc.ErrorIsNil) 383 for key, value := range leases { 384 leaders[key] = value.Holder 385 } 386 c.Assert(leaders, jc.DeepEquals, map[string]string{ 387 "mysql": "mysql/1", 388 "wordpress": "wordpress/2", 389 }) 390 } 391 392 func (s *MigrationImportSuite) TestUnits(c *gc.C) { 393 s.assertUnitsMigrated(c, constraints.MustParse("arch=amd64 mem=8G")) 394 } 395 396 func (s *MigrationImportSuite) TestUnitsWithVirtConstraint(c *gc.C) { 397 s.assertUnitsMigrated(c, constraints.MustParse("arch=amd64 mem=8G virt-type=kvm")) 398 } 399 400 func (s *MigrationImportSuite) assertUnitsMigrated(c *gc.C, cons constraints.Value) { 401 exported, pwd := s.Factory.MakeUnitReturningPassword(c, &factory.UnitParams{ 402 Constraints: cons, 403 }) 404 err := exported.SetMeterStatus("GREEN", "some info") 405 c.Assert(err, jc.ErrorIsNil) 406 err = exported.SetWorkloadVersion("amethyst") 407 c.Assert(err, jc.ErrorIsNil) 408 err = s.State.SetAnnotations(exported, testAnnotations) 409 c.Assert(err, jc.ErrorIsNil) 410 s.primeStatusHistory(c, exported, status.Active, 5) 411 s.primeStatusHistory(c, exported.Agent(), status.Idle, 5) 412 413 _, newSt := s.importModel(c) 414 415 importedApplications, err := newSt.AllApplications() 416 c.Assert(err, jc.ErrorIsNil) 417 c.Assert(importedApplications, gc.HasLen, 1) 418 419 importedUnits, err := importedApplications[0].AllUnits() 420 c.Assert(err, jc.ErrorIsNil) 421 c.Assert(importedUnits, gc.HasLen, 1) 422 imported := importedUnits[0] 423 424 c.Assert(imported.UnitTag(), gc.Equals, exported.UnitTag()) 425 c.Assert(imported.PasswordValid(pwd), jc.IsTrue) 426 version, err := imported.WorkloadVersion() 427 c.Assert(err, jc.ErrorIsNil) 428 c.Assert(version, gc.Equals, "amethyst") 429 430 exportedMachineId, err := exported.AssignedMachineId() 431 c.Assert(err, jc.ErrorIsNil) 432 importedMachineId, err := imported.AssignedMachineId() 433 c.Assert(err, jc.ErrorIsNil) 434 c.Assert(importedMachineId, gc.Equals, exportedMachineId) 435 436 // Confirm machine Principals are set. 437 exportedMachine, err := s.State.Machine(exportedMachineId) 438 c.Assert(err, jc.ErrorIsNil) 439 importedMachine, err := newSt.Machine(importedMachineId) 440 c.Assert(err, jc.ErrorIsNil) 441 s.AssertMachineEqual(c, importedMachine, exportedMachine) 442 443 meterStatus, err := imported.GetMeterStatus() 444 c.Assert(err, jc.ErrorIsNil) 445 c.Assert(meterStatus, gc.Equals, state.MeterStatus{state.MeterGreen, "some info"}) 446 s.assertAnnotations(c, newSt, imported) 447 s.checkStatusHistory(c, exported, imported, 5) 448 s.checkStatusHistory(c, exported.Agent(), imported.Agent(), 5) 449 s.checkStatusHistory(c, exported.WorkloadVersionHistory(), imported.WorkloadVersionHistory(), 1) 450 451 newCons, err := imported.Constraints() 452 c.Assert(err, jc.ErrorIsNil) 453 // Can't test the constraints directly, so go through the string repr. 454 c.Assert(newCons.String(), gc.Equals, cons.String()) 455 } 456 457 func (s *MigrationImportSuite) TestRelations(c *gc.C) { 458 wordpress := state.AddTestingService(c, s.State, "wordpress", state.AddTestingCharm(c, s.State, "wordpress")) 459 state.AddTestingService(c, s.State, "mysql", state.AddTestingCharm(c, s.State, "mysql")) 460 eps, err := s.State.InferEndpoints("mysql", "wordpress") 461 c.Assert(err, jc.ErrorIsNil) 462 rel, err := s.State.AddRelation(eps...) 463 c.Assert(err, jc.ErrorIsNil) 464 wordpress_0 := s.Factory.MakeUnit(c, &factory.UnitParams{Application: wordpress}) 465 466 ru, err := rel.Unit(wordpress_0) 467 c.Assert(err, jc.ErrorIsNil) 468 relSettings := map[string]interface{}{ 469 "name": "wordpress/0", 470 } 471 err = ru.EnterScope(relSettings) 472 c.Assert(err, jc.ErrorIsNil) 473 474 _, newSt := s.importModel(c) 475 476 newWordpress, err := newSt.Application("wordpress") 477 c.Assert(err, jc.ErrorIsNil) 478 c.Assert(state.RelationCount(newWordpress), gc.Equals, 1) 479 rels, err := newWordpress.Relations() 480 c.Assert(err, jc.ErrorIsNil) 481 c.Assert(rels, gc.HasLen, 1) 482 units, err := newWordpress.AllUnits() 483 c.Assert(err, jc.ErrorIsNil) 484 c.Assert(units, gc.HasLen, 1) 485 486 ru, err = rels[0].Unit(units[0]) 487 c.Assert(err, jc.ErrorIsNil) 488 489 settings, err := ru.Settings() 490 c.Assert(err, jc.ErrorIsNil) 491 c.Assert(settings.Map(), gc.DeepEquals, relSettings) 492 } 493 494 func (s *MigrationImportSuite) TestUnitsOpenPorts(c *gc.C) { 495 unit := s.Factory.MakeUnit(c, nil) 496 err := unit.OpenPorts("tcp", 1234, 2345) 497 c.Assert(err, jc.ErrorIsNil) 498 499 _, newSt := s.importModel(c) 500 501 // Even though the opened ports document is stored with the 502 // machine, the only way to easily access it is through the units. 503 imported, err := newSt.Unit(unit.Name()) 504 c.Assert(err, jc.ErrorIsNil) 505 506 ports, err := imported.OpenedPorts() 507 c.Assert(err, jc.ErrorIsNil) 508 c.Assert(ports, gc.HasLen, 1) 509 c.Assert(ports[0], gc.Equals, network.PortRange{ 510 FromPort: 1234, 511 ToPort: 2345, 512 Protocol: "tcp", 513 }) 514 } 515 516 func (s *MigrationImportSuite) TestSpaces(c *gc.C) { 517 space := s.Factory.MakeSpace(c, &factory.SpaceParams{ 518 Name: "one", ProviderID: network.Id("provider"), IsPublic: true}) 519 520 _, newSt := s.importModel(c) 521 522 imported, err := newSt.Space(space.Name()) 523 c.Assert(err, jc.ErrorIsNil) 524 525 c.Assert(imported.Name(), gc.Equals, space.Name()) 526 c.Assert(imported.ProviderId(), gc.Equals, space.ProviderId()) 527 c.Assert(imported.IsPublic(), gc.Equals, space.IsPublic()) 528 } 529 530 func (s *MigrationImportSuite) TestDestroyEmptyModel(c *gc.C) { 531 newModel, _ := s.importModel(c) 532 s.assertDestroyModelAdvancesLife(c, newModel, state.Dead) 533 } 534 535 func (s *MigrationImportSuite) TestDestroyModelWithMachine(c *gc.C) { 536 s.Factory.MakeMachine(c, nil) 537 newModel, _ := s.importModel(c) 538 s.assertDestroyModelAdvancesLife(c, newModel, state.Dying) 539 } 540 541 func (s *MigrationImportSuite) TestDestroyModelWithApplication(c *gc.C) { 542 s.Factory.MakeApplication(c, nil) 543 newModel, _ := s.importModel(c) 544 s.assertDestroyModelAdvancesLife(c, newModel, state.Dying) 545 } 546 547 func (s *MigrationImportSuite) assertDestroyModelAdvancesLife(c *gc.C, m *state.Model, life state.Life) { 548 err := m.Destroy() 549 c.Assert(err, jc.ErrorIsNil) 550 err = m.Refresh() 551 c.Assert(err, jc.ErrorIsNil) 552 c.Assert(m.Life(), gc.Equals, life) 553 } 554 555 func (s *MigrationImportSuite) TestLinkLayerDevice(c *gc.C) { 556 machine := s.Factory.MakeMachine(c, &factory.MachineParams{ 557 Constraints: constraints.MustParse("arch=amd64 mem=8G"), 558 }) 559 deviceArgs := state.LinkLayerDeviceArgs{ 560 Name: "foo", 561 Type: state.EthernetDevice, 562 } 563 err := machine.SetLinkLayerDevices(deviceArgs) 564 c.Assert(err, jc.ErrorIsNil) 565 _, newSt := s.importModel(c) 566 567 devices, err := newSt.AllLinkLayerDevices() 568 c.Assert(err, jc.ErrorIsNil) 569 c.Assert(devices, gc.HasLen, 1) 570 device := devices[0] 571 c.Assert(device.Name(), gc.Equals, "foo") 572 c.Assert(device.Type(), gc.Equals, state.EthernetDevice) 573 } 574 575 func (s *MigrationImportSuite) TestLinkLayerDeviceMigratesReferences(c *gc.C) { 576 machine := s.Factory.MakeMachine(c, &factory.MachineParams{ 577 Constraints: constraints.MustParse("arch=amd64 mem=8G"), 578 }) 579 machine2 := s.Factory.MakeMachineNested(c, machine.Id(), &factory.MachineParams{ 580 Constraints: constraints.MustParse("arch=amd64 mem=8G"), 581 }) 582 deviceArgs := []state.LinkLayerDeviceArgs{{ 583 Name: "foo", 584 Type: state.BridgeDevice, 585 }, { 586 Name: "bar", 587 ParentName: "foo", 588 Type: state.EthernetDevice, 589 }} 590 for _, args := range deviceArgs { 591 err := machine.SetLinkLayerDevices(args) 592 c.Assert(err, jc.ErrorIsNil) 593 } 594 machine2DeviceArgs := state.LinkLayerDeviceArgs{ 595 Name: "baz", 596 ParentName: fmt.Sprintf("m#%v#d#foo", machine.Id()), 597 Type: state.EthernetDevice, 598 } 599 err := machine2.SetLinkLayerDevices(machine2DeviceArgs) 600 c.Assert(err, jc.ErrorIsNil) 601 _, newSt := s.importModel(c) 602 603 devices, err := newSt.AllLinkLayerDevices() 604 c.Assert(err, jc.ErrorIsNil) 605 c.Assert(devices, gc.HasLen, 3) 606 var parent *state.LinkLayerDevice 607 others := []*state.LinkLayerDevice{} 608 for _, device := range devices { 609 if device.Name() == "foo" { 610 parent = device 611 } else { 612 others = append(others, device) 613 } 614 } 615 // Assert we found the parent. 616 c.Assert(others, gc.HasLen, 2) 617 err = parent.Remove() 618 c.Assert(err, gc.ErrorMatches, `.*parent device "foo" has 2 children.*`) 619 err = others[0].Remove() 620 c.Assert(err, jc.ErrorIsNil) 621 err = parent.Remove() 622 c.Assert(err, gc.ErrorMatches, `.*parent device "foo" has 1 children.*`) 623 err = others[1].Remove() 624 c.Assert(err, jc.ErrorIsNil) 625 err = parent.Remove() 626 c.Assert(err, jc.ErrorIsNil) 627 } 628 629 func (s *MigrationImportSuite) TestSubnets(c *gc.C) { 630 original, err := s.State.AddSubnet(state.SubnetInfo{ 631 CIDR: "10.0.0.0/24", 632 ProviderId: network.Id("foo"), 633 VLANTag: 64, 634 AvailabilityZone: "bar", 635 SpaceName: "bam", 636 }) 637 c.Assert(err, jc.ErrorIsNil) 638 _, err = s.State.AddSpace("bam", "", nil, true) 639 c.Assert(err, jc.ErrorIsNil) 640 641 _, newSt := s.importModel(c) 642 643 subnet, err := newSt.Subnet(original.CIDR()) 644 c.Assert(err, jc.ErrorIsNil) 645 646 c.Assert(subnet.CIDR(), gc.Equals, "10.0.0.0/24") 647 c.Assert(subnet.ProviderId(), gc.Equals, network.Id("foo")) 648 c.Assert(subnet.VLANTag(), gc.Equals, 64) 649 c.Assert(subnet.AvailabilityZone(), gc.Equals, "bar") 650 c.Assert(subnet.SpaceName(), gc.Equals, "bam") 651 } 652 653 func (s *MigrationImportSuite) TestIPAddress(c *gc.C) { 654 machine := s.Factory.MakeMachine(c, &factory.MachineParams{ 655 Constraints: constraints.MustParse("arch=amd64 mem=8G"), 656 }) 657 _, err := s.State.AddSubnet(state.SubnetInfo{CIDR: "0.1.2.0/24"}) 658 c.Assert(err, jc.ErrorIsNil) 659 deviceArgs := state.LinkLayerDeviceArgs{ 660 Name: "foo", 661 Type: state.EthernetDevice, 662 } 663 err = machine.SetLinkLayerDevices(deviceArgs) 664 c.Assert(err, jc.ErrorIsNil) 665 args := state.LinkLayerDeviceAddress{ 666 DeviceName: "foo", 667 ConfigMethod: state.StaticAddress, 668 CIDRAddress: "0.1.2.3/24", 669 ProviderID: "bar", 670 DNSServers: []string{"bam", "mam"}, 671 DNSSearchDomains: []string{"weeee"}, 672 GatewayAddress: "0.1.2.1", 673 } 674 err = machine.SetDevicesAddresses(args) 675 c.Assert(err, jc.ErrorIsNil) 676 677 _, newSt := s.importModel(c) 678 679 addresses, _ := newSt.AllIPAddresses() 680 c.Assert(addresses, gc.HasLen, 1) 681 c.Assert(err, jc.ErrorIsNil) 682 addr := addresses[0] 683 c.Assert(addr.Value(), gc.Equals, "0.1.2.3") 684 c.Assert(addr.MachineID(), gc.Equals, machine.Id()) 685 c.Assert(addr.DeviceName(), gc.Equals, "foo") 686 c.Assert(addr.ConfigMethod(), gc.Equals, state.StaticAddress) 687 c.Assert(addr.SubnetCIDR(), gc.Equals, "0.1.2.0/24") 688 c.Assert(addr.ProviderID(), gc.Equals, network.Id("bar")) 689 c.Assert(addr.DNSServers(), jc.DeepEquals, []string{"bam", "mam"}) 690 c.Assert(addr.DNSSearchDomains(), jc.DeepEquals, []string{"weeee"}) 691 c.Assert(addr.GatewayAddress(), gc.Equals, "0.1.2.1") 692 } 693 694 func (s *MigrationImportSuite) TestSSHHostKey(c *gc.C) { 695 machine := s.Factory.MakeMachine(c, &factory.MachineParams{ 696 Constraints: constraints.MustParse("arch=amd64 mem=8G"), 697 }) 698 err := s.State.SetSSHHostKeys(machine.MachineTag(), []string{"bam", "mam"}) 699 c.Assert(err, jc.ErrorIsNil) 700 701 _, newSt := s.importModel(c) 702 703 machine2, err := newSt.Machine(machine.Id()) 704 c.Assert(err, jc.ErrorIsNil) 705 keys, err := newSt.GetSSHHostKeys(machine2.MachineTag()) 706 c.Assert(err, jc.ErrorIsNil) 707 c.Assert(keys, jc.DeepEquals, state.SSHHostKeys{"bam", "mam"}) 708 } 709 710 func (s *MigrationImportSuite) TestCloudImageMetadata(c *gc.C) { 711 storageSize := uint64(3) 712 attrs := cloudimagemetadata.MetadataAttributes{ 713 Stream: "stream", 714 Region: "region-test", 715 Version: "14.04", 716 Series: "trusty", 717 Arch: "arch", 718 VirtType: "virtType-test", 719 RootStorageType: "rootStorageType-test", 720 RootStorageSize: &storageSize, 721 Source: "test", 722 } 723 metadata := []cloudimagemetadata.Metadata{{attrs, 2, "1", 2}} 724 725 err := s.State.CloudImageMetadataStorage.SaveMetadata(metadata) 726 c.Assert(err, jc.ErrorIsNil) 727 728 _, newSt := s.importModel(c) 729 defer func() { 730 c.Assert(newSt.Close(), jc.ErrorIsNil) 731 }() 732 733 images, err := s.State.CloudImageMetadataStorage.AllCloudImageMetadata() 734 c.Assert(err, jc.ErrorIsNil) 735 c.Assert(images, gc.HasLen, 1) 736 image := images[0] 737 c.Check(image.Stream, gc.Equals, "stream") 738 c.Check(image.Region, gc.Equals, "region-test") 739 c.Check(image.Version, gc.Equals, "14.04") 740 c.Check(image.Arch, gc.Equals, "arch") 741 c.Check(image.VirtType, gc.Equals, "virtType-test") 742 c.Check(image.RootStorageType, gc.Equals, "rootStorageType-test") 743 c.Check(*image.RootStorageSize, gc.Equals, uint64(3)) 744 c.Check(image.Source, gc.Equals, "test") 745 c.Check(image.Priority, gc.Equals, 2) 746 c.Check(image.ImageId, gc.Equals, "1") 747 c.Check(image.DateCreated, gc.Equals, int64(2)) 748 } 749 750 func (s *MigrationImportSuite) TestAction(c *gc.C) { 751 machine := s.Factory.MakeMachine(c, &factory.MachineParams{ 752 Constraints: constraints.MustParse("arch=amd64 mem=8G"), 753 }) 754 _, err := s.State.EnqueueAction(machine.MachineTag(), "foo", nil) 755 c.Assert(err, jc.ErrorIsNil) 756 757 _, newSt := s.importModel(c) 758 defer func() { 759 c.Assert(newSt.Close(), jc.ErrorIsNil) 760 }() 761 762 actions, _ := newSt.AllActions() 763 c.Assert(actions, gc.HasLen, 1) 764 action := actions[0] 765 c.Check(action.Receiver(), gc.Equals, machine.Id()) 766 c.Check(action.Name(), gc.Equals, "foo") 767 c.Check(action.Status(), gc.Equals, state.ActionPending) 768 } 769 770 func (s *MigrationImportSuite) TestVolumes(c *gc.C) { 771 machine := s.Factory.MakeMachine(c, &factory.MachineParams{ 772 Volumes: []state.MachineVolumeParams{{ 773 Volume: state.VolumeParams{Size: 1234}, 774 Attachment: state.VolumeAttachmentParams{ReadOnly: true}, 775 }, { 776 Volume: state.VolumeParams{Size: 4000}, 777 Attachment: state.VolumeAttachmentParams{ReadOnly: true}, 778 }}, 779 }) 780 machineTag := machine.MachineTag() 781 782 // We know that the first volume is called "0/0" - although I don't know why. 783 volTag := names.NewVolumeTag("0/0") 784 volInfo := state.VolumeInfo{ 785 HardwareId: "magic", 786 Size: 1500, 787 Pool: "loop", 788 VolumeId: "volume id", 789 Persistent: true, 790 } 791 err := s.State.SetVolumeInfo(volTag, volInfo) 792 c.Assert(err, jc.ErrorIsNil) 793 volAttachmentInfo := state.VolumeAttachmentInfo{ 794 DeviceName: "device name", 795 DeviceLink: "device link", 796 BusAddress: "bus address", 797 ReadOnly: true, 798 } 799 err = s.State.SetVolumeAttachmentInfo(machineTag, volTag, volAttachmentInfo) 800 c.Assert(err, jc.ErrorIsNil) 801 802 _, newSt := s.importModel(c) 803 804 volume, err := newSt.Volume(volTag) 805 c.Assert(err, jc.ErrorIsNil) 806 807 // TODO: check status 808 // TODO: check storage instance 809 info, err := volume.Info() 810 c.Assert(err, jc.ErrorIsNil) 811 c.Check(info, jc.DeepEquals, volInfo) 812 813 attachment, err := newSt.VolumeAttachment(machineTag, volTag) 814 c.Assert(err, jc.ErrorIsNil) 815 attInfo, err := attachment.Info() 816 c.Assert(err, jc.ErrorIsNil) 817 c.Check(attInfo, jc.DeepEquals, volAttachmentInfo) 818 819 volTag = names.NewVolumeTag("0/1") 820 volume, err = newSt.Volume(volTag) 821 c.Assert(err, jc.ErrorIsNil) 822 823 params, needsProvisioning := volume.Params() 824 c.Check(needsProvisioning, jc.IsTrue) 825 c.Check(params.Pool, gc.Equals, "loop") 826 c.Check(params.Size, gc.Equals, uint64(4000)) 827 828 attachment, err = newSt.VolumeAttachment(machineTag, volTag) 829 c.Assert(err, jc.ErrorIsNil) 830 attParams, needsProvisioning := attachment.Params() 831 c.Check(needsProvisioning, jc.IsTrue) 832 c.Check(attParams.ReadOnly, jc.IsTrue) 833 } 834 835 func (s *MigrationImportSuite) TestFilesystems(c *gc.C) { 836 machine := s.Factory.MakeMachine(c, &factory.MachineParams{ 837 Filesystems: []state.MachineFilesystemParams{{ 838 Filesystem: state.FilesystemParams{Size: 1234}, 839 Attachment: state.FilesystemAttachmentParams{ 840 Location: "location", 841 ReadOnly: true}, 842 }, { 843 Filesystem: state.FilesystemParams{Size: 4000}, 844 Attachment: state.FilesystemAttachmentParams{ 845 ReadOnly: true}, 846 }}, 847 }) 848 machineTag := machine.MachineTag() 849 850 // We know that the first filesystem is called "0/0" as it is the first 851 // filesystem (filesystems use sequences), and it is bound to machine 0. 852 fsTag := names.NewFilesystemTag("0/0") 853 fsInfo := state.FilesystemInfo{ 854 Size: 1500, 855 Pool: "rootfs", 856 FilesystemId: "filesystem id", 857 } 858 err := s.State.SetFilesystemInfo(fsTag, fsInfo) 859 c.Assert(err, jc.ErrorIsNil) 860 fsAttachmentInfo := state.FilesystemAttachmentInfo{ 861 MountPoint: "/mnt/foo", 862 ReadOnly: true, 863 } 864 err = s.State.SetFilesystemAttachmentInfo(machineTag, fsTag, fsAttachmentInfo) 865 c.Assert(err, jc.ErrorIsNil) 866 867 _, newSt := s.importModel(c) 868 869 filesystem, err := newSt.Filesystem(fsTag) 870 c.Assert(err, jc.ErrorIsNil) 871 872 // TODO: check status 873 // TODO: check storage instance 874 info, err := filesystem.Info() 875 c.Assert(err, jc.ErrorIsNil) 876 c.Check(info, jc.DeepEquals, fsInfo) 877 878 attachment, err := newSt.FilesystemAttachment(machineTag, fsTag) 879 c.Assert(err, jc.ErrorIsNil) 880 attInfo, err := attachment.Info() 881 c.Assert(err, jc.ErrorIsNil) 882 c.Check(attInfo, jc.DeepEquals, fsAttachmentInfo) 883 884 fsTag = names.NewFilesystemTag("0/1") 885 filesystem, err = newSt.Filesystem(fsTag) 886 c.Assert(err, jc.ErrorIsNil) 887 888 params, needsProvisioning := filesystem.Params() 889 c.Check(needsProvisioning, jc.IsTrue) 890 c.Check(params.Pool, gc.Equals, "rootfs") 891 c.Check(params.Size, gc.Equals, uint64(4000)) 892 893 attachment, err = newSt.FilesystemAttachment(machineTag, fsTag) 894 c.Assert(err, jc.ErrorIsNil) 895 attParams, needsProvisioning := attachment.Params() 896 c.Check(needsProvisioning, jc.IsTrue) 897 c.Check(attParams.ReadOnly, jc.IsTrue) 898 } 899 900 func (s *MigrationImportSuite) TestStorage(c *gc.C) { 901 app, u, storageTag := s.makeUnitWithStorage(c) 902 original, err := s.State.StorageInstance(storageTag) 903 c.Assert(err, jc.ErrorIsNil) 904 originalCount := state.StorageAttachmentCount(original) 905 c.Assert(originalCount, gc.Equals, 1) 906 originalAttachments, err := s.State.StorageAttachments(storageTag) 907 c.Assert(err, jc.ErrorIsNil) 908 c.Assert(originalAttachments, gc.HasLen, 1) 909 c.Assert(originalAttachments[0].Unit(), gc.Equals, u.UnitTag()) 910 appName := app.Name() 911 912 _, newSt := s.importModel(c) 913 914 app, err = newSt.Application(appName) 915 c.Assert(err, jc.ErrorIsNil) 916 cons, err := app.StorageConstraints() 917 c.Assert(err, jc.ErrorIsNil) 918 c.Check(cons, jc.DeepEquals, map[string]state.StorageConstraints{ 919 "data": {Pool: "loop-pool", Size: 0x400, Count: 1}, 920 "allecto": {Pool: "loop", Size: 0x400}, 921 }) 922 923 instance, err := newSt.StorageInstance(storageTag) 924 c.Assert(err, jc.ErrorIsNil) 925 926 c.Check(instance.Tag(), gc.Equals, original.Tag()) 927 c.Check(instance.Kind(), gc.Equals, original.Kind()) 928 c.Check(instance.Life(), gc.Equals, original.Life()) 929 c.Check(instance.StorageName(), gc.Equals, original.StorageName()) 930 c.Check(state.StorageAttachmentCount(instance), gc.Equals, originalCount) 931 932 attachments, err := newSt.StorageAttachments(storageTag) 933 934 c.Assert(attachments, gc.HasLen, 1) 935 c.Assert(attachments[0].Unit(), gc.Equals, u.UnitTag()) 936 } 937 938 func (s *MigrationImportSuite) TestStoragePools(c *gc.C) { 939 pm := poolmanager.New(state.NewStateSettings(s.State), provider.CommonStorageProviders()) 940 _, err := pm.Create("test-pool", provider.LoopProviderType, map[string]interface{}{ 941 "value": 42, 942 }) 943 c.Assert(err, jc.ErrorIsNil) 944 945 _, newSt := s.importModel(c) 946 947 pm = poolmanager.New(state.NewStateSettings(newSt), provider.CommonStorageProviders()) 948 pools, err := pm.List() 949 c.Assert(err, jc.ErrorIsNil) 950 c.Assert(pools, gc.HasLen, 1) 951 952 pool := pools[0] 953 c.Assert(pool.Name(), gc.Equals, "test-pool") 954 c.Assert(pool.Provider(), gc.Equals, provider.LoopProviderType) 955 c.Assert(pool.Attrs(), jc.DeepEquals, map[string]interface{}{ 956 "value": 42, 957 }) 958 } 959 960 func (s *MigrationImportSuite) TestPayloads(c *gc.C) { 961 originalUnit := s.Factory.MakeUnit(c, nil) 962 unitID := originalUnit.UnitTag().Id() 963 up, err := s.State.UnitPayloads(originalUnit) 964 c.Assert(err, jc.ErrorIsNil) 965 original := payload.Payload{ 966 PayloadClass: charm.PayloadClass{ 967 Name: "something", 968 Type: "special", 969 }, 970 ID: "42", 971 Status: "running", 972 Labels: []string{"foo", "bar"}, 973 } 974 err = up.Track(original) 975 c.Assert(err, jc.ErrorIsNil) 976 977 _, newSt := s.importModel(c) 978 979 unit, err := newSt.Unit(unitID) 980 c.Assert(err, jc.ErrorIsNil) 981 982 up, err = newSt.UnitPayloads(unit) 983 c.Assert(err, jc.ErrorIsNil) 984 985 result, err := up.List() 986 c.Assert(err, jc.ErrorIsNil) 987 c.Assert(result, gc.HasLen, 1) 988 c.Assert(result[0].Payload, gc.NotNil) 989 990 payload := result[0].Payload 991 992 machineID, err := unit.AssignedMachineId() 993 c.Check(err, jc.ErrorIsNil) 994 c.Check(payload.Name, gc.Equals, original.Name) 995 c.Check(payload.Type, gc.Equals, original.Type) 996 c.Check(payload.ID, gc.Equals, original.ID) 997 c.Check(payload.Status, gc.Equals, original.Status) 998 c.Check(payload.Labels, jc.DeepEquals, original.Labels) 999 c.Check(payload.Unit, gc.Equals, unitID) 1000 c.Check(payload.Machine, gc.Equals, machineID) 1001 } 1002 1003 // newModel replaces the uuid and name of the config attributes so we 1004 // can use all the other data to validate imports. An owner and name of the 1005 // model are unique together in a controller. 1006 func newModel(m description.Model, uuid, name string) description.Model { 1007 return &mockModel{m, uuid, name} 1008 } 1009 1010 type mockModel struct { 1011 description.Model 1012 uuid string 1013 name string 1014 } 1015 1016 func (m *mockModel) Tag() names.ModelTag { 1017 return names.NewModelTag(m.uuid) 1018 } 1019 1020 func (m *mockModel) Config() map[string]interface{} { 1021 c := m.Model.Config() 1022 c["uuid"] = m.uuid 1023 c["name"] = m.name 1024 return c 1025 }