feat(notify,region): improvement of news subscription

This commit is contained in:
rainzm
2021-06-24 10:30:01 +08:00
parent 7630589465
commit 311d0efb80
71 changed files with 1188 additions and 323 deletions
@@ -3,4 +3,7 @@
{{- if $d.brand -}}
{{ $d.brand }}平台
{{- end -}}
{{ .resource_type_display }}{{ $d.name }}已经成功{{ .action_display }}
{{ .resource_type_display }}{{ $d.name }}已经{{ .action_display }}{{.result_display}}
{{- if eq .result "failed" -}}
,请尽快前往控制台进行处理
{{- end -}}
@@ -0,0 +1,22 @@
{{- $d := .resource_details -}}
您在{{ $d.project }}项目的
{{- if $d.brand -}}
{{ $d.brand }}平台
{{- end -}}
{{- if $d.private_dns -}}
,内网地址为{{ $d.private_dns }}:{{ $d.private_connect_port }}
{{- end -}}
{{- if $d.public_dns -}}
,外网地址为{{ $d.public_dns }}:{{ $d.public_connect_port }}
{{- end -}}
{{- if $d.ips -}}
,IP地址为{{ $d.ips }}
{{- end -}}
{{- if $d.ip_addr -}}
,IP地址为{{ $d.ip_addr }}
{{- end -}}
{{ .resource_type_display }}{{ $d.name }}已经删除成功。
@@ -1,2 +1,5 @@
{{- $d := .resource_details -}}
Your {{ if $d.brand -}} {{ $d.brand }} {{ end -}} {{ .resource_type_display }} {{ $d.name }} {{ if $d.project -}} in project {{ $d.project }} {{ end -}} has been {{ .action_display }} successfully
Your {{ if $d.brand -}} {{ $d.brand }} {{ end -}} {{ .resource_type_display }} {{ $d.name }} {{ if $d.project -}} in project {{ $d.project }} {{ end -}} has been {{ .action_display }} {{ .result_display }}
{{- if eq .result "failed" -}}
. And please go to the console as soon as possible to process.
{{- end -}}
@@ -0,0 +1,22 @@
{{- $d := .resource_details -}}
Your {{ if $d.brand -}} {{ $d.brand }} {{ end -}} {{ .resource_type_display }} {{ $d.name }}
{{ if $d.project -}} in project {{ $d.project }} {{ end -}} has been deleted successfully
{{- if $d.private_dns -}}
, the intranet address is {{ $d.private_dns }}:{{ $d.private_connect_port }}
{{- end -}}
{{- if $d.public_dns -}}
, the internet address is {{ $d.public_dns }}:{{ $d.public_connect_port }}
{{- end -}}
{{- if and $d.address_type $d.address -}}
, the service address is {{ $d.address_type }}{{ $d.address }}
{{- end -}}
{{- if $d.ips -}}
, the IP address is {{ $d.ips }}
{{- end -}}
{{- if $d.ip_addr -}}
, the IP address is {{ $d.ip_addr }}
{{- end -}}
@@ -2,4 +2,4 @@
{{- if $d.project -}}
{{ $d.project }}项目的
{{- end -}}
{{ .resource_type_display }}{{ $d.name }}{{ .action_display }}成功
{{ .resource_type_display }}{{ $d.name }}{{ .action_display }}{{ .result_display }}
@@ -1,2 +1,2 @@
{{- $d := .resource_details -}}
The {{ .resource_type_display }} {{ .Name }} {{ if $d.project }} in poject {{ $d.project }} {{ end -}} {{ .action_display }} successfully
The {{ .resource_type_display }} {{ .Name }} {{ if $d.project }} in poject {{ $d.project }} {{ end -}} {{ .action_display }} {{ .result_display }}
+1
View File
@@ -31,6 +31,7 @@ func init() {
cmd.Perform("disable", new(options.ReceiverOptions))
cmd.Perform("trigger-verify", new(options.ReceiverTriggerVerifyOptions))
cmd.Perform("verify", new(options.ReceiverVerifyOptions))
cmd.Perform("enable-contact-type", new(options.ReceiverEnableContactTypeInput))
cmd.PerformClass("intellij-get", new(options.ReceiverIntellijGetOptions))
cmd.PerformClass("get-types", new(options.ReceiverGetTypeOptions))
}
+8 -8
View File
@@ -21,12 +21,12 @@ import (
)
func init() {
cmd := shell.NewResourceCmd(&modules.NotifyRobot).WithKeyword("notify-robot")
cmd.List(new(options.RobotListOptions))
cmd.Create(new(options.RobotCreateOptions))
cmd.Update(new(options.RobotUpdateOptions))
cmd.Show(new(options.RobotOptions))
cmd.Delete(new(options.RobotOptions))
cmd.Perform("enable", new(options.RobotOptions))
cmd.Perform("disable", new(options.RobotOptions))
cmd := shell.NewResourceCmd(&modules.NotifyRobot).WithKeyword("notify-robot")
cmd.List(new(options.RobotListOptions))
cmd.Create(new(options.RobotCreateOptions))
cmd.Update(new(options.RobotUpdateOptions))
cmd.Show(new(options.RobotOptions))
cmd.Delete(new(options.RobotOptions))
cmd.Perform("enable", new(options.RobotOptions))
cmd.Perform("disable", new(options.RobotOptions))
}
+1 -1
View File
@@ -29,7 +29,7 @@ func init() {
cmd1.Create(new(notify.SubscriberCreateOptions))
cmd1.Show(new(notify.SubscriberOptions))
cmd1.Delete(new(notify.SubscriberOptions))
cmd1.Perform("set-receiver", new(notify.SubscriberSetReceiverOptions))
cmd1.Perform("change", new(notify.SubscriberChangeOptions))
cmd1.Perform("enable", new(notify.SubscriberOptions))
cmd1.Perform("disable", new(notify.SubscriberOptions))
}
+1
View File
@@ -105,6 +105,7 @@ const (
TOPIC_RESOURCE_DBINSTANCE = "dbinstance"
TOPIC_RESOURCE_ELASTICCACHE = "elasticcache"
TOPIC_RESOURCE_SCHEDULEDTASK = "scheduledtask"
TOPIC_RESOURCE_BAREMETAL = "baremetal"
SUBSCRIBER_TYPE_ROLE = "role"
SUBSCRIBER_TYPE_ROBOT = "robot"
+41 -1
View File
@@ -33,6 +33,15 @@ var (
ActionExpiredRelease SAction = "expired_release"
ActionExecute SAction = "execute"
ActionChangeIpaddr SAction = "change_ipaddr"
ActionSyncStatus SAction = "sync_status"
ActionCleanData SAction = "clean_data"
ActionMigrate SAction = "migrate"
ActionCreateBackupServer SAction = "add_backup_server"
ActionDelBackupServer SAction = "delete_backup_server"
ResultFailed SResult = "failed"
ResultSucceed SResult = "succeed"
)
const (
@@ -41,9 +50,12 @@ const (
type SAction string
type SResult string
type SEvent struct {
resourceType string
action SAction
result SResult
}
func (se SEvent) WithResourceType(rt string) SEvent {
@@ -56,6 +68,11 @@ func (se SEvent) WithAction(a SAction) SEvent {
return se
}
func (se SEvent) WithResult(r SResult) SEvent {
se.result = r
return se
}
func (se SEvent) ResourceType() string {
return se.resourceType
}
@@ -64,6 +81,29 @@ func (se SEvent) Action() SAction {
return se.action
}
func (se SEvent) ActionWithResult(delimiter string) string {
ar := string(se.action)
if len(se.result) > 0 {
ar += delimiter + string(se.result)
}
return strings.ToUpper(ar)
}
func (se SEvent) Result() SResult {
if se.result == "" {
return ResultSucceed
}
return se.result
}
func (se SEvent) String() string {
return strings.ToUpper(fmt.Sprintf("%s%s%s", se.ResourceType(), DelimiterInEvent, se.Action()))
return se.StringWithDeli(DelimiterInEvent)
}
func (se SEvent) StringWithDeli(delimiter string) string {
str := strings.ToUpper(fmt.Sprintf("%s%s%s", se.ResourceType(), delimiter, se.Action()))
if se.result != "" {
str += delimiter + strings.ToUpper(string(se.result))
}
return str
}
+11 -6
View File
@@ -32,9 +32,9 @@ type NotificationCreateInput struct {
// description: direct contact, admin privileges required
// required: false
Contacts []string `json:"contacts"`
// description: robots
// example: feishu robot
Robots []string `json:"robots"`
// description: robots
// example: feishu robot
Robots []string `json:"robots"`
// description: contact type
// required: ture
// example: email
@@ -87,14 +87,19 @@ type NotificationListInput struct {
Tag string
}
type SContact struct {
Contact string `json:"contact"`
ContactType string `json:"contact_type"`
}
type NotificationManagerEventNotifyInput struct {
// description: ids or names of receiver
// required: false
// example: {"adfb720ccdd34c638346ea4fa7a713a8", "zhangsan"}
Receivers []string `json:"receivers"`
// example: {"adfb720ccdd34c638346ea4fa7a713a8"}
ReceiverIds []string `json:"receiver_ids"`
// description: direct contact, admin privileges required
// required: false
Contacts []string `json:"contacts"`
Contacts []SContact `json:"contacts"`
// description: contact types
// required: false
// example: email
+4
View File
@@ -162,3 +162,7 @@ type ReceiverIntellijGetInput struct {
// required: true
Scope string `json:"scope"`
}
type ReceiverEnableContactTypeInput struct {
EnabledContactTypes []string `json:"enabled_contact_types"`
}
+28 -28
View File
@@ -3,41 +3,41 @@ package notify
import "yunion.io/x/onecloud/pkg/apis"
type RobotCreateInput struct {
apis.SharableVirtualResourceCreateInput
// description: robot type
// enum: feishu,dingtalk,workwx,webhook
// example: webhook
Type string `json:"type"`
// description: address
// example: http://helloworld.io/test/webhook
Address string `json:"address"`
// description: Language preference
// example: zh_CN
Lang string `json:"lang"`
apis.SharableVirtualResourceCreateInput
// description: robot type
// enum: feishu,dingtalk,workwx,webhook
// example: webhook
Type string `json:"type"`
// description: address
// example: http://helloworld.io/test/webhook
Address string `json:"address"`
// description: Language preference
// example: zh_CN
Lang string `json:"lang"`
}
type RobotDetails struct {
apis.SharableVirtualResourceDetails
apis.SharableVirtualResourceDetails
}
type RobotListInput struct {
apis.SharableVirtualResourceListInput
apis.EnabledResourceBaseListInput
// description: robot type
// enum: feishu,dingtalk,workwx,webhook
// example: webhook
Type string `json:"type"`
// description: Language preference
// example: en
Lang string `json:"lang"`
apis.SharableVirtualResourceListInput
apis.EnabledResourceBaseListInput
// description: robot type
// enum: feishu,dingtalk,workwx,webhook
// example: webhook
Type string `json:"type"`
// description: Language preference
// example: en
Lang string `json:"lang"`
}
type RobotUpdateInput struct {
apis.SharableVirtualResourceBaseUpdateInput
// description: address
// example: http://helloworld.io/test/webhook
Address string `json:"address"`
// description: Language preference
// example: en
Lang string `json:"lang"`
apis.SharableVirtualResourceBaseUpdateInput
// description: address
// example: http://helloworld.io/test/webhook
Address string `json:"address"`
// description: Language preference
// example: en
Lang string `json:"lang"`
}
+34 -3
View File
@@ -17,7 +17,7 @@ package notify
import "yunion.io/x/onecloud/pkg/apis"
type SubscriberCreateInput struct {
apis.VirtualResourceCreateInput
apis.StandaloneAnonResourceCreateInput
// description: Id of Topic
// required
@@ -27,6 +27,14 @@ type SubscriberCreateInput struct {
// enum: system,domain,project
ResourceScope string
// description: project id or domain id of resource
// example: 1e3824756bac4ac084e784ed297ec652
ResourceAttributionId string
// description: domain id of resource
// example: 1e3824756bac4ac084e784ed297ec652
DomainId string
// description: Type of subscriber
// enum: receiver,robot,role
Type string
@@ -43,10 +51,29 @@ type SubscriberCreateInput struct {
// description: Robot(Id or Name) which is required when the type is 'robot' will Subscribe TopicID
Robot string
// description: scope
// enum: system,domain
Scope string
}
type SubscriberChangeInput struct {
// description: receivers which is required when the type is 'receiver' will Subscribe TopicID
Receivers []string
// description: Role(Id or Name) which is required when the type is 'role' will Subscribe TopicID
Role string
// description: The scope of role subscribers
// enum: system,domain,project
RoleScope string
// description: Robot(Id or Name) which is required when the type is 'robot' will Subscribe TopicID
Robot string
}
type SubscriberListInput struct {
apis.VirtualResourceListInput
apis.StandaloneAnonResourceListInput
apis.EnabledResourceBaseListInput
// description: topic id
@@ -59,6 +86,10 @@ type SubscriberListInput struct {
// description: type
// enum: receiver,robot,role
Type string
// description: scope
// enum: system,domain
Scope string
}
type Identification struct {
@@ -69,7 +100,7 @@ type Identification struct {
}
type SubscriberDetails struct {
apis.VirtualResourceDetails
apis.StandaloneAnonResourceDetails
SSubscriber
// description: receivers
+6
View File
@@ -28,3 +28,9 @@ type TopicDetails struct {
// example: ["server", "eip", "disk"]
Resources []string `json:"resource_types"`
}
type PerformEnableInput struct {
}
type PerformDisableInput struct {
}
+1
View File
@@ -197,6 +197,7 @@ func mergeQueryParams(params map[string]string, query jsonutils.JSONObject, excl
}
func listHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
log.Infof("start list handler")
manager, params, query, _ := fetchEnv(ctx, w, r)
handleList(ctx, w, manager, nil, mergeQueryParams(params, query))
}
+3
View File
@@ -1155,6 +1155,9 @@ func FetchModelObjects(modelManager IModelManager, query *sqlchemy.SQuery, targe
targetsValue := reflect.Indirect(reflect.ValueOf(targets))
for rows.Next() {
if modelManager.Keyword() == "server" {
log.Infof("one guest")
}
m, err := NewModelObject(modelManager)
if err != nil {
return err
+5
View File
@@ -52,6 +52,11 @@ var (
ActionExpiredRelease = api.ActionExpiredRelease
ActionExecute = api.ActionExecute
ActionMigrate = api.ActionMigrate
ActionCreateBackupServer = api.ActionCreateBackupServer
ActionDelBackupServer = api.ActionDelBackupServer
ActionSyncStatus = api.ActionSyncStatus
ActionPendingDelete = api.ActionPendingDelete
)
+13 -6
View File
@@ -129,7 +129,7 @@ func NotifyAllWithoutRobotWithCtx(ctx context.Context, recipientId []string, isG
// NotifyRobot will send messages via all robot contact type such as dingtalk-robot.
func NotifyRobot(robotIds []string, priority npk.TNotifyPriority, event string, data jsonutils.JSONObject) error {
return NotifyRobotWithCtx(context.Background(), robotIds, priority, event, data)
return NotifyRobotWithCtx(context.Background(), robotIds, priority, event, data)
}
// NotifyRobot will send messages via all robot contact type such as dingtalk-robot.
@@ -141,7 +141,7 @@ func NotifyRobotWithCtx(ctx context.Context, robotIds []string, priority npk.TNo
event: event,
data: data,
})
return nil
return nil
}
func SystemNotify(priority npk.TNotifyPriority, event string, data jsonutils.JSONObject) {
@@ -221,7 +221,9 @@ type SEventMessage struct {
type SEventNotifyParam struct {
Obj db.IModel
ResourceType string
Action api.SAction
IsFail bool
ObjDetailsDecorator func(context.Context, *jsonutils.JSONDict)
AdvanceDays int
}
@@ -247,9 +249,6 @@ func (t *eventTask) Run() {
}
func EventNotify(ctx context.Context, userCred mcclient.TokenCredential, ep SEventNotifyParam) {
// disable EventNotify for now
return
ret, err := db.FetchCustomizeColumns(ep.Obj.GetModelManager(), ctx, userCred, jsonutils.NewDict(), []interface{}{ep.Obj}, stringutils2.SSortedStrings{}, false)
if err != nil {
log.Errorf("unable to FetchCustomizeColumns: %v", err)
@@ -263,7 +262,14 @@ func EventNotify(ctx context.Context, userCred mcclient.TokenCredential, ep SEve
if ep.ObjDetailsDecorator != nil {
ep.ObjDetailsDecorator(ctx, objDetails)
}
event := api.Event.WithAction(ep.Action).WithResourceType(ep.Obj.GetModelManager().Keyword())
rt := ep.ResourceType
if len(rt) == 0 {
rt = ep.Obj.GetModelManager().Keyword()
}
event := api.Event.WithAction(ep.Action).WithResourceType(rt)
if ep.IsFail {
event = event.WithResult(api.ResultFailed)
}
var (
projectId string
projectDomainId string
@@ -274,6 +280,7 @@ func EventNotify(ctx context.Context, userCred mcclient.TokenCredential, ep SEve
projectDomainId = ownerId.GetProjectDomainId()
}
params := api.NotificationManagerEventNotifyInput{
ReceiverIds: []string{userCred.GetUserId()},
ResourceDetails: objDetails,
Event: event.String(),
AdvanceDays: ep.AdvanceDays,
@@ -212,7 +212,7 @@ func genMsgViaLang(ctx context.Context, p sNotifyParams) ([]npk.SNotifyMessage,
var langMap map[language.Tag]*sTarget
if p.channel == npk.NotifyByRobot {
langMap, err = langRobot(ctx, p.robots)
langMap, err = langRobot(ctx, p.robots)
} else {
langMap, err = lang(ctx, p.channel, reIds, p.contacts)
if err != nil {
@@ -226,7 +226,7 @@ func genMsgViaLang(ctx context.Context, p sNotifyParams) ([]npk.SNotifyMessage,
msg := npk.SNotifyMessage{}
msg.Uid = t.reIds
msg.Priority = p.priority
msg.Robots = p.robots
msg.Robots = p.robots
msg.Contacts = t.contacts
msg.ContactType = p.channel
topic, _ := getContent(langSuffix, p.event, "title", p.channel, p.data)
+18 -18
View File
@@ -65,26 +65,26 @@ func getUserLang(uids []string) (map[string]string, error) {
}
func getRobotLang(robots []string) (map[string]string, error) {
s, err := AdminSessionGenerator(context.Background(), consts.GetRegion(), "")
if err != nil {
return nil, err
}
robotLang := make(map[string]string)
if len(robots) > 0 {
params := jsonutils.NewDict()
s, err := AdminSessionGenerator(context.Background(), consts.GetRegion(), "")
if err != nil {
return nil, err
}
robotLang := make(map[string]string)
if len(robots) > 0 {
params := jsonutils.NewDict()
params.Set("filter", jsonutils.NewString(fmt.Sprintf("id.in(%s)", strings.Join(robots, ","))))
params.Set("scope", jsonutils.NewString("system"))
ret, err := modules.NotifyRobot.List(s, params)
if err != nil {
return nil, err
}
for i := range ret.Data {
id, _ := ret.Data[i].GetString("id")
langStr, _ := ret.Data[i].GetString("lang")
robotLang[id] = langStr
}
}
return robotLang, nil
ret, err := modules.NotifyRobot.List(s, params)
if err != nil {
return nil, err
}
for i := range ret.Data {
id, _ := ret.Data[i].GetString("id")
langStr, _ := ret.Data[i].GetString("lang")
robotLang[id] = langStr
}
}
return robotLang, nil
}
func init() {
+84
View File
@@ -16,13 +16,17 @@ package models
import (
"context"
"reflect"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
api "yunion.io/x/onecloud/pkg/apis/billing"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
@@ -204,3 +208,83 @@ func ParseBillingCycleInput(billingBase *SBillingResourceBase, input apis.Postpa
return &bc, nil
}
type SBillingResourceCheckManager struct {
db.SResourceBaseManager
}
type SBillingResourceCheck struct {
db.SResourceBase
ResourceId string `width:"128" charset:"ascii" index:"true"`
ResourceType string `width:"36" charset:"ascii" index:"true"`
AdvanceDays int
LastCheck time.Time
}
var BillingResourceCheckManager *SBillingResourceCheckManager
func init() {
BillingResourceCheckManager = &SBillingResourceCheckManager{
SResourceBaseManager: db.NewResourceBaseManager(
SBillingResourceCheck{},
"billingresourcecheck_tbl",
"billingresourcecheck",
"billingresourcechecks",
),
}
BillingResourceCheckManager.SetVirtualObject(BillingResourceCheckManager)
}
func (bm *SBillingResourceCheckManager) Create(ctx context.Context, resourceId, resourceType string, advanceDays int) error {
bc := SBillingResourceCheck{
ResourceId: resourceId,
ResourceType: resourceType,
AdvanceDays: advanceDays,
LastCheck: time.Now(),
}
return bm.TableSpec().Insert(ctx, &bc)
}
var advanceDays []int = []int{1, 3}
func CheckBillingResourceExpireAt(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
billingResourceManagers := []db.IModelManager{
GuestManager,
DBInstanceManager,
ElasticcacheManager,
}
for _, advanceDay := range advanceDays {
for _, manager := range billingResourceManagers {
upLimit := time.Now().AddDate(0, 0, advanceDay)
downLimit := time.Now().AddDate(0, 0, advanceDay-1)
v := reflect.MakeSlice(reflect.SliceOf(manager.TableSpec().DataType()), 0, 0)
q := manager.Query().LE("expired_at", upLimit).GE("expired_at", downLimit)
bq := BillingResourceCheckManager.Query("resource_id").Equals("resource_type", manager.Keyword()).Equals("advance_days", advanceDay).SubQuery()
q = q.LeftJoin(bq, sqlchemy.Equals(q.Field("id"), bq.Field("resource_id")))
q = q.IsNull("resource_id")
vp := reflect.New(v.Type())
vp.Elem().Set(v)
err := db.FetchModelObjects(manager, q, vp.Interface())
if err != nil {
log.Errorf("unable to list %s: %v", manager.KeywordPlural(), err)
}
v = vp.Elem()
log.Debugf("%s length of v: %d", manager.Alias(), v.Len())
for i := 0; i < v.Len(); i++ {
m := v.Index(i).Addr().Interface().(db.IModel)
notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
Obj: m,
Action: notifyclient.ActionExpiredRelease,
AdvanceDays: advanceDay,
})
err := BillingResourceCheckManager.Create(ctx, m.GetId(), manager.Keyword(), advanceDay)
if err != nil {
log.Errorf("unable to create billingresourcecheck for resource %s %s", manager.Keyword(), m.GetId())
}
}
}
}
}
+5
View File
@@ -973,8 +973,13 @@ func (self *SGuest) EventNotify(ctx context.Context, userCred mcclient.TokenCred
}
}
}
var resourceType string
if self.Hypervisor == api.HYPERVISOR_BAREMETAL {
resourceType = noapi.TOPIC_RESOURCE_BAREMETAL
}
notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
Obj: self,
ResourceType: resourceType,
Action: action,
ObjDetailsDecorator: detailsDecro,
AdvanceDays: 0,
+1
View File
@@ -91,6 +91,7 @@ func init() {
"servers",
),
}
log.Infof("init GuestManager")
GuestManager.SetVirtualObject(GuestManager)
GuestManager.SetAlias("guest", "guests")
}
+1
View File
@@ -95,6 +95,7 @@ func InitHandlers(app *appsrv.Application) {
models.CloudimageManager,
models.WafRuleStatementManager,
models.BillingResourceCheckManager,
} {
db.RegisterModelManager(manager)
}
+2
View File
@@ -165,6 +165,8 @@ func StartService() {
cron.AddJobEveryFewHour("InspectAllTemplate", 1, 0, 0, models.GuestTemplateManager.InspectAllTemplate, true)
cron.AddJobAtIntervalsWithStartRun("ScheduledTaskCheck", time.Duration(60)*time.Second, models.ScheduledTaskManager.Timer, true)
cron.AddJobEveryFewHour("CheckBillingResourceExpireAt", 1, 0, 0, models.CheckBillingResourceExpireAt, true)
go cron.Start2(ctx, electObj)
// init auto scaling controller
+5
View File
@@ -22,6 +22,7 @@ import (
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/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
@@ -53,6 +54,10 @@ func (task *BucketCreateTask) OnInit(ctx context.Context, obj db.IStandaloneMode
}
bucket.SetStatus(task.UserCred, api.BUCKET_STATUS_READY, "BucketCreateTask")
notifyclient.EventNotify(ctx, task.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: bucket,
Action: notifyclient.ActionCreate,
})
logclient.AddActionLogWithStartable(task, bucket, logclient.ACT_ALLOCATE, nil, task.UserCred, true)
task.SetStageComplete(ctx, nil)
}
+5
View File
@@ -22,6 +22,7 @@ import (
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/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
@@ -52,6 +53,10 @@ func (task *BucketDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneMode
return
}
notifyclient.EventNotify(ctx, task.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: bucket,
Action: notifyclient.ActionDelete,
})
logclient.AddActionLogWithStartable(task, bucket, logclient.ACT_DELETE, nil, task.UserCred, true)
task.SetStageComplete(ctx, nil)
}
@@ -23,6 +23,7 @@ import (
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/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
@@ -73,7 +74,20 @@ func (self *DBInstanceAccountResetPasswordTask) OnInit(ctx context.Context, obj
}
}
self.resetPasswdNotify(ctx, instance, account, password)
account.SetStatus(self.UserCred, api.DBINSTANCE_USER_AVAILABLE, "")
logclient.AddActionLogWithStartable(self, account, logclient.ACT_RESET_PASSWORD, nil, self.UserCred, true)
self.SetStageComplete(ctx, nil)
}
func (self *DBInstanceAccountResetPasswordTask) resetPasswdNotify(ctx context.Context, rds *models.SDBInstance, account *models.SDBInstanceAccount, password string) {
detailsDecro := func(ctx context.Context, details *jsonutils.JSONDict) {
details.Set("account", jsonutils.NewString(account.GetName()))
details.Set("password", jsonutils.NewString(password))
}
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: rds,
Action: notifyclient.ActionResetPassword,
ObjDetailsDecorator: detailsDecro,
})
}
@@ -41,6 +41,11 @@ func (self *DBInstanceChangeConfigTask) taskFailed(ctx context.Context, dbinstan
dbinstance.SetStatus(self.UserCred, api.DBINSTANCE_CHANGE_CONFIG_FAILED, err.Error())
db.OpsLog.LogEvent(dbinstance, db.ACT_CHANGE_CONFIG, err, self.GetUserCred())
logclient.AddActionLogWithStartable(self, dbinstance, logclient.ACT_CHANGE_CONFIG, err, self.UserCred, false)
notifyclient.EventNotify(ctx, self.UserCred, notifyclient.SEventNotifyParam{
Obj: dbinstance,
Action: notifyclient.ActionChangeConfig,
IsFail: true,
})
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
@@ -64,7 +69,10 @@ func (self *DBInstanceChangeConfigTask) OnInit(ctx context.Context, obj db.IStan
func (self *DBInstanceChangeConfigTask) OnDBInstanceChangeConfigComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
dbinstance := obj.(*models.SDBInstance)
logclient.AddActionLogWithStartable(self, dbinstance, logclient.ACT_CHANGE_CONFIG, nil, self.UserCred, true)
notifyclient.NotifyWebhook(ctx, self.UserCred, dbinstance, notifyclient.ActionChangeConfig)
notifyclient.EventNotify(ctx, self.UserCred, notifyclient.SEventNotifyParam{
Obj: dbinstance,
Action: notifyclient.ActionChangeConfig,
})
self.SetStage("OnSyncDBInstanceStatusComplete", nil)
models.StartResourceSyncStatusTask(ctx, self.UserCred, dbinstance, "DBInstanceSyncStatusTask", self.GetTaskId())
}
+10 -1
View File
@@ -40,6 +40,11 @@ func (self *DBInstanceCreateTask) taskFailed(ctx context.Context, dbinstance *mo
dbinstance.SetStatus(self.UserCred, api.DBINSTANCE_CREATE_FAILED, err.Error())
db.OpsLog.LogEvent(dbinstance, db.ACT_CREATE, err, self.GetUserCred())
logclient.AddActionLogWithStartable(self, dbinstance, logclient.ACT_CREATE, err, self.UserCred, false)
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: dbinstance,
Action: notifyclient.ActionCreate,
IsFail: true,
})
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
@@ -77,7 +82,11 @@ func (self *DBInstanceCreateTask) OnCreateDBInstanceCompleteFailed(ctx context.C
func (self *DBInstanceCreateTask) OnSyncDBInstanceStatusComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
dbinstance := obj.(*models.SDBInstance)
notifyclient.NotifyWebhook(ctx, self.UserCred, dbinstance, notifyclient.ActionCreate)
//notifyclient.NotifyWebhook(ctx, self.UserCred, dbinstance, notifyclient.ActionCreate)
notifyclient.EventNotify(ctx, self.UserCred, notifyclient.SEventNotifyParam{
Obj: dbinstance,
Action: notifyclient.ActionCreate,
})
self.SetStageComplete(ctx, nil)
}
+15 -2
View File
@@ -41,6 +41,11 @@ func (self *DBInstanceDeleteTask) taskFailed(ctx context.Context, dbinstance *mo
dbinstance.SetStatus(self.UserCred, api.DBINSTANCE_DELETE_FAILED, err.Error())
db.OpsLog.LogEvent(dbinstance, db.ACT_DELETE, err, self.GetUserCred())
logclient.AddActionLogWithStartable(self, dbinstance, logclient.ACT_DELETE, err, self.UserCred, false)
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: dbinstance,
Action: notifyclient.ActionDelete,
IsFail: true,
})
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
@@ -83,13 +88,21 @@ func (self *DBInstanceDeleteTask) DeleteDBInstanceComplete(ctx context.Context,
self.taskFailed(ctx, dbinstance, errors.Wrap(err, "dbinstance.Purge"))
return
}
notifyclient.NotifyWebhook(ctx, self.UserCred, dbinstance, notifyclient.ActionDelete)
//notifyclient.NotifyWebhook(ctx, self.UserCred, dbinstance, notifyclient.ActionDelete)
notifyclient.EventNotify(ctx, self.UserCred, notifyclient.SEventNotifyParam{
Obj: dbinstance,
Action: notifyclient.ActionDelete,
})
self.SetStageComplete(ctx, nil)
return
}
self.DeleteBackups(ctx, dbinstance, nil)
notifyclient.NotifyWebhook(ctx, self.UserCred, dbinstance, notifyclient.ActionDelete)
//notifyclient.NotifyWebhook(ctx, self.UserCred, dbinstance, notifyclient.ActionDelete)
notifyclient.EventNotify(ctx, self.UserCred, notifyclient.SEventNotifyParam{
Obj: dbinstance,
Action: notifyclient.ActionDelete,
})
}
func (self *DBInstanceDeleteTask) DeleteBackups(ctx context.Context, instance *models.SDBInstance, data jsonutils.JSONObject) {
@@ -23,6 +23,7 @@ import (
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/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
@@ -39,6 +40,11 @@ func (self *DBInstanceSyncStatusTask) taskFailed(ctx context.Context, dbinstance
dbinstance.SetStatus(self.UserCred, api.DBINSTANCE_UNKNOWN, err.Error())
db.OpsLog.LogEvent(dbinstance, db.ACT_SYNC_STATUS, err, self.GetUserCred())
logclient.AddActionLogWithStartable(self, dbinstance, logclient.ACT_SYNC_STATUS, err, self.UserCred, false)
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: dbinstance,
Action: notifyclient.ActionSyncStatus,
IsFail: true,
})
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
+9 -4
View File
@@ -43,6 +43,11 @@ func init() {
func (self *EipAllocateTask) onFailed(ctx context.Context, eip *models.SElasticip, reason jsonutils.JSONObject) {
eip.SetStatus(self.UserCred, api.EIP_STATUS_ALLOCATE_FAIL, reason.String())
self.setGuestAllocateEipFailed(eip, reason)
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: eip,
Action: notifyclient.ActionCreate,
IsFail: true,
})
self.SetStageFailed(ctx, reason)
}
@@ -159,6 +164,10 @@ func (self *EipAllocateTask) OnInit(ctx context.Context, obj db.IStandaloneModel
}
} else {
logclient.AddActionLogWithStartable(self, eip, logclient.ACT_ALLOCATE, nil, self.UserCred, true)
notifyclient.EventNotify(ctx, self.UserCred, notifyclient.SEventNotifyParam{
Obj: eip,
Action: notifyclient.ActionCreate,
})
self.SetStageComplete(ctx, nil)
}
}
@@ -166,10 +175,6 @@ func (self *EipAllocateTask) OnInit(ctx context.Context, obj db.IStandaloneModel
func (self *EipAllocateTask) OnEipAssociateComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
eip := obj.(*models.SElasticip)
logclient.AddActionLogWithStartable(self, eip, logclient.ACT_ALLOCATE, nil, self.UserCred, true)
notifyclient.EventNotify(ctx, self.UserCred, notifyclient.SEventNotifyParam{
Obj: eip,
Action: notifyclient.ActionCreate,
})
self.SetStageComplete(ctx, nil)
}
+5
View File
@@ -42,6 +42,11 @@ func (self *EipDeallocateTask) taskFail(ctx context.Context, eip *models.SElasti
eip.SetStatus(self.UserCred, api.EIP_STATUS_DEALLOCATE_FAIL, msg.String())
db.OpsLog.LogEvent(eip, db.ACT_DELOCATE, msg, self.GetUserCred())
logclient.AddActionLogWithStartable(self, eip, logclient.ACT_DELETE, msg, self.UserCred, false)
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: eip,
Action: notifyclient.ActionDelete,
IsFail: true,
})
self.SetStageFailed(ctx, msg)
return
}
@@ -68,7 +68,21 @@ func (self *ElasticcacheAccountResetPasswordTask) OnInit(ctx context.Context, ob
ec.(*models.SElasticcache).SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_RUNNING, "")
logclient.AddActionLogWithStartable(self, ec, logclient.ACT_RESET_PASSWORD, "", self.UserCred, true)
}
password, _ := self.GetParams().GetString("password")
self.resetPasswordNotify(ctx, ec.(*models.SElasticcache), ea, password)
logclient.AddActionLogWithStartable(self, ea, logclient.ACT_RESET_PASSWORD, "", self.UserCred, true)
self.SetStageComplete(ctx, nil)
}
}
func (self *ElasticcacheAccountResetPasswordTask) resetPasswordNotify(ctx context.Context, ec *models.SElasticcache, account *models.SElasticcacheAccount, password string) {
detailDecro := func(ctx context.Context, details *jsonutils.JSONDict) {
details.Set("account", jsonutils.NewString(account.GetName()))
details.Set("password", jsonutils.NewString(password))
}
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: ec,
Action: notifyclient.ActionResetPassword,
ObjDetailsDecorator: detailDecro,
})
}
@@ -40,7 +40,11 @@ func (self *ElasticcacheChangeSpecTask) taskFail(ctx context.Context, ec *models
ec.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_CHANGE_FAILED, reason.String())
db.OpsLog.LogEvent(ec, db.ACT_CHANGE_FLAVOR, reason, self.UserCred)
logclient.AddActionLogWithStartable(self, ec, logclient.ACT_VM_CHANGE_FLAVOR, reason, self.UserCred, false)
notifyclient.NotifySystemErrorWithCtx(ctx, ec.Id, ec.Name, api.ELASTIC_CACHE_STATUS_CHANGE_FAILED, reason.String())
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: ec,
Action: notifyclient.ActionChangeConfig,
IsFail: true,
})
self.SetStageFailed(ctx, reason)
}
+10 -2
View File
@@ -40,7 +40,11 @@ func (self *ElasticcacheCreateTask) taskFail(ctx context.Context, elasticcache *
elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_CREATE_FAILED, reason.String())
db.OpsLog.LogEvent(elasticcache, db.ACT_ALLOCATE_FAIL, reason, self.UserCred)
logclient.AddActionLogWithStartable(self, elasticcache, logclient.ACT_CREATE, reason, self.UserCred, false)
notifyclient.NotifySystemErrorWithCtx(ctx, elasticcache.Id, elasticcache.Name, api.ELASTIC_CACHE_STATUS_CREATE_FAILED, reason.String())
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: elasticcache,
Action: notifyclient.ActionCreate,
IsFail: true,
})
self.SetStageFailed(ctx, reason)
}
@@ -95,7 +99,11 @@ func (self *ElasticcacheCreateTask) OnSyncSecurityGroupCompleteFailed(ctx contex
func (self *ElasticcacheCreateTask) OnElasticcacheCreateComplete(ctx context.Context, elasticcache *models.SElasticcache, data jsonutils.JSONObject) {
elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_RUNNING, "")
logclient.AddActionLogWithStartable(self, elasticcache, logclient.ACT_CREATE, "", self.UserCred, true)
notifyclient.NotifyWebhook(ctx, self.UserCred, elasticcache, notifyclient.ActionCreate)
// notifyclient.NotifyWebhook(ctx, self.UserCred, elasticcache, notifyclient.ActionCreate)
notifyclient.EventNotify(ctx, self.UserCred, notifyclient.SEventNotifyParam{
Obj: elasticcache,
Action: notifyclient.ActionCreate,
})
self.SetStageComplete(ctx, nil)
}
@@ -40,7 +40,11 @@ func (self *ElasticcacheDeleteTask) taskFail(ctx context.Context, elasticcache *
elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_RELEASE_FAILED, reason.String())
db.OpsLog.LogEvent(elasticcache, db.ACT_DELOCATE_FAIL, reason, self.UserCred)
logclient.AddActionLogWithStartable(self, elasticcache, logclient.ACT_DELETE, reason, self.UserCred, false)
notifyclient.NotifySystemErrorWithCtx(ctx, elasticcache.Id, elasticcache.Name, api.ELASTIC_CACHE_STATUS_RELEASE_FAILED, reason.String())
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: elasticcache,
Action: notifyclient.ActionDelete,
IsFail: true,
})
self.SetStageFailed(ctx, reason)
}
@@ -62,7 +66,10 @@ func (self *ElasticcacheDeleteTask) OnInit(ctx context.Context, obj db.IStandalo
ec.DeleteSubResources(ctx, self.UserCred)
ec.SVirtualResourceBase.Delete(ctx, self.UserCred)
logclient.AddActionLogWithStartable(self, ec, logclient.ACT_DELETE, "", self.UserCred, true)
notifyclient.NotifyWebhook(ctx, self.UserCred, ec, notifyclient.ActionDelete)
notifyclient.EventNotify(ctx, self.UserCred, notifyclient.SEventNotifyParam{
Obj: ec,
Action: notifyclient.ActionDelete,
})
self.SetStageComplete(ctx, nil)
}
}
@@ -23,6 +23,7 @@ import (
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/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
@@ -40,6 +41,11 @@ func (self *ElasticcacheSyncstatusTask) taskFailed(ctx context.Context, cache *m
self.SetStageFailed(ctx, err)
db.OpsLog.LogEvent(cache, db.ACT_SYNC_STATUS, cache.GetShortDesc(ctx), self.GetUserCred())
logclient.AddActionLogWithContext(ctx, cache, logclient.ACT_SYNC_STATUS, err, self.UserCred, false)
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: cache,
Action: notifyclient.ActionSyncStatus,
IsFail: true,
})
}
func (self *ElasticcacheSyncstatusTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
+5 -1
View File
@@ -296,7 +296,11 @@ func (self *GuestBatchCreateTask) SaveScheduleResult(ctx context.Context, obj IS
self.clearPendingUsage(ctx, guest)
db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, err, self.UserCred)
logclient.AddActionLogWithStartable(self, obj, logclient.ACT_ALLOCATE, err, self.GetUserCred(), false)
notifyclient.NotifySystemErrorWithCtx(ctx, guest.Id, guest.Name, api.VM_CREATE_FAILED, err.Error())
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: guest,
Action: notifyclient.ActionCreateBackupServer,
IsFail: true,
})
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
}
}
@@ -335,7 +335,6 @@ func (self *GuestChangeConfigTask) OnGuestChangeCpuMemSpecCompleteFailed(ctx con
func (self *GuestChangeConfigTask) OnGuestChangeCpuMemSpecFinish(ctx context.Context, guest *models.SGuest) {
models.HostManager.ClearSchedDescCache(guest.HostId)
self.SetStage("OnSyncConfigComplete", nil)
notifyclient.NotifyWebhook(ctx, self.UserCred, guest, notifyclient.ActionChangeConfig)
err := guest.StartSyncTaskWithoutSyncstatus(ctx, self.UserCred, false, self.GetTaskId())
if err != nil {
self.markStageFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("StartSyncstatus fail %s", err)))
@@ -383,7 +382,11 @@ func (self *GuestChangeConfigTask) markStageFailed(ctx context.Context, guest *m
guest.SetStatus(self.UserCred, api.VM_CHANGE_FLAVOR_FAIL, reason.String())
db.OpsLog.LogEvent(guest, db.ACT_CHANGE_FLAVOR_FAIL, reason, self.UserCred)
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_VM_CHANGE_FLAVOR, reason, self.UserCred, false)
notifyclient.NotifyError(ctx, self.UserCred, guest.GetId(), guest.GetName(), logclient.ACT_VM_CHANGE_FLAVOR, reason.String())
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: guest,
Action: notifyclient.ActionChangeConfig,
IsFail: true,
})
self.SetStageFailed(ctx, reason)
}
+17 -12
View File
@@ -28,7 +28,6 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/mcclient/modules/notify"
"yunion.io/x/onecloud/pkg/util/billing"
"yunion.io/x/onecloud/pkg/util/logclient"
)
@@ -70,7 +69,12 @@ func (self *GuestCreateTask) OnDiskPreparedFailed(ctx context.Context, obj db.IS
guest.SetStatus(self.UserCred, api.VM_DISK_FAILED, "allocation failed")
db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, data, self.UserCred)
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_ALLOCATE, data, self.UserCred, false)
notifyclient.NotifySystemErrorWithCtx(ctx, guest.Id, guest.Name, api.VM_DISK_FAILED, data.String())
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: guest,
Action: notifyclient.ActionCreate,
IsFail: true,
})
self.SetStageFailed(ctx, data)
}
@@ -99,7 +103,11 @@ func (self *GuestCreateTask) OnCdromPreparedFailed(ctx context.Context, obj db.I
guest.SetStatus(self.UserCred, api.VM_DISK_FAILED, "")
db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, data, self.UserCred)
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_ALLOCATE, data, self.UserCred, false)
notifyclient.NotifySystemErrorWithCtx(ctx, guest.Id, guest.Name, api.VM_DISK_FAILED, fmt.Sprintf("cdrom_failed %s", data))
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: guest,
Action: notifyclient.ActionCreate,
IsFail: true,
})
self.SetStageFailed(ctx, data)
}
@@ -160,21 +168,18 @@ func (self *GuestCreateTask) OnDeployGuestDescComplete(ctx context.Context, obj
}
func (self *GuestCreateTask) notifyServerCreated(ctx context.Context, guest *models.SGuest) {
notifyclient.NotifyWebhook(ctx, self.UserCred, guest, notifyclient.ActionCreate)
guest.NotifyServerEvent(
ctx, self.UserCred, notifyclient.SERVER_CREATED,
notify.NotifyPriorityImportant, true, nil, false,
)
guest.NotifyAdminServerEvent(ctx, notifyclient.SERVER_CREATED_ADMIN, notify.NotifyPriorityImportant)
// guest.EventNotify(ctx, self.UserCred, notifyclient.ActionCreate)
guest.EventNotify(ctx, self.UserCred, notifyclient.ActionCreate)
}
func (self *GuestCreateTask) OnDeployGuestDescCompleteFailed(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
guest := obj.(*models.SGuest)
guest.SetStatus(self.UserCred, api.VM_DEPLOY_FAILED, "deploy_failed")
db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, data, self.UserCred)
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_ALLOCATE, data, self.UserCred, false)
notifyclient.NotifySystemErrorWithCtx(ctx, guest.Id, guest.Name, api.VM_DEPLOY_FAILED, data.String())
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: guest,
Action: notifyclient.ActionCreate,
IsFail: true,
})
self.SetStageFailed(ctx, data)
}
@@ -23,6 +23,7 @@ import (
"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/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/httputils"
"yunion.io/x/onecloud/pkg/util/logclient"
@@ -40,6 +41,11 @@ func (self *GuestDeleteBackupTask) OnFail(ctx context.Context, guest *models.SGu
logclient.AddActionLogWithContext(ctx, guest, logclient.ACT_DELETE_BACKUP, reason, self.UserCred, false)
db.OpsLog.LogEvent(guest, db.ACT_DELETE_BACKUP_FAILED, reason, self.UserCred)
guest.SetStatus(self.UserCred, compute.VM_BACKUP_DELETE_FAILED, reason.String())
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: guest,
Action: notifyclient.ActionDelBackupServer,
IsFail: true,
})
self.SetStageFailed(ctx, reason)
}
+6 -11
View File
@@ -28,7 +28,6 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/mcclient/modules/notify"
"yunion.io/x/onecloud/pkg/util/logclient"
)
@@ -307,6 +306,11 @@ func (self *GuestDeleteTask) OnFailed(ctx context.Context, guest *models.SGuest,
guest.SetStatus(self.UserCred, api.VM_DELETE_FAIL, err.String())
db.OpsLog.LogEvent(guest, db.ACT_DELOCATE_FAIL, err, self.UserCred)
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_DELOCATE, err, self.UserCred, false)
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: guest,
Action: notifyclient.ActionDelete,
IsFail: true,
})
self.SetStageFailed(ctx, err)
}
@@ -354,14 +358,5 @@ func (self *GuestDeleteTask) DeleteGuest(ctx context.Context, guest *models.SGue
}
func (self *GuestDeleteTask) NotifyServerDeleted(ctx context.Context, guest *models.SGuest) {
notifyclient.NotifyWebhook(ctx, self.UserCred, guest, notifyclient.ActionPendingDelete)
guest.NotifyServerEvent(
ctx,
self.UserCred,
notifyclient.SERVER_DELETED,
notify.NotifyPriorityImportant,
false, nil, false,
)
guest.NotifyAdminServerEvent(ctx, notifyclient.SERVER_DELETED_ADMIN, notify.NotifyPriorityImportant)
// guest.EventNotify(ctx, self.UserCred, notifyclient.ActionPendingDelete)
guest.EventNotify(ctx, self.UserCred, notifyclient.ActionPendingDelete)
}
@@ -470,6 +470,11 @@ func (self *GuestMigrateTask) TaskFailed(ctx context.Context, guest *models.SGue
logclient.AddActionLogWithContext(ctx, guest, logclient.ACT_MIGRATE, reason, self.UserCred, false)
self.SetStageFailed(ctx, reason)
notifyclient.NotifySystemErrorWithCtx(ctx, guest.Id, guest.Name, api.VM_MIGRATE_FAILED, reason.String())
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: guest,
Action: notifyclient.ActionMigrate,
IsFail: true,
})
}
//ManagedGuestMigrateTask
+6 -10
View File
@@ -27,7 +27,6 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/mcclient/modules/notify"
"yunion.io/x/onecloud/pkg/util/logclient"
)
@@ -59,6 +58,11 @@ func (self *GuestRebuildRootTask) markFailed(ctx context.Context, guest *models.
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_VM_REBUILD, reason, self.UserCred, false)
guest.SetStatus(self.GetUserCred(), api.VM_REBUILD_ROOT_FAIL, reason.String())
self.SGuestBaseTask.SetStageFailed(ctx, reason)
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: guest,
Action: notifyclient.ActionRebuildRoot,
IsFail: true,
})
gds := guest.CategorizeDisks()
imageId, _ := self.Params.GetString("origin_image_id")
_, err := db.Update(gds.Root, func() error {
@@ -176,15 +180,7 @@ func (self *GuestRebuildRootTask) OnRebuildAllDisksComplete(ctx context.Context,
}
}
db.OpsLog.LogEvent(guest, db.ACT_REBUILD_ROOT, "", self.UserCred)
notifyclient.NotifyWebhook(ctx, self.UserCred, guest, notifyclient.ActionRebuildRoot)
guest.NotifyServerEvent(
ctx,
self.UserCred,
notifyclient.SERVER_REBUILD_ROOT,
notify.NotifyPriorityImportant,
true, nil, false,
)
// guest.EventNotify(ctx, self.UserCred, notifyclient.ActionRebuildRoot)
guest.EventNotify(ctx, self.UserCred, notifyclient.ActionRebuildRoot)
self.SetStage("OnSyncStatusComplete", nil)
guest.StartSyncstatus(ctx, self.UserCred, self.GetTaskId())
}
@@ -41,6 +41,11 @@ func (self *LoadbalancerCreateTask) taskFail(ctx context.Context, lb *models.SLo
db.OpsLog.LogEvent(lb, db.ACT_ALLOCATE_FAIL, reason, self.UserCred)
logclient.AddActionLogWithStartable(self, lb, logclient.ACT_CREATE, reason, self.UserCred, false)
notifyclient.NotifySystemErrorWithCtx(ctx, lb.Id, lb.Name, api.LB_CREATE_FAILED, reason.String())
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: lb,
Action: notifyclient.ActionCreate,
IsFail: true,
})
self.SetStageFailed(ctx, reason)
}
@@ -71,7 +76,10 @@ func (self *LoadbalancerCreateTask) OnLoadbalancerCreateCompleteFailed(ctx conte
func (self *LoadbalancerCreateTask) OnLoadbalancerStartComplete(ctx context.Context, lb *models.SLoadbalancer, data jsonutils.JSONObject) {
lb.SetStatus(self.GetUserCred(), api.LB_STATUS_ENABLED, "")
notifyclient.NotifyWebhook(ctx, self.UserCred, lb, notifyclient.ActionCreate)
notifyclient.EventNotify(ctx, self.UserCred, notifyclient.SEventNotifyParam{
Obj: lb,
Action: notifyclient.ActionCreate,
})
self.SetStageComplete(ctx, nil)
}
+10 -2
View File
@@ -40,7 +40,11 @@ func (self *LoadbalancerDeleteTask) taskFail(ctx context.Context, lb *models.SLo
lb.SetStatus(self.GetUserCred(), api.LB_STATUS_DELETE_FAILED, reason.String())
db.OpsLog.LogEvent(lb, db.ACT_DELOCATE_FAIL, reason, self.UserCred)
logclient.AddActionLogWithStartable(self, lb, logclient.ACT_DELOCATE, reason, self.UserCred, false)
notifyclient.NotifySystemErrorWithCtx(ctx, lb.Id, lb.Name, api.LB_STATUS_DELETE_FAILED, reason.String())
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: lb,
Action: notifyclient.ActionDelete,
IsFail: true,
})
self.SetStageFailed(ctx, reason)
}
@@ -60,7 +64,11 @@ func (self *LoadbalancerDeleteTask) OnInit(ctx context.Context, obj db.IStandalo
func (self *LoadbalancerDeleteTask) OnLoadbalancerDeleteComplete(ctx context.Context, lb *models.SLoadbalancer, data jsonutils.JSONObject) {
db.OpsLog.LogEvent(lb, db.ACT_DELETE, lb.GetShortDesc(ctx), self.UserCred)
logclient.AddActionLogWithStartable(self, lb, logclient.ACT_DELOCATE, nil, self.UserCred, true)
notifyclient.NotifyWebhook(ctx, self.UserCred, lb, notifyclient.ActionDelete)
// notifyclient.NotifyWebhook(ctx, self.UserCred, lb, notifyclient.ActionDelete)
notifyclient.EventNotify(ctx, self.UserCred, notifyclient.SEventNotifyParam{
Obj: lb,
Action: notifyclient.ActionDelete,
})
lb.DeleteEip(ctx, self.UserCred)
lb.LBPendingDelete(ctx, self.GetUserCred())
self.SetStageComplete(ctx, nil)
@@ -159,7 +159,11 @@ func (self *LoadbalancerListenerCreateTask) taskFail(ctx context.Context, lblis
lblis.SetStatus(self.GetUserCred(), api.LB_CREATE_FAILED, reason.String())
db.OpsLog.LogEvent(lblis, db.ACT_ALLOCATE_FAIL, reason, self.UserCred)
logclient.AddActionLogWithStartable(self, lblis, logclient.ACT_CREATE, reason, self.UserCred, false)
notifyclient.NotifySystemErrorWithCtx(ctx, lblis.Id, lblis.Name, api.LB_CREATE_FAILED, reason.String())
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: lblis,
Action: notifyclient.ActionCreate,
IsFail: true,
})
self.SetStageFailed(ctx, reason)
}
@@ -40,7 +40,11 @@ func (self *LoadbalancerListenerDeleteTask) taskFail(ctx context.Context, lblis
lblis.SetStatus(self.GetUserCred(), api.LB_STATUS_DELETE_FAILED, reason.String())
db.OpsLog.LogEvent(lblis, db.ACT_DELOCATE_FAIL, reason, self.UserCred)
logclient.AddActionLogWithStartable(self, lblis, logclient.ACT_DELOCATE, reason, self.UserCred, false)
notifyclient.NotifySystemErrorWithCtx(ctx, lblis.Id, lblis.Name, api.LB_STATUS_DELETE_FAILED, reason.String())
notifyclient.EventNotify(ctx, self.GetUserCred(), notifyclient.SEventNotifyParam{
Obj: lblis,
Action: notifyclient.ActionDelete,
IsFail: true,
})
self.SetStageFailed(ctx, reason)
}
+13
View File
@@ -101,6 +101,19 @@ func (rv *ReceiverVerifyOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(rv.SreceiverVerifyOptions), nil
}
type ReceiverEnableContactTypeInput struct {
ReceiverOptions
SreceiverEnableContactTypeInput
}
func (re *ReceiverEnableContactTypeInput) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(re.SreceiverEnableContactTypeInput), nil
}
type SreceiverEnableContactTypeInput struct {
EnabledContactTypes []string `help:"Enabled contact types"`
}
type ReceiverIntellijGetOptions struct {
USERID string `help:"user id in keystone" json:"user_id"`
CreateIfNo *bool `help:"create if receiver with UserId does not exist"`
+17 -12
View File
@@ -40,14 +40,15 @@ func (so *TopicOptions) Params() (jsonutils.JSONObject, error) {
}
type SubscriberCreateOptions struct {
Name string `positional:"true"`
TopicId string `positional:"true"`
ResourceScope string `positional:"true" choices:"system|domain|project"`
Type string `positional:"true" choices:"receiver|robot|role"`
Receivers []string `help:"required if type is 'receiver'"`
Role string `help:"required if type is 'role'"`
RoleScope string `help:"required if type if 'role'"`
Robot string `help:"required if type if 'robot'"`
TopicId string `positional:"true"`
ResourceScope string `positional:"true" choices:"system|domain|project"`
ResourceAttributionId string `help:"project id or domain id of resource"`
Type string `positional:"true" choices:"receiver|robot|role"`
Receivers []string `help:"required if type is 'receiver'"`
Role string `help:"required if type is 'role'"`
RoleScope string `help:"required if type is 'role'"`
Robot string `help:"required if type is 'robot'"`
Scope string `positional:"true"`
}
func (sc *SubscriberCreateOptions) Params() (jsonutils.JSONObject, error) {
@@ -59,6 +60,7 @@ type SubscriberListOptions struct {
TopicId string
ResourceScope string `choices:"system|domain|project"`
Type string `choices:"receiver|robot|role"`
SCOPE string `choices:"system|domain"`
}
func (sl *SubscriberListOptions) Params() (jsonutils.JSONObject, error) {
@@ -77,13 +79,16 @@ func (s *SubscriberOptions) Params() (jsonutils.JSONObject, error) {
return nil, nil
}
type SubscriberSetReceiverOptions struct {
type SubscriberChangeOptions struct {
SubscriberOptions
Receivers []string
Role string
RoleScope string
Robot string
}
func (ssr *SubscriberSetReceiverOptions) Params() (jsonutils.JSONObject, error) {
params := jsonutils.NewDict()
params.Set("receivers", jsonutils.NewStringArray(ssr.Receivers))
func (ssr *SubscriberChangeOptions) Params() (jsonutils.JSONObject, error) {
params := jsonutils.Marshal(ssr)
params.(*jsonutils.JSONDict).Remove("id")
return params, nil
}
+4 -3
View File
@@ -19,6 +19,7 @@ import (
"yunion.io/x/pkg/errors"
notify_apis "yunion.io/x/onecloud/pkg/apis/notify"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/notify/rpc/apis"
)
@@ -59,15 +60,15 @@ type IServiceConfigStore interface {
GetConfigs(service string) ([]SConfig, error)
GetConfig(service, domainId string) (SConfig, error)
SetConfig(service string, config SConfig) error
HasSystemConfig(service string) (bool, error)
BatchCheckConfig(service string, domainIds []string) ([]bool, error)
HasSystemConfig(service string) (bool, error)
BatchCheckConfig(service string, domainIds []string) ([]bool, error)
}
type SNotification struct {
ContactType string
Topic string
Message string
Event string
Event notify_apis.SEvent
AdvanceDays int
}
-1
View File
@@ -74,7 +74,6 @@ func (cm *SConfigManager) ValidateCreateData(ctx context.Context, userCred mccli
if err != nil {
return input, err
}
log.Infof("input: %s", jsonutils.Marshal(input))
if len(input.ProjectDomainId) > 0 {
_, input.DomainizedResourceInput, err = db.ValidateDomainizedResourceInput(ctx, input.DomainizedResourceInput)
if err != nil {
+68
View File
@@ -0,0 +1,68 @@
// 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 models
import (
"context"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
)
type SEventManager struct {
db.SStandaloneAnonResourceBaseManager
}
var EventManager *SEventManager
func init() {
EventManager = &SEventManager{
SStandaloneAnonResourceBaseManager: db.NewStandaloneAnonResourceBaseManager(
SEvent{},
"events_tbl",
"notifyevent",
"notifyevents",
),
}
EventManager.SetVirtualObject(EventManager)
}
type SEvent struct {
db.SStandaloneAnonResourceBase
Message string
Event string `width:"32" nullable:"true"`
AdvanceDays int
}
func (e *SEventManager) CreateEvent(ctx context.Context, event, message string, advanceDays int) (*SEvent, error) {
eve := &SEvent{
Message: message,
Event: event,
AdvanceDays: advanceDays,
}
err := e.TableSpec().Insert(ctx, eve)
if err != nil {
return nil, err
}
return eve, nil
}
func (e *SEventManager) GetEvent(id string) (*SEvent, error) {
model, err := e.FetchById(id)
if err != nil {
return nil, err
}
return model.(*SEvent), nil
}
+42 -9
View File
@@ -79,12 +79,8 @@ func (lt *SLocalTemplateManager) detailsDisplay(resourceType string, details *js
}
func (lt *SLocalTemplateManager) FillWithTemplate(ctx context.Context, lang string, no notifyv2.SNotification) (params rpcapi.SendParams, err error) {
out := rpcapi.SendParams{}
event, err := parseEvent(no.Event)
if err != nil {
return out, errors.Wrapf(err, "unable to parse event %q", no.Event)
}
rtStr, aStr := event.ResourceType(), string(event.Action())
out, event := rpcapi.SendParams{}, no.Event
rtStr, aStr, resultStr := event.ResourceType(), string(event.Action()), string(event.Result())
dict, err := jsonutils.ParseString(no.Message)
if err != nil {
return out, errors.Wrapf(err, "unable to parse json from %q", no.Message)
@@ -92,10 +88,11 @@ func (lt *SLocalTemplateManager) FillWithTemplate(ctx context.Context, lang stri
webhookMsg := jsonutils.NewDict()
webhookMsg.Set("resource_type", jsonutils.NewString(rtStr))
webhookMsg.Set("action", jsonutils.NewString(aStr))
webhookMsg.Set("result", jsonutils.NewString(resultStr))
webhookMsg.Set("resource_details", dict)
if no.ContactType == api.WEBHOOK {
return rpcapi.SendParams{
Title: no.Topic,
Title: no.Event.StringWithDeli("_"),
Message: webhookMsg.String(),
}, nil
}
@@ -113,6 +110,10 @@ func (lt *SLocalTemplateManager) FillWithTemplate(ctx context.Context, lang stri
if len(aDis) == 0 {
aDis = aStr
}
resultDis := notifyclientI18nTable.LookupByLang(tag, resultStr)
if len(resultDis) == 0 {
resultDis = resultStr
}
lt.detailsDisplay(rtStr, dict.(*jsonutils.JSONDict), tag)
@@ -120,6 +121,7 @@ func (lt *SLocalTemplateManager) FillWithTemplate(ctx context.Context, lang stri
templateParams.Set("advance_days", jsonutils.NewInt(int64(no.AdvanceDays)))
templateParams.Set("resource_type_display", jsonutils.NewString(rtDis))
templateParams.Set("action_display", jsonutils.NewString(aDis))
templateParams.Set("result_display", jsonutils.NewString(resultDis))
// get title
title, err := lt.fillWithTemplate(ctx, "title", no.ContactType, lang, event, templateParams)
@@ -148,6 +150,19 @@ func (lt *SLocalTemplateManager) FillWithTemplate(ctx context.Context, lang stri
var action2Topic = make(map[string]string, 0)
func specTopic(event api.SEvent) string {
switch event.Action() {
case api.ActionRebuildRoot, api.ActionChangeIpaddr, api.ActionResetPassword:
return string(api.ActionUpdate)
case api.ActionDelete:
switch event.ResourceType() {
case api.TOPIC_RESOURCE_BAREMETAL, api.TOPIC_RESOURCE_SERVER, api.TOPIC_RESOURCE_LOADBALANCER, api.TOPIC_RESOURCE_DBINSTANCE, api.TOPIC_RESOURCE_ELASTICCACHE:
return "DELETE_WITH_IP"
}
}
return ""
}
func init() {
action2Topic[string(api.ActionRebuildRoot)] = string(api.ActionUpdate)
action2Topic[string(api.ActionResetPassword)] = string(api.ActionUpdate)
@@ -159,8 +174,11 @@ func (lt *SLocalTemplateManager) fillWithTemplate(ctx context.Context, titleOrCo
tmpl *template.Template
err error
)
actionStr := string(event.Action())
for _, topic := range []string{event.String(), actionStr, action2Topic[actionStr], "common"} {
actionResultStr := event.ActionWithResult("_")
for _, topic := range []string{specTopic(event), event.StringWithDeli("_"), actionResultStr, "common"} {
if topic == "" {
continue
}
tmpl, err = lt.getTemplate(ctx, titleOrContent, contactType, topic, lang)
if errors.Cause(err) == errors.ErrNotFound {
continue
@@ -392,6 +410,11 @@ func init() {
"scheduled task",
"定时任务",
},
sI18nElme{
api.TOPIC_RESOURCE_BAREMETAL,
"baremetal",
"裸金属",
},
sI18nElme{
string(api.ActionCreate),
"created",
@@ -437,5 +460,15 @@ func init() {
"added to the recycle bin",
"加入回收站",
},
sI18nElme{
string(api.ResultFailed),
"failed",
"失败",
},
sI18nElme{
string(api.ResultSucceed),
"successfully",
"成功",
},
)
}
+113 -33
View File
@@ -67,12 +67,11 @@ type SNotification struct {
Topic string `width:"128" nullable:"true" create:"required" search:"user"`
Priority string `width:"16" nullable:"true" create:"optional" list:"user" get:"user"`
// swagger:ignore
Message string `create:"required"`
ReceivedAt time.Time `nullable:"true" list:"user" get:"user"`
Event string `width:"32" nullable:"true" create:"optional"`
AdvanceDays int
SendTimes int
Tag string `width:"16" nullable:"true" index:"true" create:"optional"`
Message string `create:"required"`
ReceivedAt time.Time `nullable:"true" list:"user" get:"user"`
EventId string `width:"128" nullable:"true"`
SendTimes int
Tag string `width:"16" nullable:"true" index:"true" create:"optional"`
}
const (
@@ -220,7 +219,13 @@ func (nm *SNotificationManager) AllowPerformEventNotify(ctx context.Context, use
// TODO: support project and domain
func (nm *SNotificationManager) PerformEventNotify(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.NotificationManagerEventNotifyInput) (api.NotificationManagerEventNotifyOutput, error) {
log.Infof("default receiverIds: %s", input.ReceiverIds)
var output api.NotificationManagerEventNotifyOutput
// check event
_, err := parseEvent(input.Event)
if err != nil {
return output, httperrors.NewInputParameterError("unable to parse event %q", input.Event)
}
// contact type
contactTypes := input.ContactTypes
cts, err := ConfigManager.allContactType()
@@ -245,10 +250,9 @@ func (nm *SNotificationManager) PerformEventNotify(ctx context.Context, userCred
if err != nil {
return output, errors.Wrap(err, "unable to get receive")
}
log.Infof("receiver for topic: %s", receiverIds1)
receiverIds = append(receiverIds, receiverIds1...)
}
// deduplication
receiverIds = sets.NewString(receiverIds...).UnsortedList()
// robot
var robots []string
@@ -262,19 +266,33 @@ func (nm *SNotificationManager) PerformEventNotify(ctx context.Context, userCred
robots = append(robots, _robots...)
}
}
robots = intersection(robots, intersection(cts, RobotContactTypes))
var webhookRobots []string
if len(robots) > 0 {
robots = sets.NewString(robots...).UnsortedList()
rs, err := RobotManager.FetchByIdOrNames(ctx, robots...)
if err != nil {
return output, errors.Wrap(err, "unable to get robots")
}
robots, webhookRobots = make([]string, 0, len(rs)), make([]string, 0, 1)
for i := range rs {
if rs[i].Type == api.ROBOT_TYPE_WEBHOOK {
webhookRobots = append(webhookRobots, rs[i].Id)
} else {
robots = append(robots, rs[i].Id)
}
}
}
message := jsonutils.Marshal(input.ResourceDetails).String()
// append default receiver
receiverIds = append(receiverIds, input.ReceiverIds...)
// fillter non-existed receiver
receivers, err := ReceiverManager.FetchByIdOrNames(ctx, receiverIds...)
if err != nil {
return output, errors.Wrap(err, "unable to fetch receivers by ids")
}
webconsoleContacts := make([]string, 0)
webconsoleContacts := sets.NewString()
idSet := sets.NewString()
for i := range receivers {
idSet.Insert(receivers[i].Id)
@@ -283,12 +301,18 @@ func (nm *SNotificationManager) PerformEventNotify(ctx context.Context, userCred
if idSet.Has(re) {
continue
}
webconsoleContacts = append(webconsoleContacts, re)
webconsoleContacts.Insert(re)
}
receiverIds = idSet.UnsortedList()
// create event
event, err := EventManager.CreateEvent(ctx, input.Event, message, input.AdvanceDays)
if err != nil {
return output, errors.Wrap(err, "unable to create Event")
}
// webconsole
err = nm.create(ctx, userCred, api.WEBCONSOLE, receiverIds, webconsoleContacts, input.Priority, "", message, input.Event, input.AdvanceDays)
err = nm.create(ctx, userCred, api.WEBCONSOLE, receiverIds, webconsoleContacts.UnsortedList(), input.Priority, event.Id)
if err != nil {
output.FailedList = append(output.FailedList, api.FailedElem{
ContactType: api.WEBCONSOLE,
@@ -297,7 +321,10 @@ func (nm *SNotificationManager) PerformEventNotify(ctx context.Context, userCred
}
// normal contact type
for _, ct := range contactTypes {
err := nm.create(ctx, userCred, ct, receiverIds, nil, input.Priority, "", message, input.Event, input.AdvanceDays)
if ct == api.MOBILE {
continue
}
err := nm.create(ctx, userCred, ct, receiverIds, nil, input.Priority, event.Id)
if err != nil {
output.FailedList = append(output.FailedList, api.FailedElem{
ContactType: ct,
@@ -305,26 +332,64 @@ func (nm *SNotificationManager) PerformEventNotify(ctx context.Context, userCred
})
}
}
err = nm.createWithWebhookRobots(ctx, userCred, webhookRobots, input.Priority, event.Id)
if err != nil {
output.FailedList = append(output.FailedList, api.FailedElem{
ContactType: api.WEBHOOK,
Reason: err.Error(),
})
}
// robot
err = nm.createWithRobots(ctx, userCred, robots, input.Priority, "", message, input.Event, input.AdvanceDays)
output.FailedList = append(output.FailedList, api.FailedElem{
ContactType: api.ROBOT,
Reason: err.Error(),
})
err = nm.createWithRobots(ctx, userCred, robots, input.Priority, event.Id)
if err != nil {
output.FailedList = append(output.FailedList, api.FailedElem{
ContactType: api.ROBOT,
Reason: err.Error(),
})
}
return output, nil
}
func (nm *SNotificationManager) createWithRobots(ctx context.Context, userCred mcclient.TokenCredential, robotIds []string, priority, topic, message, event string, advanceDays int) error {
func (nm *SNotificationManager) createWithWebhookRobots(ctx context.Context, userCred mcclient.TokenCredential, webhookRobotIds []string, priority, eventId string) error {
if len(webhookRobotIds) == 0 {
return nil
}
n := &SNotification{
ContactType: api.WEBHOOK,
Priority: priority,
ReceivedAt: time.Now(),
EventId: eventId,
}
n.Id = db.DefaultUUIDGenerator()
for i := range webhookRobotIds {
_, err := ReceiverNotificationManager.CreateRobot(ctx, userCred, webhookRobotIds[i], n.Id)
if err != nil {
return errors.Wrap(err, "ReceiverNotificationManager.CreateRobot")
}
}
err := nm.TableSpec().Insert(ctx, n)
if err != nil {
return errors.Wrap(err, "unable to insert Notification")
}
n.SetModelManager(nm, n)
task, err := taskman.TaskManager.NewTask(ctx, "NotificationSendTask", n, userCred, nil, "", "")
if err != nil {
log.Errorf("NotificationSendTask newTask error %v", err)
} else {
task.ScheduleRun(nil)
}
return nil
}
func (nm *SNotificationManager) createWithRobots(ctx context.Context, userCred mcclient.TokenCredential, robotIds []string, priority, eventId string) error {
if len(robotIds) == 0 {
return nil
}
n := &SNotification{
ContactType: api.ROBOT,
Message: message,
Priority: priority,
ReceivedAt: time.Now(),
Event: event,
AdvanceDays: advanceDays,
EventId: eventId,
}
n.Id = db.DefaultUUIDGenerator()
for i := range robotIds {
@@ -347,7 +412,7 @@ func (nm *SNotificationManager) createWithRobots(ctx context.Context, userCred m
return nil
}
func (nm *SNotificationManager) create(ctx context.Context, userCred mcclient.TokenCredential, contactType string, receiverIds, contacts []string, priority, topic, message, event string, advanceDays int) error {
func (nm *SNotificationManager) create(ctx context.Context, userCred mcclient.TokenCredential, contactType string, receiverIds, contacts []string, priority, eventId string) error {
if len(receiverIds)+len(contacts) == 0 {
log.Infof("%s: no send", contactType)
return nil
@@ -355,11 +420,9 @@ func (nm *SNotificationManager) create(ctx context.Context, userCred mcclient.To
n := &SNotification{
ContactType: contactType,
Message: message,
Priority: priority,
ReceivedAt: time.Now(),
Event: event,
AdvanceDays: advanceDays,
EventId: eventId,
}
n.Id = db.DefaultUUIDGenerator()
err := nm.TableSpec().Insert(ctx, n)
@@ -454,6 +517,7 @@ func (n *SNotification) ReceiveDetails(userCred mcclient.TokenCredential, scope
q.AppendField(subRQ.Field("name", "receiver_name"))
q = q.Join(subRQ, sqlchemy.OR(sqlchemy.Equals(q.Field("receiver_id"), subRQ.Field("id")), sqlchemy.Equals(q.Field("contact"), subRQ.Field("id"))))
}
q.DebugQuery()
ret := make([]api.ReceiveDetail, 0, 2)
err := q.All(&ret)
if err != nil && errors.Cause(err) != sql.ErrNoRows {
@@ -466,7 +530,11 @@ func (n *SNotification) ReceiveDetails(userCred mcclient.TokenCredential, scope
func (n *SNotification) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, out api.NotificationDetails) (api.NotificationDetails, error) {
// get title adn content
lang := getLangSuffix(ctx)
p, err := n.TemplateStore().FillWithTemplate(ctx, lang, n.Notification())
nn, err := n.Notification()
if err != nil {
return out, err
}
p, err := n.TemplateStore().FillWithTemplate(ctx, lang, nn)
if err != nil {
return out, err
}
@@ -482,14 +550,26 @@ func (n *SNotification) getMoreDetails(ctx context.Context, userCred mcclient.To
return out, nil
}
func (n *SNotification) Notification() notifyv2.SNotification {
func (n *SNotification) Notification() (notifyv2.SNotification, error) {
if n.EventId == "" {
return notifyv2.SNotification{
ContactType: n.ContactType,
Topic: n.Topic,
Message: n.Message,
}, nil
}
event, err := EventManager.GetEvent(n.EventId)
if err != nil {
return notifyv2.SNotification{}, err
}
e, _ := parseEvent(event.Event)
return notifyv2.SNotification{
ContactType: n.ContactType,
Topic: n.Topic,
Message: n.Message,
Event: n.Event,
AdvanceDays: n.AdvanceDays,
}
Message: event.Message,
Event: e,
AdvanceDays: event.AdvanceDays,
}, nil
}
func (nm *SNotificationManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
@@ -738,7 +818,7 @@ func (nm *SNotificationManager) ReSend(ctx context.Context, userCred mcclient.To
}
func (n *SNotification) TemplateStore() notifyv2.ITemplateStore {
if len(n.Event) == 0 || n.ContactType == api.MOBILE {
if len(n.EventId) == 0 || n.ContactType == api.MOBILE {
return TemplateManager
}
return LocalTemplateManager
+25
View File
@@ -1294,3 +1294,28 @@ func (r *SReceiver) GetContact(cType string) (string, error) {
func (r *SReceiver) GetDomainId() string {
return r.DomainId
}
func (r *SReceiver) AllowPerformEnableContactType(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return r.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, r, "enable-contact-type")
}
func (r *SReceiver) PerformEnableContactType(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ReceiverEnableContactTypeInput) (jsonutils.JSONObject, error) {
err := r.PullCache(false)
if err != nil {
return nil, errors.Wrap(err, "unable to pull cache")
}
err = r.SetEnabledContactTypes(input.EnabledContactTypes)
if err != nil {
return nil, errors.Wrap(err, "unable to set enabled contact types")
}
err = r.PushCache(ctx)
if err != nil {
return nil, errors.Wrap(err, "unable to push cache")
}
r.SetStatus(userCred, api.RECEIVER_STATUS_PULLING, "")
err = r.StartSubcontactPullTask(ctx, userCred, nil, "")
if err != nil {
log.Errorf("unable to StartSubcontactPullTask: %v", err)
}
return nil, nil
}
+25 -16
View File
@@ -2,9 +2,11 @@ package models
import (
"context"
"net/http"
"time"
api "yunion.io/x/onecloud/pkg/apis/notify"
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/mcclient"
)
@@ -95,6 +97,13 @@ func (rnm *SReceiverNotificationManager) CreateContact(ctx context.Context, user
return rn, rnm.TableSpec().Insert(ctx, rn)
}
func (rnm *SReceiverNotificationManager) SetHandlerProcessTimeout(info *appsrv.SHandlerInfo, r *http.Request) time.Duration {
if r.Method == http.MethodGet && len(r.URL.Query().Get("export_keys")) > 0 {
return time.Hour * 2
}
return -time.Second
}
// func (rn *SReceiverNotification) Receiver() (*SReceiver, error) {
// q := ReceiverManager.Query().Equals("id", rn.ReceiverID)
// var receiver SReceiver
@@ -118,30 +127,30 @@ func (rn *SReceiverNotification) receiver() (*SReceiver, error) {
}
func (rn *SReceiverNotification) robot() (*SRobot, error) {
q := RobotManager.Query().Equals("id", rn.ReceiverID)
var robot SRobot
err := q.First(&robot)
if err != nil {
return nil, err
}
robot.SetModelManager(RobotManager, &robot)
return &robot, nil
q := RobotManager.Query().Equals("id", rn.ReceiverID)
var robot SRobot
err := q.First(&robot)
if err != nil {
return nil, err
}
robot.SetModelManager(RobotManager, &robot)
return &robot, nil
}
func (rn *SReceiverNotification) Receiver() (IReceiver, error) {
switch rn.ReceiverType {
case api.RECEIVER_TYPE_USER:
return rn.receiver()
return rn.receiver()
case api.RECEIVER_TYPE_CONTACT:
return &SContact{contact: rn.Contact}, nil
case api.RECEIVER_TYPE_ROBOT:
return rn.robot()
return rn.robot()
default:
// compatible
if rn.ReceiverID != "" && rn.ReceiverID != ReceiverIdDefault {
return rn.receiver()
}
return &SContact{contact: rn.Contact}, nil
if rn.ReceiverID != "" && rn.ReceiverID != ReceiverIdDefault {
return rn.receiver()
}
return &SContact{contact: rn.Contact}, nil
}
}
@@ -172,7 +181,7 @@ func (rn *SReceiverNotification) AfterSend(ctx context.Context, success bool, re
type IReceiver interface {
IsEnabled() bool
GetDomainId() string
GetDomainId() string
IsEnabledContactType(string) (bool, error)
IsVerifiedContactType(string) (bool, error)
GetContact(string) (string, error)
@@ -187,7 +196,7 @@ func (s SReceiverBase) IsEnabled() bool {
}
func (s SReceiverBase) GetDomainId() string {
return ""
return ""
}
func (s SReceiverBase) IsEnabledContactType(_ string) (bool, error) {
+10 -3
View File
@@ -4,10 +4,12 @@ import (
"context"
"strings"
"github.com/pkg/errors"
"golang.org/x/text/language"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/tristate"
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
@@ -211,6 +213,11 @@ func (r *SRobot) ValidateUpdateData(ctx context.Context, userCred mcclient.Token
}
func (r *SRobot) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
err := r.SSharableVirtualResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
if err != nil {
return err
}
r.Enabled = tristate.True
r.Status = api.ROBOT_STATUS_READY
return nil
}
@@ -234,11 +241,11 @@ func (r *SRobot) IsEnabled() bool {
}
func (r *SRobot) IsEnabledContactType(ctype string) (bool, error) {
return ctype == api.ROBOT, nil
return ctype == api.ROBOT || ctype == api.WEBHOOK, nil
}
func (r *SRobot) IsVerifiedContactType(ctype string) (bool, error) {
return ctype == api.ROBOT, nil
return ctype == api.ROBOT || ctype == api.WEBHOOK, nil
}
func (r *SRobot) GetContact(ctype string) (string, error) {
+142 -21
View File
@@ -25,6 +25,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/tristate"
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
@@ -34,6 +35,7 @@ import (
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
@@ -41,7 +43,7 @@ var SubscriberManager *SSubscriberManager
func init() {
SubscriberManager = &SSubscriberManager{
SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
SStandaloneAnonResourceBaseManager: db.NewStandaloneAnonResourceBaseManager(
SSubscriber{},
"subscriber_tbl",
"subscriber",
@@ -52,19 +54,22 @@ func init() {
}
type SSubscriberManager struct {
db.SVirtualResourceBaseManager
db.SStandaloneAnonResourceBaseManager
db.SEnabledResourceBaseManager
}
type SSubscriber struct {
db.SVirtualResourceBase
db.SStandaloneAnonResourceBase
db.SEnabledResourceBase
TopicID string `width:"128" charset:"ascii" nullable:"false" index:"true" get:"user" list:"user"`
Type string `width:"16" charset:"ascii" nullable:"false" index:"true" get:"user" list:"user"`
Identification string `width:"128" charset:"ascii" nullable:"false" index:"true"`
RoleScope string `width:"8" charset:"ascii" nullable:"false" get:"user" list:"user"`
ResourceScope string `width:"8" charset:"ascii" nullable:"false" get:"user" list:"user"`
TopicID string `width:"128" charset:"ascii" nullable:"false" index:"true" get:"user" list:"user" create:"required"`
Type string `width:"16" charset:"ascii" nullable:"false" index:"true" get:"user" list:"user" create:"required"`
Identification string `width:"128" charset:"ascii" nullable:"false" index:"true"`
RoleScope string `width:"8" charset:"ascii" nullable:"false" get:"user" list:"user" create:"optional"`
ResourceScope string `width:"8" charset:"ascii" nullable:"false" get:"user" list:"user" create:"required"`
ResourceAttributionId string `width:"128" charset:"ascii" nullable:"false" get:"user" list:"user" create:"optional"`
Scope string `width:"128" charset:"ascii" nullable:"false" create:"required"`
DomainId string `width:"128" charset:"ascii" nullable:"false" create:"optional"`
}
func (sm *SSubscriberManager) validateReceivers(ctx context.Context, receivers []string) ([]string, error) {
@@ -86,8 +91,25 @@ func (sm *SSubscriberManager) validateReceivers(ctx context.Context, receivers [
}
func (sm *SSubscriberManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.SubscriberCreateInput) (api.SubscriberCreateInput, error) {
log.Infof("before deal: %s", jsonutils.Marshal(input))
var err error
input.VirtualResourceCreateInput, err = sm.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.VirtualResourceCreateInput)
// permission check
sSystem, sDomain := string(rbacutils.ScopeSystem), string(rbacutils.ScopeDomain)
switch input.Scope {
case sSystem:
allow := db.IsAdminAllowCreate(userCred, sm)
if !allow {
return input, httperrors.NewForbiddenError("The scope %s and the role of the operator do not match", input.Scope)
}
case sDomain:
allow := db.IsDomainAllowCreate(userCred, sm)
if !allow {
return input, httperrors.NewForbiddenError("The scope %s and the role of the operator do not match", input.Scope)
}
default:
return input, httperrors.NewInputParameterError("unknown scope %s", input.Scope)
}
input.StandaloneAnonResourceCreateInput, err = sm.SStandaloneAnonResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StandaloneAnonResourceCreateInput)
if err != nil {
return input, errors.Wrap(err, "SVirtualResourceBaseManager.ValidateCreateData")
}
@@ -100,6 +122,32 @@ func (sm *SSubscriberManager) ValidateCreateData(ctx context.Context, userCred m
if !utils.IsInStringArray(input.ResourceScope, []string{api.SUBSCRIBER_SCOPE_SYSTEM, api.SUBSCRIBER_SCOPE_DOMAIN, api.SUBSCRIBER_SCOPE_PROJECT}) {
return input, httperrors.NewInputParameterError("unknown resource_scope %q", input.ResourceScope)
}
// resource Attribution Id
var domainId string
switch input.ResourceScope {
case api.SUBSCRIBER_SCOPE_SYSTEM:
input.ResourceAttributionId = ""
input.DomainId = ""
case api.SUBSCRIBER_SCOPE_PROJECT:
tenant, err := db.TenantCacheManager.FetchTenantByIdOrName(ctx, input.ResourceAttributionId)
if err != nil {
return input, errors.Wrapf(err, "unable to fetch project %s", input.ResourceAttributionId)
}
domainId = tenant.DomainId
input.DomainId = domainId
input.ResourceAttributionId = tenant.GetId()
case api.SUBSCRIBER_SCOPE_DOMAIN:
tenant, err := db.TenantCacheManager.FetchDomainByIdOrName(ctx, input.ResourceAttributionId)
if err != nil {
return input, errors.Wrapf(err, "unable to fetch domain %s", input.ResourceAttributionId)
}
domainId = tenant.DomainId
input.DomainId = domainId
input.ResourceAttributionId = tenant.DomainId
}
if input.Scope == sDomain && domainId != userCred.GetDomainId() {
return input, httperrors.NewForbiddenError("domain %s admin can't create subscriber for domain %s", userCred.GetDomainId(), domainId)
}
input.TopicID = t.GetId()
switch input.Type {
case api.SUBSCRIBER_TYPE_RECEIVER:
@@ -129,11 +177,12 @@ func (sm *SSubscriberManager) ValidateCreateData(ctx context.Context, userCred m
default:
return input, httperrors.NewInputParameterError("unkown type %q", input.Type)
}
log.Infof("after deal input: %s", jsonutils.Marshal(input))
return input, nil
}
func (s *SSubscriber) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
err := s.SVirtualResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
err := s.SStandaloneAnonResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
if err != nil {
return errors.Wrap(err, "SVirtualResourceBase.CustomizeCreate")
}
@@ -150,12 +199,44 @@ func (s *SSubscriber) CustomizeCreate(ctx context.Context, userCred mcclient.Tok
case api.SUBSCRIBER_TYPE_ROLE:
s.Identification = input.Role
}
s.Enabled = tristate.True
return nil
}
func (s *SSubscriber) AllowPerformChange(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return true
}
func (s *SSubscriber) PerformChange(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.SubscriberChangeInput) (jsonutils.JSONObject, error) {
if s.Scope == string(rbacutils.ScopeSystem) {
if !db.IsAdminAllowUpdate(userCred, s) {
return nil, httperrors.NewForbiddenError("")
}
} else {
if !db.IsDomainAllowUpdate(userCred, s) {
return nil, httperrors.NewForbiddenError("")
}
if s.DomainId != userCred.GetDomainId() {
return nil, httperrors.NewForbiddenError("")
}
}
switch s.Type {
case api.SUBSCRIBER_TYPE_RECEIVER:
err := s.SetReceivers(ctx, input.Receivers)
if err != nil {
log.Errorf("unable to set receivers %s", input.Receivers)
}
case api.SUBSCRIBER_TYPE_ROBOT:
s.Identification = input.Robot
case api.SUBSCRIBER_TYPE_ROLE:
s.Identification = input.Role
}
return nil, nil
}
func (sm *SSubscriberManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.SubscriberListInput) (*sqlchemy.SQuery, error) {
var err error
q, err = sm.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.VirtualResourceListInput)
q, err = sm.SStandaloneAnonResourceBaseManager.ListItemFilter(ctx, q, userCred, input.StandaloneAnonResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter")
}
@@ -163,6 +244,25 @@ func (sm *SSubscriberManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ
if err != nil {
return nil, errors.Wrap(err, "SEnabledResourceBaseManager.ListItemFilter")
}
sSystem, sDomain := string(rbacutils.ScopeSystem), string(rbacutils.ScopeDomain)
if input.Scope == "" {
input.Scope = sSystem
}
switch input.Scope {
case sSystem:
allow := db.IsAdminAllowList(userCred, sm)
if !allow {
return nil, httperrors.NewForbiddenError("")
}
case sDomain:
allow := db.IsAdminAllowList(userCred, sm)
if !allow {
return nil, httperrors.NewForbiddenError("")
}
q = q.Equals("domain_id", userCred.GetDomainId())
default:
return nil, httperrors.NewInputParameterError("unkown scope %s", input.Scope)
}
if input.TopicID != "" {
q = q.Equals("topic_id", input.TopicID)
}
@@ -177,10 +277,10 @@ func (sm *SSubscriberManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ
func (sm *SSubscriberManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []interface{}, fields stringutils2.SSortedStrings, isList bool) []api.SubscriberDetails {
var err error
vRows := sm.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
vRows := sm.SStandaloneAnonResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
rows := make([]api.SubscriberDetails, len(objs))
for i := range rows {
rows[i].VirtualResourceDetails = vRows[i]
rows[i].StandaloneAnonResourceDetails = vRows[i]
s := objs[i].(*SSubscriber)
switch s.Type {
case api.SUBSCRIBER_TYPE_RECEIVER:
@@ -203,6 +303,26 @@ func (sm *SSubscriberManager) FetchCustomizeColumns(ctx context.Context, userCre
return rows
}
func (s *SSubscriber) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
err := s.SStandaloneAnonResourceBase.CustomizeDelete(ctx, userCred, query, data)
if err != nil {
return err
}
if s.Scope == string(rbacutils.ScopeSystem) {
if !db.IsAdminAllowDelete(userCred, s) {
return httperrors.NewForbiddenError("")
}
} else {
if !db.IsDomainAllowDelete(userCred, s) {
return httperrors.NewForbiddenError("")
}
if s.DomainId != userCred.GetDomainId() {
return httperrors.NewForbiddenError("")
}
}
return nil
}
func (s *SSubscriber) receiverIdentifications() ([]api.Identification, error) {
srSubq := SubscriberReceiverManager.Query().Equals("subscription_id", s.Id).SubQuery()
rq := ReceiverManager.Query("id", "name")
@@ -248,17 +368,17 @@ func (srm *SSubscriberManager) robot(tid, projectDomainId, projectId string) ([]
}
func (srm *SSubscriberManager) findSuitableOnes(tid, projectDomainId, projectId string, types ...string) ([]SSubscriber, error) {
q := srm.Query().Equals("subscription_id", tid)
q := srm.Query().Equals("topic_id", tid).IsTrue("enabled")
q = q.Filter(sqlchemy.OR(
sqlchemy.AND(
sqlchemy.Equals(q.Field("resource_type"), api.SUBSCRIBER_SCOPE_PROJECT),
sqlchemy.Equals(q.Field("project_id"), projectId),
sqlchemy.Equals(q.Field("resource_scope"), api.SUBSCRIBER_SCOPE_PROJECT),
sqlchemy.Equals(q.Field("resource_attribution_id"), projectId),
),
sqlchemy.AND(
sqlchemy.Equals(q.Field("resource_type"), api.SUBSCRIBER_SCOPE_DOMAIN),
sqlchemy.Equals(q.Field("domain_id"), projectDomainId),
sqlchemy.Equals(q.Field("resource_scope"), api.SUBSCRIBER_SCOPE_DOMAIN),
sqlchemy.Equals(q.Field("resource_attribution_id"), projectDomainId),
),
sqlchemy.Equals(q.Field("resource_type"), api.SUBSCRIBER_SCOPE_SYSTEM),
sqlchemy.Equals(q.Field("resource_scope"), api.SUBSCRIBER_SCOPE_SYSTEM),
))
switch len(types) {
case 0:
@@ -267,6 +387,7 @@ func (srm *SSubscriberManager) findSuitableOnes(tid, projectDomainId, projectId
default:
q = q.In("type", types)
}
q.DebugQuery()
srs := make([]SSubscriber, 0, 1)
err := db.FetchModelObjects(srm, q, &srs)
if err != nil {
@@ -291,7 +412,7 @@ func (srm *SSubscriberManager) getReceiversSent(ctx context.Context, tid string,
return nil, errors.Wrap(err, "unable to get receivers")
}
receivers = append(receivers, rIds...)
} else if sr.Type == api.SUBSCRIBER_TYPE_ROBOT {
} else if sr.Type == api.SUBSCRIBER_TYPE_ROLE {
roleMap[sr.RoleScope] = append(roleMap[sr.RoleScope], sr.Identification)
receivermap[sr.RoleScope] = &[]string{}
}
@@ -407,7 +528,7 @@ func (sr *SSubscriber) SetReceivers(ctx context.Context, receiverIds []string) e
}
func (s *SSubscriber) AllowPerformSetReceiver(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return s.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, s, "set-receiver")
return db.IsAdminAllowPerform(userCred, s, "set-receiver")
}
func (s *SSubscriber) PerformSetReceiver(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.SubscriberSetReceiverInput) (jsonutils.JSONObject, error) {
+170 -66
View File
@@ -18,8 +18,10 @@ import (
"context"
"fmt"
"strings"
"sync"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/tristate"
"yunion.io/x/pkg/util/sets"
@@ -34,11 +36,16 @@ import (
)
func parseEvent(es string) (notify.SEvent, error) {
es = strings.ToLower(es)
ess := strings.Split(es, notify.DelimiterInEvent)
if len(ess) != 2 {
if len(ess) != 2 && len(ess) != 3 {
return notify.SEvent{}, fmt.Errorf("invalid event string %q", es)
}
return notify.Event.WithResourceType(ess[0]).WithAction(notify.SAction(ess[1])), nil
event := notify.Event.WithResourceType(ess[0]).WithAction(notify.SAction(ess[1]))
if len(ess) == 3 {
event = event.WithResult(notify.SResult(ess[2]))
}
return event, nil
}
type STopicManager struct {
@@ -67,18 +74,20 @@ type STopic struct {
Type string `width:"20" nullable:"false" create:"required" update:"user" list:"user"`
Resources uint64 `nullable:"false"`
Actions uint32 `nullable:"false"`
Results uint8 `nullable:"false"`
AdvanceDays int `nullable:"false"`
}
const (
DefaultResourceCreateDelete = "resource create or delete"
DefaultResourceChangeConfig = "resource change config"
DefaultResourceUpdate = "resource update"
DefaultResourceReleaseDue1Day = "resource release due 1 day"
DefaultResourceReleaseDue3Day = "resource release due 3 day"
DefaultScheduledTaskExecute = "scheduled task execute"
DefaultScalingPolicyExecute = "scaling policy execute"
DefaultSnapshotPolicyExecute = "snapshot policy execute"
DefaultResourceCreateDelete = "resource create or delete"
DefaultResourceChangeConfig = "resource change config"
DefaultResourceUpdate = "resource update"
DefaultResourceReleaseDue1Day = "resource release due 1 day"
DefaultResourceReleaseDue3Day = "resource release due 3 day"
DefaultScheduledTaskExecute = "scheduled task execute"
DefaultScalingPolicyExecute = "scaling policy execute"
DefaultSnapshotPolicyExecute = "snapshot policy execute"
DefaultResourceOperationFailed = "resource operation failed"
)
func (sm *STopicManager) InitializeData() error {
@@ -91,6 +100,7 @@ func (sm *STopicManager) InitializeData() error {
DefaultScheduledTaskExecute,
DefaultScalingPolicyExecute,
DefaultSnapshotPolicyExecute,
DefaultResourceOperationFailed,
)
q := sm.Query()
topics := make([]STopic, 0, initSNames.Len())
@@ -125,6 +135,7 @@ func (sm *STopicManager) InitializeData() error {
notify.TOPIC_RESOURCE_BUCKET,
notify.TOPIC_RESOURCE_DBINSTANCE,
notify.TOPIC_RESOURCE_ELASTICCACHE,
notify.TOPIC_RESOURCE_BAREMETAL,
)
t.addAction(
notify.ActionCreate,
@@ -189,6 +200,24 @@ func (sm *STopicManager) InitializeData() error {
t.addResources(notify.TOPIC_RESOURCE_SNAPSHOTPOLICY)
t.addAction(notify.ActionExecute)
t.Type = notify.TOPIC_TYPE_AUTOMATED_PROCESS
case DefaultResourceOperationFailed:
t.addResources(
notify.TOPIC_RESOURCE_SERVER,
notify.TOPIC_RESOURCE_EIP,
notify.TOPIC_RESOURCE_LOADBALANCER,
notify.TOPIC_RESOURCE_DBINSTANCE,
notify.TOPIC_RESOURCE_ELASTICCACHE,
)
t.addAction(
notify.ActionCreate,
notify.ActionSyncStatus,
notify.ActionRebuildRoot,
notify.ActionChangeConfig,
notify.ActionCreateBackupServer,
notify.ActionDelBackupServer,
notify.ActionMigrate,
)
t.Type = notify.TOPIC_TYPE_RESOURCE
}
err := sm.TableSpec().Insert(ctx, t)
if err != nil {
@@ -293,7 +322,15 @@ func (sm *STopicManager) TopicsByEvent(eventStr string, advanceDays int) ([]STop
return nil, errors.Wrapf(err, "unable to parse event %q", event)
}
resourceV := converter.resourceValue(event.ResourceType())
if resourceV < 0 {
log.Warningf("unknown resource type: %s", event.ResourceType())
return nil, nil
}
actionV := converter.actionValue(event.Action())
if actionV < 0 {
log.Warningf("unknown action type: %s", event.Action())
return nil, nil
}
q := sm.Query().Equals("advance_days", advanceDays)
q = q.Filter(sqlchemy.GT(sqlchemy.AND_Val("", q.Field("resources"), 1<<resourceV), 0))
q = q.Filter(sqlchemy.GT(sqlchemy.AND_Val("", q.Field("actions"), 1<<actionV), 0))
@@ -306,102 +343,169 @@ func (sm *STopicManager) TopicsByEvent(eventStr string, advanceDays int) ([]STop
return topics, nil
}
func (t *STopic) AllowPerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input notify.PerformEnableInput) bool {
return db.IsAdminAllowPerform(userCred, t, "enable")
}
func (t *STopic) PreCheckPerformAction(
ctx context.Context, userCred mcclient.TokenCredential,
action string, query jsonutils.JSONObject, data jsonutils.JSONObject,
) error {
if err := t.SStandaloneResourceBase.PreCheckPerformAction(ctx, userCred, action, query, data); err != nil {
return err
}
if action == "enable" || action == "disable" {
if !db.IsAdminAllowPerform(userCred, t, action) {
return httperrors.NewForbiddenError("only allow admin to perform enable operations")
}
}
return nil
}
func (t *STopic) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input notify.PerformEnableInput) (jsonutils.JSONObject, error) {
err := db.EnabledPerformEnable(t, ctx, userCred, true)
if err != nil {
return nil, errors.Wrap(err, "EnabledPerformEnable")
}
return nil, nil
}
func (t *STopic) AllowPerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input notify.PerformDisableInput) bool {
return db.IsAdminAllowPerform(userCred, t, "disable")
}
func (t *STopic) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input notify.PerformDisableInput) (jsonutils.JSONObject, error) {
err := db.EnabledPerformEnable(t, ctx, userCred, false)
if err != nil {
return nil, errors.Wrap(err, "EnabledPerformEnable")
}
return nil, nil
}
func init() {
converter = &sConverter{
resourceValueMap: make(map[string]int, 5),
resourceList: make([]string, 0, 5),
actionList: make([]notify.SAction, 0, 5),
actionValueMap: make(map[notify.SAction]int, 5),
resource2Value: &sync.Map{},
value2Resource: &sync.Map{},
action2Value: &sync.Map{},
value2Action: &sync.Map{},
}
converter.registerResource(
notify.TOPIC_RESOURCE_SERVER,
notify.TOPIC_RESOURCE_SCALINGGROUP,
notify.TOPIC_RESOURCE_SCALINGPOLICY,
notify.TOPIC_RESOURCE_IMAGE,
notify.TOPIC_RESOURCE_DISK,
notify.TOPIC_RESOURCE_SNAPSHOT,
notify.TOPIC_RESOURCE_INSTANCESNAPSHOT,
notify.TOPIC_RESOURCE_SNAPSHOTPOLICY,
notify.TOPIC_RESOURCE_NETWORK,
notify.TOPIC_RESOURCE_EIP,
notify.TOPIC_RESOURCE_SECGROUP,
notify.TOPIC_RESOURCE_LOADBALANCER,
notify.TOPIC_RESOURCE_LOADBALANCERACL,
notify.TOPIC_RESOURCE_LOADBALANCERCERTIFICATE,
notify.TOPIC_RESOURCE_BUCKET,
notify.TOPIC_RESOURCE_DBINSTANCE,
notify.TOPIC_RESOURCE_ELASTICCACHE,
notify.TOPIC_RESOURCE_SCHEDULEDTASK,
map[string]int{
notify.TOPIC_RESOURCE_SERVER: 0,
notify.TOPIC_RESOURCE_SCALINGGROUP: 1,
notify.TOPIC_RESOURCE_SCALINGPOLICY: 2,
notify.TOPIC_RESOURCE_IMAGE: 3,
notify.TOPIC_RESOURCE_DISK: 4,
notify.TOPIC_RESOURCE_SNAPSHOT: 5,
notify.TOPIC_RESOURCE_INSTANCESNAPSHOT: 6,
notify.TOPIC_RESOURCE_SNAPSHOTPOLICY: 7,
notify.TOPIC_RESOURCE_NETWORK: 8,
notify.TOPIC_RESOURCE_EIP: 9,
notify.TOPIC_RESOURCE_SECGROUP: 10,
notify.TOPIC_RESOURCE_LOADBALANCER: 11,
notify.TOPIC_RESOURCE_LOADBALANCERACL: 12,
notify.TOPIC_RESOURCE_LOADBALANCERCERTIFICATE: 13,
notify.TOPIC_RESOURCE_BUCKET: 14,
notify.TOPIC_RESOURCE_DBINSTANCE: 15,
notify.TOPIC_RESOURCE_ELASTICCACHE: 16,
notify.TOPIC_RESOURCE_SCHEDULEDTASK: 17,
notify.TOPIC_RESOURCE_BAREMETAL: 18,
},
)
converter.registerAction(
notify.ActionCreate,
notify.ActionDelete,
notify.ActionPendingDelete,
notify.ActionUpdate,
notify.ActionRebuildRoot,
notify.ActionResetPassword,
notify.ActionChangeConfig,
notify.ActionExpiredRelease,
notify.ActionExecute,
notify.ActionChangeIpaddr,
map[notify.SAction]int{
notify.ActionCreate: 0,
notify.ActionDelete: 1,
notify.ActionPendingDelete: 2,
notify.ActionUpdate: 3,
notify.ActionRebuildRoot: 4,
notify.ActionResetPassword: 5,
notify.ActionChangeConfig: 6,
notify.ActionExpiredRelease: 7,
notify.ActionExecute: 8,
notify.ActionChangeIpaddr: 9,
notify.ActionSyncStatus: 10,
notify.ActionCleanData: 11,
notify.ActionMigrate: 12,
notify.ActionCreateBackupServer: 13,
notify.ActionDelBackupServer: 14,
},
)
}
var converter *sConverter
type sConverter struct {
resourceValueMap map[string]int
resourceList []string
actionValueMap map[notify.SAction]int
actionList []notify.SAction
resource2Value *sync.Map
value2Resource *sync.Map
action2Value *sync.Map
value2Action *sync.Map
}
func (rc *sConverter) registerResource(resources ...string) {
for _, resource := range resources {
if _, ok := rc.resourceValueMap[resource]; ok {
return
type sResourceValue struct {
resource string
value int
}
type sActionValue struct {
action string
value int
}
func (rc *sConverter) registerResource(resourceValues map[string]int) {
for resource, value := range resourceValues {
if v, ok := rc.resource2Value.Load(resource); ok && v.(int) != value {
log.Fatalf("resource '%s' has been mapped to value '%d', and it is not allowed to map to another value '%d'", resource, v, value)
}
rc.resourceList = append(rc.resourceList, resource)
rc.resourceValueMap[resource] = len(rc.resourceList) - 1
if r, ok := rc.value2Resource.Load(value); ok && r.(string) != resource {
log.Fatalf("value '%d' has been mapped to resource '%s', and it is not allowed to map to another resource '%s'", value, r, resource)
}
rc.resource2Value.Store(resource, value)
rc.value2Resource.Store(value, resource)
}
}
func (rc *sConverter) registerAction(actions ...notify.SAction) {
for _, action := range actions {
if _, ok := rc.actionValueMap[action]; ok {
return
func (rc *sConverter) registerAction(actionValues map[notify.SAction]int) {
for action, value := range actionValues {
if v, ok := rc.action2Value.Load(action); ok && v.(int) != value {
log.Fatalf("action '%s' has been mapped to value '%d', and it is not allowed to map to another value '%d'", action, v, value)
}
rc.actionList = append(rc.actionList, action)
rc.actionValueMap[action] = len(rc.actionList) - 1
if a, ok := rc.value2Action.Load(value); ok && a.(notify.SAction) != action {
log.Fatalf("value '%d' has been mapped to action '%s', and it is not allowed to map to another action '%s'", value, a, action)
}
rc.action2Value.Store(action, value)
rc.value2Action.Store(value, action)
}
}
func (rc *sConverter) resourceValue(resource string) int {
v, ok := rc.resourceValueMap[resource]
v, ok := rc.resource2Value.Load(resource)
if !ok {
return -1
}
return v
return v.(int)
}
func (rc *sConverter) resource(resourceValue int) string {
if resourceValue < 0 || resourceValue >= len(rc.resourceList) {
r, ok := rc.value2Resource.Load(resourceValue)
if !ok {
return ""
}
return rc.resourceList[resourceValue]
return r.(string)
}
func (rc *sConverter) actionValue(action notify.SAction) int {
v, ok := rc.actionValueMap[action]
v, ok := rc.action2Value.Load(action)
if !ok {
return -1
}
return v
return v.(int)
}
func (rc *sConverter) action(actionValue int) notify.SAction {
if actionValue < 0 || actionValue >= len(rc.actionList) {
a, ok := rc.value2Action.Load(actionValue)
if !ok {
return notify.SAction("")
}
return rc.actionList[actionValue]
return a.(notify.SAction)
}
+12 -12
View File
@@ -42,15 +42,15 @@ func (c *SendNotificationClient) Send(ctx context.Context, in *SendParams, opts
}
func (c *SendNotificationClient) AddConfig(ctx context.Context, in *AddConfigInput, opts ...grpc.CallOption) (*Empty, error) {
ctx, cancel := context.WithTimeout(ctx, c.CallTimeout)
defer cancel()
return c.sendAgentClient.AddConfig(ctx, in, opts...)
ctx, cancel := context.WithTimeout(ctx, c.CallTimeout)
defer cancel()
return c.sendAgentClient.AddConfig(ctx, in, opts...)
}
func (c *SendNotificationClient) DeleteConfig(ctx context.Context, in *DeleteConfigInput, opts ...grpc.CallOption) (*Empty, error) {
ctx, cancel := context.WithTimeout(ctx, c.CallTimeout)
defer cancel()
return c.sendAgentClient.DeleteConfig(ctx, in, opts...)
ctx, cancel := context.WithTimeout(ctx, c.CallTimeout)
defer cancel()
return c.sendAgentClient.DeleteConfig(ctx, in, opts...)
}
func (c *SendNotificationClient) UpdateConfig(ctx context.Context, in *UpdateConfigInput, opts ...grpc.CallOption) (*Empty, error) {
@@ -60,9 +60,9 @@ func (c *SendNotificationClient) UpdateConfig(ctx context.Context, in *UpdateCon
}
func (c *SendNotificationClient) CompleteConfig(ctx context.Context, in *CompleteConfigInput, opts ...grpc.CallOption) (*Empty, error) {
ctx, cancel := context.WithTimeout(ctx, c.CallTimeout)
defer cancel()
return c.sendAgentClient.CompleteConfig(ctx, in, opts...)
ctx, cancel := context.WithTimeout(ctx, c.CallTimeout)
defer cancel()
return c.sendAgentClient.CompleteConfig(ctx, in, opts...)
}
func (c *SendNotificationClient) ValidateConfig(ctx context.Context, in *ValidateConfigInput, opts ...grpc.CallOption) (*ValidateConfigReply, error) {
@@ -78,9 +78,9 @@ func (c *SendNotificationClient) UseridByMobile(ctx context.Context, in *UseridB
}
func (c *SendNotificationClient) Ready(ctx context.Context, in *ReadyInput, opts ...grpc.CallOption) (*ReadyOutput, error) {
ctx, cancel := context.WithTimeout(ctx, c.CallTimeout)
defer cancel()
return c.sendAgentClient.Ready(ctx, in, opts...)
ctx, cancel := context.WithTimeout(ctx, c.CallTimeout)
defer cancel()
return c.sendAgentClient.Ready(ctx, in, opts...)
}
func (c *SendNotificationClient) BatchSend(ctx context.Context, in *BatchSendParams, opts ...grpc.CallOption) (*BatchSendReply, error) {
+2 -1
View File
@@ -6,11 +6,12 @@ package apis
import (
context "context"
fmt "fmt"
math "math"
proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
+1 -1
View File
@@ -257,7 +257,7 @@ func (self *SRpcService) ContactByMobile(ctx context.Context, mobile, serviceNam
if s.Code() == codes.NotFound {
return "", errors.Wrap(notifyv2.ErrNoSuchMobile, s.Message())
}
if s.Code() == codes.PermissionDenied {
if s.Code() == codes.FailedPrecondition {
return "", errors.Wrap(notifyv2.ErrIncompleteConfig, s.Message())
}
return "", err
+1
View File
@@ -39,6 +39,7 @@ func InitHandlers(app *appsrv.Application) {
models.SubContactManager,
db.SharedResourceManager,
models.VerificationManager,
models.EventManager,
} {
db.RegisterModelManager(manager)
}
+6 -2
View File
@@ -145,7 +145,11 @@ func (self *NotificationSendTask) OnInit(ctx context.Context, obj db.IStandalone
}
// send
p, err := notification.TemplateStore().FillWithTemplate(ctx, lang, notification.Notification())
nn, err := notification.Notification()
if err != nil {
self.taskFailed(ctx, notification, err.Error(), false)
}
p, err := notification.TemplateStore().FillWithTemplate(ctx, lang, nn)
if err != nil {
self.taskFailed(ctx, notification, err.Error(), false)
}
@@ -199,7 +203,7 @@ type FailedReceiverSpec struct {
func (self *NotificationSendTask) batchSend(ctx context.Context, contactType string, receivers []ReceiverSpec, params rpcapi.SendParams) (fails []FailedReceiverSpec, err error) {
log.Infof("contactType: %s, receivers: %s, params: %s", contactType, receivers, jsonutils.Marshal(params))
if contactType != apis.ROBOT {
if contactType != apis.ROBOT && contactType != apis.WEBHOOK {
return self._batchSend(ctx, contactType, receivers, func(res []*rpcapi.SReceiver) ([]*rpcapi.FailedRecord, error) {
return models.NotifyService.BatchSend(ctx, contactType, rpcapi.BatchSendParams{
Receivers: res,
+8 -8
View File
@@ -24,11 +24,11 @@ import (
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis/notify"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/notify/models"
"yunion.io/x/onecloud/pkg/apis/notify"
"yunion.io/x/onecloud/pkg/util/logclient"
)
@@ -62,13 +62,13 @@ func (self *RepullSuncontactTask) OnInit(ctx context.Context, obj db.IStandalone
}
subq := models.SubContactManager.Query("receiver_id").Equals("type", config.Type).SubQuery()
q := models.ReceiverManager.Query()
if config.Attribution == notify.CONFIG_ATTRIBUTION_DOMAIN {
q = q.Equals("domain_id", config.DomainId)
} else {
// The system-level config update should not affect the receiver under the domain with config
configq := models.ConfigManager.Query("domain_id").Equals("attribution", notify.CONFIG_ATTRIBUTION_DOMAIN).SubQuery()
q = q.Join(configq, sqlchemy.NotEquals(q.Field("domain_id"), configq.Field("domain_id")))
}
if config.Attribution == notify.CONFIG_ATTRIBUTION_DOMAIN {
q = q.Equals("domain_id", config.DomainId)
} else {
// The system-level config update should not affect the receiver under the domain with config
configq := models.ConfigManager.Query("domain_id").Equals("attribution", notify.CONFIG_ATTRIBUTION_DOMAIN).SubQuery()
q = q.Join(configq, sqlchemy.NotEquals(q.Field("domain_id"), configq.Field("domain_id")))
}
q.Join(subq, sqlchemy.Equals(q.Field("id"), subq.Field("receiver_id")))
rs := make([]models.SReceiver, 0)
err := db.FetchModelObjects(models.ReceiverManager, q, &rs)
+4 -4
View File
@@ -82,10 +82,10 @@ func (self *VerificationSendTask) OnInit(ctx context.Context, obj db.IStandalone
self.taskFailed(ctx, receiver, err.Error())
return
}
param.Receiver = &apis.SReceiver{
Contact: contact,
DomainId: receiver.DomainId,
}
param.Receiver = &apis.SReceiver{
Contact: contact,
DomainId: receiver.DomainId,
}
err = models.NotifyService.Send(ctx, contactType, param)
if err != nil {
self.taskFailed(ctx, receiver, err.Error())