diff --git a/cmd/climc/shell/misc/tasks.go b/cmd/climc/shell/misc/tasks.go index 84f8754f7a2..8631c1faf86 100644 --- a/cmd/climc/shell/misc/tasks.go +++ b/cmd/climc/shell/misc/tasks.go @@ -15,41 +15,80 @@ package misc import ( + "fmt" + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/apis" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/modulebase" "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + "yunion.io/x/onecloud/pkg/mcclient/modules/devtool" + "yunion.io/x/onecloud/pkg/mcclient/modules/identity" + "yunion.io/x/onecloud/pkg/mcclient/modules/image" + "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" + "yunion.io/x/onecloud/pkg/mcclient/modules/notify" ) func init() { - type RegionTaskListOptions struct { - ObjName string `help:"object name"` - ObjId string `help:"object id"` - TaskName string `help:"task name"` + cmds := []struct { + service string + manager modulebase.Manager + }{ + { + service: "region", + manager: &compute.ComputeTasks, + }, + { + service: "devtool", + manager: &devtool.DevtoolTasks, + }, + { + service: "image", + manager: &image.Tasks, + }, + { + service: "identity", + manager: &identity.Tasks, + }, + { + service: "k8s", + manager: k8s.KubeTasks, + }, + { + service: "notify", + manager: ¬ify.Tasks, + }, } - R(&RegionTaskListOptions{}, "region-task-list", "List tasks on region server", func(s *mcclient.ClientSession, args *RegionTaskListOptions) error { - params := jsonutils.Marshal(args) - result, err := compute.ComputeTasks.List(s, params) - if err != nil { - return err + for i := range cmds { + c := cmds[i] + type TaskListOptions struct { + apis.TaskListInput } - printList(result, compute.ComputeTasks.GetColumns(s)) - return nil - }) + R(&TaskListOptions{}, fmt.Sprintf("%s-task-list", c.service), "List tasks on region server", func(s *mcclient.ClientSession, args *TaskListOptions) error { + params := jsonutils.Marshal(args) + result, err := c.manager.List(s, params) + if err != nil { + return err + } + printList(result, c.manager.GetColumns(s)) + return nil + }) - type RegionTaskShowOptions struct { - ID string `help:"ID or name of the task"` - } - R(&RegionTaskShowOptions{}, "region-task-show", "Show details of a region task", func(s *mcclient.ClientSession, args *RegionTaskShowOptions) error { - result, err := compute.ComputeTasks.Get(s, args.ID, nil) - if err != nil { - return err + type TaskShowOptions struct { + ID string `help:"ID or name of the task"` } - printObject(result) - return nil - }) + R(&TaskShowOptions{}, "region-task-show", "Show details of a region task", func(s *mcclient.ClientSession, args *TaskShowOptions) error { + result, err := c.manager.GetById(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + } - type TaskListOptions struct { + /*type TaskListOptions struct { ObjName string `help:"object name"` ObjId string `help:"object id"` TaskName string `help:"task name"` @@ -80,6 +119,6 @@ func init() { } printObject(result) return nil - }) + })*/ } diff --git a/pkg/ansibleserver/models/ansibleplaybook_instance.go b/pkg/ansibleserver/models/ansibleplaybook_instance.go index 5c9521ac27c..abab8ecb508 100644 --- a/pkg/ansibleserver/models/ansibleplaybook_instance.go +++ b/pkg/ansibleserver/models/ansibleplaybook_instance.go @@ -31,8 +31,8 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/workmanager" "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/mcclient/modules/compute" + "yunion.io/x/onecloud/pkg/mcclient/modules/devtool" "yunion.io/x/onecloud/pkg/util/ansible" "yunion.io/x/onecloud/pkg/util/ansiblev2" ) @@ -216,7 +216,7 @@ var PlaybookWorker *workmanager.SWorkManager func taskFailed(ctx context.Context, reason string) { if taskId := ctx.Value(appctx.APP_CONTEXT_KEY_TASK_ID); taskId != nil { session := auth.GetAdminSessionWithInternal(ctx, "") - modules.TaskFailed(&compute.DevtoolTasks, session, taskId.(string), reason) + devtool.DevtoolTasks.TaskFailed2(session, taskId.(string), reason) } else { log.Warningf("Reqeuest task failed missing task id, with reason: %s", reason) } @@ -225,7 +225,7 @@ func taskFailed(ctx context.Context, reason string) { func taskCompleted(ctx context.Context, data jsonutils.JSONObject) { if taskId := ctx.Value(appctx.APP_CONTEXT_KEY_TASK_ID); taskId != nil { session := auth.GetAdminSessionWithInternal(ctx, "") - modules.TaskComplete(&compute.DevtoolTasks, session, taskId.(string), data) + devtool.DevtoolTasks.TaskComplete(session, taskId.(string), data) } else { log.Warningf("Reqeuest task failed missing task id, with data: %v", data) } diff --git a/pkg/apis/tasks.go b/pkg/apis/tasks.go new file mode 100644 index 00000000000..62265367e0c --- /dev/null +++ b/pkg/apis/tasks.go @@ -0,0 +1,64 @@ +// 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 apis + +import ( + "time" + + "yunion.io/x/jsonutils" +) + +type TaskListInput struct { + ModelBaseListInput + ProjectizedResourceListInput + + Id []string `json:"id" help:"id filter"` + ObjId []string `json:"obj_id" help:"object id filter"` + ObjName []string `json:"obj_name" help:"object type (in singular form) filter"` + TaskName []string `json:"task_name" help:"task name filter"` + IsMulti *bool `json:"is_multi" negative:"is_single" help:"is multi task"` + IsComplete *bool `json:"is_complete" negative:"not_complete" help:"is task completed, either fail or complete"` + IsInit *bool `json:"is_init" negative:"not_init" help:"is task started?"` + Stage []string `json:"stage" help:"task stage"` + ParentId []string `json:"parent_id" help:"filter tasks by parent_task_id"` + IsRoot *bool `json:"is_root" help:"filter root tasks"` +} + +type TaskDetails struct { + ModelBaseDetails + ProjectizedResourceInfo + + // 资源创建时间 + CreatedAt time.Time `json:"created_at"` + // 资源更新时间 + UpdatedAt time.Time `json:"updated_at"` + // 资源被更新次数 + UpdateVersion int `json:"update_version"` + // 开始任务时间 + StartAt time.Time `json:"start_at"` + // 完成任务时间 + EndAt time.Time `json:"end_at"` + + DomainId string `json:"domain_id"` + ProjectId string `json:"tenant_id"` + + Id string + ObjName string + ObjId string + TaskName string + Params *jsonutils.JSONDict + Stage string + ParentTaskId string +} diff --git a/pkg/cloudcommon/db/project.go b/pkg/cloudcommon/db/project.go index 06fa803a214..f57b672edd5 100644 --- a/pkg/cloudcommon/db/project.go +++ b/pkg/cloudcommon/db/project.go @@ -297,7 +297,8 @@ func ValidateProjectizedResourceInput(ctx context.Context, input apis.Projectize } func (manager *SProjectizedResourceBaseManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, keys stringutils2.SSortedStrings) (*sqlchemy.SQuery, error) { - q, err := manager.SDomainizedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys) + var err error + q, err = manager.SDomainizedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys) if err != nil { return nil, errors.Wrap(err, "SDomainizedResourceBaseManager.ListItemExportKeys") } diff --git a/pkg/cloudcommon/db/taskman/taskobjs.go b/pkg/cloudcommon/db/taskman/taskobjs.go index a530c395826..9f9e3207069 100644 --- a/pkg/cloudcommon/db/taskman/taskobjs.go +++ b/pkg/cloudcommon/db/taskman/taskobjs.go @@ -15,15 +15,24 @@ package taskman import ( + "context" "database/sql" + "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/rbacscope" + "yunion.io/x/sqlchemy" "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type STaskObjectManager struct { db.SModelBaseManager + db.SProjectizedResourceBaseManager } var TaskObjectManager *STaskObjectManager @@ -34,6 +43,7 @@ func init() { type STaskObject struct { db.SModelBase + db.SProjectizedResourceBase TaskId string `width:"36" charset:"ascii" nullable:"false" primary:"true" index:"true"` // Column(VARCHAR(36, charset='ascii'), nullable=False, primary_key=True, index=True) ObjId string `width:"36" charset:"ascii" nullable:"false" primary:"true"` // Column(VARCHAR(36, charset='ascii'), nullable=False, primary_key=True) @@ -62,3 +72,45 @@ func (manager *STaskObjectManager) GetObjectIds(task *STask) []string { } return ret } + +func (manager *STaskObjectManager) FetchOwnerId(ctx context.Context, data jsonutils.JSONObject) (mcclient.IIdentityProvider, error) { + return manager.SProjectizedResourceBaseManager.FetchOwnerId(ctx, data) +} + +func (manager *STaskObjectManager) FilterByOwner(ctx context.Context, q *sqlchemy.SQuery, man db.FilterByOwnerProvider, userCred mcclient.TokenCredential, owner mcclient.IIdentityProvider, scope rbacscope.TRbacScope) *sqlchemy.SQuery { + return manager.SProjectizedResourceBaseManager.FilterByOwner(ctx, q, man, userCred, owner, scope) +} + +func (manager *STaskObjectManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, keys stringutils2.SSortedStrings) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SModelBaseManager.ListItemExportKeys(ctx, q, userCred, keys) + if err != nil { + return nil, errors.Wrap(err, "SModelBaseManager.ListItemExportKeys") + } + q, err = manager.SProjectizedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys) + if err != nil { + return nil, errors.Wrap(err, "SProjectizedResourceBaseManager.ListItemExportKeys") + } + return q, nil +} + +func (manager *STaskObjectManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SModelBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SProjectizedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *STaskObjectManager) ResourceScope() rbacscope.TRbacScope { + return manager.SProjectizedResourceBaseManager.ResourceScope() +} + +func (taskObj *STaskObject) GetOwnerId() mcclient.IIdentityProvider { + return taskObj.SProjectizedResourceBase.GetOwnerId() +} diff --git a/pkg/cloudcommon/db/taskman/tasks.go b/pkg/cloudcommon/db/taskman/tasks.go index 13ecbd7b8fa..fe7ac21d4fa 100644 --- a/pkg/cloudcommon/db/taskman/tasks.go +++ b/pkg/cloudcommon/db/taskman/tasks.go @@ -49,6 +49,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/mcclient/modules/yunionconf" "yunion.io/x/onecloud/pkg/util/logclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) const ( @@ -72,31 +73,50 @@ const ( ) type STaskManager struct { - db.SResourceBaseManager + db.SModelBaseManager + db.SProjectizedResourceBaseManager } var TaskManager *STaskManager func init() { TaskManager = &STaskManager{ - SResourceBaseManager: db.NewResourceBaseManager(STask{}, "tasks_tbl", "task", "tasks")} + SModelBaseManager: db.NewModelBaseManager(STask{}, "tasks_tbl", "task", "tasks"), + } TaskManager.SetVirtualObject(TaskManager) } type STask struct { - db.SResourceBase + db.SModelBase + db.SProjectizedResourceBase + + // 资源创建时间 + CreatedAt time.Time `nullable:"false" created_at:"true" index:"true" get:"user" list:"user" json:"created_at"` + // 资源更新时间 + UpdatedAt time.Time `nullable:"false" updated_at:"true" list:"user" json:"updated_at"` + // 资源被更新次数 + UpdateVersion int `default:"0" nullable:"false" auto_version:"true" list:"user" json:"update_version"` + + // 开始任务时间 + StartAt time.Time `nullable:"true" list:"user" json:"start_at"` + // 完成任务时间 + EndAt time.Time `nullable:"true" list:"user" json:"end_at"` Id string `width:"36" charset:"ascii" primary:"true" list:"user"` // Column(VARCHAR(36, charset='ascii'), primary_key=True, default=get_uuid) - ObjName string `width:"128" charset:"utf8" nullable:"false" list:"user"` // Column(VARCHAR(128, charset='utf8'), nullable=False) - ObjId string `width:"128" charset:"ascii" nullable:"false" list:"user" index:"true"` // Column(VARCHAR(ID_LENGTH, charset='ascii'), nullable=False) - TaskName string `width:"64" charset:"ascii" nullable:"false" list:"user"` // Column(VARCHAR(64, charset='ascii'), nullable=False) - UserCred mcclient.TokenCredential `width:"1024" charset:"utf8" nullable:"false" get:"user"` // Column(VARCHAR(1024, charset='ascii'), nullable=False) + ObjName string `width:"128" charset:"utf8" nullable:"false" list:"user"` // Column(VARCHAR(128, charset='utf8'), nullable=False) + ObjId string `width:"128" charset:"ascii" nullable:"false" list:"user" index:"true"` // Column(VARCHAR(ID_LENGTH, charset='ascii'), nullable=False) + TaskName string `width:"64" charset:"ascii" nullable:"false" list:"user"` // Column(VARCHAR(64, charset='ascii'), nullable=False) + + UserCred mcclient.TokenCredential `width:"1024" charset:"utf8" nullable:"false" get:"user"` // Column(VARCHAR(1024, charset='ascii'), nullable=False) // OwnerCred string `width:"512" charset:"ascii" nullable:"true"` // Column(VARCHAR(512, charset='ascii'), nullable=True) Params *jsonutils.JSONDict `charset:"utf8" length:"medium" nullable:"false" get:"user"` // Column(MEDIUMTEXT(charset='ascii'), nullable=False) Stage string `width:"64" charset:"ascii" nullable:"false" default:"on_init" list:"user"` // Column(VARCHAR(64, charset='ascii'), nullable=False, default='on_init') + // 父任务时间 + ParentTaskId string `width:"36" charset:"ascii" primary:"true" list:"user" index:"true" json:"parent_task_id"` + taskObject db.IStandaloneModel `ignore:"true"` taskObjects []db.IStandaloneModel `ignore:"true"` } @@ -131,7 +151,6 @@ func (manager *STaskManager) PerformAction(ctx context.Context, userCred mcclien return nil, errors.Wrapf(err, "runTask") } resp := jsonutils.NewDict() - // 'result': 'ok' resp.Add(jsonutils.NewString("ok"), "result") return resp, nil } @@ -143,38 +162,36 @@ func (manager *STask) PreCheckPerformAction( return nil } -func (self *STask) GetOwnerId() mcclient.IIdentityProvider { - owner := db.SOwnerId{DomainId: self.UserCred.GetProjectDomainId(), Domain: self.UserCred.GetProjectDomain(), - ProjectId: self.UserCred.GetProjectId(), Project: self.UserCred.GetProjectName()} - return &owner +func (task *STask) GetOwnerId() mcclient.IIdentityProvider { + return task.SProjectizedResourceBase.GetOwnerId() } func (manager *STaskManager) FilterByOwner(ctx context.Context, q *sqlchemy.SQuery, man db.FilterByOwnerProvider, userCred mcclient.TokenCredential, owner mcclient.IIdentityProvider, scope rbacscope.TRbacScope) *sqlchemy.SQuery { - if owner != nil { - switch scope { - case rbacscope.ScopeProject: - if len(owner.GetProjectId()) > 0 { - q = q.Contains("user_cred", owner.GetProjectId()) - } - case rbacscope.ScopeDomain: - if len(owner.GetProjectDomainId()) > 0 { - q = q.Contains("user_cred", owner.GetProjectDomainId()) - } - } + objectQAltered := false + objectQ := TaskObjectManager.Query().Snapshot() + objectQ = TaskObjectManager.SProjectizedResourceBaseManager.FilterByOwner(ctx, objectQ, man, userCred, owner, scope) + objectQAltered = objectQ.IsAltered() + objectQ = objectQ.AppendField(sqlchemy.DISTINCT("task_id", objectQ.Field("task_id"))) + + singleTaskQAltered := false + singleTaskQ := TaskManager.Query().NotEquals("obj_id", MULTI_OBJECTS_ID).Snapshot() + singleTaskQ = TaskManager.SProjectizedResourceBaseManager.FilterByOwner(ctx, singleTaskQ, man, userCred, owner, scope) + singleTaskQAltered = singleTaskQ.IsAltered() + singleTaskQ = singleTaskQ.AppendField(sqlchemy.DISTINCT("task_id", singleTaskQ.Field("id"))) + + if objectQAltered || singleTaskQAltered { + subQ := sqlchemy.Union(objectQ, singleTaskQ).Query().SubQuery() + q = q.Join(subQ, sqlchemy.Equals(q.Field("id"), subQ.Field("task_id"))) } return q } -func (manager *STaskManager) FetchTaskById(taskId string) *STask { - return manager.fetchTask(taskId) -} - -func (self *STask) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return false +func (manager *STaskManager) FetchOwnerId(ctx context.Context, data jsonutils.JSONObject) (mcclient.IIdentityProvider, error) { + return manager.SProjectizedResourceBaseManager.FetchOwnerId(ctx, data) } -func (self *STask) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return false +func (manager *STaskManager) FetchTaskById(taskId string) *STask { + return manager.fetchTask(taskId) } func (self *STask) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error { @@ -199,6 +216,19 @@ func (self *STask) GetName() string { return self.TaskName } +func (task *STask) saveStartAt() { + if !task.StartAt.IsZero() { + return + } + _, err := db.Update(task, func() error { + task.StartAt = timeutils.UtcNow() + return nil + }) + if err != nil { + log.Errorf("task %s save start_at fail: %s", task.String(), err) + } +} + func fetchTaskParams( ctx context.Context, taskName string, @@ -271,13 +301,21 @@ func (manager *STaskManager) NewTask( data := fetchTaskParams(ctx, taskName, taskData, parentTaskId, parentTaskNotifyUrl, pendingUsage) task := &STask{ - ObjName: obj.Keyword(), - ObjId: obj.GetId(), - TaskName: taskName, - UserCred: userCred, - Params: data, - Stage: TASK_INIT_STAGE, + ObjName: obj.Keyword(), + ObjId: obj.GetId(), + TaskName: taskName, + UserCred: userCred, + Params: data, + Stage: TASK_INIT_STAGE, + ParentTaskId: parentTaskId, + } + + ownerId := obj.GetOwnerId() + if ownerId != nil { + task.DomainId = ownerId.GetProjectDomainId() + task.ProjectId = ownerId.GetProjectId() } + task.SetModelManager(manager, task) err := manager.TableSpec().Insert(ctx, task) if err != nil { @@ -319,12 +357,13 @@ func (manager *STaskManager) NewParallelTask( data := fetchTaskParams(ctx, taskName, taskData, parentTaskId, parentTaskNotifyUrl, pendingUsage) task := &STask{ - ObjName: objs[0].Keyword(), - ObjId: MULTI_OBJECTS_ID, - TaskName: taskName, - UserCred: userCred, - Params: data, - Stage: TASK_INIT_STAGE, + ObjName: objs[0].Keyword(), + ObjId: MULTI_OBJECTS_ID, + TaskName: taskName, + UserCred: userCred, + Params: data, + Stage: TASK_INIT_STAGE, + ParentTaskId: parentTaskId, } task.SetModelManager(manager, task) err := manager.TableSpec().Insert(ctx, task) @@ -333,8 +372,19 @@ func (manager *STaskManager) NewParallelTask( return nil, err } - for _, obj := range objs { - to := STaskObject{TaskId: task.Id, ObjId: obj.GetId()} + for i := range objs { + obj := objs[i] + to := STaskObject{ + TaskId: task.Id, + ObjId: obj.GetId(), + } + ownerId := obj.GetOwnerId() + if ownerId != nil { + to.DomainId = ownerId.GetProjectDomainId() + to.ProjectId = ownerId.GetProjectId() + } + to.SetModelManager(TaskObjectManager, &to) + to.SetModelManager(TaskObjectManager, &to) err := TaskObjectManager.TableSpec().Insert(ctx, &to) if err != nil { @@ -412,6 +462,8 @@ func execITask(taskValue reflect.Value, task *STask, odata jsonutils.JSONObject, ctxData := task.GetRequestContext() ctx := ctxData.GetContext() + task.saveStartAt() + taskFailed := false var data jsonutils.JSONObject @@ -589,8 +641,19 @@ func (self *STask) IsSubtask() bool { return self.HasParentTask() } -func (self *STask) HasParentTask() bool { +func (self *STask) GetParentTaskId() string { + if len(self.ParentTaskId) > 0 { + return self.ParentTaskId + } parentTaskId, _ := self.Params.GetString(PARENT_TASK_ID_KEY) + if len(parentTaskId) > 0 { + return parentTaskId + } + return "" +} + +func (self *STask) HasParentTask() bool { + parentTaskId := self.GetParentTaskId() if len(parentTaskId) > 0 { return true } @@ -598,7 +661,7 @@ func (self *STask) HasParentTask() bool { } func (self *STask) GetParentTask() *STask { - parentTaskId, _ := self.Params.GetString(PARENT_TASK_ID_KEY) + parentTaskId := self.GetParentTaskId() if len(parentTaskId) > 0 { return TaskManager.fetchTask(parentTaskId) } @@ -623,6 +686,7 @@ func (self *STask) SaveRequestContext(data *appctx.AppContextData) { params := self.Params.CopyExcludes(REQUEST_CONTEXT_KEY) params.Add(jsonData, REQUEST_CONTEXT_KEY) self.Params = params + self.EndAt = timeutils.UtcNow() return nil }) log.Debugf("Params: %s", self.Params) @@ -715,7 +779,7 @@ func (self *STask) SetStageFailed(ctx context.Context, reason jsonutils.JSONObje func (self *STask) NotifyParentTaskComplete(ctx context.Context, body *jsonutils.JSONDict, failed bool) { log.Infof("notify_parent_task_complete: %s params %s", self.TaskName, self.Params) - parentTaskId, _ := self.Params.GetString(PARENT_TASK_ID_KEY) + parentTaskId := self.GetParentTaskId() parentTaskNotify, _ := self.Params.GetString(PARENT_TASK_NOTIFY_KEY) if len(parentTaskId) > 0 { subTask := SubTaskManager.GetSubTask(parentTaskId, self.Id) @@ -771,6 +835,7 @@ func (self *STask) NotifyParentTaskFailure(ctx context.Context, reason jsonutils func (self *STask) IsCurrentStageComplete() bool { totalSubtasks := SubTaskManager.GetTotalSubtasks(self.Id, self.Stage, "") initSubtasks := SubTaskManager.GetInitSubtasks(self.Id, self.Stage) + log.Debugf("Task %s IsCurrentStageComplete totalSubtasks %d initSubtasks %d ", self.String(), len(totalSubtasks), len(initSubtasks)) if len(totalSubtasks) > 0 && len(initSubtasks) == 0 { return true } else { @@ -862,6 +927,10 @@ func (task *STask) GetTaskRequestHeader() http.Header { return header } +func (task *STask) String() string { + return fmt.Sprintf("%s(%s,%s)", task.Id, task.TaskName, task.Stage) +} + var serviceUrl string func SetServiceUrl(url string) { @@ -947,3 +1016,151 @@ func (manager *STaskManager) FetchTasksOfObject(obj db.IStandaloneModel, since t } return tasks, nil } + +// 操作日志列表 +func (manager *STaskManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input apis.TaskListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SModelBaseManager.ListItemFilter(ctx, q, userCred, input.ModelBaseListInput) + if err != nil { + return q, errors.Wrap(err, "SResourceBaseManager.ListItemFilter") + } + + if len(input.Id) > 0 { + q = q.In("id", input.Id) + } + + if len(input.ObjId) > 0 { + taskObjsQ := TaskObjectManager.Query().In("obj_id", input.ObjId) + taskObjsQ = taskObjsQ.AppendField(sqlchemy.DISTINCT("task_id", taskObjsQ.Field("task_id"))) + tasksQ := TaskManager.Query().In("obj_id", input.ObjId) + tasksQ = tasksQ.AppendField(tasksQ.Field("id").Label("task_id")) + taskIdQ := sqlchemy.Union(taskObjsQ, tasksQ).Query().SubQuery() + q = q.Join(taskIdQ, sqlchemy.Equals(taskIdQ.Field("task_id"), q.Field("id"))) + } + + if len(input.ObjName) > 0 { + q = q.In("obj_name", input.ObjName) + } + + if len(input.TaskName) > 0 { + q = q.In("task_name", input.TaskName) + } + + if len(input.Stage) > 0 { + q = q.In("stage", input.Stage) + } + + if len(input.ParentId) > 0 { + q = q.In("parent_task_id", input.ParentId) + } + + if input.IsComplete != nil { + if *input.IsComplete { + q = q.In("stage", []string{TASK_STAGE_FAILED, TASK_STAGE_COMPLETE}) + } else { + q = q.NotIn("stage", []string{TASK_STAGE_FAILED, TASK_STAGE_COMPLETE}) + } + } + + if input.IsInit != nil { + if *input.IsInit { + q = q.Equals("stage", TASK_INIT_STAGE) + } else { + q = q.NotEquals("stage", TASK_INIT_STAGE) + } + } + + if input.IsMulti != nil { + if *input.IsMulti { + q = q.Equals("obj_id", MULTI_OBJECTS_ID) + } else { + q = q.NotEquals("obj_id", MULTI_OBJECTS_ID) + } + } + + if input.IsRoot != nil { + if *input.IsRoot { + q = q.IsNullOrEmpty("parent_task_id") + } else { + q = q.IsNotEmpty("parent_task_id") + } + } + + q.DebugQuery2("taskQuery") + + return q, nil +} + +func (manager *STaskManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, keys stringutils2.SSortedStrings) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SModelBaseManager.ListItemExportKeys(ctx, q, userCred, keys) + if err != nil { + return nil, errors.Wrap(err, "SModelBaseManager.ListItemExportKeys") + } + // q, err = manager.SProjectizedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys) + // if err != nil { + // return nil, errors.Wrap(err, "SProjectizedResourceBaseManager.ListItemExportKeys") + // } + return q, nil +} + +func (manager *STaskManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SModelBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + // q, err = manager.SProjectizedResourceBaseManager.QueryDistinctExtraField(q, field) + // if err == nil { + // return q, nil + // } + return q, httperrors.ErrNotFound +} + +func (manager *STaskManager) ResourceScope() rbacscope.TRbacScope { + return manager.SProjectizedResourceBaseManager.ResourceScope() +} + +func (manager *STaskManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []apis.TaskDetails { + rows := make([]apis.TaskDetails, len(objs)) + bases := manager.SModelBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + projs := manager.SProjectizedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range objs { + rows[i] = apis.TaskDetails{ + ModelBaseDetails: bases[i], + ProjectizedResourceInfo: projs[i], + } + } + return rows +} + +func (manager *STaskManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.TaskListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SModelBaseManager.OrderByExtraFields(ctx, q, userCred, query.ModelBaseListInput) + if err != nil { + return q, errors.Wrap(err, "SModelBaseManager.OrderByExtraField") + } + // q, err = manager.SProjectizedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ProjectizedResourceListInput) + // if err != nil { + // return q, errors.Wrap(err, "SProjectizedResourceBaseManager.OrderByExtraField") + // } + return q, nil +} diff --git a/pkg/hostman/hostutils/hostutils.go b/pkg/hostman/hostutils/hostutils.go index 8f1c7879b10..7329cdc3146 100644 --- a/pkg/hostman/hostutils/hostutils.go +++ b/pkg/hostman/hostutils/hostutils.go @@ -119,7 +119,7 @@ func TaskComplete(ctx context.Context, params jsonutils.JSONObject) { func K8sTaskFailed(ctx context.Context, reason string) { if taskId := ctx.Value(appctx.APP_CONTEXT_KEY_TASK_ID); taskId != nil { - k8s.KubeTasks.TaskFailed(GetK8sSession(ctx), taskId.(string), reason) + k8s.KubeTasks.TaskFailed2(GetK8sSession(ctx), taskId.(string), reason) } else { log.Errorf("Reqeuest k8s task failed missing task id, with reason(%s)", reason) } diff --git a/pkg/mcclient/modules/compute/mod_tasks.go b/pkg/mcclient/modules/compute/mod_tasks.go index 46bc1c73773..8c110b48ae5 100644 --- a/pkg/mcclient/modules/compute/mod_tasks.go +++ b/pkg/mcclient/modules/compute/mod_tasks.go @@ -15,93 +15,17 @@ package compute import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/util/printutils" - - "yunion.io/x/onecloud/pkg/apis" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/mcclient/modulebase" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/modules/tasks" ) -var ( - ComputeTasks TasksManager - DevtoolTasks TasksManager -) - -type TasksManager struct { - modulebase.ResourceManager -} +var ComputeTasks tasks.TasksManager func init() { - ComputeTasks = TasksManager{ + ComputeTasks = tasks.TasksManager{ ResourceManager: modules.NewComputeManager("task", "tasks", []string{}, []string{"Id", "Obj_name", "Obj_Id", "Task_name", "Stage", "Created_at"}), } modules.RegisterCompute(&ComputeTasks) - - DevtoolTasks = TasksManager{ - ResourceManager: modules.NewDevtoolManager("task", "tasks", - []string{}, - []string{"Id", "Obj_name", "Obj_Id", "Task_name", "Stage", "Created_at"}, - ), - } -} - -func (man TasksManager) TaskComplete(session *mcclient.ClientSession, taskId string, params jsonutils.JSONObject) { - modules.TaskComplete(&man, session, taskId, params) -} - -func (man TasksManager) TaskFailed(session *mcclient.ClientSession, taskId string, err error) { - man.TaskFailed2(session, taskId, err.Error()) -} - -func (man TasksManager) TaskFailed2(session *mcclient.ClientSession, taskId string, reason string) { - man.TaskFailed3(session, taskId, reason, nil) -} - -func (man TasksManager) TaskFailed3(session *mcclient.ClientSession, taskId string, reason string, params *jsonutils.JSONDict) { - if params == nil { - params = jsonutils.NewDict() - } - params.Add(jsonutils.NewString("error"), "__status__") - params.Add(jsonutils.NewString(reason), "__reason__") - man.TaskComplete(session, taskId, params) -} - -func (self *TasksManager) getManager(session *mcclient.ClientSession, params jsonutils.JSONObject) (*modulebase.ResourceManager, error) { - serviceType := apis.SERVICE_TYPE_REGION - if params.Contains("service_type") { - serviceType, _ = params.GetString("service_type") - } - - version := "" - switch serviceType { - case apis.SERVICE_TYPE_KEYSTONE: - version = "v3" - case apis.SERVICE_TYPE_REGION, apis.SERVICE_TYPE_NOTIFY: - version = "v2" - case apis.SERVICE_TYPE_IMAGE: - version = "v1" - } - - _, err := session.GetServiceURL(serviceType, "") - if err != nil { - return nil, httperrors.NewNotFoundError("service %s not found error: %v", serviceType, err) - } - - return &modulebase.ResourceManager{ - BaseManager: *modulebase.NewBaseManager(serviceType, "", version, []string{}, []string{}), - Keyword: "task", KeywordPlural: "tasks", - }, nil -} - -func (this *TasksManager) List(session *mcclient.ClientSession, params jsonutils.JSONObject) (*printutils.ListResult, error) { - man, err := this.getManager(session, params) - if err != nil { - return nil, err - } - return man.List(session, params) } diff --git a/pkg/mcclient/modules/devtool/mod_devtools.go b/pkg/mcclient/modules/devtool/mod_devtools.go index 23e2bcda517..140f8635248 100644 --- a/pkg/mcclient/modules/devtool/mod_devtools.go +++ b/pkg/mcclient/modules/devtool/mod_devtools.go @@ -36,7 +36,7 @@ func init() { []string{"id", "ansible_playbook_id", "template_id", "server_id", "name", "day", "hour", "min", "sec", "interval", "start", "enabled", "created_at"}, []string{}, ) - modules.RegisterCompute(&DevToolCronjobs) + modules.Register(&DevToolCronjobs) DevToolTemplates = modules.NewDevtoolManager( "devtool_template", @@ -44,7 +44,7 @@ func init() { []string{"id", "name", "domain_id", "tenant_id", "day", "hour", "min", "sec", "interval", "start", "enabled", "description"}, []string{"is_system"}, ) - modules.RegisterCompute(&DevToolTemplates) + modules.Register(&DevToolTemplates) DevToolScripts = modules.NewDevtoolManager( "script", @@ -52,14 +52,15 @@ func init() { []string{"Id", "Name", "Type", "Playbook_Reference", "Max_Try_Times"}, []string{}, ) - modules.RegisterCompute(&DevToolScripts) + modules.Register(&DevToolScripts) + DevToolScriptApplyRecords = modules.NewDevtoolManager( "scriptapplyrecord", "scriptapplyrecords", []string{"Script_Id", "Server_Id", "Start_Time", "End_Time", "Reason", "Status"}, []string{}, ) - modules.RegisterCompute(&DevToolScriptApplyRecords) + modules.Register(&DevToolScriptApplyRecords) DevToolSshInfos = modules.NewDevtoolManager( "sshinfo", @@ -67,7 +68,7 @@ func init() { []string{"Id", "Server_Id", "Server_Name", "Server_Hypervisor", "Forward_Id", "User", "Host", "Port", "Need_Clean", "Failed_Reason"}, []string{}, ) - modules.RegisterCompute(&DevToolSshInfos) + modules.Register(&DevToolSshInfos) DevToolServiceUrls = modules.NewDevtoolManager( "serviceurl", diff --git a/pkg/mcclient/modules/devtool/mod_tasks.go b/pkg/mcclient/modules/devtool/mod_tasks.go new file mode 100644 index 00000000000..26401a3826e --- /dev/null +++ b/pkg/mcclient/modules/devtool/mod_tasks.go @@ -0,0 +1,31 @@ +// 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 devtool + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/modules/tasks" +) + +var DevtoolTasks tasks.TasksManager + +func init() { + DevtoolTasks = tasks.TasksManager{ + ResourceManager: modules.NewDevtoolManager("task", "tasks", + []string{}, + []string{"Id", "Obj_name", "Obj_Id", "Task_name", "Stage", "Created_at"}, + ), + } +} diff --git a/pkg/mcclient/modules/identity/mod_tasks.go b/pkg/mcclient/modules/identity/mod_tasks.go new file mode 100644 index 00000000000..a602116bc49 --- /dev/null +++ b/pkg/mcclient/modules/identity/mod_tasks.go @@ -0,0 +1,31 @@ +// 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 identity + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/modules/tasks" +) + +var Tasks tasks.TasksManager + +func init() { + Tasks = tasks.TasksManager{ + ResourceManager: modules.NewIdentityV3Manager("task", "tasks", + []string{}, + []string{"Id", "Obj_name", "Obj_Id", "Task_name", "Stage", "Created_at"}, + ), + } +} diff --git a/pkg/mcclient/modules/image/mod_tasks.go b/pkg/mcclient/modules/image/mod_tasks.go new file mode 100644 index 00000000000..a82e999d177 --- /dev/null +++ b/pkg/mcclient/modules/image/mod_tasks.go @@ -0,0 +1,31 @@ +// 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 image + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/modules/tasks" +) + +var Tasks tasks.TasksManager + +func init() { + Tasks = tasks.TasksManager{ + ResourceManager: modules.NewImageManager("task", "tasks", + []string{}, + []string{"Id", "Obj_name", "Obj_Id", "Task_name", "Stage", "Created_at"}, + ), + } +} diff --git a/pkg/mcclient/modules/k8s/tasks.go b/pkg/mcclient/modules/k8s/tasks.go index 52f2fce433c..45c5584d7b0 100644 --- a/pkg/mcclient/modules/k8s/tasks.go +++ b/pkg/mcclient/modules/k8s/tasks.go @@ -15,14 +15,11 @@ package k8s import ( - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/modules/tasks" ) var ( - KubeTasks *KubeTasksManager + KubeTasks *tasks.TasksManager ) type KubeTasksManager struct { @@ -30,15 +27,9 @@ type KubeTasksManager struct { } func init() { - KubeTasks = &KubeTasksManager{ - ResourceManager: *NewResourceManager("task", "tasks", NewColumns(), NewColumns("Id", "Obj_name", "Obj_Id", "Task_name", "Stage", "Created_at")), - } -} + k8sResMan := NewResourceManager("task", "tasks", NewColumns(), NewColumns("Id", "Obj_name", "Obj_Id", "Task_name", "Stage", "Created_at")) -func (m *KubeTasksManager) TaskComplete(session *mcclient.ClientSession, taskId string, params jsonutils.JSONObject) { - modules.TaskComplete(m, session, taskId, params) -} - -func (m *KubeTasksManager) TaskFailed(session *mcclient.ClientSession, taskId string, reason string) { - modules.TaskFailed(m, session, taskId, reason) + KubeTasks = &tasks.TasksManager{ + ResourceManager: k8sResMan.GetBaseManager(), + } } diff --git a/pkg/mcclient/modules/notify/mod_tasks.go b/pkg/mcclient/modules/notify/mod_tasks.go new file mode 100644 index 00000000000..143e2771691 --- /dev/null +++ b/pkg/mcclient/modules/notify/mod_tasks.go @@ -0,0 +1,31 @@ +// 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 notify + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/modules/tasks" +) + +var Tasks tasks.TasksManager + +func init() { + Tasks = tasks.TasksManager{ + ResourceManager: modules.NewNotifyv2Manager("task", "tasks", + []string{}, + []string{"Id", "Obj_name", "Obj_Id", "Task_name", "Stage", "Created_at"}, + ), + } +} diff --git a/pkg/mcclient/modules/quota/mod_quotas.go b/pkg/mcclient/modules/quota/mod_quotas.go index 5a0b9649c6a..4c58dc8cdfd 100644 --- a/pkg/mcclient/modules/quota/mod_quotas.go +++ b/pkg/mcclient/modules/quota/mod_quotas.go @@ -163,32 +163,32 @@ func init() { Quotas = QuotaManager{modules.NewComputeManager("quota", "quotas", quotaColumns, []string{})} - modules.RegisterCompute(&Quotas) + modules.Register(&Quotas) ProjectQuotas = QuotaManager{modules.NewComputeManager("project_quota", "project_quotas", quotaColumns, []string{})} - modules.RegisterCompute(&ProjectQuotas) + modules.Register(&ProjectQuotas) RegionQuotas = QuotaManager{modules.NewComputeManager("region_quota", "region_quotas", quotaColumns, []string{})} - modules.RegisterCompute(&RegionQuotas) + modules.Register(&RegionQuotas) ZoneQuotas = QuotaManager{modules.NewComputeManager("zone_quota", "zone_quotas", quotaColumns, []string{})} - modules.RegisterCompute(&ZoneQuotas) + modules.Register(&ZoneQuotas) DomainQuotas = QuotaManager{modules.NewComputeManager("domain_quota", "domain_quotas", quotaColumns, []string{})} - modules.RegisterCompute(&DomainQuotas) + modules.Register(&DomainQuotas) InfrasQuotas = QuotaManager{modules.NewComputeManager("infras_quota", "infras_quotas", quotaColumns, []string{})} - modules.RegisterCompute(&InfrasQuotas) + modules.Register(&InfrasQuotas) ImageQuotas = QuotaManager{modules.NewImageManager("image_quota", "image_quotas", quotaColumns, diff --git a/pkg/mcclient/modules/task.go b/pkg/mcclient/modules/task.go deleted file mode 100644 index 8c1bfe86b65..00000000000 --- a/pkg/mcclient/modules/task.go +++ /dev/null @@ -1,47 +0,0 @@ -// 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 modules - -import ( - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/mcclient" -) - -type ITaskResourceManager interface { - PerformClassAction(session *mcclient.ClientSession, action string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) -} - -func TaskComplete(man ITaskResourceManager, session *mcclient.ClientSession, taskId string, params jsonutils.JSONObject) { - for i := 0; i < 3; i++ { - _, err := man.PerformClassAction(session, taskId, params) - if err == nil { - log.Infof("Sync task %s complete succ", taskId) - break - } - log.Errorf("Sync task %s complete error: %v", taskId, err) - time.Sleep(5 * time.Second) - } -} - -func TaskFailed(man ITaskResourceManager, session *mcclient.ClientSession, taskId string, reason string) { - params := jsonutils.NewDict() - params.Add(jsonutils.NewString("error"), "__status__") - params.Add(jsonutils.NewString(reason), "__reason__") - TaskComplete(man, session, taskId, params) -} diff --git a/pkg/mcclient/modules/tasks/doc.go b/pkg/mcclient/modules/tasks/doc.go new file mode 100644 index 00000000000..1978ef5940d --- /dev/null +++ b/pkg/mcclient/modules/tasks/doc.go @@ -0,0 +1,15 @@ +// 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 tasks // import "yunion.io/x/onecloud/pkg/mcclient/modules/tasks" diff --git a/pkg/mcclient/modules/tasks/mod_tasks.go b/pkg/mcclient/modules/tasks/mod_tasks.go new file mode 100644 index 00000000000..c3a6d60eb21 --- /dev/null +++ b/pkg/mcclient/modules/tasks/mod_tasks.go @@ -0,0 +1,114 @@ +// 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 tasks + +import ( + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/modulebase" +) + +/*var ( + ComputeTasks TasksManager + DevtoolTasks TasksManager +)*/ + +type TasksManager struct { + modulebase.ResourceManager +} + +/*func init() { + ComputeTasks = TasksManager{ + ResourceManager: modules.NewComputeManager("task", "tasks", + []string{}, + []string{"Id", "Obj_name", "Obj_Id", "Task_name", "Stage", "Created_at"}), + } + modules.RegisterCompute(&ComputeTasks) + + DevtoolTasks = TasksManager{ + ResourceManager: modules.NewDevtoolManager("task", "tasks", + []string{}, + []string{"Id", "Obj_name", "Obj_Id", "Task_name", "Stage", "Created_at"}, + ), + } +}*/ + +func (man *TasksManager) TaskComplete(session *mcclient.ClientSession, taskId string, params jsonutils.JSONObject) { + for i := 0; i < 3; i++ { + _, err := man.PerformClassAction(session, taskId, params) + if err == nil { + log.Infof("Sync task %s complete succ", taskId) + break + } + log.Errorf("Sync task %s complete error: %v", taskId, err) + time.Sleep(5 * time.Second) + } +} + +func (man *TasksManager) TaskFailed(session *mcclient.ClientSession, taskId string, err error) { + man.TaskFailed2(session, taskId, err.Error()) +} + +func (man *TasksManager) TaskFailed2(session *mcclient.ClientSession, taskId string, reason string) { + man.TaskFailed3(session, taskId, reason, nil) +} + +func (man *TasksManager) TaskFailed3(session *mcclient.ClientSession, taskId string, reason string, params *jsonutils.JSONDict) { + if params == nil { + params = jsonutils.NewDict() + } + params.Add(jsonutils.NewString("error"), "__status__") + params.Add(jsonutils.NewString(reason), "__reason__") + man.TaskComplete(session, taskId, params) +} + +/*func (self *TasksManager) getManager(session *mcclient.ClientSession, params jsonutils.JSONObject) (*modulebase.ResourceManager, error) { + serviceType := apis.SERVICE_TYPE_REGION + if params.Contains("service_type") { + serviceType, _ = params.GetString("service_type") + } + + version := "" + switch serviceType { + case apis.SERVICE_TYPE_KEYSTONE: + version = "v3" + case apis.SERVICE_TYPE_REGION, apis.SERVICE_TYPE_NOTIFY: + version = "v2" + case apis.SERVICE_TYPE_IMAGE: + version = "v1" + } + + _, err := session.GetServiceURL(serviceType, "") + if err != nil { + return nil, httperrors.NewNotFoundError("service %s not found error: %v", serviceType, err) + } + + return &modulebase.ResourceManager{ + BaseManager: *modulebase.NewBaseManager(serviceType, "", version, []string{}, []string{}), + Keyword: "task", KeywordPlural: "tasks", + }, nil +} + +func (this *TasksManager) List(session *mcclient.ClientSession, params jsonutils.JSONObject) (*printutils.ListResult, error) { + man, err := this.getManager(session, params) + if err != nil { + return nil, err + } + return man.List(session, params) +}*/