github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/migration_export.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  	"strings"
     8  	"time"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/loggo"
    12  	"github.com/juju/utils/set"
    13  	"gopkg.in/juju/names.v2"
    14  	"gopkg.in/mgo.v2/bson"
    15  
    16  	"github.com/juju/juju/core/description"
    17  	"github.com/juju/juju/payload"
    18  	"github.com/juju/juju/storage/poolmanager"
    19  )
    20  
    21  // Export the current model for the State.
    22  func (st *State) Export() (description.Model, error) {
    23  	dbModel, err := st.Model()
    24  	if err != nil {
    25  		return nil, errors.Trace(err)
    26  	}
    27  
    28  	export := exporter{
    29  		st:      st,
    30  		dbModel: dbModel,
    31  		logger:  loggo.GetLogger("juju.state.export-model"),
    32  	}
    33  	if err := export.readAllStatuses(); err != nil {
    34  		return nil, errors.Annotate(err, "reading statuses")
    35  	}
    36  	if err := export.readAllStatusHistory(); err != nil {
    37  		return nil, errors.Trace(err)
    38  	}
    39  	if err := export.readAllSettings(); err != nil {
    40  		return nil, errors.Trace(err)
    41  	}
    42  	if err := export.readAllStorageConstraints(); err != nil {
    43  		return nil, errors.Trace(err)
    44  	}
    45  	if err := export.readAllAnnotations(); err != nil {
    46  		return nil, errors.Trace(err)
    47  	}
    48  	if err := export.readAllConstraints(); err != nil {
    49  		return nil, errors.Trace(err)
    50  	}
    51  
    52  	modelConfig, found := export.modelSettings[modelGlobalKey]
    53  	if !found {
    54  		return nil, errors.New("missing model config")
    55  	}
    56  
    57  	blocks, err := export.readBlocks()
    58  	if err != nil {
    59  		return nil, errors.Trace(err)
    60  	}
    61  
    62  	args := description.ModelArgs{
    63  		Cloud:              dbModel.Cloud(),
    64  		CloudRegion:        dbModel.CloudRegion(),
    65  		Owner:              dbModel.Owner(),
    66  		Config:             modelConfig.Settings,
    67  		LatestToolsVersion: dbModel.LatestToolsVersion(),
    68  		Blocks:             blocks,
    69  	}
    70  	export.model = description.NewModel(args)
    71  	modelKey := dbModel.globalKey()
    72  	export.model.SetAnnotations(export.getAnnotations(modelKey))
    73  	if err := export.sequences(); err != nil {
    74  		return nil, errors.Trace(err)
    75  	}
    76  	constraintsArgs, err := export.constraintsArgs(modelKey)
    77  	if err != nil {
    78  		return nil, errors.Trace(err)
    79  	}
    80  	export.model.SetConstraints(constraintsArgs)
    81  
    82  	if err := export.modelUsers(); err != nil {
    83  		return nil, errors.Trace(err)
    84  	}
    85  	if err := export.machines(); err != nil {
    86  		return nil, errors.Trace(err)
    87  	}
    88  	if err := export.applications(); err != nil {
    89  		return nil, errors.Trace(err)
    90  	}
    91  	if err := export.relations(); err != nil {
    92  		return nil, errors.Trace(err)
    93  	}
    94  	if err := export.spaces(); err != nil {
    95  		return nil, errors.Trace(err)
    96  	}
    97  	if err := export.subnets(); err != nil {
    98  		return nil, errors.Trace(err)
    99  	}
   100  
   101  	if err := export.ipaddresses(); err != nil {
   102  		return nil, errors.Trace(err)
   103  	}
   104  
   105  	if err := export.linklayerdevices(); err != nil {
   106  		return nil, errors.Trace(err)
   107  	}
   108  
   109  	if err := export.sshHostKeys(); err != nil {
   110  		return nil, errors.Trace(err)
   111  	}
   112  	if err := export.storage(); err != nil {
   113  		return nil, errors.Trace(err)
   114  	}
   115  
   116  	if err := export.actions(); err != nil {
   117  		return nil, errors.Trace(err)
   118  	}
   119  
   120  	if err := export.cloudimagemetadata(); err != nil {
   121  		return nil, errors.Trace(err)
   122  	}
   123  
   124  	if err := export.model.Validate(); err != nil {
   125  		return nil, errors.Trace(err)
   126  	}
   127  
   128  	export.logExtras()
   129  
   130  	return export.model, nil
   131  }
   132  
   133  type exporter struct {
   134  	st      *State
   135  	dbModel *Model
   136  	model   description.Model
   137  	logger  loggo.Logger
   138  
   139  	annotations             map[string]annotatorDoc
   140  	constraints             map[string]bson.M
   141  	modelSettings           map[string]settingsDoc
   142  	modelStorageConstraints map[string]storageConstraintsDoc
   143  	status                  map[string]bson.M
   144  	statusHistory           map[string][]historicalStatusDoc
   145  	// Map of application name to units. Populated as part
   146  	// of the applications export.
   147  	units map[string][]*Unit
   148  }
   149  
   150  func (e *exporter) sequences() error {
   151  	sequences, closer := e.st.getCollection(sequenceC)
   152  	defer closer()
   153  
   154  	var docs []sequenceDoc
   155  	if err := sequences.Find(nil).All(&docs); err != nil {
   156  		return errors.Trace(err)
   157  	}
   158  
   159  	for _, doc := range docs {
   160  		e.model.SetSequence(doc.Name, doc.Counter)
   161  	}
   162  	return nil
   163  }
   164  
   165  func (e *exporter) readBlocks() (map[string]string, error) {
   166  	blocks, closer := e.st.getCollection(blocksC)
   167  	defer closer()
   168  
   169  	var docs []blockDoc
   170  	if err := blocks.Find(nil).All(&docs); err != nil {
   171  		return nil, errors.Trace(err)
   172  	}
   173  
   174  	result := make(map[string]string)
   175  	for _, doc := range docs {
   176  		// We don't care about the id, uuid, or tag.
   177  		// The uuid and tag both refer to the model uuid, and the
   178  		// id is opaque - even though it is sequence generated.
   179  		result[doc.Type.MigrationValue()] = doc.Message
   180  	}
   181  	return result, nil
   182  }
   183  
   184  func (e *exporter) modelUsers() error {
   185  	users, err := e.dbModel.Users()
   186  	if err != nil {
   187  		return errors.Trace(err)
   188  	}
   189  	lastConnections, err := e.readLastConnectionTimes()
   190  	if err != nil {
   191  		return errors.Trace(err)
   192  	}
   193  	for _, user := range users {
   194  		lastConn := lastConnections[strings.ToLower(user.UserName)]
   195  		arg := description.UserArgs{
   196  			Name:           user.UserTag,
   197  			DisplayName:    user.DisplayName,
   198  			CreatedBy:      user.CreatedBy,
   199  			DateCreated:    user.DateCreated,
   200  			LastConnection: lastConn,
   201  			Access:         string(user.Access),
   202  		}
   203  		e.model.AddUser(arg)
   204  	}
   205  	return nil
   206  }
   207  
   208  func (e *exporter) machines() error {
   209  	machines, err := e.st.AllMachines()
   210  	if err != nil {
   211  		return errors.Trace(err)
   212  	}
   213  	e.logger.Debugf("found %d machines", len(machines))
   214  
   215  	instances, err := e.loadMachineInstanceData()
   216  	if err != nil {
   217  		return errors.Trace(err)
   218  	}
   219  	blockDevices, err := e.loadMachineBlockDevices()
   220  	if err != nil {
   221  		return errors.Trace(err)
   222  	}
   223  
   224  	// Read all the open ports documents.
   225  	openedPorts, closer := e.st.getCollection(openedPortsC)
   226  	defer closer()
   227  	var portsData []portsDoc
   228  	if err := openedPorts.Find(nil).All(&portsData); err != nil {
   229  		return errors.Annotate(err, "opened ports")
   230  	}
   231  	e.logger.Debugf("found %d openedPorts docs", len(portsData))
   232  
   233  	// We are iterating through a flat list of machines, but the migration
   234  	// model stores the nesting. The AllMachines method assures us that the
   235  	// machines are returned in an order so the parent will always before
   236  	// any children.
   237  	machineMap := make(map[string]description.Machine)
   238  
   239  	for _, machine := range machines {
   240  		e.logger.Debugf("export machine %s", machine.Id())
   241  
   242  		var exParent description.Machine
   243  		if parentId := ParentId(machine.Id()); parentId != "" {
   244  			var found bool
   245  			exParent, found = machineMap[parentId]
   246  			if !found {
   247  				return errors.Errorf("machine %s missing parent", machine.Id())
   248  			}
   249  		}
   250  
   251  		exMachine, err := e.newMachine(exParent, machine, instances, portsData, blockDevices)
   252  		if err != nil {
   253  			return errors.Trace(err)
   254  		}
   255  		machineMap[machine.Id()] = exMachine
   256  	}
   257  
   258  	return nil
   259  }
   260  
   261  func (e *exporter) loadMachineInstanceData() (map[string]instanceData, error) {
   262  	instanceDataCollection, closer := e.st.getCollection(instanceDataC)
   263  	defer closer()
   264  
   265  	var instData []instanceData
   266  	instances := make(map[string]instanceData)
   267  	if err := instanceDataCollection.Find(nil).All(&instData); err != nil {
   268  		return nil, errors.Annotate(err, "instance data")
   269  	}
   270  	e.logger.Debugf("found %d instanceData", len(instData))
   271  	for _, data := range instData {
   272  		instances[data.MachineId] = data
   273  	}
   274  	return instances, nil
   275  }
   276  
   277  func (e *exporter) loadMachineBlockDevices() (map[string][]BlockDeviceInfo, error) {
   278  	coll, closer := e.st.getCollection(blockDevicesC)
   279  	defer closer()
   280  
   281  	var deviceData []blockDevicesDoc
   282  	result := make(map[string][]BlockDeviceInfo)
   283  	if err := coll.Find(nil).All(&deviceData); err != nil {
   284  		return nil, errors.Annotate(err, "block devices")
   285  	}
   286  	e.logger.Debugf("found %d block device records", len(deviceData))
   287  	for _, data := range deviceData {
   288  		result[data.Machine] = data.BlockDevices
   289  	}
   290  	return result, nil
   291  }
   292  
   293  func (e *exporter) newMachine(exParent description.Machine, machine *Machine, instances map[string]instanceData, portsData []portsDoc, blockDevices map[string][]BlockDeviceInfo) (description.Machine, error) {
   294  	args := description.MachineArgs{
   295  		Id:            machine.MachineTag(),
   296  		Nonce:         machine.doc.Nonce,
   297  		PasswordHash:  machine.doc.PasswordHash,
   298  		Placement:     machine.doc.Placement,
   299  		Series:        machine.doc.Series,
   300  		ContainerType: machine.doc.ContainerType,
   301  	}
   302  
   303  	if supported, ok := machine.SupportedContainers(); ok {
   304  		containers := make([]string, len(supported))
   305  		for i, containerType := range supported {
   306  			containers[i] = string(containerType)
   307  		}
   308  		args.SupportedContainers = &containers
   309  	}
   310  
   311  	for _, job := range machine.Jobs() {
   312  		args.Jobs = append(args.Jobs, job.MigrationValue())
   313  	}
   314  
   315  	// A null value means that we don't yet know which containers
   316  	// are supported. An empty slice means 'no containers are supported'.
   317  	var exMachine description.Machine
   318  	if exParent == nil {
   319  		exMachine = e.model.AddMachine(args)
   320  	} else {
   321  		exMachine = exParent.AddContainer(args)
   322  	}
   323  	exMachine.SetAddresses(
   324  		e.newAddressArgsSlice(machine.doc.MachineAddresses),
   325  		e.newAddressArgsSlice(machine.doc.Addresses))
   326  	exMachine.SetPreferredAddresses(
   327  		e.newAddressArgs(machine.doc.PreferredPublicAddress),
   328  		e.newAddressArgs(machine.doc.PreferredPrivateAddress))
   329  
   330  	// We fully expect the machine to have tools set, and that there is
   331  	// some instance data.
   332  	instData, found := instances[machine.doc.Id]
   333  	if !found {
   334  		return nil, errors.NotValidf("missing instance data for machine %s", machine.Id())
   335  	}
   336  	exMachine.SetInstance(e.newCloudInstanceArgs(instData))
   337  
   338  	// We don't rely on devices being there. If they aren't, we get an empty slice,
   339  	// which is fine to iterate over with range.
   340  	for _, device := range blockDevices[machine.doc.Id] {
   341  		exMachine.AddBlockDevice(description.BlockDeviceArgs{
   342  			Name:           device.DeviceName,
   343  			Links:          device.DeviceLinks,
   344  			Label:          device.Label,
   345  			UUID:           device.UUID,
   346  			HardwareID:     device.HardwareId,
   347  			BusAddress:     device.BusAddress,
   348  			Size:           device.Size,
   349  			FilesystemType: device.FilesystemType,
   350  			InUse:          device.InUse,
   351  			MountPoint:     device.MountPoint,
   352  		})
   353  	}
   354  
   355  	// Find the current machine status.
   356  	globalKey := machine.globalKey()
   357  	statusArgs, err := e.statusArgs(globalKey)
   358  	if err != nil {
   359  		return nil, errors.Annotatef(err, "status for machine %s", machine.Id())
   360  	}
   361  	exMachine.SetStatus(statusArgs)
   362  	exMachine.SetStatusHistory(e.statusHistoryArgs(globalKey))
   363  
   364  	tools, err := machine.AgentTools()
   365  	if err != nil {
   366  		// This means the tools aren't set, but they should be.
   367  		return nil, errors.Trace(err)
   368  	}
   369  
   370  	exMachine.SetTools(description.AgentToolsArgs{
   371  		Version: tools.Version,
   372  		URL:     tools.URL,
   373  		SHA256:  tools.SHA256,
   374  		Size:    tools.Size,
   375  	})
   376  
   377  	for _, args := range e.openedPortsArgsForMachine(machine.Id(), portsData) {
   378  		exMachine.AddOpenedPorts(args)
   379  	}
   380  
   381  	exMachine.SetAnnotations(e.getAnnotations(globalKey))
   382  
   383  	constraintsArgs, err := e.constraintsArgs(globalKey)
   384  	if err != nil {
   385  		return nil, errors.Trace(err)
   386  	}
   387  	exMachine.SetConstraints(constraintsArgs)
   388  
   389  	return exMachine, nil
   390  }
   391  
   392  func (e *exporter) openedPortsArgsForMachine(machineId string, portsData []portsDoc) []description.OpenedPortsArgs {
   393  	var result []description.OpenedPortsArgs
   394  	for _, doc := range portsData {
   395  		// Don't bother including a subnet if there are no ports open on it.
   396  		if doc.MachineID == machineId && len(doc.Ports) > 0 {
   397  			args := description.OpenedPortsArgs{SubnetID: doc.SubnetID}
   398  			for _, p := range doc.Ports {
   399  				args.OpenedPorts = append(args.OpenedPorts, description.PortRangeArgs{
   400  					UnitName: p.UnitName,
   401  					FromPort: p.FromPort,
   402  					ToPort:   p.ToPort,
   403  					Protocol: p.Protocol,
   404  				})
   405  			}
   406  			result = append(result, args)
   407  		}
   408  	}
   409  	return result
   410  }
   411  
   412  func (e *exporter) newAddressArgsSlice(a []address) []description.AddressArgs {
   413  	result := []description.AddressArgs{}
   414  	for _, addr := range a {
   415  		result = append(result, e.newAddressArgs(addr))
   416  	}
   417  	return result
   418  }
   419  
   420  func (e *exporter) newAddressArgs(a address) description.AddressArgs {
   421  	return description.AddressArgs{
   422  		Value:  a.Value,
   423  		Type:   a.AddressType,
   424  		Scope:  a.Scope,
   425  		Origin: a.Origin,
   426  	}
   427  }
   428  
   429  func (e *exporter) newCloudInstanceArgs(data instanceData) description.CloudInstanceArgs {
   430  	inst := description.CloudInstanceArgs{
   431  		InstanceId: string(data.InstanceId),
   432  		Status:     data.Status,
   433  	}
   434  	if data.Arch != nil {
   435  		inst.Architecture = *data.Arch
   436  	}
   437  	if data.Mem != nil {
   438  		inst.Memory = *data.Mem
   439  	}
   440  	if data.RootDisk != nil {
   441  		inst.RootDisk = *data.RootDisk
   442  	}
   443  	if data.CpuCores != nil {
   444  		inst.CpuCores = *data.CpuCores
   445  	}
   446  	if data.CpuPower != nil {
   447  		inst.CpuPower = *data.CpuPower
   448  	}
   449  	if data.Tags != nil {
   450  		inst.Tags = *data.Tags
   451  	}
   452  	if data.AvailZone != nil {
   453  		inst.AvailabilityZone = *data.AvailZone
   454  	}
   455  	return inst
   456  }
   457  
   458  func (e *exporter) applications() error {
   459  	applications, err := e.st.AllApplications()
   460  	if err != nil {
   461  		return errors.Trace(err)
   462  	}
   463  	e.logger.Debugf("found %d applications", len(applications))
   464  
   465  	e.units, err = e.readAllUnits()
   466  	if err != nil {
   467  		return errors.Trace(err)
   468  	}
   469  
   470  	meterStatus, err := e.readAllMeterStatus()
   471  	if err != nil {
   472  		return errors.Trace(err)
   473  	}
   474  
   475  	leaders, err := e.st.ApplicationLeaders()
   476  	if err != nil {
   477  		return errors.Trace(err)
   478  	}
   479  
   480  	payloads, err := e.readAllPayloads()
   481  	if err != nil {
   482  		return errors.Trace(err)
   483  	}
   484  
   485  	for _, application := range applications {
   486  		applicationUnits := e.units[application.Name()]
   487  		leader := leaders[application.Name()]
   488  		if err := e.addApplication(addApplicationContext{
   489  			application: application,
   490  			units:       applicationUnits,
   491  			meterStatus: meterStatus,
   492  			leader:      leader,
   493  			payloads:    payloads,
   494  		}); err != nil {
   495  			return errors.Trace(err)
   496  		}
   497  	}
   498  	return nil
   499  }
   500  
   501  func (e *exporter) readAllStorageConstraints() error {
   502  	coll, closer := e.st.getCollection(storageConstraintsC)
   503  	defer closer()
   504  
   505  	storageConstraints := make(map[string]storageConstraintsDoc)
   506  	var doc storageConstraintsDoc
   507  	iter := coll.Find(nil).Iter()
   508  	defer iter.Close()
   509  	for iter.Next(&doc) {
   510  		storageConstraints[e.st.localID(doc.DocID)] = doc
   511  	}
   512  	if err := iter.Err(); err != nil {
   513  		return errors.Annotate(err, "failed to read storage constraints")
   514  	}
   515  	e.logger.Debugf("read %d storage constraint documents", len(storageConstraints))
   516  	e.modelStorageConstraints = storageConstraints
   517  	return nil
   518  }
   519  
   520  func (e *exporter) storageConstraints(doc storageConstraintsDoc) map[string]description.StorageConstraintArgs {
   521  	result := make(map[string]description.StorageConstraintArgs)
   522  	for key, value := range doc.Constraints {
   523  		result[key] = description.StorageConstraintArgs{
   524  			Pool:  value.Pool,
   525  			Size:  value.Size,
   526  			Count: value.Count,
   527  		}
   528  	}
   529  	return result
   530  }
   531  
   532  func (e *exporter) readAllPayloads() (map[string][]payload.FullPayloadInfo, error) {
   533  	result := make(map[string][]payload.FullPayloadInfo)
   534  	all, err := ModelPayloads{db: e.st.database}.ListAll()
   535  	if err != nil {
   536  		return nil, errors.Trace(err)
   537  	}
   538  	for _, payload := range all {
   539  		result[payload.Unit] = append(result[payload.Unit], payload)
   540  	}
   541  	return result, nil
   542  }
   543  
   544  type addApplicationContext struct {
   545  	application *Application
   546  	units       []*Unit
   547  	meterStatus map[string]*meterStatusDoc
   548  	leader      string
   549  	payloads    map[string][]payload.FullPayloadInfo
   550  }
   551  
   552  func (e *exporter) addApplication(ctx addApplicationContext) error {
   553  	application := ctx.application
   554  	appName := application.Name()
   555  	settingsKey := application.settingsKey()
   556  	leadershipKey := leadershipSettingsKey(appName)
   557  	storageConstraintsKey := application.storageConstraintsKey()
   558  
   559  	applicationSettingsDoc, found := e.modelSettings[settingsKey]
   560  	if !found {
   561  		return errors.Errorf("missing settings for application %q", appName)
   562  	}
   563  	leadershipSettingsDoc, found := e.modelSettings[leadershipKey]
   564  	if !found {
   565  		return errors.Errorf("missing leadership settings for application %q", appName)
   566  	}
   567  
   568  	args := description.ApplicationArgs{
   569  		Tag:                  application.ApplicationTag(),
   570  		Series:               application.doc.Series,
   571  		Subordinate:          application.doc.Subordinate,
   572  		CharmURL:             application.doc.CharmURL.String(),
   573  		Channel:              application.doc.Channel,
   574  		CharmModifiedVersion: application.doc.CharmModifiedVersion,
   575  		ForceCharm:           application.doc.ForceCharm,
   576  		Exposed:              application.doc.Exposed,
   577  		MinUnits:             application.doc.MinUnits,
   578  		Settings:             applicationSettingsDoc.Settings,
   579  		Leader:               ctx.leader,
   580  		LeadershipSettings:   leadershipSettingsDoc.Settings,
   581  		MetricsCredentials:   application.doc.MetricCredentials,
   582  	}
   583  	if constraints, found := e.modelStorageConstraints[storageConstraintsKey]; found {
   584  		args.StorageConstraints = e.storageConstraints(constraints)
   585  	}
   586  	exApplication := e.model.AddApplication(args)
   587  	// Find the current application status.
   588  	globalKey := application.globalKey()
   589  	statusArgs, err := e.statusArgs(globalKey)
   590  	if err != nil {
   591  		return errors.Annotatef(err, "status for application %s", appName)
   592  	}
   593  	exApplication.SetStatus(statusArgs)
   594  	exApplication.SetStatusHistory(e.statusHistoryArgs(globalKey))
   595  	exApplication.SetAnnotations(e.getAnnotations(globalKey))
   596  
   597  	constraintsArgs, err := e.constraintsArgs(globalKey)
   598  	if err != nil {
   599  		return errors.Trace(err)
   600  	}
   601  	exApplication.SetConstraints(constraintsArgs)
   602  
   603  	for _, unit := range ctx.units {
   604  		agentKey := unit.globalAgentKey()
   605  		unitMeterStatus, found := ctx.meterStatus[agentKey]
   606  		if !found {
   607  			return errors.Errorf("missing meter status for unit %s", unit.Name())
   608  		}
   609  
   610  		workloadVersion, err := unit.WorkloadVersion()
   611  		if err != nil {
   612  			return errors.Trace(err)
   613  		}
   614  		args := description.UnitArgs{
   615  			Tag:             unit.UnitTag(),
   616  			Machine:         names.NewMachineTag(unit.doc.MachineId),
   617  			WorkloadVersion: workloadVersion,
   618  			PasswordHash:    unit.doc.PasswordHash,
   619  			MeterStatusCode: unitMeterStatus.Code,
   620  			MeterStatusInfo: unitMeterStatus.Info,
   621  		}
   622  		if principalName, isSubordinate := unit.PrincipalName(); isSubordinate {
   623  			args.Principal = names.NewUnitTag(principalName)
   624  		}
   625  		if subs := unit.SubordinateNames(); len(subs) > 0 {
   626  			for _, subName := range subs {
   627  				args.Subordinates = append(args.Subordinates, names.NewUnitTag(subName))
   628  			}
   629  		}
   630  		exUnit := exApplication.AddUnit(args)
   631  
   632  		if err := e.setUnitPayloads(exUnit, ctx.payloads[unit.UnitTag().Id()]); err != nil {
   633  			return errors.Trace(err)
   634  		}
   635  
   636  		// workload uses globalKey, agent uses globalAgentKey,
   637  		// workload version uses globalWorkloadVersionKey.
   638  		globalKey := unit.globalKey()
   639  		statusArgs, err := e.statusArgs(globalKey)
   640  		if err != nil {
   641  			return errors.Annotatef(err, "workload status for unit %s", unit.Name())
   642  		}
   643  		exUnit.SetWorkloadStatus(statusArgs)
   644  		exUnit.SetWorkloadStatusHistory(e.statusHistoryArgs(globalKey))
   645  
   646  		statusArgs, err = e.statusArgs(agentKey)
   647  		if err != nil {
   648  			return errors.Annotatef(err, "agent status for unit %s", unit.Name())
   649  		}
   650  		exUnit.SetAgentStatus(statusArgs)
   651  		exUnit.SetAgentStatusHistory(e.statusHistoryArgs(agentKey))
   652  
   653  		workloadVersionKey := unit.globalWorkloadVersionKey()
   654  		exUnit.SetWorkloadVersionHistory(e.statusHistoryArgs(workloadVersionKey))
   655  
   656  		tools, err := unit.AgentTools()
   657  		if err != nil {
   658  			// This means the tools aren't set, but they should be.
   659  			return errors.Trace(err)
   660  		}
   661  		exUnit.SetTools(description.AgentToolsArgs{
   662  			Version: tools.Version,
   663  			URL:     tools.URL,
   664  			SHA256:  tools.SHA256,
   665  			Size:    tools.Size,
   666  		})
   667  		exUnit.SetAnnotations(e.getAnnotations(globalKey))
   668  
   669  		constraintsArgs, err := e.constraintsArgs(agentKey)
   670  		if err != nil {
   671  			return errors.Trace(err)
   672  		}
   673  		exUnit.SetConstraints(constraintsArgs)
   674  	}
   675  
   676  	return nil
   677  }
   678  
   679  func (e *exporter) setUnitPayloads(exUnit description.Unit, payloads []payload.FullPayloadInfo) error {
   680  	unitID := exUnit.Tag().Id()
   681  	machineID := exUnit.Machine().Id()
   682  	for _, payload := range payloads {
   683  		if payload.Machine != machineID {
   684  			return errors.NotValidf("payload for unit %q reports wrong machine %q (should be %q)", unitID, payload.Machine, machineID)
   685  		}
   686  		args := description.PayloadArgs{
   687  			Name:   payload.Name,
   688  			Type:   payload.Type,
   689  			RawID:  payload.ID,
   690  			State:  payload.Status,
   691  			Labels: payload.Labels,
   692  		}
   693  		exUnit.AddPayload(args)
   694  	}
   695  	return nil
   696  }
   697  
   698  func (e *exporter) relations() error {
   699  	rels, err := e.st.AllRelations()
   700  	if err != nil {
   701  		return errors.Trace(err)
   702  	}
   703  	e.logger.Debugf("read %d relations", len(rels))
   704  
   705  	relationScopes, err := e.readAllRelationScopes()
   706  	if err != nil {
   707  		return errors.Trace(err)
   708  	}
   709  
   710  	for _, relation := range rels {
   711  		exRelation := e.model.AddRelation(description.RelationArgs{
   712  			Id:  relation.Id(),
   713  			Key: relation.String(),
   714  		})
   715  		for _, ep := range relation.Endpoints() {
   716  			exEndPoint := exRelation.AddEndpoint(description.EndpointArgs{
   717  				ApplicationName: ep.ApplicationName,
   718  				Name:            ep.Name,
   719  				Role:            string(ep.Role),
   720  				Interface:       ep.Interface,
   721  				Optional:        ep.Optional,
   722  				Limit:           ep.Limit,
   723  				Scope:           string(ep.Scope),
   724  			})
   725  			// We expect a relationScope and settings for each of the
   726  			// units of the specified application.
   727  			units := e.units[ep.ApplicationName]
   728  			for _, unit := range units {
   729  				ru, err := relation.Unit(unit)
   730  				if err != nil {
   731  					return errors.Trace(err)
   732  				}
   733  				key := ru.key()
   734  				if !relationScopes.Contains(key) {
   735  					return errors.Errorf("missing relation scope for %s and %s", relation, unit.Name())
   736  				}
   737  				settingsDoc, found := e.modelSettings[key]
   738  				if !found {
   739  					return errors.Errorf("missing relation settings for %s and %s", relation, unit.Name())
   740  				}
   741  				exEndPoint.SetUnitSettings(unit.Name(), settingsDoc.Settings)
   742  			}
   743  		}
   744  	}
   745  	return nil
   746  }
   747  
   748  func (e *exporter) spaces() error {
   749  	spaces, err := e.st.AllSpaces()
   750  	if err != nil {
   751  		return errors.Trace(err)
   752  	}
   753  	e.logger.Debugf("read %d spaces", len(spaces))
   754  
   755  	for _, space := range spaces {
   756  		e.model.AddSpace(description.SpaceArgs{
   757  			Name:       space.Name(),
   758  			Public:     space.IsPublic(),
   759  			ProviderID: string(space.ProviderId()),
   760  		})
   761  	}
   762  	return nil
   763  }
   764  
   765  func (e *exporter) linklayerdevices() error {
   766  	linklayerdevices, err := e.st.AllLinkLayerDevices()
   767  	if err != nil {
   768  		return errors.Trace(err)
   769  	}
   770  	e.logger.Debugf("read %d ip devices", len(linklayerdevices))
   771  	for _, device := range linklayerdevices {
   772  		e.model.AddLinkLayerDevice(description.LinkLayerDeviceArgs{
   773  			ProviderID:  string(device.ProviderID()),
   774  			MachineID:   device.MachineID(),
   775  			Name:        device.Name(),
   776  			MTU:         device.MTU(),
   777  			Type:        string(device.Type()),
   778  			MACAddress:  device.MACAddress(),
   779  			IsAutoStart: device.IsAutoStart(),
   780  			IsUp:        device.IsUp(),
   781  			ParentName:  device.ParentName(),
   782  		})
   783  	}
   784  	return nil
   785  }
   786  
   787  func (e *exporter) subnets() error {
   788  	subnets, err := e.st.AllSubnets()
   789  	if err != nil {
   790  		return errors.Trace(err)
   791  	}
   792  	e.logger.Debugf("read %d subnets", len(subnets))
   793  
   794  	for _, subnet := range subnets {
   795  		e.model.AddSubnet(description.SubnetArgs{
   796  			CIDR:             subnet.CIDR(),
   797  			ProviderId:       string(subnet.ProviderId()),
   798  			VLANTag:          subnet.VLANTag(),
   799  			AvailabilityZone: subnet.AvailabilityZone(),
   800  			SpaceName:        subnet.SpaceName(),
   801  		})
   802  	}
   803  	return nil
   804  }
   805  
   806  func (e *exporter) ipaddresses() error {
   807  	ipaddresses, err := e.st.AllIPAddresses()
   808  	if err != nil {
   809  		return errors.Trace(err)
   810  	}
   811  	e.logger.Debugf("read %d ip addresses", len(ipaddresses))
   812  	for _, addr := range ipaddresses {
   813  		e.model.AddIPAddress(description.IPAddressArgs{
   814  			ProviderID:       string(addr.ProviderID()),
   815  			DeviceName:       addr.DeviceName(),
   816  			MachineID:        addr.MachineID(),
   817  			SubnetCIDR:       addr.SubnetCIDR(),
   818  			ConfigMethod:     string(addr.ConfigMethod()),
   819  			Value:            addr.Value(),
   820  			DNSServers:       addr.DNSServers(),
   821  			DNSSearchDomains: addr.DNSSearchDomains(),
   822  			GatewayAddress:   addr.GatewayAddress(),
   823  		})
   824  	}
   825  	return nil
   826  }
   827  
   828  func (e *exporter) sshHostKeys() error {
   829  	machines, err := e.st.AllMachines()
   830  	if err != nil {
   831  		return errors.Trace(err)
   832  	}
   833  	for _, machine := range machines {
   834  		keys, err := e.st.GetSSHHostKeys(machine.MachineTag())
   835  		if errors.IsNotFound(err) {
   836  			continue
   837  		} else if err != nil {
   838  			return errors.Trace(err)
   839  		}
   840  		if len(keys) == 0 {
   841  			continue
   842  		}
   843  		e.model.AddSSHHostKey(description.SSHHostKeyArgs{
   844  			MachineID: machine.Id(),
   845  			Keys:      keys,
   846  		})
   847  	}
   848  	return nil
   849  }
   850  
   851  func (e *exporter) cloudimagemetadata() error {
   852  	cloudimagemetadata, err := e.st.CloudImageMetadataStorage.AllCloudImageMetadata()
   853  	if err != nil {
   854  		return errors.Trace(err)
   855  	}
   856  	e.logger.Debugf("read %d cloudimagemetadata", len(cloudimagemetadata))
   857  	for _, metadata := range cloudimagemetadata {
   858  		e.model.AddCloudImageMetadata(description.CloudImageMetadataArgs{
   859  			Stream:          metadata.Stream,
   860  			Region:          metadata.Region,
   861  			Version:         metadata.Version,
   862  			Series:          metadata.Series,
   863  			Arch:            metadata.Arch,
   864  			VirtType:        metadata.VirtType,
   865  			RootStorageType: metadata.RootStorageType,
   866  			RootStorageSize: metadata.RootStorageSize,
   867  			DateCreated:     metadata.DateCreated,
   868  			Source:          metadata.Source,
   869  			Priority:        metadata.Priority,
   870  			ImageId:         metadata.ImageId,
   871  		})
   872  	}
   873  	return nil
   874  }
   875  
   876  func (e *exporter) actions() error {
   877  	actions, err := e.st.AllActions()
   878  	if err != nil {
   879  		return errors.Trace(err)
   880  	}
   881  	e.logger.Debugf("read %d actions", len(actions))
   882  	for _, action := range actions {
   883  		results, message := action.Results()
   884  		e.model.AddAction(description.ActionArgs{
   885  			Receiver:   action.Receiver(),
   886  			Name:       action.Name(),
   887  			Parameters: action.Parameters(),
   888  			Enqueued:   action.Enqueued(),
   889  			Started:    action.Started(),
   890  			Completed:  action.Completed(),
   891  			Status:     string(action.Status()),
   892  			Results:    results,
   893  			Message:    message,
   894  			Id:         action.Id(),
   895  		})
   896  	}
   897  	return nil
   898  }
   899  
   900  func (e *exporter) readAllRelationScopes() (set.Strings, error) {
   901  	relationScopes, closer := e.st.getCollection(relationScopesC)
   902  	defer closer()
   903  
   904  	docs := []relationScopeDoc{}
   905  	err := relationScopes.Find(nil).All(&docs)
   906  	if err != nil {
   907  		return nil, errors.Annotate(err, "cannot get all relation scopes")
   908  	}
   909  	e.logger.Debugf("found %d relationScope docs", len(docs))
   910  
   911  	result := set.NewStrings()
   912  	for _, doc := range docs {
   913  		result.Add(doc.Key)
   914  	}
   915  	return result, nil
   916  }
   917  
   918  func (e *exporter) readAllUnits() (map[string][]*Unit, error) {
   919  	unitsCollection, closer := e.st.getCollection(unitsC)
   920  	defer closer()
   921  
   922  	docs := []unitDoc{}
   923  	err := unitsCollection.Find(nil).All(&docs)
   924  	if err != nil {
   925  		return nil, errors.Annotate(err, "cannot get all units")
   926  	}
   927  	e.logger.Debugf("found %d unit docs", len(docs))
   928  	result := make(map[string][]*Unit)
   929  	for _, doc := range docs {
   930  		units := result[doc.Application]
   931  		result[doc.Application] = append(units, newUnit(e.st, &doc))
   932  	}
   933  	return result, nil
   934  }
   935  
   936  func (e *exporter) readAllMeterStatus() (map[string]*meterStatusDoc, error) {
   937  	meterStatuses, closer := e.st.getCollection(meterStatusC)
   938  	defer closer()
   939  
   940  	docs := []meterStatusDoc{}
   941  	err := meterStatuses.Find(nil).All(&docs)
   942  	if err != nil {
   943  		return nil, errors.Annotate(err, "cannot get all meter status docs")
   944  	}
   945  	e.logger.Debugf("found %d meter status docs", len(docs))
   946  	result := make(map[string]*meterStatusDoc)
   947  	for _, doc := range docs {
   948  		result[e.st.localID(doc.DocID)] = &doc
   949  	}
   950  	return result, nil
   951  }
   952  
   953  func (e *exporter) readLastConnectionTimes() (map[string]time.Time, error) {
   954  	lastConnections, closer := e.st.getCollection(modelUserLastConnectionC)
   955  	defer closer()
   956  
   957  	var docs []modelUserLastConnectionDoc
   958  	if err := lastConnections.Find(nil).All(&docs); err != nil {
   959  		return nil, errors.Trace(err)
   960  	}
   961  
   962  	result := make(map[string]time.Time)
   963  	for _, doc := range docs {
   964  		result[doc.UserName] = doc.LastConnection.UTC()
   965  	}
   966  	return result, nil
   967  }
   968  
   969  func (e *exporter) readAllAnnotations() error {
   970  	annotations, closer := e.st.getCollection(annotationsC)
   971  	defer closer()
   972  
   973  	var docs []annotatorDoc
   974  	if err := annotations.Find(nil).All(&docs); err != nil {
   975  		return errors.Trace(err)
   976  	}
   977  	e.logger.Debugf("read %d annotations docs", len(docs))
   978  
   979  	e.annotations = make(map[string]annotatorDoc)
   980  	for _, doc := range docs {
   981  		e.annotations[doc.GlobalKey] = doc
   982  	}
   983  	return nil
   984  }
   985  
   986  func (e *exporter) readAllConstraints() error {
   987  	constraintsCollection, closer := e.st.getCollection(constraintsC)
   988  	defer closer()
   989  
   990  	// Since the constraintsDoc doesn't include any global key or _id
   991  	// fields, we can't just deserialize the entire collection into a slice
   992  	// of docs, so we get them all out with bson maps.
   993  	var docs []bson.M
   994  	err := constraintsCollection.Find(nil).All(&docs)
   995  	if err != nil {
   996  		return errors.Annotate(err, "failed to read constraints collection")
   997  	}
   998  
   999  	e.logger.Debugf("read %d constraints docs", len(docs))
  1000  	e.constraints = make(map[string]bson.M)
  1001  	for _, doc := range docs {
  1002  		docId, ok := doc["_id"].(string)
  1003  		if !ok {
  1004  			return errors.Errorf("expected string, got %s (%T)", doc["_id"], doc["_id"])
  1005  		}
  1006  		id := e.st.localID(docId)
  1007  		e.constraints[id] = doc
  1008  		e.logger.Debugf("doc[%q] = %#v", id, doc)
  1009  	}
  1010  	return nil
  1011  }
  1012  
  1013  // getAnnotations doesn't really care if there are any there or not
  1014  // for the key, but if they were there, they are removed so we can
  1015  // check at the end of the export for anything we have forgotten.
  1016  func (e *exporter) getAnnotations(key string) map[string]string {
  1017  	result, found := e.annotations[key]
  1018  	if found {
  1019  		delete(e.annotations, key)
  1020  	}
  1021  	return result.Annotations
  1022  }
  1023  
  1024  func (e *exporter) readAllSettings() error {
  1025  	settings, closer := e.st.getCollection(settingsC)
  1026  	defer closer()
  1027  
  1028  	var docs []settingsDoc
  1029  	if err := settings.Find(nil).All(&docs); err != nil {
  1030  		return errors.Trace(err)
  1031  	}
  1032  
  1033  	e.modelSettings = make(map[string]settingsDoc)
  1034  	for _, doc := range docs {
  1035  		key := e.st.localID(doc.DocID)
  1036  		e.modelSettings[key] = doc
  1037  	}
  1038  	return nil
  1039  }
  1040  
  1041  func (e *exporter) readAllStatuses() error {
  1042  	statuses, closer := e.st.getCollection(statusesC)
  1043  	defer closer()
  1044  
  1045  	var docs []bson.M
  1046  	err := statuses.Find(nil).All(&docs)
  1047  	if err != nil {
  1048  		return errors.Annotate(err, "failed to read status collection")
  1049  	}
  1050  
  1051  	e.logger.Debugf("read %d status documents", len(docs))
  1052  	e.status = make(map[string]bson.M)
  1053  	for _, doc := range docs {
  1054  		docId, ok := doc["_id"].(string)
  1055  		if !ok {
  1056  			return errors.Errorf("expected string, got %s (%T)", doc["_id"], doc["_id"])
  1057  		}
  1058  		id := e.st.localID(docId)
  1059  		e.status[id] = doc
  1060  	}
  1061  
  1062  	return nil
  1063  }
  1064  
  1065  func (e *exporter) readAllStatusHistory() error {
  1066  	statuses, closer := e.st.getCollection(statusesHistoryC)
  1067  	defer closer()
  1068  
  1069  	count := 0
  1070  	e.statusHistory = make(map[string][]historicalStatusDoc)
  1071  	var doc historicalStatusDoc
  1072  	// In tests, sorting by time can leave the results
  1073  	// underconstrained - include document id for deterministic
  1074  	// ordering in those cases.
  1075  	iter := statuses.Find(nil).Sort("-updated", "-_id").Iter()
  1076  	defer iter.Close()
  1077  	for iter.Next(&doc) {
  1078  		history := e.statusHistory[doc.GlobalKey]
  1079  		e.statusHistory[doc.GlobalKey] = append(history, doc)
  1080  		count++
  1081  	}
  1082  
  1083  	if err := iter.Err(); err != nil {
  1084  		return errors.Annotate(err, "failed to read status history collection")
  1085  	}
  1086  
  1087  	e.logger.Debugf("read %d status history documents", count)
  1088  
  1089  	return nil
  1090  }
  1091  
  1092  func (e *exporter) statusArgs(globalKey string) (description.StatusArgs, error) {
  1093  	result := description.StatusArgs{}
  1094  	statusDoc, found := e.status[globalKey]
  1095  	if !found {
  1096  		return result, errors.NotFoundf("status data for %s", globalKey)
  1097  	}
  1098  
  1099  	status, ok := statusDoc["status"].(string)
  1100  	if !ok {
  1101  		return result, errors.Errorf("expected string for status, got %T", statusDoc["status"])
  1102  	}
  1103  	info, ok := statusDoc["statusinfo"].(string)
  1104  	if !ok {
  1105  		return result, errors.Errorf("expected string for statusinfo, got %T", statusDoc["statusinfo"])
  1106  	}
  1107  	// data is an embedded map and comes out as a bson.M
  1108  	// A bson.M is map[string]interface{}, so we can type cast it.
  1109  	data, ok := statusDoc["statusdata"].(bson.M)
  1110  	if !ok {
  1111  		return result, errors.Errorf("expected map for data, got %T", statusDoc["statusdata"])
  1112  	}
  1113  	dataMap := map[string]interface{}(data)
  1114  	updated, ok := statusDoc["updated"].(int64)
  1115  	if !ok {
  1116  		return result, errors.Errorf("expected int64 for updated, got %T", statusDoc["updated"])
  1117  	}
  1118  
  1119  	result.Value = status
  1120  	result.Message = info
  1121  	result.Data = dataMap
  1122  	result.Updated = time.Unix(0, updated)
  1123  	return result, nil
  1124  }
  1125  
  1126  func (e *exporter) statusHistoryArgs(globalKey string) []description.StatusArgs {
  1127  	history := e.statusHistory[globalKey]
  1128  	result := make([]description.StatusArgs, len(history))
  1129  	e.logger.Debugf("found %d status history docs for %s", len(history), globalKey)
  1130  	for i, doc := range history {
  1131  		result[i] = description.StatusArgs{
  1132  			Value:   string(doc.Status),
  1133  			Message: doc.StatusInfo,
  1134  			Data:    doc.StatusData,
  1135  			Updated: time.Unix(0, doc.Updated),
  1136  		}
  1137  	}
  1138  
  1139  	return result
  1140  }
  1141  
  1142  func (e *exporter) constraintsArgs(globalKey string) (description.ConstraintsArgs, error) {
  1143  	doc, found := e.constraints[globalKey]
  1144  	if !found {
  1145  		// No constraints for this key.
  1146  		e.logger.Debugf("no constraints found for key %q", globalKey)
  1147  		return description.ConstraintsArgs{}, nil
  1148  	}
  1149  	// We capture any type error using a closure to avoid having to return
  1150  	// multiple values from the optional functions. This does mean that we will
  1151  	// only report on the last one, but that is fine as there shouldn't be any.
  1152  	var optionalErr error
  1153  	optionalString := func(name string) string {
  1154  		switch value := doc[name].(type) {
  1155  		case nil:
  1156  		case string:
  1157  			return value
  1158  		default:
  1159  			optionalErr = errors.Errorf("expected uint64 for %s, got %T", name, value)
  1160  		}
  1161  		return ""
  1162  	}
  1163  	optionalInt := func(name string) uint64 {
  1164  		switch value := doc[name].(type) {
  1165  		case nil:
  1166  		case uint64:
  1167  			return value
  1168  		case int64:
  1169  			return uint64(value)
  1170  		default:
  1171  			optionalErr = errors.Errorf("expected uint64 for %s, got %T", name, value)
  1172  		}
  1173  		return 0
  1174  	}
  1175  	optionalStringSlice := func(name string) []string {
  1176  		switch value := doc[name].(type) {
  1177  		case nil:
  1178  		case []string:
  1179  			return value
  1180  		default:
  1181  			optionalErr = errors.Errorf("expected []string] for %s, got %T", name, value)
  1182  		}
  1183  		return nil
  1184  	}
  1185  	result := description.ConstraintsArgs{
  1186  		Architecture: optionalString("arch"),
  1187  		Container:    optionalString("container"),
  1188  		CpuCores:     optionalInt("cpucores"),
  1189  		CpuPower:     optionalInt("cpupower"),
  1190  		InstanceType: optionalString("instancetype"),
  1191  		Memory:       optionalInt("mem"),
  1192  		RootDisk:     optionalInt("rootdisk"),
  1193  		Spaces:       optionalStringSlice("spaces"),
  1194  		Tags:         optionalStringSlice("tags"),
  1195  		VirtType:     optionalString("virttype"),
  1196  	}
  1197  	if optionalErr != nil {
  1198  		return description.ConstraintsArgs{}, errors.Trace(optionalErr)
  1199  	}
  1200  	return result, nil
  1201  }
  1202  
  1203  func (e *exporter) logExtras() {
  1204  	// As annotations are saved into the model, they are removed from the
  1205  	// exporter's map. If there are any left at the end, we are missing
  1206  	// things. Not an error just now, just a warning that we have missed
  1207  	// something. Could potentially be an error at a later date when
  1208  	// migrations are complete (but probably not).
  1209  	for key, doc := range e.annotations {
  1210  		e.logger.Warningf("unexported annotation for %s, %s", doc.Tag, key)
  1211  	}
  1212  }
  1213  
  1214  func (e *exporter) storage() error {
  1215  	if err := e.volumes(); err != nil {
  1216  		return errors.Trace(err)
  1217  	}
  1218  	if err := e.filesystems(); err != nil {
  1219  		return errors.Trace(err)
  1220  	}
  1221  	if err := e.storageInstances(); err != nil {
  1222  		return errors.Trace(err)
  1223  	}
  1224  	if err := e.storagePools(); err != nil {
  1225  		return errors.Trace(err)
  1226  	}
  1227  	return nil
  1228  }
  1229  
  1230  func (e *exporter) volumes() error {
  1231  	coll, closer := e.st.getCollection(volumesC)
  1232  	defer closer()
  1233  
  1234  	attachments, err := e.readVolumeAttachments()
  1235  	if err != nil {
  1236  		return errors.Trace(err)
  1237  	}
  1238  
  1239  	var doc volumeDoc
  1240  	iter := coll.Find(nil).Sort("_id").Iter()
  1241  	defer iter.Close()
  1242  	for iter.Next(&doc) {
  1243  		vol := &volume{e.st, doc}
  1244  		if err := e.addVolume(vol, attachments[doc.Name]); err != nil {
  1245  			return errors.Trace(err)
  1246  		}
  1247  	}
  1248  	if err := iter.Err(); err != nil {
  1249  		return errors.Annotate(err, "failed to read volumes")
  1250  	}
  1251  	return nil
  1252  }
  1253  
  1254  func (e *exporter) addVolume(vol *volume, volAttachments []volumeAttachmentDoc) error {
  1255  	args := description.VolumeArgs{
  1256  		Tag:     vol.VolumeTag(),
  1257  		Binding: vol.LifeBinding(),
  1258  	}
  1259  	if tag, err := vol.StorageInstance(); err == nil {
  1260  		// only returns an error when no storage tag.
  1261  		args.Storage = tag
  1262  	} else {
  1263  		if !errors.IsNotAssigned(err) {
  1264  			// This is an unexpected error.
  1265  			return errors.Trace(err)
  1266  		}
  1267  	}
  1268  	logger.Debugf("addVolume: %#v", vol.doc)
  1269  	if info, err := vol.Info(); err == nil {
  1270  		logger.Debugf("  info %#v", info)
  1271  		args.Provisioned = true
  1272  		args.Size = info.Size
  1273  		args.Pool = info.Pool
  1274  		args.HardwareID = info.HardwareId
  1275  		args.VolumeID = info.VolumeId
  1276  		args.Persistent = info.Persistent
  1277  	} else {
  1278  		params, _ := vol.Params()
  1279  		logger.Debugf("  params %#v", params)
  1280  		args.Size = params.Size
  1281  		args.Pool = params.Pool
  1282  	}
  1283  
  1284  	globalKey := vol.globalKey()
  1285  	statusArgs, err := e.statusArgs(globalKey)
  1286  	if err != nil {
  1287  		return errors.Annotatef(err, "status for volume %s", vol.doc.Name)
  1288  	}
  1289  
  1290  	exVolume := e.model.AddVolume(args)
  1291  	exVolume.SetStatus(statusArgs)
  1292  	exVolume.SetStatusHistory(e.statusHistoryArgs(globalKey))
  1293  	if count := len(volAttachments); count != vol.doc.AttachmentCount {
  1294  		return errors.Errorf("volume attachment count mismatch, have %d, expected %d",
  1295  			count, vol.doc.AttachmentCount)
  1296  	}
  1297  	for _, doc := range volAttachments {
  1298  		va := volumeAttachment{doc}
  1299  		logger.Debugf("  attachment %#v", doc)
  1300  		args := description.VolumeAttachmentArgs{
  1301  			Machine: va.Machine(),
  1302  		}
  1303  		if info, err := va.Info(); err == nil {
  1304  			logger.Debugf("    info %#v", info)
  1305  			args.Provisioned = true
  1306  			args.ReadOnly = info.ReadOnly
  1307  			args.DeviceName = info.DeviceName
  1308  			args.DeviceLink = info.DeviceLink
  1309  			args.BusAddress = info.BusAddress
  1310  		} else {
  1311  			params, _ := va.Params()
  1312  			logger.Debugf("    params %#v", params)
  1313  			args.ReadOnly = params.ReadOnly
  1314  		}
  1315  		exVolume.AddAttachment(args)
  1316  	}
  1317  	return nil
  1318  }
  1319  
  1320  func (e *exporter) readVolumeAttachments() (map[string][]volumeAttachmentDoc, error) {
  1321  	coll, closer := e.st.getCollection(volumeAttachmentsC)
  1322  	defer closer()
  1323  
  1324  	result := make(map[string][]volumeAttachmentDoc)
  1325  	var doc volumeAttachmentDoc
  1326  	var count int
  1327  	iter := coll.Find(nil).Iter()
  1328  	defer iter.Close()
  1329  	for iter.Next(&doc) {
  1330  		result[doc.Volume] = append(result[doc.Volume], doc)
  1331  		count++
  1332  	}
  1333  	if err := iter.Err(); err != nil {
  1334  		return nil, errors.Annotate(err, "failed to read volumes attachments")
  1335  	}
  1336  	e.logger.Debugf("read %d volume attachment documents", count)
  1337  	return result, nil
  1338  }
  1339  
  1340  func (e *exporter) filesystems() error {
  1341  	coll, closer := e.st.getCollection(filesystemsC)
  1342  	defer closer()
  1343  
  1344  	attachments, err := e.readFilesystemAttachments()
  1345  	if err != nil {
  1346  		return errors.Trace(err)
  1347  	}
  1348  
  1349  	var doc filesystemDoc
  1350  	iter := coll.Find(nil).Sort("_id").Iter()
  1351  	defer iter.Close()
  1352  	for iter.Next(&doc) {
  1353  		fs := &filesystem{e.st, doc}
  1354  		if err := e.addFilesystem(fs, attachments[doc.FilesystemId]); err != nil {
  1355  			return errors.Trace(err)
  1356  		}
  1357  	}
  1358  	if err := iter.Err(); err != nil {
  1359  		return errors.Annotate(err, "failed to read filesystems")
  1360  	}
  1361  	return nil
  1362  }
  1363  
  1364  func (e *exporter) addFilesystem(fs *filesystem, fsAttachments []filesystemAttachmentDoc) error {
  1365  	// Here we don't care about the cases where the filesystem is not assigned to storage instances
  1366  	// nor no backing volues. In both those situations we have empty tags.
  1367  	storage, _ := fs.Storage()
  1368  	volume, _ := fs.Volume()
  1369  	args := description.FilesystemArgs{
  1370  		Tag:     fs.FilesystemTag(),
  1371  		Storage: storage,
  1372  		Volume:  volume,
  1373  		Binding: fs.LifeBinding(),
  1374  	}
  1375  	logger.Debugf("addFilesystem: %#v", fs.doc)
  1376  	if info, err := fs.Info(); err == nil {
  1377  		logger.Debugf("  info %#v", info)
  1378  		args.Provisioned = true
  1379  		args.Size = info.Size
  1380  		args.Pool = info.Pool
  1381  		args.FilesystemID = info.FilesystemId
  1382  	} else {
  1383  		params, _ := fs.Params()
  1384  		logger.Debugf("  params %#v", params)
  1385  		args.Size = params.Size
  1386  		args.Pool = params.Pool
  1387  	}
  1388  
  1389  	globalKey := fs.globalKey()
  1390  	statusArgs, err := e.statusArgs(globalKey)
  1391  	if err != nil {
  1392  		return errors.Annotatef(err, "status for filesystem %s", fs.doc.FilesystemId)
  1393  	}
  1394  
  1395  	exFilesystem := e.model.AddFilesystem(args)
  1396  	exFilesystem.SetStatus(statusArgs)
  1397  	exFilesystem.SetStatusHistory(e.statusHistoryArgs(globalKey))
  1398  	if count := len(fsAttachments); count != fs.doc.AttachmentCount {
  1399  		return errors.Errorf("filesystem attachment count mismatch, have %d, expected %d",
  1400  			count, fs.doc.AttachmentCount)
  1401  	}
  1402  	for _, doc := range fsAttachments {
  1403  		va := filesystemAttachment{doc}
  1404  		logger.Debugf("  attachment %#v", doc)
  1405  		args := description.FilesystemAttachmentArgs{
  1406  			Machine: va.Machine(),
  1407  		}
  1408  		if info, err := va.Info(); err == nil {
  1409  			logger.Debugf("    info %#v", info)
  1410  			args.Provisioned = true
  1411  			args.ReadOnly = info.ReadOnly
  1412  			args.MountPoint = info.MountPoint
  1413  		} else {
  1414  			params, _ := va.Params()
  1415  			logger.Debugf("    params %#v", params)
  1416  			args.ReadOnly = params.ReadOnly
  1417  			args.MountPoint = params.Location
  1418  		}
  1419  		exFilesystem.AddAttachment(args)
  1420  	}
  1421  	return nil
  1422  }
  1423  
  1424  func (e *exporter) readFilesystemAttachments() (map[string][]filesystemAttachmentDoc, error) {
  1425  	coll, closer := e.st.getCollection(filesystemAttachmentsC)
  1426  	defer closer()
  1427  
  1428  	result := make(map[string][]filesystemAttachmentDoc)
  1429  	var doc filesystemAttachmentDoc
  1430  	var count int
  1431  	iter := coll.Find(nil).Iter()
  1432  	defer iter.Close()
  1433  	for iter.Next(&doc) {
  1434  		result[doc.Filesystem] = append(result[doc.Filesystem], doc)
  1435  		count++
  1436  	}
  1437  	if err := iter.Err(); err != nil {
  1438  		return nil, errors.Annotate(err, "failed to read filesystem attachments")
  1439  	}
  1440  	e.logger.Debugf("read %d filesystem attachment documents", count)
  1441  	return result, nil
  1442  }
  1443  
  1444  func (e *exporter) storageInstances() error {
  1445  	coll, closer := e.st.getCollection(storageInstancesC)
  1446  	defer closer()
  1447  
  1448  	attachments, err := e.readStorageAttachments()
  1449  	if err != nil {
  1450  		return errors.Trace(err)
  1451  	}
  1452  
  1453  	var doc storageInstanceDoc
  1454  	iter := coll.Find(nil).Sort("_id").Iter()
  1455  	defer iter.Close()
  1456  	for iter.Next(&doc) {
  1457  		instance := &storageInstance{e.st, doc}
  1458  		if err := e.addStorage(instance, attachments[doc.Id]); err != nil {
  1459  			return errors.Trace(err)
  1460  		}
  1461  	}
  1462  	if err := iter.Err(); err != nil {
  1463  		return errors.Annotate(err, "failed to read storage instances")
  1464  	}
  1465  	return nil
  1466  }
  1467  
  1468  func (e *exporter) addStorage(instance *storageInstance, attachments []names.UnitTag) error {
  1469  	args := description.StorageArgs{
  1470  		Tag:         instance.StorageTag(),
  1471  		Kind:        instance.Kind().String(),
  1472  		Owner:       instance.Owner(),
  1473  		Name:        instance.StorageName(),
  1474  		Attachments: attachments,
  1475  	}
  1476  	e.model.AddStorage(args)
  1477  	return nil
  1478  }
  1479  
  1480  func (e *exporter) readStorageAttachments() (map[string][]names.UnitTag, error) {
  1481  	coll, closer := e.st.getCollection(storageAttachmentsC)
  1482  	defer closer()
  1483  
  1484  	result := make(map[string][]names.UnitTag)
  1485  	var doc storageAttachmentDoc
  1486  	var count int
  1487  	iter := coll.Find(nil).Iter()
  1488  	defer iter.Close()
  1489  	for iter.Next(&doc) {
  1490  		unit := names.NewUnitTag(doc.Unit)
  1491  		result[doc.StorageInstance] = append(result[doc.StorageInstance], unit)
  1492  		count++
  1493  	}
  1494  	if err := iter.Err(); err != nil {
  1495  		return nil, errors.Annotate(err, "failed to read storage attachments")
  1496  	}
  1497  	e.logger.Debugf("read %d storage attachment documents", count)
  1498  	return result, nil
  1499  }
  1500  
  1501  func (e *exporter) storagePools() error {
  1502  	registry, err := e.st.storageProviderRegistry()
  1503  	if err != nil {
  1504  		return errors.Annotate(err, "getting provider registry")
  1505  	}
  1506  	pm := poolmanager.New(storagePoolSettingsManager{e: e}, registry)
  1507  	poolConfigs, err := pm.List()
  1508  	if err != nil {
  1509  		return errors.Annotate(err, "listing pools")
  1510  	}
  1511  	for _, cfg := range poolConfigs {
  1512  		e.model.AddStoragePool(description.StoragePoolArgs{
  1513  			Name:       cfg.Name(),
  1514  			Provider:   string(cfg.Provider()),
  1515  			Attributes: cfg.Attrs(),
  1516  		})
  1517  	}
  1518  	return nil
  1519  }
  1520  
  1521  type storagePoolSettingsManager struct {
  1522  	poolmanager.SettingsManager
  1523  	e *exporter
  1524  }
  1525  
  1526  func (m storagePoolSettingsManager) ListSettings(keyPrefix string) (map[string]map[string]interface{}, error) {
  1527  	result := make(map[string]map[string]interface{})
  1528  	for key, doc := range m.e.modelSettings {
  1529  		if strings.HasPrefix(key, keyPrefix) {
  1530  			result[key] = doc.Settings
  1531  		}
  1532  	}
  1533  	return result, nil
  1534  }