github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/state/blockdevices_test.go (about)

     1  // Copyright 2014 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  	jc "github.com/juju/testing/checkers"
     9  	gc "gopkg.in/check.v1"
    10  	"gopkg.in/mgo.v2/txn"
    11  
    12  	"github.com/juju/juju/state"
    13  	"github.com/juju/juju/state/testing"
    14  )
    15  
    16  type BlockDevicesSuite struct {
    17  	ConnSuite
    18  	machine *state.Machine
    19  }
    20  
    21  var _ = gc.Suite(&BlockDevicesSuite{})
    22  
    23  func (s *BlockDevicesSuite) SetUpTest(c *gc.C) {
    24  	s.ConnSuite.SetUpTest(c)
    25  	var err error
    26  	s.machine, err = s.State.AddMachine("quantal", state.JobHostUnits)
    27  	c.Assert(err, jc.ErrorIsNil)
    28  }
    29  
    30  func (s *BlockDevicesSuite) assertBlockDevices(c *gc.C, m *state.Machine, expected map[string]state.BlockDeviceInfo) {
    31  	devices, err := m.BlockDevices()
    32  	c.Assert(err, jc.ErrorIsNil)
    33  	info := make(map[string]state.BlockDeviceInfo)
    34  	for _, dev := range devices {
    35  		devInfo, err := dev.Info()
    36  		if err != nil {
    37  			c.Assert(err, jc.Satisfies, errors.IsNotProvisioned)
    38  			devInfo = state.BlockDeviceInfo{}
    39  		}
    40  		info[dev.Name()] = devInfo
    41  	}
    42  	c.Assert(info, gc.DeepEquals, expected)
    43  }
    44  
    45  func (s *BlockDevicesSuite) TestSetMachineBlockDevices(c *gc.C) {
    46  	sda := state.BlockDeviceInfo{DeviceName: "sda"}
    47  	err := s.machine.SetMachineBlockDevices(sda)
    48  	c.Assert(err, jc.ErrorIsNil)
    49  	s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{"0": sda})
    50  }
    51  
    52  func (s *BlockDevicesSuite) TestSetMachineBlockDevicesReplaces(c *gc.C) {
    53  	sda := state.BlockDeviceInfo{DeviceName: "sda"}
    54  	err := s.machine.SetMachineBlockDevices(sda)
    55  	c.Assert(err, jc.ErrorIsNil)
    56  
    57  	sdb := state.BlockDeviceInfo{DeviceName: "sdb"}
    58  	err = s.machine.SetMachineBlockDevices(sdb)
    59  	c.Assert(err, jc.ErrorIsNil)
    60  	s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{"1": sdb})
    61  }
    62  
    63  func (s *BlockDevicesSuite) TestSetMachineBlockDevicesUpdates(c *gc.C) {
    64  	sda := state.BlockDeviceInfo{DeviceName: "sda"}
    65  	sdb := state.BlockDeviceInfo{DeviceName: "sdb"}
    66  	err := s.machine.SetMachineBlockDevices(sda, sdb)
    67  	c.Assert(err, jc.ErrorIsNil)
    68  	s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{"0": sda, "1": sdb})
    69  
    70  	sdb.Label = "root"
    71  	err = s.machine.SetMachineBlockDevices(sdb)
    72  	c.Assert(err, jc.ErrorIsNil)
    73  	s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{"1": sdb})
    74  
    75  	// If a device is attached, unattached, then attached again,
    76  	// then it gets a new name.
    77  	sdb.Label = "" // Label should be reset.
    78  	err = s.machine.SetMachineBlockDevices(sda, sdb)
    79  	c.Assert(err, jc.ErrorIsNil)
    80  	s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{
    81  		"2": sda,
    82  		"1": sdb,
    83  	})
    84  }
    85  
    86  func (s *BlockDevicesSuite) TestSetMachineBlockDevicesConcurrently(c *gc.C) {
    87  	sdaInner := state.BlockDeviceInfo{DeviceName: "sda"}
    88  	defer state.SetBeforeHooks(c, s.State, func() {
    89  		err := s.machine.SetMachineBlockDevices(sdaInner)
    90  		c.Assert(err, jc.ErrorIsNil)
    91  	}).Check()
    92  
    93  	sdaOuter := state.BlockDeviceInfo{
    94  		DeviceName: "sda",
    95  		Label:      "root",
    96  	}
    97  	err := s.machine.SetMachineBlockDevices(sdaOuter)
    98  	c.Assert(err, jc.ErrorIsNil)
    99  
   100  	// SetMachineBlockDevices will not remove concurrently added
   101  	// block devices. This is fine in practice, because there is
   102  	// a single worker responsible for populating machine block
   103  	// devices.
   104  	s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{
   105  		"1": sdaInner,
   106  		// The outer call gets 0 because it's called first;
   107  		// the before-hook call is called second but completes
   108  		// first.
   109  		"0": sdaOuter,
   110  	})
   111  }
   112  
   113  func (s *BlockDevicesSuite) TestSetMachineBlockDevicesEmpty(c *gc.C) {
   114  	sda := state.BlockDeviceInfo{DeviceName: "sda"}
   115  	err := s.machine.SetMachineBlockDevices(sda)
   116  	c.Assert(err, jc.ErrorIsNil)
   117  	s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{"0": sda})
   118  
   119  	err = s.machine.SetMachineBlockDevices()
   120  	c.Assert(err, jc.ErrorIsNil)
   121  	s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{})
   122  }
   123  
   124  func (s *BlockDevicesSuite) TestSetMachineBlockDevicesLeavesUnprovisioned(c *gc.C) {
   125  	m, err := s.State.AddOneMachine(state.MachineTemplate{
   126  		Series: "quantal",
   127  		Jobs:   []state.MachineJob{state.JobHostUnits},
   128  		BlockDevices: []state.BlockDeviceParams{
   129  			{Size: 123},
   130  		},
   131  	})
   132  	c.Assert(err, jc.ErrorIsNil)
   133  
   134  	sda := state.BlockDeviceInfo{DeviceName: "sda"}
   135  	err = m.SetMachineBlockDevices(sda)
   136  	c.Assert(err, jc.ErrorIsNil)
   137  	s.assertBlockDevices(c, m, map[string]state.BlockDeviceInfo{
   138  		"0": {}, // unprovisioned
   139  		"1": sda,
   140  	})
   141  }
   142  
   143  func (s *BlockDevicesSuite) TestSetMachineBlockDevicesUpdatesProvisioned(c *gc.C) {
   144  	m, err := s.State.AddOneMachine(state.MachineTemplate{
   145  		Series: "quantal",
   146  		Jobs:   []state.MachineJob{state.JobHostUnits},
   147  		BlockDevices: []state.BlockDeviceParams{
   148  			{Size: 123},
   149  		},
   150  	})
   151  	c.Assert(err, jc.ErrorIsNil)
   152  
   153  	sda := state.BlockDeviceInfo{
   154  		DeviceName: "sda", Size: 123,
   155  	}
   156  	err = state.SetProvisionedBlockDeviceInfo(s.State, m.Id(), map[string]state.BlockDeviceInfo{
   157  		"0": sda,
   158  	})
   159  	c.Assert(err, jc.ErrorIsNil)
   160  	devices, err := m.BlockDevices()
   161  	c.Assert(err, jc.ErrorIsNil)
   162  	c.Assert(devices[0].Attached(), jc.IsFalse)
   163  
   164  	err = m.SetMachineBlockDevices(sda)
   165  	c.Assert(err, jc.ErrorIsNil)
   166  	s.assertBlockDevices(c, m, map[string]state.BlockDeviceInfo{
   167  		"0": sda,
   168  	})
   169  	devices, err = m.BlockDevices()
   170  	c.Assert(err, jc.ErrorIsNil)
   171  	c.Assert(devices[0].Attached(), jc.IsTrue)
   172  }
   173  
   174  func (s *BlockDevicesSuite) TestBlockDevicesMachineRemove(c *gc.C) {
   175  	sda := state.BlockDeviceInfo{DeviceName: "sda"}
   176  	err := s.machine.SetMachineBlockDevices(sda)
   177  	c.Assert(err, jc.ErrorIsNil)
   178  
   179  	err = s.machine.EnsureDead()
   180  	c.Assert(err, jc.ErrorIsNil)
   181  	err = s.machine.Remove()
   182  	c.Assert(err, jc.ErrorIsNil)
   183  
   184  	s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{})
   185  }
   186  
   187  func (s *BlockDevicesSuite) TestBlockDeviceInfo(c *gc.C) {
   188  	sdaInfo := state.BlockDeviceInfo{DeviceName: "sda"}
   189  	err := state.RunTransaction(s.State, []txn.Op{{
   190  		C:      state.BlockDevicesC,
   191  		Id:     "0",
   192  		Insert: &state.BlockDeviceDoc{Name: "0"},
   193  	}, {
   194  		C:      state.BlockDevicesC,
   195  		Id:     "1",
   196  		Insert: &state.BlockDeviceDoc{Name: "1", Info: &sdaInfo},
   197  	}})
   198  	c.Assert(err, jc.ErrorIsNil)
   199  
   200  	b0, err := s.State.BlockDevice("0")
   201  	c.Assert(err, jc.ErrorIsNil)
   202  	_, err = b0.Info()
   203  	c.Assert(err, jc.Satisfies, errors.IsNotProvisioned)
   204  	b1, err := s.State.BlockDevice("1")
   205  	c.Assert(err, jc.ErrorIsNil)
   206  	info, err := b1.Info()
   207  	c.Assert(err, jc.ErrorIsNil)
   208  	c.Assert(info, gc.DeepEquals, sdaInfo)
   209  }
   210  
   211  func (s *BlockDevicesSuite) TestBlockDeviceParamsMethod(c *gc.C) {
   212  	disk1Params := state.BlockDeviceParams{Size: 123}
   213  	err := state.RunTransaction(s.State, []txn.Op{{
   214  		C:      state.BlockDevicesC,
   215  		Id:     "0",
   216  		Insert: &state.BlockDeviceDoc{Name: "0"},
   217  	}, {
   218  		C:      state.BlockDevicesC,
   219  		Id:     "1",
   220  		Insert: &state.BlockDeviceDoc{Name: "1", Params: &disk1Params},
   221  	}})
   222  	c.Assert(err, jc.ErrorIsNil)
   223  
   224  	b0, err := s.State.BlockDevice("0")
   225  	c.Assert(err, jc.ErrorIsNil)
   226  	_, ok := b0.Params()
   227  	c.Assert(ok, jc.IsFalse)
   228  	b1, err := s.State.BlockDevice("1")
   229  	c.Assert(err, jc.ErrorIsNil)
   230  	params, ok := b1.Params()
   231  	c.Assert(ok, jc.IsTrue)
   232  	c.Assert(params, gc.DeepEquals, disk1Params)
   233  }
   234  
   235  func (s *BlockDevicesSuite) TestMachineWatchBlockDevices(c *gc.C) {
   236  	sda := state.BlockDeviceInfo{DeviceName: "sda"}
   237  	sdb := state.BlockDeviceInfo{DeviceName: "sdb"}
   238  	sdc := state.BlockDeviceInfo{DeviceName: "sdc"}
   239  	err := s.machine.SetMachineBlockDevices(sda, sdb, sdc)
   240  	c.Assert(err, jc.ErrorIsNil)
   241  
   242  	// Start block device watcher.
   243  	w := s.machine.WatchBlockDevices()
   244  	defer testing.AssertStop(c, w)
   245  	wc := testing.NewStringsWatcherC(c, s.State, w)
   246  	assertOneChange := func(names ...string) {
   247  		wc.AssertChangeInSingleEvent(names...)
   248  		wc.AssertNoChange()
   249  	}
   250  	assertOneChange("0", "1", "2")
   251  
   252  	// Setting the same should not trigger the watcher.
   253  	err = s.machine.SetMachineBlockDevices(sdc, sdb, sda)
   254  	c.Assert(err, jc.ErrorIsNil)
   255  	wc.AssertNoChange()
   256  
   257  	// change sdb's label.
   258  	sdb.Label = "fatty"
   259  	err = s.machine.SetMachineBlockDevices(sda, sdb, sdc)
   260  	c.Assert(err, jc.ErrorIsNil)
   261  	assertOneChange("1")
   262  
   263  	// change sda's label and sdb's UUID at once.
   264  	sda.Label = "giggly"
   265  	sdb.UUID = "4c062658-6225-4f4b-96f3-debf00b964b4"
   266  	err = s.machine.SetMachineBlockDevices(sda, sdb, sdc)
   267  	c.Assert(err, jc.ErrorIsNil)
   268  	assertOneChange("0", "1")
   269  
   270  	// drop sdc.
   271  	err = s.machine.SetMachineBlockDevices(sda, sdb)
   272  	c.Assert(err, jc.ErrorIsNil)
   273  	assertOneChange("2")
   274  
   275  	// add sdc again: should get a new name.
   276  	err = s.machine.SetMachineBlockDevices(sda, sdb, sdc)
   277  	c.Assert(err, jc.ErrorIsNil)
   278  	assertOneChange("3")
   279  }