mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-05-09 07:02:06 +08:00
221 lines
5.8 KiB
Go
221 lines
5.8 KiB
Go
// Copyright 2019 Yunion
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package balancer
|
|
|
|
import (
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/errors"
|
|
"yunion.io/x/pkg/util/sets"
|
|
|
|
"yunion.io/x/onecloud/pkg/apis/monitor"
|
|
"yunion.io/x/onecloud/pkg/monitor/tsdb"
|
|
)
|
|
|
|
func setHostCurrent(host IHost, vals map[string]float64, key string) error {
|
|
val, ok := vals[key]
|
|
if !ok {
|
|
return errors.Errorf("not found %q in vals %#v", key, vals)
|
|
}
|
|
host.SetCurrent(val)
|
|
return nil
|
|
}
|
|
|
|
type cpuUsageActive struct{}
|
|
|
|
func newCPUUsageActive() IMetricDriver {
|
|
return &cpuUsageActive{}
|
|
}
|
|
|
|
func (c *cpuUsageActive) GetType() monitor.MigrationAlertMetricType {
|
|
return monitor.MigrationAlertMetricTypeCPUUsageActive
|
|
}
|
|
|
|
func (c *cpuUsageActive) GetTsdbQuery() *TsdbQuery {
|
|
return &TsdbQuery{
|
|
Database: monitor.METRIC_DATABASE_TELE,
|
|
Measurement: "cpu",
|
|
Fields: []string{"usage_active"},
|
|
}
|
|
}
|
|
|
|
func (c *cpuUsageActive) GetCandidate(obj jsonutils.JSONObject, host IHost, ds *tsdb.DataSource) (ICandidate, error) {
|
|
return newCPUCandidate(obj, host.GetHostResource(), ds)
|
|
}
|
|
|
|
func (c *cpuUsageActive) SetHostCurrent(host IHost, vals map[string]float64) error {
|
|
return setHostCurrent(host, vals, "usage_active")
|
|
}
|
|
|
|
func (c *cpuUsageActive) GetTarget(host jsonutils.JSONObject) (ITarget, error) {
|
|
return newTargetCPUHost(host)
|
|
}
|
|
|
|
func (ma *cpuUsageActive) GetCondition(s *monitor.AlertSetting) (ICondition, error) {
|
|
t, err := GetAlertSettingThreshold(s)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "GetAlertSettingThreshold")
|
|
}
|
|
return newCPUCond(t), nil
|
|
}
|
|
|
|
// cpuCondition implements ICondition
|
|
type cpuCondition struct {
|
|
value float64
|
|
}
|
|
|
|
func newCPUCond(val float64) ICondition {
|
|
return &cpuCondition{
|
|
value: val,
|
|
}
|
|
}
|
|
|
|
func (c *cpuCondition) GetThreshold() float64 {
|
|
return c.value
|
|
}
|
|
|
|
func (c *cpuCondition) GetSourceThresholdDelta(threshold float64, host IHost) float64 {
|
|
// cpu.usage_active
|
|
return host.GetCurrent() - threshold
|
|
}
|
|
|
|
func (m *cpuCondition) IsFitTarget(settings *monitor.MigrationAlertSettings, t ITarget, c ICandidate) error {
|
|
src := settings.Source
|
|
srcHostIds := []string{}
|
|
if src != nil {
|
|
srcHostIds = src.HostIds
|
|
}
|
|
tCPUCnt := t.(*targetCPUHost).GetCPUCount()
|
|
tScore := t.GetCurrent() + c.(*cpuCandidate).getTargetScore(tCPUCnt)
|
|
ltThreshold := tScore < m.GetThreshold()
|
|
if ltThreshold {
|
|
return nil
|
|
}
|
|
|
|
MAX_THRESHOLD := 95.0
|
|
// only when srcHostIds isn't empty
|
|
if len(srcHostIds) != 0 {
|
|
if !ltThreshold && !sets.NewString(srcHostIds...).Has(t.GetId()) && tScore < MAX_THRESHOLD {
|
|
// if target host is not in source specified hosts and calculated score is less than MAX_THRESHOLD
|
|
log.Infof("let host:%s:current(%f) + guest:%s:score(%f) < MAX_THRESHOLD(%f) to fit target, because it's not in source specified hosts", t.GetName(), t.GetCurrent(), c.GetName(), c.GetScore(), MAX_THRESHOLD)
|
|
return nil
|
|
}
|
|
}
|
|
return errors.Errorf("host:%s:current(%f) + guest:%s:score(%f) >= threshold(%f)", t.GetName(), t.GetCurrent(), c.GetName(), c.GetScore(), m.GetThreshold())
|
|
}
|
|
|
|
// cpuCandidate implements ICandidate
|
|
type cpuCandidate struct {
|
|
*guestResource
|
|
usageActive float64
|
|
guestCPUCount int
|
|
hostCPUCount int
|
|
}
|
|
|
|
func newCPUCandidate(gst jsonutils.JSONObject, host *HostResource, ds *tsdb.DataSource) (ICandidate, error) {
|
|
res, err := newGuestResource(gst, host.GetName())
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "newGuestResource")
|
|
}
|
|
|
|
gstCPUCount, err := res.guest.Int("vcpu_count")
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "get vcpu_count")
|
|
}
|
|
|
|
// fetch metric from influxdb
|
|
metrics, err := InfluxdbQuery(ds, "vm_id", []IResource{res}, &TsdbQuery{
|
|
Database: monitor.METRIC_DATABASE_TELE,
|
|
Measurement: "vm_cpu",
|
|
Fields: []string{"usage_active"},
|
|
})
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "InfluxdbQuery guest %q(%q)", res.GetName(), res.GetId())
|
|
}
|
|
|
|
metric := metrics.Get(res.GetId())
|
|
if metric == nil {
|
|
return nil, errors.Errorf("not found resource %q metric from %#v", res.GetId(), metrics.indexes)
|
|
}
|
|
usage := metric.Values["usage_active"]
|
|
return &cpuCandidate{
|
|
guestResource: res,
|
|
usageActive: usage,
|
|
guestCPUCount: int(gstCPUCount),
|
|
hostCPUCount: int(host.cpuCount),
|
|
}, nil
|
|
}
|
|
|
|
func (c cpuCandidate) GetScore() float64 {
|
|
return c.getTargetScore(c.hostCPUCount)
|
|
}
|
|
|
|
func (c cpuCandidate) getTargetScore(tCPUCnt int) float64 {
|
|
score := c.usageActive * (float64(c.guestCPUCount) / float64(tCPUCnt))
|
|
return score
|
|
}
|
|
|
|
type cpuHost struct {
|
|
*HostResource
|
|
usageActive float64
|
|
}
|
|
|
|
func newCPUHost(obj jsonutils.JSONObject) (IHost, error) {
|
|
host, err := newHostResource(obj)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "newHostResource")
|
|
}
|
|
return &cpuHost{
|
|
HostResource: host,
|
|
}, nil
|
|
}
|
|
|
|
func (h *cpuHost) GetCurrent() float64 {
|
|
return h.usageActive
|
|
}
|
|
|
|
func (h *cpuHost) SetCurrent(val float64) IHost {
|
|
h.usageActive = val
|
|
return h
|
|
}
|
|
|
|
func (h *cpuHost) Compare(oh IHost) bool {
|
|
return h.GetCurrent() < oh.GetCurrent()
|
|
}
|
|
|
|
type targetCPUHost struct {
|
|
IHost
|
|
}
|
|
|
|
func newTargetCPUHost(obj jsonutils.JSONObject) (ITarget, error) {
|
|
host, err := newCPUHost(obj)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "newCPUHost")
|
|
}
|
|
ts := &targetCPUHost{
|
|
IHost: host,
|
|
}
|
|
return ts, nil
|
|
}
|
|
|
|
func (ts *targetCPUHost) Selected(c ICandidate) ITarget {
|
|
ts.SetCurrent(ts.GetCurrent() + c.GetScore())
|
|
return ts
|
|
}
|
|
|
|
func (ts *targetCPUHost) GetCPUCount() int {
|
|
return int(ts.IHost.(*cpuHost).cpuCount)
|
|
}
|