github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/migration_import.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 "github.com/juju/loggo" 11 "github.com/juju/version" 12 "gopkg.in/juju/charm.v6-unstable" 13 "gopkg.in/juju/names.v2" 14 "gopkg.in/mgo.v2/bson" 15 "gopkg.in/mgo.v2/txn" 16 17 "github.com/juju/juju/constraints" 18 "github.com/juju/juju/core/description" 19 "github.com/juju/juju/environs/config" 20 "github.com/juju/juju/instance" 21 "github.com/juju/juju/network" 22 "github.com/juju/juju/payload" 23 "github.com/juju/juju/permission" 24 "github.com/juju/juju/state/cloudimagemetadata" 25 "github.com/juju/juju/status" 26 "github.com/juju/juju/storage" 27 "github.com/juju/juju/storage/poolmanager" 28 "github.com/juju/juju/tools" 29 ) 30 31 // When we import a new model, we need to give the leaders some time to 32 // settle. We don't want to have leader switches just because we migrated an 33 // environment, so this time needs to be long enough to make sure we cover 34 // the time taken to migration a reasonable sized environment. We don't yet 35 // know how long this is going to be, but we need something. 36 var initialLeaderClaimTime = time.Minute 37 38 // Import the database agnostic model representation into the database. 39 func (st *State) Import(model description.Model) (_ *Model, _ *State, err error) { 40 logger := loggo.GetLogger("juju.state.import-model") 41 logger.Debugf("import starting for model %s", model.Tag().Id()) 42 // At this stage, attempting to import a model with the same 43 // UUID as an existing model will error. 44 tag := model.Tag() 45 _, err = st.GetModel(tag) 46 if err == nil { 47 // We have an existing matching model. 48 return nil, nil, errors.AlreadyExistsf("model with UUID %s", tag.Id()) 49 } else if !errors.IsNotFound(err) { 50 return nil, nil, errors.Trace(err) 51 } 52 53 // Create the model. 54 cfg, err := config.New(config.NoDefaults, model.Config()) 55 if err != nil { 56 return nil, nil, errors.Trace(err) 57 } 58 dbModel, newSt, err := st.NewModel(ModelArgs{ 59 CloudName: model.Cloud(), 60 CloudRegion: model.CloudRegion(), 61 Config: cfg, 62 Owner: model.Owner(), 63 MigrationMode: MigrationModeImporting, 64 65 // NOTE(axw) we create the model without any storage 66 // pools. We'll need to import the storage pools from 67 // the model description before adding any volumes, 68 // filesystems or storage instances. 69 StorageProviderRegistry: storage.StaticProviderRegistry{}, 70 }) 71 if err != nil { 72 return nil, nil, errors.Trace(err) 73 } 74 logger.Debugf("model created %s/%s", dbModel.Owner().Canonical(), dbModel.Name()) 75 defer func() { 76 if err != nil { 77 newSt.Close() 78 } 79 }() 80 81 // I would have loved to use import, but that is a reserved word. 82 restore := importer{ 83 st: newSt, 84 dbModel: dbModel, 85 model: model, 86 logger: logger, 87 } 88 if err := restore.sequences(); err != nil { 89 return nil, nil, errors.Annotate(err, "sequences") 90 } 91 // We need to import the sequences first as we may add blocks 92 // in the modelExtras which will touch the block sequence. 93 if err := restore.modelExtras(); err != nil { 94 return nil, nil, errors.Annotate(err, "base model aspects") 95 } 96 if err := newSt.SetModelConstraints(restore.constraints(model.Constraints())); err != nil { 97 return nil, nil, errors.Annotate(err, "model constraints") 98 } 99 if err := restore.sshHostKeys(); err != nil { 100 return nil, nil, errors.Annotate(err, "sshHostKeys") 101 } 102 if err := restore.cloudimagemetadata(); err != nil { 103 return nil, nil, errors.Annotate(err, "cloudimagemetadata") 104 } 105 if err := restore.actions(); err != nil { 106 return nil, nil, errors.Annotate(err, "actions") 107 } 108 109 if err := restore.modelUsers(); err != nil { 110 return nil, nil, errors.Annotate(err, "modelUsers") 111 } 112 if err := restore.machines(); err != nil { 113 return nil, nil, errors.Annotate(err, "machines") 114 } 115 if err := restore.applications(); err != nil { 116 return nil, nil, errors.Annotate(err, "applications") 117 } 118 if err := restore.relations(); err != nil { 119 return nil, nil, errors.Annotate(err, "relations") 120 } 121 if err := restore.spaces(); err != nil { 122 return nil, nil, errors.Annotate(err, "spaces") 123 } 124 if err := restore.linklayerdevices(); err != nil { 125 return nil, nil, errors.Annotate(err, "linklayerdevices") 126 } 127 if err := restore.subnets(); err != nil { 128 return nil, nil, errors.Annotate(err, "subnets") 129 } 130 if err := restore.ipaddresses(); err != nil { 131 return nil, nil, errors.Annotate(err, "ipaddresses") 132 } 133 134 if err := restore.storage(); err != nil { 135 return nil, nil, errors.Annotate(err, "storage") 136 } 137 138 // NOTE: at the end of the import make sure that the mode of the model 139 // is set to "imported" not "active" (or whatever we call it). This way 140 // we don't start model workers for it before the migration process 141 // is complete. 142 143 // Update the sequences to match that the source. 144 145 logger.Debugf("import success") 146 return dbModel, newSt, nil 147 } 148 149 type importer struct { 150 st *State 151 dbModel *Model 152 model description.Model 153 logger loggo.Logger 154 // applicationUnits is populated at the end of loading the applications, and is a 155 // map of application name to units of that application. 156 applicationUnits map[string][]*Unit 157 } 158 159 func (i *importer) modelExtras() error { 160 if latest := i.model.LatestToolsVersion(); latest != version.Zero { 161 if err := i.dbModel.UpdateLatestToolsVersion(latest); err != nil { 162 return errors.Trace(err) 163 } 164 } 165 166 if annotations := i.model.Annotations(); len(annotations) > 0 { 167 if err := i.st.SetAnnotations(i.dbModel, annotations); err != nil { 168 return errors.Trace(err) 169 } 170 } 171 172 blockType := map[string]BlockType{ 173 "destroy-model": DestroyBlock, 174 "remove-object": RemoveBlock, 175 "all-changes": ChangeBlock, 176 } 177 178 for blockName, message := range i.model.Blocks() { 179 block, ok := blockType[blockName] 180 if !ok { 181 return errors.Errorf("unknown block type: %q", blockName) 182 } 183 i.st.SwitchBlockOn(block, message) 184 } 185 return nil 186 } 187 188 func (i *importer) sequences() error { 189 sequenceValues := i.model.Sequences() 190 docs := make([]interface{}, 0, len(sequenceValues)) 191 for key, value := range sequenceValues { 192 docs = append(docs, sequenceDoc{ 193 DocID: key, 194 Name: key, 195 Counter: value, 196 }) 197 } 198 199 // In reality, we will almost always have sequences to migrate. 200 // However, in tests, sometimes we don't. 201 if len(docs) == 0 { 202 return nil 203 } 204 205 sequences, closer := i.st.getCollection(sequenceC) 206 defer closer() 207 208 if err := sequences.Writeable().Insert(docs...); err != nil { 209 return errors.Trace(err) 210 } 211 return nil 212 } 213 214 func (i *importer) modelUsers() error { 215 i.logger.Debugf("importing users") 216 217 // The user that was auto-added when we created the model will have 218 // the wrong DateCreated, so we remove it, and add in all the users we 219 // know about. It is also possible that the owner of the model no 220 // longer has access to the model due to changes over time. 221 if err := i.st.RemoveUserAccess(i.dbModel.Owner(), i.dbModel.ModelTag()); err != nil { 222 return errors.Trace(err) 223 } 224 225 users := i.model.Users() 226 modelUUID := i.dbModel.UUID() 227 var ops []txn.Op 228 for _, user := range users { 229 ops = append(ops, createModelUserOps( 230 modelUUID, 231 user.Name(), 232 user.CreatedBy(), 233 user.DisplayName(), 234 user.DateCreated(), 235 permission.Access(user.Access()))..., 236 ) 237 } 238 if err := i.st.runTransaction(ops); err != nil { 239 return errors.Trace(err) 240 } 241 // Now set their last connection times. 242 for _, user := range users { 243 i.logger.Debugf("user %s", user.Name()) 244 lastConnection := user.LastConnection() 245 if lastConnection.IsZero() { 246 continue 247 } 248 err := i.st.updateLastModelConnection(user.Name(), lastConnection) 249 if err != nil { 250 return errors.Trace(err) 251 } 252 } 253 return nil 254 } 255 256 func (i *importer) machines() error { 257 i.logger.Debugf("importing machines") 258 for _, m := range i.model.Machines() { 259 if err := i.machine(m); err != nil { 260 i.logger.Errorf("error importing machine: %s", err) 261 return errors.Annotate(err, m.Id()) 262 } 263 } 264 265 i.logger.Debugf("importing machines succeeded") 266 return nil 267 } 268 269 func (i *importer) machine(m description.Machine) error { 270 // Import this machine, then import its containers. 271 i.logger.Debugf("importing machine %s", m.Id()) 272 273 // 1. construct a machineDoc 274 mdoc, err := i.makeMachineDoc(m) 275 if err != nil { 276 return errors.Annotatef(err, "machine %s", m.Id()) 277 } 278 // 2. construct enough MachineTemplate to pass into 'insertNewMachineOps' 279 // - adds constraints doc 280 // - adds status doc 281 // - adds machine block devices doc 282 283 mStatus := m.Status() 284 if mStatus == nil { 285 return errors.NotValidf("missing status") 286 } 287 machineStatusDoc := statusDoc{ 288 ModelUUID: i.st.ModelUUID(), 289 Status: status.Status(mStatus.Value()), 290 StatusInfo: mStatus.Message(), 291 StatusData: mStatus.Data(), 292 Updated: mStatus.Updated().UnixNano(), 293 } 294 // XXX(mjs) - this needs to be included in the serialized model 295 // (a card exists for the work). Fake it for now. 296 instanceStatusDoc := statusDoc{ 297 ModelUUID: i.st.ModelUUID(), 298 Status: status.Started, 299 } 300 cons := i.constraints(m.Constraints()) 301 prereqOps, machineOp := i.st.baseNewMachineOps( 302 mdoc, 303 machineStatusDoc, 304 instanceStatusDoc, 305 cons, 306 ) 307 308 // 3. create op for adding in instance data 309 if instance := m.Instance(); instance != nil { 310 prereqOps = append(prereqOps, i.machineInstanceOp(mdoc, instance)) 311 } 312 313 if parentId := ParentId(mdoc.Id); parentId != "" { 314 prereqOps = append(prereqOps, 315 // Update containers record for host machine. 316 i.st.addChildToContainerRefOp(parentId, mdoc.Id), 317 ) 318 } 319 // insertNewContainerRefOp adds an empty doc into the containerRefsC 320 // collection for the machine being added. 321 prereqOps = append(prereqOps, i.st.insertNewContainerRefOp(mdoc.Id)) 322 323 // 4. gather prereqs and machine op, run ops. 324 ops := append(prereqOps, machineOp) 325 326 // 5. add any ops that we may need to add the opened ports information. 327 ops = append(ops, i.machinePortsOps(m)...) 328 329 if err := i.st.runTransaction(ops); err != nil { 330 return errors.Trace(err) 331 } 332 333 machine := newMachine(i.st, mdoc) 334 if annotations := m.Annotations(); len(annotations) > 0 { 335 if err := i.st.SetAnnotations(machine, annotations); err != nil { 336 return errors.Trace(err) 337 } 338 } 339 if err := i.importStatusHistory(machine.globalKey(), m.StatusHistory()); err != nil { 340 return errors.Trace(err) 341 } 342 if err := i.importMachineBlockDevices(machine, m); err != nil { 343 return errors.Trace(err) 344 } 345 346 // Now that this machine exists in the database, process each of the 347 // containers in this machine. 348 for _, container := range m.Containers() { 349 if err := i.machine(container); err != nil { 350 return errors.Annotate(err, container.Id()) 351 } 352 } 353 return nil 354 } 355 356 func (i *importer) importMachineBlockDevices(machine *Machine, m description.Machine) error { 357 var devices []BlockDeviceInfo 358 for _, device := range m.BlockDevices() { 359 devices = append(devices, BlockDeviceInfo{ 360 DeviceName: device.Name(), 361 DeviceLinks: device.Links(), 362 Label: device.Label(), 363 UUID: device.UUID(), 364 HardwareId: device.HardwareID(), 365 BusAddress: device.BusAddress(), 366 Size: device.Size(), 367 FilesystemType: device.FilesystemType(), 368 InUse: device.InUse(), 369 MountPoint: device.MountPoint(), 370 }) 371 } 372 373 if err := machine.SetMachineBlockDevices(devices...); err != nil { 374 return errors.Trace(err) 375 } 376 return nil 377 } 378 379 func (i *importer) machinePortsOps(m description.Machine) []txn.Op { 380 var result []txn.Op 381 machineID := m.Id() 382 383 for _, ports := range m.OpenedPorts() { 384 subnetID := ports.SubnetID() 385 doc := &portsDoc{ 386 MachineID: machineID, 387 SubnetID: subnetID, 388 } 389 for _, opened := range ports.OpenPorts() { 390 doc.Ports = append(doc.Ports, PortRange{ 391 UnitName: opened.UnitName(), 392 FromPort: opened.FromPort(), 393 ToPort: opened.ToPort(), 394 Protocol: opened.Protocol(), 395 }) 396 } 397 result = append(result, txn.Op{ 398 C: openedPortsC, 399 Id: portsGlobalKey(machineID, subnetID), 400 Assert: txn.DocMissing, 401 Insert: doc, 402 }) 403 } 404 405 return result 406 } 407 408 func (i *importer) machineInstanceOp(mdoc *machineDoc, inst description.CloudInstance) txn.Op { 409 doc := &instanceData{ 410 DocID: mdoc.DocID, 411 MachineId: mdoc.Id, 412 InstanceId: instance.Id(inst.InstanceId()), 413 ModelUUID: mdoc.ModelUUID, 414 } 415 416 if arch := inst.Architecture(); arch != "" { 417 doc.Arch = &arch 418 } 419 if mem := inst.Memory(); mem != 0 { 420 doc.Mem = &mem 421 } 422 if rootDisk := inst.RootDisk(); rootDisk != 0 { 423 doc.RootDisk = &rootDisk 424 } 425 if cores := inst.CpuCores(); cores != 0 { 426 doc.CpuCores = &cores 427 } 428 if power := inst.CpuPower(); power != 0 { 429 doc.CpuPower = &power 430 } 431 if tags := inst.Tags(); len(tags) > 0 { 432 doc.Tags = &tags 433 } 434 if az := inst.AvailabilityZone(); az != "" { 435 doc.AvailZone = &az 436 } 437 438 return txn.Op{ 439 C: instanceDataC, 440 Id: mdoc.DocID, 441 Assert: txn.DocMissing, 442 Insert: doc, 443 } 444 } 445 446 func (i *importer) makeMachineDoc(m description.Machine) (*machineDoc, error) { 447 id := m.Id() 448 supported, supportedSet := m.SupportedContainers() 449 supportedContainers := make([]instance.ContainerType, len(supported)) 450 for j, c := range supported { 451 supportedContainers[j] = instance.ContainerType(c) 452 } 453 jobs, err := i.makeMachineJobs(m.Jobs()) 454 if err != nil { 455 return nil, errors.Trace(err) 456 } 457 machineTag := m.Tag() 458 return &machineDoc{ 459 DocID: i.st.docID(id), 460 Id: id, 461 ModelUUID: i.st.ModelUUID(), 462 Nonce: m.Nonce(), 463 Series: m.Series(), 464 ContainerType: m.ContainerType(), 465 Principals: nil, // Set during unit import. 466 Life: Alive, 467 Tools: i.makeTools(m.Tools()), 468 Jobs: jobs, 469 NoVote: true, // State servers can't be migrated yet. 470 HasVote: false, // State servers can't be migrated yet. 471 PasswordHash: m.PasswordHash(), 472 Clean: !i.machineHasUnits(machineTag), 473 Volumes: i.machineVolumes(machineTag), 474 Filesystems: i.machineFilesystems(machineTag), 475 Addresses: i.makeAddresses(m.ProviderAddresses()), 476 MachineAddresses: i.makeAddresses(m.MachineAddresses()), 477 PreferredPrivateAddress: i.makeAddress(m.PreferredPrivateAddress()), 478 PreferredPublicAddress: i.makeAddress(m.PreferredPublicAddress()), 479 SupportedContainersKnown: supportedSet, 480 SupportedContainers: supportedContainers, 481 Placement: m.Placement(), 482 }, nil 483 } 484 485 func (i *importer) machineHasUnits(tag names.MachineTag) bool { 486 for _, app := range i.model.Applications() { 487 for _, unit := range app.Units() { 488 if unit.Machine() == tag { 489 return true 490 } 491 } 492 } 493 return false 494 } 495 496 func (i *importer) machineVolumes(tag names.MachineTag) []string { 497 var result []string 498 for _, volume := range i.model.Volumes() { 499 for _, attachment := range volume.Attachments() { 500 if attachment.Machine() == tag { 501 result = append(result, volume.Tag().Id()) 502 } 503 } 504 } 505 return result 506 } 507 508 func (i *importer) machineFilesystems(tag names.MachineTag) []string { 509 var result []string 510 for _, filesystem := range i.model.Filesystems() { 511 for _, attachment := range filesystem.Attachments() { 512 if attachment.Machine() == tag { 513 result = append(result, filesystem.Tag().Id()) 514 } 515 } 516 } 517 return result 518 } 519 520 func (i *importer) makeMachineJobs(jobs []string) ([]MachineJob, error) { 521 // At time of writing, there are three valid jobs. If any jobs gets 522 // deprecated or changed in the future, older models that specify those 523 // jobs need to be handled here. 524 result := make([]MachineJob, 0, len(jobs)) 525 for _, job := range jobs { 526 switch job { 527 case "host-units": 528 result = append(result, JobHostUnits) 529 case "api-server": 530 result = append(result, JobManageModel) 531 default: 532 return nil, errors.Errorf("unknown machine job: %q", job) 533 } 534 } 535 return result, nil 536 } 537 538 func (i *importer) makeTools(t description.AgentTools) *tools.Tools { 539 if t == nil { 540 return nil 541 } 542 return &tools.Tools{ 543 Version: t.Version(), 544 URL: t.URL(), 545 SHA256: t.SHA256(), 546 Size: t.Size(), 547 } 548 } 549 550 func (i *importer) makeAddress(addr description.Address) address { 551 if addr == nil { 552 return address{} 553 } 554 return address{ 555 Value: addr.Value(), 556 AddressType: addr.Type(), 557 Scope: addr.Scope(), 558 Origin: addr.Origin(), 559 } 560 } 561 562 func (i *importer) makeAddresses(addrs []description.Address) []address { 563 result := make([]address, len(addrs)) 564 for j, addr := range addrs { 565 result[j] = i.makeAddress(addr) 566 } 567 return result 568 } 569 570 func (i *importer) applications() error { 571 i.logger.Debugf("importing applications") 572 for _, s := range i.model.Applications() { 573 if err := i.application(s); err != nil { 574 i.logger.Errorf("error importing application %s: %s", s.Name(), err) 575 return errors.Annotate(err, s.Name()) 576 } 577 } 578 579 if err := i.loadUnits(); err != nil { 580 return errors.Annotate(err, "loading new units from db") 581 } 582 i.logger.Debugf("importing applications succeeded") 583 return nil 584 } 585 586 func (i *importer) loadUnits() error { 587 unitsCollection, closer := i.st.getCollection(unitsC) 588 defer closer() 589 590 docs := []unitDoc{} 591 err := unitsCollection.Find(nil).All(&docs) 592 if err != nil { 593 return errors.Annotate(err, "cannot get all units") 594 } 595 596 result := make(map[string][]*Unit) 597 for _, doc := range docs { 598 units := result[doc.Application] 599 result[doc.Application] = append(units, newUnit(i.st, &doc)) 600 } 601 i.applicationUnits = result 602 return nil 603 604 } 605 606 // makeStatusDoc assumes status is non-nil. 607 func (i *importer) makeStatusDoc(statusVal description.Status) statusDoc { 608 return statusDoc{ 609 Status: status.Status(statusVal.Value()), 610 StatusInfo: statusVal.Message(), 611 StatusData: statusVal.Data(), 612 Updated: statusVal.Updated().UnixNano(), 613 } 614 } 615 616 func (i *importer) application(s description.Application) error { 617 // Import this application, then its units. 618 i.logger.Debugf("importing application %s", s.Name()) 619 620 // 1. construct an applicationDoc 621 sdoc, err := i.makeApplicationDoc(s) 622 if err != nil { 623 return errors.Trace(err) 624 } 625 626 // 2. construct a statusDoc 627 status := s.Status() 628 if status == nil { 629 return errors.NotValidf("missing status") 630 } 631 statusDoc := i.makeStatusDoc(status) 632 // TODO: update never set malarky... maybe... 633 634 ops, err := addApplicationOps(i.st, addApplicationOpsArgs{ 635 applicationDoc: sdoc, 636 statusDoc: statusDoc, 637 constraints: i.constraints(s.Constraints()), 638 storage: i.storageConstraints(s.StorageConstraints()), 639 settings: s.Settings(), 640 leadershipSettings: s.LeadershipSettings(), 641 }) 642 if err != nil { 643 return errors.Trace(err) 644 } 645 646 if err := i.st.runTransaction(ops); err != nil { 647 return errors.Trace(err) 648 } 649 650 svc := newApplication(i.st, sdoc) 651 if annotations := s.Annotations(); len(annotations) > 0 { 652 if err := i.st.SetAnnotations(svc, annotations); err != nil { 653 return errors.Trace(err) 654 } 655 } 656 if err := i.importStatusHistory(svc.globalKey(), s.StatusHistory()); err != nil { 657 return errors.Trace(err) 658 } 659 660 for _, unit := range s.Units() { 661 if err := i.unit(s, unit); err != nil { 662 return errors.Trace(err) 663 } 664 } 665 666 if s.Leader() != "" { 667 if err := i.st.LeadershipClaimer().ClaimLeadership( 668 s.Name(), 669 s.Leader(), 670 initialLeaderClaimTime); err != nil { 671 return errors.Trace(err) 672 } 673 } 674 675 return nil 676 } 677 678 func (i *importer) storageConstraints(cons map[string]description.StorageConstraint) map[string]StorageConstraints { 679 if len(cons) == 0 { 680 return nil 681 } 682 result := make(map[string]StorageConstraints) 683 for key, value := range cons { 684 result[key] = StorageConstraints{ 685 Pool: value.Pool(), 686 Size: value.Size(), 687 Count: value.Count(), 688 } 689 } 690 return result 691 } 692 693 func (i *importer) unit(s description.Application, u description.Unit) error { 694 i.logger.Debugf("importing unit %s", u.Name()) 695 696 // 1. construct a unitDoc 697 udoc, err := i.makeUnitDoc(s, u) 698 if err != nil { 699 return errors.Trace(err) 700 } 701 702 // 2. construct a statusDoc for the workload status and agent status 703 agentStatus := u.AgentStatus() 704 if agentStatus == nil { 705 return errors.NotValidf("missing agent status") 706 } 707 agentStatusDoc := i.makeStatusDoc(agentStatus) 708 709 workloadStatus := u.WorkloadStatus() 710 if workloadStatus == nil { 711 return errors.NotValidf("missing workload status") 712 } 713 workloadStatusDoc := i.makeStatusDoc(workloadStatus) 714 715 workloadVersion := u.WorkloadVersion() 716 versionStatus := status.Active 717 if workloadVersion == "" { 718 versionStatus = status.Unknown 719 } 720 workloadVersionDoc := statusDoc{ 721 Status: versionStatus, 722 StatusInfo: workloadVersion, 723 } 724 725 ops, err := addUnitOps(i.st, addUnitOpsArgs{ 726 unitDoc: udoc, 727 agentStatusDoc: agentStatusDoc, 728 workloadStatusDoc: workloadStatusDoc, 729 workloadVersionDoc: workloadVersionDoc, 730 meterStatusDoc: &meterStatusDoc{ 731 Code: u.MeterStatusCode(), 732 Info: u.MeterStatusInfo(), 733 }, 734 }) 735 if err != nil { 736 return errors.Trace(err) 737 } 738 739 // If the unit is a principal, add it to its machine. 740 if u.Principal().Id() == "" { 741 ops = append(ops, txn.Op{ 742 C: machinesC, 743 Id: u.Machine().Id(), 744 Assert: txn.DocExists, 745 Update: bson.M{"$addToSet": bson.M{"principals": u.Name()}}, 746 }) 747 } 748 749 // We should only have constraints for principal agents. 750 // We don't encode that business logic here, if there are constraints 751 // in the imported model, we put them in the database. 752 if cons := u.Constraints(); cons != nil { 753 agentGlobalKey := unitAgentGlobalKey(u.Name()) 754 ops = append(ops, createConstraintsOp(i.st, agentGlobalKey, i.constraints(cons))) 755 } 756 757 if err := i.st.runTransaction(ops); err != nil { 758 i.logger.Debugf("failed ops: %#v", ops) 759 return errors.Trace(err) 760 } 761 762 unit := newUnit(i.st, udoc) 763 if annotations := u.Annotations(); len(annotations) > 0 { 764 if err := i.st.SetAnnotations(unit, annotations); err != nil { 765 return errors.Trace(err) 766 } 767 } 768 if err := i.importStatusHistory(unit.globalKey(), u.WorkloadStatusHistory()); err != nil { 769 return errors.Trace(err) 770 } 771 if err := i.importStatusHistory(unit.globalAgentKey(), u.AgentStatusHistory()); err != nil { 772 return errors.Trace(err) 773 } 774 if err := i.importStatusHistory(unit.globalWorkloadVersionKey(), u.WorkloadVersionHistory()); err != nil { 775 return errors.Trace(err) 776 } 777 if err := i.importUnitPayloads(unit, u.Payloads()); err != nil { 778 return errors.Trace(err) 779 } 780 781 return nil 782 } 783 784 func (i *importer) importUnitPayloads(unit *Unit, payloads []description.Payload) error { 785 up, err := i.st.UnitPayloads(unit) 786 if err != nil { 787 return errors.Trace(err) 788 } 789 790 for _, p := range payloads { 791 if err := up.Track(payload.Payload{ 792 PayloadClass: charm.PayloadClass{ 793 Name: p.Name(), 794 Type: p.Type(), 795 }, 796 ID: p.RawID(), 797 Status: p.State(), 798 Labels: p.Labels(), 799 }); err != nil { 800 return errors.Trace(err) 801 } 802 } 803 804 return nil 805 } 806 807 func (i *importer) makeApplicationDoc(s description.Application) (*applicationDoc, error) { 808 charmURL, err := charm.ParseURL(s.CharmURL()) 809 if err != nil { 810 return nil, errors.Trace(err) 811 } 812 813 return &applicationDoc{ 814 Name: s.Name(), 815 Series: s.Series(), 816 Subordinate: s.Subordinate(), 817 CharmURL: charmURL, 818 Channel: s.Channel(), 819 CharmModifiedVersion: s.CharmModifiedVersion(), 820 ForceCharm: s.ForceCharm(), 821 Life: Alive, 822 UnitCount: len(s.Units()), 823 RelationCount: i.relationCount(s.Name()), 824 Exposed: s.Exposed(), 825 MinUnits: s.MinUnits(), 826 MetricCredentials: s.MetricsCredentials(), 827 }, nil 828 } 829 830 func (i *importer) relationCount(application string) int { 831 count := 0 832 833 for _, rel := range i.model.Relations() { 834 for _, ep := range rel.Endpoints() { 835 if ep.ApplicationName() == application { 836 count++ 837 } 838 } 839 } 840 841 return count 842 } 843 844 func (i *importer) makeUnitDoc(s description.Application, u description.Unit) (*unitDoc, error) { 845 // NOTE: if we want to support units having different charms deployed 846 // than the application recomments and migrate that, then we should serialize 847 // the charm url for each unit rather than grabbing the applications charm url. 848 // Currently the units charm url matching the application is a precondiation 849 // to migration. 850 charmURL, err := charm.ParseURL(s.CharmURL()) 851 if err != nil { 852 return nil, errors.Trace(err) 853 } 854 855 var subordinates []string 856 if subs := u.Subordinates(); len(subs) > 0 { 857 for _, s := range subs { 858 subordinates = append(subordinates, s.Id()) 859 } 860 } 861 862 return &unitDoc{ 863 Name: u.Name(), 864 Application: s.Name(), 865 Series: s.Series(), 866 CharmURL: charmURL, 867 Principal: u.Principal().Id(), 868 Subordinates: subordinates, 869 StorageAttachmentCount: i.unitStorageAttachmentCount(u.Tag()), 870 MachineId: u.Machine().Id(), 871 Tools: i.makeTools(u.Tools()), 872 Life: Alive, 873 PasswordHash: u.PasswordHash(), 874 }, nil 875 } 876 877 func (i *importer) unitStorageAttachmentCount(unit names.UnitTag) int { 878 count := 0 879 for _, storage := range i.model.Storages() { 880 for _, tag := range storage.Attachments() { 881 if tag == unit { 882 count++ 883 } 884 } 885 } 886 return count 887 } 888 889 func (i *importer) relations() error { 890 i.logger.Debugf("importing relations") 891 for _, r := range i.model.Relations() { 892 if err := i.relation(r); err != nil { 893 i.logger.Errorf("error importing relation %s: %s", r.Key(), err) 894 return errors.Annotate(err, r.Key()) 895 } 896 } 897 898 i.logger.Debugf("importing relations succeeded") 899 return nil 900 } 901 902 func (i *importer) relation(rel description.Relation) error { 903 relationDoc := i.makeRelationDoc(rel) 904 ops := []txn.Op{ 905 { 906 C: relationsC, 907 Id: relationDoc.Key, 908 Assert: txn.DocMissing, 909 Insert: relationDoc, 910 }, 911 } 912 913 dbRelation := newRelation(i.st, relationDoc) 914 // Add an op that adds the relation scope document for each 915 // unit of the application, and an op that adds the relation settings 916 // for each unit. 917 for _, endpoint := range rel.Endpoints() { 918 units := i.applicationUnits[endpoint.ApplicationName()] 919 for _, unit := range units { 920 ru, err := dbRelation.Unit(unit) 921 if err != nil { 922 return errors.Trace(err) 923 } 924 ruKey := ru.key() 925 ops = append(ops, txn.Op{ 926 C: relationScopesC, 927 Id: ruKey, 928 Assert: txn.DocMissing, 929 Insert: relationScopeDoc{ 930 Key: ruKey, 931 }, 932 }, 933 createSettingsOp(settingsC, ruKey, endpoint.Settings(unit.Name())), 934 ) 935 } 936 } 937 938 if err := i.st.runTransaction(ops); err != nil { 939 return errors.Trace(err) 940 } 941 942 return nil 943 } 944 945 func (i *importer) makeRelationDoc(rel description.Relation) *relationDoc { 946 endpoints := rel.Endpoints() 947 doc := &relationDoc{ 948 Key: rel.Key(), 949 Id: rel.Id(), 950 Endpoints: make([]Endpoint, len(endpoints)), 951 Life: Alive, 952 } 953 for i, ep := range endpoints { 954 doc.Endpoints[i] = Endpoint{ 955 ApplicationName: ep.ApplicationName(), 956 Relation: charm.Relation{ 957 Name: ep.Name(), 958 Role: charm.RelationRole(ep.Role()), 959 Interface: ep.Interface(), 960 Optional: ep.Optional(), 961 Limit: ep.Limit(), 962 Scope: charm.RelationScope(ep.Scope()), 963 }, 964 } 965 doc.UnitCount += ep.UnitCount() 966 } 967 return doc 968 } 969 970 func (i *importer) spaces() error { 971 i.logger.Debugf("importing spaces") 972 for _, s := range i.model.Spaces() { 973 // The subnets are added after the spaces. 974 _, err := i.st.AddSpace(s.Name(), network.Id(s.ProviderID()), nil, s.Public()) 975 if err != nil { 976 i.logger.Errorf("error importing space %s: %s", s.Name(), err) 977 return errors.Annotate(err, s.Name()) 978 } 979 } 980 981 i.logger.Debugf("importing spaces succeeded") 982 return nil 983 } 984 985 func (i *importer) linklayerdevices() error { 986 i.logger.Debugf("importing linklayerdevices") 987 for _, device := range i.model.LinkLayerDevices() { 988 err := i.addLinkLayerDevice(device) 989 if err != nil { 990 i.logger.Errorf("error importing ip device %v: %s", device, err) 991 return errors.Trace(err) 992 } 993 } 994 // Loop a second time so we can ensure that all devices have had their 995 // parent created. 996 ops := []txn.Op{} 997 for _, device := range i.model.LinkLayerDevices() { 998 if device.ParentName() == "" { 999 continue 1000 } 1001 parentDocID, err := i.parentDocIDFromDevice(device) 1002 if err != nil { 1003 return errors.Trace(err) 1004 } 1005 ops = append(ops, incrementDeviceNumChildrenOp(parentDocID)) 1006 1007 } 1008 if err := i.st.runTransaction(ops); err != nil { 1009 return errors.Trace(err) 1010 } 1011 i.logger.Debugf("importing linklayerdevices succeeded") 1012 return nil 1013 } 1014 1015 func (i *importer) parentDocIDFromDevice(device description.LinkLayerDevice) (string, error) { 1016 hostMachineID, parentName, err := parseLinkLayerDeviceParentNameAsGlobalKey(device.ParentName()) 1017 if err != nil { 1018 return "", errors.Trace(err) 1019 } 1020 if hostMachineID == "" { 1021 // ParentName is not a global key, but on the same machine. 1022 hostMachineID = device.MachineID() 1023 parentName = device.ParentName() 1024 } 1025 return i.st.docID(linkLayerDeviceGlobalKey(hostMachineID, parentName)), nil 1026 } 1027 1028 func (i *importer) addLinkLayerDevice(device description.LinkLayerDevice) error { 1029 providerID := device.ProviderID() 1030 modelUUID := i.st.ModelUUID() 1031 localID := linkLayerDeviceGlobalKey(device.MachineID(), device.Name()) 1032 linkLayerDeviceDocID := i.st.docID(localID) 1033 newDoc := &linkLayerDeviceDoc{ 1034 ModelUUID: modelUUID, 1035 DocID: linkLayerDeviceDocID, 1036 MachineID: device.MachineID(), 1037 ProviderID: providerID, 1038 Name: device.Name(), 1039 MTU: device.MTU(), 1040 Type: LinkLayerDeviceType(device.Type()), 1041 MACAddress: device.MACAddress(), 1042 IsAutoStart: device.IsAutoStart(), 1043 IsUp: device.IsUp(), 1044 ParentName: device.ParentName(), 1045 } 1046 1047 ops := []txn.Op{{ 1048 C: linkLayerDevicesC, 1049 Id: newDoc.DocID, 1050 Insert: newDoc, 1051 }, 1052 insertLinkLayerDevicesRefsOp(modelUUID, linkLayerDeviceDocID), 1053 } 1054 if providerID != "" { 1055 id := network.Id(providerID) 1056 ops = append(ops, i.st.networkEntityGlobalKeyOp("linklayerdevice", id)) 1057 } 1058 if err := i.st.runTransaction(ops); err != nil { 1059 return errors.Trace(err) 1060 } 1061 return nil 1062 } 1063 1064 func (i *importer) subnets() error { 1065 i.logger.Debugf("importing subnets") 1066 for _, subnet := range i.model.Subnets() { 1067 err := i.addSubnet(SubnetInfo{ 1068 CIDR: subnet.CIDR(), 1069 ProviderId: network.Id(subnet.ProviderId()), 1070 VLANTag: subnet.VLANTag(), 1071 AvailabilityZone: subnet.AvailabilityZone(), 1072 SpaceName: subnet.SpaceName(), 1073 }) 1074 if err != nil { 1075 return errors.Trace(err) 1076 } 1077 } 1078 i.logger.Debugf("importing subnets succeeded") 1079 return nil 1080 } 1081 1082 func (i *importer) addSubnet(args SubnetInfo) error { 1083 buildTxn := func(attempt int) ([]txn.Op, error) { 1084 subnet, err := i.st.newSubnetFromArgs(args) 1085 if err != nil { 1086 return nil, errors.Trace(err) 1087 } 1088 ops := i.st.addSubnetOps(args) 1089 if attempt != 0 { 1090 if _, err = i.st.Subnet(args.CIDR); err == nil { 1091 return nil, errors.AlreadyExistsf("subnet %q", args.CIDR) 1092 } 1093 if err := subnet.Refresh(); err != nil { 1094 if errors.IsNotFound(err) { 1095 return nil, errors.Errorf("ProviderId %q not unique", args.ProviderId) 1096 } 1097 return nil, errors.Trace(err) 1098 } 1099 } 1100 return ops, nil 1101 } 1102 err := i.st.run(buildTxn) 1103 if err != nil { 1104 return errors.Trace(err) 1105 } 1106 return nil 1107 } 1108 1109 func (i *importer) ipaddresses() error { 1110 i.logger.Debugf("importing ip addresses") 1111 for _, addr := range i.model.IPAddresses() { 1112 err := i.addIPAddress(addr) 1113 if err != nil { 1114 i.logger.Errorf("error importing ip address %v: %s", addr, err) 1115 return errors.Trace(err) 1116 } 1117 } 1118 i.logger.Debugf("importing ip addresses succeeded") 1119 return nil 1120 } 1121 1122 func (i *importer) addIPAddress(addr description.IPAddress) error { 1123 addressValue := addr.Value() 1124 subnetCIDR := addr.SubnetCIDR() 1125 1126 globalKey := ipAddressGlobalKey(addr.MachineID(), addr.DeviceName(), addressValue) 1127 ipAddressDocID := i.st.docID(globalKey) 1128 providerID := addr.ProviderID() 1129 1130 modelUUID := i.st.ModelUUID() 1131 1132 newDoc := &ipAddressDoc{ 1133 DocID: ipAddressDocID, 1134 ModelUUID: modelUUID, 1135 ProviderID: providerID, 1136 DeviceName: addr.DeviceName(), 1137 MachineID: addr.MachineID(), 1138 SubnetCIDR: subnetCIDR, 1139 ConfigMethod: AddressConfigMethod(addr.ConfigMethod()), 1140 Value: addressValue, 1141 DNSServers: addr.DNSServers(), 1142 DNSSearchDomains: addr.DNSSearchDomains(), 1143 GatewayAddress: addr.GatewayAddress(), 1144 } 1145 1146 ops := []txn.Op{{ 1147 C: ipAddressesC, 1148 Id: newDoc.DocID, 1149 Insert: newDoc, 1150 }} 1151 1152 if providerID != "" { 1153 id := network.Id(providerID) 1154 ops = append(ops, i.st.networkEntityGlobalKeyOp("address", id)) 1155 } 1156 if err := i.st.runTransaction(ops); err != nil { 1157 return errors.Trace(err) 1158 } 1159 return nil 1160 } 1161 1162 func (i *importer) sshHostKeys() error { 1163 i.logger.Debugf("importing ssh host keys") 1164 for _, key := range i.model.SSHHostKeys() { 1165 name := names.NewMachineTag(key.MachineID()) 1166 err := i.st.SetSSHHostKeys(name, key.Keys()) 1167 if err != nil { 1168 i.logger.Errorf("error importing ssh host keys %v: %s", key, err) 1169 return errors.Trace(err) 1170 } 1171 } 1172 i.logger.Debugf("importing ssh host keys succeeded") 1173 return nil 1174 } 1175 1176 func (i *importer) cloudimagemetadata() error { 1177 i.logger.Debugf("importing cloudimagemetadata") 1178 images := i.model.CloudImageMetadata() 1179 metadatas := make([]cloudimagemetadata.Metadata, len(images)) 1180 for index, image := range images { 1181 metadatas[index] = cloudimagemetadata.Metadata{ 1182 cloudimagemetadata.MetadataAttributes{ 1183 Source: image.Source(), 1184 Stream: image.Stream(), 1185 Region: image.Region(), 1186 Version: image.Version(), 1187 Series: image.Series(), 1188 Arch: image.Arch(), 1189 RootStorageType: image.RootStorageType(), 1190 VirtType: image.VirtType(), 1191 }, 1192 image.Priority(), 1193 image.ImageId(), 1194 image.DateCreated(), 1195 } 1196 } 1197 err := i.st.CloudImageMetadataStorage.SaveMetadata(metadatas) 1198 if err != nil { 1199 i.logger.Errorf("error importing cloudimagemetadata %v: %s", images, err) 1200 return errors.Trace(err) 1201 } 1202 i.logger.Debugf("importing cloudimagemetadata succeeded") 1203 return nil 1204 } 1205 1206 func (i *importer) actions() error { 1207 i.logger.Debugf("importing actions") 1208 for _, action := range i.model.Actions() { 1209 err := i.addAction(action) 1210 if err != nil { 1211 i.logger.Errorf("error importing action %v: %s", action, err) 1212 return errors.Trace(err) 1213 } 1214 } 1215 i.logger.Debugf("importing actions succeeded") 1216 return nil 1217 } 1218 1219 func (i *importer) addAction(action description.Action) error { 1220 modelUUID := i.st.ModelUUID() 1221 newDoc := &actionDoc{ 1222 DocId: i.st.docID(action.Id()), 1223 ModelUUID: modelUUID, 1224 Receiver: action.Receiver(), 1225 Name: action.Name(), 1226 Parameters: action.Parameters(), 1227 Enqueued: action.Enqueued(), 1228 Results: action.Results(), 1229 Message: action.Message(), 1230 Started: action.Started(), 1231 Completed: action.Completed(), 1232 Status: ActionStatus(action.Status()), 1233 } 1234 prefix := ensureActionMarker(action.Receiver()) 1235 notificationDoc := &actionNotificationDoc{ 1236 DocId: i.st.docID(prefix + action.Id()), 1237 ModelUUID: modelUUID, 1238 Receiver: action.Receiver(), 1239 ActionID: action.Id(), 1240 } 1241 ops := []txn.Op{{ 1242 C: actionsC, 1243 Id: newDoc.DocId, 1244 Insert: newDoc, 1245 }, { 1246 C: actionNotificationsC, 1247 Id: notificationDoc.DocId, 1248 Insert: notificationDoc, 1249 }} 1250 1251 if err := i.st.runTransaction(ops); err != nil { 1252 return errors.Trace(err) 1253 } 1254 return nil 1255 } 1256 1257 func (i *importer) importStatusHistory(globalKey string, history []description.Status) error { 1258 docs := make([]interface{}, len(history)) 1259 for i, statusVal := range history { 1260 docs[i] = historicalStatusDoc{ 1261 GlobalKey: globalKey, 1262 Status: status.Status(statusVal.Value()), 1263 StatusInfo: statusVal.Message(), 1264 StatusData: statusVal.Data(), 1265 Updated: statusVal.Updated().UnixNano(), 1266 } 1267 } 1268 if len(docs) == 0 { 1269 return nil 1270 } 1271 1272 statusHistory, closer := i.st.getCollection(statusesHistoryC) 1273 defer closer() 1274 1275 if err := statusHistory.Writeable().Insert(docs...); err != nil { 1276 return errors.Trace(err) 1277 } 1278 return nil 1279 } 1280 1281 func (i *importer) constraints(cons description.Constraints) constraints.Value { 1282 var result constraints.Value 1283 if cons == nil { 1284 return result 1285 } 1286 1287 if arch := cons.Architecture(); arch != "" { 1288 result.Arch = &arch 1289 } 1290 if container := instance.ContainerType(cons.Container()); container != "" { 1291 result.Container = &container 1292 } 1293 if cores := cons.CpuCores(); cores != 0 { 1294 result.CpuCores = &cores 1295 } 1296 if power := cons.CpuPower(); power != 0 { 1297 result.CpuPower = &power 1298 } 1299 if inst := cons.InstanceType(); inst != "" { 1300 result.InstanceType = &inst 1301 } 1302 if mem := cons.Memory(); mem != 0 { 1303 result.Mem = &mem 1304 } 1305 if disk := cons.RootDisk(); disk != 0 { 1306 result.RootDisk = &disk 1307 } 1308 if spaces := cons.Spaces(); len(spaces) > 0 { 1309 result.Spaces = &spaces 1310 } 1311 if tags := cons.Tags(); len(tags) > 0 { 1312 result.Tags = &tags 1313 } 1314 if virt := cons.VirtType(); virt != "" { 1315 result.VirtType = &virt 1316 } 1317 return result 1318 } 1319 1320 func (i *importer) storage() error { 1321 if err := i.storageInstances(); err != nil { 1322 return errors.Annotate(err, "storage instances") 1323 } 1324 if err := i.volumes(); err != nil { 1325 return errors.Annotate(err, "volumes") 1326 } 1327 if err := i.filesystems(); err != nil { 1328 return errors.Annotate(err, "filesystems") 1329 } 1330 if err := i.storagePools(); err != nil { 1331 return errors.Annotate(err, "storage pools") 1332 } 1333 return nil 1334 } 1335 1336 func (i *importer) storageInstances() error { 1337 i.logger.Debugf("importing storage instances") 1338 for _, storage := range i.model.Storages() { 1339 err := i.addStorageInstance(storage) 1340 if err != nil { 1341 i.logger.Errorf("error importing storage %s: %s", storage.Tag(), err) 1342 return errors.Trace(err) 1343 } 1344 } 1345 i.logger.Debugf("importing storage instances succeeded") 1346 return nil 1347 } 1348 1349 func (i *importer) addStorageInstance(storage description.Storage) error { 1350 kind := parseStorageKind(storage.Kind()) 1351 if kind == StorageKindUnknown { 1352 return errors.Errorf("storage kind %q is unknown", storage.Kind()) 1353 } 1354 owner, err := storage.Owner() 1355 if err != nil { 1356 return errors.Annotate(err, "storage owner") 1357 } 1358 attachments := storage.Attachments() 1359 tag := storage.Tag() 1360 var ops []txn.Op 1361 for _, unit := range attachments { 1362 ops = append(ops, createStorageAttachmentOp(tag, unit)) 1363 } 1364 doc := &storageInstanceDoc{ 1365 Id: storage.Tag().Id(), 1366 Kind: kind, 1367 Owner: owner.String(), 1368 StorageName: storage.Name(), 1369 AttachmentCount: len(attachments), 1370 } 1371 ops = append(ops, txn.Op{ 1372 C: storageInstancesC, 1373 Id: tag.Id(), 1374 Assert: txn.DocMissing, 1375 Insert: doc, 1376 }) 1377 1378 refcounts, closer := i.st.getCollection(refcountsC) 1379 defer closer() 1380 storageRefcountKey := entityStorageRefcountKey(owner, storage.Name()) 1381 incRefOp, err := nsRefcounts.CreateOrIncRefOp(refcounts, storageRefcountKey, 1) 1382 if err != nil { 1383 return errors.Trace(err) 1384 } 1385 ops = append(ops, incRefOp) 1386 1387 if err := i.st.runTransaction(ops); err != nil { 1388 return errors.Trace(err) 1389 } 1390 return nil 1391 } 1392 1393 func (i *importer) volumes() error { 1394 i.logger.Debugf("importing volumes") 1395 for _, volume := range i.model.Volumes() { 1396 err := i.addVolume(volume) 1397 if err != nil { 1398 i.logger.Errorf("error importing volume %s: %s", volume.Tag(), err) 1399 return errors.Trace(err) 1400 } 1401 } 1402 i.logger.Debugf("importing volumes succeeded") 1403 return nil 1404 } 1405 1406 func (i *importer) addVolume(volume description.Volume) error { 1407 1408 attachments := volume.Attachments() 1409 tag := volume.Tag() 1410 var binding string 1411 bindingTag, err := volume.Binding() 1412 if err != nil { 1413 return errors.Trace(err) 1414 } 1415 if bindingTag != nil { 1416 binding = bindingTag.String() 1417 } 1418 var params *VolumeParams 1419 var info *VolumeInfo 1420 if volume.Provisioned() { 1421 info = &VolumeInfo{ 1422 HardwareId: volume.HardwareID(), 1423 Size: volume.Size(), 1424 Pool: volume.Pool(), 1425 VolumeId: volume.VolumeID(), 1426 Persistent: volume.Persistent(), 1427 } 1428 } else { 1429 params = &VolumeParams{ 1430 Size: volume.Size(), 1431 Pool: volume.Pool(), 1432 } 1433 } 1434 doc := volumeDoc{ 1435 Name: tag.Id(), 1436 StorageId: volume.Storage().Id(), 1437 // Life: ..., // TODO: import life, default is Alive 1438 Binding: binding, 1439 Params: params, 1440 Info: info, 1441 AttachmentCount: len(attachments), 1442 } 1443 status := i.makeStatusDoc(volume.Status()) 1444 ops := i.st.newVolumeOps(doc, status) 1445 1446 for _, attachment := range attachments { 1447 ops = append(ops, i.addVolumeAttachmentOp(tag.Id(), attachment)) 1448 } 1449 1450 if err := i.st.runTransaction(ops); err != nil { 1451 return errors.Trace(err) 1452 } 1453 1454 if err := i.importStatusHistory(volumeGlobalKey(tag.Id()), volume.StatusHistory()); err != nil { 1455 return errors.Annotate(err, "status history") 1456 } 1457 return nil 1458 } 1459 1460 func (i *importer) addVolumeAttachmentOp(volID string, attachment description.VolumeAttachment) txn.Op { 1461 var info *VolumeAttachmentInfo 1462 var params *VolumeAttachmentParams 1463 if attachment.Provisioned() { 1464 info = &VolumeAttachmentInfo{ 1465 DeviceName: attachment.DeviceName(), 1466 DeviceLink: attachment.DeviceLink(), 1467 BusAddress: attachment.BusAddress(), 1468 ReadOnly: attachment.ReadOnly(), 1469 } 1470 } else { 1471 params = &VolumeAttachmentParams{ 1472 ReadOnly: attachment.ReadOnly(), 1473 } 1474 } 1475 1476 machineId := attachment.Machine().Id() 1477 return txn.Op{ 1478 C: volumeAttachmentsC, 1479 Id: volumeAttachmentId(machineId, volID), 1480 Assert: txn.DocMissing, 1481 Insert: &volumeAttachmentDoc{ 1482 Volume: volID, 1483 Machine: machineId, 1484 Params: params, 1485 Info: info, 1486 }, 1487 } 1488 } 1489 1490 func (i *importer) filesystems() error { 1491 i.logger.Debugf("importing filesystems") 1492 for _, fs := range i.model.Filesystems() { 1493 err := i.addFilesystem(fs) 1494 if err != nil { 1495 i.logger.Errorf("error importing filesystem %s: %s", fs.Tag(), err) 1496 return errors.Trace(err) 1497 } 1498 } 1499 i.logger.Debugf("importing filesystems succeeded") 1500 return nil 1501 } 1502 1503 func (i *importer) addFilesystem(filesystem description.Filesystem) error { 1504 1505 attachments := filesystem.Attachments() 1506 tag := filesystem.Tag() 1507 var binding string 1508 bindingTag, err := filesystem.Binding() 1509 if err != nil { 1510 return errors.Trace(err) 1511 } 1512 if bindingTag != nil { 1513 binding = bindingTag.String() 1514 } 1515 var params *FilesystemParams 1516 var info *FilesystemInfo 1517 if filesystem.Provisioned() { 1518 info = &FilesystemInfo{ 1519 Size: filesystem.Size(), 1520 Pool: filesystem.Pool(), 1521 FilesystemId: filesystem.FilesystemID(), 1522 } 1523 } else { 1524 params = &FilesystemParams{ 1525 Size: filesystem.Size(), 1526 Pool: filesystem.Pool(), 1527 } 1528 } 1529 doc := filesystemDoc{ 1530 FilesystemId: tag.Id(), 1531 StorageId: filesystem.Storage().Id(), 1532 VolumeId: filesystem.Volume().Id(), 1533 // Life: ..., // TODO: import life, default is Alive 1534 Binding: binding, 1535 Params: params, 1536 Info: info, 1537 AttachmentCount: len(attachments), 1538 } 1539 status := i.makeStatusDoc(filesystem.Status()) 1540 ops := i.st.newFilesystemOps(doc, status) 1541 1542 for _, attachment := range attachments { 1543 ops = append(ops, i.addFilesystemAttachmentOp(tag.Id(), attachment)) 1544 } 1545 1546 if err := i.st.runTransaction(ops); err != nil { 1547 return errors.Trace(err) 1548 } 1549 1550 if err := i.importStatusHistory(filesystemGlobalKey(tag.Id()), filesystem.StatusHistory()); err != nil { 1551 return errors.Annotate(err, "status history") 1552 } 1553 return nil 1554 } 1555 1556 func (i *importer) addFilesystemAttachmentOp(fsID string, attachment description.FilesystemAttachment) txn.Op { 1557 var info *FilesystemAttachmentInfo 1558 var params *FilesystemAttachmentParams 1559 if attachment.Provisioned() { 1560 info = &FilesystemAttachmentInfo{ 1561 MountPoint: attachment.MountPoint(), 1562 ReadOnly: attachment.ReadOnly(), 1563 } 1564 } else { 1565 params = &FilesystemAttachmentParams{ 1566 Location: attachment.MountPoint(), 1567 ReadOnly: attachment.ReadOnly(), 1568 } 1569 } 1570 1571 machineId := attachment.Machine().Id() 1572 return txn.Op{ 1573 C: filesystemAttachmentsC, 1574 Id: filesystemAttachmentId(machineId, fsID), 1575 Assert: txn.DocMissing, 1576 Insert: &filesystemAttachmentDoc{ 1577 Filesystem: fsID, 1578 Machine: machineId, 1579 // Life: ..., // TODO: import life, default is Alive 1580 Params: params, 1581 Info: info, 1582 }, 1583 } 1584 } 1585 1586 func (i *importer) storagePools() error { 1587 registry, err := i.st.storageProviderRegistry() 1588 if err != nil { 1589 return errors.Annotate(err, "getting provider registry") 1590 } 1591 pm := poolmanager.New(NewStateSettings(i.st), registry) 1592 1593 for _, pool := range i.model.StoragePools() { 1594 _, err := pm.Create(pool.Name(), storage.ProviderType(pool.Provider()), pool.Attributes()) 1595 if err != nil { 1596 return errors.Annotatef(err, "creating pool %q", pool.Name()) 1597 } 1598 } 1599 return nil 1600 }