diff --git a/cmd/climc/shell/compute/waf_rules.go b/cmd/climc/shell/compute/waf_rules.go index 8fecb87f5d..dbdad794f2 100644 --- a/cmd/climc/shell/compute/waf_rules.go +++ b/cmd/climc/shell/compute/waf_rules.go @@ -29,4 +29,6 @@ func init() { cmd.Show(&options.BaseIdOptions{}) cmd.Delete(&options.BaseIdOptions{}) cmd.Perform("syncstatus", &options.BaseIdOptions{}) + cmd.Perform("enable", &options.BaseIdOptions{}) + cmd.Perform("disable", &options.BaseIdOptions{}) } diff --git a/pkg/apis/compute/waf_rules.go b/pkg/apis/compute/waf_rules.go index a8cf650245..f80057138e 100644 --- a/pkg/apis/compute/waf_rules.go +++ b/pkg/apis/compute/waf_rules.go @@ -16,6 +16,7 @@ package compute import ( "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/apis" ) @@ -32,7 +33,7 @@ const ( ) type WafRuleListInput struct { - apis.StatusStandaloneResourceListInput + apis.EnabledStatusStandaloneResourceListInput apis.ExternalizedResourceBaseListInput // WAF实例Id @@ -43,12 +44,16 @@ type WafRuleListInput struct { } type WafRuleCreateInput struct { - apis.StatusStandaloneResourceCreateInput + apis.EnabledStatusStandaloneResourceCreateInput // WAF实例Id WafInstanceId string `json:"waf_instance_id"` // 规则类型 Type string `json:"type"` + // 规则表达式 + Expression string `json:"expression"` + // 规则配置 + Config jsonutils.JSONObject `json:"config"` // 优先级,不可重复 // Azure优先级范围1-100 @@ -67,14 +72,31 @@ type WafRuleCreateInput struct { } type WafRuleDetails struct { - apis.StatusStandaloneResourceDetails + apis.EnabledStatusStandaloneResourceDetails SWafRule Statements []cloudprovider.SWafStatement } type WafRuleUpdateInput struct { - apis.StatusStandaloneResourceBaseUpdateInput + apis.EnabledStatusStandaloneResourceBaseUpdateInput + // 规则表达式 + Expression string `json:"expression"` + // 规则配置 + Config jsonutils.JSONObject `json:"config"` + // 匹配后默认行为 + Action *cloudprovider.DefaultAction `json:"action"` + // 优先级 + Priority *int `json:"priority"` + // 条件表达式 Statements []cloudprovider.SWafStatement } + +type WafRuleEnableInput struct { + apis.PerformEnableInput +} + +type WafRuleDisableInput struct { + apis.PerformDisableInput +} diff --git a/pkg/compute/models/waf_rules.go b/pkg/compute/models/waf_rules.go index ab7042529b..ad97d6236c 100644 --- a/pkg/compute/models/waf_rules.go +++ b/pkg/compute/models/waf_rules.go @@ -20,10 +20,12 @@ import ( "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/tristate" "yunion.io/x/pkg/util/compare" "yunion.io/x/pkg/util/rbacscope" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" @@ -35,7 +37,7 @@ import ( ) type SWafRuleManager struct { - db.SStatusStandaloneResourceBaseManager + db.SEnabledStatusStandaloneResourceBaseManager db.SExternalizedResourceBaseManager } @@ -43,7 +45,7 @@ var WafRuleManager *SWafRuleManager func init() { WafRuleManager = &SWafRuleManager{ - SStatusStandaloneResourceBaseManager: db.NewStatusStandaloneResourceBaseManager( + SEnabledStatusStandaloneResourceBaseManager: db.NewEnabledStatusStandaloneResourceBaseManager( SWafRule{}, "waf_rules_tbl", "waf_rule", @@ -54,7 +56,7 @@ func init() { } type SWafRule struct { - db.SStatusStandaloneResourceBase + db.SEnabledStatusStandaloneResourceBase db.SExternalizedResourceBase // 规则优先级 @@ -63,7 +65,12 @@ type SWafRule struct { Action *cloudprovider.DefaultAction `charset:"utf8" nullable:"true" list:"user" update:"domain" create:"required"` // 条件 StatementConditon cloudprovider.TWafStatementCondition `width:"20" charset:"ascii" nullable:"false" list:"domain" create:"optional"` - Type string `width:"20" charset:"ascii" nullable:"false" list:"domain" create:"optional"` + // 条件表达式 + Expression string `width:"512" charset:"ascii" nullable:"false" list:"domain" create:"optional"` + // 规则类型 + Type string `width:"20" charset:"ascii" nullable:"false" list:"domain" create:"optional"` + // 规则配置 + Config jsonutils.JSONObject `width:"512" charset:"utf8" nullable:"true" list:"domain" create:"optional"` // 规则组的id WafRuleGroupId string `width:"36" charset:"ascii" nullable:"false" list:"domain" create:"optional"` // 所属waf实例id @@ -153,7 +160,7 @@ func (manager *SWafRuleManager) ValidateCreateData(ctx context.Context, userCred } var err error - input.StatusStandaloneResourceCreateInput, err = manager.SStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StatusStandaloneResourceCreateInput) + input.EnabledStatusStandaloneResourceCreateInput, err = manager.SEnabledStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledStatusStandaloneResourceCreateInput) if err != nil { return input, err } @@ -162,7 +169,7 @@ func (manager *SWafRuleManager) ValidateCreateData(ctx context.Context, userCred } func (self *SWafRule) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { - self.SStatusStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data) + self.SEnabledStatusStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data) input := &api.WafRuleCreateInput{} data.Unmarshal(input) @@ -196,7 +203,7 @@ func (manager *SWafRuleManager) ListItemFilter( ) (*sqlchemy.SQuery, error) { var err error - q, err = manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput) + q, err = manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemFilter") } @@ -233,11 +240,11 @@ func (manager *SWafRuleManager) FetchCustomizeColumns( isList bool, ) []api.WafRuleDetails { rows := make([]api.WafRuleDetails, len(objs)) - stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) ruleIds := make([]string, len(objs)) for i := range rows { rows[i] = api.WafRuleDetails{ - StatusStandaloneResourceDetails: stdRows[i], + EnabledStatusStandaloneResourceDetails: stdRows[i], } ruleIds[i] = objs[i].(*SWafRule).Id } @@ -350,7 +357,7 @@ func (self *SWafRule) ValidateUpdateData(ctx context.Context, userCred mcclient. if len(input.Name) > 0 && input.Name != self.Name { return input, httperrors.NewInputParameterError("Not allow update rule name") } - input.StatusStandaloneResourceBaseUpdateInput, err = self.SStatusStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.StatusStandaloneResourceBaseUpdateInput) + input.EnabledStatusStandaloneResourceBaseUpdateInput, err = self.SEnabledStatusStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.EnabledStatusStandaloneResourceBaseUpdateInput) if err != nil { return input, err } @@ -358,7 +365,7 @@ func (self *SWafRule) ValidateUpdateData(ctx context.Context, userCred mcclient. } func (self *SWafRule) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) { - self.SStatusStandaloneResourceBase.PostUpdate(ctx, userCred, query, data) + self.SEnabledStatusStandaloneResourceBase.PostUpdate(ctx, userCred, query, data) input := api.WafRuleUpdateInput{} data.Unmarshal(&input) @@ -397,6 +404,7 @@ func (self *SWafRule) StartUpdateTask(ctx context.Context, userCred mcclient.Tok func (self *SWafRule) SyncWithCloudRule(ctx context.Context, userCred mcclient.TokenCredential, rule cloudprovider.ICloudWafRule) error { _, err := db.Update(self, func() error { + var err error self.Action = rule.GetAction() self.StatementConditon = rule.GetStatementCondition() self.Priority = rule.GetPriority() @@ -404,6 +412,12 @@ func (self *SWafRule) SyncWithCloudRule(ctx context.Context, userCred mcclient.T self.Status = api.WAF_RULE_STATUS_AVAILABLE self.Name = rule.GetName() self.ExternalId = rule.GetGlobalId() + self.Expression = rule.GetExpression() + self.Config, err = rule.GetConfig() + if err != nil { + return errors.Wrapf(err, "GetConfig") + } + self.Enabled = tristate.NewFromBool(rule.GetEnabled()) return nil }) if err != nil { @@ -424,7 +438,14 @@ func (self *SWafInstance) newFromCloudRule(ctx context.Context, userCred mcclien rule.Priority = ext.GetPriority() rule.Type = ext.GetType() rule.Status = api.WAF_RULE_STATUS_AVAILABLE - err := WafRuleManager.TableSpec().Insert(ctx, rule) + rule.Expression = ext.GetExpression() + var err error + rule.Config, err = ext.GetConfig() + if err != nil { + return errors.Wrapf(err, "GetConfig") + } + rule.Enabled = tristate.NewFromBool(ext.GetEnabled()) + err = WafRuleManager.TableSpec().Insert(ctx, rule) if err != nil { return errors.Wrapf(err, "Insert") } @@ -576,3 +597,31 @@ func (self *SWafRule) GetICloudWafRule(ctx context.Context) (cloudprovider.IClou func (self *SWafRule) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.WafSyncstatusInput) (jsonutils.JSONObject, error) { return nil, StartResourceSyncStatusTask(ctx, userCred, self, "WafRuleSyncstatusTask", "") } + +// 启用 +func (self *SWafRule) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.WafRuleEnableInput) (jsonutils.JSONObject, error) { + _, err := self.SEnabledStatusStandaloneResourceBase.PerformEnable(ctx, userCred, query, input.PerformEnableInput) + if err != nil { + return nil, err + } + return nil, self.StartSetEnabledTask(ctx, userCred, "") +} + +func (self *SWafRule) StartSetEnabledTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error { + params := jsonutils.NewDict() + task, err := taskman.TaskManager.NewTask(ctx, "WafRuleSetEnabledTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return errors.Wrap(err, "NewTask") + } + self.SetStatus(ctx, userCred, apis.STATUS_SYNC_STATUS, "") + return task.ScheduleRun(nil) +} + +// 禁用 +func (self *SWafRule) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.WafRuleDisableInput) (jsonutils.JSONObject, error) { + _, err := self.SEnabledStatusStandaloneResourceBase.PerformDisable(ctx, userCred, query, input.PerformDisableInput) + if err != nil { + return nil, err + } + return nil, self.StartSetEnabledTask(ctx, userCred, "") +} diff --git a/pkg/compute/tasks/waf/waf_rule_create_task.go b/pkg/compute/tasks/waf/waf_rule_create_task.go index f574b48ca6..0445cd0537 100644 --- a/pkg/compute/tasks/waf/waf_rule_create_task.go +++ b/pkg/compute/tasks/waf/waf_rule_create_task.go @@ -55,6 +55,9 @@ func (self *WafRuleCreateTask) OnInit(ctx context.Context, obj db.IStandaloneMod Action: rule.Action, Priority: rule.Priority, Type: rule.Type, + Expression: rule.Expression, + Config: rule.Config, + Enable: rule.Enabled.Bool(), Statements: []cloudprovider.SWafStatement{}, } opts.StatementCondition = rule.StatementConditon diff --git a/pkg/compute/tasks/waf/waf_rule_set_enable_task.go b/pkg/compute/tasks/waf/waf_rule_set_enable_task.go new file mode 100644 index 0000000000..2427c20413 --- /dev/null +++ b/pkg/compute/tasks/waf/waf_rule_set_enable_task.go @@ -0,0 +1,74 @@ +// 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 waf + +import ( + "context" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/onecloud/pkg/apis" + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" + "yunion.io/x/onecloud/pkg/compute/models" +) + +type WafRuleSetEnabledTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(WafRuleSetEnabledTask{}) +} + +func (self *WafRuleSetEnabledTask) taskFailed(ctx context.Context, record *models.SWafRule, err error) { + record.SetStatus(ctx, self.UserCred, apis.STATUS_UNKNOWN, err.Error()) + self.SetStageFailed(ctx, jsonutils.NewString(err.Error())) +} + +func (self *WafRuleSetEnabledTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + record := obj.(*models.SWafRule) + + iRule, err := record.GetICloudWafRule(ctx) + if err != nil { + self.taskFailed(ctx, record, errors.Wrapf(err, "GetICloudWafRule")) + return + } + + if record.Enabled.Bool() { + err = iRule.Enable() + } else { + err = iRule.Disable() + } + + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotSupported { + self.taskComplete(ctx, record) + return + } + self.taskFailed(ctx, record, errors.Wrapf(err, "SetEnabled")) + return + } + + self.taskComplete(ctx, record) +} + +func (self *WafRuleSetEnabledTask) taskComplete(ctx context.Context, record *models.SWafRule) { + record.SetStatus(ctx, self.UserCred, api.WAF_RULE_STATUS_AVAILABLE, "") + self.SetStageComplete(ctx, nil) +} diff --git a/pkg/compute/tasks/waf/waf_rule_update_task.go b/pkg/compute/tasks/waf/waf_rule_update_task.go index 0871717288..553ee3fd80 100644 --- a/pkg/compute/tasks/waf/waf_rule_update_task.go +++ b/pkg/compute/tasks/waf/waf_rule_update_task.go @@ -56,6 +56,9 @@ func (self *WafRuleUpdateTask) OnInit(ctx context.Context, obj db.IStandaloneMod Desc: rule.Description, Action: rule.Action, Priority: rule.Priority, + Expression: rule.Expression, + Config: rule.Config, + Enable: rule.Enabled.Bool(), Statements: []cloudprovider.SWafStatement{}, }