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:
李泽玺
2018-09-15 10:16:30 +08:00
26 changed files with 903 additions and 246 deletions
Generated
+2 -2
View File
@@ -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"
+4
View File
@@ -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
+4
View File
@@ -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
+5
View File
@@ -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
}
@@ -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",
+1
View File
@@ -0,0 +1 @@
package baremetal // import "yunion.io/x/onecloud/pkg/compute/baremetal"
+119
View File
@@ -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"`
}
+16 -5
View File
@@ -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))
}
}
+4 -2
View File
@@ -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)
+14 -4
View File
@@ -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
View File
@@ -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
}
+11
View File
@@ -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
}
+63 -7
View File
@@ -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
View File
@@ -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
}
}
+55 -2
View File
@@ -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")
+3
View File
@@ -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())
}
+115
View File
@@ -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
}
+4 -1
View File
@@ -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
}
+223
View File
@@ -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))
+8 -6
View File
@@ -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
-62
View File
@@ -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
View File
@@ -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
View File
@@ -1 +0,0 @@
package baremetal // import "yunion.io/x/onecloud/pkg/scheduler/util/baremetal"
+8
View File
@@ -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 {