github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/state/storage_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  	jc "github.com/juju/testing/checkers"
     8  	"github.com/juju/utils/featureflag"
     9  	gc "gopkg.in/check.v1"
    10  
    11  	"github.com/juju/juju/juju/osenv"
    12  	"github.com/juju/juju/state"
    13  )
    14  
    15  type StorageStateSuite struct {
    16  	ConnSuite
    17  }
    18  
    19  var _ = gc.Suite(&StorageStateSuite{})
    20  
    21  func (s *StorageStateSuite) SetUpTest(c *gc.C) {
    22  	s.ConnSuite.SetUpTest(c)
    23  
    24  	// This suite is all about storage, so enable the feature by default.
    25  	s.PatchEnvironment(osenv.JujuFeatureFlagEnvKey, "storage")
    26  	featureflag.SetFlagsFromEnvironment(osenv.JujuFeatureFlagEnvKey)
    27  }
    28  
    29  func makeStorageCons(pool string, size, count uint64) state.StorageConstraints {
    30  	return state.StorageConstraints{Pool: pool, Size: size, Count: count}
    31  }
    32  
    33  func (s *StorageStateSuite) TestAddServiceStorageConstraintsWithoutFeature(c *gc.C) {
    34  	// Disable the storage feature, and ensure we can deploy a service from
    35  	// a charm that defines storage, without specifying the storage constraints.
    36  	s.PatchEnvironment(osenv.JujuFeatureFlagEnvKey, "")
    37  	featureflag.SetFlagsFromEnvironment(osenv.JujuFeatureFlagEnvKey)
    38  
    39  	ch := s.AddTestingCharm(c, "storage-block2")
    40  	service, err := s.State.AddService("storage-block2", "user-test-admin@local", ch, nil, nil)
    41  	c.Assert(err, jc.ErrorIsNil)
    42  	storageConstraints, err := service.StorageConstraints()
    43  	c.Assert(err, jc.ErrorIsNil)
    44  	c.Assert(storageConstraints, gc.HasLen, 0)
    45  }
    46  
    47  func (s *StorageStateSuite) TestAddServiceStorageConstraints(c *gc.C) {
    48  	ch := s.AddTestingCharm(c, "storage-block2")
    49  	addService := func(storage map[string]state.StorageConstraints) (*state.Service, error) {
    50  		return s.State.AddService("storage-block2", "user-test-admin@local", ch, nil, storage)
    51  	}
    52  	assertErr := func(storage map[string]state.StorageConstraints, expect string) {
    53  		_, err := addService(storage)
    54  		c.Assert(err, gc.ErrorMatches, expect)
    55  	}
    56  	assertErr(nil, `.*no constraints specified for store.*`)
    57  
    58  	storage := map[string]state.StorageConstraints{
    59  		"multi1to10": makeStorageCons("", 1024, 1),
    60  		"multi2up":   makeStorageCons("", 1024, 1),
    61  	}
    62  	assertErr(storage, `cannot add service "storage-block2": charm "storage-block2" store "multi2up": 2 instances required, 1 specified`)
    63  	storage["multi2up"] = makeStorageCons("", 1024, 2)
    64  	storage["multi1to10"] = makeStorageCons("", 1024, 11)
    65  	assertErr(storage, `cannot add service "storage-block2": charm "storage-block2" store "multi1to10": at most 10 instances supported, 11 specified`)
    66  	storage["multi1to10"] = makeStorageCons("ebs", 1024, 10)
    67  	assertErr(storage, `cannot add service "storage-block2": storage pools are not implemented`)
    68  	storage["multi1to10"] = makeStorageCons("", 1024, 10)
    69  	_, err := addService(storage)
    70  	c.Assert(err, jc.ErrorIsNil)
    71  }
    72  
    73  func (s *StorageStateSuite) TestAddUnit(c *gc.C) {
    74  	// Each unit added to the service will create storage instances
    75  	// to satisfy the service's storage constraints.
    76  	ch := s.AddTestingCharm(c, "storage-block2")
    77  	storage := map[string]state.StorageConstraints{
    78  		"multi1to10": makeStorageCons("", 1024, 1),
    79  		"multi2up":   makeStorageCons("", 1024, 2),
    80  	}
    81  	service := s.AddTestingServiceWithStorage(c, "storage-block2", ch, storage)
    82  	for i := 0; i < 2; i++ {
    83  		u, err := service.AddUnit()
    84  		c.Assert(err, jc.ErrorIsNil)
    85  		storageInstances, err := u.StorageInstances()
    86  		c.Assert(err, jc.ErrorIsNil)
    87  		count := make(map[string]int)
    88  		for _, si := range storageInstances {
    89  			count[si.StorageName()]++
    90  		}
    91  		c.Assert(count, gc.DeepEquals, map[string]int{
    92  			"multi1to10": 1,
    93  			"multi2up":   2,
    94  		})
    95  		c.Assert(storageInstances[0].Kind(), gc.Equals, state.StorageKindBlock)
    96  	}
    97  }
    98  
    99  func (s *StorageStateSuite) TestRemoveUnit(c *gc.C) {
   100  	ch := s.AddTestingCharm(c, "storage-block")
   101  	storage := map[string]state.StorageConstraints{
   102  		"data": makeStorageCons("", 1024, 1),
   103  	}
   104  	service := s.AddTestingServiceWithStorage(c, "storage-block", ch, storage)
   105  	unit, err := service.AddUnit()
   106  	c.Assert(err, jc.ErrorIsNil)
   107  	err = s.State.AssignUnit(unit, state.AssignCleanEmpty)
   108  	c.Assert(err, jc.ErrorIsNil)
   109  
   110  	storageInstances, err := unit.StorageInstances()
   111  	c.Assert(err, jc.ErrorIsNil)
   112  	c.Assert(storageInstances, gc.HasLen, 1)
   113  	c.Assert(unit.StorageInstanceIds(), gc.HasLen, 1)
   114  
   115  	blockDeviceNames := storageInstances[0].BlockDeviceNames()
   116  	c.Assert(blockDeviceNames, gc.HasLen, 1)
   117  	blockDevice, err := s.State.BlockDevice(blockDeviceNames[0])
   118  	c.Assert(err, jc.ErrorIsNil)
   119  	blockDeviceStorageInstance, ok := blockDevice.StorageInstance()
   120  	c.Assert(ok, jc.IsTrue)
   121  	c.Assert(blockDeviceStorageInstance, gc.Equals, unit.StorageInstanceIds()[0])
   122  
   123  	err = unit.EnsureDead()
   124  	c.Assert(err, gc.Equals, state.ErrUnitHasStorageInstances)
   125  
   126  	// TODO(axw) implement storage instance lifecycle. We currently
   127  	// just block the destruction of units while there are storage
   128  	// instances are present. The unit agent should be destroying
   129  	// storage instances when the storage instances are marked as
   130  	// dying.
   131  
   132  	// For now, we can force-destroy machines which will remove
   133  	// storage instances from units.
   134  	err = storageInstances[0].Remove()
   135  	c.Assert(err, jc.ErrorIsNil)
   136  	err = unit.Refresh()
   137  	c.Assert(err, gc.IsNil)
   138  	c.Assert(unit.StorageInstanceIds(), gc.HasLen, 0)
   139  	err = unit.EnsureDead()
   140  	c.Assert(err, jc.ErrorIsNil)
   141  
   142  	// There should not be any references from the block device back to the
   143  	// storage instance anymore.
   144  	blockDevice, err = s.State.BlockDevice(blockDeviceNames[0])
   145  	c.Assert(err, jc.ErrorIsNil)
   146  	_, ok = blockDevice.StorageInstance()
   147  	c.Assert(ok, jc.IsFalse)
   148  }