github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/migration_export_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 "math/rand" 8 "time" 9 10 jc "github.com/juju/testing/checkers" 11 "github.com/juju/version" 12 gc "gopkg.in/check.v1" 13 "gopkg.in/juju/charm.v6-unstable" 14 "gopkg.in/juju/names.v2" 15 16 "github.com/juju/juju/constraints" 17 "github.com/juju/juju/core/description" 18 "github.com/juju/juju/network" 19 "github.com/juju/juju/payload" 20 "github.com/juju/juju/permission" 21 "github.com/juju/juju/provider/dummy" 22 "github.com/juju/juju/state" 23 "github.com/juju/juju/state/cloudimagemetadata" 24 "github.com/juju/juju/status" 25 "github.com/juju/juju/storage/poolmanager" 26 "github.com/juju/juju/storage/provider" 27 "github.com/juju/juju/testing/factory" 28 ) 29 30 // Constraints stores megabytes by default for memory and root disk. 31 const ( 32 gig uint64 = 1024 33 34 addedHistoryCount = 5 35 // 6 for the one initial + 5 added. 36 expectedHistoryCount = addedHistoryCount + 1 37 ) 38 39 var testAnnotations = map[string]string{ 40 "string": "value", 41 "another": "one", 42 } 43 44 type MigrationBaseSuite struct { 45 ConnWithWallclockSuite 46 } 47 48 func (s *MigrationBaseSuite) setLatestTools(c *gc.C, latestTools version.Number) { 49 dbModel, err := s.State.Model() 50 c.Assert(err, jc.ErrorIsNil) 51 err = dbModel.UpdateLatestToolsVersion(latestTools) 52 c.Assert(err, jc.ErrorIsNil) 53 } 54 55 func (s *MigrationBaseSuite) setRandSequenceValue(c *gc.C, name string) int { 56 var value int 57 var err error 58 count := rand.Intn(5) + 1 59 for i := 0; i < count; i++ { 60 value, err = state.Sequence(s.State, name) 61 c.Assert(err, jc.ErrorIsNil) 62 } 63 // The value stored in the doc is one higher than what it returns. 64 return value + 1 65 } 66 67 func (s *MigrationBaseSuite) primeStatusHistory(c *gc.C, entity statusSetter, statusVal status.Status, count int) { 68 primeStatusHistory(c, entity, statusVal, count, func(i int) map[string]interface{} { 69 return map[string]interface{}{"index": count - i} 70 }, 0) 71 } 72 73 func (s *MigrationBaseSuite) makeApplicationWithLeader(c *gc.C, applicationname string, count int, leader int) { 74 c.Assert(leader < count, jc.IsTrue) 75 units := make([]*state.Unit, count) 76 application := s.Factory.MakeApplication(c, &factory.ApplicationParams{ 77 Name: applicationname, 78 Charm: s.Factory.MakeCharm(c, &factory.CharmParams{ 79 Name: applicationname, 80 }), 81 }) 82 for i := 0; i < count; i++ { 83 units[i] = s.Factory.MakeUnit(c, &factory.UnitParams{ 84 Application: application, 85 }) 86 } 87 err := s.State.LeadershipClaimer().ClaimLeadership( 88 application.Name(), 89 units[leader].Name(), 90 time.Minute) 91 c.Assert(err, jc.ErrorIsNil) 92 } 93 94 func (s *MigrationBaseSuite) makeUnitWithStorage(c *gc.C) (*state.Application, *state.Unit, names.StorageTag) { 95 pool := "loop-pool" 96 kind := "block" 97 // Create a default pool for block devices. 98 pm := poolmanager.New(state.NewStateSettings(s.State), dummy.StorageProviders()) 99 _, err := pm.Create(pool, provider.LoopProviderType, map[string]interface{}{}) 100 c.Assert(err, jc.ErrorIsNil) 101 102 // There are test charms called "storage-block" and 103 // "storage-filesystem" which are what you'd expect. 104 ch := s.AddTestingCharm(c, "storage-"+kind) 105 storage := map[string]state.StorageConstraints{ 106 "data": makeStorageCons(pool, 1024, 1), 107 } 108 service := s.AddTestingServiceWithStorage(c, "storage-"+kind, ch, storage) 109 unit, err := service.AddUnit() 110 111 machine := s.Factory.MakeMachine(c, nil) 112 err = unit.AssignToMachine(machine) 113 c.Assert(err, jc.ErrorIsNil) 114 115 c.Assert(err, jc.ErrorIsNil) 116 storageTag := names.NewStorageTag("data/0") 117 agentVersion := version.MustParseBinary("2.0.1-quantal-and64") 118 err = unit.SetAgentVersion(agentVersion) 119 c.Assert(err, jc.ErrorIsNil) 120 return service, unit, storageTag 121 } 122 123 type MigrationExportSuite struct { 124 MigrationBaseSuite 125 } 126 127 var _ = gc.Suite(&MigrationExportSuite{}) 128 129 func (s *MigrationExportSuite) checkStatusHistory(c *gc.C, history []description.Status, statusVal status.Status) { 130 for i, st := range history { 131 c.Logf("status history #%d: %s", i, st.Updated()) 132 c.Check(st.Value(), gc.Equals, string(statusVal)) 133 c.Check(st.Message(), gc.Equals, "") 134 c.Check(st.Data(), jc.DeepEquals, map[string]interface{}{"index": i + 1}) 135 } 136 } 137 138 func (s *MigrationExportSuite) TestModelInfo(c *gc.C) { 139 stModel, err := s.State.Model() 140 c.Assert(err, jc.ErrorIsNil) 141 err = s.State.SetAnnotations(stModel, testAnnotations) 142 c.Assert(err, jc.ErrorIsNil) 143 latestTools := version.MustParse("2.0.1") 144 s.setLatestTools(c, latestTools) 145 err = s.State.SetModelConstraints(constraints.MustParse("arch=amd64 mem=8G")) 146 c.Assert(err, jc.ErrorIsNil) 147 machineSeq := s.setRandSequenceValue(c, "machine") 148 fooSeq := s.setRandSequenceValue(c, "application-foo") 149 s.State.SwitchBlockOn(state.ChangeBlock, "locked down") 150 151 model, err := s.State.Export() 152 c.Assert(err, jc.ErrorIsNil) 153 154 dbModel, err := s.State.Model() 155 c.Assert(err, jc.ErrorIsNil) 156 c.Assert(model.Tag(), gc.Equals, dbModel.ModelTag()) 157 c.Assert(model.Owner(), gc.Equals, dbModel.Owner()) 158 dbModelCfg, err := dbModel.Config() 159 c.Assert(err, jc.ErrorIsNil) 160 modelAttrs := dbModelCfg.AllAttrs() 161 modelCfg := model.Config() 162 // Config as read from state has resources tags coerced to a map. 163 modelCfg["resource-tags"] = map[string]string{} 164 c.Assert(modelCfg, jc.DeepEquals, modelAttrs) 165 c.Assert(model.LatestToolsVersion(), gc.Equals, latestTools) 166 c.Assert(model.Annotations(), jc.DeepEquals, testAnnotations) 167 constraints := model.Constraints() 168 c.Assert(constraints, gc.NotNil) 169 c.Assert(constraints.Architecture(), gc.Equals, "amd64") 170 c.Assert(constraints.Memory(), gc.Equals, 8*gig) 171 c.Assert(model.Sequences(), jc.DeepEquals, map[string]int{ 172 "machine": machineSeq, 173 "application-foo": fooSeq, 174 // blocks is added by the switch block on call above. 175 "block": 1, 176 }) 177 c.Assert(model.Blocks(), jc.DeepEquals, map[string]string{ 178 "all-changes": "locked down", 179 }) 180 } 181 182 func (s *MigrationExportSuite) TestModelUsers(c *gc.C) { 183 // Make sure we have some last connection times for the admin user, 184 // and create a few other users. 185 lastConnection := s.State.NowToTheSecond() 186 owner, err := s.State.UserAccess(s.Owner, s.State.ModelTag()) 187 c.Assert(err, jc.ErrorIsNil) 188 err = state.UpdateModelUserLastConnection(s.State, owner, lastConnection) 189 c.Assert(err, jc.ErrorIsNil) 190 191 bobTag := names.NewUserTag("bob@external") 192 bob, err := s.State.AddModelUser(s.State.ModelUUID(), state.UserAccessSpec{ 193 User: bobTag, 194 CreatedBy: s.Owner, 195 Access: permission.ReadAccess, 196 }) 197 c.Assert(err, jc.ErrorIsNil) 198 err = state.UpdateModelUserLastConnection(s.State, bob, lastConnection) 199 c.Assert(err, jc.ErrorIsNil) 200 201 model, err := s.State.Export() 202 c.Assert(err, jc.ErrorIsNil) 203 204 users := model.Users() 205 c.Assert(users, gc.HasLen, 2) 206 207 exportedBob := users[0] 208 // admin is "test-admin", and results are sorted 209 exportedAdmin := users[1] 210 211 c.Assert(exportedAdmin.Name(), gc.Equals, s.Owner) 212 c.Assert(exportedAdmin.DisplayName(), gc.Equals, owner.DisplayName) 213 c.Assert(exportedAdmin.CreatedBy(), gc.Equals, s.Owner) 214 c.Assert(exportedAdmin.DateCreated(), gc.Equals, owner.DateCreated) 215 c.Assert(exportedAdmin.LastConnection(), gc.Equals, lastConnection) 216 c.Assert(exportedAdmin.Access(), gc.Equals, "admin") 217 218 c.Assert(exportedBob.Name(), gc.Equals, bobTag) 219 c.Assert(exportedBob.DisplayName(), gc.Equals, "") 220 c.Assert(exportedBob.CreatedBy(), gc.Equals, s.Owner) 221 c.Assert(exportedBob.DateCreated(), gc.Equals, bob.DateCreated) 222 c.Assert(exportedBob.LastConnection(), gc.Equals, lastConnection) 223 c.Assert(exportedBob.Access(), gc.Equals, "read") 224 } 225 226 func (s *MigrationExportSuite) TestMachines(c *gc.C) { 227 s.assertMachinesMigrated(c, constraints.MustParse("arch=amd64 mem=8G")) 228 } 229 230 func (s *MigrationExportSuite) TestMachinesWithVirtConstraint(c *gc.C) { 231 s.assertMachinesMigrated(c, constraints.MustParse("arch=amd64 mem=8G virt-type=kvm")) 232 } 233 234 func (s *MigrationExportSuite) assertMachinesMigrated(c *gc.C, cons constraints.Value) { 235 // Add a machine with an LXC container. 236 machine1 := s.Factory.MakeMachine(c, &factory.MachineParams{ 237 Constraints: cons, 238 }) 239 nested := s.Factory.MakeMachineNested(c, machine1.Id(), nil) 240 err := s.State.SetAnnotations(machine1, testAnnotations) 241 c.Assert(err, jc.ErrorIsNil) 242 s.primeStatusHistory(c, machine1, status.Started, addedHistoryCount) 243 244 model, err := s.State.Export() 245 c.Assert(err, jc.ErrorIsNil) 246 247 machines := model.Machines() 248 c.Assert(machines, gc.HasLen, 1) 249 250 exported := machines[0] 251 c.Assert(exported.Tag(), gc.Equals, machine1.MachineTag()) 252 c.Assert(exported.Series(), gc.Equals, machine1.Series()) 253 c.Assert(exported.Annotations(), jc.DeepEquals, testAnnotations) 254 constraints := exported.Constraints() 255 c.Assert(constraints, gc.NotNil) 256 c.Assert(constraints.Architecture(), gc.Equals, *cons.Arch) 257 c.Assert(constraints.Memory(), gc.Equals, *cons.Mem) 258 if cons.HasVirtType() { 259 c.Assert(constraints.VirtType(), gc.Equals, *cons.VirtType) 260 } 261 262 tools, err := machine1.AgentTools() 263 c.Assert(err, jc.ErrorIsNil) 264 exTools := exported.Tools() 265 c.Assert(exTools, gc.NotNil) 266 c.Assert(exTools.Version(), jc.DeepEquals, tools.Version) 267 268 history := exported.StatusHistory() 269 c.Assert(history, gc.HasLen, expectedHistoryCount) 270 s.checkStatusHistory(c, history[:addedHistoryCount], status.Started) 271 272 containers := exported.Containers() 273 c.Assert(containers, gc.HasLen, 1) 274 container := containers[0] 275 c.Assert(container.Tag(), gc.Equals, nested.MachineTag()) 276 } 277 278 func (s *MigrationExportSuite) TestMachineDevices(c *gc.C) { 279 machine := s.Factory.MakeMachine(c, nil) 280 // Create two devices, first with all fields set, second just to show that 281 // we do both. 282 sda := state.BlockDeviceInfo{ 283 DeviceName: "sda", 284 DeviceLinks: []string{"some", "data"}, 285 Label: "sda-label", 286 UUID: "some-uuid", 287 HardwareId: "magic", 288 BusAddress: "bus stop", 289 Size: 16 * 1024 * 1024 * 1024, 290 FilesystemType: "ext4", 291 InUse: true, 292 MountPoint: "/", 293 } 294 sdb := state.BlockDeviceInfo{DeviceName: "sdb", MountPoint: "/var/lib/lxd"} 295 err := machine.SetMachineBlockDevices(sda, sdb) 296 c.Assert(err, jc.ErrorIsNil) 297 298 model, err := s.State.Export() 299 c.Assert(err, jc.ErrorIsNil) 300 machines := model.Machines() 301 c.Assert(machines, gc.HasLen, 1) 302 exported := machines[0] 303 304 devices := exported.BlockDevices() 305 c.Assert(devices, gc.HasLen, 2) 306 ex1, ex2 := devices[0], devices[1] 307 308 c.Check(ex1.Name(), gc.Equals, "sda") 309 c.Check(ex1.Links(), jc.DeepEquals, []string{"some", "data"}) 310 c.Check(ex1.Label(), gc.Equals, "sda-label") 311 c.Check(ex1.UUID(), gc.Equals, "some-uuid") 312 c.Check(ex1.HardwareID(), gc.Equals, "magic") 313 c.Check(ex1.BusAddress(), gc.Equals, "bus stop") 314 c.Check(ex1.Size(), gc.Equals, uint64(16*1024*1024*1024)) 315 c.Check(ex1.FilesystemType(), gc.Equals, "ext4") 316 c.Check(ex1.InUse(), jc.IsTrue) 317 c.Check(ex1.MountPoint(), gc.Equals, "/") 318 319 c.Check(ex2.Name(), gc.Equals, "sdb") 320 c.Check(ex2.MountPoint(), gc.Equals, "/var/lib/lxd") 321 } 322 323 func (s *MigrationExportSuite) TestApplications(c *gc.C) { 324 s.assertMigrateApplications(c, constraints.MustParse("arch=amd64 mem=8G")) 325 } 326 327 func (s *MigrationExportSuite) TestApplicationsWithVirtConstraint(c *gc.C) { 328 s.assertMigrateApplications(c, constraints.MustParse("arch=amd64 mem=8G virt-type=kvm")) 329 } 330 331 func (s *MigrationExportSuite) assertMigrateApplications(c *gc.C, cons constraints.Value) { 332 application := s.Factory.MakeApplication(c, &factory.ApplicationParams{ 333 Settings: map[string]interface{}{ 334 "foo": "bar", 335 }, 336 Constraints: cons, 337 }) 338 err := application.UpdateLeaderSettings(&goodToken{}, map[string]string{ 339 "leader": "true", 340 }) 341 c.Assert(err, jc.ErrorIsNil) 342 err = application.SetMetricCredentials([]byte("sekrit")) 343 c.Assert(err, jc.ErrorIsNil) 344 err = s.State.SetAnnotations(application, testAnnotations) 345 c.Assert(err, jc.ErrorIsNil) 346 s.primeStatusHistory(c, application, status.Active, addedHistoryCount) 347 348 model, err := s.State.Export() 349 c.Assert(err, jc.ErrorIsNil) 350 351 applications := model.Applications() 352 c.Assert(applications, gc.HasLen, 1) 353 354 exported := applications[0] 355 c.Assert(exported.Name(), gc.Equals, application.Name()) 356 c.Assert(exported.Tag(), gc.Equals, application.ApplicationTag()) 357 c.Assert(exported.Series(), gc.Equals, application.Series()) 358 c.Assert(exported.Annotations(), jc.DeepEquals, testAnnotations) 359 360 c.Assert(exported.Settings(), jc.DeepEquals, map[string]interface{}{ 361 "foo": "bar", 362 }) 363 c.Assert(exported.LeadershipSettings(), jc.DeepEquals, map[string]interface{}{ 364 "leader": "true", 365 }) 366 c.Assert(exported.MetricsCredentials(), jc.DeepEquals, []byte("sekrit")) 367 368 constraints := exported.Constraints() 369 c.Assert(constraints, gc.NotNil) 370 c.Assert(constraints.Architecture(), gc.Equals, *cons.Arch) 371 c.Assert(constraints.Memory(), gc.Equals, *cons.Mem) 372 if cons.HasVirtType() { 373 c.Assert(constraints.VirtType(), gc.Equals, *cons.VirtType) 374 } 375 376 history := exported.StatusHistory() 377 c.Assert(history, gc.HasLen, expectedHistoryCount) 378 s.checkStatusHistory(c, history[:addedHistoryCount], status.Active) 379 } 380 381 func (s *MigrationExportSuite) TestMultipleApplications(c *gc.C) { 382 s.Factory.MakeApplication(c, &factory.ApplicationParams{Name: "first"}) 383 s.Factory.MakeApplication(c, &factory.ApplicationParams{Name: "second"}) 384 s.Factory.MakeApplication(c, &factory.ApplicationParams{Name: "third"}) 385 386 model, err := s.State.Export() 387 c.Assert(err, jc.ErrorIsNil) 388 389 applications := model.Applications() 390 c.Assert(applications, gc.HasLen, 3) 391 } 392 393 func (s *MigrationExportSuite) TestUnits(c *gc.C) { 394 unit := s.Factory.MakeUnit(c, &factory.UnitParams{ 395 Constraints: constraints.MustParse("arch=amd64 mem=8G"), 396 }) 397 err := unit.SetMeterStatus("GREEN", "some info") 398 c.Assert(err, jc.ErrorIsNil) 399 for _, version := range []string{"garnet", "amethyst", "pearl", "steven"} { 400 err = unit.SetWorkloadVersion(version) 401 c.Assert(err, jc.ErrorIsNil) 402 } 403 err = s.State.SetAnnotations(unit, testAnnotations) 404 c.Assert(err, jc.ErrorIsNil) 405 s.primeStatusHistory(c, unit, status.Active, addedHistoryCount) 406 s.primeStatusHistory(c, unit.Agent(), status.Idle, addedHistoryCount) 407 408 model, err := s.State.Export() 409 c.Assert(err, jc.ErrorIsNil) 410 411 applications := model.Applications() 412 c.Assert(applications, gc.HasLen, 1) 413 414 application := applications[0] 415 units := application.Units() 416 c.Assert(units, gc.HasLen, 1) 417 418 exported := units[0] 419 420 c.Assert(exported.Name(), gc.Equals, unit.Name()) 421 c.Assert(exported.Tag(), gc.Equals, unit.UnitTag()) 422 c.Assert(exported.Validate(), jc.ErrorIsNil) 423 c.Assert(exported.MeterStatusCode(), gc.Equals, "GREEN") 424 c.Assert(exported.MeterStatusInfo(), gc.Equals, "some info") 425 c.Assert(exported.WorkloadVersion(), gc.Equals, "steven") 426 c.Assert(exported.Annotations(), jc.DeepEquals, testAnnotations) 427 constraints := exported.Constraints() 428 c.Assert(constraints, gc.NotNil) 429 c.Assert(constraints.Architecture(), gc.Equals, "amd64") 430 c.Assert(constraints.Memory(), gc.Equals, 8*gig) 431 432 workloadHistory := exported.WorkloadStatusHistory() 433 c.Assert(workloadHistory, gc.HasLen, expectedHistoryCount) 434 s.checkStatusHistory(c, workloadHistory[:addedHistoryCount], status.Active) 435 436 agentHistory := exported.AgentStatusHistory() 437 c.Assert(agentHistory, gc.HasLen, expectedHistoryCount) 438 s.checkStatusHistory(c, agentHistory[:addedHistoryCount], status.Idle) 439 440 versionHistory := exported.WorkloadVersionHistory() 441 // There are extra entries at the start that we don't care about. 442 c.Assert(len(versionHistory) >= 4, jc.IsTrue) 443 versions := make([]string, 4) 444 for i, status := range versionHistory[:4] { 445 versions[i] = status.Message() 446 } 447 // The exporter reads history in reverse time order. 448 c.Assert(versions, gc.DeepEquals, []string{"steven", "pearl", "amethyst", "garnet"}) 449 } 450 451 func (s *MigrationExportSuite) TestServiceLeadership(c *gc.C) { 452 s.makeApplicationWithLeader(c, "mysql", 2, 1) 453 s.makeApplicationWithLeader(c, "wordpress", 4, 2) 454 455 model, err := s.State.Export() 456 c.Assert(err, jc.ErrorIsNil) 457 458 leaders := make(map[string]string) 459 for _, application := range model.Applications() { 460 leaders[application.Name()] = application.Leader() 461 } 462 c.Assert(leaders, jc.DeepEquals, map[string]string{ 463 "mysql": "mysql/1", 464 "wordpress": "wordpress/2", 465 }) 466 } 467 468 func (s *MigrationExportSuite) TestUnitsOpenPorts(c *gc.C) { 469 unit := s.Factory.MakeUnit(c, nil) 470 err := unit.OpenPorts("tcp", 1234, 2345) 471 c.Assert(err, jc.ErrorIsNil) 472 473 model, err := s.State.Export() 474 c.Assert(err, jc.ErrorIsNil) 475 476 machines := model.Machines() 477 c.Assert(machines, gc.HasLen, 1) 478 479 ports := machines[0].OpenedPorts() 480 c.Assert(ports, gc.HasLen, 1) 481 482 port := ports[0] 483 c.Assert(port.SubnetID(), gc.Equals, "") 484 opened := port.OpenPorts() 485 c.Assert(opened, gc.HasLen, 1) 486 c.Assert(opened[0].UnitName(), gc.Equals, unit.Name()) 487 } 488 489 func (s *MigrationExportSuite) TestRelations(c *gc.C) { 490 wordpress := state.AddTestingService(c, s.State, "wordpress", state.AddTestingCharm(c, s.State, "wordpress")) 491 mysql := state.AddTestingService(c, s.State, "mysql", state.AddTestingCharm(c, s.State, "mysql")) 492 // InferEndpoints will always return provider, requirer 493 eps, err := s.State.InferEndpoints("mysql", "wordpress") 494 c.Assert(err, jc.ErrorIsNil) 495 rel, err := s.State.AddRelation(eps...) 496 msEp, wpEp := eps[0], eps[1] 497 c.Assert(err, jc.ErrorIsNil) 498 wordpress_0 := s.Factory.MakeUnit(c, &factory.UnitParams{Application: wordpress}) 499 mysql_0 := s.Factory.MakeUnit(c, &factory.UnitParams{Application: mysql}) 500 501 ru, err := rel.Unit(wordpress_0) 502 c.Assert(err, jc.ErrorIsNil) 503 wordpressSettings := map[string]interface{}{ 504 "name": "wordpress/0", 505 } 506 err = ru.EnterScope(wordpressSettings) 507 c.Assert(err, jc.ErrorIsNil) 508 509 ru, err = rel.Unit(mysql_0) 510 c.Assert(err, jc.ErrorIsNil) 511 mysqlSettings := map[string]interface{}{ 512 "name": "mysql/0", 513 } 514 err = ru.EnterScope(mysqlSettings) 515 c.Assert(err, jc.ErrorIsNil) 516 517 model, err := s.State.Export() 518 c.Assert(err, jc.ErrorIsNil) 519 520 rels := model.Relations() 521 c.Assert(rels, gc.HasLen, 1) 522 523 exRel := rels[0] 524 c.Assert(exRel.Id(), gc.Equals, rel.Id()) 525 c.Assert(exRel.Key(), gc.Equals, rel.String()) 526 527 exEps := exRel.Endpoints() 528 c.Assert(exEps, gc.HasLen, 2) 529 530 checkEndpoint := func( 531 exEndpoint description.Endpoint, 532 unitName string, 533 ep state.Endpoint, 534 settings map[string]interface{}, 535 ) { 536 c.Logf("%#v", exEndpoint) 537 c.Check(exEndpoint.ApplicationName(), gc.Equals, ep.ApplicationName) 538 c.Check(exEndpoint.Name(), gc.Equals, ep.Name) 539 c.Check(exEndpoint.UnitCount(), gc.Equals, 1) 540 c.Check(exEndpoint.Settings(unitName), jc.DeepEquals, settings) 541 c.Check(exEndpoint.Role(), gc.Equals, string(ep.Role)) 542 c.Check(exEndpoint.Interface(), gc.Equals, ep.Interface) 543 c.Check(exEndpoint.Optional(), gc.Equals, ep.Optional) 544 c.Check(exEndpoint.Limit(), gc.Equals, ep.Limit) 545 c.Check(exEndpoint.Scope(), gc.Equals, string(ep.Scope)) 546 } 547 checkEndpoint(exEps[0], mysql_0.Name(), msEp, mysqlSettings) 548 checkEndpoint(exEps[1], wordpress_0.Name(), wpEp, wordpressSettings) 549 } 550 551 func (s *MigrationExportSuite) TestSpaces(c *gc.C) { 552 s.Factory.MakeSpace(c, &factory.SpaceParams{ 553 Name: "one", ProviderID: network.Id("provider"), IsPublic: true}) 554 555 model, err := s.State.Export() 556 c.Assert(err, jc.ErrorIsNil) 557 558 spaces := model.Spaces() 559 c.Assert(spaces, gc.HasLen, 1) 560 space := spaces[0] 561 c.Assert(space.Name(), gc.Equals, "one") 562 c.Assert(space.ProviderID(), gc.Equals, "provider") 563 c.Assert(space.Public(), jc.IsTrue) 564 } 565 566 func (s *MigrationExportSuite) TestMultipleSpaces(c *gc.C) { 567 s.Factory.MakeSpace(c, &factory.SpaceParams{Name: "one"}) 568 s.Factory.MakeSpace(c, &factory.SpaceParams{Name: "two"}) 569 s.Factory.MakeSpace(c, &factory.SpaceParams{Name: "three"}) 570 571 model, err := s.State.Export() 572 c.Assert(err, jc.ErrorIsNil) 573 c.Assert(model.Spaces(), gc.HasLen, 3) 574 } 575 576 func (s *MigrationExportSuite) TestLinkLayerDevices(c *gc.C) { 577 machine := s.Factory.MakeMachine(c, &factory.MachineParams{ 578 Constraints: constraints.MustParse("arch=amd64 mem=8G"), 579 }) 580 deviceArgs := state.LinkLayerDeviceArgs{ 581 Name: "foo", 582 Type: state.EthernetDevice, 583 } 584 err := machine.SetLinkLayerDevices(deviceArgs) 585 c.Assert(err, jc.ErrorIsNil) 586 587 model, err := s.State.Export() 588 c.Assert(err, jc.ErrorIsNil) 589 590 devices := model.LinkLayerDevices() 591 c.Assert(devices, gc.HasLen, 1) 592 device := devices[0] 593 c.Assert(device.Name(), gc.Equals, "foo") 594 c.Assert(device.Type(), gc.Equals, string(state.EthernetDevice)) 595 } 596 597 func (s *MigrationExportSuite) TestSubnets(c *gc.C) { 598 _, err := s.State.AddSubnet(state.SubnetInfo{ 599 CIDR: "10.0.0.0/24", 600 ProviderId: network.Id("foo"), 601 VLANTag: 64, 602 AvailabilityZone: "bar", 603 SpaceName: "bam", 604 }) 605 c.Assert(err, jc.ErrorIsNil) 606 _, err = s.State.AddSpace("bam", "", nil, true) 607 c.Assert(err, jc.ErrorIsNil) 608 609 model, err := s.State.Export() 610 c.Assert(err, jc.ErrorIsNil) 611 612 subnets := model.Subnets() 613 c.Assert(subnets, gc.HasLen, 1) 614 subnet := subnets[0] 615 c.Assert(subnet.CIDR(), gc.Equals, "10.0.0.0/24") 616 c.Assert(subnet.ProviderId(), gc.Equals, "foo") 617 c.Assert(subnet.VLANTag(), gc.Equals, 64) 618 c.Assert(subnet.AvailabilityZone(), gc.Equals, "bar") 619 c.Assert(subnet.SpaceName(), gc.Equals, "bam") 620 } 621 622 func (s *MigrationExportSuite) TestIPAddresses(c *gc.C) { 623 machine := s.Factory.MakeMachine(c, &factory.MachineParams{ 624 Constraints: constraints.MustParse("arch=amd64 mem=8G"), 625 }) 626 _, err := s.State.AddSubnet(state.SubnetInfo{CIDR: "0.1.2.0/24"}) 627 c.Assert(err, jc.ErrorIsNil) 628 deviceArgs := state.LinkLayerDeviceArgs{ 629 Name: "foo", 630 Type: state.EthernetDevice, 631 } 632 err = machine.SetLinkLayerDevices(deviceArgs) 633 c.Assert(err, jc.ErrorIsNil) 634 args := state.LinkLayerDeviceAddress{ 635 DeviceName: "foo", 636 ConfigMethod: state.StaticAddress, 637 CIDRAddress: "0.1.2.3/24", 638 ProviderID: "bar", 639 DNSServers: []string{"bam", "mam"}, 640 DNSSearchDomains: []string{"weeee"}, 641 GatewayAddress: "0.1.2.1", 642 } 643 err = machine.SetDevicesAddresses(args) 644 c.Assert(err, jc.ErrorIsNil) 645 646 model, err := s.State.Export() 647 c.Assert(err, jc.ErrorIsNil) 648 649 addresses := model.IPAddresses() 650 c.Assert(addresses, gc.HasLen, 1) 651 addr := addresses[0] 652 c.Assert(addr.Value(), gc.Equals, "0.1.2.3") 653 c.Assert(addr.MachineID(), gc.Equals, machine.Id()) 654 c.Assert(addr.DeviceName(), gc.Equals, "foo") 655 c.Assert(addr.ConfigMethod(), gc.Equals, string(state.StaticAddress)) 656 c.Assert(addr.SubnetCIDR(), gc.Equals, "0.1.2.0/24") 657 c.Assert(addr.ProviderID(), gc.Equals, "bar") 658 c.Assert(addr.DNSServers(), jc.DeepEquals, []string{"bam", "mam"}) 659 c.Assert(addr.DNSSearchDomains(), jc.DeepEquals, []string{"weeee"}) 660 c.Assert(addr.GatewayAddress(), gc.Equals, "0.1.2.1") 661 } 662 663 func (s *MigrationExportSuite) TestSSHHostKeys(c *gc.C) { 664 machine := s.Factory.MakeMachine(c, &factory.MachineParams{ 665 Constraints: constraints.MustParse("arch=amd64 mem=8G"), 666 }) 667 err := s.State.SetSSHHostKeys(machine.MachineTag(), []string{"bam", "mam"}) 668 c.Assert(err, jc.ErrorIsNil) 669 670 model, err := s.State.Export() 671 c.Assert(err, jc.ErrorIsNil) 672 673 keys := model.SSHHostKeys() 674 c.Assert(keys, gc.HasLen, 1) 675 key := keys[0] 676 c.Assert(key.MachineID(), gc.Equals, machine.Id()) 677 c.Assert(key.Keys(), jc.DeepEquals, []string{"bam", "mam"}) 678 } 679 680 func (s *MigrationExportSuite) TestCloudImageMetadatas(c *gc.C) { 681 storageSize := uint64(3) 682 attrs := cloudimagemetadata.MetadataAttributes{ 683 Stream: "stream", 684 Region: "region-test", 685 Version: "14.04", 686 Series: "trusty", 687 Arch: "arch", 688 VirtType: "virtType-test", 689 RootStorageType: "rootStorageType-test", 690 RootStorageSize: &storageSize, 691 Source: "test", 692 } 693 metadata := []cloudimagemetadata.Metadata{{attrs, 2, "1", 2}} 694 695 err := s.State.CloudImageMetadataStorage.SaveMetadata(metadata) 696 c.Assert(err, jc.ErrorIsNil) 697 698 model, err := s.State.Export() 699 c.Assert(err, jc.ErrorIsNil) 700 701 images := model.CloudImageMetadata() 702 c.Assert(images, gc.HasLen, 1) 703 image := images[0] 704 c.Check(image.Stream(), gc.Equals, "stream") 705 c.Check(image.Region(), gc.Equals, "region-test") 706 c.Check(image.Version(), gc.Equals, "14.04") 707 c.Check(image.Arch(), gc.Equals, "arch") 708 c.Check(image.VirtType(), gc.Equals, "virtType-test") 709 c.Check(image.RootStorageType(), gc.Equals, "rootStorageType-test") 710 value, ok := image.RootStorageSize() 711 c.Assert(ok, jc.IsTrue) 712 c.Assert(value, gc.Equals, uint64(3)) 713 c.Check(image.Source(), gc.Equals, "test") 714 c.Check(image.Priority(), gc.Equals, 2) 715 c.Check(image.ImageId(), gc.Equals, "1") 716 c.Check(image.DateCreated(), gc.Equals, int64(2)) 717 } 718 719 func (s *MigrationExportSuite) TestActions(c *gc.C) { 720 machine := s.Factory.MakeMachine(c, &factory.MachineParams{ 721 Constraints: constraints.MustParse("arch=amd64 mem=8G"), 722 }) 723 _, err := s.State.EnqueueAction(machine.MachineTag(), "foo", nil) 724 c.Assert(err, jc.ErrorIsNil) 725 726 model, err := s.State.Export() 727 c.Assert(err, jc.ErrorIsNil) 728 729 actions := model.Actions() 730 c.Assert(actions, gc.HasLen, 1) 731 action := actions[0] 732 c.Check(action.Receiver(), gc.Equals, machine.Id()) 733 c.Check(action.Name(), gc.Equals, "foo") 734 c.Check(action.Status(), gc.Equals, "pending") 735 c.Check(action.Message(), gc.Equals, "") 736 } 737 738 type goodToken struct{} 739 740 // Check implements leadership.Token 741 func (*goodToken) Check(interface{}) error { 742 return nil 743 } 744 745 func (s *MigrationExportSuite) TestVolumes(c *gc.C) { 746 machine := s.Factory.MakeMachine(c, &factory.MachineParams{ 747 Volumes: []state.MachineVolumeParams{{ 748 Volume: state.VolumeParams{Size: 1234}, 749 Attachment: state.VolumeAttachmentParams{ReadOnly: true}, 750 }, { 751 Volume: state.VolumeParams{Size: 4000}, 752 }}, 753 }) 754 machineTag := machine.MachineTag() 755 756 // We know that the first volume is called "0/0" as it is the first volume 757 // (volumes use sequences), and it is bound to machine 0. 758 volTag := names.NewVolumeTag("0/0") 759 err := s.State.SetVolumeInfo(volTag, state.VolumeInfo{ 760 HardwareId: "magic", 761 Size: 1500, 762 VolumeId: "volume id", 763 Persistent: true, 764 }) 765 c.Assert(err, jc.ErrorIsNil) 766 err = s.State.SetVolumeAttachmentInfo(machineTag, volTag, state.VolumeAttachmentInfo{ 767 DeviceName: "device name", 768 DeviceLink: "device link", 769 BusAddress: "bus address", 770 ReadOnly: true, 771 }) 772 c.Assert(err, jc.ErrorIsNil) 773 774 model, err := s.State.Export() 775 c.Assert(err, jc.ErrorIsNil) 776 777 volumes := model.Volumes() 778 c.Assert(volumes, gc.HasLen, 2) 779 provisioned, notProvisioned := volumes[0], volumes[1] 780 781 c.Check(provisioned.Tag(), gc.Equals, volTag) 782 binding, err := provisioned.Binding() 783 c.Check(err, jc.ErrorIsNil) 784 c.Check(binding, gc.Equals, machineTag) 785 c.Check(provisioned.Provisioned(), jc.IsTrue) 786 c.Check(provisioned.Size(), gc.Equals, uint64(1500)) 787 c.Check(provisioned.Pool(), gc.Equals, "loop") 788 c.Check(provisioned.HardwareID(), gc.Equals, "magic") 789 c.Check(provisioned.VolumeID(), gc.Equals, "volume id") 790 c.Check(provisioned.Persistent(), jc.IsTrue) 791 attachments := provisioned.Attachments() 792 c.Assert(attachments, gc.HasLen, 1) 793 attachment := attachments[0] 794 c.Check(attachment.Machine(), gc.Equals, machineTag) 795 c.Check(attachment.Provisioned(), jc.IsTrue) 796 c.Check(attachment.ReadOnly(), jc.IsTrue) 797 c.Check(attachment.DeviceName(), gc.Equals, "device name") 798 c.Check(attachment.DeviceLink(), gc.Equals, "device link") 799 c.Check(attachment.BusAddress(), gc.Equals, "bus address") 800 801 c.Check(notProvisioned.Tag(), gc.Equals, names.NewVolumeTag("0/1")) 802 binding, err = notProvisioned.Binding() 803 c.Check(err, jc.ErrorIsNil) 804 c.Check(binding, gc.Equals, machineTag) 805 c.Check(notProvisioned.Provisioned(), jc.IsFalse) 806 c.Check(notProvisioned.Size(), gc.Equals, uint64(4000)) 807 c.Check(notProvisioned.Pool(), gc.Equals, "loop") 808 c.Check(notProvisioned.HardwareID(), gc.Equals, "") 809 c.Check(notProvisioned.VolumeID(), gc.Equals, "") 810 c.Check(notProvisioned.Persistent(), jc.IsFalse) 811 attachments = notProvisioned.Attachments() 812 c.Assert(attachments, gc.HasLen, 1) 813 attachment = attachments[0] 814 c.Check(attachment.Machine(), gc.Equals, machineTag) 815 c.Check(attachment.Provisioned(), jc.IsFalse) 816 c.Check(attachment.ReadOnly(), jc.IsFalse) 817 c.Check(attachment.DeviceName(), gc.Equals, "") 818 c.Check(attachment.DeviceLink(), gc.Equals, "") 819 c.Check(attachment.BusAddress(), gc.Equals, "") 820 821 // Make sure there is a status. 822 status := provisioned.Status() 823 c.Check(status.Value(), gc.Equals, "pending") 824 } 825 826 func (s *MigrationExportSuite) TestFilesystems(c *gc.C) { 827 machine := s.Factory.MakeMachine(c, &factory.MachineParams{ 828 Filesystems: []state.MachineFilesystemParams{{ 829 Filesystem: state.FilesystemParams{Size: 1234}, 830 Attachment: state.FilesystemAttachmentParams{ 831 Location: "location", 832 ReadOnly: true}, 833 }, { 834 Filesystem: state.FilesystemParams{Size: 4000}, 835 }}, 836 }) 837 machineTag := machine.MachineTag() 838 839 // We know that the first filesystem is called "0/0" as it is the first 840 // filesystem (filesystems use sequences), and it is bound to machine 0. 841 fsTag := names.NewFilesystemTag("0/0") 842 err := s.State.SetFilesystemInfo(fsTag, state.FilesystemInfo{ 843 Size: 1500, 844 FilesystemId: "filesystem id", 845 }) 846 c.Assert(err, jc.ErrorIsNil) 847 err = s.State.SetFilesystemAttachmentInfo(machineTag, fsTag, state.FilesystemAttachmentInfo{ 848 MountPoint: "/mnt/foo", 849 ReadOnly: true, 850 }) 851 c.Assert(err, jc.ErrorIsNil) 852 853 model, err := s.State.Export() 854 c.Assert(err, jc.ErrorIsNil) 855 856 filesystems := model.Filesystems() 857 c.Assert(filesystems, gc.HasLen, 2) 858 provisioned, notProvisioned := filesystems[0], filesystems[1] 859 860 c.Check(provisioned.Tag(), gc.Equals, fsTag) 861 c.Check(provisioned.Volume(), gc.Equals, names.VolumeTag{}) 862 c.Check(provisioned.Storage(), gc.Equals, names.StorageTag{}) 863 binding, err := provisioned.Binding() 864 c.Check(err, jc.ErrorIsNil) 865 c.Check(binding, gc.Equals, machineTag) 866 c.Check(provisioned.Provisioned(), jc.IsTrue) 867 c.Check(provisioned.Size(), gc.Equals, uint64(1500)) 868 c.Check(provisioned.Pool(), gc.Equals, "rootfs") 869 c.Check(provisioned.FilesystemID(), gc.Equals, "filesystem id") 870 attachments := provisioned.Attachments() 871 c.Assert(attachments, gc.HasLen, 1) 872 attachment := attachments[0] 873 c.Check(attachment.Machine(), gc.Equals, machineTag) 874 c.Check(attachment.Provisioned(), jc.IsTrue) 875 c.Check(attachment.ReadOnly(), jc.IsTrue) 876 c.Check(attachment.MountPoint(), gc.Equals, "/mnt/foo") 877 878 c.Check(notProvisioned.Tag(), gc.Equals, names.NewFilesystemTag("0/1")) 879 c.Check(notProvisioned.Volume(), gc.Equals, names.VolumeTag{}) 880 c.Check(notProvisioned.Storage(), gc.Equals, names.StorageTag{}) 881 binding, err = notProvisioned.Binding() 882 c.Check(err, jc.ErrorIsNil) 883 c.Check(binding, gc.Equals, machineTag) 884 c.Check(notProvisioned.Provisioned(), jc.IsFalse) 885 c.Check(notProvisioned.Size(), gc.Equals, uint64(4000)) 886 c.Check(notProvisioned.Pool(), gc.Equals, "rootfs") 887 c.Check(notProvisioned.FilesystemID(), gc.Equals, "") 888 attachments = notProvisioned.Attachments() 889 c.Assert(attachments, gc.HasLen, 1) 890 attachment = attachments[0] 891 c.Check(attachment.Machine(), gc.Equals, machineTag) 892 c.Check(attachment.Provisioned(), jc.IsFalse) 893 c.Check(attachment.ReadOnly(), jc.IsFalse) 894 c.Check(attachment.MountPoint(), gc.Equals, "") 895 896 // Make sure there is a status. 897 status := provisioned.Status() 898 c.Check(status.Value(), gc.Equals, "pending") 899 } 900 901 func (s *MigrationExportSuite) TestStorage(c *gc.C) { 902 _, u, storageTag := s.makeUnitWithStorage(c) 903 904 model, err := s.State.Export() 905 c.Assert(err, jc.ErrorIsNil) 906 907 apps := model.Applications() 908 c.Assert(apps, gc.HasLen, 1) 909 constraints := apps[0].StorageConstraints() 910 c.Assert(constraints, gc.HasLen, 2) 911 cons, found := constraints["data"] 912 c.Assert(found, jc.IsTrue) 913 c.Check(cons.Pool(), gc.Equals, "loop-pool") 914 c.Check(cons.Size(), gc.Equals, uint64(0x400)) 915 c.Check(cons.Count(), gc.Equals, uint64(1)) 916 cons, found = constraints["allecto"] 917 c.Assert(found, jc.IsTrue) 918 c.Check(cons.Pool(), gc.Equals, "loop") 919 c.Check(cons.Size(), gc.Equals, uint64(0x400)) 920 c.Check(cons.Count(), gc.Equals, uint64(0)) 921 922 storages := model.Storages() 923 c.Assert(storages, gc.HasLen, 1) 924 925 storage := storages[0] 926 927 c.Check(storage.Tag(), gc.Equals, storageTag) 928 c.Check(storage.Kind(), gc.Equals, "block") 929 owner, err := storage.Owner() 930 c.Check(err, jc.ErrorIsNil) 931 c.Check(owner, gc.Equals, u.Tag()) 932 c.Check(storage.Name(), gc.Equals, "data") 933 c.Check(storage.Attachments(), jc.DeepEquals, []names.UnitTag{ 934 u.UnitTag(), 935 }) 936 } 937 938 func (s *MigrationExportSuite) 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 model, err := s.State.Export() 946 c.Assert(err, jc.ErrorIsNil) 947 948 pools := model.StoragePools() 949 c.Assert(pools, gc.HasLen, 1) 950 pool := pools[0] 951 c.Assert(pool.Name(), gc.Equals, "test-pool") 952 c.Assert(pool.Provider(), gc.Equals, "loop") 953 c.Assert(pool.Attributes(), jc.DeepEquals, map[string]interface{}{ 954 "value": 42, 955 }) 956 } 957 958 func (s *MigrationExportSuite) TestPayloads(c *gc.C) { 959 unit := s.Factory.MakeUnit(c, nil) 960 up, err := s.State.UnitPayloads(unit) 961 c.Assert(err, jc.ErrorIsNil) 962 original := payload.Payload{ 963 PayloadClass: charm.PayloadClass{ 964 Name: "something", 965 Type: "special", 966 }, 967 ID: "42", 968 Status: "running", 969 Labels: []string{"foo", "bar"}, 970 } 971 err = up.Track(original) 972 c.Assert(err, jc.ErrorIsNil) 973 974 model, err := s.State.Export() 975 c.Assert(err, jc.ErrorIsNil) 976 977 applications := model.Applications() 978 c.Assert(applications, gc.HasLen, 1) 979 980 units := applications[0].Units() 981 c.Assert(units, gc.HasLen, 1) 982 983 payloads := units[0].Payloads() 984 c.Assert(payloads, gc.HasLen, 1) 985 986 payload := payloads[0] 987 c.Check(payload.Name(), gc.Equals, original.Name) 988 c.Check(payload.Type(), gc.Equals, original.Type) 989 c.Check(payload.RawID(), gc.Equals, original.ID) 990 c.Check(payload.State(), gc.Equals, original.Status) 991 c.Check(payload.Labels(), jc.DeepEquals, original.Labels) 992 }