// Copyright 2019 Yunion // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package baremetal import ( "encoding/json" "reflect" "testing" "github.com/stretchr/testify/assert" "yunion.io/x/jsonutils" "yunion.io/x/log" api "yunion.io/x/onecloud/pkg/apis/compute" ) func TestParseDiskConfig(t *testing.T) { type args struct { desc string } var tAda int = 2 var zAda int = 0 var tStrip64k int64 = 64 var splits40 string = "40%, " var splits100_32 string = "100g,32g," tests := []struct { name string args args wantBdc api.BaremetalDiskConfig wantErr bool }{ { name: "rotate:[1-2,4-5]:MegaRaid", args: args{"rotate:[1-2,4-5]:MegaRaid"}, wantBdc: api.BaremetalDiskConfig{ Type: DISK_TYPE_ROTATE, Conf: DISK_CONF_NONE, Driver: DISK_DRIVER_MEGARAID, Count: 0, Range: []int64{1, 2, 4, 5}, }, wantErr: false, }, { name: "rotate:[1-2,4,6]:raid10:marvelraid", args: args{"rotate:[1-2,4,6]:raid10:marvelraid"}, wantBdc: api.BaremetalDiskConfig{ Type: DISK_TYPE_ROTATE, Conf: DISK_CONF_RAID10, Driver: DISK_DRIVER_MARVELRAID, Count: 0, Range: []int64{1, 2, 4, 6}, }, wantErr: false, }, { name: "rotate:[4,6]:raid10", args: args{"rotate:[4,6]:raid10"}, wantBdc: api.BaremetalDiskConfig{ Type: DISK_TYPE_ROTATE, Conf: DISK_CONF_RAID10, Count: 0, Range: []int64{4, 6}, }, wantErr: false, }, { name: "rotate:[4]:raid10:(40%, )", args: args{"rotate:[4]:raid10:(40%, )"}, wantBdc: api.BaremetalDiskConfig{ Type: DISK_TYPE_ROTATE, Conf: DISK_CONF_RAID10, Count: 0, Splits: splits40, Range: []int64{4}, }, wantErr: false, }, { name: "[12-13]:raid1:(100g,32g,):adapter0:strip64k", args: args{"[12-13]:raid1:(100g,32g,):adapter0:strip64k"}, wantBdc: api.BaremetalDiskConfig{ Type: DISK_TYPE_HYBRID, Conf: DISK_CONF_RAID1, Count: 0, Splits: splits100_32, Adapter: &zAda, Strip: &tStrip64k, Range: []int64{12, 13}, }, wantErr: false, }, { name: "6:raid5:adapter2", args: args{"6:raid5:adapter2"}, wantBdc: api.BaremetalDiskConfig{ Type: DISK_TYPE_HYBRID, Conf: DISK_CONF_RAID5, Count: 6, Adapter: &tAda, }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { gotBdc, err := ParseDiskConfig(tt.args.desc) if (err != nil) != tt.wantErr { t.Errorf("ParseDiskConfig() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(gotBdc, tt.wantBdc) { t.Errorf("ParseDiskConfig() = %v, want %v", gotBdc, tt.wantBdc) } }) } } var ( testStorages = []*BaremetalStorage{ // 0-11 disk on adapter2 { Driver: DISK_DRIVER_MEGARAID, Rotate: true, Size: 2861056, Adapter: 2, }, { Driver: DISK_DRIVER_MEGARAID, Rotate: true, Size: 2861056, Adapter: 2, }, { Driver: DISK_DRIVER_MEGARAID, Rotate: true, Size: 2861056, Adapter: 2, }, { Driver: DISK_DRIVER_MEGARAID, Rotate: true, Size: 2861056, Adapter: 2, }, { Driver: DISK_DRIVER_MEGARAID, Rotate: true, Size: 2861056, Adapter: 2, }, { Driver: DISK_DRIVER_MEGARAID, Rotate: true, Size: 2861056, Adapter: 2, }, { Driver: DISK_DRIVER_MEGARAID, Rotate: true, Size: 2861056, Adapter: 2, }, { Driver: DISK_DRIVER_MEGARAID, Rotate: true, Size: 2861056, Adapter: 2, }, { Driver: DISK_DRIVER_MEGARAID, Rotate: true, Size: 2861056, Adapter: 2, }, { Driver: DISK_DRIVER_MEGARAID, Rotate: true, Size: 2861056, Adapter: 2, }, { Driver: DISK_DRIVER_MEGARAID, Rotate: true, Size: 2861056, Adapter: 2, }, { Driver: DISK_DRIVER_MEGARAID, Rotate: true, Size: 2861056, Adapter: 2, }, // 0-1 disk on adapter0 { Driver: DISK_DRIVER_MEGARAID, Rotate: true, Size: 953344, Adapter: 0, }, { Driver: DISK_DRIVER_MEGARAID, Rotate: true, Size: 953344, Adapter: 0, }, } bitmainStorage = []*BaremetalStorage{ { Driver: DISK_DRIVER_MARVELRAID, Rotate: true, Size: 3814912, Adapter: 0, Enclosure: 252, MaxStripSize: 1024, MinStripSize: 64, Model: "K7GTE9JL HGST HUS726040ALE610 APGNT907", Slot: 0, Status: "online", }, { Driver: DISK_DRIVER_MARVELRAID, Rotate: true, Size: 3814912, Adapter: 0, Enclosure: 252, MaxStripSize: 1024, MinStripSize: 64, Model: "K7GTE9JL HGST HUS726040ALE610 APGNT907", Slot: 1, Status: "online", }, { Driver: DISK_DRIVER_MARVELRAID, Rotate: true, Size: 3814912, Adapter: 0, Enclosure: 252, MaxStripSize: 1024, MinStripSize: 64, Model: "K7GTE9JL HGST HUS726040ALE610 APGNT907", Slot: 2, Status: "online", }, { Driver: DISK_DRIVER_MARVELRAID, Rotate: true, Size: 3814912, Adapter: 0, Enclosure: 252, MaxStripSize: 1024, MinStripSize: 64, Model: "K7GTE9JL HGST HUS726040ALE610 APGNT907", Slot: 3, Status: "online", }, { Driver: DISK_DRIVER_PCIE, Rotate: true, Size: 2200000, Adapter: 0, Enclosure: 252, MaxStripSize: 1024, MinStripSize: 64, Model: "NVME test", Slot: 4, Status: "online", }, { Driver: DISK_DRIVER_PCIE, Rotate: true, Size: 2200000, Adapter: 0, Enclosure: 252, MaxStripSize: 1024, MinStripSize: 64, Model: "NVME test", Slot: 5, Status: "online", }, } ) func TestCalculateLayout(t *testing.T) { confs, err := NewBaremetalDiskConfigs( "[0-1]:raid1:(100g,32g,):adapter0", "6:raid5:adapter2", "6:raid5:adapter2", ) if err != nil { t.Fatalf("NewDiskConfigs err: %v", err) } expectedLayoutJson := ` [ { "disks": [ { "rotate": true, "driver": "MegaRaid", "size": 953344, "index": 0 }, { "rotate": true, "driver": "MegaRaid", "size": 953344, "index": 1 } ], "conf": { "type": "hybrid", "conf": "raid1", "count": 0, "range": [ 0, 1 ], "splits": "100g,32g,", "size": [ 102400, 32768, 818176 ], "adapter": 0, "driver": "" }, "size": 953344 }, { "disks": [ { "adapter": 2, "driver": "MegaRaid", "size": 2861056, "rotate": true, "index": 0 }, { "rotate": true, "adapter": 2, "driver": "MegaRaid", "size": 2861056, "index": 1 }, { "rotate": true, "adapter": 2, "driver": "MegaRaid", "size": 2861056, "index": 2 }, { "rotate": true, "adapter": 2, "driver": "MegaRaid", "size": 2861056, "index": 3 }, { "rotate": true, "adapter": 2, "driver": "MegaRaid", "size": 2861056, "index": 4 }, { "rotate": true, "adapter": 2, "driver": "MegaRaid", "size": 2861056, "index": 5 } ], "conf": { "type": "hybrid", "conf": "raid5", "count": 6, "range": null, "splits": "", "size": null, "adapter": 2, "driver": "" }, "size": 14305280 }, { "disks": [ { "rotate": true, "adapter": 2, "driver": "MegaRaid", "size": 2861056, "index": 6 }, { "rotate": true, "adapter": 2, "driver": "MegaRaid", "size": 2861056, "index": 7 }, { "rotate": true, "adapter": 2, "driver": "MegaRaid", "size": 2861056, "index": 8 }, { "rotate": true, "adapter": 2, "driver": "MegaRaid", "size": 2861056, "index": 9 }, { "rotate": true, "adapter": 2, "driver": "MegaRaid", "size": 2861056, "index": 10 }, { "rotate": true, "adapter": 2, "driver": "MegaRaid", "size": 2861056, "index": 11 } ], "conf": { "type": "hybrid", "conf": "raid5", "count": 6, "range": null, "splits": "", "size": null, "adapter": 2, "driver": "" }, "size": 14305280 } ] ` layout, err := CalculateLayout(confs, testStorages) if err != nil { t.Fatalf("CalculateLayout err: %v", err) } var expectedLayout []Layout err = json.Unmarshal([]byte(expectedLayoutJson), &expectedLayout) if err != nil { t.Fatalf("Unmarshal expectedLayoutJson err: %v", err) } assert := assert.New(t) if !assert.Equal(expectedLayout, layout) { t.Errorf("CalculateLayout() = %v, want %v", layout, expectedLayout) } } func TestCalculateLayout2(t *testing.T) { adapater0 := 0 confs := []*api.BaremetalDiskConfig{ { Adapter: &adapater0, Conf: DISK_CONF_RAID1, Count: 2, Driver: DISK_DRIVER_MEGARAID, Range: []int64{12, 13}, Type: DISK_TYPE_ROTATE, }, { Adapter: &adapater0, Conf: DISK_CONF_RAID10, Count: 12, Driver: DISK_DRIVER_MEGARAID, Range: []int64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, Type: DISK_TYPE_ROTATE, }, { Adapter: &adapater0, Conf: DISK_CONF_NONE, Count: 1, Driver: DISK_DRIVER_PCIE, Range: []int64{0}, Type: DISK_TYPE_SSD, }, } storages := []*BaremetalStorage{} storageJson := `[ { "adapter": 0, "block": 512, "driver": "MegaRaid", "enclousure": 65, "index": 0, "max_strip_size": 0, "min_strip_size": 0, "model": "HGST HUS728T8TAL5200 A9Y2VY1A1JPM", "rotate": true, "sector": 15626993664, "size": 7630368, "slot": 0, "status": "unconfigured_good" }, { "adapter": 0, "block": 512, "driver": "MegaRaid", "enclousure": 65, "index": 0, "max_strip_size": 0, "min_strip_size": 0, "model": "HGST HUS728T8TAL5200 A9Y2VY1AMGGM", "rotate": true, "sector": 15626993664, "size": 7630368, "slot": 1, "status": "unconfigured_good" }, { "adapter": 0, "block": 512, "driver": "MegaRaid", "enclousure": 65, "index": 0, "max_strip_size": 0, "min_strip_size": 0, "model": "HGST HUS728T8TAL5200 A9Y2VY1AN53M", "rotate": true, "sector": 15626993664, "size": 7630368, "slot": 2, "status": "unconfigured_good" }, { "adapter": 0, "block": 512, "driver": "MegaRaid", "enclousure": 65, "index": 0, "max_strip_size": 0, "min_strip_size": 0, "model": "HGST HUS728T8TAL5200 A9Y2VY1ATVBM", "rotate": true, "sector": 15626993664, "size": 7630368, "slot": 3, "status": "unconfigured_good" }, { "adapter": 0, "block": 512, "driver": "MegaRaid", "enclousure": 65, "index": 0, "max_strip_size": 0, "min_strip_size": 0, "model": "HGST HUS728T8TAL5200 A9Y2VY1AR4VM", "rotate": true, "sector": 15626993664, "size": 7630368, "slot": 4, "status": "unconfigured_good" }, { "adapter": 0, "block": 512, "driver": "MegaRaid", "enclousure": 65, "index": 0, "max_strip_size": 0, "min_strip_size": 0, "model": "HGST HUS728T8TAL5200 A9Y2VY1ARYBM", "rotate": true, "sector": 15626993664, "size": 7630368, "slot": 5, "status": "unconfigured_good" }, { "adapter": 0, "block": 512, "driver": "MegaRaid", "enclousure": 65, "index": 0, "max_strip_size": 0, "min_strip_size": 0, "model": "HGST HUS728T8TAL5200 A9Y2VY1AS36M", "rotate": true, "sector": 15626993664, "size": 7630368, "slot": 6, "status": "unconfigured_good" }, { "adapter": 0, "block": 512, "driver": "MegaRaid", "enclousure": 65, "index": 0, "max_strip_size": 0, "min_strip_size": 0, "model": "HGST HUS728T8TAL5200 A9Y2VY1A1K6M", "rotate": true, "sector": 15626993664, "size": 7630368, "slot": 7, "status": "unconfigured_good" }, { "adapter": 0, "block": 512, "driver": "MegaRaid", "enclousure": 65, "index": 0, "max_strip_size": 0, "min_strip_size": 0, "model": "HGST HUS728T8TAL5200 A9Y2VY1AM98M", "rotate": true, "sector": 15626993664, "size": 7630368, "slot": 8, "status": "unconfigured_good" }, { "adapter": 0, "block": 512, "driver": "MegaRaid", "enclousure": 65, "index": 0, "max_strip_size": 0, "min_strip_size": 0, "model": "HGST HUS728T8TAL5200 A9Y2VY1ATTLM", "rotate": true, "sector": 15626993664, "size": 7630368, "slot": 9, "status": "unconfigured_good" }, { "adapter": 0, "block": 512, "driver": "MegaRaid", "enclousure": 65, "index": 0, "max_strip_size": 0, "min_strip_size": 0, "model": "HGST HUS728T8TAL5200 A9Y2VY1AR3DM", "rotate": true, "sector": 15626993664, "size": 7630368, "slot": 10, "status": "unconfigured_good" }, { "adapter": 0, "block": 512, "driver": "MegaRaid", "enclousure": 65, "index": 0, "max_strip_size": 0, "min_strip_size": 0, "model": "HGST HUS728T8TAL5200 A9Y2VY1AN3DM", "rotate": true, "sector": 15626993664, "size": 7630368, "slot": 11, "status": "unconfigured_good" }, { "adapter": 0, "block": 512, "driver": "MegaRaid", "enclousure": 65, "index": 0, "max_strip_size": 0, "min_strip_size": 0, "model": "TOSHIBA AL15SEB060N 310253K0A07BFYVH", "rotate": true, "sector": 1171062784, "size": 571808, "slot": 12, "status": "online" }, { "adapter": 0, "block": 512, "driver": "MegaRaid", "enclousure": 65, "index": 0, "max_strip_size": 0, "min_strip_size": 0, "model": "TOSHIBA AL15SEB060N 310253K0A0EDFYVH", "rotate": true, "sector": 1171062784, "size": 571808, "slot": 13, "status": "online" }, { "adapter": 0, "block": 512, "dev": "nvme0n1", "driver": "", "enclousure": 0, "index": 0, "kernel": "unknown", "max_strip_size": 0, "min_strip_size": 0, "module": "INSPUR-NS8600G2U640", "pci_class": "unknown", "rotate": false, "sector": 12502446768, "size": 6104710, "slot": 0 } ]` storageObj, err := jsonutils.ParseString(storageJson) if err != nil { t.Fatalf("parse json error: %v", err) } if err := storageObj.Unmarshal(&storages); err != nil { t.Fatalf("unmarshal json to storages: %v", err) } layout, err := CalculateLayout(confs, storages) if err != nil { t.Fatalf("calculate layout: %v", err) } log.Infof("layout: %+v", layout) } func TestCheckDisksAllocable(t *testing.T) { confs, err := NewBaremetalDiskConfigs( "[0-1]:raid1:(100g,32g,):adapter0", "6:raid5:adapter2", "6:raid5:adapter2", ) bitmainConfs, err := NewBaremetalDiskConfigs("MarvelRaid:raid10:(60g,)") if err != nil { t.Fatalf("NewDiskConfigs err: %v", err) } layout, err := CalculateLayout(confs, testStorages) defaultLayout, err := CalculateLayout([]*api.BaremetalDiskConfig{&BaremetalDefaultDiskConfig}, testStorages[12:]) if err != nil { t.Fatalf("CalculateLayout err: %v", err) } bitmainLayout, err := CalculateLayout(bitmainConfs, bitmainStorage) if err != nil { t.Fatalf("Calculate bitmain layout err: %v", err) } tdiskDefault := []*api.DiskConfig{ {SizeMb: -1}, {SizeMb: -1}, } tdisk1 := []*api.DiskConfig{ {SizeMb: 960000}, {SizeMb: -1}, {SizeMb: -1}, {SizeMb: -1}, } tdisk2 := []*api.DiskConfig{ {SizeMb: -1}, {SizeMb: -1}, {SizeMb: -1}, {SizeMb: -1}, } tdisk3 := []*api.DiskConfig{ {SizeMb: 102398}, {SizeMb: -1}, {SizeMb: -1}, {SizeMb: -1}, } btdisk1 := []*api.DiskConfig{ {SizeMb: 61438}, {SizeMb: -1}, } btdisk2 := []*api.DiskConfig{ {SizeMb: 61440}, {SizeMb: -1}, } btdisk3 := []*api.DiskConfig{ {SizeMb: -1}, {SizeMb: -1}, } btPcieDisk := []*api.DiskConfig{ {SizeMb: 44440}, {SizeMb: -1}, {SizeMb: -1}, {SizeMb: -1}, {SizeMb: -1}, } type args struct { layouts []Layout disks []*api.DiskConfig } tests := []struct { name string args args want bool extraCount int }{ { name: "default none type config should allocable", args: args{ layouts: defaultLayout, disks: tdiskDefault, }, want: true, extraCount: 0, }, { name: "should not allocable", args: args{ layouts: layout, disks: tdisk1, }, want: false, extraCount: 0, }, { name: "should allocable", args: args{ layouts: layout, disks: tdisk2, }, want: true, extraCount: 1, }, { name: "should allocable2", args: args{ layouts: layout, disks: tdisk3, }, want: true, extraCount: 1, }, { name: "Bitmain allocable 61438 should true", args: args{ layouts: bitmainLayout, disks: btdisk1, }, want: true, extraCount: 2, }, { name: "Bitmain allocable 61440 should false", args: args{ layouts: bitmainLayout, disks: btdisk2, }, want: false, extraCount: 0, }, { name: "Bitmain allocable autoextend should true", args: args{ layouts: bitmainLayout, disks: btdisk3, }, want: true, extraCount: 2, }, { name: "Bitmain allocable PCIE disk should true", args: args{ layouts: bitmainLayout, disks: btPcieDisk, }, want: true, extraCount: 0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got, extraDisks := CheckDisksAllocable(tt.args.layouts, tt.args.disks); got != tt.want || len(extraDisks) != tt.extraCount { t.Errorf("CheckDisksAllocable() = %v, %d, want %v %d", got, len(extraDisks), tt.want, tt.extraCount) } }) } } var testStorages2 string = ` [ { "adapter": 0, "driver": "MarvelRaid", "model": "SSDSCKJB120G7R", "rotate": true, "size": 114473, "slot": 0, "sn": "PHDW80440155150A" }, { "adapter": 0, "driver": "MarvelRaid", "model": "SSDSCKJB120G7R", "rotate": true, "size": 114473, "slot": 1, "sn": "PHDW80440180150A" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "BTYM73040578960CGNSSDSC2KG960G7R SCV1DL56", "rotate": false, "size": 915200, "slot": 0, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "BTYM73040566960CGNSSDSC2KG960G7R SCV1DL56", "rotate": false, "size": 915200, "slot": 1, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "BTYM734403W7960CGNSSDSC2KG960G7R SCV1DL56", "rotate": false, "size": 915200, "slot": 2, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "BTYM734600B1960CGNSSDSC2KG960G7R SCV1DL56", "rotate": false, "size": 915200, "slot": 3, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012850A192FL7E", "rotate": true, "size": 1716352, "slot": 4, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012850A1A4FL7E", "rotate": true, "size": 1716352, "slot": 5, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012850A190FL7E", "rotate": true, "size": 1716352, "slot": 6, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012850A15WFL7E", "rotate": true, "size": 1716352, "slot": 7, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012850A18CFL7E", "rotate": true, "size": 1716352, "slot": 8, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012850A1ABFL7E", "rotate": true, "size": 1716352, "slot": 9, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012850A1ACFL7E", "rotate": true, "size": 1716352, "slot": 10, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012840A23VFL7E", "rotate": true, "size": 1716352, "slot": 11, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012840A21SFL7E", "rotate": true, "size": 1716352, "slot": 12, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012850A191FL7E", "rotate": true, "size": 1716352, "slot": 13, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012850A15UFL7E", "rotate": true, "size": 1716352, "slot": 14, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012840A23TFL7E", "rotate": true, "size": 1716352, "slot": 15, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012850A13GFL7E", "rotate": true, "size": 1716352, "slot": 16, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012850A13JFL7E", "rotate": true, "size": 1716352, "slot": 17, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012850A19EFL7E", "rotate": true, "size": 1716352, "slot": 18, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012850A19UFL7E", "rotate": true, "size": 1716352, "slot": 19, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012850A1BSFL7E", "rotate": true, "size": 1716352, "slot": 20, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012850A1B5FL7E", "rotate": true, "size": 1716352, "slot": 21, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012850A16FFL7E", "rotate": true, "size": 1716352, "slot": 22, "status": "offline" }, { "adapter": 0, "driver": "MegaRaid", "enclosure": 64, "max_strip_size": 1024, "min_strip_size": 64, "model": "TOSHIBA AL14SEB18EQY EB012850A165FL7E", "rotate": true, "size": 1716352, "slot": 23, "status": "offline" } ] ` func TestStorageLoad(t *testing.T) { ss := make([]*BaremetalStorage, 0) confs, err := NewBaremetalDiskConfigs( "2:raid1:MarvelRaid", "4:raid10:MegaRaid", "raid5", ) if err != nil { t.Fatalf("NewDiskConfigs err: %v", err) } json.Unmarshal([]byte(testStorages2), &ss) _, err = CalculateLayout(confs, ss) if err != nil { t.Fatalf("CalculateLayout err: %v", err) } } func TestCalculateSize(t *testing.T) { type args struct { conf string storages []*BaremetalStorage } tests := []struct { name string args args want int64 }{ { name: "NoneRaid", args: args{ conf: "", storages: testStorages, }, want: 2861056*12 + 953344*2, }, { name: "RAID1", args: args{ conf: DISK_CONF_RAID1, storages: testStorages, }, want: 953344 * (12 + 2) / 2, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := CalculateSize(tt.args.conf, tt.args.storages); got != tt.want { t.Errorf("CalculateSize() = %v, want %v", got, tt.want) } }) } } func TestGetDiskSpecs(t *testing.T) { tests := []struct { name string storages []*BaremetalStorage want []*api.DiskSpec }{ { name: "empty storage", storages: []*BaremetalStorage{}, want: []*api.DiskSpec{}, }, { name: "normal input", storages: testStorages, want: []*api.DiskSpec{ { Type: HDD_DISK_SPEC_TYPE, Size: 2861056, StartIndex: 0, EndIndex: 11, Count: 12, }, { Type: HDD_DISK_SPEC_TYPE, Size: 953344, StartIndex: 12, EndIndex: 13, Count: 2, }, }, }, { name: "discontinuity check", storages: []*BaremetalStorage{ { Rotate: false, Size: 30, }, { Rotate: true, Size: 20, }, { Rotate: true, Size: 20, }, { Rotate: false, Size: 30, }, }, want: []*api.DiskSpec{ { Type: getStorageDiskType(false), Size: 30, StartIndex: 0, EndIndex: 0, Count: 1, }, { Type: getStorageDiskType(true), Size: 20, StartIndex: 1, EndIndex: 2, Count: 2, }, { Type: getStorageDiskType(false), Size: 30, StartIndex: 3, EndIndex: 3, Count: 1, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := GetDiskSpecs(tt.storages); !reflect.DeepEqual(got, tt.want) { t.Errorf("GetDiskSpecs() = %v, want %v", got, tt.want) } }) } } func TestValidateDiskConfigs(t *testing.T) { tests := []struct { name string confs []*api.BaremetalDiskConfig wantErr bool }{ { name: "empty", confs: []*api.BaremetalDiskConfig{}, wantErr: false, }, { name: "none_raid", confs: []*api.BaremetalDiskConfig{ {Conf: DISK_CONF_NONE}, {Conf: DISK_CONF_RAID0}, }, wantErr: true, }, { name: "raid_none_raid", confs: []*api.BaremetalDiskConfig{ {Conf: DISK_CONF_RAID0}, {Conf: DISK_CONF_NONE}, {Conf: DISK_CONF_RAID5}, }, wantErr: true, }, { name: "nones", confs: []*api.BaremetalDiskConfig{ {Conf: DISK_CONF_NONE}, {Conf: DISK_CONF_NONE}, }, wantErr: false, }, { name: "raids_nones", confs: []*api.BaremetalDiskConfig{ {Conf: DISK_CONF_RAID0}, {Conf: DISK_CONF_RAID5}, {Conf: DISK_CONF_NONE}, {Conf: DISK_CONF_NONE}, }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if err := ValidateDiskConfigs(tt.confs); (err != nil) != tt.wantErr { t.Errorf("ValidateDiskConfigs() error = %v, wantErr %v", err, tt.wantErr) } }) } } func TestRetrieveStorages(t *testing.T) { type args struct { diskConfig *api.BaremetalDiskConfig storages []*BaremetalStorage } s1 := &BaremetalStorage{ Size: 1, Driver: "MegaRaid", Adapter: 0, } s2 := &BaremetalStorage{ Size: 1, Driver: "MegaRaid", Adapter: 0, } s3 := &BaremetalStorage{ Size: 2, Driver: "MegaRaid", Adapter: 0, } tests := []struct { name string args args wantSelected []*BaremetalStorage wantRest []*BaremetalStorage }{ { name: "select all", args: args{ diskConfig: &api.BaremetalDiskConfig{ Driver: "MegaRaid", Count: 0, Type: api.DISK_TYPE_HYBRID, }, storages: []*BaremetalStorage{s1, s2, s3}, }, wantSelected: []*BaremetalStorage{s1, s2, s3}, wantRest: []*BaremetalStorage{}, }, { name: "select count 2", args: args{ diskConfig: &api.BaremetalDiskConfig{ Driver: "MegaRaid", Count: 2, Type: api.DISK_TYPE_HYBRID, }, storages: []*BaremetalStorage{s1, s2, s3}, }, wantSelected: []*BaremetalStorage{s1, s2}, wantRest: []*BaremetalStorage{s3}, }, { name: "select by range", args: args{ diskConfig: &api.BaremetalDiskConfig{ Driver: "MegaRaid", Range: []int64{1, 2}, Type: api.DISK_TYPE_HYBRID, }, storages: []*BaremetalStorage{s1, s2, s3}, }, wantSelected: []*BaremetalStorage{s2, s3}, wantRest: []*BaremetalStorage{s1}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { gotSelected, gotRest, err := RetrieveStorages(tt.args.diskConfig, tt.args.storages) if !reflect.DeepEqual(gotSelected, tt.wantSelected) { t.Errorf("RetrieveStorages() gotSelected = %v, want %v, err: %s", gotSelected, tt.wantSelected, err) } if !reflect.DeepEqual(gotRest, tt.wantRest) { t.Errorf("RetrieveStorages() gotRest = %v, want %v, err: %s", gotRest, tt.wantRest, err) } }) } } func TestGetSplitSizes(t *testing.T) { type args struct { size int64 splitConf string } var totalSize int64 = 22889472 size10p := int64(float64(totalSize) * 0.1) tests := []struct { name string args args want []int64 }{ { name: "split gb", args: args{ size: totalSize, splitConf: "60g,", }, want: []int64{61440, totalSize - 61440}, }, { name: "split by percent", args: args{ size: totalSize, splitConf: "10%,", }, want: []int64{ size10p, totalSize - size10p, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := GetSplitSizes(tt.args.size, tt.args.splitConf); !reflect.DeepEqual(got, tt.want) { t.Errorf("GetSplitSizes() = %v, want %v", got, tt.want) } }) } } var ( pcieStorages = []*BaremetalStorage{ { Driver: DISK_DRIVER_LINUX, Rotate: true, Size: 51200, Adapter: 0, Index: 0, }, { Driver: DISK_DRIVER_PCIE, Rotate: false, Size: 61440, Adapter: 0, Index: 0, }, } pcie2Storages = []*BaremetalStorage{ { Driver: DISK_DRIVER_LINUX, Dev: "sda", Rotate: true, Size: 3815447, Adapter: 0, Index: 0, }, { Driver: DISK_DRIVER_PCIE, Dev: "nvme0n1", Rotate: false, Size: 1953514, Adapter: 0, Index: 0, }, { Driver: DISK_DRIVER_PCIE, Dev: "nvme1n1", Rotate: false, Size: 122104, Adapter: 0, Index: 0, }, } ) func TestPCIEStoragesAllocable(t *testing.T) { adapter0 := 0 confs := []*api.BaremetalDiskConfig{ { Adapter: &adapter0, Conf: DISK_CONF_NONE, Count: 1, Driver: DISK_DRIVER_PCIE, Range: []int64{0}, Type: DISK_TYPE_SSD, }, { Adapter: &adapter0, Conf: DISK_CONF_NONE, Count: 1, Driver: DISK_DRIVER_LINUX, Range: []int64{0}, Type: DISK_TYPE_ROTATE, }, } layouts, err := CalculateLayout(confs, pcieStorages) if err != nil { t.Errorf("CalculateLayout error: %v", err) return } // log.Errorf("layouts: %s", jsonutils.Marshal(layouts)) disks := []*api.DiskConfig{ { Backend: api.STORAGE_LOCAL, Driver: "scsi", SizeMb: 30720, }, { Backend: api.STORAGE_LOCAL, Driver: "scsi", Fs: "ext4", Mountpoint: "/opt", SizeMb: -1, }, { Backend: api.STORAGE_LOCAL, Driver: "scsi", Fs: "ext4", Mountpoint: "/data", SizeMb: -1, }, } if ok := IsDisksAllocable(layouts, disks); !ok { t.Errorf("Disk not allocable") } } func Test2PCIEStoragesAllocable(t *testing.T) { adapter0 := 0 confs := []*api.BaremetalDiskConfig{ { Adapter: &adapter0, Conf: DISK_CONF_NONE, Count: 0, Driver: DISK_DRIVER_PCIE, Range: []int64{1}, Type: DISK_TYPE_SSD, }, } layouts, err := CalculateLayout(confs, pcie2Storages) if err != nil { t.Errorf("CalculateLayout error: %v", err) return } log.Errorf("layouts: %s", jsonutils.Marshal(layouts)) disks := []*api.DiskConfig{ { Backend: api.STORAGE_LOCAL, Driver: "scsi", SizeMb: -1, }, } if ok := IsDisksAllocable(layouts, disks); !ok { t.Errorf("Disk not allocable") } }