github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/migration_import_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	"fmt"
     8  	"sort"
     9  	"strconv"
    10  	"time" // only uses time.Time values
    11  
    12  	"github.com/juju/charm/v12"
    13  	"github.com/juju/description/v5"
    14  	"github.com/juju/errors"
    15  	"github.com/juju/names/v5"
    16  	jc "github.com/juju/testing/checkers"
    17  	"github.com/juju/utils/v3"
    18  	"github.com/juju/version/v2"
    19  	"github.com/kr/pretty"
    20  	"go.uber.org/mock/gomock"
    21  	gc "gopkg.in/check.v1"
    22  	"gopkg.in/juju/environschema.v1"
    23  	"gopkg.in/yaml.v2"
    24  
    25  	"github.com/juju/juju/core/arch"
    26  	corecharm "github.com/juju/juju/core/charm"
    27  	"github.com/juju/juju/core/constraints"
    28  	"github.com/juju/juju/core/crossmodel"
    29  	"github.com/juju/juju/core/instance"
    30  	"github.com/juju/juju/core/model"
    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/secrets"
    35  	"github.com/juju/juju/core/status"
    36  	"github.com/juju/juju/environs"
    37  	"github.com/juju/juju/environs/config"
    38  	"github.com/juju/juju/state"
    39  	"github.com/juju/juju/state/cloudimagemetadata"
    40  	"github.com/juju/juju/state/mocks"
    41  	"github.com/juju/juju/storage"
    42  	"github.com/juju/juju/storage/poolmanager"
    43  	"github.com/juju/juju/storage/provider"
    44  	coretesting "github.com/juju/juju/testing"
    45  	"github.com/juju/juju/testing/factory"
    46  	jujuversion "github.com/juju/juju/version"
    47  )
    48  
    49  type MigrationImportSuite struct {
    50  	MigrationBaseSuite
    51  }
    52  
    53  var _ = gc.Suite(&MigrationImportSuite{})
    54  
    55  func (s *MigrationImportSuite) checkStatusHistory(c *gc.C, exported, imported status.StatusHistoryGetter, size int) {
    56  	exportedHistory, err := exported.StatusHistory(status.StatusHistoryFilter{Size: size})
    57  	c.Assert(err, jc.ErrorIsNil)
    58  	importedHistory, err := imported.StatusHistory(status.StatusHistoryFilter{Size: size})
    59  	c.Assert(err, jc.ErrorIsNil)
    60  	for i := 0; i < size; i++ {
    61  		c.Check(importedHistory[i].Status, gc.Equals, exportedHistory[i].Status)
    62  		c.Check(importedHistory[i].Message, gc.Equals, exportedHistory[i].Message)
    63  		c.Check(importedHistory[i].Data, jc.DeepEquals, exportedHistory[i].Data)
    64  		c.Check(importedHistory[i].Since, jc.DeepEquals, exportedHistory[i].Since)
    65  	}
    66  }
    67  
    68  func (s *MigrationImportSuite) TestExisting(c *gc.C) {
    69  	out, err := s.State.Export(map[string]string{})
    70  	c.Assert(err, jc.ErrorIsNil)
    71  
    72  	_, _, err = s.Controller.Import(out)
    73  	c.Assert(err, jc.Satisfies, errors.IsAlreadyExists)
    74  }
    75  
    76  func (s *MigrationImportSuite) importModel(
    77  	c *gc.C, st *state.State, transform ...func(map[string]interface{}),
    78  ) (*state.Model, *state.State) {
    79  	desc, err := st.Export(map[string]string{})
    80  	c.Assert(err, jc.ErrorIsNil)
    81  	return s.importModelDescription(c, desc, transform...)
    82  }
    83  
    84  func (s *MigrationImportSuite) importModelDescription(
    85  	c *gc.C, desc description.Model, transform ...func(map[string]interface{}),
    86  ) (*state.Model, *state.State) {
    87  
    88  	// When working with importing models, it becomes very handy to read the
    89  	// model in a human-readable format.
    90  	// yaml.Marshal will do this in a decent manor.
    91  	//	bytes, _ := yaml.Marshal(desc)
    92  	//	fmt.Println(string(bytes))
    93  
    94  	if len(transform) > 0 {
    95  		var outM map[string]interface{}
    96  		outYaml, err := description.Serialize(desc)
    97  		c.Assert(err, jc.ErrorIsNil)
    98  		err = yaml.Unmarshal(outYaml, &outM)
    99  		c.Assert(err, jc.ErrorIsNil)
   100  
   101  		for _, transform := range transform {
   102  			transform(outM)
   103  		}
   104  
   105  		outYaml, err = yaml.Marshal(outM)
   106  		c.Assert(err, jc.ErrorIsNil)
   107  		desc, err = description.Deserialize(outYaml)
   108  		c.Assert(err, jc.ErrorIsNil)
   109  	}
   110  
   111  	uuid := utils.MustNewUUID().String()
   112  	in := newModel(desc, uuid, "new")
   113  
   114  	newModel, newSt, err := s.Controller.Import(in)
   115  	c.Assert(err, jc.ErrorIsNil)
   116  
   117  	s.AddCleanup(func(c *gc.C) {
   118  		c.Check(newSt.Close(), jc.ErrorIsNil)
   119  	})
   120  	return newModel, newSt
   121  }
   122  
   123  func (s *MigrationImportSuite) assertAnnotations(c *gc.C, model *state.Model, entity state.GlobalEntity) {
   124  	annotations, err := model.Annotations(entity)
   125  	c.Assert(err, jc.ErrorIsNil)
   126  	c.Assert(annotations, jc.DeepEquals, testAnnotations)
   127  }
   128  
   129  func (s *MigrationImportSuite) TestNewModel(c *gc.C) {
   130  	cons := constraints.MustParse("arch=amd64 mem=8G")
   131  	latestTools := version.MustParse("2.0.1")
   132  	s.setLatestTools(c, latestTools)
   133  	c.Assert(s.State.SetModelConstraints(cons), jc.ErrorIsNil)
   134  	machineSeq := s.setRandSequenceValue(c, "machine")
   135  	fooSeq := s.setRandSequenceValue(c, "application-foo")
   136  	s.State.SwitchBlockOn(state.ChangeBlock, "locked down")
   137  
   138  	original, err := s.State.Model()
   139  	c.Assert(err, jc.ErrorIsNil)
   140  
   141  	environVersion := 123
   142  	err = original.SetEnvironVersion(environVersion)
   143  	c.Assert(err, jc.ErrorIsNil)
   144  
   145  	err = original.SetPassword("supersecret1111111111111")
   146  	c.Assert(err, jc.ErrorIsNil)
   147  
   148  	err = s.Model.SetAnnotations(original, testAnnotations)
   149  	c.Assert(err, jc.ErrorIsNil)
   150  
   151  	out, err := s.State.Export(map[string]string{})
   152  	c.Assert(err, jc.ErrorIsNil)
   153  
   154  	uuid := utils.MustNewUUID().String()
   155  	in := newModel(out, uuid, "new")
   156  
   157  	newModel, newSt, err := s.Controller.Import(in)
   158  	c.Assert(err, jc.ErrorIsNil)
   159  	defer newSt.Close()
   160  
   161  	c.Assert(newModel.PasswordHash(), gc.Equals, utils.AgentPasswordHash("supersecret1111111111111"))
   162  	c.Assert(newModel.Type(), gc.Equals, original.Type())
   163  	c.Assert(newModel.Owner(), gc.Equals, original.Owner())
   164  	c.Assert(newModel.LatestToolsVersion(), gc.Equals, latestTools)
   165  	c.Assert(newModel.MigrationMode(), gc.Equals, state.MigrationModeImporting)
   166  	c.Assert(newModel.EnvironVersion(), gc.Equals, environVersion)
   167  	s.assertAnnotations(c, newModel, newModel)
   168  
   169  	statusInfo, err := newModel.Status()
   170  	c.Check(err, jc.ErrorIsNil)
   171  	c.Check(statusInfo.Status, gc.Equals, status.Busy)
   172  	c.Check(statusInfo.Message, gc.Equals, "importing")
   173  	// One for original "available", one for "busy (importing)"
   174  	history, err := newModel.StatusHistory(status.StatusHistoryFilter{Size: 5})
   175  	c.Assert(err, jc.ErrorIsNil)
   176  	c.Check(history, gc.HasLen, 2)
   177  	c.Check(history[0].Status, gc.Equals, status.Busy)
   178  	c.Check(history[1].Status, gc.Equals, status.Available)
   179  
   180  	originalConfig, err := original.Config()
   181  	c.Assert(err, jc.ErrorIsNil)
   182  	originalAttrs := originalConfig.AllAttrs()
   183  
   184  	newConfig, err := newModel.Config()
   185  	c.Assert(err, jc.ErrorIsNil)
   186  	newAttrs := newConfig.AllAttrs()
   187  
   188  	c.Assert(newAttrs["uuid"], gc.Equals, uuid)
   189  	c.Assert(newAttrs["name"], gc.Equals, "new")
   190  
   191  	// Now drop the uuid and name and the rest of the attributes should match.
   192  	delete(newAttrs, "uuid")
   193  	delete(newAttrs, "name")
   194  	delete(originalAttrs, "uuid")
   195  	delete(originalAttrs, "name")
   196  	c.Assert(newAttrs, jc.DeepEquals, originalAttrs)
   197  
   198  	newCons, err := newSt.ModelConstraints()
   199  	c.Assert(err, jc.ErrorIsNil)
   200  	// Can't test the constraints directly, so go through the string repr.
   201  	c.Assert(newCons.String(), gc.Equals, cons.String())
   202  
   203  	seq, err := state.Sequence(newSt, "machine")
   204  	c.Assert(err, jc.ErrorIsNil)
   205  	c.Assert(seq, gc.Equals, machineSeq)
   206  	seq, err = state.Sequence(newSt, "application-foo")
   207  	c.Assert(err, jc.ErrorIsNil)
   208  	c.Assert(seq, gc.Equals, fooSeq)
   209  
   210  	blocks, err := newSt.AllBlocks()
   211  	c.Assert(err, jc.ErrorIsNil)
   212  	c.Assert(blocks, gc.HasLen, 1)
   213  	c.Assert(blocks[0].Type(), gc.Equals, state.ChangeBlock)
   214  	c.Assert(blocks[0].Message(), gc.Equals, "locked down")
   215  }
   216  
   217  func (s *MigrationImportSuite) newModelUser(c *gc.C, name string, readOnly bool, lastConnection time.Time) permission.UserAccess {
   218  	access := permission.AdminAccess
   219  	if readOnly {
   220  		access = permission.ReadAccess
   221  	}
   222  	user, err := s.Model.AddUser(state.UserAccessSpec{
   223  		User:      names.NewUserTag(name),
   224  		CreatedBy: s.Owner,
   225  		Access:    access,
   226  	})
   227  	c.Assert(err, jc.ErrorIsNil)
   228  	if !lastConnection.IsZero() {
   229  		err = state.UpdateModelUserLastConnection(s.State, user, lastConnection)
   230  		c.Assert(err, jc.ErrorIsNil)
   231  	}
   232  	return user
   233  }
   234  
   235  func (s *MigrationImportSuite) AssertUserEqual(c *gc.C, newUser, oldUser permission.UserAccess) {
   236  	c.Assert(newUser.UserName, gc.Equals, oldUser.UserName)
   237  	c.Assert(newUser.DisplayName, gc.Equals, oldUser.DisplayName)
   238  	c.Assert(newUser.CreatedBy, gc.Equals, oldUser.CreatedBy)
   239  	c.Assert(newUser.DateCreated, gc.Equals, oldUser.DateCreated)
   240  	c.Assert(newUser.Access, gc.Equals, newUser.Access)
   241  
   242  	connTime, err := s.Model.LastModelConnection(oldUser.UserTag)
   243  	if state.IsNeverConnectedError(err) {
   244  		_, err := s.Model.LastModelConnection(newUser.UserTag)
   245  		// The new user should also return an error for last connection.
   246  		c.Assert(err, jc.Satisfies, state.IsNeverConnectedError)
   247  	} else {
   248  		c.Assert(err, jc.ErrorIsNil)
   249  		newTime, err := s.Model.LastModelConnection(newUser.UserTag)
   250  		c.Assert(err, jc.ErrorIsNil)
   251  		c.Assert(newTime, gc.Equals, connTime)
   252  	}
   253  }
   254  
   255  func (s *MigrationImportSuite) TestModelUsers(c *gc.C) {
   256  	// To be sure with this test, we create three env users, and remove
   257  	// the owner.
   258  	err := s.State.RemoveUserAccess(s.Owner, s.modelTag)
   259  	c.Assert(err, jc.ErrorIsNil)
   260  
   261  	lastConnection := state.NowToTheSecond(s.State)
   262  
   263  	bravo := s.newModelUser(c, "bravo@external", false, lastConnection)
   264  	charlie := s.newModelUser(c, "charlie@external", true, lastConnection)
   265  	delta := s.newModelUser(c, "delta@external", true, coretesting.ZeroTime())
   266  
   267  	newModel, newSt := s.importModel(c, s.State)
   268  
   269  	// Check the import values of the users.
   270  	for _, user := range []permission.UserAccess{bravo, charlie, delta} {
   271  		newUser, err := newSt.UserAccess(user.UserTag, newModel.Tag())
   272  		c.Assert(err, jc.ErrorIsNil)
   273  		s.AssertUserEqual(c, newUser, user)
   274  	}
   275  
   276  	// Also make sure that there aren't any more.
   277  	allUsers, err := newModel.Users()
   278  	c.Assert(err, jc.ErrorIsNil)
   279  	c.Assert(allUsers, gc.HasLen, 3)
   280  }
   281  
   282  func (s *MigrationImportSuite) TestSLA(c *gc.C) {
   283  	err := s.State.SetSLA("essential", "bob", []byte("creds"))
   284  	c.Assert(err, jc.ErrorIsNil)
   285  	newModel, newSt := s.importModel(c, s.State)
   286  
   287  	c.Assert(newModel.SLALevel(), gc.Equals, "essential")
   288  	c.Assert(newModel.SLACredential(), jc.DeepEquals, []byte("creds"))
   289  	level, err := newSt.SLALevel()
   290  	c.Assert(err, jc.ErrorIsNil)
   291  	c.Assert(level, gc.Equals, "essential")
   292  	creds, err := newSt.SLACredential()
   293  	c.Assert(err, jc.ErrorIsNil)
   294  	c.Assert(creds, jc.DeepEquals, []byte("creds"))
   295  }
   296  
   297  func (s *MigrationImportSuite) TestMeterStatus(c *gc.C) {
   298  	err := s.State.SetModelMeterStatus("RED", "info message")
   299  	c.Assert(err, jc.ErrorIsNil)
   300  	newModel, newSt := s.importModel(c, s.State)
   301  
   302  	ms := newModel.MeterStatus()
   303  	c.Assert(ms.Code.String(), gc.Equals, "RED")
   304  	c.Assert(ms.Info, gc.Equals, "info message")
   305  	ms, err = newSt.ModelMeterStatus()
   306  	c.Assert(err, jc.ErrorIsNil)
   307  	c.Assert(ms.Code.String(), gc.Equals, "RED")
   308  	c.Assert(ms.Info, gc.Equals, "info message")
   309  }
   310  
   311  func (s *MigrationImportSuite) TestMeterStatusNotAvailable(c *gc.C) {
   312  	newModel, newSt := s.importModel(c, s.State, func(desc map[string]interface{}) {
   313  		c.Log(desc["meter-status"])
   314  		desc["meter-status"].(map[interface{}]interface{})["code"] = ""
   315  	})
   316  
   317  	ms := newModel.MeterStatus()
   318  	c.Assert(ms.Code.String(), gc.Equals, "NOT AVAILABLE")
   319  	c.Assert(ms.Info, gc.Equals, "")
   320  	ms, err := newSt.ModelMeterStatus()
   321  	c.Assert(err, jc.ErrorIsNil)
   322  	c.Assert(ms.Code.String(), gc.Equals, "NOT AVAILABLE")
   323  	c.Assert(ms.Info, gc.Equals, "")
   324  }
   325  
   326  func (s *MigrationImportSuite) AssertMachineEqual(c *gc.C, newMachine, oldMachine *state.Machine) {
   327  	c.Assert(newMachine.Id(), gc.Equals, oldMachine.Id())
   328  	c.Assert(newMachine.Principals(), jc.DeepEquals, oldMachine.Principals())
   329  	c.Assert(newMachine.Base().String(), gc.Equals, oldMachine.Base().String())
   330  	c.Assert(newMachine.ContainerType(), gc.Equals, oldMachine.ContainerType())
   331  	newHardware, err := newMachine.HardwareCharacteristics()
   332  	c.Assert(err, jc.ErrorIsNil)
   333  	oldHardware, err := oldMachine.HardwareCharacteristics()
   334  	c.Assert(err, jc.ErrorIsNil)
   335  	c.Assert(newHardware, jc.DeepEquals, oldHardware)
   336  	c.Assert(newMachine.Jobs(), jc.DeepEquals, oldMachine.Jobs())
   337  	c.Assert(newMachine.Life(), gc.Equals, oldMachine.Life())
   338  	newTools, err := newMachine.AgentTools()
   339  	c.Assert(err, jc.ErrorIsNil)
   340  	oldTools, err := oldMachine.AgentTools()
   341  	c.Assert(err, jc.ErrorIsNil)
   342  	c.Assert(newTools, jc.DeepEquals, oldTools)
   343  
   344  	oldStatus, err := oldMachine.Status()
   345  	c.Assert(err, jc.ErrorIsNil)
   346  	newStatus, err := newMachine.Status()
   347  	c.Assert(err, jc.ErrorIsNil)
   348  	c.Assert(newStatus, jc.DeepEquals, oldStatus)
   349  
   350  	oldInstID, oldInstDisplayName, err := oldMachine.InstanceNames()
   351  	c.Assert(err, jc.ErrorIsNil)
   352  	newInstID, newInstDisplayName, err := newMachine.InstanceNames()
   353  	c.Assert(err, jc.ErrorIsNil)
   354  	c.Assert(newInstID, gc.Equals, oldInstID)
   355  	c.Assert(newInstDisplayName, gc.Equals, oldInstDisplayName)
   356  
   357  	oldStatus, err = oldMachine.InstanceStatus()
   358  	c.Assert(err, jc.ErrorIsNil)
   359  	newStatus, err = newMachine.InstanceStatus()
   360  	c.Assert(err, jc.ErrorIsNil)
   361  	c.Assert(newStatus, jc.DeepEquals, oldStatus)
   362  }
   363  
   364  func (s *MigrationImportSuite) TestMachines(c *gc.C) {
   365  	// Add a machine with an LXC container.
   366  	cons := constraints.MustParse("arch=amd64 mem=8G root-disk-source=bunyan")
   367  	source := "bunyan"
   368  	displayName := "test-display-name"
   369  
   370  	addr := network.NewSpaceAddress("1.1.1.1")
   371  	addr.SpaceID = "9"
   372  
   373  	machine1 := s.Factory.MakeMachine(c, &factory.MachineParams{
   374  		Constraints: cons,
   375  		Characteristics: &instance.HardwareCharacteristics{
   376  			RootDiskSource: &source,
   377  		},
   378  		DisplayName: displayName,
   379  		Addresses:   network.SpaceAddresses{addr},
   380  	})
   381  	err := s.Model.SetAnnotations(machine1, testAnnotations)
   382  	c.Assert(err, jc.ErrorIsNil)
   383  	s.primeStatusHistory(c, machine1, status.Started, 5)
   384  
   385  	// machine1 should have some instance data.
   386  	hardware, err := machine1.HardwareCharacteristics()
   387  	c.Assert(err, jc.ErrorIsNil)
   388  	c.Assert(hardware, gc.NotNil)
   389  
   390  	_ = s.Factory.MakeMachineNested(c, machine1.Id(), nil)
   391  
   392  	allMachines, err := s.State.AllMachines()
   393  	c.Assert(err, jc.ErrorIsNil)
   394  	c.Assert(allMachines, gc.HasLen, 2)
   395  
   396  	newModel, newSt := s.importModel(c, s.State)
   397  
   398  	importedMachines, err := newSt.AllMachines()
   399  	c.Assert(err, jc.ErrorIsNil)
   400  	c.Assert(importedMachines, gc.HasLen, 2)
   401  
   402  	// AllMachines returns the machines in the same order, yay us.
   403  	for i, newMachine := range importedMachines {
   404  		s.AssertMachineEqual(c, newMachine, allMachines[i])
   405  	}
   406  
   407  	// And a few extra checks.
   408  	parent := importedMachines[0]
   409  	container := importedMachines[1]
   410  	containers, err := parent.Containers()
   411  	c.Assert(err, jc.ErrorIsNil)
   412  	c.Assert(containers, jc.DeepEquals, []string{container.Id()})
   413  	parentId, isContainer := container.ParentId()
   414  	c.Assert(parentId, gc.Equals, parent.Id())
   415  	c.Assert(isContainer, jc.IsTrue)
   416  
   417  	s.assertAnnotations(c, newModel, parent)
   418  	s.checkStatusHistory(c, machine1, parent, 5)
   419  
   420  	newCons, err := parent.Constraints()
   421  	c.Assert(err, jc.ErrorIsNil)
   422  	// Can't test the constraints directly, so go through the string repr.
   423  	c.Assert(newCons.String(), gc.Equals, cons.String())
   424  
   425  	// Test the modification status is set to the initial state.
   426  	modStatus, err := parent.ModificationStatus()
   427  	c.Assert(err, jc.ErrorIsNil)
   428  	c.Assert(modStatus.Status, gc.Equals, status.Idle)
   429  
   430  	characteristics, err := parent.HardwareCharacteristics()
   431  	c.Assert(err, jc.ErrorIsNil)
   432  	c.Assert(*characteristics.RootDiskSource, gc.Equals, "bunyan")
   433  }
   434  
   435  func (s *MigrationImportSuite) TestMachineDevices(c *gc.C) {
   436  	machine := s.Factory.MakeMachine(c, nil)
   437  	// Create two devices, first with all fields set, second just to show that
   438  	// we do both.
   439  	sda := state.BlockDeviceInfo{
   440  		DeviceName:     "sda",
   441  		DeviceLinks:    []string{"some", "data"},
   442  		Label:          "sda-label",
   443  		UUID:           "some-uuid",
   444  		HardwareId:     "magic",
   445  		WWN:            "drbr",
   446  		BusAddress:     "bus stop",
   447  		Size:           16 * 1024 * 1024 * 1024,
   448  		FilesystemType: "ext4",
   449  		InUse:          true,
   450  		MountPoint:     "/",
   451  	}
   452  	sdb := state.BlockDeviceInfo{DeviceName: "sdb", MountPoint: "/var/lib/lxd"}
   453  	err := machine.SetMachineBlockDevices(sda, sdb)
   454  	c.Assert(err, jc.ErrorIsNil)
   455  
   456  	_, newSt := s.importModel(c, s.State)
   457  
   458  	imported, err := newSt.Machine(machine.Id())
   459  	c.Assert(err, jc.ErrorIsNil)
   460  
   461  	sb, err := state.NewStorageBackend(s.State)
   462  	c.Assert(err, jc.ErrorIsNil)
   463  	devices, err := sb.BlockDevices(imported.MachineTag())
   464  	c.Assert(err, jc.ErrorIsNil)
   465  
   466  	c.Check(devices, jc.DeepEquals, []state.BlockDeviceInfo{sda, sdb})
   467  }
   468  
   469  func (s *MigrationImportSuite) TestMachinePortOps(c *gc.C) {
   470  	ctrl, mockMachine := setupMockOpenedPortRanges(c, "3")
   471  	defer ctrl.Finish()
   472  
   473  	ops, err := state.MachinePortOps(s.State, mockMachine)
   474  	c.Assert(err, jc.ErrorIsNil)
   475  	c.Assert(ops, gc.HasLen, 1)
   476  	c.Assert(ops[0].Id, gc.Equals, "3")
   477  }
   478  
   479  func (s *MigrationImportSuite) ApplicationPortOps(c *gc.C) {
   480  	ctrl := gomock.NewController(c)
   481  	mockApplication := mocks.NewMockApplication(ctrl)
   482  	mockApplicationPortRanges := mocks.NewMockPortRanges(ctrl)
   483  
   484  	aExp := mockApplication.EXPECT()
   485  	aExp.Name().Return("gitlab")
   486  	aExp.OpenedPortRanges().Return(mockApplicationPortRanges)
   487  
   488  	opExp := mockApplicationPortRanges.EXPECT()
   489  	opExp.ByUnit().Return(nil)
   490  
   491  	ops, err := state.ApplicationPortOps(s.State, mockApplication)
   492  	c.Assert(err, jc.ErrorIsNil)
   493  	c.Assert(ops, gc.HasLen, 1)
   494  	c.Assert(ops[0].Id, gc.Equals, "gitlab")
   495  }
   496  
   497  //go:generate go run go.uber.org/mock/mockgen -package mocks -destination mocks/description_mock.go github.com/juju/description/v5 Application,Machine,PortRanges,UnitPortRanges
   498  func setupMockOpenedPortRanges(c *gc.C, mID string) (*gomock.Controller, *mocks.MockMachine) {
   499  	ctrl := gomock.NewController(c)
   500  	mockMachine := mocks.NewMockMachine(ctrl)
   501  	mockMachinePortRanges := mocks.NewMockPortRanges(ctrl)
   502  
   503  	mExp := mockMachine.EXPECT()
   504  	mExp.Id().Return(mID)
   505  	mExp.OpenedPortRanges().Return(mockMachinePortRanges)
   506  
   507  	opExp := mockMachinePortRanges.EXPECT()
   508  	opExp.ByUnit().Return(nil)
   509  
   510  	return ctrl, mockMachine
   511  }
   512  
   513  func (s *MigrationImportSuite) setupSourceApplications(
   514  	c *gc.C, st *state.State, cons constraints.Value,
   515  	platform *state.Platform, primeStatusHistory bool,
   516  ) (*state.Charm, *state.Application, string) {
   517  	// Add a application with charm settings, app config, and leadership settings.
   518  	f := factory.NewFactory(st, s.StatePool)
   519  
   520  	serverSpace, err := s.State.AddSpace("server", "", nil, true)
   521  	c.Assert(err, jc.ErrorIsNil)
   522  	exposedSpaceIDs := []string{serverSpace.Id()}
   523  
   524  	testModel, err := st.Model()
   525  	c.Assert(err, jc.ErrorIsNil)
   526  	series := "quantal"
   527  	if testModel.Type() == state.ModelTypeCAAS {
   528  		series = "kubernetes"
   529  		exposedSpaceIDs = nil
   530  	}
   531  	// Add a application with charm settings, app config, and leadership settings.
   532  	testCharm := f.MakeCharm(c, &factory.CharmParams{
   533  		Name:   "starsay", // it has resources
   534  		Series: series,
   535  	})
   536  	c.Assert(testCharm.Meta().Resources, gc.HasLen, 3)
   537  	application, pwd := f.MakeApplicationReturningPassword(c, &factory.ApplicationParams{
   538  		Charm: testCharm,
   539  		CharmOrigin: &state.CharmOrigin{
   540  			Source:   "charm-hub",
   541  			Type:     "charm",
   542  			Revision: &charm.MustParseURL(testCharm.URL()).Revision,
   543  			Channel: &state.Channel{
   544  				Risk: "edge",
   545  			},
   546  			Hash:     "some-hash",
   547  			ID:       "some-id",
   548  			Platform: platform,
   549  		},
   550  		CharmConfig: map[string]interface{}{
   551  			"foo": "bar",
   552  		},
   553  		ApplicationConfig: map[string]interface{}{
   554  			"app foo": "app bar",
   555  		},
   556  		ApplicationConfigFields: environschema.Fields{
   557  			"app foo": environschema.Attr{Type: environschema.Tstring}},
   558  		Constraints:  cons,
   559  		DesiredScale: 3,
   560  	})
   561  	err = application.UpdateLeaderSettings(&goodToken{}, map[string]string{
   562  		"leader": "true",
   563  	})
   564  	c.Assert(err, jc.ErrorIsNil)
   565  	err = application.SetMetricCredentials([]byte("sekrit"))
   566  	c.Assert(err, jc.ErrorIsNil)
   567  	// Expose the application.
   568  	err = application.MergeExposeSettings(map[string]state.ExposedEndpoint{
   569  		"admin": {
   570  			ExposeToSpaceIDs: exposedSpaceIDs,
   571  			ExposeToCIDRs:    []string{"13.37.0.0/16"},
   572  		},
   573  	})
   574  	c.Assert(err, jc.ErrorIsNil)
   575  	err = testModel.SetAnnotations(application, testAnnotations)
   576  	c.Assert(err, jc.ErrorIsNil)
   577  	if testModel.Type() == state.ModelTypeCAAS {
   578  		application.SetOperatorStatus(status.StatusInfo{Status: status.Running})
   579  	}
   580  	if primeStatusHistory {
   581  		s.primeStatusHistory(c, application, status.Active, 5)
   582  	}
   583  	return testCharm, application, pwd
   584  }
   585  
   586  func (s *MigrationImportSuite) assertImportedApplication(
   587  	c *gc.C, application *state.Application, pwd string, cons constraints.Value,
   588  	exported *state.Application, newModel *state.Model, newSt *state.State, checkStatusHistory bool,
   589  ) {
   590  	importedApplications, err := newSt.AllApplications()
   591  	c.Assert(err, jc.ErrorIsNil)
   592  	c.Assert(importedApplications, gc.HasLen, 1)
   593  	imported := importedApplications[0]
   594  
   595  	c.Assert(imported.ApplicationTag(), gc.Equals, exported.ApplicationTag())
   596  	c.Assert(imported.IsExposed(), gc.Equals, exported.IsExposed())
   597  	c.Assert(imported.ExposedEndpoints(), gc.DeepEquals, exported.ExposedEndpoints())
   598  	c.Assert(imported.MetricCredentials(), jc.DeepEquals, exported.MetricCredentials())
   599  	c.Assert(imported.PasswordValid(pwd), jc.IsTrue)
   600  	exportedOrigin := exported.CharmOrigin()
   601  	if corecharm.CharmHub.Matches(exportedOrigin.Source) && exportedOrigin.Channel.Track == "" {
   602  		exportedOrigin.Channel.Track = "latest"
   603  	}
   604  	c.Assert(imported.CharmOrigin(), jc.DeepEquals, exportedOrigin)
   605  
   606  	exportedCharmConfig, err := exported.CharmConfig(model.GenerationMaster)
   607  	c.Assert(err, jc.ErrorIsNil)
   608  	importedCharmConfig, err := imported.CharmConfig(model.GenerationMaster)
   609  	c.Assert(err, jc.ErrorIsNil)
   610  	c.Assert(importedCharmConfig, jc.DeepEquals, exportedCharmConfig)
   611  
   612  	exportedAppConfig, err := exported.ApplicationConfig()
   613  	c.Assert(err, jc.ErrorIsNil)
   614  	importedAppConfig, err := imported.ApplicationConfig()
   615  	c.Assert(err, jc.ErrorIsNil)
   616  	c.Assert(importedAppConfig, jc.DeepEquals, exportedAppConfig)
   617  
   618  	exportedLeaderSettings, err := exported.LeaderSettings()
   619  	c.Assert(err, jc.ErrorIsNil)
   620  	importedLeaderSettings, err := imported.LeaderSettings()
   621  	c.Assert(err, jc.ErrorIsNil)
   622  	c.Assert(importedLeaderSettings, jc.DeepEquals, exportedLeaderSettings)
   623  
   624  	s.assertAnnotations(c, newModel, imported)
   625  	if checkStatusHistory {
   626  		s.checkStatusHistory(c, application, imported, 5)
   627  	}
   628  
   629  	newCons, err := imported.Constraints()
   630  	c.Assert(err, jc.ErrorIsNil)
   631  	// Can't test the constraints directly, so go through the string repr.
   632  	c.Assert(newCons.String(), gc.Equals, cons.String())
   633  
   634  	rSt := newSt.Resources()
   635  	resources, err := rSt.ListResources(imported.Name())
   636  	c.Assert(err, jc.ErrorIsNil)
   637  	c.Assert(resources.Resources, gc.HasLen, 3)
   638  
   639  	if newModel.Type() == state.ModelTypeCAAS {
   640  		agentTools := version.Binary{
   641  			Number:  jujuversion.Current,
   642  			Arch:    arch.HostArch(),
   643  			Release: application.CharmOrigin().Platform.OS,
   644  		}
   645  
   646  		tools, err := imported.AgentTools()
   647  		c.Assert(err, jc.ErrorIsNil)
   648  		c.Assert(tools.Version, gc.Equals, agentTools)
   649  	}
   650  }
   651  
   652  func (s *MigrationImportSuite) TestApplications(c *gc.C) {
   653  	cons := constraints.MustParse("arch=amd64 mem=8G root-disk-source=tralfamadore")
   654  	platform := &state.Platform{Architecture: arch.DefaultArchitecture, OS: "ubuntu", Channel: "12.10/stable"}
   655  	testCharm, application, pwd := s.setupSourceApplications(c, s.State, cons, platform, true)
   656  
   657  	allApplications, err := s.State.AllApplications()
   658  	c.Assert(err, jc.ErrorIsNil)
   659  	c.Assert(allApplications, gc.HasLen, 1)
   660  	exported := allApplications[0]
   661  
   662  	newModel, newSt := s.importModel(c, s.State)
   663  	// Manually copy across the charm from the old model
   664  	// as it's normally done later.
   665  	f := factory.NewFactory(newSt, s.StatePool)
   666  	f.MakeCharm(c, &factory.CharmParams{
   667  		Name:     "starsay", // it has resources
   668  		URL:      testCharm.URL(),
   669  		Revision: strconv.Itoa(testCharm.Revision()),
   670  	})
   671  	s.assertImportedApplication(c, application, pwd, cons, exported, newModel, newSt, true)
   672  }
   673  
   674  func (s *MigrationImportSuite) TestApplicationsUpdateSeriesNotPlatform(c *gc.C) {
   675  	// The application series should be quantal, the origin platform series should
   676  	// be focal.  After migration, the platform series should be quantal as well.
   677  	cons := constraints.MustParse("arch=amd64 mem=8G root-disk-source=tralfamadore")
   678  	platform := &state.Platform{
   679  		Architecture: arch.DefaultArchitecture,
   680  		OS:           "ubuntu",
   681  		Channel:      "20.04/stable",
   682  	}
   683  	_, _, _ = s.setupSourceApplications(c, s.State, cons, platform, true)
   684  
   685  	allApplications, err := s.State.AllApplications()
   686  	c.Assert(err, jc.ErrorIsNil)
   687  	c.Assert(allApplications, gc.HasLen, 1)
   688  	exportedApp := allApplications[0]
   689  	origin := exportedApp.CharmOrigin()
   690  	c.Check(origin, gc.NotNil)
   691  	c.Check(origin.Platform, gc.NotNil)
   692  	c.Check(origin.Platform.Channel, gc.Equals, "20.04/stable")
   693  
   694  	_, newSt := s.importModel(c, s.State)
   695  
   696  	obtainedApp, err := newSt.Application("starsay")
   697  	c.Assert(err, jc.ErrorIsNil)
   698  	obtainedOrigin := obtainedApp.CharmOrigin()
   699  	c.Assert(obtainedOrigin, gc.NotNil)
   700  	c.Assert(obtainedOrigin.Platform, gc.NotNil)
   701  	c.Assert(obtainedOrigin.Platform.Architecture, gc.Equals, arch.DefaultArchitecture)
   702  	c.Assert(obtainedOrigin.Platform.OS, gc.Equals, "ubuntu")
   703  	c.Assert(obtainedOrigin.Platform.Channel, gc.Equals, "20.04/stable")
   704  }
   705  
   706  func (s *MigrationImportSuite) TestCharmhubApplicationCharmOriginNormalised(c *gc.C) {
   707  	platform := &state.Platform{Architecture: arch.DefaultArchitecture, OS: "ubuntu", Channel: "12.10/stable"}
   708  	f := factory.NewFactory(s.State, s.StatePool)
   709  
   710  	testCharm := f.MakeCharm(c, &factory.CharmParams{Revision: "8", URL: "ch:mysql-8"})
   711  	wrongRev := 4
   712  	_ = f.MakeApplication(c, &factory.ApplicationParams{
   713  		Charm: testCharm,
   714  		Name:  "mysql",
   715  		CharmOrigin: &state.CharmOrigin{
   716  			Source:   "charm-hub",
   717  			Type:     "charm",
   718  			Platform: platform,
   719  			Revision: &wrongRev,
   720  			Channel:  &state.Channel{Track: "20.04", Risk: "stable", Branch: "deadbeef"},
   721  			Hash:     "some-hash",
   722  			ID:       "some-id",
   723  		},
   724  	})
   725  
   726  	_, newSt := s.importModel(c, s.State)
   727  	newApp, err := newSt.Application("mysql")
   728  	c.Assert(err, jc.ErrorIsNil)
   729  	rev := 8
   730  	c.Assert(newApp.CharmOrigin(), gc.DeepEquals, &state.CharmOrigin{
   731  		Source:   "charm-hub",
   732  		Type:     "charm",
   733  		Platform: platform,
   734  		Revision: &rev,
   735  		Channel:  &state.Channel{Track: "20.04", Risk: "stable", Branch: "deadbeef"},
   736  		Hash:     "some-hash",
   737  		ID:       "some-id",
   738  	})
   739  }
   740  
   741  func (s *MigrationImportSuite) TestLocalApplicationCharmOriginNormalised(c *gc.C) {
   742  	platform := &state.Platform{Architecture: arch.DefaultArchitecture, OS: "ubuntu", Channel: "12.10/stable"}
   743  	f := factory.NewFactory(s.State, s.StatePool)
   744  
   745  	testCharm := f.MakeCharm(c, &factory.CharmParams{Revision: "8", URL: "local:mysql-8"})
   746  	wrongRev := 4
   747  	_ = f.MakeApplication(c, &factory.ApplicationParams{
   748  		Charm: testCharm,
   749  		Name:  "mysql",
   750  		CharmOrigin: &state.CharmOrigin{
   751  			Source:   "charm-hub",
   752  			Type:     "charm",
   753  			Platform: platform,
   754  			Revision: &wrongRev,
   755  			Channel:  &state.Channel{Track: "20.04", Risk: "stable", Branch: "deadbeef"},
   756  			Hash:     "some-hash",
   757  			ID:       "some-id",
   758  		},
   759  	})
   760  
   761  	_, newSt := s.importModel(c, s.State)
   762  	newApp, err := newSt.Application("mysql")
   763  	c.Assert(err, jc.ErrorIsNil)
   764  	rev := 8
   765  	c.Assert(newApp.CharmOrigin(), gc.DeepEquals, &state.CharmOrigin{
   766  		Source:   "local",
   767  		Type:     "charm",
   768  		Platform: platform,
   769  		Revision: &rev,
   770  	})
   771  }
   772  
   773  func (s *MigrationImportSuite) TestApplicationStatus(c *gc.C) {
   774  	cons := constraints.MustParse("arch=amd64 mem=8G")
   775  	platform := &state.Platform{Architecture: arch.DefaultArchitecture, OS: "ubuntu", Channel: "12.10/stable"}
   776  	testCharm, application, pwd := s.setupSourceApplications(c, s.State, cons, platform, false)
   777  
   778  	s.Factory.MakeUnit(c, &factory.UnitParams{
   779  		Application: application,
   780  		Status: &status.StatusInfo{
   781  			Status:  status.Active,
   782  			Message: "unit active",
   783  		},
   784  	})
   785  
   786  	allApplications, err := s.State.AllApplications()
   787  	c.Assert(err, jc.ErrorIsNil)
   788  	c.Assert(allApplications, gc.HasLen, 1)
   789  	exported := allApplications[0]
   790  
   791  	newModel, newSt := s.importModel(c, s.State)
   792  	// Manually copy across the charm from the old model
   793  	// as it's normally done later.
   794  	f := factory.NewFactory(newSt, s.StatePool)
   795  	f.MakeCharm(c, &factory.CharmParams{
   796  		Name:     "starsay", // it has resources
   797  		URL:      testCharm.URL(),
   798  		Revision: strconv.Itoa(testCharm.Revision()),
   799  	})
   800  	s.assertImportedApplication(c, application, pwd, cons, exported, newModel, newSt, false)
   801  	newApp, err := newSt.Application(application.Name())
   802  	c.Assert(err, jc.ErrorIsNil)
   803  	// Has unset application status.
   804  	appStatus, err := newApp.Status()
   805  	c.Assert(err, jc.ErrorIsNil)
   806  	c.Assert(appStatus.Status, gc.Equals, status.Unset)
   807  	c.Assert(appStatus.Message, gc.Equals, "")
   808  }
   809  
   810  func (s *MigrationImportSuite) TestCAASApplications(c *gc.C) {
   811  	caasSt := s.Factory.MakeCAASModel(c, nil)
   812  	s.AddCleanup(func(_ *gc.C) { caasSt.Close() })
   813  
   814  	cons := constraints.MustParse("arch=amd64 mem=8G")
   815  	platform := &state.Platform{Architecture: arch.DefaultArchitecture, OS: "ubuntu", Channel: "20.04/stable"}
   816  	charm, application, pwd := s.setupSourceApplications(c, caasSt, cons, platform, true)
   817  
   818  	model, err := caasSt.Model()
   819  	c.Assert(err, jc.ErrorIsNil)
   820  	caasModel, err := model.CAASModel()
   821  	c.Assert(err, jc.ErrorIsNil)
   822  	err = caasModel.SetPodSpec(nil, application.ApplicationTag(), strPtr("pod spec"))
   823  	c.Assert(err, jc.ErrorIsNil)
   824  	addr := network.NewSpaceAddress("192.168.1.1", network.WithScope(network.ScopeCloudLocal))
   825  	addr.SpaceID = "0"
   826  	err = application.UpdateCloudService("provider-id", []network.SpaceAddress{addr})
   827  	c.Assert(err, jc.ErrorIsNil)
   828  
   829  	allApplications, err := caasSt.AllApplications()
   830  	c.Assert(err, jc.ErrorIsNil)
   831  	c.Assert(allApplications, gc.HasLen, 1)
   832  	exported := allApplications[0]
   833  
   834  	newModel, newSt := s.importModel(c, caasSt)
   835  	// Manually copy across the charm from the old model
   836  	// as it's normally done later.
   837  	f := factory.NewFactory(newSt, s.StatePool)
   838  	f.MakeCharm(c, &factory.CharmParams{
   839  		Name:     "starsay", // it has resources
   840  		Series:   "kubernetes",
   841  		URL:      charm.URL(),
   842  		Revision: strconv.Itoa(charm.Revision()),
   843  	})
   844  	s.assertImportedApplication(c, application, pwd, cons, exported, newModel, newSt, true)
   845  	newCAASModel, err := newModel.CAASModel()
   846  	c.Assert(err, jc.ErrorIsNil)
   847  	podSpec, err := newCAASModel.PodSpec(application.ApplicationTag())
   848  	c.Assert(err, jc.ErrorIsNil)
   849  	c.Assert(podSpec, gc.Equals, "pod spec")
   850  	newApp, err := newSt.Application(application.Name())
   851  	c.Assert(err, jc.ErrorIsNil)
   852  	cloudService, err := newApp.ServiceInfo()
   853  	c.Assert(err, jc.ErrorIsNil)
   854  	c.Assert(cloudService.ProviderId(), gc.Equals, "provider-id")
   855  	c.Assert(cloudService.Addresses(), jc.DeepEquals, network.SpaceAddresses{addr})
   856  	c.Assert(newApp.GetScale(), gc.Equals, 3)
   857  	c.Assert(newApp.GetPlacement(), gc.Equals, "")
   858  	c.Assert(state.GetApplicationHasResources(newApp), jc.IsTrue)
   859  }
   860  
   861  func (s *MigrationImportSuite) TestCAASApplicationStatus(c *gc.C) {
   862  	// Caas application status that is derived from unit statuses must survive migration.
   863  	caasSt := s.Factory.MakeCAASModel(c, nil)
   864  	s.AddCleanup(func(_ *gc.C) { caasSt.Close() })
   865  
   866  	cons := constraints.MustParse("arch=amd64 mem=8G")
   867  	platform := &state.Platform{Architecture: arch.DefaultArchitecture, OS: "ubuntu", Channel: "20.04"}
   868  	testCharm, application, _ := s.setupSourceApplications(c, caasSt, cons, platform, false)
   869  	ss, err := application.Status()
   870  	c.Assert(err, jc.ErrorIsNil)
   871  	c.Logf("status: %s", ss)
   872  
   873  	addUnitFactory := factory.NewFactory(caasSt, s.StatePool)
   874  	unit := addUnitFactory.MakeUnit(c, &factory.UnitParams{
   875  		Application: application,
   876  		Status: &status.StatusInfo{
   877  			Status:  status.Active,
   878  			Message: "unit active",
   879  		},
   880  	})
   881  	var updateUnits state.UpdateUnitsOperation
   882  	updateUnits.Updates = []*state.UpdateUnitOperation{
   883  		unit.UpdateOperation(state.UnitUpdateProperties{
   884  			ProviderId: strPtr("provider-id"),
   885  			Address:    strPtr("192.168.1.2"),
   886  			Ports:      &[]string{"80"},
   887  			CloudContainerStatus: &status.StatusInfo{
   888  				Status:  status.Active,
   889  				Message: "cloud container active",
   890  			},
   891  		})}
   892  	err = application.UpdateUnits(&updateUnits)
   893  	c.Assert(err, jc.ErrorIsNil)
   894  
   895  	testModel, err := caasSt.Model()
   896  	c.Assert(err, jc.ErrorIsNil)
   897  	caasModel, err := testModel.CAASModel()
   898  	c.Assert(err, jc.ErrorIsNil)
   899  	err = caasModel.SetPodSpec(nil, application.ApplicationTag(), strPtr("pod spec"))
   900  	c.Assert(err, jc.ErrorIsNil)
   901  	addr := network.NewSpaceAddress("192.168.1.1", network.WithScope(network.ScopeCloudLocal))
   902  	err = application.UpdateCloudService("provider-id", []network.SpaceAddress{addr})
   903  	c.Assert(err, jc.ErrorIsNil)
   904  
   905  	allApplications, err := caasSt.AllApplications()
   906  	c.Assert(err, jc.ErrorIsNil)
   907  	c.Assert(allApplications, gc.HasLen, 1)
   908  
   909  	_, newSt := s.importModel(c, caasSt)
   910  	// Manually copy across the charm from the old model
   911  	// as it's normally done later.
   912  	f := factory.NewFactory(newSt, s.StatePool)
   913  	f.MakeCharm(c, &factory.CharmParams{
   914  		Name:     "starsay", // it has resources
   915  		Series:   "kubernetes",
   916  		URL:      testCharm.URL(),
   917  		Revision: strconv.Itoa(testCharm.Revision()),
   918  	})
   919  	newApp, err := newSt.Application(application.Name())
   920  	c.Assert(err, jc.ErrorIsNil)
   921  	// Has unset application status.
   922  	appStatus, err := newApp.Status()
   923  	c.Assert(err, jc.ErrorIsNil)
   924  	c.Assert(appStatus.Status, gc.Equals, status.Unset)
   925  	c.Assert(appStatus.Message, gc.Equals, "")
   926  }
   927  
   928  func (s *MigrationImportSuite) TestApplicationsWithExposedOffers(c *gc.C) {
   929  	_ = s.Factory.MakeUser(c, &factory.UserParams{Name: "admin"})
   930  	fooUser := s.Factory.MakeUser(c, &factory.UserParams{Name: "foo"})
   931  	serverSpace, err := s.State.AddSpace("server", "", nil, true)
   932  	c.Assert(err, jc.ErrorIsNil)
   933  
   934  	wordpress := s.AddTestingApplication(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
   935  	wordpressEP, err := wordpress.Endpoint("db")
   936  	c.Assert(err, jc.ErrorIsNil)
   937  
   938  	testCharm := s.AddTestingCharm(c, "mysql")
   939  	application := s.AddTestingApplicationWithBindings(c, "mysql",
   940  		testCharm,
   941  		map[string]string{
   942  			"server": serverSpace.Id(),
   943  		},
   944  	)
   945  	applicationEP, err := application.Endpoint("server")
   946  	c.Assert(err, jc.ErrorIsNil)
   947  	_, err = s.State.AddRelation(wordpressEP, applicationEP)
   948  	c.Assert(err, jc.ErrorIsNil)
   949  
   950  	stOffers := state.NewApplicationOffers(s.State)
   951  	stOffer, err := stOffers.AddOffer(
   952  		crossmodel.AddApplicationOfferArgs{
   953  			OfferName:              "my-offer",
   954  			Owner:                  "admin",
   955  			ApplicationDescription: "my app",
   956  			ApplicationName:        application.Name(),
   957  			Endpoints: map[string]string{
   958  				"server": serverSpace.Name(),
   959  			},
   960  		},
   961  	)
   962  	c.Assert(err, jc.ErrorIsNil)
   963  
   964  	// Allow "foo" to consume offer
   965  	err = s.State.CreateOfferAccess(
   966  		names.NewApplicationOfferTag(stOffer.OfferUUID),
   967  		fooUser.UserTag(),
   968  		permission.ConsumeAccess,
   969  	)
   970  	c.Assert(err, jc.ErrorIsNil)
   971  
   972  	stateOffers := state.NewApplicationOffers(s.State)
   973  	exportedOffers, err := stateOffers.AllApplicationOffers()
   974  	c.Assert(err, jc.ErrorIsNil)
   975  	c.Assert(exportedOffers, gc.HasLen, 1)
   976  	exported := exportedOffers[0]
   977  
   978  	_, newSt := s.importModel(c, s.State, func(_ map[string]interface{}) {
   979  		// Application offer permissions are keyed on the offer uuid
   980  		// rather than a model uuid.
   981  		// If we import and the permissions still exist, the txn will fail
   982  		// as imports all assume any records do not already exist.
   983  		err = s.State.RemoveOfferAccess(
   984  			names.NewApplicationOfferTag(stOffer.OfferUUID),
   985  			fooUser.UserTag(),
   986  		)
   987  		c.Assert(err, jc.ErrorIsNil)
   988  		err = s.State.RemoveOfferAccess(
   989  			names.NewApplicationOfferTag(stOffer.OfferUUID),
   990  			names.NewUserTag("admin"),
   991  		)
   992  		c.Assert(err, jc.ErrorIsNil)
   993  	})
   994  
   995  	// The following is required because we don't add charms during an import,
   996  	// these are added at a later date. When constructing an application offer,
   997  	// the charm is required for the charm.Relation, so we need to inject it
   998  	// into the new state.
   999  	state.AddTestingCharm(c, newSt, "mysql")
  1000  
  1001  	newStateOffers := state.NewApplicationOffers(newSt)
  1002  	importedOffers, err := newStateOffers.AllApplicationOffers()
  1003  	c.Assert(err, jc.ErrorIsNil)
  1004  	c.Assert(importedOffers, gc.HasLen, 1)
  1005  	imported := importedOffers[0]
  1006  	c.Assert(exported, gc.DeepEquals, imported)
  1007  
  1008  	users, err := newSt.GetOfferUsers(stOffer.OfferUUID)
  1009  	c.Assert(err, jc.ErrorIsNil)
  1010  	c.Assert(users, gc.HasLen, 2)
  1011  	c.Assert(users, gc.DeepEquals, map[string]permission.Access{
  1012  		"admin": "admin",
  1013  		"foo":   "consume",
  1014  	})
  1015  }
  1016  
  1017  func (s *MigrationImportSuite) TestExternalControllers(c *gc.C) {
  1018  	remoteApp, err := s.State.AddRemoteApplication(state.AddRemoteApplicationParams{
  1019  		Name:        "gravy-rainbow",
  1020  		URL:         "me/model.rainbow",
  1021  		SourceModel: s.Model.ModelTag(),
  1022  		Token:       "charisma",
  1023  	})
  1024  	c.Assert(err, jc.ErrorIsNil)
  1025  	err = remoteApp.SetStatus(status.StatusInfo{Status: status.Active})
  1026  	c.Assert(err, jc.ErrorIsNil)
  1027  
  1028  	stateExternalCtrl := state.NewExternalControllers(s.State)
  1029  	crossModelController, err := stateExternalCtrl.Save(crossmodel.ControllerInfo{
  1030  		ControllerTag: s.Model.ControllerTag(),
  1031  		Addrs:         []string{"192.168.1.1:8080"},
  1032  		Alias:         "magic",
  1033  		CACert:        "magic-ca-cert",
  1034  	}, s.Model.UUID())
  1035  	c.Assert(err, jc.ErrorIsNil)
  1036  
  1037  	stateExternalController, err := s.State.ExternalControllerForModel(s.Model.UUID())
  1038  	c.Assert(err, jc.ErrorIsNil)
  1039  
  1040  	_, newSt := s.importModel(c, s.State, func(map[string]interface{}) {
  1041  		err := stateExternalCtrl.Remove(s.Model.ControllerTag().Id())
  1042  		c.Assert(err, jc.ErrorIsNil)
  1043  	})
  1044  
  1045  	newExternalCtrl := state.NewExternalControllers(newSt)
  1046  
  1047  	newCtrl, err := newExternalCtrl.ControllerForModel(s.Model.UUID())
  1048  	c.Assert(err, jc.ErrorIsNil)
  1049  	c.Assert(newCtrl.ControllerInfo(), jc.DeepEquals, crossModelController.ControllerInfo())
  1050  
  1051  	newExternalController, err := newSt.ExternalControllerForModel(s.Model.UUID())
  1052  	c.Assert(err, jc.ErrorIsNil)
  1053  	c.Assert(stateExternalController, gc.DeepEquals, newExternalController)
  1054  }
  1055  
  1056  func (s *MigrationImportSuite) TestCharmRevSequencesNotImported(c *gc.C) {
  1057  	s.Factory.MakeApplication(c, &factory.ApplicationParams{
  1058  		Charm: s.Factory.MakeCharm(c, &factory.CharmParams{
  1059  			Name: "mysql",
  1060  			URL:  "local:trusty/mysql-2",
  1061  		}),
  1062  	})
  1063  	// Sequence should be set in the source model.
  1064  	const charmSeqName = "charmrev-local:trusty/mysql"
  1065  	nextVal, err := state.Sequence(s.State, charmSeqName)
  1066  	c.Assert(err, jc.ErrorIsNil)
  1067  	c.Check(nextVal, gc.Equals, 3)
  1068  
  1069  	out, err := s.State.Export(map[string]string{})
  1070  	c.Assert(err, jc.ErrorIsNil)
  1071  
  1072  	c.Assert(len(out.Applications()), gc.Equals, 1)
  1073  
  1074  	uuid := utils.MustNewUUID().String()
  1075  	in := newModel(out, uuid, "new")
  1076  
  1077  	_, newSt, err := s.Controller.Import(in)
  1078  	c.Assert(err, jc.ErrorIsNil)
  1079  	defer newSt.Close()
  1080  
  1081  	// Charm revision sequence shouldn't have been imported. The
  1082  	// import of the charm binaries (done separately later) will
  1083  	// handle this.
  1084  	nextVal, err = state.Sequence(newSt, charmSeqName)
  1085  	c.Assert(err, jc.ErrorIsNil)
  1086  	c.Check(nextVal, gc.Equals, 0)
  1087  }
  1088  
  1089  func (s *MigrationImportSuite) TestApplicationsSubordinatesAfter(c *gc.C) {
  1090  	// Test for https://bugs.launchpad.net/juju/+bug/1650249
  1091  	subordinate := s.Factory.MakeApplication(c, &factory.ApplicationParams{
  1092  		Charm: s.Factory.MakeCharm(c, &factory.CharmParams{Name: "logging"}),
  1093  	})
  1094  
  1095  	principal := s.Factory.MakeApplication(c, &factory.ApplicationParams{
  1096  		Charm: s.Factory.MakeCharm(c, &factory.CharmParams{Name: "mysql"}),
  1097  	})
  1098  	unit := s.Factory.MakeUnit(c, &factory.UnitParams{Application: principal})
  1099  
  1100  	sEndpoint, err := subordinate.Endpoint("info")
  1101  	c.Assert(err, jc.ErrorIsNil)
  1102  	pEndpoint, err := principal.Endpoint("juju-info")
  1103  	c.Assert(err, jc.ErrorIsNil)
  1104  	relation := s.Factory.MakeRelation(c, &factory.RelationParams{
  1105  		Endpoints: []state.Endpoint{sEndpoint, pEndpoint},
  1106  	})
  1107  
  1108  	ru, err := relation.Unit(unit)
  1109  	c.Assert(err, jc.ErrorIsNil)
  1110  
  1111  	// Ensure the subordinate unit is created.
  1112  	err = ru.EnterScope(nil)
  1113  	c.Assert(err, jc.ErrorIsNil)
  1114  
  1115  	tools, err := unit.AgentTools()
  1116  	c.Assert(err, jc.ErrorIsNil)
  1117  
  1118  	sUnits, err := subordinate.AllUnits()
  1119  	c.Assert(err, jc.ErrorIsNil)
  1120  	for _, u := range sUnits {
  1121  		// For some reason the EnterScope call doesn't set up the
  1122  		// version or enter the scope for the subordinate unit on the
  1123  		// other side of the relation.
  1124  		err := u.SetAgentVersion(tools.Version)
  1125  		c.Assert(err, jc.ErrorIsNil)
  1126  		ru, err := relation.Unit(u)
  1127  		c.Assert(err, jc.ErrorIsNil)
  1128  		err = ru.EnterScope(nil)
  1129  		c.Assert(err, jc.ErrorIsNil)
  1130  	}
  1131  
  1132  	out, err := s.State.Export(map[string]string{})
  1133  	c.Assert(err, jc.ErrorIsNil)
  1134  
  1135  	apps := out.Applications()
  1136  	c.Assert(len(apps), gc.Equals, 2)
  1137  
  1138  	// This test is only valid if the subordinate logging application
  1139  	// comes first in the model output.
  1140  	if apps[0].Name() != "logging" {
  1141  		out = &swapModel{out, c}
  1142  	}
  1143  
  1144  	uuid := utils.MustNewUUID().String()
  1145  	in := newModel(out, uuid, "new")
  1146  
  1147  	_, newSt, err := s.Controller.Import(in)
  1148  	c.Assert(err, jc.ErrorIsNil)
  1149  	// add the cleanup here to close the model.
  1150  	s.AddCleanup(func(c *gc.C) {
  1151  		c.Check(newSt.Close(), jc.ErrorIsNil)
  1152  	})
  1153  }
  1154  
  1155  func (s *MigrationImportSuite) TestUnits(c *gc.C) {
  1156  	s.assertUnitsMigrated(c, s.State, constraints.MustParse("arch=amd64 mem=8G"))
  1157  }
  1158  
  1159  func (s *MigrationImportSuite) TestCAASUnits(c *gc.C) {
  1160  	caasSt := s.Factory.MakeCAASModel(c, nil)
  1161  	s.AddCleanup(func(_ *gc.C) { caasSt.Close() })
  1162  
  1163  	s.assertUnitsMigrated(c, caasSt, constraints.MustParse("arch=amd64 mem=8G"))
  1164  }
  1165  
  1166  func (s *MigrationImportSuite) TestUnitsWithVirtConstraint(c *gc.C) {
  1167  	s.assertUnitsMigrated(c, s.State, constraints.MustParse("arch=amd64 mem=8G virt-type=kvm"))
  1168  }
  1169  
  1170  func (s *MigrationImportSuite) TestUnitWithoutAnyPersistedState(c *gc.C) {
  1171  	f := factory.NewFactory(s.State, s.StatePool)
  1172  
  1173  	// Export unit without any controller-persisted state
  1174  	exported := f.MakeUnit(c, &factory.UnitParams{
  1175  		Constraints: constraints.MustParse("arch=amd64 mem=8G"),
  1176  	})
  1177  
  1178  	exportedState, err := exported.State()
  1179  	c.Assert(err, jc.ErrorIsNil)
  1180  	_, isSet := exportedState.CharmState()
  1181  	c.Assert(isSet, jc.IsFalse, gc.Commentf("expected charm state to be empty"))
  1182  	_, isSet = exportedState.RelationState()
  1183  	c.Assert(isSet, jc.IsFalse, gc.Commentf("expected uniter relation state to be empty"))
  1184  	_, isSet = exportedState.UniterState()
  1185  	c.Assert(isSet, jc.IsFalse, gc.Commentf("expected uniter state to be empty"))
  1186  	_, isSet = exportedState.StorageState()
  1187  	c.Assert(isSet, jc.IsFalse, gc.Commentf("expected uniter storage state to be empty"))
  1188  	_, isSet = exportedState.MeterStatusState()
  1189  	c.Assert(isSet, jc.IsFalse, gc.Commentf("expected meter status state to be empty"))
  1190  
  1191  	// Import model and ensure that its UnitState was not mutated.
  1192  	_, newSt := s.importModel(c, s.State)
  1193  
  1194  	importedApplications, err := newSt.AllApplications()
  1195  	c.Assert(err, jc.ErrorIsNil)
  1196  	c.Assert(importedApplications, gc.HasLen, 1)
  1197  
  1198  	importedUnits, err := importedApplications[0].AllUnits()
  1199  	c.Assert(err, jc.ErrorIsNil)
  1200  	c.Assert(importedUnits, gc.HasLen, 1)
  1201  	imported := importedUnits[0]
  1202  
  1203  	c.Assert(imported.UnitTag(), gc.Equals, exported.UnitTag())
  1204  
  1205  	unitState, err := imported.State()
  1206  	c.Assert(err, jc.ErrorIsNil)
  1207  	_, isSet = unitState.CharmState()
  1208  	c.Assert(isSet, jc.IsFalse, gc.Commentf("unexpected charm state after import; SetState should not have been called"))
  1209  	_, isSet = unitState.RelationState()
  1210  	c.Assert(isSet, jc.IsFalse, gc.Commentf("unexpected uniter relation state after import; SetState should not have been called"))
  1211  	_, isSet = unitState.UniterState()
  1212  	c.Assert(isSet, jc.IsFalse, gc.Commentf("unexpected uniter state after import; SetState should not have been called"))
  1213  	_, isSet = unitState.StorageState()
  1214  	c.Assert(isSet, jc.IsFalse, gc.Commentf("unexpected uniter storage state after import; SetState should not have been called"))
  1215  	_, isSet = unitState.MeterStatusState()
  1216  	c.Assert(isSet, jc.IsFalse, gc.Commentf("unexpected meter status state after import; SetState should not have been called"))
  1217  }
  1218  
  1219  func (s *MigrationImportSuite) assertUnitsMigrated(c *gc.C, st *state.State, cons constraints.Value) {
  1220  	f := factory.NewFactory(st, s.StatePool)
  1221  
  1222  	exported, pwd := f.MakeUnitReturningPassword(c, &factory.UnitParams{
  1223  		Constraints: cons,
  1224  	})
  1225  	err := exported.SetMeterStatus("GREEN", "some info")
  1226  	c.Assert(err, jc.ErrorIsNil)
  1227  	err = exported.SetWorkloadVersion("amethyst")
  1228  	c.Assert(err, jc.ErrorIsNil)
  1229  	testModel, err := st.Model()
  1230  	c.Assert(err, jc.ErrorIsNil)
  1231  	err = testModel.SetAnnotations(exported, testAnnotations)
  1232  	c.Assert(err, jc.ErrorIsNil)
  1233  	us := state.NewUnitState()
  1234  	us.SetCharmState(map[string]string{"payload": "0xb4c0ffee"})
  1235  	us.SetRelationState(map[int]string{42: "magic"})
  1236  	us.SetUniterState("uniter state")
  1237  	us.SetStorageState("storage state")
  1238  	us.SetMeterStatusState("meter status state")
  1239  	err = exported.SetState(us, state.UnitStateSizeLimits{})
  1240  	c.Assert(err, jc.ErrorIsNil)
  1241  
  1242  	if testModel.Type() == state.ModelTypeCAAS {
  1243  		var updateUnits state.UpdateUnitsOperation
  1244  		// need to set a cloud container status so that SetStatus for
  1245  		// the unit doesn't throw away the history writes.
  1246  		updateUnits.Updates = []*state.UpdateUnitOperation{
  1247  			exported.UpdateOperation(state.UnitUpdateProperties{
  1248  				ProviderId: strPtr("provider-id"),
  1249  				Address:    strPtr("192.168.1.2"),
  1250  				Ports:      &[]string{"80"},
  1251  				CloudContainerStatus: &status.StatusInfo{
  1252  					Status:  status.Active,
  1253  					Message: "cloud container active",
  1254  				},
  1255  			})}
  1256  		app, err := exported.Application()
  1257  		c.Assert(err, jc.ErrorIsNil)
  1258  		err = app.UpdateUnits(&updateUnits)
  1259  		c.Assert(err, jc.ErrorIsNil)
  1260  	}
  1261  	s.primeStatusHistory(c, exported, status.Active, 5)
  1262  	s.primeStatusHistory(c, exported.Agent(), status.Idle, 5)
  1263  
  1264  	newModel, newSt := s.importModel(c, st)
  1265  
  1266  	importedApplications, err := newSt.AllApplications()
  1267  	c.Assert(err, jc.ErrorIsNil)
  1268  	c.Assert(importedApplications, gc.HasLen, 1)
  1269  
  1270  	importedUnits, err := importedApplications[0].AllUnits()
  1271  	c.Assert(err, jc.ErrorIsNil)
  1272  	c.Assert(importedUnits, gc.HasLen, 1)
  1273  	imported := importedUnits[0]
  1274  
  1275  	c.Assert(imported.UnitTag(), gc.Equals, exported.UnitTag())
  1276  	c.Assert(imported.PasswordValid(pwd), jc.IsTrue)
  1277  	v, err := imported.WorkloadVersion()
  1278  	c.Assert(err, jc.ErrorIsNil)
  1279  	c.Assert(v, gc.Equals, "amethyst")
  1280  
  1281  	if newModel.Type() == state.ModelTypeIAAS {
  1282  		exportedMachineId, err := exported.AssignedMachineId()
  1283  		c.Assert(err, jc.ErrorIsNil)
  1284  		importedMachineId, err := imported.AssignedMachineId()
  1285  		c.Assert(err, jc.ErrorIsNil)
  1286  		c.Assert(importedMachineId, gc.Equals, exportedMachineId)
  1287  
  1288  		// Confirm machine Principals are set.
  1289  		exportedMachine, err := st.Machine(exportedMachineId)
  1290  		c.Assert(err, jc.ErrorIsNil)
  1291  		importedMachine, err := newSt.Machine(importedMachineId)
  1292  		c.Assert(err, jc.ErrorIsNil)
  1293  		s.AssertMachineEqual(c, importedMachine, exportedMachine)
  1294  	}
  1295  	if newModel.Type() == state.ModelTypeCAAS {
  1296  		containerInfo, err := imported.ContainerInfo()
  1297  		c.Assert(err, jc.ErrorIsNil)
  1298  		c.Assert(containerInfo.ProviderId(), gc.Equals, "provider-id")
  1299  		c.Assert(containerInfo.Ports(), jc.DeepEquals, []string{"80"})
  1300  		addr := network.NewSpaceAddress("192.168.1.2", network.WithScope(network.ScopeMachineLocal))
  1301  		addr.SpaceID = "0"
  1302  		c.Assert(containerInfo.Address(), jc.DeepEquals, &addr)
  1303  	}
  1304  
  1305  	meterStatus, err := imported.GetMeterStatus()
  1306  	c.Assert(err, jc.ErrorIsNil)
  1307  	c.Assert(meterStatus, gc.Equals, state.MeterStatus{state.MeterGreen, "some info"})
  1308  	s.assertAnnotations(c, newModel, imported)
  1309  	s.checkStatusHistory(c, exported, imported, 5)
  1310  	s.checkStatusHistory(c, exported.Agent(), imported.Agent(), 5)
  1311  	s.checkStatusHistory(c, exported.WorkloadVersionHistory(), imported.WorkloadVersionHistory(), 1)
  1312  
  1313  	unitState, err := imported.State()
  1314  	c.Assert(err, jc.ErrorIsNil)
  1315  	charmState, _ := unitState.CharmState()
  1316  	c.Assert(charmState, jc.DeepEquals, map[string]string{"payload": "0xb4c0ffee"}, gc.Commentf("persisted charm state not migrated"))
  1317  	relationState, _ := unitState.RelationState()
  1318  	c.Assert(relationState, jc.DeepEquals, map[int]string{42: "magic"}, gc.Commentf("persisted relation state not migrated"))
  1319  	uniterState, _ := unitState.UniterState()
  1320  	c.Assert(uniterState, gc.Equals, "uniter state", gc.Commentf("persisted uniter state not migrated"))
  1321  	storageState, _ := unitState.StorageState()
  1322  	c.Assert(storageState, gc.Equals, "storage state", gc.Commentf("persisted uniter storage state not migrated"))
  1323  	meterStatusState, _ := unitState.MeterStatusState()
  1324  	c.Assert(meterStatusState, gc.Equals, "meter status state", gc.Commentf("persisted meter status state not migrated"))
  1325  
  1326  	newCons, err := imported.Constraints()
  1327  	c.Assert(err, jc.ErrorIsNil)
  1328  	// Can't test the constraints directly, so go through the string repr.
  1329  	c.Assert(newCons.String(), gc.Equals, cons.String())
  1330  }
  1331  
  1332  func (s *MigrationImportSuite) TestRemoteEntities(c *gc.C) {
  1333  	srcRemoteEntities := s.State.RemoteEntities()
  1334  	err := srcRemoteEntities.ImportRemoteEntity(names.NewApplicationTag("uuid3"), "xxx-aaa-bbb")
  1335  	c.Assert(err, jc.ErrorIsNil)
  1336  	err = srcRemoteEntities.ImportRemoteEntity(names.NewApplicationTag("uuid4"), "ccc-ddd-zzz")
  1337  	c.Assert(err, jc.ErrorIsNil)
  1338  
  1339  	_, newSt := s.importModel(c, s.State)
  1340  
  1341  	newRemoteEntities := newSt.RemoteEntities()
  1342  	token, err := newRemoteEntities.GetToken(names.NewApplicationTag("uuid3"))
  1343  	c.Assert(err, jc.ErrorIsNil)
  1344  	c.Assert(token, gc.Equals, "xxx-aaa-bbb")
  1345  
  1346  	token, err = newRemoteEntities.GetToken(names.NewApplicationTag("uuid4"))
  1347  	c.Assert(err, jc.ErrorIsNil)
  1348  	c.Assert(token, gc.Equals, "ccc-ddd-zzz")
  1349  }
  1350  
  1351  func (s *MigrationImportSuite) TestRelationNetworks(c *gc.C) {
  1352  	wordpress := s.AddTestingApplication(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
  1353  	wordpressEP, err := wordpress.Endpoint("db")
  1354  	c.Assert(err, jc.ErrorIsNil)
  1355  	mysql := s.AddTestingApplication(c, "mysql", s.AddTestingCharm(c, "mysql"))
  1356  	mysqlEP, err := mysql.Endpoint("server")
  1357  	c.Assert(err, jc.ErrorIsNil)
  1358  	_, err = s.State.AddRelation(wordpressEP, mysqlEP)
  1359  	c.Assert(err, jc.ErrorIsNil)
  1360  
  1361  	srcRelationNetworks := state.NewRelationIngressNetworks(s.State)
  1362  	_, err = srcRelationNetworks.Save("wordpress:db mysql:server", false, []string{"192.168.1.0/16"})
  1363  	c.Assert(err, jc.ErrorIsNil)
  1364  
  1365  	_, newSt := s.importModel(c, s.State)
  1366  
  1367  	newRelationNetworks := state.NewRelationNetworks(newSt)
  1368  	networks, err := newRelationNetworks.AllRelationNetworks()
  1369  	c.Assert(err, jc.ErrorIsNil)
  1370  	c.Assert(networks, gc.HasLen, 1)
  1371  
  1372  	entity0 := networks[0]
  1373  	c.Assert(entity0.RelationKey(), gc.Equals, "wordpress:db mysql:server")
  1374  	c.Assert(entity0.CIDRS(), gc.DeepEquals, []string{"192.168.1.0/16"})
  1375  }
  1376  
  1377  func (s *MigrationImportSuite) TestRelations(c *gc.C) {
  1378  	wordpress := state.AddTestingApplication(c, s.State, "wordpress", state.AddTestingCharm(c, s.State, "wordpress"))
  1379  	state.AddTestingApplication(c, s.State, "mysql", state.AddTestingCharm(c, s.State, "mysql"))
  1380  	eps, err := s.State.InferEndpoints("mysql", "wordpress")
  1381  	c.Assert(err, jc.ErrorIsNil)
  1382  
  1383  	rel, err := s.State.AddRelation(eps...)
  1384  	c.Assert(err, jc.ErrorIsNil)
  1385  	err = rel.SetStatus(status.StatusInfo{Status: status.Joined})
  1386  	c.Assert(err, jc.ErrorIsNil)
  1387  
  1388  	wordpress0 := s.Factory.MakeUnit(c, &factory.UnitParams{Application: wordpress})
  1389  	ru, err := rel.Unit(wordpress0)
  1390  	c.Assert(err, jc.ErrorIsNil)
  1391  
  1392  	relSettings := map[string]interface{}{
  1393  		"name": "wordpress/0",
  1394  	}
  1395  	err = ru.EnterScope(relSettings)
  1396  	c.Assert(err, jc.ErrorIsNil)
  1397  
  1398  	_, newSt := s.importModel(c, s.State)
  1399  
  1400  	newWordpress, err := newSt.Application("wordpress")
  1401  	c.Assert(err, jc.ErrorIsNil)
  1402  	c.Assert(state.RelationCount(newWordpress), gc.Equals, 1)
  1403  	rels, err := newWordpress.Relations()
  1404  	c.Assert(err, jc.ErrorIsNil)
  1405  	c.Assert(rels, gc.HasLen, 1)
  1406  	units, err := newWordpress.AllUnits()
  1407  	c.Assert(err, jc.ErrorIsNil)
  1408  	c.Assert(units, gc.HasLen, 1)
  1409  
  1410  	relStatus, err := rels[0].Status()
  1411  	c.Assert(err, jc.ErrorIsNil)
  1412  	c.Assert(relStatus.Status, gc.Equals, status.Joined)
  1413  
  1414  	ru, err = rels[0].Unit(units[0])
  1415  	c.Assert(err, jc.ErrorIsNil)
  1416  
  1417  	settings, err := ru.Settings()
  1418  	c.Assert(err, jc.ErrorIsNil)
  1419  	c.Assert(settings.Map(), gc.DeepEquals, relSettings)
  1420  }
  1421  
  1422  func (s *MigrationImportSuite) TestCMRRemoteRelationScope(c *gc.C) {
  1423  	_, err := s.State.AddRemoteApplication(state.AddRemoteApplicationParams{
  1424  		Name:        "gravy-rainbow",
  1425  		URL:         "me/model.rainbow",
  1426  		SourceModel: s.Model.ModelTag(),
  1427  		Token:       "charisma",
  1428  		OfferUUID:   "offer-uuid",
  1429  		Endpoints: []charm.Relation{{
  1430  			Interface: "mysql",
  1431  			Name:      "db",
  1432  			Role:      charm.RoleProvider,
  1433  			Scope:     charm.ScopeGlobal,
  1434  		}},
  1435  	})
  1436  	c.Assert(err, jc.ErrorIsNil)
  1437  
  1438  	wordpress := state.AddTestingApplication(c, s.State, "wordpress", state.AddTestingCharm(c, s.State, "wordpress"))
  1439  	eps, err := s.State.InferEndpoints("gravy-rainbow", "wordpress")
  1440  	c.Assert(err, jc.ErrorIsNil)
  1441  	rel, err := s.State.AddRelation(eps...)
  1442  	c.Assert(err, jc.ErrorIsNil)
  1443  
  1444  	wordpress0 := s.Factory.MakeUnit(c, &factory.UnitParams{Application: wordpress})
  1445  	localRU, err := rel.Unit(wordpress0)
  1446  	c.Assert(err, jc.ErrorIsNil)
  1447  
  1448  	wordpressSettings := map[string]interface{}{"name": "wordpress/0"}
  1449  	err = localRU.EnterScope(wordpressSettings)
  1450  	c.Assert(err, jc.ErrorIsNil)
  1451  
  1452  	remoteRU, err := rel.RemoteUnit("gravy-rainbow/0")
  1453  	c.Assert(err, jc.ErrorIsNil)
  1454  
  1455  	gravySettings := map[string]interface{}{"name": "gravy-rainbow/0"}
  1456  	err = remoteRU.EnterScope(gravySettings)
  1457  	c.Assert(err, jc.ErrorIsNil)
  1458  
  1459  	_, newSt := s.importModel(c, s.State)
  1460  
  1461  	newWordpress, err := newSt.Application("wordpress")
  1462  	c.Assert(err, jc.ErrorIsNil)
  1463  
  1464  	rels, err := newWordpress.Relations()
  1465  	c.Assert(err, jc.ErrorIsNil)
  1466  	c.Assert(rels, gc.HasLen, 1)
  1467  
  1468  	ru, err := rels[0].RemoteUnit("gravy-rainbow/0")
  1469  	c.Assert(err, jc.ErrorIsNil)
  1470  
  1471  	inScope, err := ru.InScope()
  1472  	c.Assert(err, jc.ErrorIsNil)
  1473  	c.Assert(inScope, jc.IsTrue)
  1474  }
  1475  
  1476  func (s *MigrationImportSuite) assertRelationsMissingStatus(c *gc.C, hasUnits bool) {
  1477  	wordpress := state.AddTestingApplication(c, s.State, "wordpress", state.AddTestingCharm(c, s.State, "wordpress"))
  1478  	state.AddTestingApplication(c, s.State, "mysql", state.AddTestingCharm(c, s.State, "mysql"))
  1479  	eps, err := s.State.InferEndpoints("mysql", "wordpress")
  1480  	c.Assert(err, jc.ErrorIsNil)
  1481  	rel, err := s.State.AddRelation(eps...)
  1482  	c.Assert(err, jc.ErrorIsNil)
  1483  
  1484  	if hasUnits {
  1485  		wordpress_0 := s.Factory.MakeUnit(c, &factory.UnitParams{Application: wordpress})
  1486  		ru, err := rel.Unit(wordpress_0)
  1487  		c.Assert(err, jc.ErrorIsNil)
  1488  		relSettings := map[string]interface{}{
  1489  			"name": "wordpress/0",
  1490  		}
  1491  		err = ru.EnterScope(relSettings)
  1492  		c.Assert(err, jc.ErrorIsNil)
  1493  	}
  1494  
  1495  	_, newSt := s.importModel(c, s.State, func(desc map[string]interface{}) {
  1496  		relations := desc["relations"].(map[interface{}]interface{})
  1497  		for _, item := range relations["relations"].([]interface{}) {
  1498  			relation := item.(map[interface{}]interface{})
  1499  			delete(relation, "status")
  1500  		}
  1501  	})
  1502  
  1503  	newWordpress, err := newSt.Application("wordpress")
  1504  	c.Assert(err, jc.ErrorIsNil)
  1505  	c.Assert(state.RelationCount(newWordpress), gc.Equals, 1)
  1506  	rels, err := newWordpress.Relations()
  1507  	c.Assert(err, jc.ErrorIsNil)
  1508  	c.Assert(rels, gc.HasLen, 1)
  1509  
  1510  	relStatus, err := rels[0].Status()
  1511  	c.Assert(err, jc.ErrorIsNil)
  1512  	if hasUnits {
  1513  		c.Assert(relStatus.Status, gc.Equals, status.Joined)
  1514  	} else {
  1515  		c.Assert(relStatus.Status, gc.Equals, status.Joining)
  1516  	}
  1517  }
  1518  
  1519  func (s *MigrationImportSuite) TestRelationsMissingStatusWithUnits(c *gc.C) {
  1520  	s.assertRelationsMissingStatus(c, true)
  1521  }
  1522  
  1523  func (s *MigrationImportSuite) TestRelationsMissingStatusNoUnits(c *gc.C) {
  1524  	s.assertRelationsMissingStatus(c, false)
  1525  }
  1526  
  1527  func (s *MigrationImportSuite) TestEndpointBindings(c *gc.C) {
  1528  	// Endpoint bindings need both valid charms, applications, and spaces.
  1529  	space := s.Factory.MakeSpace(c, &factory.SpaceParams{
  1530  		Name: "one", ProviderID: "provider", IsPublic: true})
  1531  	state.AddTestingApplicationWithBindings(
  1532  		c, s.State, "wordpress", state.AddTestingCharm(c, s.State, "wordpress"),
  1533  		map[string]string{"db": space.Id()})
  1534  
  1535  	_, newSt := s.importModel(c, s.State)
  1536  
  1537  	newWordpress, err := newSt.Application("wordpress")
  1538  	c.Assert(err, jc.ErrorIsNil)
  1539  
  1540  	bindings, err := newWordpress.EndpointBindings()
  1541  	c.Assert(err, jc.ErrorIsNil)
  1542  	// Check the "db" endpoint has the correct space ID, the others
  1543  	// should have the AlphaSpaceId
  1544  	c.Assert(bindings.Map()["db"], gc.Equals, space.Id())
  1545  	c.Assert(bindings.Map()[""], gc.Equals, network.AlphaSpaceId)
  1546  }
  1547  
  1548  func (s *MigrationImportSuite) TestIncompleteEndpointBindings(c *gc.C) {
  1549  	// Ensure we handle the case coming from an early 2.7 controller
  1550  	// where the default binding is missing.
  1551  	space := s.Factory.MakeSpace(c, &factory.SpaceParams{
  1552  		Name: "one", ProviderID: "provider", IsPublic: true})
  1553  	state.AddTestingApplicationWithBindings(
  1554  		c, s.State, "wordpress", state.AddTestingCharm(c, s.State, "wordpress"),
  1555  		map[string]string{"db": space.Id()})
  1556  
  1557  	_, newSt := s.importModel(c, s.State, func(desc map[string]interface{}) {
  1558  		apps := desc["applications"].(map[interface{}]interface{})
  1559  		for _, item := range apps["applications"].([]interface{}) {
  1560  			bindings, ok := item.(map[interface{}]interface{})["endpoint-bindings"].(map[interface{}]interface{})
  1561  			if !ok {
  1562  				continue
  1563  			}
  1564  			delete(bindings, "")
  1565  		}
  1566  	})
  1567  
  1568  	newWordpress, err := newSt.Application("wordpress")
  1569  	c.Assert(err, jc.ErrorIsNil)
  1570  
  1571  	bindings, err := newWordpress.EndpointBindings()
  1572  	c.Assert(err, jc.ErrorIsNil)
  1573  	c.Assert(bindings.Map()["db"], gc.Equals, space.Id())
  1574  	c.Assert(bindings.Map()[""], gc.Equals, network.AlphaSpaceId)
  1575  }
  1576  
  1577  func (s *MigrationImportSuite) TestNilEndpointBindings(c *gc.C) {
  1578  	app := state.AddTestingApplicationWithEmptyBindings(
  1579  		c, s.State, "dummy", state.AddTestingCharm(c, s.State, "dummy"))
  1580  
  1581  	bindings, err := app.EndpointBindings()
  1582  	c.Assert(err, jc.ErrorIsNil)
  1583  	c.Assert(bindings.Map(), gc.HasLen, 0)
  1584  
  1585  	_, newSt := s.importModel(c, s.State)
  1586  
  1587  	newApp, err := newSt.Application("dummy")
  1588  	c.Assert(err, jc.ErrorIsNil)
  1589  
  1590  	newBindings, err := newApp.EndpointBindings()
  1591  	c.Assert(err, jc.ErrorIsNil)
  1592  	c.Assert(newBindings.Map()[""], gc.Equals, network.AlphaSpaceId)
  1593  }
  1594  
  1595  func (s *MigrationImportSuite) TestUnitsOpenPorts(c *gc.C) {
  1596  	unit := s.Factory.MakeUnit(c, nil)
  1597  
  1598  	unitPortRanges, err := unit.OpenedPortRanges()
  1599  	c.Assert(err, jc.ErrorIsNil)
  1600  	unitPortRanges.Open(allEndpoints, network.MustParsePortRange("1234-2345/tcp"))
  1601  	c.Assert(s.State.ApplyOperation(unitPortRanges.Changes()), jc.ErrorIsNil)
  1602  
  1603  	_, newSt := s.importModel(c, s.State)
  1604  
  1605  	// Even though the opened ports document is stored with the
  1606  	// machine, the only way to easily access it is through the units.
  1607  	imported, err := newSt.Unit(unit.Name())
  1608  	c.Assert(err, jc.ErrorIsNil)
  1609  
  1610  	unitPortRanges, err = imported.OpenedPortRanges()
  1611  	c.Assert(err, jc.ErrorIsNil)
  1612  	c.Assert(unitPortRanges.UniquePortRanges(), gc.HasLen, 1)
  1613  
  1614  	portRanges := unitPortRanges.ForEndpoint(allEndpoints)
  1615  	c.Assert(portRanges, gc.HasLen, 1)
  1616  	c.Assert(portRanges[0], gc.Equals, network.PortRange{
  1617  		FromPort: 1234,
  1618  		ToPort:   2345,
  1619  		Protocol: "tcp",
  1620  	})
  1621  }
  1622  
  1623  func (s *MigrationImportSuite) TestSpaces(c *gc.C) {
  1624  	space := s.Factory.MakeSpace(c, &factory.SpaceParams{
  1625  		Name: "one", ProviderID: network.Id("provider"), IsPublic: true})
  1626  
  1627  	spaceNoID := s.Factory.MakeSpace(c, &factory.SpaceParams{
  1628  		Name: "no-id", ProviderID: network.Id("provider2"), IsPublic: true})
  1629  
  1630  	// Blank the ID from the second space to check that import creates it.
  1631  	_, newSt := s.importModel(c, s.State, func(desc map[string]interface{}) {
  1632  		spaces := desc["spaces"].(map[interface{}]interface{})
  1633  		for _, item := range spaces["spaces"].([]interface{}) {
  1634  			sp := item.(map[interface{}]interface{})
  1635  			if sp["name"] == spaceNoID.Name() {
  1636  				sp["id"] = ""
  1637  			}
  1638  		}
  1639  	})
  1640  
  1641  	imported, err := newSt.SpaceByName(space.Name())
  1642  	c.Assert(err, jc.ErrorIsNil)
  1643  
  1644  	c.Check(imported.Id(), gc.Equals, space.Id())
  1645  	c.Check(imported.Name(), gc.Equals, space.Name())
  1646  	c.Check(imported.ProviderId(), gc.Equals, space.ProviderId())
  1647  	c.Check(imported.IsPublic(), gc.Equals, space.IsPublic())
  1648  
  1649  	imported, err = newSt.SpaceByName(spaceNoID.Name())
  1650  	c.Assert(err, jc.ErrorIsNil)
  1651  	c.Check(imported.Id(), gc.Not(gc.Equals), "")
  1652  }
  1653  
  1654  func (s *MigrationImportSuite) TestFirewallRules(c *gc.C) {
  1655  	ctrl := gomock.NewController(c)
  1656  	defer ctrl.Finish()
  1657  
  1658  	sshCIDRs := []string{"192.168.1.0/24", "192.0.2.1/24"}
  1659  	sshRule := state.NewMockFirewallRule(ctrl)
  1660  	sshRule.EXPECT().WellKnownService().Return("ssh")
  1661  	sshRule.EXPECT().WhitelistCIDRs().Return(sshCIDRs)
  1662  
  1663  	saasCIDRs := []string{"10.0.0.0/16"}
  1664  	saasRule := state.NewMockFirewallRule(ctrl)
  1665  	saasRule.EXPECT().WellKnownService().Return("juju-application-offer")
  1666  	saasRule.EXPECT().WhitelistCIDRs().Return(saasCIDRs)
  1667  
  1668  	base, err := s.State.Export(map[string]string{})
  1669  	c.Assert(err, jc.ErrorIsNil)
  1670  	uuid := utils.MustNewUUID().String()
  1671  	model := newModel(base, uuid, "new")
  1672  	model.fwRules = []description.FirewallRule{sshRule, saasRule}
  1673  
  1674  	_, newSt := s.importModelDescription(c, model)
  1675  
  1676  	m, err := newSt.Model()
  1677  	c.Assert(err, jc.ErrorIsNil)
  1678  	cfg, err := m.ModelConfig()
  1679  	c.Assert(err, jc.ErrorIsNil)
  1680  
  1681  	c.Assert(cfg.SSHAllow(), gc.DeepEquals, sshCIDRs)
  1682  	c.Assert(cfg.SAASIngressAllow(), gc.DeepEquals, saasCIDRs)
  1683  }
  1684  
  1685  func (s *MigrationImportSuite) TestDestroyEmptyModel(c *gc.C) {
  1686  	newModel, _ := s.importModel(c, s.State)
  1687  	s.assertDestroyModelAdvancesLife(c, newModel, state.Dying)
  1688  }
  1689  
  1690  func (s *MigrationImportSuite) TestDestroyModelWithMachine(c *gc.C) {
  1691  	s.Factory.MakeMachine(c, nil)
  1692  	newModel, _ := s.importModel(c, s.State)
  1693  	s.assertDestroyModelAdvancesLife(c, newModel, state.Dying)
  1694  }
  1695  
  1696  func (s *MigrationImportSuite) TestDestroyModelWithApplication(c *gc.C) {
  1697  	s.Factory.MakeApplication(c, nil)
  1698  	newModel, _ := s.importModel(c, s.State)
  1699  	s.assertDestroyModelAdvancesLife(c, newModel, state.Dying)
  1700  }
  1701  
  1702  func (s *MigrationImportSuite) assertDestroyModelAdvancesLife(c *gc.C, m *state.Model, life state.Life) {
  1703  	c.Assert(m.Destroy(state.DestroyModelParams{}), jc.ErrorIsNil)
  1704  	c.Assert(m.Refresh(), jc.ErrorIsNil)
  1705  	c.Assert(m.Life(), gc.Equals, life)
  1706  }
  1707  
  1708  func (s *MigrationImportSuite) TestLinkLayerDevice(c *gc.C) {
  1709  	machine := s.Factory.MakeMachine(c, &factory.MachineParams{
  1710  		Constraints: constraints.MustParse("arch=amd64 mem=8G"),
  1711  	})
  1712  	deviceArgs := state.LinkLayerDeviceArgs{
  1713  		Name:            "foo",
  1714  		Type:            network.EthernetDevice,
  1715  		VirtualPortType: network.OvsPort,
  1716  	}
  1717  	err := machine.SetLinkLayerDevices(deviceArgs)
  1718  	c.Assert(err, jc.ErrorIsNil)
  1719  	_, newSt := s.importModel(c, s.State)
  1720  
  1721  	devices, err := newSt.AllLinkLayerDevices()
  1722  	c.Assert(err, jc.ErrorIsNil)
  1723  	c.Assert(devices, gc.HasLen, 1)
  1724  	device := devices[0]
  1725  	c.Assert(device.Name(), gc.Equals, "foo")
  1726  	c.Assert(device.Type(), gc.Equals, network.EthernetDevice)
  1727  	c.Assert(device.VirtualPortType(), gc.Equals, network.OvsPort, gc.Commentf("VirtualPortType not migrated correctly"))
  1728  }
  1729  
  1730  func (s *MigrationImportSuite) TestLinkLayerDeviceMigratesReferences(c *gc.C) {
  1731  	machine := s.Factory.MakeMachine(c, &factory.MachineParams{
  1732  		Constraints: constraints.MustParse("arch=amd64 mem=8G"),
  1733  	})
  1734  	machine2 := s.Factory.MakeMachineNested(c, machine.Id(), &factory.MachineParams{
  1735  		Constraints: constraints.MustParse("arch=amd64 mem=8G"),
  1736  	})
  1737  	deviceArgs := []state.LinkLayerDeviceArgs{{
  1738  		Name: "foo",
  1739  		Type: network.BridgeDevice,
  1740  	}, {
  1741  		Name:       "bar",
  1742  		ParentName: "foo",
  1743  		Type:       network.EthernetDevice,
  1744  	}}
  1745  	for _, args := range deviceArgs {
  1746  		err := machine.SetLinkLayerDevices(args)
  1747  		c.Assert(err, jc.ErrorIsNil)
  1748  	}
  1749  	machine2DeviceArgs := state.LinkLayerDeviceArgs{
  1750  		Name:       "baz",
  1751  		ParentName: fmt.Sprintf("m#%v#d#foo", machine.Id()),
  1752  		Type:       network.EthernetDevice,
  1753  	}
  1754  	err := machine2.SetLinkLayerDevices(machine2DeviceArgs)
  1755  	c.Assert(err, jc.ErrorIsNil)
  1756  	_, newSt := s.importModel(c, s.State)
  1757  
  1758  	devices, err := newSt.AllLinkLayerDevices()
  1759  	c.Assert(err, jc.ErrorIsNil)
  1760  	c.Assert(devices, gc.HasLen, 3)
  1761  	var parent *state.LinkLayerDevice
  1762  	others := []*state.LinkLayerDevice{}
  1763  	for _, device := range devices {
  1764  		if device.Name() == "foo" {
  1765  			parent = device
  1766  		} else {
  1767  			others = append(others, device)
  1768  		}
  1769  	}
  1770  	// Assert we found the parent.
  1771  	c.Assert(others, gc.HasLen, 2)
  1772  	err = parent.Remove()
  1773  	c.Assert(err, gc.ErrorMatches, `.*parent device "foo" has 2 children.*`)
  1774  	err = others[0].Remove()
  1775  	c.Assert(err, jc.ErrorIsNil)
  1776  	err = parent.Remove()
  1777  	c.Assert(err, gc.ErrorMatches, `.*parent device "foo" has 1 children.*`)
  1778  	err = others[1].Remove()
  1779  	c.Assert(err, jc.ErrorIsNil)
  1780  	err = parent.Remove()
  1781  	c.Assert(err, jc.ErrorIsNil)
  1782  }
  1783  
  1784  func (s *MigrationImportSuite) TestSubnets(c *gc.C) {
  1785  	sp, err := s.State.AddSpace("bam", "", nil, true)
  1786  	c.Assert(err, jc.ErrorIsNil)
  1787  	original, err := s.State.AddSubnet(network.SubnetInfo{
  1788  		CIDR:              "10.0.0.0/24",
  1789  		ProviderId:        "foo",
  1790  		ProviderNetworkId: "elm",
  1791  		VLANTag:           64,
  1792  		SpaceID:           sp.Id(),
  1793  		AvailabilityZones: []string{"bar"},
  1794  		IsPublic:          true,
  1795  	})
  1796  	c.Assert(err, jc.ErrorIsNil)
  1797  	originalNoID, err := s.State.AddSubnet(network.SubnetInfo{
  1798  		CIDR:              "10.76.0.0/24",
  1799  		ProviderId:        "bar",
  1800  		ProviderNetworkId: "oak",
  1801  		VLANTag:           64,
  1802  		SpaceID:           sp.Id(),
  1803  		AvailabilityZones: []string{"bar"},
  1804  	})
  1805  	c.Assert(err, jc.ErrorIsNil)
  1806  
  1807  	_, newSt := s.importModel(c, s.State, func(desc map[string]interface{}) {
  1808  		subnets := desc["subnets"].(map[interface{}]interface{})
  1809  		for _, item := range subnets["subnets"].([]interface{}) {
  1810  			sn := item.(map[interface{}]interface{})
  1811  
  1812  			if sn["subnet-id"] == originalNoID.ID() {
  1813  				// Remove the subnet ID, to check that it is created by import.
  1814  				sn["subnet-id"] = ""
  1815  
  1816  				// Swap the space ID for a space name to check migrating from
  1817  				// a pre-2.7 model.
  1818  				sn["space-id"] = ""
  1819  				sn["space-name"] = sp.Name()
  1820  			}
  1821  		}
  1822  	})
  1823  
  1824  	subnet, err := newSt.Subnet(original.ID())
  1825  	c.Assert(err, jc.ErrorIsNil)
  1826  
  1827  	c.Assert(subnet.CIDR(), gc.Equals, "10.0.0.0/24")
  1828  	c.Assert(subnet.ProviderId(), gc.Equals, network.Id("foo"))
  1829  	c.Assert(subnet.ProviderNetworkId(), gc.Equals, network.Id("elm"))
  1830  	c.Assert(subnet.VLANTag(), gc.Equals, 64)
  1831  	c.Assert(subnet.AvailabilityZones(), gc.DeepEquals, []string{"bar"})
  1832  	c.Assert(subnet.SpaceID(), gc.Equals, sp.Id())
  1833  	c.Assert(subnet.FanLocalUnderlay(), gc.Equals, "")
  1834  	c.Assert(subnet.FanOverlay(), gc.Equals, "")
  1835  	c.Assert(subnet.IsPublic(), gc.Equals, true)
  1836  
  1837  	imported, err := newSt.SubnetByCIDR(originalNoID.CIDR())
  1838  	c.Assert(err, jc.ErrorIsNil)
  1839  	c.Check(imported, gc.Not(gc.Equals), "")
  1840  }
  1841  
  1842  func (s *MigrationImportSuite) TestSubnetsWithFan(c *gc.C) {
  1843  	subnet, err := s.State.AddSubnet(network.SubnetInfo{
  1844  		CIDR: "100.2.0.0/16",
  1845  	})
  1846  	c.Assert(err, jc.ErrorIsNil)
  1847  	sp, err := s.State.AddSpace("bam", "", []string{subnet.ID()}, true)
  1848  	c.Assert(err, jc.ErrorIsNil)
  1849  
  1850  	sn := network.SubnetInfo{
  1851  		CIDR:              "10.0.0.0/24",
  1852  		ProviderId:        network.Id("foo"),
  1853  		ProviderNetworkId: network.Id("elm"),
  1854  		VLANTag:           64,
  1855  		AvailabilityZones: []string{"bar"},
  1856  	}
  1857  	sn.SetFan("100.2.0.0/16", "253.0.0.0/8")
  1858  
  1859  	original, err := s.State.AddSubnet(sn)
  1860  	c.Assert(err, jc.ErrorIsNil)
  1861  
  1862  	_, newSt := s.importModel(c, s.State)
  1863  
  1864  	subnet, err = newSt.SubnetByCIDR(original.CIDR())
  1865  	c.Assert(err, jc.ErrorIsNil)
  1866  
  1867  	c.Assert(subnet.CIDR(), gc.Equals, "10.0.0.0/24")
  1868  	c.Assert(subnet.ProviderId(), gc.Equals, network.Id("foo"))
  1869  	c.Assert(subnet.ProviderNetworkId(), gc.Equals, network.Id("elm"))
  1870  	c.Assert(subnet.VLANTag(), gc.Equals, 64)
  1871  	c.Assert(subnet.AvailabilityZones(), gc.DeepEquals, []string{"bar"})
  1872  	c.Assert(subnet.SpaceID(), gc.Equals, sp.Id())
  1873  	c.Assert(subnet.FanLocalUnderlay(), gc.Equals, "100.2.0.0/16")
  1874  	c.Assert(subnet.FanOverlay(), gc.Equals, "253.0.0.0/8")
  1875  }
  1876  
  1877  func (s *MigrationImportSuite) TestIPAddress(c *gc.C) {
  1878  	machine := s.Factory.MakeMachine(c, &factory.MachineParams{
  1879  		Constraints: constraints.MustParse("arch=amd64 mem=8G"),
  1880  	})
  1881  	space, err := s.State.AddSpace("testme", "", nil, true)
  1882  	c.Assert(err, jc.ErrorIsNil)
  1883  	_, err = s.State.AddSubnet(network.SubnetInfo{CIDR: "0.1.2.0/24", SpaceID: space.Id()})
  1884  	c.Assert(err, jc.ErrorIsNil)
  1885  	deviceArgs := state.LinkLayerDeviceArgs{
  1886  		Name: "foo",
  1887  		Type: network.EthernetDevice,
  1888  	}
  1889  	err = machine.SetLinkLayerDevices(deviceArgs)
  1890  	c.Assert(err, jc.ErrorIsNil)
  1891  	args := state.LinkLayerDeviceAddress{
  1892  		DeviceName:        "foo",
  1893  		ConfigMethod:      network.ConfigStatic,
  1894  		CIDRAddress:       "0.1.2.3/24",
  1895  		ProviderID:        "bar",
  1896  		DNSServers:        []string{"bam", "mam"},
  1897  		DNSSearchDomains:  []string{"weeee"},
  1898  		GatewayAddress:    "0.1.2.1",
  1899  		ProviderNetworkID: "p-net-id",
  1900  		ProviderSubnetID:  "p-sub-id",
  1901  		Origin:            network.OriginProvider,
  1902  	}
  1903  	err = machine.SetDevicesAddresses(args)
  1904  	c.Assert(err, jc.ErrorIsNil)
  1905  
  1906  	_, newSt := s.importModel(c, s.State)
  1907  
  1908  	addresses, _ := newSt.AllIPAddresses()
  1909  	c.Assert(addresses, gc.HasLen, 1)
  1910  	c.Assert(err, jc.ErrorIsNil)
  1911  	addr := addresses[0]
  1912  	c.Assert(addr.Value(), gc.Equals, "0.1.2.3")
  1913  	c.Assert(addr.MachineID(), gc.Equals, machine.Id())
  1914  	c.Assert(addr.DeviceName(), gc.Equals, "foo")
  1915  	c.Assert(addr.ConfigMethod(), gc.Equals, network.ConfigStatic)
  1916  	c.Assert(addr.SubnetCIDR(), gc.Equals, "0.1.2.0/24")
  1917  	c.Assert(addr.ProviderID(), gc.Equals, network.Id("bar"))
  1918  	c.Assert(addr.DNSServers(), jc.DeepEquals, []string{"bam", "mam"})
  1919  	c.Assert(addr.DNSSearchDomains(), jc.DeepEquals, []string{"weeee"})
  1920  	c.Assert(addr.GatewayAddress(), gc.Equals, "0.1.2.1")
  1921  	c.Assert(addr.ProviderNetworkID().String(), gc.Equals, "p-net-id")
  1922  	c.Assert(addr.ProviderSubnetID().String(), gc.Equals, "p-sub-id")
  1923  	c.Assert(addr.Origin(), gc.Equals, network.OriginProvider)
  1924  }
  1925  
  1926  func (s *MigrationImportSuite) TestIPAddressCompatibility(c *gc.C) {
  1927  	machine := s.Factory.MakeMachine(c, &factory.MachineParams{
  1928  		Constraints: constraints.MustParse("arch=amd64 mem=8G"),
  1929  	})
  1930  
  1931  	_, err := s.State.AddSubnet(network.SubnetInfo{CIDR: "0.1.2.0/24"})
  1932  	c.Assert(err, jc.ErrorIsNil)
  1933  	deviceArgs := state.LinkLayerDeviceArgs{
  1934  		Name: "foo",
  1935  		Type: network.EthernetDevice,
  1936  	}
  1937  	err = machine.SetLinkLayerDevices(deviceArgs)
  1938  	c.Assert(err, jc.ErrorIsNil)
  1939  	args := state.LinkLayerDeviceAddress{
  1940  		DeviceName:   "foo",
  1941  		ConfigMethod: "dynamic",
  1942  		CIDRAddress:  "0.1.2.3/24",
  1943  		Origin:       network.OriginProvider,
  1944  	}
  1945  	err = machine.SetDevicesAddresses(args)
  1946  	c.Assert(err, jc.ErrorIsNil)
  1947  
  1948  	_, newSt := s.importModel(c, s.State)
  1949  
  1950  	addresses, _ := newSt.AllIPAddresses()
  1951  	c.Assert(addresses, gc.HasLen, 1)
  1952  	c.Assert(addresses[0].ConfigMethod(), gc.Equals, network.ConfigDHCP)
  1953  }
  1954  
  1955  func (s *MigrationImportSuite) TestSSHHostKey(c *gc.C) {
  1956  	machine := s.Factory.MakeMachine(c, &factory.MachineParams{
  1957  		Constraints: constraints.MustParse("arch=amd64 mem=8G"),
  1958  	})
  1959  	err := s.State.SetSSHHostKeys(machine.MachineTag(), []string{"bam", "mam"})
  1960  	c.Assert(err, jc.ErrorIsNil)
  1961  
  1962  	_, newSt := s.importModel(c, s.State)
  1963  
  1964  	machine2, err := newSt.Machine(machine.Id())
  1965  	c.Assert(err, jc.ErrorIsNil)
  1966  	keys, err := newSt.GetSSHHostKeys(machine2.MachineTag())
  1967  	c.Assert(err, jc.ErrorIsNil)
  1968  	c.Assert(keys, jc.DeepEquals, state.SSHHostKeys{"bam", "mam"})
  1969  }
  1970  
  1971  func (s *MigrationImportSuite) TestCloudImageMetadata(c *gc.C) {
  1972  	storageSize := uint64(3)
  1973  	attrs := cloudimagemetadata.MetadataAttributes{
  1974  		Stream:          "stream",
  1975  		Region:          "region-test",
  1976  		Version:         "22.04",
  1977  		Arch:            "arch",
  1978  		VirtType:        "virtType-test",
  1979  		RootStorageType: "rootStorageType-test",
  1980  		RootStorageSize: &storageSize,
  1981  		Source:          "test",
  1982  	}
  1983  	attrsCustom := cloudimagemetadata.MetadataAttributes{
  1984  		Stream:          "stream",
  1985  		Region:          "region-custom",
  1986  		Version:         "22.04",
  1987  		Arch:            "arch",
  1988  		VirtType:        "virtType-test",
  1989  		RootStorageType: "rootStorageType-test",
  1990  		RootStorageSize: &storageSize,
  1991  		Source:          "custom",
  1992  	}
  1993  	metadata := []cloudimagemetadata.Metadata{
  1994  		{attrs, 2, "1", 2},
  1995  		{attrsCustom, 3, "2", 3},
  1996  	}
  1997  
  1998  	err := s.State.CloudImageMetadataStorage.SaveMetadata(metadata)
  1999  	c.Assert(err, jc.ErrorIsNil)
  2000  
  2001  	_, newSt := s.importModel(c, s.State, func(map[string]interface{}) {
  2002  		// Image metadata collection is global so we need to delete it
  2003  		// to properly test import.
  2004  		all, err := s.State.CloudImageMetadataStorage.AllCloudImageMetadata()
  2005  		c.Assert(err, jc.ErrorIsNil)
  2006  		for _, m := range all {
  2007  			err := s.State.CloudImageMetadataStorage.DeleteMetadata(m.ImageId)
  2008  			c.Assert(err, jc.ErrorIsNil)
  2009  		}
  2010  	})
  2011  	defer func() {
  2012  		c.Assert(newSt.Close(), jc.ErrorIsNil)
  2013  	}()
  2014  
  2015  	images, err := newSt.CloudImageMetadataStorage.AllCloudImageMetadata()
  2016  	c.Assert(err, jc.ErrorIsNil)
  2017  	c.Assert(images, gc.HasLen, 1)
  2018  	image := images[0]
  2019  	c.Check(image.Stream, gc.Equals, "stream")
  2020  	c.Check(image.Region, gc.Equals, "region-custom")
  2021  	c.Check(image.Version, gc.Equals, "22.04")
  2022  	c.Check(image.Arch, gc.Equals, "arch")
  2023  	c.Check(image.VirtType, gc.Equals, "virtType-test")
  2024  	c.Check(image.RootStorageType, gc.Equals, "rootStorageType-test")
  2025  	c.Check(*image.RootStorageSize, gc.Equals, uint64(3))
  2026  	c.Check(image.Source, gc.Equals, "custom")
  2027  	c.Check(image.Priority, gc.Equals, 3)
  2028  	c.Check(image.ImageId, gc.Equals, "2")
  2029  	c.Check(image.DateCreated, gc.Equals, int64(3))
  2030  }
  2031  
  2032  func (s *MigrationImportSuite) TestAction(c *gc.C) {
  2033  	machine := s.Factory.MakeMachine(c, &factory.MachineParams{
  2034  		Constraints: constraints.MustParse("arch=amd64 mem=8G"),
  2035  	})
  2036  
  2037  	m, err := s.State.Model()
  2038  	c.Assert(err, jc.ErrorIsNil)
  2039  
  2040  	// pending action.
  2041  	operationIDPending, err := m.EnqueueOperation("a test", 2)
  2042  	c.Assert(err, jc.ErrorIsNil)
  2043  	actionPending, err := m.EnqueueAction(operationIDPending, machine.MachineTag(), "action-pending", nil, true, "group", nil)
  2044  	c.Assert(err, jc.ErrorIsNil)
  2045  	c.Assert(actionPending.Status(), gc.Equals, state.ActionPending)
  2046  
  2047  	// running action.
  2048  	operationIDRunning, err := m.EnqueueOperation("another test", 2)
  2049  	c.Assert(err, jc.ErrorIsNil)
  2050  	actionRunning, err := m.EnqueueAction(operationIDRunning, machine.MachineTag(), "action-running", nil, true, "group", nil)
  2051  	c.Assert(err, jc.ErrorIsNil)
  2052  	c.Assert(actionRunning.Status(), gc.Equals, state.ActionPending)
  2053  	actionRunning, err = actionRunning.Begin()
  2054  	c.Assert(err, jc.ErrorIsNil)
  2055  	c.Assert(actionRunning.Status(), gc.Equals, state.ActionRunning)
  2056  
  2057  	// aborting action.
  2058  	operationIDAborting, err := m.EnqueueOperation("another test", 2)
  2059  	c.Assert(err, jc.ErrorIsNil)
  2060  	actionAborting, err := m.EnqueueAction(operationIDAborting, machine.MachineTag(), "action-aborting", nil, true, "group", nil)
  2061  	c.Assert(err, jc.ErrorIsNil)
  2062  	c.Assert(actionAborting.Status(), gc.Equals, state.ActionPending)
  2063  	actionAborting, err = actionAborting.Begin()
  2064  	c.Assert(err, jc.ErrorIsNil)
  2065  	c.Assert(actionAborting.Status(), gc.Equals, state.ActionRunning)
  2066  	actionAborting, err = actionAborting.Finish(state.ActionResults{Status: state.ActionAborting})
  2067  	c.Assert(err, jc.ErrorIsNil)
  2068  	c.Assert(actionAborting.Status(), gc.Equals, state.ActionAborting)
  2069  
  2070  	// aborted action.
  2071  	operationIDAborted, err := m.EnqueueOperation("another test", 2)
  2072  	c.Assert(err, jc.ErrorIsNil)
  2073  	actionAborted, err := m.EnqueueAction(operationIDAborted, machine.MachineTag(), "action-aborted", nil, true, "group", nil)
  2074  	c.Assert(err, jc.ErrorIsNil)
  2075  	c.Assert(actionAborted.Status(), gc.Equals, state.ActionPending)
  2076  	actionAborted, err = actionAborted.Begin()
  2077  	c.Assert(err, jc.ErrorIsNil)
  2078  	c.Assert(actionAborted.Status(), gc.Equals, state.ActionRunning)
  2079  	actionAborted, err = actionAborted.Finish(state.ActionResults{Status: state.ActionAborted})
  2080  	c.Assert(err, jc.ErrorIsNil)
  2081  	c.Assert(actionAborted.Status(), gc.Equals, state.ActionAborted)
  2082  
  2083  	// completed action.
  2084  	operationIDCompleted, err := m.EnqueueOperation("another test", 2)
  2085  	c.Assert(err, jc.ErrorIsNil)
  2086  	actionCompleted, err := m.EnqueueAction(operationIDCompleted, machine.MachineTag(), "action-completed", nil, true, "group", nil)
  2087  	c.Assert(err, jc.ErrorIsNil)
  2088  	c.Assert(actionCompleted.Status(), gc.Equals, state.ActionPending)
  2089  	actionCompleted, err = actionCompleted.Begin()
  2090  	c.Assert(err, jc.ErrorIsNil)
  2091  	c.Assert(actionCompleted.Status(), gc.Equals, state.ActionRunning)
  2092  	actionCompleted, err = actionCompleted.Finish(state.ActionResults{Status: state.ActionCompleted})
  2093  	c.Assert(err, jc.ErrorIsNil)
  2094  	c.Assert(actionCompleted.Status(), gc.Equals, state.ActionCompleted)
  2095  
  2096  	newModel, newState := s.importModel(c, s.State)
  2097  	defer func() {
  2098  		c.Assert(newState.Close(), jc.ErrorIsNil)
  2099  	}()
  2100  
  2101  	actions, err := newModel.AllActions()
  2102  	c.Assert(err, jc.ErrorIsNil)
  2103  	c.Assert(actions, gc.HasLen, 5)
  2104  
  2105  	actionPending, err = newModel.ActionByTag(actionPending.ActionTag())
  2106  	c.Assert(err, jc.ErrorIsNil)
  2107  	c.Check(actionPending.Receiver(), gc.Equals, machine.Id())
  2108  	c.Check(actionPending.Name(), gc.Equals, "action-pending")
  2109  	c.Check(state.ActionOperationId(actionPending), gc.Equals, operationIDPending)
  2110  	c.Check(actionPending.Status(), gc.Equals, state.ActionPending)
  2111  	c.Check(actionPending.Parallel(), jc.IsTrue)
  2112  	c.Check(actionPending.ExecutionGroup(), gc.Equals, "group")
  2113  
  2114  	actionRunning, err = newModel.ActionByTag(actionRunning.ActionTag())
  2115  	c.Assert(err, jc.ErrorIsNil)
  2116  	c.Check(actionRunning.Receiver(), gc.Equals, machine.Id())
  2117  	c.Check(actionRunning.Name(), gc.Equals, "action-running")
  2118  	c.Check(state.ActionOperationId(actionRunning), gc.Equals, operationIDRunning)
  2119  	c.Check(actionRunning.Status(), gc.Equals, state.ActionRunning)
  2120  	c.Check(actionRunning.Parallel(), jc.IsTrue)
  2121  	c.Check(actionRunning.ExecutionGroup(), gc.Equals, "group")
  2122  
  2123  	actionAborting, err = newModel.ActionByTag(actionAborting.ActionTag())
  2124  	c.Assert(err, jc.ErrorIsNil)
  2125  	c.Check(actionAborting.Receiver(), gc.Equals, machine.Id())
  2126  	c.Check(actionAborting.Name(), gc.Equals, "action-aborting")
  2127  	c.Check(state.ActionOperationId(actionAborting), gc.Equals, operationIDAborting)
  2128  	c.Check(actionAborting.Status(), gc.Equals, state.ActionAborting)
  2129  	c.Check(actionAborting.Parallel(), jc.IsTrue)
  2130  	c.Check(actionAborting.ExecutionGroup(), gc.Equals, "group")
  2131  
  2132  	actionAborted, err = newModel.ActionByTag(actionAborted.ActionTag())
  2133  	c.Assert(err, jc.ErrorIsNil)
  2134  	c.Check(actionAborted.Receiver(), gc.Equals, machine.Id())
  2135  	c.Check(actionAborted.Name(), gc.Equals, "action-aborted")
  2136  	c.Check(state.ActionOperationId(actionAborted), gc.Equals, operationIDAborted)
  2137  	c.Check(actionAborted.Status(), gc.Equals, state.ActionAborted)
  2138  	c.Check(actionAborted.Parallel(), jc.IsTrue)
  2139  	c.Check(actionAborted.ExecutionGroup(), gc.Equals, "group")
  2140  
  2141  	actionCompleted, err = newModel.ActionByTag(actionCompleted.ActionTag())
  2142  	c.Assert(err, jc.ErrorIsNil)
  2143  	c.Check(actionCompleted.Receiver(), gc.Equals, machine.Id())
  2144  	c.Check(actionCompleted.Name(), gc.Equals, "action-completed")
  2145  	c.Check(state.ActionOperationId(actionCompleted), gc.Equals, operationIDCompleted)
  2146  	c.Check(actionCompleted.Status(), gc.Equals, state.ActionCompleted)
  2147  	c.Check(actionCompleted.Parallel(), jc.IsTrue)
  2148  	c.Check(actionCompleted.ExecutionGroup(), gc.Equals, "group")
  2149  
  2150  	// Only pending/running/aborting actions will have action notification docs imported.
  2151  	actionIDs, err := newModel.AllActionIDsHasActionNotifications()
  2152  	c.Assert(err, jc.ErrorIsNil)
  2153  	sort.Strings(actionIDs)
  2154  	expectedIDs := []string{
  2155  		actionRunning.Id(),
  2156  		actionPending.Id(),
  2157  		actionAborting.Id(),
  2158  	}
  2159  	sort.Strings(expectedIDs)
  2160  	c.Check(actionIDs, gc.DeepEquals, expectedIDs)
  2161  }
  2162  
  2163  func (s *MigrationImportSuite) TestOperation(c *gc.C) {
  2164  	m, err := s.State.Model()
  2165  	c.Assert(err, jc.ErrorIsNil)
  2166  
  2167  	operationID, err := m.EnqueueOperation("a test", 2)
  2168  	c.Assert(err, jc.ErrorIsNil)
  2169  	err = m.FailOperationEnqueuing(operationID, "fail", 1)
  2170  	c.Assert(err, jc.ErrorIsNil)
  2171  
  2172  	newModel, newState := s.importModel(c, s.State)
  2173  	defer func() {
  2174  		c.Assert(newState.Close(), jc.ErrorIsNil)
  2175  	}()
  2176  
  2177  	operations, _ := newModel.AllOperations()
  2178  	c.Assert(operations, gc.HasLen, 1)
  2179  	op := operations[0]
  2180  	c.Check(op.Summary(), gc.Equals, "a test")
  2181  	c.Check(op.Fail(), gc.Equals, "fail")
  2182  	c.Check(op.Id(), gc.Equals, operationID)
  2183  	c.Check(op.Status(), gc.Equals, state.ActionPending)
  2184  	c.Check(op.SpawnedTaskCount(), gc.Equals, 1)
  2185  }
  2186  
  2187  func (s *MigrationImportSuite) TestVolumes(c *gc.C) {
  2188  	machine := s.Factory.MakeMachine(c, &factory.MachineParams{
  2189  		Volumes: []state.HostVolumeParams{{
  2190  			Volume:     state.VolumeParams{Size: 1234},
  2191  			Attachment: state.VolumeAttachmentParams{ReadOnly: true},
  2192  		}, {
  2193  			Volume:     state.VolumeParams{Size: 4000},
  2194  			Attachment: state.VolumeAttachmentParams{ReadOnly: true},
  2195  		}, {
  2196  			Volume:     state.VolumeParams{Size: 3000},
  2197  			Attachment: state.VolumeAttachmentParams{ReadOnly: true},
  2198  		}},
  2199  	})
  2200  	machineTag := machine.MachineTag()
  2201  
  2202  	// We know that the first volume is called "0/0" - although I don't know why.
  2203  	volTag := names.NewVolumeTag("0/0")
  2204  	volInfo := state.VolumeInfo{
  2205  		HardwareId: "magic",
  2206  		WWN:        "drbr",
  2207  		Size:       1500,
  2208  		Pool:       "loop",
  2209  		VolumeId:   "volume id",
  2210  		Persistent: true,
  2211  	}
  2212  	sb, err := state.NewStorageBackend(s.State)
  2213  	c.Assert(err, jc.ErrorIsNil)
  2214  	err = sb.SetVolumeInfo(volTag, volInfo)
  2215  	c.Assert(err, jc.ErrorIsNil)
  2216  	volAttachmentInfo := state.VolumeAttachmentInfo{
  2217  		DeviceName: "device name",
  2218  		DeviceLink: "device link",
  2219  		BusAddress: "bus address",
  2220  		ReadOnly:   true,
  2221  	}
  2222  
  2223  	err = sb.SetVolumeAttachmentInfo(machineTag, volTag, volAttachmentInfo)
  2224  	c.Assert(err, jc.ErrorIsNil)
  2225  
  2226  	// attach a iSCSI volume
  2227  	iscsiVolTag := names.NewVolumeTag("0/2")
  2228  	iscsiVolInfo := state.VolumeInfo{
  2229  		HardwareId: "magic",
  2230  		WWN:        "iscsi",
  2231  		Size:       1500,
  2232  		Pool:       "loop",
  2233  		VolumeId:   "iscsi id",
  2234  		Persistent: true,
  2235  	}
  2236  
  2237  	deviceAttrs := map[string]string{
  2238  		"iqn":         "bogusIQN",
  2239  		"address":     "192.168.1.1",
  2240  		"port":        "9999",
  2241  		"chap-user":   "example",
  2242  		"chap-secret": "supersecretpassword",
  2243  	}
  2244  
  2245  	attachmentPlanInfo := state.VolumeAttachmentPlanInfo{
  2246  		DeviceType:       storage.DeviceTypeISCSI,
  2247  		DeviceAttributes: deviceAttrs,
  2248  	}
  2249  
  2250  	iscsiVolAttachmentInfo := state.VolumeAttachmentInfo{
  2251  		DeviceName: "iscsi device",
  2252  		DeviceLink: "iscsi link",
  2253  		BusAddress: "iscsi address",
  2254  		ReadOnly:   true,
  2255  		PlanInfo:   &attachmentPlanInfo,
  2256  	}
  2257  
  2258  	err = sb.SetVolumeInfo(iscsiVolTag, iscsiVolInfo)
  2259  	c.Assert(err, jc.ErrorIsNil)
  2260  
  2261  	err = sb.SetVolumeAttachmentInfo(machineTag, iscsiVolTag, iscsiVolAttachmentInfo)
  2262  	c.Assert(err, jc.ErrorIsNil)
  2263  
  2264  	err = sb.CreateVolumeAttachmentPlan(machineTag, iscsiVolTag, attachmentPlanInfo)
  2265  	c.Assert(err, jc.ErrorIsNil)
  2266  
  2267  	deviceLinks := []string{"/dev/sdb", "/dev/mapper/testDevice"}
  2268  
  2269  	blockInfo := state.BlockDeviceInfo{
  2270  		WWN:         "testWWN",
  2271  		DeviceLinks: deviceLinks,
  2272  		HardwareId:  "test-id",
  2273  	}
  2274  
  2275  	err = sb.SetVolumeAttachmentPlanBlockInfo(machineTag, iscsiVolTag, blockInfo)
  2276  	c.Assert(err, jc.ErrorIsNil)
  2277  
  2278  	_, newSt := s.importModel(c, s.State)
  2279  	newSb, err := state.NewStorageBackend(newSt)
  2280  	c.Assert(err, jc.ErrorIsNil)
  2281  
  2282  	volume, err := newSb.Volume(volTag)
  2283  	c.Assert(err, jc.ErrorIsNil)
  2284  
  2285  	// TODO: check status
  2286  	// TODO: check storage instance
  2287  	info, err := volume.Info()
  2288  	c.Assert(err, jc.ErrorIsNil)
  2289  	c.Check(info, jc.DeepEquals, volInfo)
  2290  
  2291  	attachment, err := newSb.VolumeAttachment(machineTag, volTag)
  2292  	c.Assert(err, jc.ErrorIsNil)
  2293  	attInfo, err := attachment.Info()
  2294  	c.Assert(err, jc.ErrorIsNil)
  2295  	c.Check(attInfo, jc.DeepEquals, volAttachmentInfo)
  2296  
  2297  	_, err = newSb.VolumeAttachmentPlan(machineTag, volTag)
  2298  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
  2299  
  2300  	volTag = names.NewVolumeTag("0/1")
  2301  	volume, err = newSb.Volume(volTag)
  2302  	c.Assert(err, jc.ErrorIsNil)
  2303  
  2304  	params, needsProvisioning := volume.Params()
  2305  	c.Check(needsProvisioning, jc.IsTrue)
  2306  	c.Check(params.Pool, gc.Equals, "loop")
  2307  	c.Check(params.Size, gc.Equals, uint64(4000))
  2308  
  2309  	attachment, err = newSb.VolumeAttachment(machineTag, volTag)
  2310  	c.Assert(err, jc.ErrorIsNil)
  2311  	attParams, needsProvisioning := attachment.Params()
  2312  	c.Check(needsProvisioning, jc.IsTrue)
  2313  	c.Check(attParams.ReadOnly, jc.IsTrue)
  2314  
  2315  	iscsiVolume, err := newSb.Volume(iscsiVolTag)
  2316  	c.Assert(err, jc.ErrorIsNil)
  2317  
  2318  	iscsiInfo, err := iscsiVolume.Info()
  2319  	c.Assert(err, jc.ErrorIsNil)
  2320  	c.Check(iscsiInfo, jc.DeepEquals, iscsiVolInfo)
  2321  
  2322  	attachment, err = newSb.VolumeAttachment(machineTag, iscsiVolTag)
  2323  	c.Assert(err, jc.ErrorIsNil)
  2324  	attInfo, err = attachment.Info()
  2325  	c.Assert(err, jc.ErrorIsNil)
  2326  	c.Check(attInfo, jc.DeepEquals, iscsiVolAttachmentInfo)
  2327  
  2328  	attachmentPlan, err := newSb.VolumeAttachmentPlan(machineTag, iscsiVolTag)
  2329  	c.Assert(err, gc.IsNil)
  2330  	c.Assert(attachmentPlan.Volume(), gc.Equals, iscsiVolTag)
  2331  	c.Assert(attachmentPlan.Machine(), gc.Equals, machineTag)
  2332  
  2333  	planInfo, err := attachmentPlan.PlanInfo()
  2334  	c.Assert(err, gc.IsNil)
  2335  	c.Assert(planInfo, jc.DeepEquals, attachmentPlanInfo)
  2336  
  2337  	volBlockInfo, err := attachmentPlan.BlockDeviceInfo()
  2338  	c.Assert(err, gc.IsNil)
  2339  	c.Assert(volBlockInfo, jc.DeepEquals, blockInfo)
  2340  }
  2341  
  2342  func (s *MigrationImportSuite) TestFilesystems(c *gc.C) {
  2343  	machine := s.Factory.MakeMachine(c, &factory.MachineParams{
  2344  		Filesystems: []state.HostFilesystemParams{{
  2345  			Filesystem: state.FilesystemParams{Size: 1234},
  2346  			Attachment: state.FilesystemAttachmentParams{
  2347  				Location: "location",
  2348  				ReadOnly: true},
  2349  		}, {
  2350  			Filesystem: state.FilesystemParams{Size: 4000},
  2351  			Attachment: state.FilesystemAttachmentParams{
  2352  				ReadOnly: true},
  2353  		}},
  2354  	})
  2355  	machineTag := machine.MachineTag()
  2356  
  2357  	// We know that the first filesystem is called "0/0" as it is the first
  2358  	// filesystem (filesystems use sequences), and it is bound to machine 0.
  2359  	fsTag := names.NewFilesystemTag("0/0")
  2360  	fsInfo := state.FilesystemInfo{
  2361  		Size:         1500,
  2362  		Pool:         "rootfs",
  2363  		FilesystemId: "filesystem id",
  2364  	}
  2365  	sb, err := state.NewStorageBackend(s.State)
  2366  	c.Assert(err, jc.ErrorIsNil)
  2367  	err = sb.SetFilesystemInfo(fsTag, fsInfo)
  2368  	c.Assert(err, jc.ErrorIsNil)
  2369  	fsAttachmentInfo := state.FilesystemAttachmentInfo{
  2370  		MountPoint: "/mnt/foo",
  2371  		ReadOnly:   true,
  2372  	}
  2373  	err = sb.SetFilesystemAttachmentInfo(machineTag, fsTag, fsAttachmentInfo)
  2374  	c.Assert(err, jc.ErrorIsNil)
  2375  
  2376  	_, newSt := s.importModel(c, s.State)
  2377  	newSb, err := state.NewStorageBackend(newSt)
  2378  	c.Assert(err, jc.ErrorIsNil)
  2379  
  2380  	filesystem, err := newSb.Filesystem(fsTag)
  2381  	c.Assert(err, jc.ErrorIsNil)
  2382  
  2383  	// TODO: check status
  2384  	// TODO: check storage instance
  2385  	info, err := filesystem.Info()
  2386  	c.Assert(err, jc.ErrorIsNil)
  2387  	c.Check(info, jc.DeepEquals, fsInfo)
  2388  
  2389  	attachment, err := newSb.FilesystemAttachment(machineTag, fsTag)
  2390  	c.Assert(err, jc.ErrorIsNil)
  2391  	attInfo, err := attachment.Info()
  2392  	c.Assert(err, jc.ErrorIsNil)
  2393  	c.Check(attInfo, jc.DeepEquals, fsAttachmentInfo)
  2394  
  2395  	fsTag = names.NewFilesystemTag("0/1")
  2396  	filesystem, err = newSb.Filesystem(fsTag)
  2397  	c.Assert(err, jc.ErrorIsNil)
  2398  
  2399  	params, needsProvisioning := filesystem.Params()
  2400  	c.Check(needsProvisioning, jc.IsTrue)
  2401  	c.Check(params.Pool, gc.Equals, "rootfs")
  2402  	c.Check(params.Size, gc.Equals, uint64(4000))
  2403  
  2404  	attachment, err = newSb.FilesystemAttachment(machineTag, fsTag)
  2405  	c.Assert(err, jc.ErrorIsNil)
  2406  	attParams, needsProvisioning := attachment.Params()
  2407  	c.Check(needsProvisioning, jc.IsTrue)
  2408  	c.Check(attParams.ReadOnly, jc.IsTrue)
  2409  }
  2410  
  2411  func (s *MigrationImportSuite) TestStorage(c *gc.C) {
  2412  	app, u, storageTag := s.makeUnitWithStorage(c)
  2413  	sb, err := state.NewStorageBackend(s.State)
  2414  	c.Assert(err, jc.ErrorIsNil)
  2415  	original, err := sb.StorageInstance(storageTag)
  2416  	c.Assert(err, jc.ErrorIsNil)
  2417  	originalCount := state.StorageAttachmentCount(original)
  2418  	c.Assert(originalCount, gc.Equals, 1)
  2419  	originalAttachments, err := sb.StorageAttachments(storageTag)
  2420  	c.Assert(err, jc.ErrorIsNil)
  2421  	c.Assert(originalAttachments, gc.HasLen, 1)
  2422  	c.Assert(originalAttachments[0].Unit(), gc.Equals, u.UnitTag())
  2423  	appName := app.Name()
  2424  
  2425  	_, newSt := s.importModel(c, s.State)
  2426  
  2427  	app, err = newSt.Application(appName)
  2428  	c.Assert(err, jc.ErrorIsNil)
  2429  	cons, err := app.StorageConstraints()
  2430  	c.Assert(err, jc.ErrorIsNil)
  2431  	c.Check(cons, jc.DeepEquals, map[string]state.StorageConstraints{
  2432  		"data":    {Pool: "modelscoped", Size: 0x400, Count: 1},
  2433  		"allecto": {Pool: "loop", Size: 0x400},
  2434  	})
  2435  
  2436  	newSb, err := state.NewStorageBackend(newSt)
  2437  	c.Assert(err, jc.ErrorIsNil)
  2438  
  2439  	testInstance, err := newSb.StorageInstance(storageTag)
  2440  	c.Assert(err, jc.ErrorIsNil)
  2441  
  2442  	c.Check(testInstance.Tag(), gc.Equals, original.Tag())
  2443  	c.Check(testInstance.Kind(), gc.Equals, original.Kind())
  2444  	c.Check(testInstance.Life(), gc.Equals, original.Life())
  2445  	c.Check(testInstance.StorageName(), gc.Equals, original.StorageName())
  2446  	c.Check(testInstance.Pool(), gc.Equals, original.Pool())
  2447  	c.Check(state.StorageAttachmentCount(testInstance), gc.Equals, originalCount)
  2448  
  2449  	attachments, err := newSb.StorageAttachments(storageTag)
  2450  	c.Assert(err, jc.ErrorIsNil)
  2451  	c.Assert(attachments, gc.HasLen, 1)
  2452  	c.Assert(attachments[0].Unit(), gc.Equals, u.UnitTag())
  2453  }
  2454  
  2455  func (s *MigrationImportSuite) TestStorageDetached(c *gc.C) {
  2456  	_, u, storageTag := s.makeUnitWithStorage(c)
  2457  	err := u.Destroy()
  2458  	c.Assert(err, jc.ErrorIsNil)
  2459  	sb, err := state.NewStorageBackend(s.State)
  2460  	c.Assert(err, jc.ErrorIsNil)
  2461  	err = sb.DetachStorage(storageTag, u.UnitTag(), false, dontWait)
  2462  	c.Assert(err, jc.ErrorIsNil)
  2463  	err = u.EnsureDead()
  2464  	c.Assert(err, jc.ErrorIsNil)
  2465  	err = u.Remove()
  2466  	c.Assert(err, jc.ErrorIsNil)
  2467  
  2468  	s.importModel(c, s.State)
  2469  }
  2470  
  2471  func (s *MigrationImportSuite) TestStorageInstanceConstraints(c *gc.C) {
  2472  	_, _, storageTag := s.makeUnitWithStorage(c)
  2473  	_, newSt := s.importModel(c, s.State, func(desc map[string]interface{}) {
  2474  		storages := desc["storages"].(map[interface{}]interface{})
  2475  		for _, item := range storages["storages"].([]interface{}) {
  2476  			testStorage := item.(map[interface{}]interface{})
  2477  			cons := testStorage["constraints"].(map[interface{}]interface{})
  2478  			cons["pool"] = "static"
  2479  		}
  2480  	})
  2481  	newSb, err := state.NewStorageBackend(newSt)
  2482  	c.Assert(err, jc.ErrorIsNil)
  2483  	testInstance, err := newSb.StorageInstance(storageTag)
  2484  	c.Assert(err, jc.ErrorIsNil)
  2485  	c.Check(testInstance.Pool(), gc.Equals, "static")
  2486  }
  2487  
  2488  func (s *MigrationImportSuite) TestStorageInstanceConstraintsFallback(c *gc.C) {
  2489  	_, u, storageTag0 := s.makeUnitWithStorage(c)
  2490  
  2491  	sb, err := state.NewStorageBackend(s.State)
  2492  	c.Assert(err, jc.ErrorIsNil)
  2493  	_, err = sb.AddStorageForUnit(u.UnitTag(), "allecto", state.StorageConstraints{
  2494  		Count: 3,
  2495  		Size:  1234,
  2496  		Pool:  "modelscoped",
  2497  	})
  2498  	c.Assert(err, jc.ErrorIsNil)
  2499  	storageTag1 := names.NewStorageTag("allecto/1")
  2500  	storageTag2 := names.NewStorageTag("allecto/2")
  2501  
  2502  	// We delete the storage instance constraints for each storage
  2503  	// instance. For data/0 and allecto/1 we also delete the volume,
  2504  	// and we delete the application storage constraints for "data".
  2505  	//
  2506  	// We expect:
  2507  	//  - for data/0, to get the defaults (loop, 1G)
  2508  	//  - for allecto/1, to get the application storage constraints
  2509  	//  - for allecto/2, to get the volume pool/size
  2510  
  2511  	_, newSt := s.importModel(c, s.State, func(desc map[string]interface{}) {
  2512  		applications := desc["applications"].(map[interface{}]interface{})
  2513  		volumes := desc["volumes"].(map[interface{}]interface{})
  2514  		storages := desc["storages"].(map[interface{}]interface{})
  2515  		storages["version"] = 2
  2516  
  2517  		app := applications["applications"].([]interface{})[0].(map[interface{}]interface{})
  2518  		sc := app["storage-directives"].(map[interface{}]interface{})
  2519  		delete(sc, "data")
  2520  		sc["allecto"].(map[interface{}]interface{})["pool"] = "modelscoped-block"
  2521  
  2522  		var keepVolumes []interface{}
  2523  		for _, item := range volumes["volumes"].([]interface{}) {
  2524  			volume := item.(map[interface{}]interface{})
  2525  			switch volume["storage-id"] {
  2526  			case storageTag0.Id(), storageTag1.Id():
  2527  			default:
  2528  				keepVolumes = append(keepVolumes, volume)
  2529  			}
  2530  		}
  2531  		volumes["volumes"] = keepVolumes
  2532  
  2533  		for _, item := range storages["storages"].([]interface{}) {
  2534  			testStorage := item.(map[interface{}]interface{})
  2535  			delete(testStorage, "constraints")
  2536  		}
  2537  	})
  2538  
  2539  	newSb, err := state.NewStorageBackend(newSt)
  2540  	c.Assert(err, jc.ErrorIsNil)
  2541  
  2542  	instance0, err := newSb.StorageInstance(storageTag0)
  2543  	c.Assert(err, jc.ErrorIsNil)
  2544  	c.Check(instance0.Pool(), gc.Equals, "loop")
  2545  
  2546  	instance1, err := newSb.StorageInstance(storageTag1)
  2547  	c.Assert(err, jc.ErrorIsNil)
  2548  	c.Check(instance1.Pool(), gc.Equals, "modelscoped-block")
  2549  
  2550  	instance2, err := newSb.StorageInstance(storageTag2)
  2551  	c.Assert(err, jc.ErrorIsNil)
  2552  	c.Check(instance2.Pool(), gc.Equals, "modelscoped")
  2553  }
  2554  
  2555  func (s *MigrationImportSuite) TestStoragePools(c *gc.C) {
  2556  	pm := poolmanager.New(state.NewStateSettings(s.State), provider.CommonStorageProviders())
  2557  	_, err := pm.Create("test-pool", provider.LoopProviderType, map[string]interface{}{
  2558  		"value": 42,
  2559  	})
  2560  	c.Assert(err, jc.ErrorIsNil)
  2561  
  2562  	_, newSt := s.importModel(c, s.State)
  2563  
  2564  	pm = poolmanager.New(state.NewStateSettings(newSt), provider.CommonStorageProviders())
  2565  	pools, err := pm.List()
  2566  	c.Assert(err, jc.ErrorIsNil)
  2567  	c.Assert(pools, gc.HasLen, 1)
  2568  
  2569  	pool := pools[0]
  2570  	c.Assert(pool.Name(), gc.Equals, "test-pool")
  2571  	c.Assert(pool.Provider(), gc.Equals, provider.LoopProviderType)
  2572  	c.Assert(pool.Attrs(), jc.DeepEquals, storage.Attrs{
  2573  		"value": 42,
  2574  	})
  2575  }
  2576  
  2577  func (s *MigrationImportSuite) TestPayloads(c *gc.C) {
  2578  	originalUnit := s.Factory.MakeUnit(c, nil)
  2579  	unitID := originalUnit.UnitTag().Id()
  2580  	up, err := s.State.UnitPayloads(originalUnit)
  2581  	c.Assert(err, jc.ErrorIsNil)
  2582  	original := payloads.Payload{
  2583  		PayloadClass: charm.PayloadClass{
  2584  			Name: "something",
  2585  			Type: "special",
  2586  		},
  2587  		ID:     "42",
  2588  		Status: "running",
  2589  		Labels: []string{"foo", "bar"},
  2590  	}
  2591  	err = up.Track(original)
  2592  	c.Assert(err, jc.ErrorIsNil)
  2593  
  2594  	_, newSt := s.importModel(c, s.State)
  2595  
  2596  	unit, err := newSt.Unit(unitID)
  2597  	c.Assert(err, jc.ErrorIsNil)
  2598  
  2599  	up, err = newSt.UnitPayloads(unit)
  2600  	c.Assert(err, jc.ErrorIsNil)
  2601  
  2602  	result, err := up.List()
  2603  	c.Assert(err, jc.ErrorIsNil)
  2604  	c.Assert(result, gc.HasLen, 1)
  2605  	c.Assert(result[0].Payload, gc.NotNil)
  2606  
  2607  	testPayload := result[0].Payload
  2608  
  2609  	machineID, err := unit.AssignedMachineId()
  2610  	c.Check(err, jc.ErrorIsNil)
  2611  	c.Check(testPayload.Name, gc.Equals, original.Name)
  2612  	c.Check(testPayload.Type, gc.Equals, original.Type)
  2613  	c.Check(testPayload.ID, gc.Equals, original.ID)
  2614  	c.Check(testPayload.Status, gc.Equals, original.Status)
  2615  	c.Check(testPayload.Labels, jc.DeepEquals, original.Labels)
  2616  	c.Check(testPayload.Unit, gc.Equals, unitID)
  2617  	c.Check(testPayload.Machine, gc.Equals, machineID)
  2618  }
  2619  
  2620  func (s *MigrationImportSuite) TestRemoteApplications(c *gc.C) {
  2621  	remoteApp, err := s.State.AddRemoteApplication(state.AddRemoteApplicationParams{
  2622  		Name:        "gravy-rainbow",
  2623  		URL:         "me/model.rainbow",
  2624  		SourceModel: s.Model.ModelTag(),
  2625  		Token:       "charisma",
  2626  		Endpoints: []charm.Relation{{
  2627  			Interface: "mysql",
  2628  			Name:      "db",
  2629  			Role:      charm.RoleProvider,
  2630  			Scope:     charm.ScopeGlobal,
  2631  		}, {
  2632  			Interface: "mysql-root",
  2633  			Name:      "db-admin",
  2634  			Limit:     5,
  2635  			Role:      charm.RoleProvider,
  2636  			Scope:     charm.ScopeGlobal,
  2637  		}, {
  2638  			Interface: "logging",
  2639  			Name:      "logging",
  2640  			Role:      charm.RoleProvider,
  2641  			Scope:     charm.ScopeGlobal,
  2642  		}},
  2643  		Spaces: []*environs.ProviderSpaceInfo{{
  2644  			SpaceInfo: network.SpaceInfo{
  2645  				Name:       "unicorns",
  2646  				ProviderId: "space-provider-id",
  2647  				Subnets: []network.SubnetInfo{{
  2648  					CIDR:              "10.0.1.0/24",
  2649  					ProviderId:        "subnet-provider-id",
  2650  					AvailabilityZones: []string{"eu-west-1"},
  2651  				}},
  2652  			},
  2653  		}},
  2654  	})
  2655  	c.Assert(err, jc.ErrorIsNil)
  2656  	err = remoteApp.SetStatus(status.StatusInfo{Status: status.Active})
  2657  	c.Assert(err, jc.ErrorIsNil)
  2658  
  2659  	service := state.NewExternalControllers(s.State)
  2660  	_, err = service.Save(crossmodel.ControllerInfo{
  2661  		ControllerTag: s.Model.ControllerTag(),
  2662  		Addrs:         []string{"192.168.1.1:8080"},
  2663  		Alias:         "magic",
  2664  		CACert:        "magic-ca-cert",
  2665  	}, s.Model.UUID())
  2666  	c.Assert(err, jc.ErrorIsNil)
  2667  
  2668  	out, err := s.State.Export(map[string]string{})
  2669  	c.Assert(err, jc.ErrorIsNil)
  2670  
  2671  	uuid := utils.MustNewUUID().String()
  2672  	in := newModel(out, uuid, "new")
  2673  
  2674  	_, newSt, err := s.Controller.Import(in)
  2675  	if err == nil {
  2676  		defer newSt.Close()
  2677  	}
  2678  	c.Assert(err, jc.ErrorIsNil)
  2679  	remoteApplications, err := newSt.AllRemoteApplications()
  2680  	c.Assert(err, jc.ErrorIsNil)
  2681  	c.Assert(remoteApplications, gc.HasLen, 1)
  2682  
  2683  	remoteApplication := remoteApplications[0]
  2684  	c.Assert(remoteApplication.Name(), gc.Equals, "gravy-rainbow")
  2685  	c.Assert(remoteApplication.ConsumeVersion(), gc.Equals, 1)
  2686  
  2687  	url, _ := remoteApplication.URL()
  2688  	c.Assert(url, gc.Equals, "me/model.rainbow")
  2689  	c.Assert(remoteApplication.SourceModel(), gc.Equals, s.Model.ModelTag())
  2690  
  2691  	token, err := remoteApplication.Token()
  2692  	c.Assert(err, jc.ErrorIsNil)
  2693  	c.Assert(token, gc.Equals, "charisma")
  2694  
  2695  	s.assertRemoteApplicationEndpoints(c, remoteApp, remoteApplication)
  2696  	s.assertRemoteApplicationSpaces(c, remoteApp, remoteApplication)
  2697  }
  2698  
  2699  func (s *MigrationImportSuite) TestRemoteApplicationsConsumerProxy(c *gc.C) {
  2700  	remoteApp, err := s.State.AddRemoteApplication(state.AddRemoteApplicationParams{
  2701  		Name:            "gravy-rainbow",
  2702  		URL:             "me/model.rainbow",
  2703  		SourceModel:     s.Model.ModelTag(),
  2704  		Token:           "charisma",
  2705  		ConsumeVersion:  2,
  2706  		IsConsumerProxy: true,
  2707  		Endpoints: []charm.Relation{{
  2708  			Interface: "mysql",
  2709  			Name:      "db",
  2710  			Role:      charm.RoleProvider,
  2711  			Scope:     charm.ScopeGlobal,
  2712  		}, {
  2713  			Interface: "mysql-root",
  2714  			Name:      "db-admin",
  2715  			Limit:     5,
  2716  			Role:      charm.RoleProvider,
  2717  			Scope:     charm.ScopeGlobal,
  2718  		}, {
  2719  			Interface: "logging",
  2720  			Name:      "logging",
  2721  			Role:      charm.RoleProvider,
  2722  			Scope:     charm.ScopeGlobal,
  2723  		}},
  2724  		Spaces: []*environs.ProviderSpaceInfo{{
  2725  			SpaceInfo: network.SpaceInfo{
  2726  				Name:       "unicorns",
  2727  				ProviderId: "space-provider-id",
  2728  				Subnets: []network.SubnetInfo{{
  2729  					CIDR:              "10.0.1.0/24",
  2730  					ProviderId:        "subnet-provider-id",
  2731  					AvailabilityZones: []string{"eu-west-1"},
  2732  				}},
  2733  			},
  2734  		}},
  2735  	})
  2736  	c.Assert(err, jc.ErrorIsNil)
  2737  
  2738  	service := state.NewExternalControllers(s.State)
  2739  	_, err = service.Save(crossmodel.ControllerInfo{
  2740  		ControllerTag: s.Model.ControllerTag(),
  2741  		Addrs:         []string{"192.168.1.1:8080"},
  2742  		Alias:         "magic",
  2743  		CACert:        "magic-ca-cert",
  2744  	}, s.Model.UUID())
  2745  	c.Assert(err, jc.ErrorIsNil)
  2746  
  2747  	out, err := s.State.Export(map[string]string{})
  2748  	c.Assert(err, jc.ErrorIsNil)
  2749  
  2750  	uuid := utils.MustNewUUID().String()
  2751  	in := newModel(out, uuid, "new")
  2752  
  2753  	_, newSt, err := s.Controller.Import(in)
  2754  	if err == nil {
  2755  		defer newSt.Close()
  2756  	}
  2757  	c.Assert(err, jc.ErrorIsNil)
  2758  	remoteApplications, err := newSt.AllRemoteApplications()
  2759  	c.Assert(err, jc.ErrorIsNil)
  2760  	c.Assert(remoteApplications, gc.HasLen, 1)
  2761  
  2762  	remoteApplication := remoteApplications[0]
  2763  	c.Assert(remoteApplication.Name(), gc.Equals, "gravy-rainbow")
  2764  	c.Assert(remoteApplication.ConsumeVersion(), gc.Equals, 2)
  2765  
  2766  	url, _ := remoteApplication.URL()
  2767  	c.Assert(url, gc.Equals, "me/model.rainbow")
  2768  	c.Assert(remoteApplication.SourceModel(), gc.Equals, s.Model.ModelTag())
  2769  
  2770  	token, err := remoteApplication.Token()
  2771  	c.Assert(err, jc.ErrorIsNil)
  2772  	c.Assert(token, gc.Equals, "charisma")
  2773  
  2774  	s.assertRemoteApplicationEndpoints(c, remoteApp, remoteApplication)
  2775  	s.assertRemoteApplicationSpaces(c, remoteApp, remoteApplication)
  2776  }
  2777  
  2778  func (s *MigrationImportSuite) assertRemoteApplicationEndpoints(c *gc.C, expected, received *state.RemoteApplication) {
  2779  	receivedEndpoints, err := received.Endpoints()
  2780  	c.Assert(err, jc.ErrorIsNil)
  2781  	c.Assert(receivedEndpoints, gc.HasLen, 3)
  2782  
  2783  	expectedEndpoints, err := expected.Endpoints()
  2784  	c.Assert(err, jc.ErrorIsNil)
  2785  	c.Assert(expectedEndpoints, gc.HasLen, 3)
  2786  
  2787  	for k, expectedEndpoint := range expectedEndpoints {
  2788  		receivedEndpoint := receivedEndpoints[k]
  2789  		c.Assert(receivedEndpoint.Interface, gc.Equals, expectedEndpoint.Interface)
  2790  		c.Assert(receivedEndpoint.Name, gc.Equals, expectedEndpoint.Name)
  2791  	}
  2792  }
  2793  
  2794  func (s *MigrationImportSuite) assertRemoteApplicationSpaces(c *gc.C, expected, received *state.RemoteApplication) {
  2795  	receivedSpaces := received.Spaces()
  2796  	c.Assert(receivedSpaces, gc.HasLen, 1)
  2797  
  2798  	expectedSpaces := expected.Spaces()
  2799  	c.Assert(expectedSpaces, gc.HasLen, 1)
  2800  	for k, expectedSpace := range expectedSpaces {
  2801  		receivedSpace := receivedSpaces[k]
  2802  		c.Assert(receivedSpace.Name, gc.Equals, expectedSpace.Name)
  2803  		c.Assert(receivedSpace.ProviderId, gc.Equals, expectedSpace.ProviderId)
  2804  
  2805  		c.Assert(receivedSpace.Subnets, gc.HasLen, 1)
  2806  		receivedSubnet := receivedSpace.Subnets[0]
  2807  
  2808  		c.Assert(expectedSpace.Subnets, gc.HasLen, 1)
  2809  		expectedSubnet := expectedSpace.Subnets[0]
  2810  
  2811  		c.Assert(receivedSubnet.CIDR, gc.Equals, expectedSubnet.CIDR)
  2812  		c.Assert(receivedSubnet.ProviderId, gc.Equals, expectedSubnet.ProviderId)
  2813  		c.Assert(receivedSubnet.AvailabilityZones, gc.DeepEquals, expectedSubnet.AvailabilityZones)
  2814  	}
  2815  }
  2816  
  2817  func (s *MigrationImportSuite) TestApplicationsWithNilConfigValues(c *gc.C) {
  2818  	application := s.Factory.MakeApplication(c, &factory.ApplicationParams{
  2819  		CharmConfig: map[string]interface{}{
  2820  			"foo": "bar",
  2821  		},
  2822  	})
  2823  	s.primeStatusHistory(c, application, status.Active, 5)
  2824  	// Since above factory method calls newly updated state.AddApplication(...)
  2825  	// which removes config settings with nil value before writing
  2826  	// application into database,
  2827  	// strip config setting values to nil directly to simulate
  2828  	// what could happen to some applications in 2.0 and 2.1.
  2829  	// For more context, see https://bugs.launchpad.net/juju/+bug/1667199
  2830  	settings := state.GetApplicationCharmConfig(s.State, application)
  2831  	settings.Set("foo", nil)
  2832  	_, err := settings.Write()
  2833  	c.Assert(err, jc.ErrorIsNil)
  2834  
  2835  	_, newSt := s.importModel(c, s.State)
  2836  
  2837  	importedApplications, err := newSt.AllApplications()
  2838  	c.Assert(err, jc.ErrorIsNil)
  2839  	c.Assert(importedApplications, gc.HasLen, 1)
  2840  	importedApplication := importedApplications[0]
  2841  
  2842  	// Ensure that during import application settings with nil config values
  2843  	// were stripped and not written into database.
  2844  	importedSettings := state.GetApplicationCharmConfig(newSt, importedApplication)
  2845  	_, importedFound := importedSettings.Get("foo")
  2846  	c.Assert(importedFound, jc.IsFalse)
  2847  }
  2848  
  2849  func (s *MigrationImportSuite) TestOneSubordinateTwoGuvnors(c *gc.C) {
  2850  	// Check that invalid relationscopes aren't created when importing
  2851  	// a subordinate related to 2 principals.
  2852  	wordpress := state.AddTestingApplication(c, s.State, "wordpress", state.AddTestingCharm(c, s.State, "wordpress"))
  2853  	mysql := state.AddTestingApplication(c, s.State, "mysql", state.AddTestingCharm(c, s.State, "mysql"))
  2854  	wordpress0 := s.Factory.MakeUnit(c, &factory.UnitParams{Application: wordpress})
  2855  	mysql0 := s.Factory.MakeUnit(c, &factory.UnitParams{Application: mysql})
  2856  
  2857  	logging := s.AddTestingApplication(c, "logging", s.AddTestingCharm(c, "logging"))
  2858  
  2859  	addSubordinate := func(app *state.Application, unit *state.Unit) string {
  2860  		eps, err := s.State.InferEndpoints(app.Name(), logging.Name())
  2861  		c.Assert(err, jc.ErrorIsNil)
  2862  		rel, err := s.State.AddRelation(eps...)
  2863  		c.Assert(err, jc.ErrorIsNil)
  2864  		pru, err := rel.Unit(unit)
  2865  		c.Assert(err, jc.ErrorIsNil)
  2866  		err = pru.EnterScope(nil)
  2867  		c.Assert(err, jc.ErrorIsNil)
  2868  		// Need to reload the doc to get the subordinates.
  2869  		err = unit.Refresh()
  2870  		c.Assert(err, jc.ErrorIsNil)
  2871  		subordinates := unit.SubordinateNames()
  2872  		c.Assert(subordinates, gc.HasLen, 1)
  2873  		loggingUnit, err := s.State.Unit(subordinates[0])
  2874  		c.Assert(err, jc.ErrorIsNil)
  2875  		sub, err := rel.Unit(loggingUnit)
  2876  		c.Assert(err, jc.ErrorIsNil)
  2877  		err = sub.EnterScope(nil)
  2878  		c.Assert(err, jc.ErrorIsNil)
  2879  		return rel.String()
  2880  	}
  2881  
  2882  	logMysqlKey := addSubordinate(mysql, mysql0)
  2883  	logWpKey := addSubordinate(wordpress, wordpress0)
  2884  
  2885  	units, err := logging.AllUnits()
  2886  	c.Assert(err, jc.ErrorIsNil)
  2887  	c.Assert(units, gc.HasLen, 2)
  2888  
  2889  	for _, unit := range units {
  2890  		app, err := unit.Application()
  2891  		c.Assert(err, jc.ErrorIsNil)
  2892  		agentTools := version.Binary{
  2893  			Number:  jujuversion.Current,
  2894  			Arch:    arch.HostArch(),
  2895  			Release: app.CharmOrigin().Platform.OS,
  2896  		}
  2897  		err = unit.SetAgentVersion(agentTools)
  2898  		c.Assert(err, jc.ErrorIsNil)
  2899  	}
  2900  
  2901  	_, newSt := s.importModel(c, s.State)
  2902  
  2903  	logMysqlRel, err := newSt.KeyRelation(logMysqlKey)
  2904  	c.Assert(err, jc.ErrorIsNil)
  2905  	logWpRel, err := newSt.KeyRelation(logWpKey)
  2906  	c.Assert(err, jc.ErrorIsNil)
  2907  
  2908  	mysqlLogUnit, err := newSt.Unit("logging/0")
  2909  	c.Assert(err, jc.ErrorIsNil)
  2910  	wpLogUnit, err := newSt.Unit("logging/1")
  2911  	c.Assert(err, jc.ErrorIsNil)
  2912  
  2913  	// Sanity checks
  2914  	name, ok := mysqlLogUnit.PrincipalName()
  2915  	c.Assert(ok, jc.IsTrue)
  2916  	c.Assert(name, gc.Equals, "mysql/0")
  2917  
  2918  	name, ok = wpLogUnit.PrincipalName()
  2919  	c.Assert(ok, jc.IsTrue)
  2920  	c.Assert(name, gc.Equals, "wordpress/0")
  2921  
  2922  	checkScope := func(unit *state.Unit, rel *state.Relation, expected bool) {
  2923  		ru, err := rel.Unit(unit)
  2924  		c.Assert(err, jc.ErrorIsNil)
  2925  		// Sanity check
  2926  		valid, err := ru.Valid()
  2927  		c.Assert(err, jc.ErrorIsNil)
  2928  		c.Check(valid, gc.Equals, expected)
  2929  
  2930  		inscope, err := ru.InScope()
  2931  		c.Assert(err, jc.ErrorIsNil)
  2932  		c.Check(inscope, gc.Equals, expected)
  2933  	}
  2934  	// The WP logging unit shouldn't be in scope for the mysql-logging
  2935  	// relation.
  2936  	checkScope(wpLogUnit, logMysqlRel, false)
  2937  	// Similarly, the mysql logging unit shouldn't be in scope for the
  2938  	// wp-logging relation.
  2939  	checkScope(mysqlLogUnit, logWpRel, false)
  2940  
  2941  	// But obviously the units should be in their relations.
  2942  	checkScope(mysqlLogUnit, logMysqlRel, true)
  2943  	checkScope(wpLogUnit, logWpRel, true)
  2944  }
  2945  
  2946  func (s *MigrationImportSuite) TestImportingModelWithBlankType(c *gc.C) {
  2947  	testModel, err := s.State.Export(map[string]string{})
  2948  	c.Assert(err, jc.ErrorIsNil)
  2949  
  2950  	newConfig := testModel.Config()
  2951  	newConfig["uuid"] = "aabbccdd-1234-8765-abcd-0123456789ab"
  2952  	newConfig["name"] = "something-new"
  2953  	noTypeModel := description.NewModel(description.ModelArgs{
  2954  		Type:               "",
  2955  		Owner:              testModel.Owner(),
  2956  		Config:             newConfig,
  2957  		LatestToolsVersion: testModel.LatestToolsVersion(),
  2958  		EnvironVersion:     testModel.EnvironVersion(),
  2959  		Blocks:             testModel.Blocks(),
  2960  		Cloud:              testModel.Cloud(),
  2961  		CloudRegion:        testModel.CloudRegion(),
  2962  	})
  2963  	imported, newSt, err := s.Controller.Import(noTypeModel)
  2964  	c.Assert(err, jc.ErrorIsNil)
  2965  	defer func() { _ = newSt.Close() }()
  2966  
  2967  	c.Assert(imported.Type(), gc.Equals, state.ModelTypeIAAS)
  2968  }
  2969  
  2970  func (s *MigrationImportSuite) TestImportingModelWithDefaultSeriesBefore2935(c *gc.C) {
  2971  	defaultBase, ok := s.testImportingModelWithDefaultSeries(c, version.MustParse("2.7.8"))
  2972  	c.Assert(ok, jc.IsFalse, gc.Commentf("value: %q", defaultBase))
  2973  }
  2974  
  2975  func (s *MigrationImportSuite) TestImportingModelWithDefaultSeriesAfter2935(c *gc.C) {
  2976  	defaultBase, ok := s.testImportingModelWithDefaultSeries(c, version.MustParse("2.9.35"))
  2977  	c.Assert(ok, jc.IsTrue)
  2978  	c.Assert(defaultBase, gc.Equals, "ubuntu@22.04/stable")
  2979  }
  2980  
  2981  func (s *MigrationImportSuite) testImportingModelWithDefaultSeries(c *gc.C, toolsVer version.Number) (string, bool) {
  2982  	testModel, err := s.State.Export(map[string]string{})
  2983  	c.Assert(err, jc.ErrorIsNil)
  2984  
  2985  	newConfig := testModel.Config()
  2986  	newConfig["uuid"] = "aabbccdd-1234-8765-abcd-0123456789ab"
  2987  	newConfig["name"] = "something-new"
  2988  	newConfig["default-series"] = "jammy"
  2989  	newConfig["agent-version"] = toolsVer.String()
  2990  	importModel := description.NewModel(description.ModelArgs{
  2991  		Type:           string(state.ModelTypeIAAS),
  2992  		Owner:          testModel.Owner(),
  2993  		Config:         newConfig,
  2994  		EnvironVersion: testModel.EnvironVersion(),
  2995  		Blocks:         testModel.Blocks(),
  2996  		Cloud:          testModel.Cloud(),
  2997  		CloudRegion:    testModel.CloudRegion(),
  2998  	})
  2999  	imported, newSt, err := s.Controller.Import(importModel)
  3000  	c.Assert(err, jc.ErrorIsNil)
  3001  	defer func() { _ = newSt.Close() }()
  3002  
  3003  	importedCfg, err := imported.Config()
  3004  	c.Assert(err, jc.ErrorIsNil)
  3005  	return importedCfg.DefaultBase()
  3006  }
  3007  
  3008  func (s *MigrationImportSuite) TestImportingRelationApplicationSettings(c *gc.C) {
  3009  	state.AddTestingApplication(c, s.State, "wordpress", state.AddTestingCharm(c, s.State, "wordpress"))
  3010  	state.AddTestingApplication(c, s.State, "mysql", state.AddTestingCharm(c, s.State, "mysql"))
  3011  	eps, err := s.State.InferEndpoints("mysql", "wordpress")
  3012  	c.Assert(err, jc.ErrorIsNil)
  3013  	rel, err := s.State.AddRelation(eps...)
  3014  	c.Assert(err, jc.ErrorIsNil)
  3015  
  3016  	wordpressSettings := map[string]interface{}{
  3017  		"venusian": "superbug",
  3018  	}
  3019  	err = rel.UpdateApplicationSettings("wordpress", &fakeToken{}, wordpressSettings)
  3020  	c.Assert(err, jc.ErrorIsNil)
  3021  	mysqlSettings := map[string]interface{}{
  3022  		"planet b": "perihelion",
  3023  	}
  3024  	err = rel.UpdateApplicationSettings("mysql", &fakeToken{}, mysqlSettings)
  3025  	c.Assert(err, jc.ErrorIsNil)
  3026  
  3027  	_, newSt := s.importModel(c, s.State)
  3028  
  3029  	newWordpress, err := newSt.Application("wordpress")
  3030  	c.Assert(err, jc.ErrorIsNil)
  3031  	c.Assert(state.RelationCount(newWordpress), gc.Equals, 1)
  3032  	rels, err := newWordpress.Relations()
  3033  	c.Assert(err, jc.ErrorIsNil)
  3034  	c.Assert(rels, gc.HasLen, 1)
  3035  
  3036  	newRel := rels[0]
  3037  
  3038  	newWpSettings, err := newRel.ApplicationSettings("wordpress")
  3039  	c.Assert(err, jc.ErrorIsNil)
  3040  	c.Assert(newWpSettings, gc.DeepEquals, wordpressSettings)
  3041  
  3042  	newMysqlSettings, err := newRel.ApplicationSettings("mysql")
  3043  	c.Assert(err, jc.ErrorIsNil)
  3044  	c.Assert(newMysqlSettings, gc.DeepEquals, mysqlSettings)
  3045  }
  3046  
  3047  func (s *MigrationImportSuite) TestApplicationAddLatestCharmChannelTrack(c *gc.C) {
  3048  	st := s.State
  3049  	// Add a application with charm settings, app config, and leadership settings.
  3050  	f := factory.NewFactory(st, s.StatePool)
  3051  
  3052  	// Add a application with charm settings, app config, and leadership settings.
  3053  	testCharm := f.MakeCharmV2(c, &factory.CharmParams{
  3054  		Name: "snappass-test", // it has resources
  3055  	})
  3056  	c.Assert(testCharm.Meta().Resources, gc.HasLen, 3)
  3057  	origin := &state.CharmOrigin{
  3058  		Source:   "charm-hub",
  3059  		Type:     "charm",
  3060  		Revision: &charm.MustParseURL(testCharm.URL()).Revision,
  3061  		Channel: &state.Channel{
  3062  			Risk: "edge",
  3063  		},
  3064  		ID:   "charm-hub-id",
  3065  		Hash: "charmhub-hash",
  3066  		Platform: &state.Platform{
  3067  			Architecture: charm.MustParseURL(testCharm.URL()).Architecture,
  3068  			OS:           "ubuntu",
  3069  			Channel:      "12.10/stable",
  3070  		},
  3071  	}
  3072  	application := f.MakeApplication(c, &factory.ApplicationParams{
  3073  		Charm:       testCharm,
  3074  		CharmOrigin: origin,
  3075  	})
  3076  	allApplications, err := s.State.AllApplications()
  3077  	c.Assert(err, jc.ErrorIsNil)
  3078  	c.Assert(allApplications, gc.HasLen, 1)
  3079  
  3080  	_, newSt := s.importModel(c, s.State)
  3081  	importedApp, err := newSt.Application(application.Name())
  3082  	c.Assert(err, jc.ErrorIsNil)
  3083  	exportedOrigin := application.CharmOrigin()
  3084  	exportedOrigin.Channel.Track = "latest"
  3085  	c.Assert(importedApp.CharmOrigin(), gc.DeepEquals, exportedOrigin, gc.Commentf("obtained %s", pretty.Sprint(importedApp.CharmOrigin())))
  3086  }
  3087  
  3088  func (s *MigrationImportSuite) TestApplicationFillInCharmOriginID(c *gc.C) {
  3089  	st := s.State
  3090  	// Add a application with charm settings, app config, and leadership settings.
  3091  	f := factory.NewFactory(st, s.StatePool)
  3092  
  3093  	// Add a application with charm settings, app config, and leadership settings.
  3094  	testCharm := f.MakeCharmV2(c, &factory.CharmParams{
  3095  		Name: "snappass-test", // it has resources
  3096  	})
  3097  	c.Assert(testCharm.Meta().Resources, gc.HasLen, 3)
  3098  	origin := &state.CharmOrigin{
  3099  		Source:   "charm-hub",
  3100  		Type:     "charm",
  3101  		Revision: &charm.MustParseURL(testCharm.URL()).Revision,
  3102  		Channel: &state.Channel{
  3103  			Risk: "edge",
  3104  		},
  3105  		ID:   "charm-hub-id",
  3106  		Hash: "charmhub-hash",
  3107  		Platform: &state.Platform{
  3108  			Architecture: charm.MustParseURL(testCharm.URL()).Architecture,
  3109  			OS:           "ubuntu",
  3110  			Channel:      "12.10/stable",
  3111  		},
  3112  	}
  3113  	appOne := f.MakeApplication(c, &factory.ApplicationParams{
  3114  		Name:        "one",
  3115  		Charm:       testCharm,
  3116  		CharmOrigin: origin,
  3117  	})
  3118  	originNoID := origin
  3119  	originNoID.ID = ""
  3120  	originNoID.Hash = ""
  3121  	appTwo := f.MakeApplication(c, &factory.ApplicationParams{
  3122  		Name:        "two",
  3123  		Charm:       testCharm,
  3124  		CharmOrigin: origin,
  3125  	})
  3126  	appThree := f.MakeApplication(c, &factory.ApplicationParams{
  3127  		Name:        "three",
  3128  		Charm:       testCharm,
  3129  		CharmOrigin: origin,
  3130  	})
  3131  	allApplications, err := s.State.AllApplications()
  3132  	c.Assert(err, jc.ErrorIsNil)
  3133  	c.Assert(allApplications, gc.HasLen, 3)
  3134  
  3135  	_, newSt := s.importModel(c, s.State)
  3136  	importedAppOne, err := newSt.Application(appOne.Name())
  3137  	c.Assert(err, jc.ErrorIsNil)
  3138  	importedAppTwo, err := newSt.Application(appTwo.Name())
  3139  	c.Assert(err, jc.ErrorIsNil)
  3140  	importedAppThree, err := newSt.Application(appThree.Name())
  3141  	c.Assert(err, jc.ErrorIsNil)
  3142  	obtainedChOrigOne := importedAppOne.CharmOrigin()
  3143  	obtainedChOrigTwo := importedAppTwo.CharmOrigin()
  3144  	obtainedChOrigThree := importedAppThree.CharmOrigin()
  3145  	c.Assert(obtainedChOrigTwo.ID, gc.Equals, obtainedChOrigOne.ID)
  3146  	c.Assert(obtainedChOrigThree.ID, gc.Equals, obtainedChOrigOne.ID)
  3147  }
  3148  
  3149  func (s *MigrationImportSuite) TestSecrets(c *gc.C) {
  3150  	now := time.Now().UTC().Round(time.Second)
  3151  	next := now.Add(time.Minute).Round(time.Second).UTC()
  3152  
  3153  	backendStore := state.NewSecretBackends(s.State)
  3154  	backendID, err := backendStore.CreateSecretBackend(state.CreateSecretBackendParams{
  3155  		Name:                "myvault",
  3156  		BackendType:         "vault",
  3157  		TokenRotateInterval: ptr(666 * time.Second),
  3158  		NextRotateTime:      ptr(next),
  3159  	})
  3160  	c.Assert(err, jc.ErrorIsNil)
  3161  
  3162  	store := state.NewSecrets(s.State)
  3163  	owner := s.Factory.MakeApplication(c, nil)
  3164  	uri := secrets.NewURI()
  3165  	expire := now.Add(2 * time.Hour).Round(time.Second).UTC()
  3166  	p := state.CreateSecretParams{
  3167  		Version: 1,
  3168  		Owner:   owner.Tag(),
  3169  		UpdateSecretParams: state.UpdateSecretParams{
  3170  			LeaderToken:    &fakeToken{},
  3171  			RotatePolicy:   ptr(secrets.RotateDaily),
  3172  			NextRotateTime: ptr(next),
  3173  			Description:    ptr("my secret"),
  3174  			Label:          ptr("foobar"),
  3175  			ExpireTime:     ptr(expire),
  3176  			Params:         nil,
  3177  			Data:           map[string]string{"foo": "bar"},
  3178  		},
  3179  	}
  3180  	md, err := store.CreateSecret(uri, p)
  3181  	c.Assert(err, jc.ErrorIsNil)
  3182  	updateTime := time.Now().UTC().Round(time.Second)
  3183  	md, err = store.UpdateSecret(md.URI, state.UpdateSecretParams{
  3184  		LeaderToken: &fakeToken{},
  3185  		AutoPrune:   ptr(true),
  3186  		ValueRef: &secrets.ValueRef{
  3187  			BackendID:  backendID,
  3188  			RevisionID: "rev-id",
  3189  		},
  3190  	})
  3191  	c.Assert(err, jc.ErrorIsNil)
  3192  
  3193  	err = s.State.GrantSecretAccess(uri, state.SecretAccessParams{
  3194  		LeaderToken: &fakeToken{},
  3195  		Scope:       owner.Tag(),
  3196  		Subject:     owner.Tag(),
  3197  		Role:        secrets.RoleManage,
  3198  	})
  3199  	c.Assert(err, jc.ErrorIsNil)
  3200  
  3201  	consumer := s.Factory.MakeApplication(c, &factory.ApplicationParams{
  3202  		Charm: s.Factory.MakeCharm(c, &factory.CharmParams{
  3203  			Name: "wordpress",
  3204  		}),
  3205  	})
  3206  	err = s.State.SaveSecretConsumer(uri, consumer.Tag(), &secrets.SecretConsumerMetadata{
  3207  		Label:           "consumer label",
  3208  		CurrentRevision: 666,
  3209  	})
  3210  	c.Assert(err, jc.ErrorIsNil)
  3211  
  3212  	_, err = s.State.AddRemoteApplication(state.AddRemoteApplicationParams{
  3213  		Name: "remote-app", SourceModel: s.Model.ModelTag(), IsConsumerProxy: true})
  3214  	c.Assert(err, jc.ErrorIsNil)
  3215  	remoteConsumer := names.NewApplicationTag("remote-app")
  3216  	err = s.State.SaveSecretRemoteConsumer(uri, remoteConsumer, &secrets.SecretConsumerMetadata{
  3217  		CurrentRevision: 667,
  3218  	})
  3219  	c.Assert(err, jc.ErrorIsNil)
  3220  
  3221  	backendRefCount, err := s.State.ReadBackendRefCount(backendID)
  3222  	c.Assert(err, jc.ErrorIsNil)
  3223  	c.Assert(backendRefCount, gc.Equals, 1)
  3224  
  3225  	err = s.Model.UpdateModelConfig(map[string]interface{}{config.SecretBackendKey: "myvault"}, nil)
  3226  	c.Assert(err, jc.ErrorIsNil)
  3227  	mCfg, err := s.Model.ModelConfig()
  3228  	c.Assert(err, jc.ErrorIsNil)
  3229  	c.Assert(mCfg.SecretBackend(), jc.DeepEquals, "myvault")
  3230  
  3231  	newModel, newSt := s.importModel(c, s.State)
  3232  
  3233  	mCfg, err = newModel.ModelConfig()
  3234  	c.Assert(err, jc.ErrorIsNil)
  3235  	c.Assert(mCfg.SecretBackend(), jc.DeepEquals, "myvault")
  3236  
  3237  	backendRefCount, err = s.State.ReadBackendRefCount(backendID)
  3238  	c.Assert(err, jc.ErrorIsNil)
  3239  	c.Assert(backendRefCount, gc.Equals, 2)
  3240  
  3241  	store = state.NewSecrets(newSt)
  3242  	all, err := store.ListSecrets(state.SecretsFilter{})
  3243  	c.Assert(err, jc.ErrorIsNil)
  3244  	c.Assert(all, gc.HasLen, 1)
  3245  	c.Assert(all[0], jc.DeepEquals, md)
  3246  
  3247  	revs, err := store.ListSecretRevisions(md.URI)
  3248  	c.Assert(err, jc.ErrorIsNil)
  3249  	mc := jc.NewMultiChecker()
  3250  	mc.AddExpr(`_.CreateTime`, jc.Almost, jc.ExpectedValue)
  3251  	mc.AddExpr(`_.UpdateTime`, jc.Almost, jc.ExpectedValue)
  3252  	c.Assert(revs, mc, []*secrets.SecretRevisionMetadata{{
  3253  		Revision:   1,
  3254  		ValueRef:   nil,
  3255  		CreateTime: now,
  3256  		UpdateTime: updateTime,
  3257  		ExpireTime: &expire,
  3258  	}, {
  3259  		Revision: 2,
  3260  		ValueRef: &secrets.ValueRef{
  3261  			BackendID:  backendID,
  3262  			RevisionID: "rev-id",
  3263  		},
  3264  		BackendName: ptr("myvault"),
  3265  		CreateTime:  now,
  3266  		UpdateTime:  now,
  3267  	}})
  3268  
  3269  	access, err := newSt.SecretAccess(uri, owner.Tag())
  3270  	c.Assert(err, jc.ErrorIsNil)
  3271  	c.Assert(access, gc.Equals, secrets.RoleManage)
  3272  
  3273  	info, err := newSt.GetSecretConsumer(uri, consumer.Tag())
  3274  	c.Assert(err, jc.ErrorIsNil)
  3275  	c.Assert(info, jc.DeepEquals, &secrets.SecretConsumerMetadata{
  3276  		Label:           "consumer label",
  3277  		CurrentRevision: 666,
  3278  		LatestRevision:  2,
  3279  	})
  3280  
  3281  	info, err = newSt.GetSecretRemoteConsumer(uri, remoteConsumer)
  3282  	c.Assert(err, jc.ErrorIsNil)
  3283  	c.Assert(info, jc.DeepEquals, &secrets.SecretConsumerMetadata{
  3284  		CurrentRevision: 667,
  3285  		LatestRevision:  2,
  3286  	})
  3287  
  3288  	backendRefCount, err = newSt.ReadBackendRefCount(backendID)
  3289  	c.Assert(err, jc.ErrorIsNil)
  3290  	c.Assert(backendRefCount, gc.Equals, 2)
  3291  }
  3292  
  3293  func (s *MigrationImportSuite) TestSecretsEnsureConsumerRevisionInfo(c *gc.C) {
  3294  	store := state.NewSecrets(s.State)
  3295  	owner := s.Factory.MakeApplication(c, nil)
  3296  	uri := secrets.NewURI()
  3297  	p := state.CreateSecretParams{
  3298  		Version: 1,
  3299  		Owner:   owner.Tag(),
  3300  		UpdateSecretParams: state.UpdateSecretParams{
  3301  			LeaderToken:  &fakeToken{},
  3302  			RotatePolicy: ptr(secrets.RotateNever),
  3303  			Data:         map[string]string{"foo": "bar"},
  3304  		},
  3305  	}
  3306  	md, err := store.CreateSecret(uri, p)
  3307  	c.Assert(err, jc.ErrorIsNil)
  3308  
  3309  	consumer := s.Factory.MakeApplication(c, &factory.ApplicationParams{
  3310  		Charm: s.Factory.MakeCharm(c, &factory.CharmParams{
  3311  			Name: "wordpress",
  3312  		}),
  3313  	})
  3314  	err = s.State.SaveSecretConsumer(uri, consumer.Tag(), &secrets.SecretConsumerMetadata{
  3315  		Label:           "consumer label",
  3316  		CurrentRevision: 0,
  3317  		LatestRevision:  0,
  3318  	})
  3319  	c.Assert(err, jc.ErrorIsNil)
  3320  
  3321  	_, newSt := s.importModel(c, s.State)
  3322  
  3323  	store = state.NewSecrets(newSt)
  3324  	all, err := store.ListSecrets(state.SecretsFilter{})
  3325  	c.Assert(err, jc.ErrorIsNil)
  3326  	c.Assert(all, gc.HasLen, 1)
  3327  	c.Assert(all[0], jc.DeepEquals, md)
  3328  
  3329  	info, err := newSt.GetSecretConsumer(uri, consumer.Tag())
  3330  	c.Assert(err, jc.ErrorIsNil)
  3331  	c.Assert(info, jc.DeepEquals, &secrets.SecretConsumerMetadata{
  3332  		Label:           "consumer label",
  3333  		CurrentRevision: 1,
  3334  		LatestRevision:  1,
  3335  	})
  3336  }
  3337  
  3338  func (s *MigrationImportSuite) TestSecretsMissingBackend(c *gc.C) {
  3339  	store := state.NewSecrets(s.State)
  3340  	owner := s.Factory.MakeApplication(c, nil)
  3341  	uri := secrets.NewURI()
  3342  
  3343  	backendStore := state.NewSecretBackends(s.State)
  3344  	_, err := backendStore.CreateSecretBackend(state.CreateSecretBackendParams{
  3345  		ID:          "backend-id",
  3346  		Name:        "foo",
  3347  		BackendType: "vault",
  3348  	})
  3349  	c.Assert(err, jc.ErrorIsNil)
  3350  
  3351  	p := state.CreateSecretParams{
  3352  		Version: 1,
  3353  		Owner:   owner.Tag(),
  3354  		UpdateSecretParams: state.UpdateSecretParams{
  3355  			LeaderToken: &fakeToken{},
  3356  			ValueRef: &secrets.ValueRef{
  3357  				BackendID:  "backend-id",
  3358  				RevisionID: "rev-id",
  3359  			},
  3360  		},
  3361  	}
  3362  	_, err = store.CreateSecret(uri, p)
  3363  	c.Assert(err, jc.ErrorIsNil)
  3364  
  3365  	out, err := s.State.Export(map[string]string{})
  3366  	c.Assert(err, jc.ErrorIsNil)
  3367  
  3368  	err = backendStore.DeleteSecretBackend("foo", true)
  3369  	c.Assert(err, jc.ErrorIsNil)
  3370  
  3371  	uuid := utils.MustNewUUID().String()
  3372  	in := newModel(out, uuid, "new")
  3373  	_, _, err = s.Controller.Import(in)
  3374  	c.Assert(err, gc.ErrorMatches, "secrets: target controller does not have all required secret backends set up")
  3375  }
  3376  
  3377  func (s *MigrationImportSuite) TestDefaultSecretBackend(c *gc.C) {
  3378  	testModel, err := s.State.Export(map[string]string{})
  3379  	c.Assert(err, jc.ErrorIsNil)
  3380  
  3381  	newConfig := testModel.Config()
  3382  	newConfig["uuid"] = "aabbccdd-1234-8765-abcd-0123456789ab"
  3383  	newConfig["name"] = "something-new"
  3384  	delete(newConfig, "secret-backend")
  3385  	importModel := description.NewModel(description.ModelArgs{
  3386  		Type:           string(state.ModelTypeIAAS),
  3387  		Owner:          testModel.Owner(),
  3388  		Config:         newConfig,
  3389  		EnvironVersion: testModel.EnvironVersion(),
  3390  		Blocks:         testModel.Blocks(),
  3391  		Cloud:          testModel.Cloud(),
  3392  		CloudRegion:    testModel.CloudRegion(),
  3393  	})
  3394  	imported, newSt, err := s.Controller.Import(importModel)
  3395  	c.Assert(err, jc.ErrorIsNil)
  3396  	defer func() { _ = newSt.Close() }()
  3397  
  3398  	importedCfg, err := imported.Config()
  3399  	c.Assert(err, jc.ErrorIsNil)
  3400  	c.Assert(importedCfg.SecretBackend(), gc.Equals, "auto")
  3401  }
  3402  
  3403  func (s *MigrationImportSuite) TestApplicationWithProvisioningState(c *gc.C) {
  3404  	caasSt := s.Factory.MakeCAASModel(c, nil)
  3405  	s.AddCleanup(func(_ *gc.C) { caasSt.Close() })
  3406  
  3407  	cons := constraints.MustParse("arch=amd64 mem=8G")
  3408  	platform := &state.Platform{
  3409  		Architecture: arch.DefaultArchitecture,
  3410  		OS:           "ubuntu",
  3411  		Channel:      "20.04",
  3412  	}
  3413  	testCharm, application, _ := s.setupSourceApplications(c, caasSt, cons, platform, false)
  3414  
  3415  	err := application.SetScale(1, 0, true)
  3416  	c.Assert(err, jc.ErrorIsNil)
  3417  	err = application.SetProvisioningState(state.ApplicationProvisioningState{
  3418  		Scaling:     true,
  3419  		ScaleTarget: 1,
  3420  	})
  3421  	c.Assert(err, jc.ErrorIsNil)
  3422  
  3423  	allApplications, err := caasSt.AllApplications()
  3424  	c.Assert(err, jc.ErrorIsNil)
  3425  	c.Assert(allApplications, gc.HasLen, 1)
  3426  
  3427  	_, newSt := s.importModel(c, caasSt)
  3428  	// Manually copy across the charm from the old model
  3429  	// as it's normally done later.
  3430  	f := factory.NewFactory(newSt, s.StatePool)
  3431  	f.MakeCharm(c, &factory.CharmParams{
  3432  		Name:     "starsay", // it has resources
  3433  		Series:   "kubernetes",
  3434  		URL:      testCharm.URL(),
  3435  		Revision: strconv.Itoa(testCharm.Revision()),
  3436  	})
  3437  	importedApplication, err := newSt.Application(application.Name())
  3438  	c.Assert(err, jc.ErrorIsNil)
  3439  
  3440  	c.Assert(importedApplication.ProvisioningState(), jc.DeepEquals, &state.ApplicationProvisioningState{
  3441  		Scaling:     true,
  3442  		ScaleTarget: 1,
  3443  	})
  3444  }
  3445  
  3446  // newModel replaces the uuid and name of the config attributes so we
  3447  // can use all the other data to validate imports. An owner and name of the
  3448  // model are unique together in a controller.
  3449  // Also, optionally overwrite the return value of certain methods
  3450  func newModel(m description.Model, uuid, name string) *mockModel {
  3451  	return &mockModel{Model: m, uuid: uuid, name: name}
  3452  }
  3453  
  3454  type mockModel struct {
  3455  	description.Model
  3456  	uuid    string
  3457  	name    string
  3458  	fwRules []description.FirewallRule
  3459  }
  3460  
  3461  func (m *mockModel) Tag() names.ModelTag {
  3462  	return names.NewModelTag(m.uuid)
  3463  }
  3464  
  3465  func (m *mockModel) Config() map[string]interface{} {
  3466  	c := m.Model.Config()
  3467  	c["uuid"] = m.uuid
  3468  	c["name"] = m.name
  3469  	return c
  3470  }
  3471  
  3472  func (m *mockModel) FirewallRules() []description.FirewallRule {
  3473  	if m.fwRules == nil {
  3474  		return m.Model.FirewallRules()
  3475  	}
  3476  	return m.fwRules
  3477  }
  3478  
  3479  // swapModel will swap the order of the applications appearing in the
  3480  // model.
  3481  type swapModel struct {
  3482  	description.Model
  3483  	c *gc.C
  3484  }
  3485  
  3486  func (m swapModel) Applications() []description.Application {
  3487  	values := m.Model.Applications()
  3488  	m.c.Assert(len(values), gc.Equals, 2)
  3489  	values[0], values[1] = values[1], values[0]
  3490  	return values
  3491  }