From 03868d28b5216d339f35b2e3cde78d3790028a3e Mon Sep 17 00:00:00 2001 From: Rain Date: Fri, 17 Apr 2020 19:02:39 +0800 Subject: [PATCH] fix(region): Fix some problem for Auto Scaling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 主机组的 vpc 和 backendgroup 可以为空,修复了使用 brand 过滤出现的问题 2. ScalingPolicy 的执行,区分手动和非手动 3. 拒绝执行或者执行失败的 ScalingAvtivity 不刷新冷却时间 4. 告警策略增加 Cycle 的检查和默认值 5. 修复 monitor 的一个数组越界问题 --- pkg/compute/models/scaling_group.go | 21 +++++++++++++------ pkg/compute/models/scaling_policy.go | 8 +++---- pkg/compute/models/scaling_trigger.go | 6 ++++++ .../tasks/guest_detach_scalinggroup.go | 2 +- pkg/controller/autoscaling/timer.go | 1 - pkg/monitor/alerting/conditions/query.go | 6 +++++- 6 files changed, 31 insertions(+), 13 deletions(-) diff --git a/pkg/compute/models/scaling_group.go b/pkg/compute/models/scaling_group.go index 7be241303f..8e415ef9bf 100644 --- a/pkg/compute/models/scaling_group.go +++ b/pkg/compute/models/scaling_group.go @@ -298,6 +298,11 @@ func (sg *SScalingGroup) ScalingPolicies() ([]SScalingPolicy, error) { func (sgm *SScalingGroupManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.ScalingGroupListInput) (*sqlchemy.SQuery, error) { + // hack + // vpc and backendgroup may be empty, and these subresoruce shouldn't be fiter by brand + brand := input.Brand + input.Brand = "" + q, err := sgm.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, input.RegionalFilterListInput) if err != nil { return q, err @@ -325,9 +330,10 @@ func (sgm *SScalingGroupManager) ListItemFilter(ctx context.Context, q *sqlchemy if len(input.Hypervisor) > 0 { q = q.Equals("hypervisor", input.Hypervisor) } - if len(input.Brand) > 0 { + if len(brand) > 0 { q = q.Equals("hypervisor", Brand2Hypervisor(input.Brand)) } + input.Brand = brand return q, nil } @@ -491,27 +497,30 @@ func (sg *SScalingGroup) exec(ctx context.Context, action IScalingAction) (ret s // Scale will modify SScalingGroup.DesireInstanceNumber and generate SScalingActivity based on the trigger and its // corresponding SScalingPolicy. -func (sg *SScalingGroup) Scale(ctx context.Context, triggerDesc IScalingTriggerDesc, action IScalingAction) error { +func (sg *SScalingGroup) Scale(ctx context.Context, triggerDesc IScalingTriggerDesc, action IScalingAction) (bool, error) { + isExec := false if sg.Enabled.IsFalse() { - return nil + return isExec, nil } scalingActivity, err := ScalingActivityManager.CreateScalingActivity(sg.Id, triggerDesc.TriggerDescription(), api.SA_STATUS_EXEC) if err != nil { - return errors.Wrapf(err, "create ScalingActivity whose ScalingGroup is %s error", sg.Id) + return isExec, errors.Wrapf(err, "create ScalingActivity whose ScalingGroup is %s error", sg.Id) } if action.CheckCoolTime() && !sg.AllowScale() { err = scalingActivity.SetReject("", fmt.Sprintf("The Cooling Time limit the execution time of the policy to at least: %s", sg.AllowScaleTime)) - return nil + return isExec, nil } ret := sg.exec(ctx, action) switch ret.code { case 0: err = scalingActivity.SetResult(ret.actionStr, api.SA_STATUS_SUCCEED, "", ret.intanceNum) + isExec = true case 1: err = scalingActivity.SetResult(ret.actionStr, api.SA_STATUS_PART_SUCCEED, ret.reason, ret.intanceNum) + isExec = true case 2: err = scalingActivity.SetReject("", ret.reason) case 3: @@ -521,7 +530,7 @@ func (sg *SScalingGroup) Scale(ctx context.Context, triggerDesc IScalingTriggerD if err != nil { log.Errorf("ScalingActivity set result failed: %s", err.Error()) } - return nil + return isExec, nil } func (sgm *SScalingGroupManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { diff --git a/pkg/compute/models/scaling_policy.go b/pkg/compute/models/scaling_policy.go index 335656264c..187f70c87f 100644 --- a/pkg/compute/models/scaling_policy.go +++ b/pkg/compute/models/scaling_policy.go @@ -374,8 +374,8 @@ func (sp *SScalingPolicy) PerformTrigger(ctx context.Context, userCred mcclient. return nil, nil } - unmanual, _ := data.Bool("unmanual") - if !unmanual { + manual, _ := data.Bool("manual") + if manual { triggerDesc = SScalingManual{SScalingPolicyBase{sp.Id}} } else { trigger, err := sp.Trigger(nil) @@ -393,11 +393,11 @@ func (sp *SScalingPolicy) PerformTrigger(ctx context.Context, userCred mcclient. } triggerDesc = trigger } - err = sg.Scale(ctx, triggerDesc, sp) + isExec, err := sg.Scale(ctx, triggerDesc, sp) if err != nil { return nil, errors.Wrap(err, "ScalingPolicy.Scale") } - if sp.CoolingTime > 0 { + if isExec && sp.CoolingTime > 0 { sg.SetAllowScaleTime(time.Now().Add(time.Duration(sp.CoolingTime) * time.Second)) } return nil, err diff --git a/pkg/compute/models/scaling_trigger.go b/pkg/compute/models/scaling_trigger.go index 757ba4a474..ffdea7e8c4 100644 --- a/pkg/compute/models/scaling_trigger.go +++ b/pkg/compute/models/scaling_trigger.go @@ -382,6 +382,9 @@ func (sa *SScalingAlarm) ValidateCreateData(input api.ScalingPolicyCreateInput) if len(input.Alarm.Operator) == 0 { input.Alarm.Operator = api.OPERATOR_GT } + if input.Alarm.Cycle == 0 { + input.Alarm.Cycle = 300 + } if !utils.IsInStringArray(input.Alarm.Operator, []string{api.OPERATOR_GT, api.OPERATOR_LT}) { return input, httperrors.NewInputParameterError("unkown operator in alarm %s", input.Alarm.Operator) } @@ -392,6 +395,9 @@ func (sa *SScalingAlarm) ValidateCreateData(input api.ScalingPolicyCreateInput) if !utils.IsInStringArray(input.Alarm.Wrapper, []string{api.WRAPPER_MIN, api.WRAPPER_MAX, api.WRAPPER_AVER}) { return input, httperrors.NewInputParameterError("unkown wrapper in alarm %s", input.Alarm.Wrapper) } + if input.Alarm.Cycle < 300 { + return input, httperrors.NewInputParameterError("the min value of cycle in alarm is 300") + } return input, nil } diff --git a/pkg/compute/tasks/guest_detach_scalinggroup.go b/pkg/compute/tasks/guest_detach_scalinggroup.go index 5333b89523..41d5dd04d7 100644 --- a/pkg/compute/tasks/guest_detach_scalinggroup.go +++ b/pkg/compute/tasks/guest_detach_scalinggroup.go @@ -120,7 +120,7 @@ func (self *GuestDetachScalingGroupTask) OnDeleteGuestComplete(ctx context.Conte logclient.AddActionLogWithStartable(self, sg, logclient.ACT_REMOVE_GUEST, fmt.Sprintf("Instance '%s' was removed", guestId), self.UserCred, true) if auto, _ := self.Params.Bool("auto"); !auto { // scale; change the desire number - err := sg.Scale(ctx, SScalingTriggerDesc{guestName}, SScalingActionDesc{}) + _, err := sg.Scale(ctx, SScalingTriggerDesc{guestName}, SScalingActionDesc{}) if err != nil { log.Errorf("ScalingGroup '%s' scale after removing instance '%s' failed: %s", sg.GetId(), guestId, err.Error()) } diff --git a/pkg/controller/autoscaling/timer.go b/pkg/controller/autoscaling/timer.go index 30f64de3c4..770dfca131 100644 --- a/pkg/controller/autoscaling/timer.go +++ b/pkg/controller/autoscaling/timer.go @@ -62,7 +62,6 @@ func (asc *SASController) Timer(ctx context.Context, userCred mcclient.TokenCred log.Debugf("timeScope: start: %s, end: %s", timeScope.Start, timeScope.End) session := auth.GetSession(ctx, userCred, "", "") triggerParams := jsonutils.NewDict() - triggerParams.Set("unmanual", jsonutils.JSONTrue) for i := range scalingTimers { scalingTimer := scalingTimers[i] asc.timerQueue <- struct{}{} diff --git a/pkg/monitor/alerting/conditions/query.go b/pkg/monitor/alerting/conditions/query.go index 3d7bbbb17b..2abb9c06d7 100644 --- a/pkg/monitor/alerting/conditions/query.go +++ b/pkg/monitor/alerting/conditions/query.go @@ -119,8 +119,12 @@ func (c *QueryCondition) Eval(context *alerting.EvalContext) (*alerting.Conditio evalMatchCount++ } tags := c.filterTags(series.Tags) + var meta *tsdb.QueryResultMeta + if len(metas) > idx { + meta = &metas[idx] + } matches = append(matches, &monitor.EvalMatch{ - Condition: c.GenerateFormatCond(&metas[idx]).String(), + Condition: c.GenerateFormatCond(meta).String(), Metric: series.Name, Value: reducedValue, Tags: tags,