github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/storage_dynamicadd_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/names"
     9  	jc "github.com/juju/testing/checkers"
    10  	gc "gopkg.in/check.v1"
    11  
    12  	"github.com/juju/juju/state"
    13  )
    14  
    15  type storageAddSuite struct {
    16  	StorageStateSuiteBase
    17  
    18  	unitTag    names.UnitTag
    19  	machineTag names.MachineTag
    20  
    21  	originalStorageCount    int
    22  	originalVolumeCount     int
    23  	originalFilesystemCount int
    24  }
    25  
    26  var _ = gc.Suite(&storageAddSuite{})
    27  
    28  func (s *storageAddSuite) setupMultipleStoragesForAdd(c *gc.C) *state.Unit {
    29  	storageCons := map[string]state.StorageConstraints{
    30  		"multi1to10": makeStorageCons("loop", 0, 3),
    31  	}
    32  	charm := s.AddTestingCharm(c, "storage-block2")
    33  	service, err := s.State.AddService(state.AddServiceArgs{Name: "storage-block2", Owner: "user-test-admin@local", Charm: charm, Storage: storageCons})
    34  	c.Assert(err, jc.ErrorIsNil)
    35  	u, err := service.AddUnit()
    36  	c.Assert(err, jc.ErrorIsNil)
    37  	s.unitTag = u.UnitTag()
    38  	all, err := s.State.AllStorageInstances()
    39  	c.Assert(err, jc.ErrorIsNil)
    40  	s.originalStorageCount = len(all)
    41  	return u
    42  }
    43  
    44  func (s *storageAddSuite) assignUnit(c *gc.C, u *state.Unit) {
    45  	// Assign unit to machine to get volumes and filesystems
    46  	err := s.State.AssignUnit(u, state.AssignCleanEmpty)
    47  	c.Assert(err, jc.ErrorIsNil)
    48  	machineId, err := u.AssignedMachineId()
    49  	c.Assert(err, jc.ErrorIsNil)
    50  
    51  	m, err := s.State.Machine(machineId)
    52  	c.Assert(err, jc.ErrorIsNil)
    53  	s.machineTag = m.MachineTag()
    54  
    55  	volumes, err := s.State.AllVolumes()
    56  	c.Assert(err, jc.ErrorIsNil)
    57  	s.originalVolumeCount = len(volumes)
    58  
    59  	filesystems, err := s.State.MachineFilesystemAttachments(s.machineTag)
    60  	c.Assert(err, jc.ErrorIsNil)
    61  	s.originalFilesystemCount = len(filesystems)
    62  }
    63  
    64  func (s *storageAddSuite) assertStorageCount(c *gc.C, count int) {
    65  	all, err := s.State.AllStorageInstances()
    66  	c.Assert(err, jc.ErrorIsNil)
    67  	c.Assert(all, gc.HasLen, count)
    68  }
    69  
    70  func (s *storageAddSuite) assertVolumeCount(c *gc.C, count int) {
    71  	all, err := s.State.AllVolumes()
    72  	c.Assert(err, jc.ErrorIsNil)
    73  	c.Assert(all, gc.HasLen, count)
    74  }
    75  
    76  func (s *storageAddSuite) assertFileSystemCount(c *gc.C, count int) {
    77  	all, err := s.State.MachineFilesystemAttachments(s.machineTag)
    78  	c.Assert(err, jc.ErrorIsNil)
    79  	c.Assert(all, gc.HasLen, count)
    80  }
    81  
    82  func (s *storageAddSuite) TestAddStorageToUnit(c *gc.C) {
    83  	u := s.setupMultipleStoragesForAdd(c)
    84  	s.assignUnit(c, u)
    85  
    86  	err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 1024, 1))
    87  	c.Assert(err, jc.ErrorIsNil)
    88  	s.assertStorageCount(c, s.originalStorageCount+1)
    89  	s.assertVolumeCount(c, s.originalVolumeCount+1)
    90  	s.assertFileSystemCount(c, s.originalFilesystemCount)
    91  	assertMachineStorageRefs(c, s.State, s.machineTag)
    92  }
    93  
    94  func (s *storageAddSuite) TestAddStorageToUnitNotAssigned(c *gc.C) {
    95  	u := s.setupMultipleStoragesForAdd(c)
    96  	// don't assign unit
    97  
    98  	err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 1024, 1))
    99  	c.Assert(err, jc.ErrorIsNil)
   100  	s.assertStorageCount(c, s.originalStorageCount+1)
   101  	s.assertVolumeCount(c, 0)
   102  	s.assertFileSystemCount(c, 0)
   103  
   104  	s.assignUnit(c, u)
   105  	s.assertVolumeCount(c, 6)
   106  	s.assertFileSystemCount(c, 0)
   107  }
   108  
   109  func (s *storageAddSuite) TestAddStorageWithCount(c *gc.C) {
   110  	u := s.setupMultipleStoragesForAdd(c)
   111  	s.assignUnit(c, u)
   112  	err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 1024, 2))
   113  	c.Assert(err, jc.ErrorIsNil)
   114  	s.assertStorageCount(c, s.originalStorageCount+2)
   115  	s.assertVolumeCount(c, s.originalVolumeCount+2)
   116  	s.assertFileSystemCount(c, s.originalFilesystemCount)
   117  	assertMachineStorageRefs(c, s.State, s.machineTag)
   118  }
   119  
   120  func (s *storageAddSuite) TestAddStorageMultipleCalls(c *gc.C) {
   121  	u := s.setupMultipleStoragesForAdd(c)
   122  	s.assignUnit(c, u)
   123  
   124  	err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 1024, 2))
   125  	c.Assert(err, jc.ErrorIsNil)
   126  	s.assertStorageCount(c, s.originalStorageCount+2)
   127  
   128  	// Should not succeed as the number of storages after
   129  	// this call would be 11 whereas our upper limit is 10 here.
   130  	err = s.State.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 1024, 6))
   131  	c.Assert(err, gc.ErrorMatches, `.*charm "storage-block2" store "multi1to10": at most 10 instances supported, 11 specified.*`)
   132  	s.assertStorageCount(c, s.originalStorageCount+2)
   133  	s.assertVolumeCount(c, s.originalVolumeCount+2)
   134  	s.assertFileSystemCount(c, s.originalFilesystemCount)
   135  	assertMachineStorageRefs(c, s.State, s.machineTag)
   136  }
   137  
   138  func (s *storageAddSuite) TestAddStorageToDyingUnitFails(c *gc.C) {
   139  	s.setupMultipleStoragesForAdd(c)
   140  
   141  	defer state.SetBeforeHooks(c, s.State, func() {
   142  		u, err := s.State.Unit(s.unitTag.Id())
   143  		c.Assert(err, jc.ErrorIsNil)
   144  		err = u.Destroy()
   145  		c.Assert(err, jc.ErrorIsNil)
   146  	}).Check()
   147  
   148  	err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 1024, 1))
   149  	c.Assert(err, gc.ErrorMatches, `adding storage to unit storage-block2/0: unit is not alive`)
   150  
   151  	s.assertStorageCount(c, s.originalStorageCount)
   152  }
   153  
   154  func (s *storageAddSuite) TestAddStorageExceedCount(c *gc.C) {
   155  	_, u, _ := s.setupSingleStorage(c, "block", "loop-pool")
   156  	s.assertStorageCount(c, 1)
   157  
   158  	err := s.State.AddStorageForUnit(u.UnitTag(), "data", makeStorageCons("loop-pool", 1024, 1))
   159  	c.Assert(err, gc.ErrorMatches, `.*charm "storage-block" store "data": at most 1 instances supported, 2 specified.*`)
   160  	s.assertStorageCount(c, 1)
   161  	s.assertVolumeCount(c, 0)
   162  	s.assertFileSystemCount(c, 0)
   163  }
   164  
   165  func (s *storageAddSuite) createAndAssignUnitWithSingleStorage(c *gc.C) names.UnitTag {
   166  	_, u, _ := s.setupSingleStorage(c, "block", "loop-pool")
   167  	s.assertStorageCount(c, 1)
   168  
   169  	// Assign unit to machine to get volumes and filesystems
   170  	err := s.State.AssignUnit(u, state.AssignCleanEmpty)
   171  	c.Assert(err, jc.ErrorIsNil)
   172  
   173  	volumes, err := s.State.AllVolumes()
   174  	c.Assert(err, jc.ErrorIsNil)
   175  	s.originalVolumeCount = len(volumes)
   176  
   177  	filesystems, err := s.State.MachineFilesystemAttachments(s.machineTag)
   178  	c.Assert(err, jc.ErrorIsNil)
   179  	s.originalFilesystemCount = len(filesystems)
   180  
   181  	return u.UnitTag()
   182  }
   183  
   184  func (s *storageAddSuite) TestAddStorageMinCount(c *gc.C) {
   185  	unit := s.createAndAssignUnitWithSingleStorage(c)
   186  	err := s.State.AddStorageForUnit(unit, "allecto", makeStorageCons("loop-pool", 1024, 1))
   187  	c.Assert(err, jc.ErrorIsNil)
   188  	s.assertStorageCount(c, 2)
   189  	s.assertVolumeCount(c, 2)
   190  	s.assertFileSystemCount(c, 0)
   191  	assertMachineStorageRefs(c, s.State, s.machineTag)
   192  }
   193  
   194  func (s *storageAddSuite) TestAddStorageZeroCount(c *gc.C) {
   195  	unit := s.createAndAssignUnitWithSingleStorage(c)
   196  	err := s.State.AddStorageForUnit(unit, "allecto", state.StorageConstraints{Pool: "loop-pool", Size: 1024})
   197  	c.Assert(errors.Cause(err), gc.ErrorMatches, "adding storage where instance count is 0 not valid")
   198  	s.assertStorageCount(c, 1)
   199  	s.assertVolumeCount(c, 1)
   200  	s.assertFileSystemCount(c, 0)
   201  	assertMachineStorageRefs(c, s.State, s.machineTag)
   202  }
   203  
   204  func (s *storageAddSuite) TestAddStorageTriggerDefaultPopulated(c *gc.C) {
   205  	u := s.setupMultipleStoragesForAdd(c)
   206  	s.assignUnit(c, u)
   207  
   208  	err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Count: 1})
   209  	c.Assert(err, jc.ErrorIsNil)
   210  	s.assertStorageCount(c, s.originalStorageCount+1)
   211  	s.assertVolumeCount(c, s.originalVolumeCount+1)
   212  	s.assertFileSystemCount(c, s.originalFilesystemCount)
   213  	assertMachineStorageRefs(c, s.State, s.machineTag)
   214  }
   215  
   216  func (s *storageAddSuite) TestAddStorageDiffPool(c *gc.C) {
   217  	u := s.setupMultipleStoragesForAdd(c)
   218  	s.assignUnit(c, u)
   219  
   220  	err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Pool: "loop-pool", Count: 1})
   221  	c.Assert(err, jc.ErrorIsNil)
   222  	s.assertStorageCount(c, s.originalStorageCount+1)
   223  	s.assertVolumeCount(c, s.originalVolumeCount+1)
   224  	s.assertFileSystemCount(c, s.originalFilesystemCount)
   225  	assertMachineStorageRefs(c, s.State, s.machineTag)
   226  }
   227  
   228  func (s *storageAddSuite) TestAddStorageDiffSize(c *gc.C) {
   229  	u := s.setupMultipleStoragesForAdd(c)
   230  	s.assignUnit(c, u)
   231  
   232  	err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Size: 2048, Count: 1})
   233  	c.Assert(err, jc.ErrorIsNil)
   234  	s.assertStorageCount(c, s.originalStorageCount+1)
   235  	s.assertVolumeCount(c, s.originalVolumeCount+1)
   236  	s.assertFileSystemCount(c, s.originalFilesystemCount)
   237  	assertMachineStorageRefs(c, s.State, s.machineTag)
   238  }
   239  
   240  func (s *storageAddSuite) TestAddStorageLessMinSize(c *gc.C) {
   241  	u := s.setupMultipleStoragesForAdd(c)
   242  	s.assignUnit(c, u)
   243  
   244  	err := s.State.AddStorageForUnit(s.unitTag, "multi2up", state.StorageConstraints{Size: 2, Count: 1})
   245  	c.Assert(err, gc.ErrorMatches, `.*charm "storage-block2" store "multi2up": minimum storage size is 2.0GB, 2.0MB specified.*`)
   246  	s.assertStorageCount(c, s.originalStorageCount)
   247  	s.assertVolumeCount(c, s.originalVolumeCount)
   248  	s.assertFileSystemCount(c, s.originalFilesystemCount)
   249  	assertMachineStorageRefs(c, s.State, s.machineTag)
   250  }
   251  
   252  func (s *storageAddSuite) TestAddStorageWrongName(c *gc.C) {
   253  	u := s.setupMultipleStoragesForAdd(c)
   254  	s.assignUnit(c, u)
   255  
   256  	err := s.State.AddStorageForUnit(s.unitTag, "furball", state.StorageConstraints{Size: 2})
   257  	c.Assert(err, gc.ErrorMatches, `.*charm storage "furball" not found.*`)
   258  	s.assertStorageCount(c, s.originalStorageCount)
   259  	s.assertVolumeCount(c, s.originalVolumeCount)
   260  	s.assertFileSystemCount(c, s.originalFilesystemCount)
   261  }
   262  
   263  func (s *storageAddSuite) TestAddStorageConcurrently(c *gc.C) {
   264  	u := s.setupMultipleStoragesForAdd(c)
   265  	s.assignUnit(c, u)
   266  
   267  	addStorage := func() {
   268  		err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Count: 1})
   269  		c.Assert(err, jc.ErrorIsNil)
   270  	}
   271  	defer state.SetBeforeHooks(c, s.State, addStorage).Check()
   272  	addStorage()
   273  	s.assertStorageCount(c, s.originalStorageCount+2)
   274  	s.assertVolumeCount(c, s.originalVolumeCount+2)
   275  	s.assertFileSystemCount(c, s.originalFilesystemCount)
   276  	assertMachineStorageRefs(c, s.State, s.machineTag)
   277  }
   278  
   279  func (s *storageAddSuite) TestAddStorageConcurrentlyExceedCount(c *gc.C) {
   280  	u := s.setupMultipleStoragesForAdd(c)
   281  	s.assignUnit(c, u)
   282  
   283  	count := 6
   284  	addStorage := func() {
   285  		err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Count: uint64(count)})
   286  		c.Assert(err, jc.ErrorIsNil)
   287  	}
   288  	defer state.SetBeforeHooks(c, s.State, addStorage).Check()
   289  	err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Count: uint64(count)})
   290  	c.Assert(err, gc.ErrorMatches, `.*charm "storage-block2" store "multi1to10": at most 10 instances supported, 15 specified.*`)
   291  
   292  	// Only "count" number of instances should have been added.
   293  	s.assertStorageCount(c, s.originalStorageCount+count)
   294  	s.assertVolumeCount(c, s.originalVolumeCount+count)
   295  	s.assertFileSystemCount(c, s.originalFilesystemCount)
   296  	assertMachineStorageRefs(c, s.State, s.machineTag)
   297  }
   298  
   299  func (s *storageAddSuite) TestAddStorageFilesystem(c *gc.C) {
   300  	_, u, _ := s.setupSingleStorage(c, "filesystem", "loop-pool")
   301  
   302  	// Assign unit to machine to get volumes and filesystems
   303  	err := s.State.AssignUnit(u, state.AssignCleanEmpty)
   304  	c.Assert(err, jc.ErrorIsNil)
   305  	machineId, err := u.AssignedMachineId()
   306  	c.Assert(err, jc.ErrorIsNil)
   307  	s.machineTag = names.NewMachineTag(machineId)
   308  	s.assertFileSystemCount(c, 1)
   309  
   310  	s.assertStorageCount(c, 1)
   311  	s.assertVolumeCount(c, 1)
   312  	s.assertFileSystemCount(c, 1)
   313  
   314  	err = s.State.AddStorageForUnit(u.UnitTag(), "data", makeStorageCons("loop-pool", 1024, 1))
   315  	c.Assert(err, jc.ErrorIsNil)
   316  	s.assertStorageCount(c, 2)
   317  	s.assertVolumeCount(c, 2)
   318  	s.assertFileSystemCount(c, 2)
   319  	assertMachineStorageRefs(c, s.State, s.machineTag)
   320  }
   321  
   322  func (s *storageAddSuite) TestAddStorageStatic(c *gc.C) {
   323  	// Create a unit with static storage; ensure that storage-add
   324  	// fails to add more of this kind of storage.
   325  	_, u, _ := s.setupSingleStorage(c, "filesystem", "static")
   326  	s.assertStorageCount(c, 1)
   327  
   328  	// Assign unit to machine to get volumes and filesystems
   329  	err := s.State.AssignUnit(u, state.AssignCleanEmpty)
   330  	c.Assert(err, jc.ErrorIsNil)
   331  	machineId, err := u.AssignedMachineId()
   332  	c.Assert(err, jc.ErrorIsNil)
   333  	s.machineTag = names.NewMachineTag(machineId)
   334  	s.assertFileSystemCount(c, 1)
   335  
   336  	err = s.State.AddStorageForUnit(
   337  		u.UnitTag(), "data",
   338  		makeStorageCons("static", 1024, 1),
   339  	)
   340  	c.Assert(err, gc.ErrorMatches, "adding storage to unit storage-filesystem/0: "+
   341  		"creating machine storage for storage data/1: "+
   342  		`"static" storage provider does not support dynamic storage`)
   343  	s.assertStorageCount(c, 1)    // no change
   344  	s.assertFileSystemCount(c, 1) // no change
   345  	assertMachineStorageRefs(c, s.State, s.machineTag)
   346  }