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  }