github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/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  	"encoding/hex"
     8  	"fmt"
     9  	"reflect"
    10  	"strconv"
    11  	"time"
    12  
    13  	"github.com/juju/charm/v12"
    14  	"github.com/juju/collections/set"
    15  	"github.com/juju/collections/transform"
    16  	"github.com/juju/description/v5"
    17  	"github.com/juju/errors"
    18  	"github.com/juju/loggo"
    19  	"github.com/juju/mgo/v3/bson"
    20  	"github.com/juju/mgo/v3/txn"
    21  	"github.com/juju/names/v5"
    22  	"github.com/juju/version/v2"
    23  
    24  	"github.com/juju/juju/cloud"
    25  	"github.com/juju/juju/controller"
    26  	corebase "github.com/juju/juju/core/base"
    27  	corecharm "github.com/juju/juju/core/charm"
    28  	"github.com/juju/juju/core/constraints"
    29  	"github.com/juju/juju/core/container"
    30  	"github.com/juju/juju/core/instance"
    31  	"github.com/juju/juju/core/network"
    32  	"github.com/juju/juju/core/payloads"
    33  	"github.com/juju/juju/core/permission"
    34  	"github.com/juju/juju/core/status"
    35  	"github.com/juju/juju/environs/config"
    36  	secretsprovider "github.com/juju/juju/secrets/provider"
    37  	"github.com/juju/juju/state/cloudimagemetadata"
    38  	"github.com/juju/juju/storage"
    39  	"github.com/juju/juju/storage/poolmanager"
    40  	"github.com/juju/juju/storage/provider"
    41  	"github.com/juju/juju/tools"
    42  )
    43  
    44  // Import the database agnostic model representation into the database.
    45  func (ctrl *Controller) Import(model description.Model) (_ *Model, _ *State, err error) {
    46  	st, err := ctrl.pool.SystemState()
    47  	if err != nil {
    48  		return nil, nil, errors.Trace(err)
    49  	}
    50  	modelUUID := model.Tag().Id()
    51  	logger := loggo.GetLogger("juju.state.import-model")
    52  	logger.Debugf("import starting for model %s", modelUUID)
    53  
    54  	// At this stage, attempting to import a model with the same
    55  	// UUID as an existing model will error.
    56  	if modelExists, err := st.ModelExists(modelUUID); err != nil {
    57  		return nil, nil, errors.Trace(err)
    58  	} else if modelExists {
    59  		// We have an existing matching model.
    60  		return nil, nil, errors.AlreadyExistsf("model %s", modelUUID)
    61  	}
    62  
    63  	// Unfortunately a version was released that exports v4 models
    64  	// with the Type field blank. Treat this as IAAS.
    65  	modelType := ModelTypeIAAS
    66  	if model.Type() != "" {
    67  		modelType, err = ParseModelType(model.Type())
    68  		if err != nil {
    69  			return nil, nil, errors.Trace(err)
    70  		}
    71  	}
    72  
    73  	// Create the model.
    74  	cfg, err := modelConfig(model.Config())
    75  	if err != nil {
    76  		return nil, nil, errors.Trace(err)
    77  	}
    78  	args := ModelArgs{
    79  		Type:                    modelType,
    80  		CloudName:               model.Cloud(),
    81  		CloudRegion:             model.CloudRegion(),
    82  		Config:                  cfg,
    83  		Owner:                   model.Owner(),
    84  		MigrationMode:           MigrationModeImporting,
    85  		EnvironVersion:          model.EnvironVersion(),
    86  		PasswordHash:            model.PasswordHash(),
    87  		StorageProviderRegistry: storage.StaticProviderRegistry{},
    88  	}
    89  	if creds := model.CloudCredential(); creds != nil {
    90  		// Need to add credential or make sure an existing credential
    91  		// matches.
    92  		// TODO: there really should be a way to create a cloud credential
    93  		// tag in the names package from the cloud, owner and name.
    94  		credID := fmt.Sprintf("%s/%s/%s", creds.Cloud(), creds.Owner(), creds.Name())
    95  		if !names.IsValidCloudCredential(credID) {
    96  			return nil, nil, errors.NotValidf("cloud credential ID %q", credID)
    97  		}
    98  		credTag := names.NewCloudCredentialTag(credID)
    99  
   100  		existingCreds, err := st.CloudCredential(credTag)
   101  
   102  		if errors.IsNotFound(err) {
   103  			credential := cloud.NewCredential(
   104  				cloud.AuthType(creds.AuthType()),
   105  				creds.Attributes())
   106  			if err := st.UpdateCloudCredential(credTag, credential); err != nil {
   107  				return nil, nil, errors.Trace(err)
   108  			}
   109  		} else if err != nil {
   110  			return nil, nil, errors.Trace(err)
   111  		} else {
   112  			// ensure existing creds match
   113  			if existingCreds.AuthType != creds.AuthType() {
   114  				return nil, nil, errors.Errorf("credential auth type mismatch: %q != %q", existingCreds.AuthType, creds.AuthType())
   115  			}
   116  			if !reflect.DeepEqual(existingCreds.Attributes, creds.Attributes()) {
   117  				return nil, nil, errors.Errorf("credential attribute mismatch: %v != %v", existingCreds.Attributes, creds.Attributes())
   118  			}
   119  			if existingCreds.Revoked {
   120  				return nil, nil, errors.Errorf("credential %q is revoked", credID)
   121  			}
   122  		}
   123  
   124  		args.CloudCredential = credTag
   125  	}
   126  	dbModel, newSt, err := ctrl.NewModel(args)
   127  	if err != nil {
   128  		return nil, nil, errors.Trace(err)
   129  	}
   130  	logger.Debugf("model created %s/%s", dbModel.Owner().Id(), dbModel.Name())
   131  	defer func() {
   132  		if err != nil {
   133  			newSt.Close()
   134  		}
   135  	}()
   136  
   137  	// We don't actually care what the old model status was, because we are
   138  	// going to set it to busy, with a message of migrating.
   139  	if err := dbModel.SetStatus(status.StatusInfo{
   140  		Status:  status.Busy,
   141  		Message: "importing",
   142  	}); err != nil {
   143  		return nil, nil, errors.Trace(err)
   144  	}
   145  
   146  	// I would have loved to use import, but that is a reserved word.
   147  	restore := importer{
   148  		st:      newSt,
   149  		dbModel: dbModel,
   150  		model:   model,
   151  		logger:  logger,
   152  	}
   153  	if err := restore.sequences(); err != nil {
   154  		return nil, nil, errors.Annotate(err, "sequences")
   155  	}
   156  	// We need to import the sequences first as we may add blocks
   157  	// in the modelExtras which will touch the block sequence.
   158  	if err := restore.modelExtras(); err != nil {
   159  		return nil, nil, errors.Annotate(err, "base model aspects")
   160  	}
   161  	if err := newSt.SetModelConstraints(restore.constraints(model.Constraints())); err != nil {
   162  		return nil, nil, errors.Annotate(err, "model constraints")
   163  	}
   164  	if err := restore.sshHostKeys(); err != nil {
   165  		return nil, nil, errors.Annotate(err, "sshHostKeys")
   166  	}
   167  	if err := restore.cloudimagemetadata(); err != nil {
   168  		return nil, nil, errors.Annotate(err, "cloudimagemetadata")
   169  	}
   170  	if err := restore.actions(); err != nil {
   171  		return nil, nil, errors.Annotate(err, "actions")
   172  	}
   173  	if err := restore.operations(); err != nil {
   174  		return nil, nil, errors.Annotate(err, "operations")
   175  	}
   176  
   177  	if err := restore.modelUsers(); err != nil {
   178  		return nil, nil, errors.Annotate(err, "modelUsers")
   179  	}
   180  	// Spaces are needed to migrate Subnets
   181  	if err := restore.spaces(); err != nil {
   182  		return nil, nil, errors.Annotate(err, "spaces")
   183  	}
   184  	// Subnets are needed to migrate machine portsDocs
   185  	if err := restore.subnets(); err != nil {
   186  		return nil, nil, errors.Annotate(err, "subnets")
   187  	}
   188  	if err := restore.machines(); err != nil {
   189  		return nil, nil, errors.Annotate(err, "machines")
   190  	}
   191  	if err := restore.applications(); err != nil {
   192  		return nil, nil, errors.Annotate(err, "applications")
   193  	}
   194  	if err := restore.remoteApplications(); err != nil {
   195  		return nil, nil, errors.Annotate(err, "remoteapplications")
   196  	}
   197  	if err := restore.firewallRules(); err != nil {
   198  		return nil, nil, errors.Annotate(err, "firewallrules")
   199  	}
   200  	if err := restore.relations(); err != nil {
   201  		return nil, nil, errors.Annotate(err, "relations")
   202  	}
   203  	if err := restore.remoteEntities(); err != nil {
   204  		return nil, nil, errors.Annotate(err, "remoteentitites")
   205  	}
   206  	if err := restore.externalControllers(); err != nil {
   207  		return nil, nil, errors.Annotate(err, "externalcontrollers")
   208  	}
   209  	if err := restore.relationNetworks(); err != nil {
   210  		return nil, nil, errors.Annotate(err, "relationnetworks")
   211  	}
   212  	if err := restore.linklayerdevices(); err != nil {
   213  		return nil, nil, errors.Annotate(err, "linklayerdevices")
   214  	}
   215  	if err := restore.ipAddresses(); err != nil {
   216  		return nil, nil, errors.Annotate(err, "ipAddresses")
   217  	}
   218  	if err := restore.storage(); err != nil {
   219  		return nil, nil, errors.Annotate(err, "storage")
   220  	}
   221  	if err := restore.secretBackend(); err != nil {
   222  		return nil, nil, errors.Annotate(err, "secret backend")
   223  	}
   224  	if err := restore.secrets(); err != nil {
   225  		return nil, nil, errors.Annotate(err, "secrets")
   226  	}
   227  	if err := restore.remoteSecrets(); err != nil {
   228  		return nil, nil, errors.Annotate(err, "remote secrets")
   229  	}
   230  
   231  	// NOTE: at the end of the import make sure that the mode of the model
   232  	// is set to "imported" not "active" (or whatever we call it). This way
   233  	// we don't start model workers for it before the migration process
   234  	// is complete.
   235  
   236  	// Update the sequences to match that the source.
   237  
   238  	if err := dbModel.SetSLA(
   239  		model.SLA().Level(),
   240  		model.SLA().Owner(),
   241  		[]byte(model.SLA().Credentials()),
   242  	); err != nil {
   243  		return nil, nil, errors.Trace(err)
   244  	}
   245  
   246  	if MeterStatusFromString(model.MeterStatus().Code()).String() != MeterNotAvailable.String() {
   247  		if err := dbModel.SetMeterStatus(model.MeterStatus().Code(), model.MeterStatus().Info()); err != nil {
   248  			return nil, nil, errors.Trace(err)
   249  		}
   250  	}
   251  
   252  	logger.Debugf("import success")
   253  	return dbModel, newSt, nil
   254  }
   255  
   256  // modelConfig creates a config for the model being imported.
   257  func modelConfig(attrs map[string]interface{}) (*config.Config, error) {
   258  	// If the tools version is before 2.9.35, the default-series
   259  	// value is cleared. This matches an upgrade step for 2.9.35
   260  	// as well. Ensuring that the default-series value is set by
   261  	// the user rather than a hold over from an old juju set value.
   262  	// Related to using the default-series value in the same way
   263  	// as a series flag at deploy.
   264  	v, ok := attrs[config.AgentVersionKey].(string)
   265  	if !ok {
   266  		return nil, errors.New("model config missing agent-version")
   267  	}
   268  	toolsVersion, err := version.Parse(v)
   269  	if err != nil {
   270  		return nil, errors.Trace(err)
   271  	}
   272  	// Using MustParse as the value parsed will never change.
   273  	newer := version.MustParse("2.9.35")
   274  	if comp := toolsVersion.Compare(newer); comp < 0 {
   275  		attrs[config.DefaultBaseKey] = ""
   276  		delete(attrs, config.DefaultSeriesKey)
   277  	}
   278  
   279  	if v, ok := attrs[config.DefaultSeriesKey]; ok {
   280  		if v == "" {
   281  			attrs[config.DefaultBaseKey] = ""
   282  		} else {
   283  			s, err := corebase.GetBaseFromSeries(v.(string))
   284  			if err != nil {
   285  				return nil, errors.Trace(err)
   286  			}
   287  			attrs[config.DefaultBaseKey] = s.String()
   288  		}
   289  		delete(attrs, config.DefaultSeriesKey)
   290  	}
   291  
   292  	// Ensure the expected default secret-backend value is set.
   293  	if v, ok := attrs[config.SecretBackendKey].(string); v == "" || !ok {
   294  		attrs[config.SecretBackendKey] = config.DefaultSecretBackend
   295  	}
   296  
   297  	return config.New(config.NoDefaults, attrs)
   298  }
   299  
   300  // ImportStateMigration defines a migration for importing various entities from
   301  // a source description model to the destination state.
   302  // It accumulates a series of migrations to Run at a later time.
   303  // Running the state migration visits all the migrations and exits upon seeing
   304  // the first error from the migration.
   305  type ImportStateMigration struct {
   306  	src                 description.Model
   307  	dst                 Database
   308  	knownSecretBackends set.Strings
   309  	migrations          []func() error
   310  }
   311  
   312  // Add adds a migration to execute at a later time
   313  // Return error from the addition will cause the Run to terminate early.
   314  func (m *ImportStateMigration) Add(f func() error) {
   315  	m.migrations = append(m.migrations, f)
   316  }
   317  
   318  // Run executes all the migrations required to be run.
   319  func (m *ImportStateMigration) Run() error {
   320  	for _, f := range m.migrations {
   321  		if err := f(); err != nil {
   322  			return errors.Trace(err)
   323  		}
   324  	}
   325  	return nil
   326  }
   327  
   328  type importer struct {
   329  	st      *State
   330  	dbModel *Model
   331  	model   description.Model
   332  	logger  loggo.Logger
   333  	// applicationUnits is populated at the end of loading the applications, and is a
   334  	// map of application name to the units of that application.
   335  	applicationUnits map[string]map[string]*Unit
   336  	charmOrigins     map[string]*CharmOrigin
   337  }
   338  
   339  func (i *importer) modelExtras() error {
   340  	if latest := i.model.LatestToolsVersion(); latest.String() != version.Zero.String() {
   341  		if err := i.dbModel.UpdateLatestToolsVersion(latest); err != nil {
   342  			return errors.Trace(err)
   343  		}
   344  	}
   345  
   346  	if annotations := i.model.Annotations(); len(annotations) > 0 {
   347  		if err := i.dbModel.SetAnnotations(i.dbModel, annotations); err != nil {
   348  			return errors.Trace(err)
   349  		}
   350  	}
   351  
   352  	blockType := map[string]BlockType{
   353  		"destroy-model": DestroyBlock,
   354  		"remove-object": RemoveBlock,
   355  		"all-changes":   ChangeBlock,
   356  	}
   357  
   358  	for blockName, message := range i.model.Blocks() {
   359  		block, ok := blockType[blockName]
   360  		if !ok {
   361  			return errors.Errorf("unknown block type: %q", blockName)
   362  		}
   363  		// We should check that each switch block can be assigned.
   364  		err := i.st.SwitchBlockOn(block, message)
   365  		if err != nil {
   366  			return errors.Trace(err)
   367  		}
   368  	}
   369  
   370  	if err := i.importStatusHistory(modelGlobalKey, i.model.StatusHistory()); err != nil {
   371  		return errors.Trace(err)
   372  	}
   373  	return nil
   374  }
   375  
   376  func (i *importer) sequences() error {
   377  	sequenceValues := i.model.Sequences()
   378  	docs := make([]interface{}, 0, len(sequenceValues))
   379  	for key, value := range sequenceValues {
   380  		// The sequences which track charm revisions aren't imported
   381  		// here because they get set when charm binaries are imported
   382  		// later. Importing them here means the wrong values get used.
   383  		if !isCharmRevSeqName(key) {
   384  			docs = append(docs, sequenceDoc{
   385  				DocID:   key,
   386  				Name:    key,
   387  				Counter: value,
   388  			})
   389  		}
   390  	}
   391  
   392  	// In reality, we will almost always have sequences to migrate.
   393  	// However, in tests, sometimes we don't.
   394  	if len(docs) == 0 {
   395  		return nil
   396  	}
   397  
   398  	sequences, closer := i.st.db().GetCollection(sequenceC)
   399  	defer closer()
   400  
   401  	if err := sequences.Writeable().Insert(docs...); err != nil {
   402  		return errors.Trace(err)
   403  	}
   404  	return nil
   405  }
   406  
   407  func (i *importer) modelUsers() error {
   408  	i.logger.Debugf("importing users")
   409  
   410  	// The user that was auto-added when we created the model will have
   411  	// the wrong DateCreated, so we remove it, and add in all the users we
   412  	// know about. It is also possible that the owner of the model no
   413  	// longer has access to the model due to changes over time.
   414  	if err := i.st.RemoveUserAccess(i.dbModel.Owner(), i.dbModel.ModelTag()); err != nil {
   415  		return errors.Trace(err)
   416  	}
   417  
   418  	users := i.model.Users()
   419  	modelUUID := i.dbModel.UUID()
   420  	var ops []txn.Op
   421  	for _, user := range users {
   422  		ops = append(ops, createModelUserOps(
   423  			modelUUID,
   424  			user.Name(),
   425  			user.CreatedBy(),
   426  			user.DisplayName(),
   427  			user.DateCreated(),
   428  			permission.Access(user.Access()))...,
   429  		)
   430  	}
   431  	if err := i.st.db().RunTransaction(ops); err != nil {
   432  		return errors.Trace(err)
   433  	}
   434  	// Now set their last connection times.
   435  	for _, user := range users {
   436  		i.logger.Debugf("user %s", user.Name())
   437  		lastConnection := user.LastConnection()
   438  		if lastConnection.IsZero() {
   439  			continue
   440  		}
   441  		err := i.dbModel.updateLastModelConnection(user.Name(), lastConnection)
   442  		if err != nil {
   443  			return errors.Trace(err)
   444  		}
   445  	}
   446  	return nil
   447  }
   448  
   449  func (i *importer) machines() error {
   450  	i.logger.Debugf("importing machines")
   451  	for _, m := range i.model.Machines() {
   452  		if err := i.machine(m); err != nil {
   453  			i.logger.Errorf("error importing machine: %s", err)
   454  			return errors.Annotate(err, m.Id())
   455  		}
   456  	}
   457  
   458  	i.logger.Debugf("importing machines succeeded")
   459  	return nil
   460  }
   461  
   462  func (i *importer) machine(m description.Machine) error {
   463  	// Import this machine, then import its containers.
   464  	i.logger.Debugf("importing machine %s", m.Id())
   465  
   466  	// 1. construct a machineDoc
   467  	mdoc, err := i.makeMachineDoc(m)
   468  	if err != nil {
   469  		return errors.Annotatef(err, "machine %s", m.Id())
   470  	}
   471  	// 2. construct enough MachineTemplate to pass into 'insertNewMachineOps'
   472  	//    - adds constraints doc
   473  	//    - adds status doc
   474  	//    - adds machine block devices doc
   475  
   476  	mStatus := m.Status()
   477  	if mStatus == nil {
   478  		return errors.NotValidf("missing status")
   479  	}
   480  	machineStatusDoc := statusDoc{
   481  		ModelUUID:  i.st.ModelUUID(),
   482  		Status:     status.Status(mStatus.Value()),
   483  		StatusInfo: mStatus.Message(),
   484  		StatusData: mStatus.Data(),
   485  		Updated:    mStatus.Updated().UnixNano(),
   486  	}
   487  	// A machine isn't valid if it doesn't have an instance.
   488  	instance := m.Instance()
   489  	instStatus := instance.Status()
   490  	instanceStatusDoc := statusDoc{
   491  		ModelUUID:  i.st.ModelUUID(),
   492  		Status:     status.Status(instStatus.Value()),
   493  		StatusInfo: instStatus.Message(),
   494  		StatusData: instStatus.Data(),
   495  		Updated:    instStatus.Updated().UnixNano(),
   496  	}
   497  	// importing without a modification-status shouldn't cause a panic, so we
   498  	// should check if it's nil or not.
   499  	var modificationStatusDoc statusDoc
   500  	if modStatus := instance.ModificationStatus(); modStatus != nil {
   501  		modificationStatusDoc = statusDoc{
   502  			ModelUUID:  i.st.ModelUUID(),
   503  			Status:     status.Status(modStatus.Value()),
   504  			StatusInfo: modStatus.Message(),
   505  			StatusData: modStatus.Data(),
   506  			Updated:    modStatus.Updated().UnixNano(),
   507  		}
   508  	}
   509  	cons := i.constraints(m.Constraints())
   510  	prereqOps, machineOp := i.st.baseNewMachineOps(
   511  		mdoc,
   512  		machineStatusDoc,
   513  		instanceStatusDoc,
   514  		modificationStatusDoc,
   515  		cons,
   516  	)
   517  
   518  	// 3. create op for adding in instance data
   519  	prereqOps = append(prereqOps, i.machineInstanceOp(mdoc, instance))
   520  
   521  	if parentId := container.ParentId(mdoc.Id); parentId != "" {
   522  		prereqOps = append(prereqOps,
   523  			// Update containers record for host machine.
   524  			addChildToContainerRefOp(i.st, parentId, mdoc.Id),
   525  		)
   526  	}
   527  	// insertNewContainerRefOp adds an empty doc into the containerRefsC
   528  	// collection for the machine being added.
   529  	prereqOps = append(prereqOps, insertNewContainerRefOp(i.st, mdoc.Id))
   530  
   531  	// 4. gather prereqs and machine op, run ops.
   532  	ops := append(prereqOps, machineOp)
   533  
   534  	// 5. add any ops that we may need to add the opened ports information for the machine.
   535  	ops = append(ops, i.machinePortsOp(m))
   536  
   537  	if err := i.st.db().RunTransaction(ops); err != nil {
   538  		return errors.Trace(err)
   539  	}
   540  
   541  	machine := newMachine(i.st, mdoc)
   542  	if annotations := m.Annotations(); len(annotations) > 0 {
   543  		if err := i.dbModel.SetAnnotations(machine, annotations); err != nil {
   544  			return errors.Trace(err)
   545  		}
   546  	}
   547  	if err := i.importStatusHistory(machine.globalKey(), m.StatusHistory()); err != nil {
   548  		return errors.Trace(err)
   549  	}
   550  	if err := i.importStatusHistory(machine.globalInstanceKey(), instance.StatusHistory()); err != nil {
   551  		return errors.Trace(err)
   552  	}
   553  	if err := i.importMachineBlockDevices(machine, m); err != nil {
   554  		return errors.Trace(err)
   555  	}
   556  
   557  	// Now that this machine exists in the database, process each of the
   558  	// containers in this machine.
   559  	for _, container := range m.Containers() {
   560  		if err := i.machine(container); err != nil {
   561  			return errors.Annotate(err, container.Id())
   562  		}
   563  	}
   564  	return nil
   565  }
   566  
   567  func (i *importer) importMachineBlockDevices(machine *Machine, m description.Machine) error {
   568  	var devices []BlockDeviceInfo
   569  	for _, device := range m.BlockDevices() {
   570  		devices = append(devices, BlockDeviceInfo{
   571  			DeviceName:     device.Name(),
   572  			DeviceLinks:    device.Links(),
   573  			Label:          device.Label(),
   574  			UUID:           device.UUID(),
   575  			HardwareId:     device.HardwareID(),
   576  			WWN:            device.WWN(),
   577  			BusAddress:     device.BusAddress(),
   578  			Size:           device.Size(),
   579  			FilesystemType: device.FilesystemType(),
   580  			InUse:          device.InUse(),
   581  			MountPoint:     device.MountPoint(),
   582  		})
   583  	}
   584  
   585  	if err := machine.SetMachineBlockDevices(devices...); err != nil {
   586  		return errors.Trace(err)
   587  	}
   588  	return nil
   589  }
   590  
   591  func (i *importer) machinePortsOp(m description.Machine) txn.Op {
   592  	modelUUID := i.st.ModelUUID()
   593  	machineID := m.Id()
   594  
   595  	portRangeDoc := machinePortRangesDoc{
   596  		DocID:      i.st.docID(machineID),
   597  		MachineID:  machineID,
   598  		ModelUUID:  modelUUID,
   599  		UnitRanges: make(map[string]network.GroupedPortRanges),
   600  	}
   601  
   602  	for unitName, unitPorts := range m.OpenedPortRanges().ByUnit() {
   603  		portRangeDoc.UnitRanges[unitName] = make(network.GroupedPortRanges)
   604  
   605  		for endpointName, portRanges := range unitPorts.ByEndpoint() {
   606  			portRangeList := make([]network.PortRange, len(portRanges))
   607  			for i, pr := range portRanges {
   608  				portRangeList[i] = network.PortRange{
   609  					FromPort: pr.FromPort(),
   610  					ToPort:   pr.ToPort(),
   611  					Protocol: pr.Protocol(),
   612  				}
   613  			}
   614  
   615  			portRangeDoc.UnitRanges[unitName][endpointName] = portRangeList
   616  		}
   617  	}
   618  
   619  	return txn.Op{
   620  		C:      openedPortsC,
   621  		Id:     machineID,
   622  		Assert: txn.DocMissing,
   623  		Insert: portRangeDoc,
   624  	}
   625  }
   626  
   627  func (i *importer) applicationPortsOp(a description.Application) txn.Op {
   628  	modelUUID := i.st.ModelUUID()
   629  	appName := a.Name()
   630  	docID := i.st.docID(applicationGlobalKey(appName))
   631  
   632  	portRangeDoc := newApplicationPortRangesDoc(docID, modelUUID, appName)
   633  	for unitName, unitPorts := range a.OpenedPortRanges().ByUnit() {
   634  		portRangeDoc.UnitRanges[unitName] = make(network.GroupedPortRanges)
   635  
   636  		for endpointName, portRanges := range unitPorts.ByEndpoint() {
   637  			portRangeList := transform.Slice(portRanges, func(pr description.UnitPortRange) network.PortRange {
   638  				return network.PortRange{
   639  					FromPort: pr.FromPort(),
   640  					ToPort:   pr.ToPort(),
   641  					Protocol: pr.Protocol(),
   642  				}
   643  			})
   644  			portRangeDoc.UnitRanges[unitName][endpointName] = portRangeList
   645  		}
   646  	}
   647  
   648  	return txn.Op{
   649  		C:      openedPortsC,
   650  		Id:     docID,
   651  		Assert: txn.DocMissing,
   652  		Insert: portRangeDoc,
   653  	}
   654  }
   655  
   656  func (i *importer) machineInstanceOp(mdoc *machineDoc, inst description.CloudInstance) txn.Op {
   657  	doc := &instanceData{
   658  		DocID:       mdoc.DocID,
   659  		MachineId:   mdoc.Id,
   660  		InstanceId:  instance.Id(inst.InstanceId()),
   661  		DisplayName: inst.DisplayName(),
   662  		ModelUUID:   mdoc.ModelUUID,
   663  	}
   664  
   665  	if arch := inst.Architecture(); arch != "" {
   666  		doc.Arch = &arch
   667  	}
   668  	if mem := inst.Memory(); mem != 0 {
   669  		doc.Mem = &mem
   670  	}
   671  	if rootDisk := inst.RootDisk(); rootDisk != 0 {
   672  		doc.RootDisk = &rootDisk
   673  	}
   674  	if rootDiskSource := inst.RootDiskSource(); rootDiskSource != "" {
   675  		doc.RootDiskSource = &rootDiskSource
   676  	}
   677  	if cores := inst.CpuCores(); cores != 0 {
   678  		doc.CpuCores = &cores
   679  	}
   680  	if power := inst.CpuPower(); power != 0 {
   681  		doc.CpuPower = &power
   682  	}
   683  	if tags := inst.Tags(); len(tags) > 0 {
   684  		doc.Tags = &tags
   685  	}
   686  	if az := inst.AvailabilityZone(); az != "" {
   687  		doc.AvailZone = &az
   688  	}
   689  	if vt := inst.VirtType(); vt != "" {
   690  		doc.VirtType = &vt
   691  	}
   692  	if profiles := inst.CharmProfiles(); len(profiles) > 0 {
   693  		doc.CharmProfiles = profiles
   694  	}
   695  
   696  	return txn.Op{
   697  		C:      instanceDataC,
   698  		Id:     mdoc.DocID,
   699  		Assert: txn.DocMissing,
   700  		Insert: doc,
   701  	}
   702  }
   703  
   704  func (i *importer) makeMachineDoc(m description.Machine) (*machineDoc, error) {
   705  	id := m.Id()
   706  	supported, supportedSet := m.SupportedContainers()
   707  	supportedContainers := make([]instance.ContainerType, len(supported))
   708  	for j, c := range supported {
   709  		supportedContainers[j] = instance.ContainerType(c)
   710  	}
   711  	jobs, err := i.makeMachineJobs(m.Jobs())
   712  	if err != nil {
   713  		return nil, errors.Trace(err)
   714  	}
   715  
   716  	agentTools, err := i.makeTools(m.Tools())
   717  	if err != nil {
   718  		return nil, errors.Trace(err)
   719  	}
   720  
   721  	machineTag := m.Tag()
   722  	base, err := corebase.ParseBaseFromString(m.Base())
   723  	if err != nil {
   724  		return nil, errors.Trace(err)
   725  	}
   726  	macBase := Base{OS: base.OS, Channel: base.Channel.String()}
   727  	return &machineDoc{
   728  		DocID:                    i.st.docID(id),
   729  		Id:                       id,
   730  		ModelUUID:                i.st.ModelUUID(),
   731  		Nonce:                    m.Nonce(),
   732  		Base:                     macBase.Normalise(),
   733  		ContainerType:            m.ContainerType(),
   734  		Principals:               nil, // Set during unit import.
   735  		Life:                     Alive,
   736  		Tools:                    agentTools,
   737  		Jobs:                     jobs,
   738  		PasswordHash:             m.PasswordHash(),
   739  		Clean:                    !i.machineHasUnits(machineTag),
   740  		Volumes:                  i.machineVolumes(machineTag),
   741  		Filesystems:              i.machineFilesystems(machineTag),
   742  		Addresses:                i.makeAddresses(m.ProviderAddresses()),
   743  		MachineAddresses:         i.makeAddresses(m.MachineAddresses()),
   744  		PreferredPrivateAddress:  i.makeAddress(m.PreferredPrivateAddress()),
   745  		PreferredPublicAddress:   i.makeAddress(m.PreferredPublicAddress()),
   746  		SupportedContainersKnown: supportedSet,
   747  		SupportedContainers:      supportedContainers,
   748  		Placement:                m.Placement(),
   749  	}, nil
   750  }
   751  
   752  func (i *importer) machineHasUnits(tag names.MachineTag) bool {
   753  	for _, app := range i.model.Applications() {
   754  		for _, unit := range app.Units() {
   755  			if unit.Machine() == tag {
   756  				return true
   757  			}
   758  		}
   759  	}
   760  	return false
   761  }
   762  
   763  func (i *importer) machineVolumes(tag names.MachineTag) []string {
   764  	var result []string
   765  	for _, volume := range i.model.Volumes() {
   766  		for _, attachment := range volume.Attachments() {
   767  			if attachment.Host() == tag {
   768  				result = append(result, volume.Tag().Id())
   769  			}
   770  		}
   771  	}
   772  	return result
   773  }
   774  
   775  func (i *importer) machineFilesystems(tag names.MachineTag) []string {
   776  	var result []string
   777  	for _, filesystem := range i.model.Filesystems() {
   778  		for _, attachment := range filesystem.Attachments() {
   779  			if attachment.Host() == tag {
   780  				result = append(result, filesystem.Tag().Id())
   781  			}
   782  		}
   783  	}
   784  	return result
   785  }
   786  
   787  func (i *importer) makeMachineJobs(jobs []string) ([]MachineJob, error) {
   788  	// At time of writing, there are three valid jobs. If any jobs gets
   789  	// deprecated or changed in the future, older models that specify those
   790  	// jobs need to be handled here.
   791  	result := make([]MachineJob, 0, len(jobs))
   792  	for _, job := range jobs {
   793  		switch job {
   794  		case "host-units":
   795  			result = append(result, JobHostUnits)
   796  		case "api-server":
   797  			result = append(result, JobManageModel)
   798  		default:
   799  			return nil, errors.Errorf("unknown machine job: %q", job)
   800  		}
   801  	}
   802  	return result, nil
   803  }
   804  
   805  func (i *importer) makeTools(t description.AgentTools) (*tools.Tools, error) {
   806  	if t == nil {
   807  		return nil, nil
   808  	}
   809  	result := &tools.Tools{
   810  		Version: t.Version(),
   811  		URL:     t.URL(),
   812  		SHA256:  t.SHA256(),
   813  		Size:    t.Size(),
   814  	}
   815  	return result, nil
   816  }
   817  
   818  func (i *importer) makeAddress(addr description.Address) address {
   819  	if addr == nil {
   820  		return address{}
   821  	}
   822  
   823  	newAddr := address{
   824  		Value:       addr.Value(),
   825  		AddressType: addr.Type(),
   826  		Scope:       addr.Scope(),
   827  		Origin:      addr.Origin(),
   828  		SpaceID:     addr.SpaceID(),
   829  	}
   830  
   831  	// Addresses are placed in the default space if no space ID is set.
   832  	if newAddr.SpaceID == "" {
   833  		newAddr.SpaceID = "0"
   834  	}
   835  
   836  	return newAddr
   837  }
   838  
   839  func (i *importer) makeAddresses(addrs []description.Address) []address {
   840  	result := make([]address, len(addrs))
   841  	for j, addr := range addrs {
   842  		result[j] = i.makeAddress(addr)
   843  	}
   844  	return result
   845  }
   846  
   847  func (i *importer) applications() error {
   848  	i.logger.Debugf("importing applications")
   849  
   850  	ctrlCfg, err := i.st.ControllerConfig()
   851  	if err != nil {
   852  		return errors.Trace(err)
   853  	}
   854  
   855  	// Ensure we import principal applications first, so that
   856  	// subordinate units can refer to the principal ones.
   857  	var principals, subordinates []description.Application
   858  	for _, app := range i.model.Applications() {
   859  		if app.Subordinate() {
   860  			subordinates = append(subordinates, app)
   861  		} else {
   862  			principals = append(principals, app)
   863  		}
   864  	}
   865  
   866  	i.charmOrigins = make(map[string]*CharmOrigin, len(principals)+len(subordinates))
   867  
   868  	for _, s := range append(principals, subordinates...) {
   869  		if err := i.application(s, ctrlCfg); err != nil {
   870  			i.logger.Errorf("error importing application %s: %s", s.Name(), err)
   871  			return errors.Annotate(err, s.Name())
   872  		}
   873  	}
   874  
   875  	if err := i.loadUnits(); err != nil {
   876  		return errors.Annotate(err, "loading new units from db")
   877  	}
   878  	i.logger.Debugf("importing applications succeeded")
   879  	return nil
   880  }
   881  
   882  func (i *importer) loadUnits() error {
   883  	unitsCollection, closer := i.st.db().GetCollection(unitsC)
   884  	defer closer()
   885  
   886  	docs := []unitDoc{}
   887  	err := unitsCollection.Find(nil).All(&docs)
   888  	if err != nil {
   889  		return errors.Annotate(err, "cannot get all units")
   890  	}
   891  
   892  	result := make(map[string]map[string]*Unit)
   893  	for _, doc := range docs {
   894  		units, found := result[doc.Application]
   895  		if !found {
   896  			units = make(map[string]*Unit)
   897  			result[doc.Application] = units
   898  		}
   899  		units[doc.Name] = newUnit(i.st, i.dbModel.Type(), &doc)
   900  	}
   901  	i.applicationUnits = result
   902  	return nil
   903  
   904  }
   905  
   906  // makeStatusDoc assumes status is non-nil.
   907  func (i *importer) makeStatusDoc(statusVal description.Status) statusDoc {
   908  	doc := statusDoc{
   909  		Status:     status.Status(statusVal.Value()),
   910  		StatusInfo: statusVal.Message(),
   911  		StatusData: statusVal.Data(),
   912  		Updated:    statusVal.Updated().UnixNano(),
   913  	}
   914  	// Older versions of Juju would pass through NeverSet() on the status
   915  	// description for application statuses that hadn't been explicitly
   916  	// set by the lead unit. If that is the case, we make the status what
   917  	// the new code expects.
   918  	if statusVal.NeverSet() {
   919  		doc.Status = status.Unset
   920  		doc.StatusInfo = ""
   921  		doc.StatusData = nil
   922  	}
   923  	return doc
   924  }
   925  
   926  func (i *importer) application(a description.Application, ctrlCfg controller.Config) error {
   927  	// Import this application, then its units.
   928  	i.logger.Debugf("importing application %s", a.Name())
   929  
   930  	// 1. construct an applicationDoc
   931  	appDoc, err := i.makeApplicationDoc(a)
   932  	if err != nil {
   933  		return errors.Trace(err)
   934  	}
   935  	app := newApplication(i.st, appDoc)
   936  
   937  	// 2. construct a statusDoc
   938  	status := a.Status()
   939  	if status == nil {
   940  		return errors.NotValidf("missing status")
   941  	}
   942  	appStatusDoc := i.makeStatusDoc(status)
   943  
   944  	// When creating the settings, we ignore nils.  In other circumstances, nil
   945  	// means to delete the value (reset to default), so creating with nil should
   946  	// mean to use the default, i.e. don't set the value.
   947  	// There may have existed some applications with settings that contained
   948  	// nil values, see lp#1667199. When importing, we want these stripped.
   949  	removeNils(a.CharmConfig())
   950  	removeNils(a.ApplicationConfig())
   951  
   952  	var operatorStatusDoc *statusDoc
   953  	if i.dbModel.Type() == ModelTypeCAAS {
   954  		operatorStatus := i.makeStatusDoc(a.OperatorStatus())
   955  		operatorStatusDoc = &operatorStatus
   956  	}
   957  	ops, err := addApplicationOps(i.st, app, addApplicationOpsArgs{
   958  		applicationDoc:     appDoc,
   959  		statusDoc:          appStatusDoc,
   960  		constraints:        i.constraints(a.Constraints()),
   961  		storage:            i.storageConstraints(a.StorageDirectives()),
   962  		charmConfig:        a.CharmConfig(),
   963  		applicationConfig:  a.ApplicationConfig(),
   964  		leadershipSettings: a.LeadershipSettings(),
   965  		operatorStatus:     operatorStatusDoc,
   966  	})
   967  	if err != nil {
   968  		return errors.Trace(err)
   969  	}
   970  
   971  	bindings, err := i.parseBindings(a.EndpointBindings())
   972  	if err != nil {
   973  		return errors.Trace(err)
   974  	}
   975  
   976  	ops = append(ops, txn.Op{
   977  		C:      endpointBindingsC,
   978  		Id:     app.globalKey(),
   979  		Assert: txn.DocMissing,
   980  		Insert: endpointBindingsDoc{
   981  			Bindings: bindings.Map(),
   982  		},
   983  	})
   984  
   985  	ops = append(ops, i.appResourceOps(a)...)
   986  
   987  	// add any ops that we may need to add the opened ports information for the application.
   988  	ops = append(ops, i.applicationPortsOp(a))
   989  
   990  	if err := i.st.db().RunTransaction(ops); err != nil {
   991  		return errors.Trace(err)
   992  	}
   993  
   994  	if a.PodSpec() != "" {
   995  		cm, err := i.dbModel.CAASModel()
   996  		if err != nil {
   997  			return errors.NewNotSupported(err, "adding pod spec to IAAS model")
   998  		}
   999  		// We pass a nil token as there is no need to perform
  1000  		// leadership checks while migrating.
  1001  		spec := a.PodSpec()
  1002  		if err := cm.SetPodSpec(nil, a.Tag(), &spec); err != nil {
  1003  			return errors.Trace(err)
  1004  		}
  1005  	}
  1006  	// TODO(caas): Add raw k8s spec to juju/description for model migration!
  1007  
  1008  	if cs := a.CloudService(); cs != nil {
  1009  		app, err := i.st.Application(a.Name())
  1010  		if err != nil {
  1011  			return errors.Trace(err)
  1012  		}
  1013  		addr := i.makeAddresses(cs.Addresses())
  1014  		if err := app.UpdateCloudService(cs.ProviderId(), networkAddresses(addr)); err != nil {
  1015  			return errors.Trace(err)
  1016  		}
  1017  	}
  1018  
  1019  	if annotations := a.Annotations(); len(annotations) > 0 {
  1020  		if err := i.dbModel.SetAnnotations(app, annotations); err != nil {
  1021  			return errors.Trace(err)
  1022  		}
  1023  	}
  1024  	if err := i.importStatusHistory(app.globalKey(), a.StatusHistory()); err != nil {
  1025  		return errors.Trace(err)
  1026  	}
  1027  
  1028  	for _, unit := range a.Units() {
  1029  		if err := i.unit(a, unit, ctrlCfg); err != nil {
  1030  			return errors.Trace(err)
  1031  		}
  1032  	}
  1033  
  1034  	if err := i.applicationOffers(a); err != nil {
  1035  		i.logger.Errorf("error importing application %s: %s", app.Name(), err)
  1036  		return errors.Annotate(err, app.Name())
  1037  	}
  1038  
  1039  	return nil
  1040  }
  1041  
  1042  func (i *importer) applicationOffers(app ApplicationDescription) error {
  1043  	i.logger.Debugf("importing application offer")
  1044  	migration := &ImportStateMigration{
  1045  		src: i.model,
  1046  		dst: i.st.db(),
  1047  	}
  1048  	migration.Add(func() error {
  1049  		m := ImportApplicationOffer{}
  1050  		// The following shims compose a model and series of methods that should
  1051  		// be public, but are private (for unit/mock testing) and we encapsulate
  1052  		// that as one thing.
  1053  		return m.Execute(applicationDescriptionShim{
  1054  			stateApplicationOfferDocumentFactoryShim{
  1055  				stateModelNamspaceShim{
  1056  					Model: migration.src,
  1057  					st:    i.st,
  1058  				},
  1059  				i,
  1060  			},
  1061  			app,
  1062  		}, migration.dst)
  1063  	})
  1064  	if err := migration.Run(); err != nil {
  1065  		return errors.Trace(err)
  1066  	}
  1067  	i.logger.Debugf("importing application offer succeeded")
  1068  	return nil
  1069  }
  1070  
  1071  // parseBindings converts a bindings map from a 2.6.x or 2.7+ migration export
  1072  // into a Bindings object.
  1073  //
  1074  // When migrating from a 2.6.x controller, the bindings in the description
  1075  // output are encoded as {endpoint name => space name} with "" representing
  1076  // the "default" (now called alpha) space. The empty spaces must be remapped
  1077  // to the correct default space name for the new controller.
  1078  //
  1079  // On the other hand, migration exports from 2.7+ are using space IDs instead
  1080  // of space names as the map values and can safely be passed to the NewBindings
  1081  // c-tor.
  1082  func (i *importer) parseBindings(bindingsMap map[string]string) (*Bindings, error) {
  1083  	defaultMappingsAreIds := true
  1084  	for epName, spNameOrID := range bindingsMap {
  1085  		if spNameOrID == "" {
  1086  			defaultMappingsAreIds = false
  1087  			bindingsMap[epName] = network.AlphaSpaceName
  1088  		}
  1089  	}
  1090  
  1091  	// 2.6 controllers only populate the default space key if set to the
  1092  	// non-default space whereas 2.7 controllers always set it.
  1093  	// The application implementation in the description package has
  1094  	// `omitempty` for bindings, so we need to create it if nil.
  1095  	// There's an added complication. Coming from a 2.6 controller, the
  1096  	// mapping is endpoint -> spaceName. If the 2.6 controller has been
  1097  	// upgraded to 2.7.x (x < 7), the mapping is endpoint -> spaceID.
  1098  	// We need to ensure that a consistent mapping value is used.
  1099  	if bindingsMap == nil {
  1100  		bindingsMap = make(map[string]string, 1)
  1101  	}
  1102  	if _, exists := bindingsMap[defaultEndpointName]; !exists {
  1103  		if defaultMappingsAreIds {
  1104  			bindingsMap[defaultEndpointName] = network.AlphaSpaceId
  1105  		} else {
  1106  			bindingsMap[defaultEndpointName] = network.AlphaSpaceName
  1107  		}
  1108  	}
  1109  
  1110  	return NewBindings(i.st, bindingsMap)
  1111  }
  1112  
  1113  func (i *importer) appResourceOps(app description.Application) []txn.Op {
  1114  	// Add a placeholder record for each resource that is a placeholder.
  1115  	// Resources define placeholders as resources where the timestamp is Zero.
  1116  	var result []txn.Op
  1117  	appName := app.Name()
  1118  
  1119  	var makeResourceDoc = func(id, name string, rev description.ResourceRevision) resourceDoc {
  1120  		fingerprint, _ := hex.DecodeString(rev.FingerprintHex())
  1121  		return resourceDoc{
  1122  			ID:            id,
  1123  			ApplicationID: appName,
  1124  			Name:          name,
  1125  			Type:          rev.Type(),
  1126  			Path:          rev.Path(),
  1127  			Description:   rev.Description(),
  1128  			Origin:        rev.Origin(),
  1129  			Revision:      rev.Revision(),
  1130  			Fingerprint:   fingerprint,
  1131  			Size:          rev.Size(),
  1132  			Username:      rev.Username(),
  1133  		}
  1134  	}
  1135  
  1136  	for _, r := range app.Resources() {
  1137  		// I cannot for the life of me find the function where the underlying
  1138  		// resource id is defined to be the appname/resname but that is what
  1139  		// ends up in the DB.
  1140  		resName := r.Name()
  1141  		resID := appName + "/" + resName
  1142  		// Check both the app and charmstore
  1143  		if appRev := r.ApplicationRevision(); appRev.Timestamp().IsZero() {
  1144  			result = append(result, txn.Op{
  1145  				C:      resourcesC,
  1146  				Id:     applicationResourceID(resID),
  1147  				Assert: txn.DocMissing,
  1148  				Insert: makeResourceDoc(resID, resName, appRev),
  1149  			})
  1150  		}
  1151  		if storeRev := r.CharmStoreRevision(); storeRev.Timestamp().IsZero() {
  1152  			doc := makeResourceDoc(resID, resName, storeRev)
  1153  			doc.LastPolled = i.st.nowToTheSecond()
  1154  			result = append(result, txn.Op{
  1155  				C:      resourcesC,
  1156  				Id:     charmStoreResourceID(resID),
  1157  				Assert: txn.DocMissing,
  1158  				Insert: doc,
  1159  			})
  1160  		}
  1161  	}
  1162  	return result
  1163  }
  1164  
  1165  func (i *importer) storageConstraints(cons map[string]description.StorageDirective) map[string]StorageConstraints {
  1166  	if len(cons) == 0 {
  1167  		return nil
  1168  	}
  1169  	result := make(map[string]StorageConstraints)
  1170  	for key, value := range cons {
  1171  		result[key] = StorageConstraints{
  1172  			Pool:  value.Pool(),
  1173  			Size:  value.Size(),
  1174  			Count: value.Count(),
  1175  		}
  1176  	}
  1177  	return result
  1178  }
  1179  
  1180  func (i *importer) unit(s description.Application, u description.Unit, ctrlCfg controller.Config) error {
  1181  	i.logger.Debugf("importing unit %s", u.Name())
  1182  
  1183  	// 1. construct a unitDoc
  1184  	udoc, err := i.makeUnitDoc(s, u)
  1185  	if err != nil {
  1186  		return errors.Trace(err)
  1187  	}
  1188  
  1189  	// 2. construct a statusDoc for the workload status and agent status
  1190  	agentStatus := u.AgentStatus()
  1191  	if agentStatus == nil {
  1192  		return errors.NotValidf("missing agent status")
  1193  	}
  1194  	agentStatusDoc := i.makeStatusDoc(agentStatus)
  1195  
  1196  	workloadStatus := u.WorkloadStatus()
  1197  	if workloadStatus == nil {
  1198  		return errors.NotValidf("missing workload status")
  1199  	}
  1200  	workloadStatusDoc := i.makeStatusDoc(workloadStatus)
  1201  
  1202  	workloadVersion := u.WorkloadVersion()
  1203  	versionStatus := status.Active
  1204  	if workloadVersion == "" {
  1205  		versionStatus = status.Unknown
  1206  	}
  1207  	workloadVersionDoc := statusDoc{
  1208  		Status:     versionStatus,
  1209  		StatusInfo: workloadVersion,
  1210  	}
  1211  
  1212  	var cloudContainer *cloudContainerDoc
  1213  	if cc := u.CloudContainer(); cc != nil {
  1214  		cloudContainer = &cloudContainerDoc{
  1215  			Id:         unitGlobalKey(u.Name()),
  1216  			ProviderId: cc.ProviderId(),
  1217  			Ports:      cc.Ports(),
  1218  		}
  1219  		if cc.Address() != nil {
  1220  			addr := i.makeAddress(cc.Address())
  1221  			cloudContainer.Address = &addr
  1222  		}
  1223  	}
  1224  
  1225  	ops, err := addUnitOps(i.st, addUnitOpsArgs{
  1226  		unitDoc:            udoc,
  1227  		agentStatusDoc:     agentStatusDoc,
  1228  		workloadStatusDoc:  &workloadStatusDoc,
  1229  		workloadVersionDoc: &workloadVersionDoc,
  1230  		meterStatusDoc: &meterStatusDoc{
  1231  			Code: u.MeterStatusCode(),
  1232  			Info: u.MeterStatusInfo(),
  1233  		},
  1234  		containerDoc: cloudContainer,
  1235  	})
  1236  	if err != nil {
  1237  		return errors.Trace(err)
  1238  	}
  1239  
  1240  	if i.dbModel.Type() == ModelTypeIAAS && u.Principal().Id() == "" {
  1241  		// If the unit is a principal, add it to its machine.
  1242  		ops = append(ops, txn.Op{
  1243  			C:      machinesC,
  1244  			Id:     u.Machine().Id(),
  1245  			Assert: txn.DocExists,
  1246  			Update: bson.M{"$addToSet": bson.M{"principals": u.Name()}},
  1247  		})
  1248  	}
  1249  
  1250  	// We should only have constraints for principal agents.
  1251  	// We don't encode that business logic here, if there are constraints
  1252  	// in the imported model, we put them in the database.
  1253  	if cons := u.Constraints(); cons != nil {
  1254  		agentGlobalKey := unitAgentGlobalKey(u.Name())
  1255  		ops = append(ops, createConstraintsOp(agentGlobalKey, i.constraints(cons)))
  1256  	}
  1257  
  1258  	if err := i.st.db().RunTransaction(ops); err != nil {
  1259  		i.logger.Debugf("failed ops: %#v", ops)
  1260  		return errors.Trace(err)
  1261  	}
  1262  
  1263  	model, err := i.st.Model()
  1264  	if err != nil {
  1265  		return errors.Trace(err)
  1266  	}
  1267  
  1268  	// The assertion logic in unit.SetState assumes that the DocID is
  1269  	// present.  Since the txn for creating the unit doc has completed
  1270  	// without an error, we can safely populate the doc's model UUID and
  1271  	// DocID.
  1272  	udoc.ModelUUID = model.UUID()
  1273  	udoc.DocID = ensureModelUUID(udoc.ModelUUID, udoc.Name)
  1274  
  1275  	unit := newUnit(i.st, model.Type(), udoc)
  1276  	if annotations := u.Annotations(); len(annotations) > 0 {
  1277  		if err := i.dbModel.SetAnnotations(unit, annotations); err != nil {
  1278  			return errors.Trace(err)
  1279  		}
  1280  	}
  1281  	if err := i.importStatusHistory(unit.globalKey(), u.WorkloadStatusHistory()); err != nil {
  1282  		return errors.Trace(err)
  1283  	}
  1284  	if err := i.importStatusHistory(unit.globalAgentKey(), u.AgentStatusHistory()); err != nil {
  1285  		return errors.Trace(err)
  1286  	}
  1287  	if err := i.importStatusHistory(unit.globalWorkloadVersionKey(), u.WorkloadVersionHistory()); err != nil {
  1288  		return errors.Trace(err)
  1289  	}
  1290  	if err := i.importUnitState(unit, u, ctrlCfg); err != nil {
  1291  		return errors.Trace(err)
  1292  	}
  1293  	if i.dbModel.Type() == ModelTypeIAAS {
  1294  		if err := i.importUnitPayloads(unit, u.Payloads()); err != nil {
  1295  			return errors.Trace(err)
  1296  		}
  1297  	}
  1298  	return nil
  1299  }
  1300  
  1301  func (i *importer) importUnitState(unit *Unit, u description.Unit, ctrlCfg controller.Config) error {
  1302  	us := NewUnitState()
  1303  
  1304  	if charmState := u.CharmState(); len(charmState) != 0 {
  1305  		us.SetCharmState(charmState)
  1306  	}
  1307  	if relationState := u.RelationState(); len(relationState) != 0 {
  1308  		us.SetRelationState(relationState)
  1309  	}
  1310  	if uniterState := u.UniterState(); uniterState != "" {
  1311  		us.SetUniterState(uniterState)
  1312  	}
  1313  	if storageState := u.StorageState(); storageState != "" {
  1314  		us.SetStorageState(storageState)
  1315  	}
  1316  	if meterStatusState := u.MeterStatusState(); meterStatusState != "" {
  1317  		us.SetMeterStatusState(meterStatusState)
  1318  	}
  1319  
  1320  	// No state to persist.
  1321  	if !us.Modified() {
  1322  		return nil
  1323  	}
  1324  
  1325  	return unit.SetState(us, UnitStateSizeLimits{
  1326  		MaxCharmStateSize: ctrlCfg.MaxCharmStateSize(),
  1327  		MaxAgentStateSize: ctrlCfg.MaxAgentStateSize(),
  1328  	})
  1329  }
  1330  
  1331  func (i *importer) importUnitPayloads(unit *Unit, payloadInfo []description.Payload) error {
  1332  	up, err := i.st.UnitPayloads(unit)
  1333  	if err != nil {
  1334  		return errors.Trace(err)
  1335  	}
  1336  
  1337  	for _, p := range payloadInfo {
  1338  		if err := up.Track(payloads.Payload{
  1339  			PayloadClass: charm.PayloadClass{
  1340  				Name: p.Name(),
  1341  				Type: p.Type(),
  1342  			},
  1343  			ID:     p.RawID(),
  1344  			Status: p.State(),
  1345  			Labels: p.Labels(),
  1346  		}); err != nil {
  1347  			return errors.Trace(err)
  1348  		}
  1349  	}
  1350  
  1351  	return nil
  1352  }
  1353  
  1354  func (i *importer) makeApplicationDoc(a description.Application) (*applicationDoc, error) {
  1355  	units := a.Units()
  1356  
  1357  	origin, err := i.makeCharmOrigin(a)
  1358  	if err != nil {
  1359  		return nil, errors.Trace(err)
  1360  	}
  1361  
  1362  	var exposedEndpoints map[string]ExposedEndpoint
  1363  	if expEps := a.ExposedEndpoints(); len(expEps) > 0 {
  1364  		exposedEndpoints = make(map[string]ExposedEndpoint, len(expEps))
  1365  		for epName, details := range expEps {
  1366  			exposedEndpoints[epName] = ExposedEndpoint{
  1367  				ExposeToSpaceIDs: details.ExposeToSpaceIDs(),
  1368  				ExposeToCIDRs:    details.ExposeToCIDRs(),
  1369  			}
  1370  		}
  1371  	}
  1372  
  1373  	agentTools, err := i.makeTools(a.Tools())
  1374  	if err != nil {
  1375  		return nil, errors.Trace(err)
  1376  	}
  1377  	cURLStr := a.CharmURL()
  1378  
  1379  	appDoc := &applicationDoc{
  1380  		Name:                 a.Name(),
  1381  		Subordinate:          a.Subordinate(),
  1382  		CharmURL:             &cURLStr,
  1383  		CharmModifiedVersion: a.CharmModifiedVersion(),
  1384  		CharmOrigin:          *origin,
  1385  		ForceCharm:           a.ForceCharm(),
  1386  		PasswordHash:         a.PasswordHash(),
  1387  		Life:                 Alive,
  1388  		UnitCount:            len(units),
  1389  		RelationCount:        i.relationCount(a.Name()),
  1390  		Exposed:              a.Exposed(),
  1391  		ExposedEndpoints:     exposedEndpoints,
  1392  		MinUnits:             a.MinUnits(),
  1393  		Tools:                agentTools,
  1394  		MetricCredentials:    a.MetricsCredentials(),
  1395  		DesiredScale:         a.DesiredScale(),
  1396  		Placement:            a.Placement(),
  1397  		HasResources:         a.HasResources(),
  1398  	}
  1399  
  1400  	if ps := a.ProvisioningState(); ps != nil {
  1401  		appDoc.ProvisioningState = &ApplicationProvisioningState{
  1402  			Scaling:     ps.Scaling(),
  1403  			ScaleTarget: ps.ScaleTarget(),
  1404  		}
  1405  	}
  1406  
  1407  	return appDoc, nil
  1408  }
  1409  
  1410  // makeCharmOrigin returns the charm origin for an application
  1411  //
  1412  // Previous versions of the Juju server and clients have treated applications charm
  1413  // origins very loosely, particularly during `refresh --switch`s. The server performed
  1414  // no validation on origins received from the client, and client often mutated them
  1415  // incorrectly. For instance, when switching from a ch charm to local, pylibjuju simply
  1416  // sent back a copy of the ch charm origin, whereas the CLI only set the source to local.
  1417  // Both resulted in incorrect/invalidate origins.
  1418  //
  1419  // Calculate the origin Source and Revision from the charm url. Ensure ID, Hash and Channel
  1420  // are dropped from local charm. Keep ID, Hash and Channel (for ch charms) and Platform (always)
  1421  // we get from the origin. We can trust these since supported clients cannot break these
  1422  //
  1423  // This was fixed in pylibjuju 3.2.3.0 and juju 3.3.0. As of writing, no versions of the
  1424  // server validate new charm origins on calls to SetCharm. Ideally, the client shouldn't
  1425  // handle charm origins at all, being an implementation detail. But this will probably have
  1426  // to wait until the api re-write
  1427  //
  1428  // https://bugs.launchpad.net/juju/+bug/2039267
  1429  // https://github.com/juju/python-libjuju/issues/962
  1430  //
  1431  // Due to LP:1986547: where the track is missing from the effective channel it implicitly
  1432  // resolves to 'latest' if the charm does not have a default channel defined. So if the
  1433  // received channel has no track, we can be confident it should be 'latest'
  1434  //
  1435  // TODO: Once we have confidence in charm origins, do not parse charm url and simplify
  1436  // into a translation layer
  1437  func (i *importer) makeCharmOrigin(a description.Application) (*CharmOrigin, error) {
  1438  	sourceOrigin := a.CharmOrigin()
  1439  	curl, err := charm.ParseURL(a.CharmURL())
  1440  	if err != nil {
  1441  		return nil, errors.Trace(err)
  1442  	}
  1443  
  1444  	// Fix bad datasets from LP 1999060 during migration.
  1445  	// ID and Hash missing from N-1 of N applications'
  1446  	// charm origins when deployed using the same charm.
  1447  	if foundOrigin, ok := i.charmOrigins[curl.String()]; ok {
  1448  		return foundOrigin, nil
  1449  	}
  1450  
  1451  	var channel *Channel
  1452  	serialized := sourceOrigin.Channel()
  1453  	if serialized != "" && charm.CharmHub.Matches(curl.Schema) {
  1454  		c, err := charm.ParseChannelNormalize(serialized)
  1455  		if err != nil {
  1456  			return nil, errors.Trace(err)
  1457  		}
  1458  		track := c.Track
  1459  		if track == "" {
  1460  			track = "latest"
  1461  		}
  1462  		channel = &Channel{
  1463  			Track:  track,
  1464  			Risk:   string(c.Risk),
  1465  			Branch: c.Branch,
  1466  		}
  1467  	}
  1468  
  1469  	p, err := corecharm.ParsePlatformNormalize(sourceOrigin.Platform())
  1470  	if err != nil {
  1471  		return nil, errors.Trace(err)
  1472  	}
  1473  	platform := &Platform{
  1474  		Architecture: p.Architecture,
  1475  		OS:           p.OS,
  1476  		Channel:      p.Channel,
  1477  	}
  1478  
  1479  	// We can hardcode type to charm as we never store bundles in state.
  1480  	var origin *CharmOrigin
  1481  	if charm.Local.Matches(curl.Schema) {
  1482  		origin = &CharmOrigin{
  1483  			Source:   corecharm.Local.String(),
  1484  			Type:     "charm",
  1485  			Revision: &curl.Revision,
  1486  			Platform: platform,
  1487  		}
  1488  	} else if charm.CharmHub.Matches(curl.Schema) {
  1489  		origin = &CharmOrigin{
  1490  			Source:   corecharm.CharmHub.String(),
  1491  			Type:     "charm",
  1492  			Revision: &curl.Revision,
  1493  			ID:       sourceOrigin.ID(),
  1494  			Hash:     sourceOrigin.Hash(),
  1495  			Channel:  channel,
  1496  			Platform: platform,
  1497  		}
  1498  	} else {
  1499  		return nil, errors.Errorf("Unrecognised charm url schema %q", curl.Schema)
  1500  	}
  1501  
  1502  	if !reflect.DeepEqual(sourceOrigin, origin) {
  1503  		i.logger.Warningf("Source origin for application %q is invalid. Normalising", a.Name())
  1504  	}
  1505  
  1506  	i.charmOrigins[curl.String()] = origin
  1507  	return origin, nil
  1508  }
  1509  
  1510  func (i *importer) relationCount(application string) int {
  1511  	count := 0
  1512  
  1513  	for _, rel := range i.model.Relations() {
  1514  		for _, ep := range rel.Endpoints() {
  1515  			if ep.ApplicationName() == application {
  1516  				count++
  1517  			}
  1518  		}
  1519  	}
  1520  
  1521  	return count
  1522  }
  1523  
  1524  func (i *importer) getPrincipalMachineID(principal names.UnitTag) string {
  1525  	// We know this is a valid unit name, so we don't care about the error.
  1526  	appName, _ := names.UnitApplication(principal.Id())
  1527  	for _, app := range i.model.Applications() {
  1528  		if app.Name() == appName {
  1529  			for _, unit := range app.Units() {
  1530  				if unit.Tag() == principal {
  1531  					return unit.Machine().Id()
  1532  				}
  1533  			}
  1534  		}
  1535  	}
  1536  	// We should never get here, but if we do, just return an empty
  1537  	// machine ID.
  1538  	i.logger.Warningf("unable to find principal %q", principal.Id())
  1539  	return ""
  1540  }
  1541  
  1542  func (i *importer) makeUnitDoc(s description.Application, u description.Unit) (*unitDoc, error) {
  1543  	// NOTE: if we want to support units having different charms deployed
  1544  	// than the application recommends and migrate that, then we should serialize
  1545  	// the charm url for each unit rather than grabbing the applications charm url.
  1546  	// Currently the units charm url matching the application is a precondiation
  1547  	// to migration.
  1548  	charmURL := s.CharmURL()
  1549  
  1550  	var subordinates []string
  1551  	if subs := u.Subordinates(); len(subs) > 0 {
  1552  		for _, s := range subs {
  1553  			subordinates = append(subordinates, s.Id())
  1554  		}
  1555  	}
  1556  
  1557  	machineID := u.Machine().Id()
  1558  	if s.Subordinate() && machineID == "" && i.dbModel.Type() != ModelTypeCAAS {
  1559  		// If we don't have a machine ID and we should, go get the
  1560  		// machine ID from the principal.
  1561  		machineID = i.getPrincipalMachineID(u.Principal())
  1562  	}
  1563  
  1564  	agentTools, err := i.makeTools(u.Tools())
  1565  	if err != nil {
  1566  		return nil, errors.Trace(err)
  1567  	}
  1568  
  1569  	p, err := corecharm.ParsePlatformNormalize(s.CharmOrigin().Platform())
  1570  	if err != nil {
  1571  		return nil, errors.Trace(err)
  1572  	}
  1573  	base := Base{OS: p.OS, Channel: p.Channel}.Normalise()
  1574  	return &unitDoc{
  1575  		Name:                   u.Name(),
  1576  		Application:            s.Name(),
  1577  		Base:                   base,
  1578  		CharmURL:               &charmURL,
  1579  		Principal:              u.Principal().Id(),
  1580  		Subordinates:           subordinates,
  1581  		StorageAttachmentCount: i.unitStorageAttachmentCount(u.Tag()),
  1582  		MachineId:              machineID,
  1583  		Tools:                  agentTools,
  1584  		Life:                   Alive,
  1585  		PasswordHash:           u.PasswordHash(),
  1586  	}, nil
  1587  }
  1588  
  1589  func (i *importer) unitStorageAttachmentCount(unit names.UnitTag) int {
  1590  	count := 0
  1591  	for _, storage := range i.model.Storages() {
  1592  		for _, tag := range storage.Attachments() {
  1593  			if tag == unit {
  1594  				count++
  1595  			}
  1596  		}
  1597  	}
  1598  	return count
  1599  }
  1600  
  1601  func (i *importer) remoteApplications() error {
  1602  	i.logger.Debugf("importing remote applications")
  1603  	migration := &ImportStateMigration{
  1604  		src: i.model,
  1605  		dst: i.st.db(),
  1606  	}
  1607  	migration.Add(func() error {
  1608  		m := ImportRemoteApplications{}
  1609  		return m.Execute(stateDocumentFactoryShim{
  1610  			stateModelNamspaceShim{
  1611  				Model: migration.src,
  1612  				st:    i.st,
  1613  			},
  1614  			i,
  1615  		}, migration.dst)
  1616  	})
  1617  	if err := migration.Run(); err != nil {
  1618  		return errors.Trace(err)
  1619  	}
  1620  	i.logger.Debugf("importing remote applications succeeded")
  1621  	return nil
  1622  }
  1623  
  1624  func (i *importer) firewallRules() error {
  1625  	i.logger.Debugf("importing firewall rules")
  1626  	migration := &ImportStateMigration{
  1627  		src: i.model,
  1628  		dst: i.st.db(),
  1629  	}
  1630  	migration.Add(func() error {
  1631  		m := ImportFirewallRules{}
  1632  		return m.Execute(stateModelNamspaceShim{
  1633  			Model: migration.src,
  1634  			st:    i.st,
  1635  		}, i.dbModel)
  1636  	})
  1637  	if err := migration.Run(); err != nil {
  1638  		return errors.Trace(err)
  1639  	}
  1640  	i.logger.Debugf("importing firewall rules succeeded")
  1641  	return nil
  1642  }
  1643  
  1644  func (i *importer) makeRemoteApplicationDoc(app description.RemoteApplication) *remoteApplicationDoc {
  1645  	doc := &remoteApplicationDoc{
  1646  		Name:            app.Name(),
  1647  		URL:             app.URL(),
  1648  		SourceModelUUID: app.SourceModelTag().Id(),
  1649  		IsConsumerProxy: app.IsConsumerProxy(),
  1650  		Bindings:        app.Bindings(),
  1651  		Macaroon:        app.Macaroon(),
  1652  		Version:         app.ConsumeVersion(),
  1653  	}
  1654  	if !doc.IsConsumerProxy {
  1655  		doc.OfferUUID = app.OfferUUID()
  1656  	}
  1657  	descEndpoints := app.Endpoints()
  1658  	eps := make([]remoteEndpointDoc, len(descEndpoints))
  1659  	for i, ep := range descEndpoints {
  1660  		eps[i] = remoteEndpointDoc{
  1661  			Name:      ep.Name(),
  1662  			Role:      charm.RelationRole(ep.Role()),
  1663  			Interface: ep.Interface(),
  1664  			// TODO: Role, Scope
  1665  		}
  1666  	}
  1667  	doc.Endpoints = eps
  1668  	descSpaces := app.Spaces()
  1669  	spaces := make([]remoteSpaceDoc, len(descSpaces))
  1670  	for i, space := range descSpaces {
  1671  		spaces[i] = remoteSpaceDoc{
  1672  			CloudType:          space.CloudType(),
  1673  			Name:               space.Name(),
  1674  			ProviderId:         space.ProviderId(),
  1675  			ProviderAttributes: space.ProviderAttributes(),
  1676  		}
  1677  		descSubnets := space.Subnets()
  1678  		subnets := make([]remoteSubnetDoc, len(descSubnets))
  1679  		for i, subnet := range descSubnets {
  1680  			subnets[i] = remoteSubnetDoc{
  1681  				CIDR:              subnet.CIDR(),
  1682  				ProviderId:        subnet.ProviderId(),
  1683  				VLANTag:           subnet.VLANTag(),
  1684  				AvailabilityZones: subnet.AvailabilityZones(),
  1685  				ProviderSpaceId:   subnet.ProviderSpaceId(),
  1686  				ProviderNetworkId: subnet.ProviderNetworkId(),
  1687  			}
  1688  		}
  1689  		spaces[i].Subnets = subnets
  1690  	}
  1691  	doc.Spaces = spaces
  1692  	return doc
  1693  }
  1694  
  1695  func (i *importer) relations() error {
  1696  	i.logger.Debugf("importing relations")
  1697  	for _, r := range i.model.Relations() {
  1698  		if err := i.relation(r); err != nil {
  1699  			i.logger.Errorf("error importing relation %s: %s", r.Key(), err)
  1700  			return errors.Annotate(err, r.Key())
  1701  		}
  1702  	}
  1703  
  1704  	i.logger.Debugf("importing relations succeeded")
  1705  	return nil
  1706  }
  1707  
  1708  func (i *importer) relation(rel description.Relation) error {
  1709  	relationDoc := i.makeRelationDoc(rel)
  1710  	ops := []txn.Op{
  1711  		{
  1712  			C:      relationsC,
  1713  			Id:     relationDoc.Key,
  1714  			Assert: txn.DocMissing,
  1715  			Insert: relationDoc,
  1716  		},
  1717  	}
  1718  
  1719  	var relStatusDoc statusDoc
  1720  	relStatus := rel.Status()
  1721  	if relStatus != nil {
  1722  		relStatusDoc = i.makeStatusDoc(relStatus)
  1723  	} else {
  1724  		// Relations are marked as either
  1725  		// joining or joined, depending on
  1726  		// whether there are any units in scope.
  1727  		relStatusDoc = statusDoc{
  1728  			Status:  status.Joining,
  1729  			Updated: time.Now().UnixNano(),
  1730  		}
  1731  		if relationDoc.UnitCount > 0 {
  1732  			relStatusDoc.Status = status.Joined
  1733  		}
  1734  	}
  1735  	ops = append(ops, createStatusOp(i.st, relationGlobalScope(rel.Id()), relStatusDoc))
  1736  
  1737  	dbRelation := newRelation(i.st, relationDoc)
  1738  	// Add an op that adds the relation scope document for each
  1739  	// unit of the application, and an op that adds the relation settings
  1740  	// for each unit.
  1741  	for _, endpoint := range rel.Endpoints() {
  1742  		appKey := relationApplicationSettingsKey(dbRelation.Id(), endpoint.ApplicationName())
  1743  		appSettings := endpoint.ApplicationSettings()
  1744  		ops = append(ops, createSettingsOp(settingsC, appKey, appSettings))
  1745  
  1746  		units := i.applicationUnits[endpoint.ApplicationName()]
  1747  		for unitName, settings := range endpoint.AllSettings() {
  1748  			var ru *RelationUnit
  1749  			var err error
  1750  
  1751  			if unit, ok := units[unitName]; ok {
  1752  				ru, err = dbRelation.Unit(unit)
  1753  				if err != nil {
  1754  					return errors.Trace(err)
  1755  				}
  1756  			} else {
  1757  				ru, err = dbRelation.RemoteUnit(unitName)
  1758  				if err != nil {
  1759  					if errors.Is(err, errors.NotFound) {
  1760  						// This mirrors the logic from export.
  1761  						// If there are no local or remote units in scope,
  1762  						// then we are done for this endpoint.
  1763  						continue
  1764  					}
  1765  					return errors.Trace(err)
  1766  				}
  1767  			}
  1768  
  1769  			ruKey := ru.key()
  1770  			ops = append(ops, txn.Op{
  1771  				C:      relationScopesC,
  1772  				Id:     ruKey,
  1773  				Assert: txn.DocMissing,
  1774  				Insert: relationScopeDoc{
  1775  					Key: ruKey,
  1776  				},
  1777  			},
  1778  				createSettingsOp(settingsC, ruKey, settings),
  1779  			)
  1780  		}
  1781  	}
  1782  
  1783  	if err := i.st.db().RunTransaction(ops); err != nil {
  1784  		return errors.Trace(err)
  1785  	}
  1786  
  1787  	return nil
  1788  }
  1789  
  1790  func (i *importer) makeRelationDoc(rel description.Relation) *relationDoc {
  1791  	endpoints := rel.Endpoints()
  1792  	doc := &relationDoc{
  1793  		Key:       rel.Key(),
  1794  		Id:        rel.Id(),
  1795  		Endpoints: make([]Endpoint, len(endpoints)),
  1796  		Life:      Alive,
  1797  	}
  1798  	for i, ep := range endpoints {
  1799  		doc.Endpoints[i] = Endpoint{
  1800  			ApplicationName: ep.ApplicationName(),
  1801  			Relation: charm.Relation{
  1802  				Name:      ep.Name(),
  1803  				Role:      charm.RelationRole(ep.Role()),
  1804  				Interface: ep.Interface(),
  1805  				Optional:  ep.Optional(),
  1806  				Limit:     ep.Limit(),
  1807  				Scope:     charm.RelationScope(ep.Scope()),
  1808  			},
  1809  		}
  1810  		doc.UnitCount += ep.UnitCount()
  1811  	}
  1812  	return doc
  1813  }
  1814  
  1815  func (i *importer) remoteEntities() error {
  1816  	i.logger.Debugf("importing remote entities")
  1817  	migration := &ImportStateMigration{
  1818  		src: i.model,
  1819  		dst: i.st.db(),
  1820  	}
  1821  	offerUUIDByName := make(map[string]string)
  1822  	for _, app := range i.model.Applications() {
  1823  		for _, offer := range app.Offers() {
  1824  			offerUUIDByName[offer.OfferName()] = offer.OfferUUID()
  1825  		}
  1826  	}
  1827  	migration.Add(func() error {
  1828  		m := ImportRemoteEntities{}
  1829  		return m.Execute(&applicationOffersStateShim{
  1830  			offerUUIDByName: offerUUIDByName,
  1831  			stateModelNamspaceShim: stateModelNamspaceShim{
  1832  				Model: migration.src,
  1833  				st:    i.st,
  1834  			}}, migration.dst)
  1835  	})
  1836  	if err := migration.Run(); err != nil {
  1837  		return errors.Trace(err)
  1838  	}
  1839  	i.logger.Debugf("importing remote entities succeeded")
  1840  	return nil
  1841  }
  1842  
  1843  func (i *importer) relationNetworks() error {
  1844  	i.logger.Debugf("importing relation networks")
  1845  	migration := &ImportStateMigration{
  1846  		src: i.model,
  1847  		dst: i.st.db(),
  1848  	}
  1849  	migration.Add(func() error {
  1850  		m := ImportRelationNetworks{}
  1851  		return m.Execute(stateModelNamspaceShim{
  1852  			Model: migration.src,
  1853  			st:    i.st,
  1854  		}, migration.dst)
  1855  	})
  1856  	if err := migration.Run(); err != nil {
  1857  		return errors.Trace(err)
  1858  	}
  1859  	i.logger.Debugf("importing relation networks succeeded")
  1860  	return nil
  1861  }
  1862  
  1863  func (i *importer) externalControllers() error {
  1864  	i.logger.Debugf("importing external controllers")
  1865  	migration := &ImportStateMigration{
  1866  		src: i.model,
  1867  		dst: i.st.db(),
  1868  	}
  1869  	migration.Add(func() error {
  1870  		m := ImportExternalControllers{}
  1871  		return m.Execute(stateExternalControllerDocumentFactoryShim{
  1872  			stateModelNamspaceShim{
  1873  				Model: migration.src,
  1874  				st:    i.st,
  1875  			},
  1876  			i,
  1877  		}, migration.dst)
  1878  	})
  1879  	if err := migration.Run(); err != nil {
  1880  		return errors.Trace(err)
  1881  	}
  1882  	i.logger.Debugf("importing external controllers succeeded")
  1883  	return nil
  1884  }
  1885  
  1886  // spaces imports spaces without subnets, which are added later.
  1887  func (i *importer) spaces() error {
  1888  	i.logger.Debugf("importing spaces")
  1889  	for _, s := range i.model.Spaces() {
  1890  		// The default space should not have been exported, but be defensive.
  1891  		// Any subnets added to the space will be imported subsequently.
  1892  		if s.Name() == network.AlphaSpaceName {
  1893  			continue
  1894  		}
  1895  
  1896  		if s.Id() == "" {
  1897  			if _, err := i.st.AddSpace(s.Name(), network.Id(s.ProviderID()), nil, s.Public()); err != nil {
  1898  				i.logger.Errorf("error importing space %s: %s", s.Name(), err)
  1899  				return errors.Annotate(err, s.Name())
  1900  			}
  1901  			continue
  1902  		}
  1903  
  1904  		ops := i.st.addSpaceTxnOps(s.Id(), s.Name(), network.Id(s.ProviderID()), s.Public())
  1905  		if err := i.st.db().RunTransaction(ops); err != nil {
  1906  			i.logger.Errorf("error importing space %s: %s", s.Name(), err)
  1907  			return errors.Annotate(err, s.Name())
  1908  		}
  1909  	}
  1910  
  1911  	i.logger.Debugf("importing spaces succeeded")
  1912  	return nil
  1913  }
  1914  
  1915  func (i *importer) linklayerdevices() error {
  1916  	i.logger.Debugf("importing linklayerdevices")
  1917  	for _, device := range i.model.LinkLayerDevices() {
  1918  		err := i.addLinkLayerDevice(device)
  1919  		if err != nil {
  1920  			i.logger.Errorf("error importing ip device %v: %s", device, err)
  1921  			return errors.Trace(err)
  1922  		}
  1923  	}
  1924  	i.logger.Debugf("importing linklayerdevices succeeded")
  1925  	return nil
  1926  }
  1927  
  1928  func (i *importer) addLinkLayerDevice(device description.LinkLayerDevice) error {
  1929  	providerID := device.ProviderID()
  1930  	modelUUID := i.st.ModelUUID()
  1931  	localID := linkLayerDeviceGlobalKey(device.MachineID(), device.Name())
  1932  	linkLayerDeviceDocID := i.st.docID(localID)
  1933  	newDoc := &linkLayerDeviceDoc{
  1934  		ModelUUID:       modelUUID,
  1935  		DocID:           linkLayerDeviceDocID,
  1936  		MachineID:       device.MachineID(),
  1937  		ProviderID:      providerID,
  1938  		Name:            device.Name(),
  1939  		MTU:             device.MTU(),
  1940  		Type:            network.LinkLayerDeviceType(device.Type()),
  1941  		MACAddress:      device.MACAddress(),
  1942  		IsAutoStart:     device.IsAutoStart(),
  1943  		IsUp:            device.IsUp(),
  1944  		ParentName:      device.ParentName(),
  1945  		VirtualPortType: network.VirtualPortType(device.VirtualPortType()),
  1946  	}
  1947  
  1948  	ops := []txn.Op{{
  1949  		C:      linkLayerDevicesC,
  1950  		Id:     newDoc.DocID,
  1951  		Insert: newDoc,
  1952  	}}
  1953  	if providerID != "" {
  1954  		id := network.Id(providerID)
  1955  		ops = append(ops, i.st.networkEntityGlobalKeyOp("linklayerdevice", id))
  1956  	}
  1957  	if err := i.st.db().RunTransaction(ops); err != nil {
  1958  		return errors.Trace(err)
  1959  	}
  1960  	return nil
  1961  }
  1962  
  1963  func (i *importer) subnets() error {
  1964  	i.logger.Debugf("importing subnets")
  1965  	for _, subnet := range i.model.Subnets() {
  1966  		info := network.SubnetInfo{
  1967  			CIDR:              subnet.CIDR(),
  1968  			ProviderId:        network.Id(subnet.ProviderId()),
  1969  			ProviderNetworkId: network.Id(subnet.ProviderNetworkId()),
  1970  			VLANTag:           subnet.VLANTag(),
  1971  			AvailabilityZones: subnet.AvailabilityZones(),
  1972  			IsPublic:          subnet.IsPublic(),
  1973  			SpaceID:           subnet.SpaceID(),
  1974  
  1975  			// SpaceName will only be present when migrating from pre-2.7
  1976  			// models. We use it to look up a space ID.
  1977  			SpaceName: subnet.SpaceName(),
  1978  		}
  1979  		info.SetFan(subnet.FanLocalUnderlay(), subnet.FanOverlay())
  1980  
  1981  		if info.SpaceID == "" && info.SpaceName != "" {
  1982  			space, err := i.st.SpaceByName(subnet.SpaceName())
  1983  			if err != nil {
  1984  				return errors.Trace(err)
  1985  			}
  1986  			info.SpaceID = space.Id()
  1987  		}
  1988  
  1989  		snID := subnet.ID()
  1990  		if snID == "" {
  1991  			seq, err := sequence(i.st, "subnet")
  1992  			if err != nil {
  1993  				return errors.Trace(err)
  1994  			}
  1995  			snID = strconv.Itoa(seq)
  1996  		}
  1997  		err := i.addSubnet(snID, info)
  1998  		if err != nil {
  1999  			return errors.Trace(err)
  2000  		}
  2001  	}
  2002  	i.logger.Debugf("importing subnets succeeded")
  2003  	return nil
  2004  }
  2005  
  2006  func (i *importer) addSubnet(id string, args network.SubnetInfo) error {
  2007  	buildTxn := func(attempt int) ([]txn.Op, error) {
  2008  		subnetDoc, ops, err := i.st.addSubnetOps(id, args)
  2009  		if err != nil {
  2010  			return nil, errors.Trace(err)
  2011  		}
  2012  		subnet := &Subnet{st: i.st, doc: subnetDoc}
  2013  		if attempt != 0 {
  2014  			if _, err = i.st.Subnet(id); err == nil {
  2015  				return nil, errors.AlreadyExistsf("subnet %q", args.CIDR)
  2016  			}
  2017  			if err := subnet.Refresh(); err != nil {
  2018  				if errors.IsNotFound(err) {
  2019  					return nil, errors.Errorf("ProviderId %q not unique", args.ProviderId)
  2020  				}
  2021  				return nil, errors.Trace(err)
  2022  			}
  2023  		}
  2024  		return ops, nil
  2025  	}
  2026  	err := i.st.db().Run(buildTxn)
  2027  	if err != nil {
  2028  		return errors.Trace(err)
  2029  	}
  2030  	return nil
  2031  }
  2032  
  2033  func (i *importer) ipAddresses() error {
  2034  	i.logger.Debugf("importing IP addresses")
  2035  	for _, addr := range i.model.IPAddresses() {
  2036  		err := i.addIPAddress(addr)
  2037  		if err != nil {
  2038  			i.logger.Errorf("error importing IP address %v: %s", addr, err)
  2039  			return errors.Trace(err)
  2040  		}
  2041  	}
  2042  	i.logger.Debugf("importing IP addresses succeeded")
  2043  	return nil
  2044  }
  2045  
  2046  func (i *importer) addIPAddress(addr description.IPAddress) error {
  2047  	addressValue := addr.Value()
  2048  	subnetCIDR := addr.SubnetCIDR()
  2049  
  2050  	globalKey := ipAddressGlobalKey(addr.MachineID(), addr.DeviceName(), addressValue)
  2051  	ipAddressDocID := i.st.docID(globalKey)
  2052  	providerID := addr.ProviderID()
  2053  
  2054  	modelUUID := i.st.ModelUUID()
  2055  
  2056  	// Compatibility shim for deployments prior to 2.9.1.
  2057  	configType := addr.ConfigMethod()
  2058  	if configType == "dynamic" {
  2059  		configType = string(network.ConfigDHCP)
  2060  	}
  2061  
  2062  	newDoc := &ipAddressDoc{
  2063  		DocID:             ipAddressDocID,
  2064  		ModelUUID:         modelUUID,
  2065  		ProviderID:        providerID,
  2066  		DeviceName:        addr.DeviceName(),
  2067  		MachineID:         addr.MachineID(),
  2068  		SubnetCIDR:        subnetCIDR,
  2069  		ConfigMethod:      network.AddressConfigType(configType),
  2070  		Value:             addressValue,
  2071  		DNSServers:        addr.DNSServers(),
  2072  		DNSSearchDomains:  addr.DNSSearchDomains(),
  2073  		GatewayAddress:    addr.GatewayAddress(),
  2074  		IsDefaultGateway:  addr.IsDefaultGateway(),
  2075  		ProviderNetworkID: addr.ProviderNetworkID(),
  2076  		ProviderSubnetID:  addr.ProviderSubnetID(),
  2077  		Origin:            network.Origin(addr.Origin()),
  2078  		IsShadow:          addr.IsShadow(),
  2079  		IsSecondary:       addr.IsSecondary(),
  2080  	}
  2081  
  2082  	ops := []txn.Op{{
  2083  		C:      ipAddressesC,
  2084  		Id:     newDoc.DocID,
  2085  		Insert: newDoc,
  2086  	}}
  2087  
  2088  	if providerID != "" {
  2089  		id := network.Id(providerID)
  2090  		ops = append(ops, i.st.networkEntityGlobalKeyOp("address", id))
  2091  	}
  2092  	if err := i.st.db().RunTransaction(ops); err != nil {
  2093  		return errors.Trace(err)
  2094  	}
  2095  	return nil
  2096  }
  2097  
  2098  func (i *importer) sshHostKeys() error {
  2099  	i.logger.Debugf("importing ssh host keys")
  2100  	for _, key := range i.model.SSHHostKeys() {
  2101  		name := names.NewMachineTag(key.MachineID())
  2102  		err := i.st.SetSSHHostKeys(name, key.Keys())
  2103  		if err != nil {
  2104  			i.logger.Errorf("error importing ssh host keys %v: %s", key, err)
  2105  			return errors.Trace(err)
  2106  		}
  2107  	}
  2108  	i.logger.Debugf("importing ssh host keys succeeded")
  2109  	return nil
  2110  }
  2111  
  2112  func (i *importer) cloudimagemetadata() error {
  2113  	i.logger.Debugf("importing cloudimagemetadata")
  2114  	images := i.model.CloudImageMetadata()
  2115  	var metadatas []cloudimagemetadata.Metadata
  2116  	for _, image := range images {
  2117  		// We only want to import custom (user defined metadata).
  2118  		// Everything else *now* expires after a set time anyway and
  2119  		// coming from Juju < 2.3.4 would result in non-expiring metadata.
  2120  		if image.Source() != "custom" {
  2121  			continue
  2122  		}
  2123  		var rootStoragePtr *uint64
  2124  		if rootStorageSize, ok := image.RootStorageSize(); ok {
  2125  			rootStoragePtr = &rootStorageSize
  2126  		}
  2127  		metadatas = append(metadatas, cloudimagemetadata.Metadata{
  2128  			MetadataAttributes: cloudimagemetadata.MetadataAttributes{
  2129  				Source:          image.Source(),
  2130  				Stream:          image.Stream(),
  2131  				Region:          image.Region(),
  2132  				Version:         image.Version(),
  2133  				Arch:            image.Arch(),
  2134  				RootStorageType: image.RootStorageType(),
  2135  				RootStorageSize: rootStoragePtr,
  2136  				VirtType:        image.VirtType(),
  2137  			},
  2138  			Priority:    image.Priority(),
  2139  			ImageId:     image.ImageId(),
  2140  			DateCreated: image.DateCreated(),
  2141  		})
  2142  	}
  2143  	err := i.st.CloudImageMetadataStorage.SaveMetadata(metadatas)
  2144  	if err != nil {
  2145  		i.logger.Errorf("error importing cloudimagemetadata %v: %s", images, err)
  2146  		return errors.Trace(err)
  2147  	}
  2148  	i.logger.Debugf("importing cloudimagemetadata succeeded")
  2149  	return nil
  2150  }
  2151  
  2152  func (i *importer) actions() error {
  2153  	i.logger.Debugf("importing actions")
  2154  	for _, action := range i.model.Actions() {
  2155  		err := i.addAction(action)
  2156  		if err != nil {
  2157  			i.logger.Errorf("error importing action %v: %s", action, err)
  2158  			return errors.Trace(err)
  2159  		}
  2160  	}
  2161  	i.logger.Debugf("importing actions succeeded")
  2162  	return nil
  2163  }
  2164  
  2165  func (i *importer) addAction(action description.Action) error {
  2166  	modelUUID := i.st.ModelUUID()
  2167  	newDoc := &actionDoc{
  2168  		DocId:          i.st.docID(action.Id()),
  2169  		ModelUUID:      modelUUID,
  2170  		Receiver:       action.Receiver(),
  2171  		Name:           action.Name(),
  2172  		Operation:      action.Operation(),
  2173  		Parameters:     action.Parameters(),
  2174  		Enqueued:       action.Enqueued(),
  2175  		Results:        action.Results(),
  2176  		Message:        action.Message(),
  2177  		Started:        action.Started(),
  2178  		Completed:      action.Completed(),
  2179  		Status:         ActionStatus(action.Status()),
  2180  		Parallel:       action.Parallel(),
  2181  		ExecutionGroup: action.ExecutionGroup(),
  2182  	}
  2183  
  2184  	ops := []txn.Op{{
  2185  		C:      actionsC,
  2186  		Id:     newDoc.DocId,
  2187  		Insert: newDoc,
  2188  	}}
  2189  
  2190  	if activeStatus.Contains(string(newDoc.Status)) {
  2191  		prefix := ensureActionMarker(action.Receiver())
  2192  		notificationDoc := &actionNotificationDoc{
  2193  			DocId:     i.st.docID(prefix + action.Id()),
  2194  			ModelUUID: modelUUID,
  2195  			Receiver:  action.Receiver(),
  2196  			ActionID:  action.Id(),
  2197  		}
  2198  		ops = append(ops, txn.Op{
  2199  			C:      actionNotificationsC,
  2200  			Id:     notificationDoc.DocId,
  2201  			Insert: notificationDoc,
  2202  		})
  2203  	}
  2204  
  2205  	if err := i.st.db().RunTransaction(ops); err != nil {
  2206  		return errors.Trace(err)
  2207  	}
  2208  	return nil
  2209  }
  2210  
  2211  // operations takes the imported operations data and writes it to
  2212  // the new model.
  2213  func (i *importer) operations() error {
  2214  	i.logger.Debugf("importing operations")
  2215  	for _, op := range i.model.Operations() {
  2216  		err := i.addOperation(op)
  2217  		if err != nil {
  2218  			i.logger.Errorf("error importing operation %v: %s", op, err)
  2219  			return errors.Trace(err)
  2220  		}
  2221  	}
  2222  	i.logger.Debugf("importing operations succeeded")
  2223  	return nil
  2224  }
  2225  
  2226  func (i *importer) addOperation(op description.Operation) error {
  2227  	modelUUID := i.st.ModelUUID()
  2228  	newDoc := &operationDoc{
  2229  		DocId:             i.st.docID(op.Id()),
  2230  		ModelUUID:         modelUUID,
  2231  		Summary:           op.Summary(),
  2232  		Fail:              op.Fail(),
  2233  		Enqueued:          op.Enqueued(),
  2234  		Started:           op.Started(),
  2235  		Completed:         op.Completed(),
  2236  		Status:            ActionStatus(op.Status()),
  2237  		CompleteTaskCount: op.CompleteTaskCount(),
  2238  		SpawnedTaskCount:  i.countActionTasksForOperation(op),
  2239  	}
  2240  	ops := []txn.Op{{
  2241  		C:      operationsC,
  2242  		Id:     newDoc.DocId,
  2243  		Insert: newDoc,
  2244  	}}
  2245  
  2246  	if err := i.st.db().RunTransaction(ops); err != nil {
  2247  		return errors.Trace(err)
  2248  	}
  2249  	return nil
  2250  }
  2251  
  2252  func (i *importer) countActionTasksForOperation(op description.Operation) int {
  2253  	if op.SpawnedTaskCount() > 0 {
  2254  		return op.SpawnedTaskCount()
  2255  	}
  2256  	opID := op.Id()
  2257  	var count int
  2258  	for _, action := range i.model.Actions() {
  2259  		if action.Operation() == opID {
  2260  			count += 1
  2261  		}
  2262  	}
  2263  	return count
  2264  }
  2265  
  2266  func (i *importer) importStatusHistory(globalKey string, history []description.Status) error {
  2267  	docs := make([]interface{}, len(history))
  2268  	for i, statusVal := range history {
  2269  		docs[i] = historicalStatusDoc{
  2270  			GlobalKey:  globalKey,
  2271  			Status:     status.Status(statusVal.Value()),
  2272  			StatusInfo: statusVal.Message(),
  2273  			StatusData: statusVal.Data(),
  2274  			Updated:    statusVal.Updated().UnixNano(),
  2275  		}
  2276  	}
  2277  	if len(docs) == 0 {
  2278  		return nil
  2279  	}
  2280  
  2281  	statusHistory, closer := i.st.db().GetCollection(statusesHistoryC)
  2282  	defer closer()
  2283  
  2284  	if err := statusHistory.Writeable().Insert(docs...); err != nil {
  2285  		return errors.Trace(err)
  2286  	}
  2287  	return nil
  2288  }
  2289  
  2290  func (i *importer) constraints(cons description.Constraints) constraints.Value {
  2291  	var result constraints.Value
  2292  	if cons == nil {
  2293  		return result
  2294  	}
  2295  
  2296  	if allocate := cons.AllocatePublicIP(); allocate {
  2297  		result.AllocatePublicIP = &allocate
  2298  	}
  2299  	if arch := cons.Architecture(); arch != "" {
  2300  		result.Arch = &arch
  2301  	}
  2302  	if container := instance.ContainerType(cons.Container()); container != "" {
  2303  		result.Container = &container
  2304  	}
  2305  	if cores := cons.CpuCores(); cores != 0 {
  2306  		result.CpuCores = &cores
  2307  	}
  2308  	if power := cons.CpuPower(); power != 0 {
  2309  		result.CpuPower = &power
  2310  	}
  2311  	if inst := cons.InstanceType(); inst != "" {
  2312  		result.InstanceType = &inst
  2313  	}
  2314  	if mem := cons.Memory(); mem != 0 {
  2315  		result.Mem = &mem
  2316  	}
  2317  	if disk := cons.RootDisk(); disk != 0 {
  2318  		result.RootDisk = &disk
  2319  	}
  2320  	if source := cons.RootDiskSource(); source != "" {
  2321  		result.RootDiskSource = &source
  2322  	}
  2323  	if spaces := cons.Spaces(); len(spaces) > 0 {
  2324  		result.Spaces = &spaces
  2325  	}
  2326  	if tags := cons.Tags(); len(tags) > 0 {
  2327  		result.Tags = &tags
  2328  	}
  2329  	if virt := cons.VirtType(); virt != "" {
  2330  		result.VirtType = &virt
  2331  	}
  2332  	if zones := cons.Zones(); len(zones) > 0 {
  2333  		result.Zones = &zones
  2334  	}
  2335  	return result
  2336  }
  2337  
  2338  func (i *importer) storage() error {
  2339  	if err := i.storagePools(); err != nil {
  2340  		return errors.Annotate(err, "storage pools")
  2341  	}
  2342  	if err := i.storageInstances(); err != nil {
  2343  		return errors.Annotate(err, "storage instances")
  2344  	}
  2345  	if err := i.volumes(); err != nil {
  2346  		return errors.Annotate(err, "volumes")
  2347  	}
  2348  	if err := i.filesystems(); err != nil {
  2349  		return errors.Annotate(err, "filesystems")
  2350  	}
  2351  	return nil
  2352  }
  2353  
  2354  func (i *importer) storageInstances() error {
  2355  	i.logger.Debugf("importing storage instances")
  2356  	for _, storage := range i.model.Storages() {
  2357  		err := i.addStorageInstance(storage)
  2358  		if err != nil {
  2359  			i.logger.Errorf("error importing storage %s: %s", storage.Tag(), err)
  2360  			return errors.Trace(err)
  2361  		}
  2362  	}
  2363  	i.logger.Debugf("importing storage instances succeeded")
  2364  	return nil
  2365  }
  2366  
  2367  func (i *importer) addStorageInstance(storage description.Storage) error {
  2368  	kind := parseStorageKind(storage.Kind())
  2369  	if kind == StorageKindUnknown {
  2370  		return errors.Errorf("storage kind %q is unknown", storage.Kind())
  2371  	}
  2372  	owner, err := storage.Owner()
  2373  	if err != nil {
  2374  		return errors.Annotate(err, "storage owner")
  2375  	}
  2376  	var storageOwner string
  2377  	if owner != nil {
  2378  		storageOwner = owner.String()
  2379  	}
  2380  	attachments := storage.Attachments()
  2381  	tag := storage.Tag()
  2382  	var ops []txn.Op
  2383  	for _, unit := range attachments {
  2384  		ops = append(ops, createStorageAttachmentOp(tag, unit))
  2385  	}
  2386  	doc := &storageInstanceDoc{
  2387  		Id:              storage.Tag().Id(),
  2388  		Kind:            kind,
  2389  		Owner:           storageOwner,
  2390  		StorageName:     storage.Name(),
  2391  		AttachmentCount: len(attachments),
  2392  		Constraints:     i.storageInstanceConstraints(storage),
  2393  	}
  2394  	ops = append(ops, txn.Op{
  2395  		C:      storageInstancesC,
  2396  		Id:     tag.Id(),
  2397  		Assert: txn.DocMissing,
  2398  		Insert: doc,
  2399  	})
  2400  
  2401  	if owner != nil {
  2402  		refcounts, closer := i.st.db().GetCollection(refcountsC)
  2403  		defer closer()
  2404  		storageRefcountKey := entityStorageRefcountKey(owner, storage.Name())
  2405  		incRefOp, err := nsRefcounts.CreateOrIncRefOp(refcounts, storageRefcountKey, 1)
  2406  		if err != nil {
  2407  			return errors.Trace(err)
  2408  		}
  2409  		ops = append(ops, incRefOp)
  2410  	}
  2411  
  2412  	if err := i.st.db().RunTransaction(ops); err != nil {
  2413  		return errors.Trace(err)
  2414  	}
  2415  	return nil
  2416  }
  2417  
  2418  func (i *importer) storageInstanceConstraints(storage description.Storage) storageInstanceConstraints {
  2419  	if cons, ok := storage.Constraints(); ok {
  2420  		return storageInstanceConstraints(cons)
  2421  	}
  2422  	// Older versions of Juju did not record storage constraints on the
  2423  	// storage instance, so we must do what we do during upgrade steps:
  2424  	// reconstitute the constraints from the corresponding volume or
  2425  	// filesystem, or else look in the owner's application storage
  2426  	// constraints, and if all else fails, apply the defaults.
  2427  	var cons storageInstanceConstraints
  2428  	var defaultPool string
  2429  	switch parseStorageKind(storage.Kind()) {
  2430  	case StorageKindBlock:
  2431  		defaultPool = string(provider.LoopProviderType)
  2432  		for _, volume := range i.model.Volumes() {
  2433  			if volume.Storage() == storage.Tag() {
  2434  				cons.Pool = volume.Pool()
  2435  				cons.Size = volume.Size()
  2436  				break
  2437  			}
  2438  		}
  2439  	case StorageKindFilesystem:
  2440  		defaultPool = string(provider.RootfsProviderType)
  2441  		for _, filesystem := range i.model.Filesystems() {
  2442  			if filesystem.Storage() == storage.Tag() {
  2443  				cons.Pool = filesystem.Pool()
  2444  				cons.Size = filesystem.Size()
  2445  				break
  2446  			}
  2447  		}
  2448  	}
  2449  	if cons.Pool == "" {
  2450  		cons.Pool = defaultPool
  2451  		cons.Size = 1024
  2452  		if owner, _ := storage.Owner(); owner != nil {
  2453  			var appName string
  2454  			switch owner := owner.(type) {
  2455  			case names.ApplicationTag:
  2456  				appName = owner.Id()
  2457  			case names.UnitTag:
  2458  				appName, _ = names.UnitApplication(owner.Id())
  2459  			}
  2460  			for _, app := range i.model.Applications() {
  2461  				if app.Name() != appName {
  2462  					continue
  2463  				}
  2464  				storageName, _ := names.StorageName(storage.Tag().Id())
  2465  				appStorageCons, ok := app.StorageDirectives()[storageName]
  2466  				if ok {
  2467  					cons.Pool = appStorageCons.Pool()
  2468  					cons.Size = appStorageCons.Size()
  2469  				}
  2470  				break
  2471  			}
  2472  		}
  2473  		logger.Warningf(
  2474  			"no volume or filesystem found, using application storage constraints for %s",
  2475  			names.ReadableString(storage.Tag()),
  2476  		)
  2477  	}
  2478  	return cons
  2479  }
  2480  
  2481  func (i *importer) volumes() error {
  2482  	i.logger.Debugf("importing volumes")
  2483  	sb, err := NewStorageBackend(i.st)
  2484  	if err != nil {
  2485  		return errors.Trace(err)
  2486  	}
  2487  	for _, volume := range i.model.Volumes() {
  2488  		err := i.addVolume(volume, sb)
  2489  		if err != nil {
  2490  			i.logger.Errorf("error importing volume %s: %s", volume.Tag(), err)
  2491  			return errors.Trace(err)
  2492  		}
  2493  	}
  2494  	i.logger.Debugf("importing volumes succeeded")
  2495  	return nil
  2496  }
  2497  
  2498  func (i *importer) addVolume(volume description.Volume, sb *storageBackend) error {
  2499  	attachments := volume.Attachments()
  2500  	attachmentPlans := volume.AttachmentPlans()
  2501  
  2502  	tag := volume.Tag()
  2503  	var params *VolumeParams
  2504  	var info *VolumeInfo
  2505  	if volume.Provisioned() {
  2506  		info = &VolumeInfo{
  2507  			HardwareId: volume.HardwareID(),
  2508  			WWN:        volume.WWN(),
  2509  			Size:       volume.Size(),
  2510  			Pool:       volume.Pool(),
  2511  			VolumeId:   volume.VolumeID(),
  2512  			Persistent: volume.Persistent(),
  2513  		}
  2514  	} else {
  2515  		params = &VolumeParams{
  2516  			Size: volume.Size(),
  2517  			Pool: volume.Pool(),
  2518  		}
  2519  	}
  2520  	doc := volumeDoc{
  2521  		Name:      tag.Id(),
  2522  		StorageId: volume.Storage().Id(),
  2523  		// Life: ..., // TODO: import life, default is Alive
  2524  		Params:          params,
  2525  		Info:            info,
  2526  		AttachmentCount: len(attachments),
  2527  	}
  2528  	if detachable, err := isDetachableVolumePool(sb, volume.Pool()); err != nil {
  2529  		return errors.Trace(err)
  2530  	} else if !detachable && len(attachments) == 1 {
  2531  		doc.HostId = attachments[0].Host().Id()
  2532  	}
  2533  	status := i.makeStatusDoc(volume.Status())
  2534  	ops := sb.newVolumeOps(doc, status)
  2535  
  2536  	for _, attachment := range attachments {
  2537  		ops = append(ops, i.addVolumeAttachmentOp(tag.Id(), attachment, attachment.VolumePlanInfo()))
  2538  	}
  2539  
  2540  	if len(attachmentPlans) > 0 {
  2541  		for _, val := range attachmentPlans {
  2542  			ops = append(ops, i.addVolumeAttachmentPlanOp(tag.Id(), val))
  2543  		}
  2544  	}
  2545  
  2546  	if err := i.st.db().RunTransaction(ops); err != nil {
  2547  		return errors.Trace(err)
  2548  	}
  2549  
  2550  	if err := i.importStatusHistory(volumeGlobalKey(tag.Id()), volume.StatusHistory()); err != nil {
  2551  		return errors.Annotate(err, "status history")
  2552  	}
  2553  	return nil
  2554  }
  2555  
  2556  func (i *importer) addVolumeAttachmentPlanOp(volID string, volumePlan description.VolumeAttachmentPlan) txn.Op {
  2557  	descriptionPlanInfo := volumePlan.VolumePlanInfo()
  2558  	planInfo := &VolumeAttachmentPlanInfo{
  2559  		DeviceType:       storage.DeviceType(descriptionPlanInfo.DeviceType()),
  2560  		DeviceAttributes: descriptionPlanInfo.DeviceAttributes(),
  2561  	}
  2562  
  2563  	descriptionBlockInfo := volumePlan.BlockDevice()
  2564  	blockInfo := &BlockDeviceInfo{
  2565  		DeviceName:     descriptionBlockInfo.Name(),
  2566  		DeviceLinks:    descriptionBlockInfo.Links(),
  2567  		Label:          descriptionBlockInfo.Label(),
  2568  		UUID:           descriptionBlockInfo.UUID(),
  2569  		HardwareId:     descriptionBlockInfo.HardwareID(),
  2570  		WWN:            descriptionBlockInfo.WWN(),
  2571  		BusAddress:     descriptionBlockInfo.BusAddress(),
  2572  		Size:           descriptionBlockInfo.Size(),
  2573  		FilesystemType: descriptionBlockInfo.FilesystemType(),
  2574  		InUse:          descriptionBlockInfo.InUse(),
  2575  		MountPoint:     descriptionBlockInfo.MountPoint(),
  2576  	}
  2577  
  2578  	machineId := volumePlan.Machine().Id()
  2579  	return txn.Op{
  2580  		C:      volumeAttachmentPlanC,
  2581  		Id:     volumeAttachmentId(machineId, volID),
  2582  		Assert: txn.DocMissing,
  2583  		Insert: &volumeAttachmentPlanDoc{
  2584  			Volume:      volID,
  2585  			Machine:     machineId,
  2586  			PlanInfo:    planInfo,
  2587  			BlockDevice: blockInfo,
  2588  		},
  2589  	}
  2590  }
  2591  
  2592  func (i *importer) addVolumeAttachmentOp(volID string, attachment description.VolumeAttachment, planInfo description.VolumePlanInfo) txn.Op {
  2593  	var info *VolumeAttachmentInfo
  2594  	var params *VolumeAttachmentParams
  2595  
  2596  	planInf := &VolumeAttachmentPlanInfo{}
  2597  
  2598  	deviceType := planInfo.DeviceType()
  2599  	deviceAttrs := planInfo.DeviceAttributes()
  2600  	if deviceType != "" || deviceAttrs != nil {
  2601  		if deviceType != "" {
  2602  			planInf.DeviceType = storage.DeviceType(deviceType)
  2603  		}
  2604  		if deviceAttrs != nil {
  2605  			planInf.DeviceAttributes = deviceAttrs
  2606  		}
  2607  	} else {
  2608  		planInf = nil
  2609  	}
  2610  
  2611  	if attachment.Provisioned() {
  2612  		info = &VolumeAttachmentInfo{
  2613  			DeviceName: attachment.DeviceName(),
  2614  			DeviceLink: attachment.DeviceLink(),
  2615  			BusAddress: attachment.BusAddress(),
  2616  			ReadOnly:   attachment.ReadOnly(),
  2617  			PlanInfo:   planInf,
  2618  		}
  2619  	} else {
  2620  		params = &VolumeAttachmentParams{
  2621  			ReadOnly: attachment.ReadOnly(),
  2622  		}
  2623  	}
  2624  
  2625  	hostId := attachment.Host().Id()
  2626  	return txn.Op{
  2627  		C:      volumeAttachmentsC,
  2628  		Id:     volumeAttachmentId(hostId, volID),
  2629  		Assert: txn.DocMissing,
  2630  		Insert: &volumeAttachmentDoc{
  2631  			Volume: volID,
  2632  			Host:   hostId,
  2633  			Params: params,
  2634  			Info:   info,
  2635  		},
  2636  	}
  2637  }
  2638  
  2639  func (i *importer) filesystems() error {
  2640  	i.logger.Debugf("importing filesystems")
  2641  	sb, err := NewStorageBackend(i.st)
  2642  	if err != nil {
  2643  		return errors.Trace(err)
  2644  	}
  2645  	for _, fs := range i.model.Filesystems() {
  2646  		err := i.addFilesystem(fs, sb)
  2647  		if err != nil {
  2648  			i.logger.Errorf("error importing filesystem %s: %s", fs.Tag(), err)
  2649  			return errors.Trace(err)
  2650  		}
  2651  	}
  2652  	i.logger.Debugf("importing filesystems succeeded")
  2653  	return nil
  2654  }
  2655  
  2656  func (i *importer) addFilesystem(filesystem description.Filesystem, sb *storageBackend) error {
  2657  
  2658  	attachments := filesystem.Attachments()
  2659  	tag := filesystem.Tag()
  2660  	var params *FilesystemParams
  2661  	var info *FilesystemInfo
  2662  	if filesystem.Provisioned() {
  2663  		info = &FilesystemInfo{
  2664  			Size:         filesystem.Size(),
  2665  			Pool:         filesystem.Pool(),
  2666  			FilesystemId: filesystem.FilesystemID(),
  2667  		}
  2668  	} else {
  2669  		params = &FilesystemParams{
  2670  			Size: filesystem.Size(),
  2671  			Pool: filesystem.Pool(),
  2672  		}
  2673  	}
  2674  	doc := filesystemDoc{
  2675  		FilesystemId: tag.Id(),
  2676  		StorageId:    filesystem.Storage().Id(),
  2677  		VolumeId:     filesystem.Volume().Id(),
  2678  		// Life: ..., // TODO: import life, default is Alive
  2679  		Params:          params,
  2680  		Info:            info,
  2681  		AttachmentCount: len(attachments),
  2682  	}
  2683  	if detachable, err := isDetachableFilesystemPool(sb, filesystem.Pool()); err != nil {
  2684  		return errors.Trace(err)
  2685  	} else if !detachable && len(attachments) == 1 {
  2686  		doc.HostId = attachments[0].Host().Id()
  2687  	}
  2688  	status := i.makeStatusDoc(filesystem.Status())
  2689  	ops := sb.newFilesystemOps(doc, status)
  2690  
  2691  	for _, attachment := range attachments {
  2692  		ops = append(ops, i.addFilesystemAttachmentOp(tag.Id(), attachment))
  2693  	}
  2694  
  2695  	if err := i.st.db().RunTransaction(ops); err != nil {
  2696  		return errors.Trace(err)
  2697  	}
  2698  
  2699  	if err := i.importStatusHistory(filesystemGlobalKey(tag.Id()), filesystem.StatusHistory()); err != nil {
  2700  		return errors.Annotate(err, "status history")
  2701  	}
  2702  	return nil
  2703  }
  2704  
  2705  func (i *importer) addFilesystemAttachmentOp(fsID string, attachment description.FilesystemAttachment) txn.Op {
  2706  	var info *FilesystemAttachmentInfo
  2707  	var params *FilesystemAttachmentParams
  2708  	if attachment.Provisioned() {
  2709  		info = &FilesystemAttachmentInfo{
  2710  			MountPoint: attachment.MountPoint(),
  2711  			ReadOnly:   attachment.ReadOnly(),
  2712  		}
  2713  	} else {
  2714  		params = &FilesystemAttachmentParams{
  2715  			Location: attachment.MountPoint(),
  2716  			ReadOnly: attachment.ReadOnly(),
  2717  		}
  2718  	}
  2719  
  2720  	hostId := attachment.Host().Id()
  2721  	return txn.Op{
  2722  		C:      filesystemAttachmentsC,
  2723  		Id:     filesystemAttachmentId(hostId, fsID),
  2724  		Assert: txn.DocMissing,
  2725  		Insert: &filesystemAttachmentDoc{
  2726  			Filesystem: fsID,
  2727  			Host:       hostId,
  2728  			// Life: ..., // TODO: import life, default is Alive
  2729  			Params: params,
  2730  			Info:   info,
  2731  		},
  2732  	}
  2733  }
  2734  
  2735  func (i *importer) storagePools() error {
  2736  	registry, err := i.st.storageProviderRegistry()
  2737  	if err != nil {
  2738  		return errors.Annotate(err, "getting provider registry")
  2739  	}
  2740  	pm := poolmanager.New(NewStateSettings(i.st), registry)
  2741  
  2742  	for _, pool := range i.model.StoragePools() {
  2743  		_, err := pm.Create(pool.Name(), storage.ProviderType(pool.Provider()), pool.Attributes())
  2744  		if err != nil {
  2745  			return errors.Annotatef(err, "creating pool %q", pool.Name())
  2746  		}
  2747  	}
  2748  	return nil
  2749  }
  2750  
  2751  func (i *importer) secretBackend() error {
  2752  	mCfg, err := i.dbModel.ModelConfig()
  2753  	if err != nil {
  2754  		return errors.Trace(err)
  2755  	}
  2756  	mSecretBackendName := mCfg.SecretBackend()
  2757  	if mSecretBackendName == "" || mSecretBackendName == secretsprovider.Auto || mSecretBackendName == secretsprovider.Internal {
  2758  		return nil
  2759  	}
  2760  
  2761  	backendID := i.model.SecretBackendID()
  2762  	if backendID == "" {
  2763  		// We reject if no backend ID is set, because we don't want to accidentally drain secrets to the wrong backend.
  2764  		// So we suggest to upgrade the source controller if no backend ID in the exported data(because the source model is too old).
  2765  		return errors.NotFoundf("secret backend config %q in model export", mSecretBackendName)
  2766  	}
  2767  	i.logger.Debugf("importing secret backend")
  2768  	backends := NewSecretBackends(i.st)
  2769  	mBackend, err := backends.GetSecretBackendByID(backendID)
  2770  	if err != nil {
  2771  		return errors.Annotatef(err, "cannot load secret backend %q", backendID)
  2772  	}
  2773  	err = i.dbModel.UpdateModelConfig(map[string]interface{}{config.SecretBackendKey: mBackend.Name}, nil)
  2774  	return errors.Trace(err)
  2775  }
  2776  
  2777  func (i *importer) secrets() error {
  2778  	i.logger.Debugf("importing secrets")
  2779  	backends := NewSecretBackends(i.st)
  2780  	allBackends, err := backends.ListSecretBackends()
  2781  	if err != nil {
  2782  		return errors.Annotate(err, "loading secret backends")
  2783  	}
  2784  
  2785  	knownBackends := set.NewStrings()
  2786  	for _, b := range allBackends {
  2787  		knownBackends.Add(b.ID)
  2788  	}
  2789  
  2790  	migration := &ImportStateMigration{
  2791  		src:                 i.model,
  2792  		dst:                 i.st.db(),
  2793  		knownSecretBackends: knownBackends,
  2794  	}
  2795  	migration.Add(func() error {
  2796  		m := ImportSecrets{}
  2797  		return m.Execute(&secretStateShim{
  2798  			stateModelNamspaceShim: stateModelNamspaceShim{
  2799  				Model: migration.src,
  2800  				st:    i.st,
  2801  			},
  2802  		}, migration.dst, migration.knownSecretBackends)
  2803  	})
  2804  	if err := migration.Run(); err != nil {
  2805  		return errors.Trace(err)
  2806  	}
  2807  	i.logger.Debugf("importing secrets succeeded")
  2808  	return nil
  2809  }
  2810  
  2811  func (i *importer) remoteSecrets() error {
  2812  	i.logger.Debugf("importing remote secret references")
  2813  	migration := &ImportStateMigration{
  2814  		src: i.model,
  2815  		dst: i.st.db(),
  2816  	}
  2817  	migration.Add(func() error {
  2818  		m := ImportRemoteSecrets{}
  2819  		return m.Execute(&secretStateShim{
  2820  			stateModelNamspaceShim: stateModelNamspaceShim{
  2821  				Model: migration.src,
  2822  				st:    i.st,
  2823  			},
  2824  		}, migration.dst)
  2825  	})
  2826  	if err := migration.Run(); err != nil {
  2827  		return errors.Trace(err)
  2828  	}
  2829  	i.logger.Debugf("importing remote secret references succeeded")
  2830  	return nil
  2831  }