github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/diskmanager/lsblk_test.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // +build linux
     5  
     6  package diskmanager_test
     7  
     8  import (
     9  	"errors"
    10  	"os"
    11  	"strings"
    12  
    13  	"github.com/juju/testing"
    14  	jc "github.com/juju/testing/checkers"
    15  	gc "gopkg.in/check.v1"
    16  
    17  	"github.com/juju/juju/storage"
    18  	coretesting "github.com/juju/juju/testing"
    19  	"github.com/juju/juju/worker/diskmanager"
    20  )
    21  
    22  var _ = gc.Suite(&ListBlockDevicesSuite{})
    23  
    24  type ListBlockDevicesSuite struct {
    25  	coretesting.BaseSuite
    26  }
    27  
    28  func (s *ListBlockDevicesSuite) SetUpTest(c *gc.C) {
    29  	s.BaseSuite.SetUpTest(c)
    30  	s.PatchValue(diskmanager.BlockDeviceInUse, func(storage.BlockDevice) (bool, error) {
    31  		return false, nil
    32  	})
    33  	testing.PatchExecutable(c, s, "udevadm", `#!/bin/bash --norc`)
    34  }
    35  
    36  func (s *ListBlockDevicesSuite) TestListBlockDevices(c *gc.C) {
    37  	s.PatchValue(diskmanager.BlockDeviceInUse, func(dev storage.BlockDevice) (bool, error) {
    38  		return dev.DeviceName == "sdb", nil
    39  	})
    40  	testing.PatchExecutable(c, s, "lsblk", `#!/bin/bash --norc
    41  cat <<EOF
    42  KNAME="sda" SIZE="240057409536" LABEL="" UUID="" TYPE="disk"
    43  KNAME="sda1" SIZE="254803968" LABEL="" UUID="7a62bd85-a350-4c09-8944-5b99bf2080c6" MOUNTPOINT="/tmp" TYPE="part"
    44  KNAME="sda2" SIZE="1024" LABEL="boot" UUID="" TYPE="part"
    45  KNAME="sdb" SIZE="32017047552" LABEL="" UUID="" TYPE="disk"
    46  KNAME="sdb1" SIZE="32015122432" LABEL="media" UUID="2c1c701d-f2ce-43a4-b345-33e2e39f9503" FSTYPE="ext4" TYPE="part"
    47  KNAME="fd0" SIZE="1024" TYPE="disk" MAJ:MIN="2:0"
    48  KNAME="fd1" SIZE="1024" TYPE="disk" MAJ:MIN="2:1"
    49  EOF`)
    50  
    51  	devices, err := diskmanager.ListBlockDevices()
    52  	c.Assert(err, jc.ErrorIsNil)
    53  	c.Assert(devices, jc.DeepEquals, []storage.BlockDevice{{
    54  		DeviceName: "sda",
    55  		Size:       228936,
    56  	}, {
    57  		DeviceName: "sda1",
    58  		Size:       243,
    59  		UUID:       "7a62bd85-a350-4c09-8944-5b99bf2080c6",
    60  		MountPoint: "/tmp",
    61  	}, {
    62  		DeviceName: "sda2",
    63  		Size:       0, // truncated
    64  		Label:      "boot",
    65  	}, {
    66  		DeviceName: "sdb",
    67  		Size:       30533,
    68  		InUse:      true,
    69  	}, {
    70  		DeviceName:     "sdb1",
    71  		Size:           30532,
    72  		Label:          "media",
    73  		UUID:           "2c1c701d-f2ce-43a4-b345-33e2e39f9503",
    74  		FilesystemType: "ext4",
    75  	}})
    76  }
    77  
    78  func (s *ListBlockDevicesSuite) TestListBlockDevicesWWN(c *gc.C) {
    79  	// If ID_WWN is found, then we should get
    80  	// a WWN value.
    81  	s.testListBlockDevicesExtended(c, `
    82  ID_WWN=foo
    83  `, storage.BlockDevice{WWN: "foo"})
    84  }
    85  
    86  func (s *ListBlockDevicesSuite) TestListBlockDevicesExtendedWWN(c *gc.C) {
    87  	// If ID_WWN_WITH_EXTENSION is found, then we should use that
    88  	// in preference to the ID_WWN value.
    89  	s.testListBlockDevicesExtended(c, `
    90  ID_WWN_WITH_EXTENSION=foobar
    91  ID_WWN=foo
    92  `, storage.BlockDevice{WWN: "foobar"})
    93  }
    94  
    95  func (s *ListBlockDevicesSuite) TestListBlockDevicesBusAddress(c *gc.C) {
    96  	// If ID_BUS is scsi, then we should get a
    97  	// BusAddress value.
    98  	s.testListBlockDevicesExtended(c, `
    99  DEVPATH=/a/b/c/d/1:2:3:4/block/sda
   100  ID_BUS=scsi
   101  `, storage.BlockDevice{BusAddress: "scsi@1:2.3.4"})
   102  }
   103  
   104  func (s *ListBlockDevicesSuite) TestListBlockDevicesHardwareId(c *gc.C) {
   105  	// If ID_BUS and ID_SERIAL are both present, we
   106  	// should get a HardwareId value.
   107  	s.testListBlockDevicesExtended(c, `
   108  ID_BUS=ata
   109  ID_SERIAL=0980978987987
   110  `, storage.BlockDevice{HardwareId: "ata-0980978987987"})
   111  }
   112  
   113  func (s *ListBlockDevicesSuite) TestListBlockDevicesDeviceLinks(c *gc.C) {
   114  	// Values from DEVLINKS should be split by space, and entered into
   115  	// DeviceLinks verbatim.
   116  	s.testListBlockDevicesExtended(c, `
   117  DEVLINKS=/dev/disk/by-id/abc /dev/disk/by-id/def
   118  `, storage.BlockDevice{
   119  		DeviceLinks: []string{"/dev/disk/by-id/abc", "/dev/disk/by-id/def"},
   120  	})
   121  }
   122  
   123  func (s *ListBlockDevicesSuite) TestListBlockDevicesAll(c *gc.C) {
   124  	s.testListBlockDevicesExtended(c, `
   125  DEVPATH=/a/b/c/d/1:2:3:4/block/sda
   126  ID_BUS=scsi
   127  ID_SERIAL=0980978987987
   128  `, storage.BlockDevice{BusAddress: "scsi@1:2.3.4", HardwareId: "scsi-0980978987987"})
   129  }
   130  
   131  func (s *ListBlockDevicesSuite) TestListBlockDevicesUnexpectedDevpathFormat(c *gc.C) {
   132  	// If DEVPATH's format doesn't match what we expect, then we should
   133  	// just not get the BusAddress value.
   134  	s.testListBlockDevicesExtended(c, `
   135  DEVPATH=/a/b/c/d/x:y:z:zy/block/sda
   136  ID_BUS=ata
   137  ID_SERIAL=0980978987987
   138  `, storage.BlockDevice{HardwareId: "ata-0980978987987"})
   139  }
   140  
   141  func (s *ListBlockDevicesSuite) TestListBlockDevicesUnexpectedPropertyFormat(c *gc.C) {
   142  	// If udevadm outputs in an unexpected format, we won't error;
   143  	// we only error if some catastrophic error occurs while reading
   144  	// from the udevadm command's stdout.
   145  	s.testListBlockDevicesExtended(c, "nonsense", storage.BlockDevice{})
   146  }
   147  
   148  func (s *ListBlockDevicesSuite) testListBlockDevicesExtended(
   149  	c *gc.C,
   150  	udevadmInfo string,
   151  	expect storage.BlockDevice,
   152  ) {
   153  	testing.PatchExecutable(c, s, "lsblk", `#!/bin/bash --norc
   154  cat <<EOF
   155  KNAME="sda" SIZE="240057409536" LABEL="" UUID="" TYPE="disk"
   156  EOF`)
   157  	testing.PatchExecutable(c, s, "udevadm", `#!/bin/bash --norc
   158  cat <<EOF
   159  `+strings.TrimSpace(udevadmInfo)+`
   160  EOF`)
   161  
   162  	expect.DeviceName = "sda"
   163  	expect.Size = 228936
   164  
   165  	devices, err := diskmanager.ListBlockDevices()
   166  	c.Assert(err, jc.ErrorIsNil)
   167  	c.Assert(devices, jc.DeepEquals, []storage.BlockDevice{expect})
   168  }
   169  
   170  func (s *ListBlockDevicesSuite) TestListBlockDevicesLsblkError(c *gc.C) {
   171  	testing.PatchExecutableThrowError(c, s, "lsblk", 123)
   172  	devices, err := diskmanager.ListBlockDevices()
   173  	c.Assert(err, gc.ErrorMatches, "cannot list block devices: lsblk failed: exit status 123")
   174  	c.Assert(devices, gc.IsNil)
   175  }
   176  
   177  func (s *ListBlockDevicesSuite) TestListBlockDevicesBlockDeviceInUseError(c *gc.C) {
   178  	s.PatchValue(diskmanager.BlockDeviceInUse, func(dev storage.BlockDevice) (bool, error) {
   179  		return false, errors.New("badness")
   180  	})
   181  	testing.PatchExecutable(c, s, "lsblk", `#!/bin/bash --norc
   182  cat <<EOF
   183  KNAME="sda" SIZE="240057409536" LABEL="" UUID="" TYPE="disk"
   184  EOF`)
   185  
   186  	// If the in-use check errors, the block device will be marked "in use"
   187  	// to prevent it from being used, but no error will be returned.
   188  	devices, err := diskmanager.ListBlockDevices()
   189  	c.Assert(err, jc.ErrorIsNil)
   190  	c.Assert(devices, jc.DeepEquals, []storage.BlockDevice{{
   191  		DeviceName: "sda",
   192  		Size:       228936,
   193  		InUse:      true,
   194  	}})
   195  }
   196  
   197  func (s *ListBlockDevicesSuite) TestListBlockDevicesLsblkBadOutput(c *gc.C) {
   198  	// Extra key/value pairs should be ignored; invalid sizes should
   199  	// be logged and ignored (Size will be set to zero).
   200  	testing.PatchExecutable(c, s, "lsblk", `#!/bin/bash --norc
   201  cat <<EOF
   202  KNAME="sda" SIZE="eleventy" LABEL="" UUID="" TYPE="disk"
   203  KNAME="sdb" SIZE="1048576" LABEL="" UUID="" BOB="DOBBS" TYPE="disk"
   204  EOF`)
   205  
   206  	devices, err := diskmanager.ListBlockDevices()
   207  	c.Assert(err, jc.ErrorIsNil)
   208  	c.Assert(devices, jc.DeepEquals, []storage.BlockDevice{{
   209  		DeviceName: "sda",
   210  		Size:       0,
   211  	}, {
   212  		DeviceName: "sdb",
   213  		Size:       1,
   214  	}})
   215  }
   216  
   217  func (s *ListBlockDevicesSuite) TestListBlockDevicesDeviceNotExist(c *gc.C) {
   218  	s.PatchValue(diskmanager.BlockDeviceInUse, func(dev storage.BlockDevice) (bool, error) {
   219  		return false, os.ErrNotExist
   220  	})
   221  	testing.PatchExecutable(c, s, "lsblk", `#!/bin/bash --norc
   222  cat <<EOF
   223  KNAME="sda" SIZE="240057409536" LABEL="" UUID="" TYPE="disk"
   224  KNAME="sdb" SIZE="32017047552" LABEL="" UUID="" TYPE="disk"
   225  EOF`)
   226  
   227  	devices, err := diskmanager.ListBlockDevices()
   228  	c.Assert(err, jc.ErrorIsNil)
   229  	c.Assert(devices, gc.HasLen, 0)
   230  }
   231  
   232  func (s *ListBlockDevicesSuite) TestListBlockDevicesDeviceFiltering(c *gc.C) {
   233  	testing.PatchExecutable(c, s, "lsblk", `#!/bin/bash --norc
   234  cat <<EOF
   235  KNAME="sda" SIZE="240057409536" LABEL="" UUID="" TYPE="disk"
   236  KNAME="sda1" SIZE="254803968" LABEL="" UUID="" TYPE="part"
   237  KNAME="loop0" SIZE="254803968" LABEL="" UUID="" TYPE="loop"
   238  KNAME="sr0" SIZE="254803968" LABEL="" UUID="" TYPE="rom"
   239  KNAME="whatever" SIZE="254803968" LABEL="" UUID="" TYPE="lvm"
   240  EOF`)
   241  
   242  	devices, err := diskmanager.ListBlockDevices()
   243  	c.Assert(err, gc.IsNil)
   244  	c.Assert(devices, jc.DeepEquals, []storage.BlockDevice{{
   245  		DeviceName: "sda",
   246  		Size:       228936,
   247  	}, {
   248  		DeviceName: "sda1",
   249  		Size:       243,
   250  	}, {
   251  		DeviceName: "loop0",
   252  		Size:       243,
   253  	}})
   254  }