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