mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
Automatic merge from release/2.1.0 -> release/2.2.0
* commit '91ca98de309e2aeb2eb5af0f7c4cde213585c721': region: capabilities add specs region: query model by spec keys, filter by zone region: spec handler
This commit is contained in:
Generated
+2
-2
@@ -1124,7 +1124,7 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:253553e4aea4744856900c4015036177f56ddfa4400a4422a2aab8cb1737bd00"
|
||||
digest = "1:e5dd1b8806ddb16ddd31b64c2208d0cc566cd184d12f63844c33581c28d7fa50"
|
||||
name = "yunion.io/x/pkg"
|
||||
packages = [
|
||||
"gotypes",
|
||||
@@ -1158,7 +1158,7 @@
|
||||
"utils",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "6a2c5061c44f5e4a813a87553014ef72d1b983ea"
|
||||
revision = "98dfb17dd78a596fbe5542e8276f4c717dc752fe"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
||||
@@ -13,6 +13,7 @@ func init() {
|
||||
Unused bool `help:"Only show unused devices"`
|
||||
Gpu bool `help:"Only show gpu devices"`
|
||||
Host string `help:"Host ID or Name"`
|
||||
Zone string `help:"Zone ID or Name"`
|
||||
}
|
||||
R(&DeviceListOptions{}, "isolated-device-list", "List isolated devices like GPU", func(s *mcclient.ClientSession, args *DeviceListOptions) error {
|
||||
var params *jsonutils.JSONDict
|
||||
@@ -33,6 +34,9 @@ func init() {
|
||||
if args.Gpu {
|
||||
params.Add(jsonutils.JSONTrue, "gpu")
|
||||
}
|
||||
if args.Zone != "" {
|
||||
params.Add(jsonutils.NewString(args.Zone), "zone")
|
||||
}
|
||||
result, err := modules.IsolatedDevices.List(s, params)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -15,6 +15,7 @@ func init() {
|
||||
Model string `help:"Specified model specs" choices:"hosts|isolated_devices|guests"`
|
||||
HostType string `help:"Host type filter" choices:"baremetal|hypervisor|esxi|kubelet|hyperv"`
|
||||
Gpu bool `help:"Only show gpu devices"`
|
||||
Zone string `help:"Filter by zone id or name"`
|
||||
}
|
||||
R(&ListOptions{}, "spec", "List all kinds of model specs", func(s *mcclient.ClientSession, args *ListOptions) error {
|
||||
var params *jsonutils.JSONDict
|
||||
@@ -36,6 +37,9 @@ func init() {
|
||||
if args.Gpu {
|
||||
params.Add(jsonutils.JSONTrue, "gpu")
|
||||
}
|
||||
if args.Zone != "" {
|
||||
params.Add(jsonutils.NewString(args.Zone), "zone")
|
||||
}
|
||||
result, err := modules.Specs.GetModelSpecs(s, model, params)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -255,6 +255,11 @@ func applyListItemsGeneralJointFilters(manager IModelManager, q *sqlchemy.SQuery
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func ListItemQueryFilters(manager IModelManager, ctx context.Context, q *sqlchemy.SQuery,
|
||||
userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) {
|
||||
return listItemQueryFilters(manager, ctx, q, userCred, query)
|
||||
}
|
||||
|
||||
func listItemQueryFilters(manager IModelManager, ctx context.Context, q *sqlchemy.SQuery,
|
||||
userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) {
|
||||
|
||||
|
||||
@@ -8,68 +8,10 @@ import (
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/api"
|
||||
"yunion.io/x/pkg/util/sets"
|
||||
"yunion.io/x/pkg/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
DISK_CONF_RAID0 = api.DISK_CONF_RAID0
|
||||
DISK_CONF_RAID1 = api.DISK_CONF_RAID1
|
||||
DISK_CONF_RAID5 = api.DISK_CONF_RAID5
|
||||
DISK_CONF_RAID10 = api.DISK_CONF_RAID10
|
||||
DISK_CONF_NONE = api.DISK_CONF_NONE
|
||||
|
||||
DEFAULT_DISK_CONF = DISK_CONF_NONE
|
||||
|
||||
DISK_TYPE_ROTATE = api.DISK_TYPE_ROTATE
|
||||
DISK_TYPE_SSD = api.DISK_TYPE_SSD
|
||||
DISK_TYPE_HYBRID = api.DISK_TYPE_HYBRID
|
||||
|
||||
DEFAULT_DISK_TYPE = DISK_TYPE_ROTATE
|
||||
|
||||
DISK_DRIVER_MEGARAID = api.DISK_DRIVER_MEGARAID
|
||||
DISK_DRIVER_LINUX = api.DISK_DRIVER_LINUX
|
||||
DISK_DRIVER_HPSARAID = api.DISK_DRIVER_HPSARAID
|
||||
DISK_DRIVER_MPT2SAS = api.DISK_DRIVER_MPT2SAS
|
||||
DISK_DRIVER_MARVELRAID = api.DISK_DRIVER_MARVELRAID
|
||||
DISK_DRIVER_PCIE = api.DISK_DRIVER_PCIE
|
||||
|
||||
HDD_DISK_SPEC_TYPE = api.HDD_DISK_SPEC_TYPE
|
||||
SSD_DISK_SPEC_TYPE = api.SSD_DISK_SPEC_TYPE
|
||||
|
||||
ErrMoreThanOneSizeUnspecificSplit = `more than 1 size unspecific split`
|
||||
ErrNoMoreSpaceForUnspecificSplit = `no more space for an unspecific split`
|
||||
ErrSubtotalOfSplitExceedsDiskSize = `subtotal of split exceeds disk size`
|
||||
)
|
||||
|
||||
var (
|
||||
DISK_CONFS = sets.NewString(
|
||||
DISK_CONF_RAID0,
|
||||
DISK_CONF_RAID1,
|
||||
DISK_CONF_RAID5,
|
||||
DISK_CONF_RAID10,
|
||||
DISK_CONF_NONE,
|
||||
)
|
||||
|
||||
DISK_TYPES = sets.NewString(
|
||||
DISK_TYPE_ROTATE,
|
||||
DISK_TYPE_SSD,
|
||||
DISK_TYPE_HYBRID,
|
||||
)
|
||||
|
||||
DISK_DRIVERS_RAID = sets.NewString(
|
||||
DISK_DRIVER_MEGARAID,
|
||||
DISK_DRIVER_HPSARAID,
|
||||
DISK_DRIVER_MPT2SAS,
|
||||
DISK_DRIVER_MARVELRAID,
|
||||
)
|
||||
|
||||
DISK_DRIVERS = sets.NewString(
|
||||
DISK_DRIVER_LINUX,
|
||||
DISK_DRIVER_PCIE).Union(DISK_DRIVERS_RAID)
|
||||
)
|
||||
|
||||
// return bytes
|
||||
func parseStrip(stripStr string, defaultSize string) int64 {
|
||||
size, _ := utils.GetSize(stripStr, defaultSize, 1024)
|
||||
@@ -149,7 +91,7 @@ func ParseRange(rangeStr string) (ret []int64, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func ParseDiskConfig(desc string) (bdc api.BaremetalDiskConfig, err error) {
|
||||
func ParseDiskConfig(desc string) (bdc BaremetalDiskConfig, err error) {
|
||||
bdc.Type = DISK_TYPE_HYBRID
|
||||
bdc.Conf = DISK_CONF_NONE
|
||||
bdc.Count = 0
|
||||
@@ -216,11 +158,11 @@ func ParseDiskConfig(desc string) (bdc api.BaremetalDiskConfig, err error) {
|
||||
}
|
||||
|
||||
func isDiskConfigStorageMatch(
|
||||
config *api.BaremetalDiskConfig,
|
||||
config *BaremetalDiskConfig,
|
||||
confDriver *string,
|
||||
confAdapter *int,
|
||||
storage *api.BaremetalStorage,
|
||||
selected []*api.BaremetalStorage,
|
||||
storage *BaremetalStorage,
|
||||
selected []*BaremetalStorage,
|
||||
) bool {
|
||||
isRotate := storage.Rotate
|
||||
adapter := storage.Adapter
|
||||
@@ -252,7 +194,7 @@ func isDiskConfigStorageMatch(
|
||||
return false
|
||||
}
|
||||
|
||||
func RetrieveStorages(diskConfig *api.BaremetalDiskConfig, storages []*api.BaremetalStorage) (selected, rest []*api.BaremetalStorage) {
|
||||
func RetrieveStorages(diskConfig *BaremetalDiskConfig, storages []*BaremetalStorage) (selected, rest []*BaremetalStorage) {
|
||||
var confDriver *string = nil
|
||||
var confAdapter *int = nil
|
||||
|
||||
@@ -263,8 +205,8 @@ func RetrieveStorages(diskConfig *api.BaremetalDiskConfig, storages []*api.Barem
|
||||
confDriver = &diskConfig.Driver
|
||||
}
|
||||
|
||||
selected = make([]*api.BaremetalStorage, 0)
|
||||
rest = make([]*api.BaremetalStorage, 0)
|
||||
selected = make([]*BaremetalStorage, 0)
|
||||
rest = make([]*BaremetalStorage, 0)
|
||||
idx := 0
|
||||
|
||||
for _, storage := range storages {
|
||||
@@ -307,9 +249,9 @@ func RequireEvenDisks(diskConfig string) bool {
|
||||
}
|
||||
|
||||
type Layout struct {
|
||||
Disks []*api.BaremetalStorage `json:"disks"`
|
||||
Conf *api.BaremetalDiskConfig `json:"conf"`
|
||||
Size int64 `json:"size"`
|
||||
Disks []*BaremetalStorage `json:"disks"`
|
||||
Conf *BaremetalDiskConfig `json:"conf"`
|
||||
Size int64 `json:"size"`
|
||||
}
|
||||
|
||||
func (l Layout) String() string {
|
||||
@@ -317,7 +259,7 @@ func (l Layout) String() string {
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
func RetrieveStorageDrivers(storages []*api.BaremetalStorage) sets.String {
|
||||
func RetrieveStorageDrivers(storages []*BaremetalStorage) sets.String {
|
||||
ret := sets.NewString()
|
||||
for _, s := range storages {
|
||||
ret = ret.Union(sets.NewString(s.Driver))
|
||||
@@ -326,8 +268,8 @@ func RetrieveStorageDrivers(storages []*api.BaremetalStorage) sets.String {
|
||||
}
|
||||
|
||||
func MeetConfig(
|
||||
conf *api.BaremetalDiskConfig,
|
||||
storages []*api.BaremetalStorage,
|
||||
conf *BaremetalDiskConfig,
|
||||
storages []*BaremetalStorage,
|
||||
) error {
|
||||
storageDrvs := RetrieveStorageDrivers(storages)
|
||||
if len(storageDrvs.List()) > 1 {
|
||||
@@ -380,7 +322,7 @@ func MeetConfig(
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetStoragesMinSize(ss []*api.BaremetalStorage) int64 {
|
||||
func GetStoragesMinSize(ss []*BaremetalStorage) int64 {
|
||||
minSize := int64(-1)
|
||||
for _, s := range ss {
|
||||
if minSize < 0 || minSize > s.Size {
|
||||
@@ -390,7 +332,7 @@ func GetStoragesMinSize(ss []*api.BaremetalStorage) int64 {
|
||||
return minSize
|
||||
}
|
||||
|
||||
func CalculateSize(conf string, storages []*api.BaremetalStorage) int64 {
|
||||
func CalculateSize(conf string, storages []*BaremetalStorage) int64 {
|
||||
if conf == "" {
|
||||
conf = DEFAULT_DISK_CONF
|
||||
}
|
||||
@@ -427,7 +369,7 @@ func GetSplitSizes(size int64, splitConf string) []int64 {
|
||||
subtotal += isizes[index]
|
||||
} else {
|
||||
if leftoverIdx >= 0 {
|
||||
log.Errorln(ErrMoreThanOneSizeUnspecificSplit)
|
||||
log.Errorf("%v", ErrMoreThanOneSizeUnspecificSplit)
|
||||
return []int64{}
|
||||
}
|
||||
leftoverIdx = index
|
||||
@@ -436,12 +378,12 @@ func GetSplitSizes(size int64, splitConf string) []int64 {
|
||||
if leftoverIdx >= 0 {
|
||||
isizes[leftoverIdx] = size - subtotal
|
||||
if isizes[leftoverIdx] <= 0 {
|
||||
log.Errorln(ErrNoMoreSpaceForUnspecificSplit)
|
||||
log.Errorf("%v", ErrNoMoreSpaceForUnspecificSplit)
|
||||
return []int64{}
|
||||
}
|
||||
} else {
|
||||
if subtotal > size {
|
||||
log.Errorln(ErrSubtotalOfSplitExceedsDiskSize)
|
||||
log.Errorf("%v", ErrSubtotalOfSplitExceedsDiskSize)
|
||||
return []int64{}
|
||||
}
|
||||
}
|
||||
@@ -454,7 +396,7 @@ func ExpandNoneConf(layouts []Layout) (ret []Layout) {
|
||||
conf := layout.Conf
|
||||
conf.Count = 1
|
||||
for _, disk := range layout.Disks {
|
||||
ret = append(ret, Layout{Disks: []*api.BaremetalStorage{disk}, Conf: conf, Size: disk.Size})
|
||||
ret = append(ret, Layout{Disks: []*BaremetalStorage{disk}, Conf: conf, Size: disk.Size})
|
||||
}
|
||||
} else {
|
||||
ret = append(ret, layout)
|
||||
@@ -464,20 +406,20 @@ func ExpandNoneConf(layouts []Layout) (ret []Layout) {
|
||||
}
|
||||
|
||||
func CalculateLayout(
|
||||
confs []*api.BaremetalDiskConfig,
|
||||
storages []*api.BaremetalStorage,
|
||||
confs []*BaremetalDiskConfig,
|
||||
storages []*BaremetalStorage,
|
||||
) (layouts []Layout, err error) {
|
||||
|
||||
if len(confs) == 0 {
|
||||
err = fmt.Errorf("[]*api.BaremetalDiskConfig must be provided.")
|
||||
err = fmt.Errorf("[]*BaremetalDiskConfig must be provided.")
|
||||
return
|
||||
}
|
||||
|
||||
layouts = make([]Layout, 0)
|
||||
var (
|
||||
plainDisks = make([]*api.BaremetalStorage, 0)
|
||||
pcieDisks = make([]*api.BaremetalStorage, 0)
|
||||
raidDisks = make([]*api.BaremetalStorage, 0)
|
||||
plainDisks = make([]*BaremetalStorage, 0)
|
||||
pcieDisks = make([]*BaremetalStorage, 0)
|
||||
raidDisks = make([]*BaremetalStorage, 0)
|
||||
)
|
||||
|
||||
for _, storage := range storages {
|
||||
@@ -493,7 +435,7 @@ func CalculateLayout(
|
||||
if len(plainDisks) > 0 {
|
||||
layouts = append(layouts, Layout{
|
||||
Disks: plainDisks,
|
||||
Conf: &api.BaremetalDiskConfig{Conf: DISK_CONF_NONE},
|
||||
Conf: &BaremetalDiskConfig{Conf: DISK_CONF_NONE},
|
||||
Size: 0,
|
||||
})
|
||||
}
|
||||
@@ -557,7 +499,7 @@ func CalculateLayout(
|
||||
if len(pcieDisks) > 0 {
|
||||
layouts = append(layouts, Layout{
|
||||
Disks: pcieDisks,
|
||||
Conf: &api.BaremetalDiskConfig{Conf: DISK_CONF_NONE},
|
||||
Conf: &BaremetalDiskConfig{Conf: DISK_CONF_NONE},
|
||||
Size: 0,
|
||||
})
|
||||
}
|
||||
@@ -582,7 +524,7 @@ func expandLayoutSplits(layouts []Layout) []Layout {
|
||||
return ret
|
||||
}
|
||||
|
||||
func CheckDisksAllocable(layouts []Layout, disks []*api.Disk) bool {
|
||||
func CheckDisksAllocable(layouts []Layout, disks []*Disk) bool {
|
||||
layouts = expandLayoutSplits(layouts)
|
||||
storeIndex := 0
|
||||
storeFreeSize := int64(-1)
|
||||
@@ -619,8 +561,8 @@ func CheckDisksAllocable(layouts []Layout, disks []*api.Disk) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func NewBaremetalDiskConfigs(dss ...string) ([]*api.BaremetalDiskConfig, error) {
|
||||
ret := make([]*api.BaremetalDiskConfig, 0)
|
||||
func NewBaremetalDiskConfigs(dss ...string) ([]*BaremetalDiskConfig, error) {
|
||||
ret := make([]*BaremetalDiskConfig, 0)
|
||||
for _, ds := range dss {
|
||||
r, err := ParseDiskConfig(ds)
|
||||
if err != nil {
|
||||
@@ -634,7 +576,7 @@ func NewBaremetalDiskConfigs(dss ...string) ([]*api.BaremetalDiskConfig, error)
|
||||
type SpecSizeCount map[string]int
|
||||
type DiskSpec map[string]SpecSizeCount
|
||||
|
||||
func GetDiskSpec(storages []*api.BaremetalStorage) DiskSpec {
|
||||
func GetDiskSpec(storages []*BaremetalStorage) DiskSpec {
|
||||
diskSpec := make(map[string]SpecSizeCount)
|
||||
|
||||
for _, s := range storages {
|
||||
@@ -658,3 +600,56 @@ func GetDiskSpec(storages []*api.BaremetalStorage) DiskSpec {
|
||||
}
|
||||
return diskSpec
|
||||
}
|
||||
|
||||
func getStoragesByDriver(driver string, storages []*BaremetalStorage) []*BaremetalStorage {
|
||||
ret := make([]*BaremetalStorage, 0)
|
||||
for _, s := range storages {
|
||||
if s.Driver == driver {
|
||||
ret = append(ret, s)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func groupByAdapter(storages []*BaremetalStorage) map[string][]*BaremetalStorage {
|
||||
ret := make(map[string][]*BaremetalStorage)
|
||||
for _, storage := range storages {
|
||||
adapter := storage.Adapter
|
||||
adapterKey := fmt.Sprintf("adapter%d", adapter)
|
||||
oldStorages := ret[adapterKey]
|
||||
if len(oldStorages) == 0 {
|
||||
ret[adapterKey] = []*BaremetalStorage{storage}
|
||||
} else {
|
||||
oldStorages = append(oldStorages, storage)
|
||||
ret[adapterKey] = oldStorages
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type DiskAdapterSpecs map[string]DiskSpec
|
||||
|
||||
func getSpec(storages []*BaremetalStorage) DiskAdapterSpecs {
|
||||
ret := make(map[string]DiskSpec)
|
||||
for adapterKey, newStorages := range groupByAdapter(storages) {
|
||||
if len(newStorages) == 0 {
|
||||
continue
|
||||
}
|
||||
ret[adapterKey] = GetDiskSpec(newStorages)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type DiskDriverSpecs map[string]DiskAdapterSpecs
|
||||
|
||||
func GetDiskSpecV2(storages []*BaremetalStorage) DiskDriverSpecs {
|
||||
spec := make(map[string]DiskAdapterSpecs)
|
||||
for _, driver := range DISK_DRIVERS.List() {
|
||||
driverStorages := getStoragesByDriver(driver, storages)
|
||||
if len(driverStorages) == 0 {
|
||||
continue
|
||||
}
|
||||
spec[driver] = getSpec(storages)
|
||||
}
|
||||
return spec
|
||||
}
|
||||
+21
-22
@@ -6,7 +6,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/api"
|
||||
)
|
||||
|
||||
func TestParseDiskConfig(t *testing.T) {
|
||||
@@ -23,13 +22,13 @@ func TestParseDiskConfig(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantBdc api.BaremetalDiskConfig
|
||||
wantBdc BaremetalDiskConfig
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "rotate:[1-2,4-5]:MegaRaid",
|
||||
args: args{"rotate:[1-2,4-5]:MegaRaid"},
|
||||
wantBdc: api.BaremetalDiskConfig{
|
||||
wantBdc: BaremetalDiskConfig{
|
||||
Type: DISK_TYPE_ROTATE,
|
||||
Conf: DISK_CONF_NONE,
|
||||
Driver: DISK_DRIVER_MEGARAID,
|
||||
@@ -41,7 +40,7 @@ func TestParseDiskConfig(t *testing.T) {
|
||||
{
|
||||
name: "rotate:[1-2,4,6]:raid10:marvelraid",
|
||||
args: args{"rotate:[1-2,4,6]:raid10:marvelraid"},
|
||||
wantBdc: api.BaremetalDiskConfig{
|
||||
wantBdc: BaremetalDiskConfig{
|
||||
Type: DISK_TYPE_ROTATE,
|
||||
Conf: DISK_CONF_RAID10,
|
||||
Driver: DISK_DRIVER_MARVELRAID,
|
||||
@@ -53,7 +52,7 @@ func TestParseDiskConfig(t *testing.T) {
|
||||
{
|
||||
name: "rotate:[4,6]:raid10",
|
||||
args: args{"rotate:[4,6]:raid10"},
|
||||
wantBdc: api.BaremetalDiskConfig{
|
||||
wantBdc: BaremetalDiskConfig{
|
||||
Type: DISK_TYPE_ROTATE,
|
||||
Conf: DISK_CONF_RAID10,
|
||||
Count: 0,
|
||||
@@ -64,7 +63,7 @@ func TestParseDiskConfig(t *testing.T) {
|
||||
{
|
||||
name: "rotate:[4]:raid10:(40%, )",
|
||||
args: args{"rotate:[4]:raid10:(40%, )"},
|
||||
wantBdc: api.BaremetalDiskConfig{
|
||||
wantBdc: BaremetalDiskConfig{
|
||||
Type: DISK_TYPE_ROTATE,
|
||||
Conf: DISK_CONF_RAID10,
|
||||
Count: 0,
|
||||
@@ -76,7 +75,7 @@ func TestParseDiskConfig(t *testing.T) {
|
||||
{
|
||||
name: "[12-13]:raid1:(100g,32g,):adapter0:strip64k",
|
||||
args: args{"[12-13]:raid1:(100g,32g,):adapter0:strip64k"},
|
||||
wantBdc: api.BaremetalDiskConfig{
|
||||
wantBdc: BaremetalDiskConfig{
|
||||
Type: DISK_TYPE_HYBRID,
|
||||
Conf: DISK_CONF_RAID1,
|
||||
Count: 0,
|
||||
@@ -90,7 +89,7 @@ func TestParseDiskConfig(t *testing.T) {
|
||||
{
|
||||
name: "6:raid5:adapter2",
|
||||
args: args{"6:raid5:adapter2"},
|
||||
wantBdc: api.BaremetalDiskConfig{
|
||||
wantBdc: BaremetalDiskConfig{
|
||||
Type: DISK_TYPE_HYBRID,
|
||||
Conf: DISK_CONF_RAID5,
|
||||
Count: 6,
|
||||
@@ -163,7 +162,7 @@ func TestParseRange(t *testing.T) {
|
||||
}
|
||||
|
||||
var (
|
||||
testStorages = []*api.BaremetalStorage{
|
||||
testStorages = []*BaremetalStorage{
|
||||
// 0-11 disk on adapter2
|
||||
{
|
||||
Driver: DISK_DRIVER_MEGARAID,
|
||||
@@ -252,7 +251,7 @@ var (
|
||||
Adapter: 0,
|
||||
},
|
||||
}
|
||||
bitmainStorage = []*api.BaremetalStorage{
|
||||
bitmainStorage = []*BaremetalStorage{
|
||||
{
|
||||
Driver: DISK_DRIVER_MARVELRAID,
|
||||
Rotate: true,
|
||||
@@ -580,7 +579,7 @@ func TestCheckDisksAllocable(t *testing.T) {
|
||||
}
|
||||
|
||||
layout, err := CalculateLayout(confs, testStorages)
|
||||
defaultLayout, err := CalculateLayout([]*api.BaremetalDiskConfig{&api.BaremetalDefaultDiskConfig}, testStorages[12:])
|
||||
defaultLayout, err := CalculateLayout([]*BaremetalDiskConfig{&BaremetalDefaultDiskConfig}, testStorages[12:])
|
||||
if err != nil {
|
||||
t.Fatalf("CalculateLayout err: %v", err)
|
||||
}
|
||||
@@ -593,48 +592,48 @@ func TestCheckDisksAllocable(t *testing.T) {
|
||||
log.Debugf("layout: %s", layout)
|
||||
log.Debugf("Bitmain layout: %s", bitmainLayout)
|
||||
|
||||
tdiskDefault := []*api.Disk{
|
||||
tdiskDefault := []*Disk{
|
||||
{Size: -1},
|
||||
{Size: -1},
|
||||
}
|
||||
|
||||
tdisk1 := []*api.Disk{
|
||||
tdisk1 := []*Disk{
|
||||
{Size: 960000},
|
||||
{Size: -1},
|
||||
{Size: -1},
|
||||
{Size: -1},
|
||||
}
|
||||
|
||||
tdisk2 := []*api.Disk{
|
||||
tdisk2 := []*Disk{
|
||||
{Size: -1},
|
||||
{Size: -1},
|
||||
{Size: -1},
|
||||
{Size: -1},
|
||||
}
|
||||
|
||||
tdisk3 := []*api.Disk{
|
||||
tdisk3 := []*Disk{
|
||||
{Size: 102398},
|
||||
{Size: -1},
|
||||
{Size: -1},
|
||||
{Size: -1},
|
||||
}
|
||||
|
||||
btdisk1 := []*api.Disk{
|
||||
btdisk1 := []*Disk{
|
||||
{Size: 61438},
|
||||
{Size: -1},
|
||||
}
|
||||
|
||||
btdisk2 := []*api.Disk{
|
||||
btdisk2 := []*Disk{
|
||||
{Size: 61440},
|
||||
{Size: -1},
|
||||
}
|
||||
|
||||
btdisk3 := []*api.Disk{
|
||||
btdisk3 := []*Disk{
|
||||
{Size: -1},
|
||||
{Size: -1},
|
||||
}
|
||||
|
||||
btPcieDisk := []*api.Disk{
|
||||
btPcieDisk := []*Disk{
|
||||
{Size: 44440},
|
||||
{Size: -1},
|
||||
{Size: -1},
|
||||
@@ -644,7 +643,7 @@ func TestCheckDisksAllocable(t *testing.T) {
|
||||
|
||||
type args struct {
|
||||
layouts []Layout
|
||||
disks []*api.Disk
|
||||
disks []*Disk
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -727,7 +726,7 @@ func TestCheckDisksAllocable(t *testing.T) {
|
||||
|
||||
func TestGetDiskSpec(t *testing.T) {
|
||||
type args struct {
|
||||
storages []*api.BaremetalStorage
|
||||
storages []*BaremetalStorage
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -1068,7 +1067,7 @@ var testStorages2 string = `
|
||||
`
|
||||
|
||||
func TestStorageLoad(t *testing.T) {
|
||||
ss := make([]*api.BaremetalStorage, 0)
|
||||
ss := make([]*BaremetalStorage, 0)
|
||||
confs, err := NewBaremetalDiskConfigs(
|
||||
"2:raid1:MarvelRaid",
|
||||
"4:raid10:MegaRaid",
|
||||
@@ -0,0 +1 @@
|
||||
package baremetal // import "yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
@@ -0,0 +1,119 @@
|
||||
package baremetal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"yunion.io/x/pkg/util/sets"
|
||||
)
|
||||
|
||||
const (
|
||||
DISK_CONF_RAID0 = "raid0"
|
||||
DISK_CONF_RAID1 = "raid1"
|
||||
DISK_CONF_RAID5 = "raid5"
|
||||
DISK_CONF_RAID10 = "raid10"
|
||||
DISK_CONF_NONE = "none"
|
||||
|
||||
DEFAULT_DISK_CONF = DISK_CONF_NONE
|
||||
|
||||
DISK_TYPE_ROTATE = "rotate"
|
||||
DISK_TYPE_SSD = "ssd"
|
||||
DISK_TYPE_HYBRID = "hybrid"
|
||||
|
||||
DEFAULT_DISK_TYPE = DISK_TYPE_ROTATE
|
||||
|
||||
DISK_DRIVER_MEGARAID = "MegaRaid"
|
||||
DISK_DRIVER_LINUX = "Linux"
|
||||
DISK_DRIVER_HPSARAID = "HPSARaid"
|
||||
DISK_DRIVER_MPT2SAS = "Mpt2SAS"
|
||||
DISK_DRIVER_MARVELRAID = "MarvelRaid"
|
||||
DISK_DRIVER_PCIE = "PCIE"
|
||||
|
||||
HDD_DISK_SPEC_TYPE = "HDD"
|
||||
SSD_DISK_SPEC_TYPE = "SSD"
|
||||
)
|
||||
|
||||
var (
|
||||
BaremetalDefaultDiskConfig = BaremetalDiskConfig{
|
||||
Type: DISK_TYPE_HYBRID,
|
||||
Conf: DISK_CONF_NONE,
|
||||
Count: 0,
|
||||
}
|
||||
|
||||
DISK_CONFS = sets.NewString(
|
||||
DISK_CONF_RAID0,
|
||||
DISK_CONF_RAID1,
|
||||
DISK_CONF_RAID5,
|
||||
DISK_CONF_RAID10,
|
||||
DISK_CONF_NONE,
|
||||
)
|
||||
|
||||
DISK_TYPES = sets.NewString(
|
||||
DISK_TYPE_ROTATE,
|
||||
DISK_TYPE_SSD,
|
||||
DISK_TYPE_HYBRID,
|
||||
)
|
||||
|
||||
DISK_DRIVERS_RAID = sets.NewString(
|
||||
DISK_DRIVER_MEGARAID,
|
||||
DISK_DRIVER_HPSARAID,
|
||||
DISK_DRIVER_MPT2SAS,
|
||||
DISK_DRIVER_MARVELRAID,
|
||||
)
|
||||
|
||||
DISK_DRIVERS = sets.NewString(
|
||||
DISK_DRIVER_LINUX,
|
||||
DISK_DRIVER_PCIE).Union(DISK_DRIVERS_RAID)
|
||||
)
|
||||
|
||||
var (
|
||||
ErrMoreThanOneSizeUnspecificSplit = errors.New(`more than 1 size unspecific split`)
|
||||
ErrNoMoreSpaceForUnspecificSplit = errors.New(`no more space for an unspecific split`)
|
||||
ErrSubtotalOfSplitExceedsDiskSize = errors.New(`subtotal of split exceeds disk size`)
|
||||
)
|
||||
|
||||
type BaremetalStorage struct {
|
||||
Slot int `json:"slot"`
|
||||
Status string `json:"status"`
|
||||
Rotate bool `json:"rotate"`
|
||||
Adapter int `json:"adapter"`
|
||||
Driver string `json:"driver"`
|
||||
Model string `json:"model"`
|
||||
Enclosure int `json:"enclousure"`
|
||||
Size int64 `json:"size"`
|
||||
MinStripSize int64 `json:"min_strip_size,omitempty"`
|
||||
MaxStripSize int64 `json:"max_strip_size,omitempty"`
|
||||
Index int64 `json:"index"`
|
||||
}
|
||||
|
||||
type BaremetalDiskConfig struct {
|
||||
// disk type
|
||||
Type string `json:"type"`
|
||||
// raid config
|
||||
Conf string `json:"conf"`
|
||||
Count int64 `json:"count"`
|
||||
Range []int64 `json:"range"`
|
||||
Splits string `json:"splits"`
|
||||
Adapter *int `json:"adapter"`
|
||||
Driver string `json:"driver"`
|
||||
Cachedbadbbu bool `json:"cachedbadbbu"`
|
||||
Strip int64 `json:"strip"`
|
||||
RA bool `json:"ra"`
|
||||
WT bool `json:"wt"`
|
||||
Direct bool `json:"direct"`
|
||||
}
|
||||
|
||||
type Disk struct {
|
||||
Backend string `json:"backend"`
|
||||
ImageID string `json:"image_id"`
|
||||
Fs *string `json:"fs"`
|
||||
Os string `json:"os"`
|
||||
OSDistribution string `json:"os_distribution"`
|
||||
OsVersion string `json:"os_version"`
|
||||
Format string `json:"format"`
|
||||
MountPoint *string `json:"mountpoint"`
|
||||
Driver *string `json:"driver"`
|
||||
Cache *string `json:"cache"`
|
||||
ImageDiskFormat string `json:"image_disk_format"`
|
||||
Size int64 `json:"size"`
|
||||
Storage *string `json:"storage"`
|
||||
}
|
||||
@@ -1,22 +1,33 @@
|
||||
package capabilities
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
"yunion.io/x/onecloud/pkg/appsrv"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
)
|
||||
|
||||
func AddCapabilityHandler(prefix string, app *appsrv.Application) {
|
||||
app.AddHandler2("GET", fmt.Sprintf("%s/capabilities", prefix), auth.Authenticate(capaHandler), nil, "get_capabilities", nil)
|
||||
}
|
||||
|
||||
func capaHandler(context context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
capa := models.GetCapabilities(nil)
|
||||
func capaHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
userCred := auth.FetchUserCredential(ctx)
|
||||
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
return
|
||||
}
|
||||
capa, err := models.GetCapabilities(ctx, userCred, query, nil)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
return
|
||||
}
|
||||
appsrv.SendJSON(w, jsonutils.Marshal(capa))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,10 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/compute/usages"
|
||||
"yunion.io/x/onecloud/pkg/compute/capabilities"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/compute/specs"
|
||||
"yunion.io/x/onecloud/pkg/compute/usages"
|
||||
)
|
||||
|
||||
func InitHandlers(app *appsrv.Application) {
|
||||
@@ -19,6 +20,7 @@ func InitHandlers(app *appsrv.Application) {
|
||||
quotas.AddQuotaHandler(models.QuotaManager, "", app)
|
||||
usages.AddUsageHandler("", app)
|
||||
capabilities.AddCapabilityHandler("", app)
|
||||
specs.AddSpecHandler("", app)
|
||||
|
||||
taskman.AddTaskHandler("", app)
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/sqlchemy"
|
||||
)
|
||||
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
)
|
||||
|
||||
type SCapabilities struct {
|
||||
Hypervisors []string
|
||||
@@ -17,9 +20,10 @@ type SCapabilities struct {
|
||||
MaxDataDiskCount int
|
||||
SchedPolicySupport bool
|
||||
Usable bool
|
||||
Specs jsonutils.JSONObject
|
||||
}
|
||||
|
||||
func GetCapabilities(zone *SZone) SCapabilities {
|
||||
func GetCapabilities(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, zone *SZone) (SCapabilities, error) {
|
||||
capa := SCapabilities{}
|
||||
capa.Hypervisors = getHypervisors(zone)
|
||||
capa.StorageTypes = getStorageTypes(zone)
|
||||
@@ -30,7 +34,13 @@ func GetCapabilities(zone *SZone) SCapabilities {
|
||||
capa.MinDataDiskCount = getMinDataDiskCount(zone)
|
||||
capa.MaxDataDiskCount = getMaxDataDiskCount(zone)
|
||||
capa.Usable = isUsable(zone)
|
||||
return capa
|
||||
if query == nil {
|
||||
query = jsonutils.NewDict()
|
||||
}
|
||||
var err error
|
||||
mans := []ISpecModelManager{HostManager, IsolatedDeviceManager}
|
||||
capa.Specs, err = GetModelsSpecs(ctx, userCred, query.(*jsonutils.JSONDict), mans...)
|
||||
return capa, err
|
||||
}
|
||||
|
||||
func getHypervisors(zone *SZone) []string {
|
||||
@@ -161,4 +171,4 @@ func isUsable(zone *SZone) bool {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+35
-21
@@ -863,27 +863,6 @@ func parseIsoInfo(ctx context.Context, userCred mcclient.TokenCredential, info s
|
||||
return image.Id, nil
|
||||
}
|
||||
|
||||
// def get_disk_spec_v2(conf):
|
||||
// def _get_spec(storages):
|
||||
// spec = {}
|
||||
// for adapter, ss in group_by_adapter(storages).items():
|
||||
// if len(ss) == 0:
|
||||
// continue
|
||||
// spec[adapter] = get_disk_spec(ss)
|
||||
// return spec
|
||||
|
||||
// spec = {}
|
||||
// for driver in DISK_DRIVERS:
|
||||
// storages = [s for s in conf if s['driver'] == driver]
|
||||
// if len(storages) != 0:
|
||||
// spec[driver] = _get_spec(storages)
|
||||
// return spec
|
||||
|
||||
func GetDiskSpecV2(storageInfo jsonutils.JSONObject) *jsonutils.JSONDict {
|
||||
// ToDo
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SDisk) fetchDiskInfo(diskConfig *SDiskConfig) {
|
||||
if len(diskConfig.ImageId) > 0 {
|
||||
self.TemplateId = diskConfig.ImageId
|
||||
@@ -905,6 +884,37 @@ func (self *SDisk) fetchDiskInfo(diskConfig *SDiskConfig) {
|
||||
self.DiskSize = diskConfig.Size
|
||||
}
|
||||
|
||||
type DiskInfo struct {
|
||||
ImageId string
|
||||
Fs string
|
||||
MountPoint string
|
||||
Format string
|
||||
Size int64
|
||||
StorageId string
|
||||
Backend string
|
||||
MediumType string
|
||||
Driver string
|
||||
Cache string
|
||||
}
|
||||
|
||||
func (self *SDisk) ToDiskInfo() DiskInfo {
|
||||
ret := DiskInfo{
|
||||
ImageId: self.GetTemplateId(),
|
||||
Fs: self.GetFsFormat(),
|
||||
MountPoint: self.GetMountPoint(),
|
||||
Format: self.DiskFormat,
|
||||
Size: int64(self.DiskSize),
|
||||
}
|
||||
storage := self.GetStorage()
|
||||
if storage == nil {
|
||||
return ret
|
||||
}
|
||||
ret.StorageId = storage.Id
|
||||
ret.Backend = storage.StorageType
|
||||
ret.MediumType = storage.MediumType
|
||||
return ret
|
||||
}
|
||||
|
||||
func (self *SDisk) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||||
// override
|
||||
log.Infof("disk delete do nothing")
|
||||
@@ -1083,6 +1093,10 @@ func (self *SDisk) getDev() string {
|
||||
return self.GetMetadata("dev", nil)
|
||||
}
|
||||
|
||||
func (self *SDisk) GetMountPoint() string {
|
||||
return self.GetMetadata("mountpoint", nil)
|
||||
}
|
||||
|
||||
func (self *SDisk) isReady() bool {
|
||||
return self.Status == DISK_READY
|
||||
}
|
||||
|
||||
@@ -211,3 +211,14 @@ func (self *SGuestdisk) Delete(ctx context.Context, userCred mcclient.TokenCrede
|
||||
func (self *SGuestdisk) Detach(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||||
return db.DetachJoint(ctx, userCred, self)
|
||||
}
|
||||
|
||||
func (self *SGuestdisk) ToDiskInfo() DiskInfo {
|
||||
disk := self.GetDisk()
|
||||
if disk == nil {
|
||||
return DiskInfo{}
|
||||
}
|
||||
info := disk.ToDiskInfo()
|
||||
info.Driver = self.Driver
|
||||
info.Cache = self.CacheMode
|
||||
return info
|
||||
}
|
||||
|
||||
@@ -3470,7 +3470,7 @@ func (manager *SGuestManager) FetchGuestById(guestId string) *SGuest {
|
||||
|
||||
func (self *SGuest) GetSpec(checkStatus bool) *jsonutils.JSONDict {
|
||||
if checkStatus {
|
||||
if !utils.IsInStringArray(self.Status, []string{VM_SCHEDULE_FAILED}) {
|
||||
if utils.IsInStringArray(self.Status, []string{VM_SCHEDULE_FAILED}) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -3482,12 +3482,11 @@ func (self *SGuest) GetSpec(checkStatus bool) *jsonutils.JSONDict {
|
||||
guestdisks := self.GetDisks()
|
||||
diskSpecs := jsonutils.NewArray()
|
||||
for _, guestdisk := range guestdisks {
|
||||
disk := guestdisk.GetDisk()
|
||||
info := guestdisk.ToDiskInfo()
|
||||
diskSpec := jsonutils.NewDict()
|
||||
diskSpec.Set("size", jsonutils.NewInt(int64(disk.DiskSize)))
|
||||
s := disk.GetStorage()
|
||||
diskSpec.Set("backend", jsonutils.NewString(s.StorageType))
|
||||
diskSpec.Set("medium_type", jsonutils.NewString(s.MediumType))
|
||||
diskSpec.Set("size", jsonutils.NewInt(info.Size))
|
||||
diskSpec.Set("backend", jsonutils.NewString(info.Backend))
|
||||
diskSpec.Set("medium_type", jsonutils.NewString(info.MediumType))
|
||||
diskSpecs.Add(diskSpec)
|
||||
}
|
||||
spec.Set("disk", diskSpecs)
|
||||
@@ -3522,6 +3521,63 @@ func (self *SGuest) GetSpec(checkStatus bool) *jsonutils.JSONDict {
|
||||
return spec
|
||||
}
|
||||
|
||||
func (manager *SGuestManager) GetSpecIdent(spec *jsonutils.JSONDict) []string {
|
||||
cpuCount, _ := spec.Int("cpu")
|
||||
memSize, _ := spec.Int("mem")
|
||||
memSizeMB, _ := utils.GetSizeMB(fmt.Sprintf("%d", memSize), "M")
|
||||
specKeys := []string{
|
||||
fmt.Sprintf("cpu:%d", cpuCount),
|
||||
fmt.Sprintf("mem:%dM", memSizeMB),
|
||||
}
|
||||
|
||||
countKey := func(kf func(*jsonutils.JSONDict) string, dataArray jsonutils.JSONObject) map[string]int64 {
|
||||
countMap := make(map[string]int64)
|
||||
datas, _ := dataArray.GetArray()
|
||||
for _, data := range datas {
|
||||
key := kf(data.(*jsonutils.JSONDict))
|
||||
if count, ok := countMap[key]; !ok {
|
||||
countMap[key] = 1
|
||||
} else {
|
||||
count++
|
||||
countMap[key] = count
|
||||
}
|
||||
}
|
||||
return countMap
|
||||
}
|
||||
|
||||
kfuncs := map[string]func(*jsonutils.JSONDict) string{
|
||||
"disk": func(data *jsonutils.JSONDict) string {
|
||||
backend, _ := data.GetString("backend")
|
||||
mediumType, _ := data.GetString("medium_type")
|
||||
size, _ := data.Int("size")
|
||||
sizeGB, _ := utils.GetSizeGB(fmt.Sprintf("%d", size), "M")
|
||||
return fmt.Sprintf("disk:%s_%s_%dG", backend, mediumType, sizeGB)
|
||||
},
|
||||
"nic": func(data *jsonutils.JSONDict) string {
|
||||
typ, _ := data.GetString("type")
|
||||
bw, _ := data.Int("bandwidth")
|
||||
return fmt.Sprintf("nic:%s_%dM", typ, bw)
|
||||
},
|
||||
"gpu": func(data *jsonutils.JSONDict) string {
|
||||
vendor, _ := data.GetString("vendor")
|
||||
model, _ := data.GetString("model")
|
||||
return fmt.Sprintf("gpu:%s_%s", vendor, model)
|
||||
},
|
||||
}
|
||||
|
||||
for sKey, kf := range kfuncs {
|
||||
sArrary, err := spec.Get(sKey)
|
||||
if err != nil {
|
||||
log.Errorf("Get key %s array error: %v", sKey, err)
|
||||
continue
|
||||
}
|
||||
for key, count := range countKey(kf, sArrary) {
|
||||
specKeys = append(specKeys, fmt.Sprintf("%sx%d", key, count))
|
||||
}
|
||||
}
|
||||
return specKeys
|
||||
}
|
||||
|
||||
func (self *SGuest) GetTemplateId() string {
|
||||
guestdisks := self.GetDisks()
|
||||
for _, guestdisk := range guestdisks {
|
||||
@@ -3569,7 +3625,7 @@ func (self *SGuest) GetShortDesc() *jsonutils.JSONDict {
|
||||
host := self.GetHost()
|
||||
if host != nil {
|
||||
hostSpec := host.GetSpec(false)
|
||||
hostSpecIdent := host.GetSpecIdent(hostSpec)
|
||||
hostSpecIdent := HostManager.GetSpecIdent(hostSpec)
|
||||
spec.Set("host_spec", jsonutils.NewString(strings.Join(hostSpecIdent, "/")))
|
||||
}
|
||||
}
|
||||
|
||||
+72
-11
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -19,6 +20,7 @@ import (
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/compute/options"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
@@ -520,16 +522,14 @@ func (self *SHost) GetSpec(statusCheck bool) *jsonutils.JSONDict {
|
||||
}
|
||||
spec := self.GetHardwareSpecification()
|
||||
spec.Remove("storage_info")
|
||||
netInfo := jsonutils.NewArray()
|
||||
nifs := self.GetNetInterfaces()
|
||||
var nicCount int64
|
||||
for _, nif := range nifs {
|
||||
netDesc := nif.getBaremetalJsonDesc()
|
||||
nicType, err := netDesc.GetString("nic_type")
|
||||
if err != nil && nicType != NIC_TYPE_IPMI {
|
||||
netInfo.Add(netDesc)
|
||||
if nif.NicType != NIC_TYPE_IPMI {
|
||||
nicCount++
|
||||
}
|
||||
}
|
||||
spec.Set("nic_count", jsonutils.NewInt(int64(netInfo.Length())))
|
||||
spec.Set("nic_count", jsonutils.NewInt(nicCount))
|
||||
manufacture, err := self.SysInfo.Get("manufacture")
|
||||
if err != nil {
|
||||
manufacture = jsonutils.NewString("Unknown")
|
||||
@@ -540,12 +540,73 @@ func (self *SHost) GetSpec(statusCheck bool) *jsonutils.JSONDict {
|
||||
model = jsonutils.NewString("Unknown")
|
||||
}
|
||||
spec.Set("model", model)
|
||||
return nil
|
||||
return spec
|
||||
}
|
||||
|
||||
func (self *SHost) GetSpecIdent(spec *jsonutils.JSONDict) []string {
|
||||
// Todo
|
||||
return []string{}
|
||||
func (manager *SHostManager) GetSpecIdent(spec *jsonutils.JSONDict) []string {
|
||||
nCpu, _ := spec.Int("cpu")
|
||||
memSize, _ := spec.Int("mem")
|
||||
memGB, err := utils.GetSizeGB(fmt.Sprintf("%d", memSize), "M")
|
||||
if err != nil {
|
||||
log.Errorf("Get mem size %d GB error: %v", memSize, err)
|
||||
}
|
||||
nicCount, _ := spec.Int("nic_count")
|
||||
manufacture, _ := spec.GetString("manufacture")
|
||||
model, _ := spec.GetString("model")
|
||||
|
||||
specKeys := []string{
|
||||
fmt.Sprintf("cpu:%d", nCpu),
|
||||
fmt.Sprintf("mem:%dG", memGB),
|
||||
fmt.Sprintf("nic:%d", nicCount),
|
||||
fmt.Sprintf("manufacture:%s", manufacture),
|
||||
fmt.Sprintf("model:%s", model),
|
||||
}
|
||||
diskSpec, _ := spec.Get("disk")
|
||||
if diskSpec != nil {
|
||||
driverSpecs, _ := diskSpec.GetMap()
|
||||
for driver, driverSpec := range driverSpecs {
|
||||
specKeys = append(specKeys, parseDiskDriverSpec(driver, driverSpec)...)
|
||||
}
|
||||
}
|
||||
sort.Strings(specKeys)
|
||||
return specKeys
|
||||
}
|
||||
|
||||
func parseDiskDriverSpec(driver string, spec jsonutils.JSONObject) []string {
|
||||
ret := make([]string, 0)
|
||||
adapterSpecs, _ := spec.GetMap()
|
||||
for adapterKey, adapterSpec := range adapterSpecs {
|
||||
for _, diskType := range []string{baremetal.HDD_DISK_SPEC_TYPE, baremetal.SSD_DISK_SPEC_TYPE} {
|
||||
sizeCountMap, _ := adapterSpec.GetMap(diskType)
|
||||
if sizeCountMap == nil {
|
||||
continue
|
||||
}
|
||||
for size, count := range sizeCountMap {
|
||||
sizeGB, _ := utils.GetSizeGB(size, "M")
|
||||
diskKey := fmt.Sprintf("disk:%s_%s_%s_%dGx%s", driver, adapterKey, diskType, sizeGB, count)
|
||||
ret = append(ret, diskKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func GetDiskSpecV2(storageInfo jsonutils.JSONObject) jsonutils.JSONObject {
|
||||
storages := []baremetal.BaremetalStorage{}
|
||||
err := storageInfo.Unmarshal(&storages)
|
||||
if err != nil {
|
||||
log.Errorf("Unmarshal to baremetal storage error: %v", err)
|
||||
return nil
|
||||
}
|
||||
refStorages := func() []*baremetal.BaremetalStorage {
|
||||
ret := make([]*baremetal.BaremetalStorage, len(storages))
|
||||
for i, s := range storages {
|
||||
ret[i] = &s
|
||||
}
|
||||
return ret
|
||||
}()
|
||||
diskSpec := baremetal.GetDiskSpecV2(refStorages)
|
||||
return jsonutils.Marshal(diskSpec)
|
||||
}
|
||||
|
||||
func (self *SHost) GetHardwareSpecification() *jsonutils.JSONDict {
|
||||
@@ -1640,4 +1701,4 @@ func (self *SHost) GetLocalStoragecache() *SStoragecache {
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +113,16 @@ func (manager *SIsolatedDeviceManager) ListItemFilter(ctx context.Context, q *sq
|
||||
if jsonutils.QueryBoolean(query, "unused", false) {
|
||||
q = q.IsEmpty("guest_id")
|
||||
}
|
||||
zoneStr := jsonutils.GetAnyString(query, []string{"zone", "zone_id"})
|
||||
if len(zoneStr) > 0 {
|
||||
zone, _ := ZoneManager.FetchByIdOrName("", zoneStr)
|
||||
if zone == nil {
|
||||
return nil, httperrors.NewResourceNotFoundError("Zone %s not found", zoneStr)
|
||||
}
|
||||
hosts := HostManager.Query().SubQuery()
|
||||
sq := hosts.Query(hosts.Field("id")).Filter(sqlchemy.Equals(hosts.Field("zone_id"), zone.GetId()))
|
||||
q = q.Filter(sqlchemy.In(q.Field("host_id"), sq))
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
|
||||
@@ -307,6 +317,36 @@ func (manager *SIsolatedDeviceManager) findUnusedQuery() *sqlchemy.SQuery {
|
||||
return q
|
||||
}
|
||||
|
||||
func (manager *SIsolatedDeviceManager) UnusedGpuQuery() *sqlchemy.SQuery {
|
||||
q := manager.findUnusedQuery()
|
||||
q = q.Filter(sqlchemy.OR(
|
||||
sqlchemy.Equals(q.Field("dev_type"), GPU_HPC_TYPE),
|
||||
sqlchemy.Equals(q.Field("dev_type"), GPU_VGA_TYPE)))
|
||||
return q
|
||||
}
|
||||
|
||||
func (manager *SIsolatedDeviceManager) FindUnusedByModels(models []string) ([]SIsolatedDevice, error) {
|
||||
devs := make([]SIsolatedDevice, 0)
|
||||
q := manager.findUnusedQuery()
|
||||
q = q.In("model", models)
|
||||
err := q.All(&devs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return devs, nil
|
||||
}
|
||||
|
||||
func (manager *SIsolatedDeviceManager) FindUnusedGpusOnHost(hostId string) ([]SIsolatedDevice, error) {
|
||||
devs := make([]SIsolatedDevice, 0)
|
||||
q := manager.UnusedGpuQuery()
|
||||
q = q.Equals("host_id", hostId)
|
||||
err := q.All(&devs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return devs, nil
|
||||
}
|
||||
|
||||
func (manager *SIsolatedDeviceManager) findHostUnusedByModel(model string, hostId string) ([]SIsolatedDevice, error) {
|
||||
devs := make([]SIsolatedDevice, 0)
|
||||
q := manager.findUnusedQuery()
|
||||
@@ -381,8 +421,8 @@ func (self *SIsolatedDevice) getDesc() *jsonutils.JSONDict {
|
||||
return desc
|
||||
}
|
||||
|
||||
func (self *SIsolatedDevice) GetSpec(checkStatus bool) *jsonutils.JSONDict {
|
||||
if checkStatus {
|
||||
func (self *SIsolatedDevice) GetSpec(statusCheck bool) *jsonutils.JSONDict {
|
||||
if statusCheck {
|
||||
if len(self.GuestId) > 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -399,6 +439,19 @@ func (self *SIsolatedDevice) GetSpec(checkStatus bool) *jsonutils.JSONDict {
|
||||
return spec
|
||||
}
|
||||
|
||||
func (man *SIsolatedDeviceManager) GetSpecIdent(spec *jsonutils.JSONDict) []string {
|
||||
log.Errorf("gpu get specIdent: %s", spec)
|
||||
devType, _ := spec.GetString("dev_type")
|
||||
vendor, _ := spec.GetString("vendor")
|
||||
model, _ := spec.GetString("model")
|
||||
keys := []string{
|
||||
fmt.Sprintf("type:%s", devType),
|
||||
fmt.Sprintf("vendor:%s", vendor),
|
||||
fmt.Sprintf("model:%s", model),
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func (self *SIsolatedDevice) GetShortDesc() *jsonutils.JSONDict {
|
||||
desc := self.getDesc()
|
||||
desc.Add(jsonutils.NewString(self.Keyword()), "res_name")
|
||||
|
||||
@@ -162,6 +162,9 @@ func (self *SNetInterface) getServerJsonDesc() *jsonutils.JSONDict {
|
||||
|
||||
func (self *SNetInterface) getBaremetalJsonDesc() *jsonutils.JSONDict {
|
||||
bn := self.GetBaremetalNetwork()
|
||||
if bn == nil {
|
||||
return nil
|
||||
}
|
||||
return self.toJson(bn.IpAddr, bn.GetNetwork())
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
)
|
||||
|
||||
type ISpecModelManager interface {
|
||||
db.IStandaloneModelManager
|
||||
GetSpecIdent(spec *jsonutils.JSONDict) []string
|
||||
}
|
||||
|
||||
type ISpecModel interface {
|
||||
db.IStandaloneModel
|
||||
GetSpec(statusCheck bool) *jsonutils.JSONDict
|
||||
}
|
||||
|
||||
func GetAllModelSpecs(ctx context.Context, userCred mcclient.TokenCredential, query *jsonutils.JSONDict) (jsonutils.JSONObject, error) {
|
||||
mans := []ISpecModelManager{HostManager, IsolatedDeviceManager, GuestManager}
|
||||
return GetModelsSpecs(ctx, userCred, query, mans...)
|
||||
}
|
||||
|
||||
func GetModelsSpecs(ctx context.Context, userCred mcclient.TokenCredential, query *jsonutils.JSONDict, managers ...ISpecModelManager) (jsonutils.JSONObject, error) {
|
||||
ret := jsonutils.NewDict()
|
||||
for _, man := range managers {
|
||||
spec, err := getModelSpecs(man, ctx, userCred, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.Add(spec, man.KeywordPlural())
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func GetHostSpecs(ctx context.Context, userCred mcclient.TokenCredential, query *jsonutils.JSONDict) (jsonutils.JSONObject, error) {
|
||||
return getModelSpecs(HostManager, ctx, userCred, query)
|
||||
}
|
||||
|
||||
func GetIsolatedDeviceSpecs(ctx context.Context, userCred mcclient.TokenCredential, query *jsonutils.JSONDict) (jsonutils.JSONObject, error) {
|
||||
return getModelSpecs(IsolatedDeviceManager, ctx, userCred, query)
|
||||
}
|
||||
|
||||
func GetServerSpecs(ctx context.Context, userCred mcclient.TokenCredential, query *jsonutils.JSONDict) (jsonutils.JSONObject, error) {
|
||||
return getModelSpecs(GuestManager, ctx, userCred, query)
|
||||
}
|
||||
|
||||
func getModelSpecs(manager ISpecModelManager, ctx context.Context, userCred mcclient.TokenCredential, query *jsonutils.JSONDict) (jsonutils.JSONObject, error) {
|
||||
items, err := ListItems(manager, ctx, userCred, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
retDict := jsonutils.NewDict()
|
||||
for _, obj := range items {
|
||||
specObj := obj.(ISpecModel)
|
||||
spec := specObj.GetSpec(true)
|
||||
if spec == nil {
|
||||
continue
|
||||
}
|
||||
specKeys := manager.GetSpecIdent(spec)
|
||||
sort.Strings(specKeys)
|
||||
specKey := strings.Join(specKeys, "/")
|
||||
if oldSpec, _ := retDict.Get(specKey); oldSpec == nil {
|
||||
spec.Add(jsonutils.NewInt(1), "count")
|
||||
retDict.Add(spec, specKey)
|
||||
} else {
|
||||
count, _ := oldSpec.Int("count")
|
||||
oldSpec.(*jsonutils.JSONDict).Set("count", jsonutils.NewInt(count+1))
|
||||
retDict.Set(specKey, oldSpec)
|
||||
}
|
||||
}
|
||||
return retDict, nil
|
||||
}
|
||||
|
||||
func ListItems(manager db.IModelManager, ctx context.Context, userCred mcclient.TokenCredential, queryDict *jsonutils.JSONDict) ([]ISpecModel, error) {
|
||||
q := manager.Query()
|
||||
queryDict, err := manager.ValidateListConditions(ctx, userCred, queryDict)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
q, err = db.ListItemQueryFilters(manager, ctx, q, userCred, queryDict)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rows, err := q.Rows()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items := make([]ISpecModel, 0)
|
||||
for rows.Next() {
|
||||
item, err := db.NewModelObject(manager)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
itemInitValue := reflect.Indirect(reflect.ValueOf(item))
|
||||
item, err = db.NewModelObject(manager)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
itemValue := reflect.Indirect(reflect.ValueOf(item))
|
||||
itemValue.Set(itemInitValue)
|
||||
err = q.Row2Struct(rows, item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, item.(ISpecModel))
|
||||
}
|
||||
return items, err
|
||||
}
|
||||
@@ -479,7 +479,10 @@ func (self *SZone) AllowGetDetailsCapability(ctx context.Context, userCred mccli
|
||||
}
|
||||
|
||||
func (self *SZone) GetDetailsCapability(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
capa := GetCapabilities(self)
|
||||
capa, err := GetCapabilities(ctx, userCred, query, self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return jsonutils.Marshal(&capa), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
package specs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/util/sets"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/appctx"
|
||||
"yunion.io/x/onecloud/pkg/appsrv"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
)
|
||||
|
||||
type specHandleFunc func(context context.Context, userCred mcclient.TokenCredential, query *jsonutils.JSONDict) (jsonutils.JSONObject, error)
|
||||
|
||||
func AddSpecHandler(prefix string, app *appsrv.Application) {
|
||||
// get models specs
|
||||
for key, handleF := range map[string]specHandleFunc{
|
||||
"": models.GetAllModelSpecs,
|
||||
"hosts": models.GetHostSpecs,
|
||||
"isolated_devices": models.GetIsolatedDeviceSpecs,
|
||||
"servers": models.GetServerSpecs,
|
||||
} {
|
||||
addModelSpecHandler(prefix, key, handleF, app)
|
||||
}
|
||||
|
||||
// get model objects by spec key
|
||||
for key, handleF := range map[string]specQueryHandleFunc{
|
||||
"hosts": queryHosts,
|
||||
"isolated_devices": queryIsolatedDevices,
|
||||
} {
|
||||
AddQuerySpecModelHandler(prefix, key, handleF, app)
|
||||
}
|
||||
}
|
||||
|
||||
func processFilter(handleFunc specHandleFunc) appsrv.FilterHandler {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
userCred := auth.FetchUserCredential(ctx)
|
||||
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
return
|
||||
}
|
||||
params := appctx.AppContextParams(ctx)
|
||||
for key, v := range params {
|
||||
query.(*jsonutils.JSONDict).Add(jsonutils.NewString(v), key)
|
||||
}
|
||||
spec, err := handleFunc(ctx, userCred, query.(*jsonutils.JSONDict))
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(w, err)
|
||||
return
|
||||
}
|
||||
ret := jsonutils.NewDict()
|
||||
ret.Add(spec, "spec")
|
||||
appsrv.SendJSON(w, ret)
|
||||
}
|
||||
}
|
||||
|
||||
func addModelSpecHandler(prefix, managerPluralKey string, handleFunc specHandleFunc, app *appsrv.Application) {
|
||||
af := auth.Authenticate(processFilter(handleFunc))
|
||||
name := "get_spec"
|
||||
prefix = fmt.Sprintf("%s/specs", prefix)
|
||||
if len(managerPluralKey) != 0 {
|
||||
prefix = fmt.Sprintf("%s/%s", prefix, managerPluralKey)
|
||||
name = fmt.Sprintf("get_%s_spec", managerPluralKey)
|
||||
}
|
||||
app.AddHandler2("GET", prefix, af, nil, name, nil)
|
||||
}
|
||||
|
||||
func AddQuerySpecModelHandler(prefix, managerPluralKey string, handleFunc specQueryHandleFunc, app *appsrv.Application) {
|
||||
af := auth.Authenticate(processFilter(queryModelHandle(handleFunc)))
|
||||
prefix = fmt.Sprintf("%s/specs/%s", prefix, managerPluralKey)
|
||||
name := fmt.Sprintf("get_%s_spec_query", managerPluralKey)
|
||||
app.AddHandler2("GET", fmt.Sprintf("%s/<spec_key>/resource", prefix), af, nil, name, nil)
|
||||
}
|
||||
|
||||
func parseSpecKey(key string) ([]string, error) {
|
||||
unEscapeStr, err := url.PathUnescape(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return strings.Split(unEscapeStr, "/"), nil
|
||||
}
|
||||
|
||||
type specQueryHandleFunc func(context.Context, mcclient.TokenCredential, *jsonutils.JSONDict, []string) (jsonutils.JSONObject, error)
|
||||
|
||||
func queryModelHandle(queryF specQueryHandleFunc) specHandleFunc {
|
||||
return func(ctx context.Context, userCred mcclient.TokenCredential, query *jsonutils.JSONDict) (jsonutils.JSONObject, error) {
|
||||
specKey, _ := query.GetString("<spec_key>")
|
||||
if specKey == "" {
|
||||
return nil, httperrors.NewInputParameterError("Empty spec query key")
|
||||
}
|
||||
specKeys, err := parseSpecKey(specKey)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInputParameterError("Parse spec key %s error: %v", specKey, err)
|
||||
}
|
||||
return queryF(ctx, userCred, query, specKeys)
|
||||
}
|
||||
}
|
||||
|
||||
func queryHosts(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query *jsonutils.JSONDict,
|
||||
specKeys []string,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
gpuModels := []string{}
|
||||
newSpecs := []string{}
|
||||
gpuHostIds := []string{}
|
||||
for _, specKey := range specKeys {
|
||||
if specKey == "gpu_model" {
|
||||
gpuModels = append(gpuModels, strings.Split(specKey, ":")[1])
|
||||
} else {
|
||||
newSpecs = append(newSpecs, specKey)
|
||||
}
|
||||
}
|
||||
|
||||
if len(gpuModels) != 0 {
|
||||
devs, err := models.IsolatedDeviceManager.FindUnusedByModels(gpuModels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, dev := range devs {
|
||||
gpuHostIds = append(gpuHostIds, dev.HostId)
|
||||
}
|
||||
}
|
||||
|
||||
isOk := func(obj models.ISpecModel) bool {
|
||||
if len(gpuHostIds) > 0 {
|
||||
if !sets.NewString(gpuHostIds...).Has(obj.GetId()) {
|
||||
return false
|
||||
}
|
||||
gpus, _ := models.IsolatedDeviceManager.FindUnusedGpusOnHost(obj.GetId())
|
||||
if len(gpus) == 0 {
|
||||
return false
|
||||
}
|
||||
hostGpuModels := []string{}
|
||||
for _, gpu := range gpus {
|
||||
hostGpuModels = append(hostGpuModels, gpu.Model)
|
||||
}
|
||||
if !sets.NewString(hostGpuModels...).IsSuperset(sets.NewString(gpuModels...)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return handleQueryModel(models.HostManager, ctx, userCred, query, specKeys, isOk)
|
||||
}
|
||||
|
||||
func queryIsolatedDevices(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query *jsonutils.JSONDict,
|
||||
specKeys []string,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
return handleQueryModel(models.IsolatedDeviceManager, ctx, userCred, query, specKeys, nil)
|
||||
}
|
||||
|
||||
func handleQueryModel(
|
||||
manager models.ISpecModelManager,
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query *jsonutils.JSONDict,
|
||||
specKeys []string,
|
||||
isOkF func(models.ISpecModel) bool,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
objects, err := models.ListItems(manager, ctx, userCred, query)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInternalServerError("Get object error: %v", err)
|
||||
}
|
||||
if len(objects) == 0 {
|
||||
ret := jsonutils.NewArray()
|
||||
return ret, nil
|
||||
}
|
||||
objs := QueryObjects(manager, objects, specKeys, isOkF)
|
||||
return QueryObjectsToJson(objs, ctx, userCred, query)
|
||||
}
|
||||
|
||||
func QueryObjects(manager models.ISpecModelManager, objs []models.ISpecModel, specKeys []string, isOkF func(models.ISpecModel) bool) []models.ISpecModel {
|
||||
selectedObjs := make([]models.ISpecModel, 0)
|
||||
for _, obj := range objs {
|
||||
specs := obj.GetSpec(true)
|
||||
if specs == nil {
|
||||
continue
|
||||
}
|
||||
if isOkF != nil && !isOkF(obj) {
|
||||
continue
|
||||
}
|
||||
specIdents := manager.GetSpecIdent(specs)
|
||||
if len(specIdents) == 0 {
|
||||
continue
|
||||
}
|
||||
if !sets.NewString(specIdents...).IsSuperset(sets.NewString(specKeys...)) {
|
||||
continue
|
||||
}
|
||||
selectedObjs = append(selectedObjs, obj)
|
||||
}
|
||||
return selectedObjs
|
||||
}
|
||||
|
||||
func QueryObjectsToJson(objs []models.ISpecModel, ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
ret := jsonutils.NewArray()
|
||||
for _, obj := range objs {
|
||||
jsonData := jsonutils.Marshal(obj)
|
||||
jsonDict, ok := jsonData.(*jsonutils.JSONDict)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Invalid model data structure, not a dict")
|
||||
}
|
||||
extraDict := obj.GetCustomizeColumns(ctx, userCred, query)
|
||||
if extraDict != nil {
|
||||
jsonDict.Update(extraDict)
|
||||
}
|
||||
ret.Add(jsonDict)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
@@ -3,10 +3,10 @@ package baremetal
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
//"yunion.io/x/log"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/algorithm/predicates"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/api"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/core"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/util/baremetal"
|
||||
)
|
||||
|
||||
type StoragePredicate struct {
|
||||
@@ -21,6 +21,27 @@ func (p *StoragePredicate) Clone() core.FitPredicate {
|
||||
return &StoragePredicate{}
|
||||
}
|
||||
|
||||
func toBaremetalDisks(disks []*api.Disk) []*baremetal.Disk {
|
||||
ret := make([]*baremetal.Disk, len(disks))
|
||||
for i, disk := range disks {
|
||||
ret[i] = &baremetal.Disk{
|
||||
Backend: disk.Backend,
|
||||
ImageID: disk.ImageID,
|
||||
Fs: disk.Fs,
|
||||
Os: disk.Os,
|
||||
OSDistribution: disk.OSDistribution,
|
||||
Format: disk.Format,
|
||||
MountPoint: disk.MountPoint,
|
||||
Driver: disk.Driver,
|
||||
Cache: disk.Cache,
|
||||
ImageDiskFormat: disk.ImageDiskFormat,
|
||||
Size: disk.Size,
|
||||
Storage: disk.Storage,
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (p *StoragePredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.PredicateFailureReason, error) {
|
||||
h := predicates.NewPredicateHelper(p, u, c)
|
||||
schedData := u.SchedData()
|
||||
@@ -35,7 +56,7 @@ func (p *StoragePredicate) Execute(u *core.Unit, c core.Candidater) (bool, []cor
|
||||
candidate.Storages,
|
||||
)
|
||||
|
||||
if err == nil && baremetal.CheckDisksAllocable(layouts, schedData.Disks) {
|
||||
if err == nil && baremetal.CheckDisksAllocable(layouts, toBaremetalDisks(schedData.Disks)) {
|
||||
h.SetCapacity(int64(1))
|
||||
} else {
|
||||
h.SetCapacity(int64(0))
|
||||
|
||||
@@ -9,8 +9,10 @@ import (
|
||||
"github.com/bitly/go-simplejson"
|
||||
|
||||
"yunion.io/x/log"
|
||||
o "yunion.io/x/onecloud/cmd/scheduler/options"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
o "yunion.io/x/onecloud/cmd/scheduler/options"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
)
|
||||
|
||||
type Meta map[string]string
|
||||
@@ -98,7 +100,7 @@ type SchedData struct {
|
||||
GroupRelations []GroupRelation `json:"group_relations"`
|
||||
|
||||
// baremental
|
||||
BaremetalDiskConfigs []*BaremetalDiskConfig `json:"baremetal_disk_config"`
|
||||
BaremetalDiskConfigs []*baremetal.BaremetalDiskConfig `json:"baremetal_disk_config"`
|
||||
}
|
||||
|
||||
func NewSchedData(sjson *simplejson.Json, count int64, byTest bool) (*SchedData, error) {
|
||||
@@ -543,8 +545,8 @@ func newDiskFromSimpleJson(sjson *simplejson.Json, byTest bool) (*Disk, error) {
|
||||
return disk, nil
|
||||
}
|
||||
|
||||
func newBaremetalDiskConfigFromSimpleJson(sjson *simplejson.Json) (*BaremetalDiskConfig, error) {
|
||||
baremetalDiskConfig := new(BaremetalDiskConfig)
|
||||
func newBaremetalDiskConfigFromSimpleJson(sjson *simplejson.Json) (*baremetal.BaremetalDiskConfig, error) {
|
||||
baremetalDiskConfig := new(baremetal.BaremetalDiskConfig)
|
||||
baremetalDiskConfig.Count = sjson.Get("count").MustInt64()
|
||||
baremetalDiskConfig.Conf = sjson.Get("conf").MustString()
|
||||
|
||||
@@ -597,13 +599,13 @@ func (d *SchedData) fillDisksInfo(sjson *simplejson.Json, byTest bool) error {
|
||||
}
|
||||
|
||||
func (d *SchedData) fillBaremetalDiskConfig(sjson *simplejson.Json) error {
|
||||
baremetalDiskConfigs := []*BaremetalDiskConfig{}
|
||||
baremetalDiskConfigs := []*baremetal.BaremetalDiskConfig{}
|
||||
if d.Hypervisor != HostTypeBaremetal {
|
||||
return nil
|
||||
}
|
||||
config, ok := sjson.CheckGet("baremetal_disk_config")
|
||||
if !ok {
|
||||
defaultConfs := []*BaremetalDiskConfig{&BaremetalDefaultDiskConfig}
|
||||
defaultConfs := []*baremetal.BaremetalDiskConfig{&baremetal.BaremetalDefaultDiskConfig}
|
||||
d.BaremetalDiskConfigs = defaultConfs
|
||||
log.V(4).Warningf("No baremetal_disk_config info found in json, use default baremetal disk config: %#v", defaultConfs)
|
||||
return nil
|
||||
|
||||
@@ -24,31 +24,6 @@ const (
|
||||
AggregateStrategyPrefer = "prefer"
|
||||
AggregateStrategyAvoid = "avoid"
|
||||
|
||||
// Baremetal related const
|
||||
DISK_CONF_RAID0 = "raid0"
|
||||
DISK_CONF_RAID1 = "raid1"
|
||||
DISK_CONF_RAID5 = "raid5"
|
||||
DISK_CONF_RAID10 = "raid10"
|
||||
DISK_CONF_NONE = "none"
|
||||
|
||||
DEFAULT_DISK_CONF = DISK_CONF_NONE
|
||||
|
||||
DISK_TYPE_ROTATE = "rotate"
|
||||
DISK_TYPE_SSD = "ssd"
|
||||
DISK_TYPE_HYBRID = "hybrid"
|
||||
|
||||
DEFAULT_DISK_TYPE = DISK_TYPE_ROTATE
|
||||
|
||||
DISK_DRIVER_MEGARAID = "MegaRaid"
|
||||
DISK_DRIVER_LINUX = "Linux"
|
||||
DISK_DRIVER_HPSARAID = "HPSARaid"
|
||||
DISK_DRIVER_MPT2SAS = "Mpt2SAS"
|
||||
DISK_DRIVER_MARVELRAID = "MarvelRaid"
|
||||
DISK_DRIVER_PCIE = "PCIE"
|
||||
|
||||
HDD_DISK_SPEC_TYPE = "HDD"
|
||||
SSD_DISK_SPEC_TYPE = "SSD"
|
||||
|
||||
// passthrough device type
|
||||
DIRECT_PCI_TYPE = "PCI"
|
||||
GPU_HPC_TYPE = "GPU-HPC"
|
||||
@@ -75,12 +50,6 @@ var (
|
||||
HostTypeAliyun,
|
||||
)
|
||||
|
||||
BaremetalDefaultDiskConfig = BaremetalDiskConfig{
|
||||
Type: DISK_TYPE_HYBRID,
|
||||
Conf: DISK_CONF_NONE,
|
||||
Count: 0,
|
||||
}
|
||||
|
||||
ValidGpuTypes = sets.NewString(
|
||||
GPU_HPC_TYPE,
|
||||
GPU_VGA_TYPE,
|
||||
@@ -112,34 +81,3 @@ func AggregateStrategyCheck(strategy string) (err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type BaremetalStorage struct {
|
||||
Slot int `json:"slot"`
|
||||
Status string `json:"status"`
|
||||
Rotate bool `json:"rotate"`
|
||||
Adapter int `json:"adapter"`
|
||||
Driver string `json:"driver"`
|
||||
Model string `json:"model"`
|
||||
Enclosure int `json:"enclousure"`
|
||||
Size int64 `json:"size"`
|
||||
MinStripSize int64 `json:"min_strip_size,omitempty"`
|
||||
MaxStripSize int64 `json:"max_strip_size,omitempty"`
|
||||
Index int64 `json:"index"`
|
||||
}
|
||||
|
||||
type BaremetalDiskConfig struct {
|
||||
// disk type
|
||||
Type string `json:"type"`
|
||||
// raid config
|
||||
Conf string `json:"conf"`
|
||||
Count int64 `json:"count"`
|
||||
Range []int64 `json:"range"`
|
||||
Splits string `json:"splits"`
|
||||
Adapter *int `json:"adapter"`
|
||||
Driver string `json:"driver"`
|
||||
Cachedbadbbu bool `json:"cachedbadbbu"`
|
||||
Strip int64 `json:"strip"`
|
||||
RA bool `json:"ra"`
|
||||
WT bool `json:"wt"`
|
||||
Direct bool `json:"direct"`
|
||||
}
|
||||
|
||||
+8
-8
@@ -8,7 +8,7 @@ import (
|
||||
fjson "github.com/json-iterator/go"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/api"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/cache"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/cache/db"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/core"
|
||||
@@ -18,12 +18,12 @@ import (
|
||||
type BaremetalDesc struct {
|
||||
baseHostDesc
|
||||
|
||||
Storages []*api.BaremetalStorage `json:"storages"`
|
||||
StorageType string `json:"storage_type"`
|
||||
StorageSize int64 `json:"storage_size"`
|
||||
StorageInfo string `json:"storage_info"`
|
||||
StorageDriver string `json:"storage_driver"`
|
||||
ServerID string `json:"server_id"`
|
||||
Storages []*baremetal.BaremetalStorage `json:"storages"`
|
||||
StorageType string `json:"storage_type"`
|
||||
StorageSize int64 `json:"storage_size"`
|
||||
StorageInfo string `json:"storage_info"`
|
||||
StorageDriver string `json:"storage_driver"`
|
||||
ServerID string `json:"server_id"`
|
||||
}
|
||||
|
||||
type BaremetalBuilder struct {
|
||||
@@ -234,7 +234,7 @@ func (bb *BaremetalBuilder) buildOne(bm *models.Host) (interface{}, error) {
|
||||
desc.HostType = bm.HostType
|
||||
desc.IsBaremetal = bm.IsBaremetal
|
||||
|
||||
var baremetalStorages []*api.BaremetalStorage
|
||||
var baremetalStorages []*baremetal.BaremetalStorage
|
||||
err := fjson.Unmarshal([]byte(bm.StorageInfo), &baremetalStorages)
|
||||
if err != nil {
|
||||
// StorageInfo maybe is NULL
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
package baremetal // import "yunion.io/x/onecloud/pkg/scheduler/util/baremetal"
|
||||
+8
@@ -486,6 +486,14 @@ func GetBytes(sizeStr string) (int64, error) {
|
||||
return GetSize(sizeStr, "", 1024)
|
||||
}
|
||||
|
||||
func GetSizeGB(sizeStr, defaultSize string) (int64, error) {
|
||||
bytes, err := GetSizeBytes(sizeStr, defaultSize)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return bytes / 1024 / 1024 / 1024, nil
|
||||
}
|
||||
|
||||
func GetSizeMB(sizeStr, defaultSize string) (int64, error) {
|
||||
bytes, err := GetSizeBytes(sizeStr, defaultSize)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user