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 }