github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/common/storagecommon/storage_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package storagecommon_test
     5  
     6  import (
     7  	"path/filepath"
     8  
     9  	"github.com/juju/errors"
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  	"gopkg.in/juju/names.v2"
    13  
    14  	"github.com/juju/juju/apiserver/common/storagecommon"
    15  	apiservertesting "github.com/juju/juju/apiserver/testing"
    16  	"github.com/juju/juju/state"
    17  	statetesting "github.com/juju/juju/state/testing"
    18  	"github.com/juju/juju/storage"
    19  )
    20  
    21  type storageAttachmentInfoSuite struct {
    22  	machineTag        names.MachineTag
    23  	volumeTag         names.VolumeTag
    24  	storageTag        names.StorageTag
    25  	st                *fakeStorage
    26  	storageInstance   *fakeStorageInstance
    27  	storageAttachment *fakeStorageAttachment
    28  	volume            *fakeVolume
    29  	volumeAttachment  *fakeVolumeAttachment
    30  	blockDevices      []state.BlockDeviceInfo
    31  }
    32  
    33  var _ = gc.Suite(&storageAttachmentInfoSuite{})
    34  
    35  func (s *storageAttachmentInfoSuite) SetUpTest(c *gc.C) {
    36  	s.machineTag = names.NewMachineTag("0")
    37  	s.volumeTag = names.NewVolumeTag("0")
    38  	s.storageTag = names.NewStorageTag("osd-devices/0")
    39  	s.storageInstance = &fakeStorageInstance{
    40  		tag:   s.storageTag,
    41  		owner: s.machineTag,
    42  		kind:  state.StorageKindBlock,
    43  	}
    44  	s.storageAttachment = &fakeStorageAttachment{
    45  		storageTag: s.storageTag,
    46  	}
    47  	s.volume = &fakeVolume{
    48  		tag: s.volumeTag,
    49  		info: &state.VolumeInfo{
    50  			VolumeId: "vol-ume",
    51  			Pool:     "radiance",
    52  			Size:     1024,
    53  		},
    54  	}
    55  	s.volumeAttachment = &fakeVolumeAttachment{
    56  		info: &state.VolumeAttachmentInfo{},
    57  	}
    58  	s.blockDevices = []state.BlockDeviceInfo{{
    59  		DeviceName:  "sda",
    60  		DeviceLinks: []string{"/dev/disk/by-id/verbatim"},
    61  		HardwareId:  "whatever",
    62  	}}
    63  	s.st = &fakeStorage{
    64  		storageInstance: func(tag names.StorageTag) (state.StorageInstance, error) {
    65  			return s.storageInstance, nil
    66  		},
    67  		storageInstanceVolume: func(tag names.StorageTag) (state.Volume, error) {
    68  			return s.volume, nil
    69  		},
    70  		volumeAttachment: func(m names.MachineTag, v names.VolumeTag) (state.VolumeAttachment, error) {
    71  			return s.volumeAttachment, nil
    72  		},
    73  		blockDevices: func(m names.MachineTag) ([]state.BlockDeviceInfo, error) {
    74  			return s.blockDevices, nil
    75  		},
    76  	}
    77  }
    78  
    79  func (s *storageAttachmentInfoSuite) TestStorageAttachmentInfoPersistentDeviceName(c *gc.C) {
    80  	s.volumeAttachment.info.DeviceName = "sda"
    81  	info, err := storagecommon.StorageAttachmentInfo(s.st, s.storageAttachment, s.machineTag)
    82  	c.Assert(err, jc.ErrorIsNil)
    83  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "BlockDevices")
    84  	c.Assert(info, jc.DeepEquals, &storage.StorageAttachmentInfo{
    85  		Kind:     storage.StorageKindBlock,
    86  		Location: filepath.FromSlash("/dev/sda"),
    87  	})
    88  }
    89  
    90  func (s *storageAttachmentInfoSuite) TestStorageAttachmentInfoMissingBlockDevice(c *gc.C) {
    91  	// If the block device has not shown up yet,
    92  	// then we should get a NotProvisioned error.
    93  	s.blockDevices = nil
    94  	s.volumeAttachment.info.DeviceName = "sda"
    95  	_, err := storagecommon.StorageAttachmentInfo(s.st, s.storageAttachment, s.machineTag)
    96  	c.Assert(err, jc.Satisfies, errors.IsNotProvisioned)
    97  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "BlockDevices")
    98  }
    99  
   100  func (s *storageAttachmentInfoSuite) TestStorageAttachmentInfoPersistentDeviceLink(c *gc.C) {
   101  	s.volumeAttachment.info.DeviceLink = "/dev/disk/by-id/verbatim"
   102  	info, err := storagecommon.StorageAttachmentInfo(s.st, s.storageAttachment, s.machineTag)
   103  	c.Assert(err, jc.ErrorIsNil)
   104  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "BlockDevices")
   105  	c.Assert(info, jc.DeepEquals, &storage.StorageAttachmentInfo{
   106  		Kind:     storage.StorageKindBlock,
   107  		Location: "/dev/disk/by-id/verbatim",
   108  	})
   109  }
   110  
   111  func (s *storageAttachmentInfoSuite) TestStorageAttachmentInfoPersistentHardwareId(c *gc.C) {
   112  	s.volume.info.HardwareId = "whatever"
   113  	info, err := storagecommon.StorageAttachmentInfo(s.st, s.storageAttachment, s.machineTag)
   114  	c.Assert(err, jc.ErrorIsNil)
   115  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "BlockDevices")
   116  	c.Assert(info, jc.DeepEquals, &storage.StorageAttachmentInfo{
   117  		Kind:     storage.StorageKindBlock,
   118  		Location: filepath.FromSlash("/dev/disk/by-id/whatever"),
   119  	})
   120  }
   121  
   122  func (s *storageAttachmentInfoSuite) TestStorageAttachmentInfoMatchingBlockDevice(c *gc.C) {
   123  	// The bus address alone is not enough to produce a path to the block
   124  	// device; we need to find a published block device with the matching
   125  	// bus address.
   126  	s.volumeAttachment.info.BusAddress = "scsi@1:2.3.4"
   127  	s.blockDevices = []state.BlockDeviceInfo{{
   128  		DeviceName: "sda",
   129  	}, {
   130  		DeviceName: "sdb",
   131  		BusAddress: s.volumeAttachment.info.BusAddress,
   132  	}}
   133  	info, err := storagecommon.StorageAttachmentInfo(s.st, s.storageAttachment, s.machineTag)
   134  	c.Assert(err, jc.ErrorIsNil)
   135  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "BlockDevices")
   136  	c.Assert(info, jc.DeepEquals, &storage.StorageAttachmentInfo{
   137  		Kind:     storage.StorageKindBlock,
   138  		Location: filepath.FromSlash("/dev/sdb"),
   139  	})
   140  }
   141  
   142  func (s *storageAttachmentInfoSuite) TestStorageAttachmentInfoNoBlockDevice(c *gc.C) {
   143  	// Neither the volume nor the volume attachment has enough information
   144  	// to persistently identify the path, so we must enquire about block
   145  	// devices; there are none (yet), so NotProvisioned is returned.
   146  	s.volumeAttachment.info.BusAddress = "scsi@1:2.3.4"
   147  	_, err := storagecommon.StorageAttachmentInfo(s.st, s.storageAttachment, s.machineTag)
   148  	c.Assert(err, jc.Satisfies, errors.IsNotProvisioned)
   149  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "BlockDevices")
   150  }
   151  
   152  type watchStorageAttachmentSuite struct {
   153  	storageTag               names.StorageTag
   154  	machineTag               names.MachineTag
   155  	unitTag                  names.UnitTag
   156  	st                       *fakeStorage
   157  	storageInstance          *fakeStorageInstance
   158  	volume                   *fakeVolume
   159  	volumeAttachmentWatcher  *apiservertesting.FakeNotifyWatcher
   160  	blockDevicesWatcher      *apiservertesting.FakeNotifyWatcher
   161  	storageAttachmentWatcher *apiservertesting.FakeNotifyWatcher
   162  }
   163  
   164  var _ = gc.Suite(&watchStorageAttachmentSuite{})
   165  
   166  func (s *watchStorageAttachmentSuite) SetUpTest(c *gc.C) {
   167  	s.storageTag = names.NewStorageTag("osd-devices/0")
   168  	s.machineTag = names.NewMachineTag("0")
   169  	s.unitTag = names.NewUnitTag("ceph/0")
   170  	s.storageInstance = &fakeStorageInstance{
   171  		tag:   s.storageTag,
   172  		owner: s.machineTag,
   173  		kind:  state.StorageKindBlock,
   174  	}
   175  	s.volume = &fakeVolume{tag: names.NewVolumeTag("0")}
   176  	s.volumeAttachmentWatcher = apiservertesting.NewFakeNotifyWatcher()
   177  	s.blockDevicesWatcher = apiservertesting.NewFakeNotifyWatcher()
   178  	s.storageAttachmentWatcher = apiservertesting.NewFakeNotifyWatcher()
   179  	s.st = &fakeStorage{
   180  		storageInstance: func(tag names.StorageTag) (state.StorageInstance, error) {
   181  			return s.storageInstance, nil
   182  		},
   183  		storageInstanceVolume: func(tag names.StorageTag) (state.Volume, error) {
   184  			return s.volume, nil
   185  		},
   186  		watchVolumeAttachment: func(names.MachineTag, names.VolumeTag) state.NotifyWatcher {
   187  			return s.volumeAttachmentWatcher
   188  		},
   189  		watchBlockDevices: func(names.MachineTag) state.NotifyWatcher {
   190  			return s.blockDevicesWatcher
   191  		},
   192  		watchStorageAttachment: func(names.StorageTag, names.UnitTag) state.NotifyWatcher {
   193  			return s.storageAttachmentWatcher
   194  		},
   195  	}
   196  }
   197  
   198  func (s *watchStorageAttachmentSuite) TestWatchStorageAttachmentVolumeAttachmentChanges(c *gc.C) {
   199  	s.testWatchBlockStorageAttachment(c, func() {
   200  		s.volumeAttachmentWatcher.C <- struct{}{}
   201  	})
   202  }
   203  
   204  func (s *watchStorageAttachmentSuite) TestWatchStorageAttachmentStorageAttachmentChanges(c *gc.C) {
   205  	s.testWatchBlockStorageAttachment(c, func() {
   206  		s.storageAttachmentWatcher.C <- struct{}{}
   207  	})
   208  }
   209  
   210  func (s *watchStorageAttachmentSuite) TestWatchStorageAttachmentBlockDevicesChange(c *gc.C) {
   211  	s.testWatchBlockStorageAttachment(c, func() {
   212  		s.blockDevicesWatcher.C <- struct{}{}
   213  	})
   214  }
   215  
   216  func (s *watchStorageAttachmentSuite) testWatchBlockStorageAttachment(c *gc.C, change func()) {
   217  	s.testWatchStorageAttachment(c, change)
   218  	s.st.CheckCallNames(c,
   219  		"StorageInstance",
   220  		"StorageInstanceVolume",
   221  		"WatchVolumeAttachment",
   222  		"WatchBlockDevices",
   223  		"WatchStorageAttachment",
   224  	)
   225  }
   226  
   227  func (s *watchStorageAttachmentSuite) testWatchStorageAttachment(c *gc.C, change func()) {
   228  	w, err := storagecommon.WatchStorageAttachment(
   229  		s.st,
   230  		s.storageTag,
   231  		s.machineTag,
   232  		s.unitTag,
   233  	)
   234  	c.Assert(err, jc.ErrorIsNil)
   235  	wc := statetesting.NewNotifyWatcherC(c, nopSyncStarter{}, w)
   236  	wc.AssertOneChange()
   237  	change()
   238  	wc.AssertOneChange()
   239  }