github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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  	"github.com/juju/names"
    11  	jc "github.com/juju/testing/checkers"
    12  	gc "gopkg.in/check.v1"
    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.volumeAttachmentWatcher.C <- struct{}{}
   178  	s.blockDevicesWatcher = apiservertesting.NewFakeNotifyWatcher()
   179  	s.blockDevicesWatcher.C <- struct{}{}
   180  	s.storageAttachmentWatcher = apiservertesting.NewFakeNotifyWatcher()
   181  	s.storageAttachmentWatcher.C <- struct{}{}
   182  	s.st = &fakeStorage{
   183  		storageInstance: func(tag names.StorageTag) (state.StorageInstance, error) {
   184  			return s.storageInstance, nil
   185  		},
   186  		storageInstanceVolume: func(tag names.StorageTag) (state.Volume, error) {
   187  			return s.volume, nil
   188  		},
   189  		watchVolumeAttachment: func(names.MachineTag, names.VolumeTag) state.NotifyWatcher {
   190  			return s.volumeAttachmentWatcher
   191  		},
   192  		watchBlockDevices: func(names.MachineTag) state.NotifyWatcher {
   193  			return s.blockDevicesWatcher
   194  		},
   195  		watchStorageAttachment: func(names.StorageTag, names.UnitTag) state.NotifyWatcher {
   196  			return s.storageAttachmentWatcher
   197  		},
   198  	}
   199  }
   200  
   201  func (s *watchStorageAttachmentSuite) TestWatchStorageAttachmentVolumeAttachmentChanges(c *gc.C) {
   202  	s.testWatchBlockStorageAttachment(c, func() {
   203  		s.volumeAttachmentWatcher.C <- struct{}{}
   204  	})
   205  }
   206  
   207  func (s *watchStorageAttachmentSuite) TestWatchStorageAttachmentStorageAttachmentChanges(c *gc.C) {
   208  	s.testWatchBlockStorageAttachment(c, func() {
   209  		s.storageAttachmentWatcher.C <- struct{}{}
   210  	})
   211  }
   212  
   213  func (s *watchStorageAttachmentSuite) TestWatchStorageAttachmentBlockDevicesChange(c *gc.C) {
   214  	s.testWatchBlockStorageAttachment(c, func() {
   215  		s.blockDevicesWatcher.C <- struct{}{}
   216  	})
   217  }
   218  
   219  func (s *watchStorageAttachmentSuite) testWatchBlockStorageAttachment(c *gc.C, change func()) {
   220  	s.testWatchStorageAttachment(c, change)
   221  	s.st.CheckCallNames(c,
   222  		"StorageInstance",
   223  		"StorageInstanceVolume",
   224  		"WatchVolumeAttachment",
   225  		"WatchBlockDevices",
   226  		"WatchStorageAttachment",
   227  	)
   228  }
   229  
   230  func (s *watchStorageAttachmentSuite) testWatchStorageAttachment(c *gc.C, change func()) {
   231  	w, err := storagecommon.WatchStorageAttachment(
   232  		s.st,
   233  		s.storageTag,
   234  		s.machineTag,
   235  		s.unitTag,
   236  	)
   237  	c.Assert(err, jc.ErrorIsNil)
   238  	wc := statetesting.NewNotifyWatcherC(c, nopSyncStarter{}, w)
   239  	wc.AssertOneChange()
   240  	change()
   241  	wc.AssertOneChange()
   242  }