github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/maas/volumes_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package maas
     5  
     6  import (
     7  	"github.com/juju/gomaasapi"
     8  	jc "github.com/juju/testing/checkers"
     9  	gc "gopkg.in/check.v1"
    10  	"gopkg.in/juju/names.v2"
    11  
    12  	"github.com/juju/juju/core/constraints"
    13  	"github.com/juju/juju/core/instance"
    14  	"github.com/juju/juju/environs/context"
    15  	"github.com/juju/juju/storage"
    16  	"github.com/juju/juju/testing"
    17  )
    18  
    19  type volumeSuite struct {
    20  	providerSuite
    21  }
    22  
    23  var _ = gc.Suite(&volumeSuite{})
    24  
    25  func (s *volumeSuite) TestBuildMAASVolumeParametersNoVolumes(c *gc.C) {
    26  	vInfo, err := buildMAASVolumeParameters(nil, constraints.Value{})
    27  	c.Assert(err, jc.ErrorIsNil)
    28  	c.Assert(vInfo, gc.HasLen, 0)
    29  }
    30  
    31  func (s *volumeSuite) TestBuildMAASVolumeParametersJustRootDisk(c *gc.C) {
    32  	var cons constraints.Value
    33  	rootSize := uint64(20000)
    34  	cons.RootDisk = &rootSize
    35  	vInfo, err := buildMAASVolumeParameters(nil, cons)
    36  	c.Assert(err, jc.ErrorIsNil)
    37  	c.Assert(vInfo, jc.DeepEquals, []volumeInfo{
    38  		{"root", 20, nil},
    39  	})
    40  }
    41  
    42  func (s *volumeSuite) TestBuildMAASVolumeParametersNoTags(c *gc.C) {
    43  	vInfo, err := buildMAASVolumeParameters([]storage.VolumeParams{
    44  		{Tag: names.NewVolumeTag("1"), Size: 2000000},
    45  	}, constraints.Value{})
    46  	c.Assert(err, jc.ErrorIsNil)
    47  	c.Assert(vInfo, jc.DeepEquals, []volumeInfo{
    48  		{"root", 0, nil}, //root disk
    49  		{"1", 1954, nil},
    50  	})
    51  }
    52  
    53  func (s *volumeSuite) TestBuildMAASVolumeParametersWithRootDisk(c *gc.C) {
    54  	var cons constraints.Value
    55  	rootSize := uint64(20000)
    56  	cons.RootDisk = &rootSize
    57  	vInfo, err := buildMAASVolumeParameters([]storage.VolumeParams{
    58  		{Tag: names.NewVolumeTag("1"), Size: 2000000},
    59  	}, cons)
    60  	c.Assert(err, jc.ErrorIsNil)
    61  	c.Assert(vInfo, jc.DeepEquals, []volumeInfo{
    62  		{"root", 20, nil}, //root disk
    63  		{"1", 1954, nil},
    64  	})
    65  }
    66  
    67  func (s *volumeSuite) TestBuildMAASVolumeParametersWithTags(c *gc.C) {
    68  	vInfo, err := buildMAASVolumeParameters([]storage.VolumeParams{
    69  		{Tag: names.NewVolumeTag("1"), Size: 2000000, Attributes: map[string]interface{}{"tags": "tag1,tag2"}},
    70  	}, constraints.Value{})
    71  	c.Assert(err, jc.ErrorIsNil)
    72  	c.Assert(vInfo, jc.DeepEquals, []volumeInfo{
    73  		{"root", 0, nil}, //root disk
    74  		{"1", 1954, []string{"tag1", "tag2"}},
    75  	})
    76  }
    77  
    78  func (s *volumeSuite) TestInstanceVolumesMAAS2(c *gc.C) {
    79  	instance := maas2Instance{
    80  		machine: &fakeMachine{},
    81  		constraintMatches: gomaasapi.ConstraintMatches{
    82  			Storage: map[string][]gomaasapi.StorageDevice{
    83  				"root": {&fakeBlockDevice{name: "sda", idPath: "/dev/disk/by-dname/sda", size: 250059350016}},
    84  				"1":    {&fakeBlockDevice{name: "sdb", idPath: "/dev/sdb", size: 500059350016}},
    85  				"2":    {&fakeBlockDevice{name: "sdc", idPath: "/dev/disk/by-id/foo", size: 250362438230}},
    86  				"3": {
    87  					&fakeBlockDevice{name: "sdd", idPath: "/dev/disk/by-dname/sdd", size: 250362438230},
    88  					&fakeBlockDevice{name: "sde", idPath: "/dev/disk/by-dname/sde", size: 250362438230},
    89  				},
    90  				"4": {
    91  					&fakeBlockDevice{name: "sdf", idPath: "/dev/disk/by-id/wwn-drbr", size: 280362438231},
    92  				},
    93  				"5": {
    94  					&fakePartition{name: "sde-part1", path: "/dev/disk/by-dname/sde-part1", size: 280362438231},
    95  				},
    96  				"6": {
    97  					&fakeBlockDevice{name: "sdg", idPath: "/dev/disk/by-dname/sdg", size: 280362438231},
    98  				},
    99  			},
   100  		},
   101  	}
   102  	mTag := names.NewMachineTag("1")
   103  	volumes, attachments, err := instance.volumes(mTag, []names.VolumeTag{
   104  		names.NewVolumeTag("1"),
   105  		names.NewVolumeTag("2"),
   106  		names.NewVolumeTag("3"),
   107  		names.NewVolumeTag("4"),
   108  		names.NewVolumeTag("5"),
   109  	})
   110  	c.Assert(err, jc.ErrorIsNil)
   111  	// Expect 4 volumes - root volume is ignored, as are volumes
   112  	// with tags we did not request.
   113  	c.Assert(volumes, gc.HasLen, 5)
   114  	c.Assert(attachments, gc.HasLen, 5)
   115  	c.Check(volumes, jc.SameContents, []storage.Volume{{
   116  		names.NewVolumeTag("1"),
   117  		storage.VolumeInfo{
   118  			VolumeId: "volume-1",
   119  			Size:     476893,
   120  		},
   121  	}, {
   122  		names.NewVolumeTag("2"),
   123  		storage.VolumeInfo{
   124  			VolumeId:   "volume-2",
   125  			Size:       238764,
   126  			HardwareId: "foo",
   127  		},
   128  	}, {
   129  		names.NewVolumeTag("3"),
   130  		storage.VolumeInfo{
   131  			VolumeId: "volume-3",
   132  			Size:     238764,
   133  		},
   134  	}, {
   135  		names.NewVolumeTag("4"),
   136  		storage.VolumeInfo{
   137  			VolumeId: "volume-4",
   138  			Size:     267374,
   139  			WWN:      "drbr",
   140  		},
   141  	}, {
   142  		names.NewVolumeTag("5"),
   143  		storage.VolumeInfo{
   144  			VolumeId: "volume-5",
   145  			Size:     267374,
   146  		},
   147  	}})
   148  	c.Assert(attachments, jc.SameContents, []storage.VolumeAttachment{{
   149  		names.NewVolumeTag("1"),
   150  		mTag,
   151  		storage.VolumeAttachmentInfo{
   152  			DeviceName: "sdb",
   153  		},
   154  	}, {
   155  		names.NewVolumeTag("2"),
   156  		mTag,
   157  		storage.VolumeAttachmentInfo{},
   158  	}, {
   159  		names.NewVolumeTag("3"),
   160  		mTag,
   161  		storage.VolumeAttachmentInfo{
   162  			DeviceLink: "/dev/disk/by-dname/sdd",
   163  		},
   164  	}, {
   165  		names.NewVolumeTag("4"),
   166  		mTag,
   167  		storage.VolumeAttachmentInfo{},
   168  	}, {
   169  		names.NewVolumeTag("5"),
   170  		mTag,
   171  		storage.VolumeAttachmentInfo{
   172  			DeviceLink: "/dev/disk/by-dname/sde-part1",
   173  		},
   174  	}})
   175  }
   176  
   177  func (s *volumeSuite) TestInstanceVolumes(c *gc.C) {
   178  	obj := s.testMAASObject.TestServer.NewNode(validVolumeJson)
   179  	statusGetter := func(context.ProviderCallContext, instance.Id) (string, string) {
   180  		return "unknown", "FAKE"
   181  	}
   182  
   183  	instance := maas1Instance{&obj, nil, statusGetter}
   184  	mTag := names.NewMachineTag("1")
   185  	volumes, attachments, err := instance.volumes(mTag, []names.VolumeTag{
   186  		names.NewVolumeTag("1"),
   187  		names.NewVolumeTag("2"),
   188  	})
   189  	c.Assert(err, jc.ErrorIsNil)
   190  	// Expect 2 volumes - root volume is ignored.
   191  	c.Assert(volumes, gc.HasLen, 2)
   192  	c.Assert(attachments, gc.HasLen, 2)
   193  	c.Check(volumes, jc.DeepEquals, []storage.Volume{
   194  		{
   195  			// This volume has no id_path.
   196  			names.NewVolumeTag("1"),
   197  			storage.VolumeInfo{
   198  				HardwareId: "",
   199  				VolumeId:   "volume-1",
   200  				Size:       476893,
   201  				Persistent: false,
   202  			},
   203  		},
   204  		{
   205  			names.NewVolumeTag("2"),
   206  			storage.VolumeInfo{
   207  				HardwareId: "id_for_sdc",
   208  				VolumeId:   "volume-2",
   209  				Size:       238764,
   210  				Persistent: false,
   211  			},
   212  		},
   213  	})
   214  	c.Assert(attachments, jc.DeepEquals, []storage.VolumeAttachment{
   215  		{
   216  			names.NewVolumeTag("1"),
   217  			mTag,
   218  			storage.VolumeAttachmentInfo{
   219  				DeviceName: "sdb",
   220  				ReadOnly:   false,
   221  			},
   222  		},
   223  		// Device name not set because there's a hardware id in the volume.
   224  		{
   225  			names.NewVolumeTag("2"),
   226  			mTag,
   227  			storage.VolumeAttachmentInfo{
   228  				DeviceName: "",
   229  				ReadOnly:   false,
   230  			},
   231  		},
   232  	})
   233  }
   234  
   235  func (s *volumeSuite) TestInstanceVolumesOldMass(c *gc.C) {
   236  	obj := s.testMAASObject.TestServer.NewNode(`{"system_id": "node0"}`)
   237  	statusGetter := func(context.ProviderCallContext, instance.Id) (string, string) {
   238  		// status, substatus or status info.
   239  		return "provisioning", "substatus"
   240  	}
   241  
   242  	instance := maas1Instance{&obj, nil, statusGetter}
   243  	volumes, attachments, err := instance.volumes(names.NewMachineTag("1"), []names.VolumeTag{
   244  		names.NewVolumeTag("1"),
   245  		names.NewVolumeTag("2"),
   246  	})
   247  	c.Assert(err, jc.ErrorIsNil)
   248  	c.Assert(volumes, gc.HasLen, 0)
   249  	c.Assert(attachments, gc.HasLen, 0)
   250  }
   251  
   252  var validVolumeJson = `
   253  {
   254      "system_id": "node0",
   255      "physicalblockdevice_set": [
   256          {
   257              "name": "sda",
   258              "tags": [
   259                  "ssd",
   260                  "sata"
   261              ],
   262              "id": 1,
   263              "id_path": "/dev/disk/by-id/id_for_sda",
   264              "path": "/dev/sda",
   265              "model": "Samsung_SSD_850_EVO_250GB",
   266              "block_size": 4096,
   267              "serial": "S21NNSAFC38075L",
   268              "size": 250059350016
   269          },
   270          {
   271              "name": "sdb",
   272              "tags": [
   273                  "ssd",
   274                  "sata"
   275              ],
   276              "id": 2,
   277              "path": "/dev/sdb",
   278              "model": "Samsung_SSD_850_EVO_500GB",
   279              "block_size": 4096,
   280              "serial": "S21NNSAFC38076L",
   281              "size": 500059350016
   282          },
   283          {
   284              "name": "sdb",
   285              "tags": [
   286                  "ssd",
   287                  "sata"
   288              ],
   289              "id": 3,
   290              "id_path": "/dev/disk/by-id/id_for_sdc",
   291              "path": "/dev/sdc",
   292              "model": "Samsung_SSD_850_EVO_250GB",
   293              "block_size": 4096,
   294              "serial": "S21NNSAFC38999L",
   295              "size": 250362438230
   296          },
   297          {
   298              "name": "sdd",
   299              "tags": [
   300                  "ssd",
   301                  "sata"
   302              ],
   303              "id": 4,
   304              "id_path": "/dev/disk/by-id/id_for_sdd",
   305              "path": "/dev/sdd",
   306              "model": "Samsung_SSD_850_EVO_250GB",
   307              "block_size": 4096,
   308              "serial": "S21NNSAFC386666L",
   309              "size": 250362438230
   310          },
   311          {
   312              "name": "sde",
   313              "tags": [
   314                  "ssd",
   315                  "sata"
   316              ],
   317              "id": 666,
   318              "id_path": "/dev/disk/by-id/id_for_sde",
   319              "path": "/dev/sde",
   320              "model": "Samsung_SSD_850_EVO_250GB",
   321              "block_size": 4096,
   322              "serial": "S21NNSAFC388888L",
   323  			"size": 250362438230,
   324  			"partitions": [
   325  				{
   326  					"id": 1,
   327  					"name": "sde-part1",
   328  					"path": "/dev/disk/by-dname/sde-part1",
   329  					"size": 280362438231
   330  				}
   331  			]
   332  		}
   333      ],
   334      "constraint_map": {
   335          "1": "root",
   336          "2": "1",
   337          "3": "2",
   338  		"4": "3",
   339  		"5": "partition:1"
   340      }
   341  }
   342  `[1:]
   343  
   344  type storageProviderSuite struct {
   345  	testing.BaseSuite
   346  }
   347  
   348  var _ = gc.Suite(&storageProviderSuite{})
   349  
   350  func (*storageProviderSuite) TestValidateConfigTags(c *gc.C) {
   351  	p := maasStorageProvider{}
   352  	validate := func(tags interface{}) {
   353  		cfg, err := storage.NewConfig("foo", maasStorageProviderType, map[string]interface{}{
   354  			"tags": tags,
   355  		})
   356  		c.Assert(err, jc.ErrorIsNil)
   357  		err = p.ValidateConfig(cfg)
   358  		c.Assert(err, jc.ErrorIsNil)
   359  	}
   360  	validate("singular")
   361  	validate("mul,ti,ple")
   362  	validate(" leading, spaces")
   363  	validate("trailing ,spaces ")
   364  	validate(" and,everything, in ,  between ")
   365  }
   366  
   367  func (*storageProviderSuite) TestValidateConfigInvalidConfig(c *gc.C) {
   368  	p := maasStorageProvider{}
   369  	cfg, err := storage.NewConfig("foo", maasStorageProviderType, map[string]interface{}{
   370  		"tags": "white space",
   371  	})
   372  	c.Assert(err, jc.ErrorIsNil)
   373  	err = p.ValidateConfig(cfg)
   374  	c.Assert(err, gc.ErrorMatches, `tags may not contain whitespace: "white space"`)
   375  }
   376  
   377  func (*storageProviderSuite) TestValidateConfigUnknownAttribute(c *gc.C) {
   378  	p := maasStorageProvider{}
   379  	cfg, err := storage.NewConfig("foo", maasStorageProviderType, map[string]interface{}{
   380  		"unknown": "config",
   381  	})
   382  	c.Assert(err, jc.ErrorIsNil)
   383  	err = p.ValidateConfig(cfg)
   384  	c.Assert(err, jc.ErrorIsNil) // unknown attributes are ignored
   385  }
   386  
   387  func (s *storageProviderSuite) TestSupports(c *gc.C) {
   388  	p := maasStorageProvider{}
   389  	c.Assert(p.Supports(storage.StorageKindBlock), jc.IsTrue)
   390  	c.Assert(p.Supports(storage.StorageKindFilesystem), jc.IsFalse)
   391  }
   392  
   393  func (s *storageProviderSuite) TestScope(c *gc.C) {
   394  	p := maasStorageProvider{}
   395  	c.Assert(p.Scope(), gc.Equals, storage.ScopeEnviron)
   396  }