diff --git a/pkg/scheduler/algorithm/predicates/error.go b/pkg/scheduler/algorithm/predicates/error.go index 11b8640943..f7b73fc20b 100644 --- a/pkg/scheduler/algorithm/predicates/error.go +++ b/pkg/scheduler/algorithm/predicates/error.go @@ -24,6 +24,7 @@ const ( ErrNoMoreSpaceForUnspecificSplit = `no more space for an unspecific split` ErrSubtotalOfSplitExceedsDiskSize = `subtotal of split exceeds disk size` ErrBaremetalHasAlreadyBeenOccupied = `baremetal has already been occupied` + ErrPrepaidHostOccupied = `prepaid host occupied` ErrUnknown = `unknown error` ) diff --git a/pkg/scheduler/algorithm/predicates/resource_type_predicate.go b/pkg/scheduler/algorithm/predicates/resource_type_predicate.go new file mode 100644 index 0000000000..6406186ee4 --- /dev/null +++ b/pkg/scheduler/algorithm/predicates/resource_type_predicate.go @@ -0,0 +1,48 @@ +package predicates + +import ( + "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/scheduler/core" +) + +type ResourceTypePredicate struct { + BasePredicate +} + +func (p *ResourceTypePredicate) Name() string { + return "resource_type" +} + +func (p *ResourceTypePredicate) Clone() core.FitPredicate { + return &ResourceTypePredicate{} +} + +func (p *ResourceTypePredicate) PreExecute(u *core.Unit, cs []core.Candidater) (bool, error) { + if u.SchedData().ResourceType == "" { + return false, nil + } + return true, nil +} + +func (p *ResourceTypePredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.PredicateFailureReason, error) { + h := NewPredicateHelper(p, u, c) + + d := u.SchedData() + + hostResType := c.GetResourceType() + reqResType := d.ResourceType + if hostResType != reqResType { + h.Exclude2("resource_type", hostResType, reqResType) + } + + if reqResType == models.HostResourceTypePrepaidRecycle { + if c.GetGuestCount() == 0 { + h.SetCapacity(1) + } else { + h.Exclude(ErrPrepaidHostOccupied) + } + } + // TODO: support HostResourceTypeDedicated + + return h.GetResult() +} diff --git a/pkg/scheduler/algorithmprovider/baremetal.go b/pkg/scheduler/algorithmprovider/baremetal.go index 8850607b98..f2cd386339 100644 --- a/pkg/scheduler/algorithmprovider/baremetal.go +++ b/pkg/scheduler/algorithmprovider/baremetal.go @@ -20,5 +20,6 @@ func baremetalPredicates() sets.String { factory.RegisterFitPredicate("d-BaremetalMemoryFilter", &predicatebm.MemoryPredicate{}), factory.RegisterFitPredicate("e-BaremetalStorageFilter", &predicatebm.StoragePredicate{}), factory.RegisterFitPredicate("f-BaremetalNetFilter", &predicatebm.NetworkPredicate{}), + factory.RegisterFitPredicate("g-BaremetalResourceTypeFilter", &predicates.ResourceTypePredicate{}), ) } diff --git a/pkg/scheduler/algorithmprovider/defaults.go b/pkg/scheduler/algorithmprovider/defaults.go index 7aab7ef437..6da42fc24b 100644 --- a/pkg/scheduler/algorithmprovider/defaults.go +++ b/pkg/scheduler/algorithmprovider/defaults.go @@ -25,6 +25,7 @@ func defaultPredicates() sets.String { factory.RegisterFitPredicate("i-GuestStorageFilter", &predicateguest.StoragePredicate{}), factory.RegisterFitPredicate("j-GuestNetworkFilter", &predicateguest.NetworkPredicate{}), factory.RegisterFitPredicate("k-GuestIsolatedDeviceFilter", &predicateguest.IsolatedDevicePredicate{}), + factory.RegisterFitPredicate("l-GuestResourceTypeFilter", &predicates.ResourceTypePredicate{}), ) } diff --git a/pkg/scheduler/api/sched.go b/pkg/scheduler/api/sched.go index f75caf556a..ca8634d981 100644 --- a/pkg/scheduler/api/sched.go +++ b/pkg/scheduler/api/sched.go @@ -94,6 +94,7 @@ type SchedData struct { ForGuests []*ForGuest `json:"for_guests"` GuestStatus string `json:"guest_status"` Hypervisor string `json:"hypervisor"` + ResourceType string `json:"resource_type"` // VM Groups []string `json:"group"` @@ -168,6 +169,10 @@ func NewSchedData(sjson *simplejson.Json, count int64, byTest bool) (*SchedData, } } + if resourceType, ok := sjson.CheckGet("resource_type"); ok { + data.ResourceType = resourceType.MustString() + } + data.Candidates = candidates err := data.reviseSchedType(sjson) diff --git a/pkg/scheduler/api/types.go b/pkg/scheduler/api/types.go index bfcc540ee3..2a2cca01ce 100644 --- a/pkg/scheduler/api/types.go +++ b/pkg/scheduler/api/types.go @@ -4,6 +4,8 @@ import ( "fmt" "yunion.io/x/pkg/util/sets" + + "yunion.io/x/onecloud/pkg/compute/models" ) const ( @@ -16,10 +18,6 @@ const ( SchedTypeHyperV = "hyperv" SchedTypeKvm = "kvm" HostHypervisorForKvm = "hypervisor" - HostTypeAliyun = "aliyun" - HostTypeAzure = "azure" - HostTypeAws = "aws" - HostTypeQcloud = "qcloud" HostTypeKubelet = "kubelet" AggregateStrategyRequire = "require" @@ -49,12 +47,7 @@ var ( AggregateStrategyAvoid, ) - PublicCloudProviders = sets.NewString( - HostTypeAliyun, - HostTypeAzure, - HostTypeAws, - HostTypeQcloud, - ) + PublicCloudProviders = sets.NewString(models.PUBLIC_CLOUD_HYPERVISORS...) ValidGpuTypes = sets.NewString( GPU_HPC_TYPE, diff --git a/pkg/scheduler/cache/candidate/baremetals.go b/pkg/scheduler/cache/candidate/baremetals.go index 88910cb4a0..9ab2489da5 100644 --- a/pkg/scheduler/cache/candidate/baremetals.go +++ b/pkg/scheduler/cache/candidate/baremetals.go @@ -104,6 +104,13 @@ func (bd *BaremetalDesc) Get(key string) interface{} { } } +func (bd *BaremetalDesc) GetGuestCount() int64 { + if bd.ServerID == "" { + return 0 + } + return 1 +} + func (bd *BaremetalDesc) XGet(key string, kind core.Kind) interface{} { return core.XGetCalculator(bd, key, kind) } diff --git a/pkg/scheduler/cache/candidate/desc.go b/pkg/scheduler/cache/candidate/desc.go index 5aaeb1506b..5779b97cf1 100644 --- a/pkg/scheduler/cache/candidate/desc.go +++ b/pkg/scheduler/cache/candidate/desc.go @@ -8,6 +8,7 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/utils" + cloudmodels "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/scheduler/api" "yunion.io/x/onecloud/pkg/scheduler/db/models" ) @@ -24,6 +25,7 @@ func (b *baseDesc) UUID() string { type baseHostDesc struct { baseDesc + models.BillingResourceBase ManagerID *string `json:"manager_id"` Status string `json:"status"` @@ -44,6 +46,15 @@ type baseHostDesc struct { Aggregates []*models.Aggregate `json:"aggregates"` HostAggregates []*models.Aggregate `json:"host_aggregates"` Cloudprovider *models.Cloudprovider `json:"cloudprovider"` + ResourceType string `json:"resource_type"` + RealExternalId string `json:"real_external_id"` +} + +func reviseResourceType(resType string) string { + if resType == "" { + return cloudmodels.HostResourceTypeDefault + } + return resType } func newBaseHostDesc(host *models.Host) (*baseHostDesc, error) { @@ -53,16 +64,19 @@ func newBaseHostDesc(host *models.Host) (*baseHostDesc, error) { Name: host.Name, UpdatedAt: host.UpdatedAt, }, - ManagerID: host.ManagerID, - Status: host.Status, - CPUCount: host.CPUCount, - MemSize: host.MemSize, - HostStatus: host.HostStatus, - Enabled: host.Enabled, - HostType: host.HostType, - IsBaremetal: host.IsBaremetal, - NodeCount: host.NodeCount, - IsMaintenance: host.IsMaintenance, + BillingResourceBase: host.BillingResourceBase, + ManagerID: host.ManagerID, + Status: host.Status, + CPUCount: host.CPUCount, + MemSize: host.MemSize, + HostStatus: host.HostStatus, + Enabled: host.Enabled, + HostType: host.HostType, + IsBaremetal: host.IsBaremetal, + NodeCount: host.NodeCount, + IsMaintenance: host.IsMaintenance, + ResourceType: reviseResourceType(host.ResourceType), + RealExternalId: host.RealExternalId, } if err := desc.fillCloudProvider(host); err != nil { @@ -97,6 +111,7 @@ func (b baseHostDesc) GetSchedDesc() *jsonutils.JSONDict { desc.Add(jsonutils.NewString(b.HostType), "host_type") desc.Add(jsonutils.NewString(b.ZoneID), "zone_id") desc.Add(jsonutils.NewString(b.Zone), "zone") + desc.Add(jsonutils.NewString(b.ResourceType), "resource_type") if b.Cloudprovider != nil { p := b.Cloudprovider @@ -109,6 +124,10 @@ func (b baseHostDesc) GetSchedDesc() *jsonutils.JSONDict { return desc } +func (b baseHostDesc) GetResourceType() string { + return b.ResourceType +} + func (b *baseHostDesc) fillCloudProvider(host *models.Host) error { if host.ManagerID == nil { log.Debugf("Host %q manager id is empty, no cloud provider", host.Name) diff --git a/pkg/scheduler/cache/candidate/hosts.go b/pkg/scheduler/cache/candidate/hosts.go index 841418e9b0..6be549ff64 100644 --- a/pkg/scheduler/cache/candidate/hosts.go +++ b/pkg/scheduler/cache/candidate/hosts.go @@ -224,6 +224,10 @@ func (h *HostDesc) Type() int { return 0 } +func (h *HostDesc) GetGuestCount() int64 { + return h.GuestCount +} + func (h *HostDesc) Get(key string) interface{} { switch key { case "ID": @@ -953,7 +957,7 @@ func (b *HostBuilder) build() ([]interface{}, error) { if len(errs) > 0 { //return nil, errors.NewAggregate(errs) err := errors.NewAggregate(errs) - log.Warningf("Build schedule descs error: %s", err) + log.V(4).Warningf("Build schedule descs error: %s", err) } return schedDescs, nil diff --git a/pkg/scheduler/core/context.go b/pkg/scheduler/core/context.go index abd9f1cd57..de1044dbdc 100644 --- a/pkg/scheduler/core/context.go +++ b/pkg/scheduler/core/context.go @@ -7,6 +7,7 @@ import ( "sync" "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/scheduler/api" ) diff --git a/pkg/scheduler/core/types.go b/pkg/scheduler/core/types.go index e2ca3ab950..7ca0459fc8 100644 --- a/pkg/scheduler/core/types.go +++ b/pkg/scheduler/core/types.go @@ -49,6 +49,8 @@ type Candidater interface { GetHostAggregates() []*models.Aggregate GetSchedDesc() *jsonutils.JSONDict + GetGuestCount() int64 + GetResourceType() string } // HostPriority represents the priority of scheduling to particular host, higher priority is better. diff --git a/pkg/scheduler/db/models/billing.go b/pkg/scheduler/db/models/billing.go new file mode 100644 index 0000000000..3343552562 --- /dev/null +++ b/pkg/scheduler/db/models/billing.go @@ -0,0 +1,11 @@ +package models + +import ( + "time" +) + +type BillingResourceBase struct { + BillingType string `json:"billing_type" gorm:"column:billing_type"` + ExpiredAt time.Time `json:"expired_at" gorm:"column:expired_at;type:datetime"` + BillingCycle string `json:"billing_cycle" gorm:"column:billing_cycle"` +} diff --git a/pkg/scheduler/db/models/host.go b/pkg/scheduler/db/models/host.go index 99311516be..e8d2e13083 100644 --- a/pkg/scheduler/db/models/host.go +++ b/pkg/scheduler/db/models/host.go @@ -20,6 +20,7 @@ var ( type Host struct { StandaloneModel + BillingResourceBase Rack string `json:"rack,omitempty" gorm:"column:rack"` Slots string `json:"slots,omitempty" gorm:"column:slots"` @@ -57,6 +58,9 @@ type Host struct { ManagerID *string `json:"manager_id" gorm:"column:manager_id"` IsMaintenance bool `json:"is_maintenance" gorm:"column:is_maintenance"` + ResourceType string `json:"resource_type" gorm:"column:resource_type"` + RealExternalId string `json:"real_external_id" gorm:"column:real_external_id;type:varchar(256) CHARACTER SET utf8"` + // DECAPITATE ClusterID string `json:"cluster_id" gorm:"column:cluster_id"` PoolID string `json:"pool_id,omitempty" gorm:"column:pool_id"`