mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-08-29 03:51:54 +08:00
fix(scheduler): storage predicate add actualCapacity filter
This commit is contained in:
@@ -61,7 +61,7 @@ func init() {
|
||||
ID string `help:"ID or Name of storage to update"`
|
||||
Name string `help:"New Name of storage"`
|
||||
Desc string `help:"Description"`
|
||||
CommitBound float64 `help:"Upper bound of storage overcommit rate"`
|
||||
CommitBound float64 `help:"Upper bound of storage overcommit rate" json:"cmtbound"`
|
||||
MediumType string `help:"Medium type" choices:"ssd|rotate"`
|
||||
RbdRadosMonOpTimeout int64 `help:"ceph rados_mon_op_timeout"`
|
||||
RbdRadosOsdOpTimeout int64 `help:"ceph rados_osd_op_timeout"`
|
||||
|
||||
@@ -22,7 +22,7 @@ var (
|
||||
|
||||
func init() {
|
||||
Storages = NewComputeManager("storage", "storages",
|
||||
[]string{"ID", "Name", "Capacity", "Status", "Used_capacity", "Waste_capacity", "Free_capacity", "Storage_type", "Medium_type", "Virtual_capacity", "commit_bound", "commit_rate", "Enabled", "public_scope"},
|
||||
[]string{"ID", "Name", "Capacity", "Actual_capacity_used", "Status", "Used_capacity", "Waste_capacity", "Free_capacity", "Storage_type", "Medium_type", "Virtual_capacity", "commit_bound", "commit_rate", "Enabled", "public_scope"},
|
||||
[]string{})
|
||||
|
||||
registerCompute(&Storages)
|
||||
|
||||
@@ -72,11 +72,26 @@ func (p *StoragePredicate) Execute(u *core.Unit, c core.Candidater) (bool, []cor
|
||||
return false
|
||||
}
|
||||
|
||||
getStorageCapacity := func(backend string, reqMaxSize int64, reqTotalSize int64, useRsvd bool) (int64, int64) {
|
||||
totalFree := getter.GetFreeStorageSizeOfType(backend, useRsvd)
|
||||
capacity := totalFree / utils.Max(reqTotalSize, 1)
|
||||
type storageCapacity struct {
|
||||
capacity int64
|
||||
free int64
|
||||
isActual bool
|
||||
}
|
||||
|
||||
return capacity, totalFree
|
||||
newStorageCapacity := func(capacity int64, free int64, isActual bool) *storageCapacity {
|
||||
return &storageCapacity{
|
||||
capacity: capacity,
|
||||
free: free,
|
||||
isActual: isActual,
|
||||
}
|
||||
}
|
||||
|
||||
getStorageCapacity := func(backend string, reqMaxSize int64, reqTotalSize int64, useRsvd bool) (*storageCapacity, *storageCapacity) {
|
||||
totalFree, actualFree := getter.GetFreeStorageSizeOfType(backend, useRsvd)
|
||||
reqTotalSize = utils.Max(reqTotalSize, 1)
|
||||
capacity := totalFree / reqTotalSize
|
||||
actualCapacity := actualFree / reqTotalSize
|
||||
return newStorageCapacity(capacity, totalFree, false), newStorageCapacity(actualCapacity, actualFree, true)
|
||||
}
|
||||
|
||||
getReqSizeStr := func(backend string) string {
|
||||
@@ -90,15 +105,21 @@ func (p *StoragePredicate) Execute(u *core.Unit, c core.Candidater) (bool, []cor
|
||||
return strings.Join(ss, "+")
|
||||
}
|
||||
|
||||
getStorageFreeStr := func(backend string, useRsvd bool) string {
|
||||
getStorageFreeStr := func(backend string, useRsvd bool, isActual bool) string {
|
||||
ss := []string{}
|
||||
for _, s := range getter.Storages() {
|
||||
if s.StorageType == backend {
|
||||
total := int64(float32(s.Capacity) * s.Cmtbound)
|
||||
used := s.GetUsedCapacity(tristate.True)
|
||||
waste := s.GetUsedCapacity(tristate.False)
|
||||
free := total - int64(used) - int64(waste)
|
||||
ss = append(ss, fmt.Sprintf("(%v-%v-%v=%v)", total, used, waste, free))
|
||||
if isActual {
|
||||
total := s.Capacity
|
||||
free := total - s.ActualCapacityUsed
|
||||
ss = append(ss, fmt.Sprintf("actual_total:%d - actual_used:%d = free:%d", total, s.ActualCapacityUsed, free))
|
||||
} else {
|
||||
total := int64(float32(s.Capacity) * s.Cmtbound)
|
||||
used := s.GetUsedCapacity(tristate.True)
|
||||
waste := s.GetUsedCapacity(tristate.False)
|
||||
free := total - int64(used) - int64(waste)
|
||||
ss = append(ss, fmt.Sprintf("total:%d - used:%d - waste:%d = free:%d", total, used, waste, free))
|
||||
}
|
||||
}
|
||||
}
|
||||
return strings.Join(ss, " + ")
|
||||
@@ -130,14 +151,28 @@ func (p *StoragePredicate) Execute(u *core.Unit, c core.Candidater) (bool, []cor
|
||||
|
||||
useRsvd := h.UseReserved()
|
||||
minCapacity := int64(0xFFFFFFFF)
|
||||
for be, req := range sizeRequest {
|
||||
capacity, totalFree := getStorageCapacity(be, req["max"], req["total"], useRsvd)
|
||||
if capacity == 0 {
|
||||
s := fmt.Sprintf("no enough %q storage, req=%v(%v), free=%v(%v)",
|
||||
be, req["total"], getReqSizeStr(be), totalFree, getStorageFreeStr(be, useRsvd))
|
||||
h.AppendPredicateFailMsg(s)
|
||||
|
||||
appendFailMsg := func(backend string, req map[string]int64, useRsvd bool, capacity *storageCapacity) {
|
||||
reqStr := fmt.Sprintf("no enough %q storage, req=%v(%v)", backend, req["total"], getReqSizeStr(backend))
|
||||
freePrex := "free"
|
||||
isActual := capacity.isActual
|
||||
if isActual {
|
||||
freePrex = "actual_free"
|
||||
}
|
||||
minCapacity = utils.Min(minCapacity, capacity)
|
||||
freeStr := fmt.Sprintf("%s=%v(%v)", freePrex, capacity.free, getStorageFreeStr(backend, useRsvd, isActual))
|
||||
msg := reqStr + ", " + freeStr
|
||||
h.AppendPredicateFailMsg(msg)
|
||||
}
|
||||
|
||||
for be, req := range sizeRequest {
|
||||
capacity, actualCapacity := getStorageCapacity(be, req["max"], req["total"], useRsvd)
|
||||
tmpCap := utils.Min(capacity.capacity, actualCapacity.capacity)
|
||||
if capacity.capacity <= 0 {
|
||||
appendFailMsg(be, req, useRsvd, capacity)
|
||||
} else if actualCapacity.capacity <= 0 {
|
||||
appendFailMsg(be, req, useRsvd, actualCapacity)
|
||||
}
|
||||
minCapacity = utils.Min(minCapacity, tmpCap)
|
||||
}
|
||||
|
||||
h.SetCapacity(minCapacity)
|
||||
|
||||
@@ -53,7 +53,7 @@ type SchedInfo struct {
|
||||
UserCred mcclient.TokenCredential
|
||||
}
|
||||
|
||||
func fetchAuthToken(req *http.Request) (mcclient.TokenCredential, error) {
|
||||
func FetchAuthToken(req *http.Request) (mcclient.TokenCredential, error) {
|
||||
tokenStr := req.Header.Get(identity.AUTH_TOKEN_HEADER)
|
||||
if tokenStr == "" {
|
||||
return nil, errors.Wrap(httperrors.ErrInvalidCredential, "missing token header")
|
||||
@@ -65,11 +65,20 @@ func fetchAuthToken(req *http.Request) (mcclient.TokenCredential, error) {
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func FetchSchedInfo(req *http.Request) (*SchedInfo, error) {
|
||||
token, err := fetchAuthToken(req)
|
||||
func FetchUserCred(req *http.Request) (mcclient.TokenCredential, error) {
|
||||
token, err := FetchAuthToken(req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchAuthToken")
|
||||
}
|
||||
userCred := policy.FilterPolicyCredential(token)
|
||||
return userCred, nil
|
||||
}
|
||||
|
||||
func FetchSchedInfo(req *http.Request) (*SchedInfo, error) {
|
||||
userCred, err := FetchUserCred(req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetch user cred")
|
||||
}
|
||||
|
||||
body, err := appsrv.FetchJSON(req)
|
||||
if err != nil {
|
||||
@@ -84,7 +93,7 @@ func FetchSchedInfo(req *http.Request) (*SchedInfo, error) {
|
||||
input = models.ApplySchedPolicies(input)
|
||||
|
||||
data := NewSchedInfo(input)
|
||||
data.UserCred = policy.FilterPolicyCredential(token)
|
||||
data.UserCred = userCred
|
||||
|
||||
domainId := data.Domain
|
||||
for _, net := range data.Networks {
|
||||
|
||||
+4
-2
@@ -207,14 +207,16 @@ func (b baseHostGetter) TotalMemorySize(_ bool) int64 {
|
||||
return int64(b.h.MemSize)
|
||||
}
|
||||
|
||||
func (b baseHostGetter) GetFreeStorageSizeOfType(storageType string, useRsvd bool) int64 {
|
||||
func (b baseHostGetter) GetFreeStorageSizeOfType(storageType string, useRsvd bool) (int64, int64) {
|
||||
var size int64
|
||||
var actualSize int64
|
||||
for _, s := range b.Storages() {
|
||||
if s.StorageType == storageType {
|
||||
size += int64(float32(s.Capacity) * s.Cmtbound)
|
||||
actualSize += s.Capacity - s.ActualCapacityUsed
|
||||
}
|
||||
}
|
||||
return size
|
||||
return size, actualSize
|
||||
}
|
||||
|
||||
func (b baseHostGetter) GetFreePort(netId string) int {
|
||||
|
||||
+8
-5
@@ -85,7 +85,7 @@ func (h *hostGetter) StorageInfo() []*baremetal.BaremetalStorage {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *hostGetter) GetFreeStorageSizeOfType(storageType string, useRsvd bool) int64 {
|
||||
func (h *hostGetter) GetFreeStorageSizeOfType(storageType string, useRsvd bool) (int64, int64) {
|
||||
return h.h.GetFreeStorageSizeOfType(storageType, useRsvd)
|
||||
}
|
||||
|
||||
@@ -317,15 +317,18 @@ func (h *HostDesc) freeStorageSize(onlyLocal, useRsvd bool) int64 {
|
||||
return total
|
||||
}
|
||||
|
||||
func (h *HostDesc) GetFreeStorageSizeOfType(sType string, useRsvd bool) int64 {
|
||||
func (h *HostDesc) GetFreeStorageSizeOfType(sType string, useRsvd bool) (int64, int64) {
|
||||
return h.freeStorageSizeOfType(sType, useRsvd)
|
||||
}
|
||||
|
||||
func (h *HostDesc) freeStorageSizeOfType(storageType string, useRsvd bool) int64 {
|
||||
func (h *HostDesc) freeStorageSizeOfType(storageType string, useRsvd bool) (int64, int64) {
|
||||
var total int64
|
||||
var actualTotal int64
|
||||
|
||||
for _, storage := range h.Storages {
|
||||
if storage.StorageType == storageType {
|
||||
total += int64(storage.GetFreeCapacity())
|
||||
actualTotal += storage.Capacity - storage.ActualCapacityUsed
|
||||
}
|
||||
}
|
||||
if utils.IsLocalStorage(storageType) {
|
||||
@@ -336,10 +339,10 @@ func (h *HostDesc) freeStorageSizeOfType(storageType string, useRsvd bool) int64
|
||||
}
|
||||
}
|
||||
if useRsvd {
|
||||
return reservedResourceAddCal(total, h.GuestReservedStorageSizeFree(), useRsvd)
|
||||
return reservedResourceAddCal(total, h.GuestReservedStorageSizeFree(), useRsvd), actualTotal
|
||||
}
|
||||
|
||||
return total - int64(h.GetPendingUsage().DiskUsage.Get(storageType))
|
||||
return total - int64(h.GetPendingUsage().DiskUsage.Get(storageType)), actualTotal
|
||||
}
|
||||
|
||||
func (h *HostDesc) GetFreePort(netId string) int {
|
||||
|
||||
@@ -97,7 +97,7 @@ type CandidatePropertyGetter interface {
|
||||
FreeMemorySize(useRsvd bool) int64
|
||||
|
||||
StorageInfo() []*baremetal.BaremetalStorage
|
||||
GetFreeStorageSizeOfType(storageType string, useRsvd bool) int64
|
||||
GetFreeStorageSizeOfType(storageType string, useRsvd bool) (int64, int64)
|
||||
|
||||
GetFreePort(netId string) int
|
||||
|
||||
|
||||
@@ -162,7 +162,13 @@ func doCandidateList(c *gin.Context) {
|
||||
}
|
||||
|
||||
func doCandidateDetail(c *gin.Context, id string) {
|
||||
hs, err := computemodels.HostManager.FetchById(id)
|
||||
userCred, err := api.FetchUserCred(c.Request)
|
||||
if err != nil {
|
||||
c.AbortWithError(http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
hs, err := computemodels.HostManager.FetchByIdOrName(userCred, id)
|
||||
if err != nil {
|
||||
c.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
@@ -176,7 +182,7 @@ func doCandidateDetail(c *gin.Context, id string) {
|
||||
host := hs.(*computemodels.SHost)
|
||||
|
||||
args := new(api.CandidateDetailArgs)
|
||||
args.ID = id
|
||||
args.ID = host.GetId()
|
||||
if host.HostType == computeapi.HOST_TYPE_BAREMETAL {
|
||||
args.Type = api.HostTypeBaremetal
|
||||
} else {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"math"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
@@ -165,11 +166,11 @@ func (mr *MockCandidatePropertyGetterMockRecorder) GetFreePort(arg0 interface{})
|
||||
}
|
||||
|
||||
// GetFreeStorageSizeOfType mocks base method
|
||||
func (m *MockCandidatePropertyGetter) GetFreeStorageSizeOfType(arg0 string, arg1 bool) int64 {
|
||||
func (m *MockCandidatePropertyGetter) GetFreeStorageSizeOfType(arg0 string, arg1 bool) (int64, int64) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetFreeStorageSizeOfType", arg0, arg1)
|
||||
ret0, _ := ret[0].(int64)
|
||||
return ret0
|
||||
return ret0, math.MaxInt64
|
||||
}
|
||||
|
||||
// GetFreeStorageSizeOfType indicates an expected call of GetFreeStorageSizeOfType
|
||||
|
||||
@@ -169,7 +169,7 @@ func buildGetter(ctrl *gomock.Controller, param sGetterParams) *mock.MockCandida
|
||||
cg.EXPECT().FreeCPUCount(gomock.Any()).AnyTimes().Return(param.FreeCPUCount)
|
||||
cg.EXPECT().TotalMemorySize(gomock.Any()).AnyTimes().Return(param.TotalMemorySize)
|
||||
cg.EXPECT().FreeMemorySize(gomock.Any()).AnyTimes().Return(param.FreeMemorySize)
|
||||
cg.EXPECT().GetFreeStorageSizeOfType(gomock.Any(), gomock.Any()).AnyTimes().Return(param.FreeStorageSizeAnyType)
|
||||
cg.EXPECT().GetFreeStorageSizeOfType(gomock.Any(), gomock.Any()).AnyTimes().Return(param.FreeStorageSizeAnyType, int64(0))
|
||||
cg.EXPECT().GetFreePort(gomock.Any()).AnyTimes().Return(param.FreePort)
|
||||
if param.QuotaKeys != nil {
|
||||
cg.EXPECT().GetQuotaKeys(gomock.Any()).AnyTimes().Return(param.QuotaKeys)
|
||||
|
||||
Reference in New Issue
Block a user