From bb9b2c0d2cd8892e15d309d28c6954c343268141 Mon Sep 17 00:00:00 2001 From: Zhang Dongliang Date: Wed, 22 Aug 2018 14:24:59 +0800 Subject: [PATCH 01/32] =?UTF-8?q?=E5=A2=9E=E5=8A=A0logclient?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/util/logclient/doc.go | 1 + pkg/util/logclient/logclient.go | 64 +++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 pkg/util/logclient/doc.go create mode 100644 pkg/util/logclient/logclient.go diff --git a/pkg/util/logclient/doc.go b/pkg/util/logclient/doc.go new file mode 100644 index 0000000000..7466f9702f --- /dev/null +++ b/pkg/util/logclient/doc.go @@ -0,0 +1 @@ +package logclient // import "yunion.io/x/onecloud/pkg/util/logclient" diff --git a/pkg/util/logclient/logclient.go b/pkg/util/logclient/logclient.go new file mode 100644 index 0000000000..3f5ea151c2 --- /dev/null +++ b/pkg/util/logclient/logclient.go @@ -0,0 +1,64 @@ +package logclient + +import ( + "fmt" + "net/http" + "context" + "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/mcclient/auth" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/log" +) + +func fetchRegion(req *http.Request) string { + r, e := req.Cookie("region") + if e != nil { + return "" + } + return r.Value +} + +func AddActionLog(ctx context.Context, userCred mcclient.TokenCredential, action, notes string, e error) { + // 记录企业信息变更操作日志 + +// token := auth.FetchUserCredential(ctx) + log.Errorf("\n.\n.\n.\n.\n.") + log.Errorf("[AddActionLog]ctx: %s", ctx) +// log.Errorf("[AddActionLog] token: %s", token) + log.Errorf("[AddActionLog] token.userid: %s", userCred.GetUserId()) + log.Errorf("\n.\n.\n.\n.\n.") + // userid := userCred.GetUserId() + // username := userCred.GetUserName() + // tenantid := userCred.GetTenantId() + token := userCred + // s := auth.GetAdminSession(fetchRegion(req), "") + s := auth.GetSession(userCred, "", "") + log.Errorf("session id: Fzu3qiEYUS9P %s", s) + + log := jsonutils.NewDict() + log.Add(jsonutils.NewString("infos"), "obj_type") + log.Add(jsonutils.NewString("-"), "obj_id") + log.Add(jsonutils.NewString("-"), "obj_name") + log.Add(jsonutils.NewString("更新"), "action") + log.Add(jsonutils.NewString(token.GetUserId()), "user_id") + log.Add(jsonutils.NewString(token.GetUserName()), "user") + log.Add(jsonutils.NewString(token.GetTenantId()), "tenant_id") + log.Add(jsonutils.NewString(token.GetTenantName()), "tenant") + log.Add(jsonutils.NewString(notes), "notes") + + if e != nil { + // 失败日志 + log.Add(jsonutils.JSONFalse, "success") + } else { + // 成功日志 + log.Add(jsonutils.JSONTrue, "success") + } + + _, e = modules.Actions.Create(s, log) + if e != nil { + fmt.Printf("create action log failed %s", e) + } else { + fmt.Println("create action log sucess") + } +} From 6e5b509f3ecf1997e08a4d075571a775562c2477 Mon Sep 17 00:00:00 2001 From: Zhang Dongliang Date: Fri, 24 Aug 2018 15:34:02 +0800 Subject: [PATCH 02/32] =?UTF-8?q?=E5=A2=9E=E5=8A=A0logclient;=20aliyun=20s?= =?UTF-8?q?erver=20crud=20=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/cloudcommon/db/db_dispatcher.go | 20 ++- pkg/compute/tasks/guest_rebuild_root_task.go | 11 +- pkg/compute/tasks/guest_start_task.go | 4 +- pkg/compute/tasks/guest_stop_task.go | 4 +- pkg/compute/tasks/guest_syncstatus_task.go | 7 + pkg/util/logclient/logclient.go | 142 ++++++++++++------- 6 files changed, 128 insertions(+), 60 deletions(-) diff --git a/pkg/cloudcommon/db/db_dispatcher.go b/pkg/cloudcommon/db/db_dispatcher.go index 8b4179f50d..89d6cd54dd 100644 --- a/pkg/cloudcommon/db/db_dispatcher.go +++ b/pkg/cloudcommon/db/db_dispatcher.go @@ -21,6 +21,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/mcclient/modules" "yunion.io/x/onecloud/pkg/util/httputils" + "yunion.io/x/onecloud/pkg/util/logclient" ) type DBModelDispatcher struct { @@ -740,6 +741,7 @@ func (dispatcher *DBModelDispatcher) Create(ctx context.Context, query jsonutils return nil, httperrors.NewGeneralError(err) } OpsLog.LogEvent(model, ACT_CREATE, model.GetShortDesc(), userCred) + logclient.AddActionLog(ctx, userCred, logclient.ACT_CREATE, "", model, "") dispatcher.modelManager.OnCreateComplete(ctx, []IModel{model}, userCred, query, data) return getItemDetails(dispatcher.modelManager, model, ctx, userCred, query) } @@ -958,11 +960,13 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre if err != nil { log.Errorf("validate update condition error: %s", err) + logclient.AddActionLog(ctx, userCred, logclient.ACT_UPDATE, "", item, err.Error()) return nil, httperrors.NewGeneralError(err) } dataDict, ok := data.(*jsonutils.JSONDict) if !ok { + logclient.AddActionLog(ctx, userCred, logclient.ACT_UPDATE, "", item, "Invalid data JSONObject") return nil, httperrors.NewInternalServerError("Invalid data JSONObject") } @@ -970,13 +974,16 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre if len(name) > 0 { err = alterNameValidator(item, name) if err != nil { + logclient.AddActionLog(ctx, userCred, logclient.ACT_UPDATE, "", item, err.Error()) return nil, err } } dataDict, err = item.ValidateUpdateData(ctx, userCred, query, dataDict) if err != nil { - log.Errorf("validate update data error: %s", err) + errMsg := fmt.Sprintf("validate update data error: %s", err) + log.Errorf(errMsg) + logclient.AddActionLog(ctx, userCred, logclient.ACT_UPDATE, "", item, errMsg) return nil, httperrors.NewGeneralError(err) } item.PreUpdate(ctx, userCred, query, dataDict) @@ -985,7 +992,9 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre filterData := dataDict.CopyIncludes(updateFields(manager, userCred)...) err = filterData.Unmarshal(item) if err != nil { - log.Errorf("unmarshal fail: %s", err) + errMsg := fmt.Sprintf("unmarshal fail: %s", err) + logclient.AddActionLog(ctx, userCred, logclient.ACT_UPDATE, "", item, errMsg) + log.Errorf(errMsg) return httperrors.NewGeneralError(err) } return nil @@ -999,8 +1008,10 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre diffStr := sqlchemy.UpdateDiffString(diff) if len(diffStr) > 0 { OpsLog.LogEvent(item, ACT_UPDATE, diffStr, userCred) + logclient.AddActionLog(ctx, userCred, logclient.ACT_UPDATE, "", item, diffStr) } } + logclient.AddActionLog(ctx, userCred, logclient.ACT_UPDATE, dataDict.String(), item, "") return getItemDetails(manager, item, ctx, userCred, query) } @@ -1027,10 +1038,13 @@ func DeleteModel(ctx context.Context, userCred mcclient.TokenCredential, item IM return item.MarkDelete() }) if err != nil { - log.Errorf("save update error %s", err) + msg := fmt.Sprintf("save update error %s", err) + log.Errorf(msg) + logclient.AddActionLog(ctx, userCred, logclient.ACT_DELETE, "", item, msg) return httperrors.NewGeneralError(err) } OpsLog.LogEvent(item, ACT_DELETE, item.GetShortDesc(), userCred) + logclient.AddActionLog(ctx, userCred, logclient.ACT_DELETE, "", item, "") return nil } diff --git a/pkg/compute/tasks/guest_rebuild_root_task.go b/pkg/compute/tasks/guest_rebuild_root_task.go index 03345b85ac..165b8ff213 100644 --- a/pkg/compute/tasks/guest_rebuild_root_task.go +++ b/pkg/compute/tasks/guest_rebuild_root_task.go @@ -11,6 +11,7 @@ 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/util/logclient" ) func init() { @@ -48,6 +49,7 @@ func (self *GuestRebuildRootTask) StartRebuildRootDisk(ctx context.Context, gues }) if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) return } else { db.OpsLog.LogEvent(gds.Root, db.ACT_UPDATE_STATUS, @@ -64,16 +66,19 @@ func (self *GuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Context, imginfo, err := models.CachedimageManager.GetImageById(ctx, self.UserCred, imgId, false) if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) return } osprof, err := osprofile.GetOSProfileFromImageProperties(imginfo.Properties, guest.Hypervisor) if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) return } err = guest.SetMetadata(ctx, "__os_profile__", osprof, self.UserCred) if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) return } if guest.OsType != osprof.OSType { @@ -83,11 +88,11 @@ func (self *GuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Context, }) if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) return } } db.OpsLog.LogEvent(guest, db.ACT_REBUILD_ROOT, "", self.UserCred) - // TODO: logclient guest.NotifyServerEvent(notifyclient.SERVER_REBUILD_ROOT, notifyclient.PRIORITY_IMPORTANT, true) self.SetStage("OnSyncStatusComplete", nil) guest.StartSyncstatus(ctx, self.UserCred, self.GetTaskId()) @@ -96,7 +101,7 @@ func (self *GuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Context, func (self *GuestRebuildRootTask) OnRebuildRootDiskCompleteFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { db.OpsLog.LogEvent(guest, db.ACT_REBUILD_ROOT_FAIL, data.String(), self.UserCred) guest.SetStatus(self.UserCred, models.VM_REBUILD_ROOT_FAIL, "") - // TODO: logclient + logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_REBUILD, "", guest, data.String()) } func (self *GuestRebuildRootTask) OnSyncStatusComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { @@ -106,6 +111,7 @@ func (self *GuestRebuildRootTask) OnSyncStatusComplete(ctx context.Context, gues } else { self.SetStageComplete(ctx, nil) } + logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_REBUILD, "", guest, "") } func (self *GuestRebuildRootTask) OnGuestStartComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { @@ -137,6 +143,7 @@ func (self *KVMGuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Conte func (self *KVMGuestRebuildRootTask) OnRebuildRootDiskCompleteFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { self.SetStageFailed(ctx, data.String()) + logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_REBUILD, "", guest, data.String()) } func (self *KVMGuestRebuildRootTask) OnGuestDeployComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { diff --git a/pkg/compute/tasks/guest_start_task.go b/pkg/compute/tasks/guest_start_task.go index 7bbb2ca2dc..3965a51d05 100644 --- a/pkg/compute/tasks/guest_start_task.go +++ b/pkg/compute/tasks/guest_start_task.go @@ -4,10 +4,10 @@ import ( "context" "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" ) type GuestStartTask struct { @@ -59,6 +59,7 @@ func (self *GuestStartTask) OnStartComplete(ctx context.Context, obj db.IStandal db.OpsLog.LogEvent(guest, db.ACT_START, guest.GetShortDesc(), self.UserCred) self.SetStage("on_guest_syncstatus_after_start", nil) guest.StartSyncstatus(ctx, self.UserCred, self.GetTaskId()) + logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_START, "", guest, "") // self.taskComplete(ctx, guest) } @@ -75,6 +76,7 @@ func (self *GuestStartTask) OnStartCompleteFailed(ctx context.Context, obj db.IS func (self *GuestStartTask) onStartGuestFailed(ctx context.Context, guest *models.SGuest, err error) { self.SetStageFailed(ctx, err.Error()) self.OnStartCompleteFailed(ctx, guest, jsonutils.NewString(err.Error())) + logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_START, "", guest, err.Error()) } func (self *GuestStartTask) taskComplete(ctx context.Context, guest *models.SGuest) { diff --git a/pkg/compute/tasks/guest_stop_task.go b/pkg/compute/tasks/guest_stop_task.go index 2ed0f4aa6c..aa0119d549 100644 --- a/pkg/compute/tasks/guest_stop_task.go +++ b/pkg/compute/tasks/guest_stop_task.go @@ -6,10 +6,10 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" - "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" ) type GuestStopTask struct { @@ -58,10 +58,12 @@ func (self *GuestStopTask) OnGuestStopTaskComplete(ctx context.Context, obj db.I if guest.Status == models.VM_READY && guest.DisableDelete.IsFalse() && guest.ShutdownBehavior == models.SHUTDOWN_TERMINATE { guest.StartAutoDeleteGuestTask(ctx, self.UserCred, "") } + logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_STOP, "", guest, "") } func (self *GuestStopTask) OnStopGuestFail(ctx context.Context, guest *models.SGuest, err error) { guest.SetStatus(self.UserCred, models.VM_STOP_FAILED, err.Error()) db.OpsLog.LogEvent(guest, db.ACT_STOP_FAIL, err.Error(), self.UserCred) self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_STOP, "", guest, err.Error()) } diff --git a/pkg/compute/tasks/guest_syncstatus_task.go b/pkg/compute/tasks/guest_syncstatus_task.go index 478f4afe6d..7b161e9f27 100644 --- a/pkg/compute/tasks/guest_syncstatus_task.go +++ b/pkg/compute/tasks/guest_syncstatus_task.go @@ -2,6 +2,7 @@ package tasks import ( "context" + "fmt" "yunion.io/x/jsonutils" "yunion.io/x/log" @@ -9,6 +10,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" ) type GuestSyncstatusTask struct { @@ -53,9 +55,14 @@ func (self *GuestSyncstatusTask) OnGetStatusSucc(ctx context.Context, guest *mod statusData.Add(jsonutils.NewString(statusStr), "status") guest.PerformStatus(ctx, self.UserCred, nil, statusData) self.SetStageComplete(ctx, nil) + fmt.Println(" \n*\n*\n*\n*\n*\n*\n*\n*\n*\n*\n*\\n*n* * * * * * * * * * * * * ") + fmt.Println("* * * * * * * * * * * * * server obj:", guest) + fmt.Println(" \n*\n*\n*\n*\n*\n*\n*\n*\n*\n*\n*\\n*n* * * * * * * * * * * * * ") + logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_SYNC_STATUS, "", guest, "") } func (self *GuestSyncstatusTask) OnGetStatusFail(ctx context.Context, guest *models.SGuest, err error) { guest.SetStatus(self.UserCred, models.VM_UNKNOWN, err.Error()) self.SetStageComplete(ctx, nil) + logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_SYNC_STATUS, "", guest, err.Error()) } diff --git a/pkg/util/logclient/logclient.go b/pkg/util/logclient/logclient.go index 3f5ea151c2..b7b52ec23f 100644 --- a/pkg/util/logclient/logclient.go +++ b/pkg/util/logclient/logclient.go @@ -1,64 +1,100 @@ package logclient import ( - "fmt" - "net/http" "context" - "yunion.io/x/onecloud/pkg/mcclient/modules" + "fmt" + "log" + "net/http" + "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/pkg/mcclient/auth" + "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/mcclient/auth" + "yunion.io/x/onecloud/pkg/util/httputils" ) -func fetchRegion(req *http.Request) string { - r, e := req.Cookie("region") - if e != nil { - return "" +const ( + ACT_VM_RESET_PSWD = "重置密码" + ACT_VM_REBUILD = "重装系统" + ACT_VM_START = "开机" + ACT_VM_STOP = "关机" + ACT_VM_PURGE = "清除" + ACT_VM_CHANGE_FLAVOR = "调整配置" + ACT_VM_SYNC_CONF = "同步配置" + ACT_GUEST_ATTACH_ISOLATED_DEVICE = "挂载透传设备" + ACT_GUEST_DETACH_ISOLATED_DEVICE = "卸载透传设备" + ACT_VM_SYNC_STATUS = "同步状态" + ACT_CREATE = "创建" + ACT_DELETE = "删除" + ACT_UPDATE = "更新" + ACT_RESERVE_IP = "预留IP" + ACT_RELEASE_IP = "释放IP" + ACT_CANCEL_DELETE = "恢复" + ACT_UNCACHED_IMAGE = "清除缓存" + ACT_ENABLE = "启用" + ACT_DISABLE = "禁用" + ACT_ONLINE = "上线" + ACT_OFFLINE = "下线" + ACT_PUBLIC = "设为共享" + ACT_PRIVATE = "设为私有" + ACT_MERGE = "合并" + ACT_SPLIT = "分割" + ACT_ALLOCATE = "分配" + ACT_BM_MAINTENANCE = "进入离线状态" + ACT_BM_UNMAINTENANCE = "退出离线状态" + ACT_BM_CONVERT_HYPER = "转换为宿主机" + ACT_BM_UNCONVERT_HYPER = "转换为受管物理机" + ACT_ADDTAG = "添加标签" + ACT_RMTAG = "删除标签" + ACT_RESIZE = "扩容" + ACT_VM_ATTACH_DISK = "挂载磁盘" + ACT_VM_DETACH_DISK = "卸载磁盘" +) + +type IObject interface { + GetId() string + GetName() string + Keyword() string +} + +func AddActionLog(ctx context.Context, userCred mcclient.TokenCredential, action, notes string, obj IObject, e string) { + + token := userCred + logentry := jsonutils.NewDict() + logentry.Add(jsonutils.NewString(obj.GetName()), "obj_name") + logentry.Add(jsonutils.NewString(obj.Keyword()), "obj_type") + logentry.Add(jsonutils.NewString(obj.GetId()), "obj_id") + logentry.Add(jsonutils.NewString(action), "action") + logentry.Add(jsonutils.NewString(token.GetUserId()), "user_id") + logentry.Add(jsonutils.NewString(token.GetUserName()), "user") + logentry.Add(jsonutils.NewString(token.GetTenantId()), "tenant_id") + logentry.Add(jsonutils.NewString(token.GetTenantName()), "tenant") + // todo: 正式版去掉下面这行。 + notes = "[region2]" + notes + + if len(e) > 0 { + // 失败日志 + logentry.Add(jsonutils.JSONFalse, "success") + notes = fmt.Sprintf("%s%s", notes, e) + logentry.Add(jsonutils.NewString(notes), "notes") + } else { + // 成功日志 + logentry.Add(jsonutils.JSONTrue, "success") + logentry.Add(jsonutils.NewString(notes), "notes") } - return r.Value -} -func AddActionLog(ctx context.Context, userCred mcclient.TokenCredential, action, notes string, e error) { - // 记录企业信息变更操作日志 - -// token := auth.FetchUserCredential(ctx) - log.Errorf("\n.\n.\n.\n.\n.") - log.Errorf("[AddActionLog]ctx: %s", ctx) -// log.Errorf("[AddActionLog] token: %s", token) - log.Errorf("[AddActionLog] token.userid: %s", userCred.GetUserId()) - log.Errorf("\n.\n.\n.\n.\n.") - // userid := userCred.GetUserId() - // username := userCred.GetUserName() - // tenantid := userCred.GetTenantId() - token := userCred - // s := auth.GetAdminSession(fetchRegion(req), "") - s := auth.GetSession(userCred, "", "") - log.Errorf("session id: Fzu3qiEYUS9P %s", s) - - log := jsonutils.NewDict() - log.Add(jsonutils.NewString("infos"), "obj_type") - log.Add(jsonutils.NewString("-"), "obj_id") - log.Add(jsonutils.NewString("-"), "obj_name") - log.Add(jsonutils.NewString("更新"), "action") - log.Add(jsonutils.NewString(token.GetUserId()), "user_id") - log.Add(jsonutils.NewString(token.GetUserName()), "user") - log.Add(jsonutils.NewString(token.GetTenantId()), "tenant_id") - log.Add(jsonutils.NewString(token.GetTenantName()), "tenant") - log.Add(jsonutils.NewString(notes), "notes") - - if e != nil { - // 失败日志 - log.Add(jsonutils.JSONFalse, "success") - } else { - // 成功日志 - log.Add(jsonutils.JSONTrue, "success") - } - - _, e = modules.Actions.Create(s, log) - if e != nil { - fmt.Printf("create action log failed %s", e) - } else { - fmt.Println("create action log sucess") - } + uri, err := auth.GetServiceURL("log", options.Options.Region, "", "") + if err != nil { + log.Println("log service not ready", err) + return + } + + uri = fmt.Sprintf("%s/actions", uri) + header := http.Header{} + header.Add("X-Auth-Token", userCred.GetTokenString()) + _, _, err = httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", uri, header, logentry, false) + if err != nil { + log.Println("post log error", err) + return + } } From 58edf9daf4afca6e7c0376f34e95bc58316ebd3d Mon Sep 17 00:00:00 2001 From: Zhang Dongliang Date: Sat, 25 Aug 2018 07:50:31 +0800 Subject: [PATCH 03/32] =?UTF-8?q?=E9=98=BF=E9=87=8C=E4=BA=91=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E8=99=9A=E6=9C=BA=E5=A4=B1=E8=B4=A5=E6=97=B6=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=20actionlog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/cloudcommon/db/db_dispatcher.go | 20 ++++++++++---------- pkg/cloudcommon/db/statusstandalone.go | 5 +++++ pkg/compute/tasks/guest_create_task.go | 4 ++++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/pkg/cloudcommon/db/db_dispatcher.go b/pkg/cloudcommon/db/db_dispatcher.go index 89d6cd54dd..fa4ae37536 100644 --- a/pkg/cloudcommon/db/db_dispatcher.go +++ b/pkg/cloudcommon/db/db_dispatcher.go @@ -741,7 +741,7 @@ func (dispatcher *DBModelDispatcher) Create(ctx context.Context, query jsonutils return nil, httperrors.NewGeneralError(err) } OpsLog.LogEvent(model, ACT_CREATE, model.GetShortDesc(), userCred) - logclient.AddActionLog(ctx, userCred, logclient.ACT_CREATE, "", model, "") + logclient.AddActionLog(userCred, logclient.ACT_CREATE, "", model, "") dispatcher.modelManager.OnCreateComplete(ctx, []IModel{model}, userCred, query, data) return getItemDetails(dispatcher.modelManager, model, ctx, userCred, query) } @@ -960,13 +960,13 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre if err != nil { log.Errorf("validate update condition error: %s", err) - logclient.AddActionLog(ctx, userCred, logclient.ACT_UPDATE, "", item, err.Error()) + logclient.AddActionLog(userCred, logclient.ACT_UPDATE, "", item, err.Error()) return nil, httperrors.NewGeneralError(err) } dataDict, ok := data.(*jsonutils.JSONDict) if !ok { - logclient.AddActionLog(ctx, userCred, logclient.ACT_UPDATE, "", item, "Invalid data JSONObject") + logclient.AddActionLog(userCred, logclient.ACT_UPDATE, "", item, "Invalid data JSONObject") return nil, httperrors.NewInternalServerError("Invalid data JSONObject") } @@ -974,7 +974,7 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre if len(name) > 0 { err = alterNameValidator(item, name) if err != nil { - logclient.AddActionLog(ctx, userCred, logclient.ACT_UPDATE, "", item, err.Error()) + logclient.AddActionLog(userCred, logclient.ACT_UPDATE, "", item, err.Error()) return nil, err } } @@ -983,7 +983,7 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre if err != nil { errMsg := fmt.Sprintf("validate update data error: %s", err) log.Errorf(errMsg) - logclient.AddActionLog(ctx, userCred, logclient.ACT_UPDATE, "", item, errMsg) + logclient.AddActionLog(userCred, logclient.ACT_UPDATE, "", item, errMsg) return nil, httperrors.NewGeneralError(err) } item.PreUpdate(ctx, userCred, query, dataDict) @@ -993,7 +993,7 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre err = filterData.Unmarshal(item) if err != nil { errMsg := fmt.Sprintf("unmarshal fail: %s", err) - logclient.AddActionLog(ctx, userCred, logclient.ACT_UPDATE, "", item, errMsg) + logclient.AddActionLog(userCred, logclient.ACT_UPDATE, "", item, errMsg) log.Errorf(errMsg) return httperrors.NewGeneralError(err) } @@ -1008,10 +1008,10 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre diffStr := sqlchemy.UpdateDiffString(diff) if len(diffStr) > 0 { OpsLog.LogEvent(item, ACT_UPDATE, diffStr, userCred) - logclient.AddActionLog(ctx, userCred, logclient.ACT_UPDATE, "", item, diffStr) + logclient.AddActionLog(userCred, logclient.ACT_UPDATE, "", item, diffStr) } } - logclient.AddActionLog(ctx, userCred, logclient.ACT_UPDATE, dataDict.String(), item, "") + logclient.AddActionLog(userCred, logclient.ACT_UPDATE, dataDict.String(), item, "") return getItemDetails(manager, item, ctx, userCred, query) } @@ -1040,11 +1040,11 @@ func DeleteModel(ctx context.Context, userCred mcclient.TokenCredential, item IM if err != nil { msg := fmt.Sprintf("save update error %s", err) log.Errorf(msg) - logclient.AddActionLog(ctx, userCred, logclient.ACT_DELETE, "", item, msg) + logclient.AddActionLog(userCred, logclient.ACT_DELETE, "", item, msg) return httperrors.NewGeneralError(err) } OpsLog.LogEvent(item, ACT_DELETE, item.GetShortDesc(), userCred) - logclient.AddActionLog(ctx, userCred, logclient.ACT_DELETE, "", item, "") + logclient.AddActionLog(userCred, logclient.ACT_DELETE, "", item, "") return nil } diff --git a/pkg/cloudcommon/db/statusstandalone.go b/pkg/cloudcommon/db/statusstandalone.go index cc7ea853a3..588bd88999 100644 --- a/pkg/cloudcommon/db/statusstandalone.go +++ b/pkg/cloudcommon/db/statusstandalone.go @@ -3,9 +3,11 @@ package db import ( "context" "fmt" + "strings" "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/logclient" ) type SStatusStandaloneResourceBase struct { @@ -40,6 +42,9 @@ func (model *SStatusStandaloneResourceBase) SetStatus(userCred mcclient.TokenCre notes = fmt.Sprintf("%s: %s", notes, reason) } OpsLog.LogEvent(model, ACT_UPDATE_STATUS, notes, userCred) + if strings.Contains(notes, "fail") { + logclient.AddActionLog(userCred, logclient.ACT_VM_SYNC_STATUS, "", model, notes) + } } return nil } diff --git a/pkg/compute/tasks/guest_create_task.go b/pkg/compute/tasks/guest_create_task.go index a57f49afca..9f104a12ef 100644 --- a/pkg/compute/tasks/guest_create_task.go +++ b/pkg/compute/tasks/guest_create_task.go @@ -11,6 +11,7 @@ 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/util/logclient" ) type GuestCreateTask struct { @@ -49,6 +50,7 @@ func (self *GuestCreateTask) OnDiskPreparedFailed(ctx context.Context, obj db.IS guest := obj.(*models.SGuest) guest.SetStatus(self.UserCred, models.VM_DISK_FAILED, "allocation failed") db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, data, self.UserCred) + logclient.AddActionLog(self.UserCred, logclient.ACT_ALLOCATE, "", guest, data.String()) notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_DISK_FAILED, data.String()) } @@ -76,6 +78,7 @@ func (self *GuestCreateTask) OnCdromPreparedFailed(ctx context.Context, obj db.I guest := obj.(*models.SGuest) guest.SetStatus(self.UserCred, models.VM_DISK_FAILED, "") db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, data, self.UserCred) + logclient.AddActionLog(self.UserCred, logclient.ACT_ALLOCATE, "", guest, data.String()) notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_DISK_FAILED, fmt.Sprintf("cdrom_failed %s", data)) } @@ -102,6 +105,7 @@ func (self *GuestCreateTask) OnDeployGuestDescCompleteFailed(ctx context.Context guest := obj.(*models.SGuest) guest.SetStatus(self.UserCred, models.VM_DEPLOY_FAILED, "deploy_failed") db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, data, self.UserCred) + logclient.AddActionLog(self.UserCred, logclient.ACT_ALLOCATE, "", guest, data.String()) notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_DEPLOY_FAILED, data.String()) } From a77e8f3b67f0f3e21b25663e2883970300c302b9 Mon Sep 17 00:00:00 2001 From: Zhang Dongliang Date: Sat, 25 Aug 2018 07:54:50 +0800 Subject: [PATCH 04/32] =?UTF-8?q?=E9=98=BF=E9=87=8C=E4=BA=91=E8=99=9A?= =?UTF-8?q?=E6=9C=BA=E5=88=A0=E9=99=A4=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/compute/tasks/guest_delete_task.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/compute/tasks/guest_delete_task.go b/pkg/compute/tasks/guest_delete_task.go index b86a63d2ec..1e502edce2 100644 --- a/pkg/compute/tasks/guest_delete_task.go +++ b/pkg/compute/tasks/guest_delete_task.go @@ -9,6 +9,7 @@ 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/util/logclient" "yunion.io/x/pkg/utils" ) @@ -88,6 +89,7 @@ func (self *GuestDeleteTask) OnGuestDeleteCompleteFailed(ctx context.Context, ob guest := obj.(*models.SGuest) guest.SetStatus(self.UserCred, models.VM_DELETE_FAIL, err.String()) db.OpsLog.LogEvent(guest, db.ACT_DELOCATE_FAIL, err, self.UserCred) + logclient.AddActionLog(self.UserCred, logclient.ACT_DELETE, "", guest, err.String()) } func (self *GuestDeleteTask) OnGuestDeleteComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { @@ -103,6 +105,7 @@ func (self *GuestDeleteTask) DeleteGuest(ctx context.Context, guest *models.SGue guest.RealDelete(ctx, self.UserCred) guest.RemoveAllMetadata(ctx, self.UserCred) db.OpsLog.LogEvent(guest, db.ACT_DELOCATE, nil, self.UserCred) + logclient.AddActionLog(self.UserCred, logclient.ACT_DELETE, "", guest, "") if !guest.IsSystem && !guest.PendingDeleted { self.NotifyServerDeleted(ctx, guest) } From 0d1a33b495cce61fc79d0ddb248ce6455de3179c Mon Sep 17 00:00:00 2001 From: Zhang Dongliang Date: Sat, 25 Aug 2018 07:59:46 +0800 Subject: [PATCH 05/32] =?UTF-8?q?=E9=98=BF=E9=87=8C=E4=BA=91=E9=87=8D?= =?UTF-8?q?=E8=A3=85=E7=B3=BB=E7=BB=9F=E3=80=81=E5=BC=80=E6=9C=BA=E5=85=B3?= =?UTF-8?q?=E6=9C=BA=E3=80=81=E5=90=8C=E6=AD=A5=E7=8A=B6=E6=80=81=E6=97=A5?= =?UTF-8?q?=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/compute/tasks/guest_rebuild_root_task.go | 16 +++++----- pkg/compute/tasks/guest_start_task.go | 4 +-- pkg/compute/tasks/guest_stop_task.go | 4 +-- pkg/compute/tasks/guest_syncstatus_task.go | 4 +-- pkg/util/logclient/logclient.go | 31 +++++++------------- 5 files changed, 25 insertions(+), 34 deletions(-) diff --git a/pkg/compute/tasks/guest_rebuild_root_task.go b/pkg/compute/tasks/guest_rebuild_root_task.go index 165b8ff213..1bd7c81249 100644 --- a/pkg/compute/tasks/guest_rebuild_root_task.go +++ b/pkg/compute/tasks/guest_rebuild_root_task.go @@ -49,7 +49,7 @@ func (self *GuestRebuildRootTask) StartRebuildRootDisk(ctx context.Context, gues }) if err != nil { self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) + logclient.AddActionLog(self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) return } else { db.OpsLog.LogEvent(gds.Root, db.ACT_UPDATE_STATUS, @@ -66,19 +66,19 @@ func (self *GuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Context, imginfo, err := models.CachedimageManager.GetImageById(ctx, self.UserCred, imgId, false) if err != nil { self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) + logclient.AddActionLog(self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) return } osprof, err := osprofile.GetOSProfileFromImageProperties(imginfo.Properties, guest.Hypervisor) if err != nil { self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) + logclient.AddActionLog(self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) return } err = guest.SetMetadata(ctx, "__os_profile__", osprof, self.UserCred) if err != nil { self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) + logclient.AddActionLog(self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) return } if guest.OsType != osprof.OSType { @@ -88,7 +88,7 @@ func (self *GuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Context, }) if err != nil { self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) + logclient.AddActionLog(self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) return } } @@ -101,7 +101,7 @@ func (self *GuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Context, func (self *GuestRebuildRootTask) OnRebuildRootDiskCompleteFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { db.OpsLog.LogEvent(guest, db.ACT_REBUILD_ROOT_FAIL, data.String(), self.UserCred) guest.SetStatus(self.UserCred, models.VM_REBUILD_ROOT_FAIL, "") - logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_REBUILD, "", guest, data.String()) + logclient.AddActionLog(self.UserCred, logclient.ACT_VM_REBUILD, "", guest, data.String()) } func (self *GuestRebuildRootTask) OnSyncStatusComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { @@ -111,7 +111,7 @@ func (self *GuestRebuildRootTask) OnSyncStatusComplete(ctx context.Context, gues } else { self.SetStageComplete(ctx, nil) } - logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_REBUILD, "", guest, "") + logclient.AddActionLog(self.UserCred, logclient.ACT_VM_REBUILD, "", guest, "") } func (self *GuestRebuildRootTask) OnGuestStartComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { @@ -143,7 +143,7 @@ func (self *KVMGuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Conte func (self *KVMGuestRebuildRootTask) OnRebuildRootDiskCompleteFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { self.SetStageFailed(ctx, data.String()) - logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_REBUILD, "", guest, data.String()) + logclient.AddActionLog(self.UserCred, logclient.ACT_VM_REBUILD, "", guest, data.String()) } func (self *KVMGuestRebuildRootTask) OnGuestDeployComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { diff --git a/pkg/compute/tasks/guest_start_task.go b/pkg/compute/tasks/guest_start_task.go index 3965a51d05..d5af7cadb3 100644 --- a/pkg/compute/tasks/guest_start_task.go +++ b/pkg/compute/tasks/guest_start_task.go @@ -59,7 +59,7 @@ func (self *GuestStartTask) OnStartComplete(ctx context.Context, obj db.IStandal db.OpsLog.LogEvent(guest, db.ACT_START, guest.GetShortDesc(), self.UserCred) self.SetStage("on_guest_syncstatus_after_start", nil) guest.StartSyncstatus(ctx, self.UserCred, self.GetTaskId()) - logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_START, "", guest, "") + logclient.AddActionLog(self.UserCred, logclient.ACT_VM_START, "", guest, "") // self.taskComplete(ctx, guest) } @@ -76,7 +76,7 @@ func (self *GuestStartTask) OnStartCompleteFailed(ctx context.Context, obj db.IS func (self *GuestStartTask) onStartGuestFailed(ctx context.Context, guest *models.SGuest, err error) { self.SetStageFailed(ctx, err.Error()) self.OnStartCompleteFailed(ctx, guest, jsonutils.NewString(err.Error())) - logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_START, "", guest, err.Error()) + logclient.AddActionLog(self.UserCred, logclient.ACT_VM_START, "", guest, err.Error()) } func (self *GuestStartTask) taskComplete(ctx context.Context, guest *models.SGuest) { diff --git a/pkg/compute/tasks/guest_stop_task.go b/pkg/compute/tasks/guest_stop_task.go index aa0119d549..303c48b2e0 100644 --- a/pkg/compute/tasks/guest_stop_task.go +++ b/pkg/compute/tasks/guest_stop_task.go @@ -58,12 +58,12 @@ func (self *GuestStopTask) OnGuestStopTaskComplete(ctx context.Context, obj db.I if guest.Status == models.VM_READY && guest.DisableDelete.IsFalse() && guest.ShutdownBehavior == models.SHUTDOWN_TERMINATE { guest.StartAutoDeleteGuestTask(ctx, self.UserCred, "") } - logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_STOP, "", guest, "") + logclient.AddActionLog(self.UserCred, logclient.ACT_VM_STOP, "", guest, "") } func (self *GuestStopTask) OnStopGuestFail(ctx context.Context, guest *models.SGuest, err error) { guest.SetStatus(self.UserCred, models.VM_STOP_FAILED, err.Error()) db.OpsLog.LogEvent(guest, db.ACT_STOP_FAIL, err.Error(), self.UserCred) self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_STOP, "", guest, err.Error()) + logclient.AddActionLog(self.UserCred, logclient.ACT_VM_STOP, "", guest, err.Error()) } diff --git a/pkg/compute/tasks/guest_syncstatus_task.go b/pkg/compute/tasks/guest_syncstatus_task.go index 7b161e9f27..c315525baf 100644 --- a/pkg/compute/tasks/guest_syncstatus_task.go +++ b/pkg/compute/tasks/guest_syncstatus_task.go @@ -58,11 +58,11 @@ func (self *GuestSyncstatusTask) OnGetStatusSucc(ctx context.Context, guest *mod fmt.Println(" \n*\n*\n*\n*\n*\n*\n*\n*\n*\n*\n*\\n*n* * * * * * * * * * * * * ") fmt.Println("* * * * * * * * * * * * * server obj:", guest) fmt.Println(" \n*\n*\n*\n*\n*\n*\n*\n*\n*\n*\n*\\n*n* * * * * * * * * * * * * ") - logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_SYNC_STATUS, "", guest, "") + logclient.AddActionLog(self.UserCred, logclient.ACT_VM_SYNC_STATUS, "", guest, "") } func (self *GuestSyncstatusTask) OnGetStatusFail(ctx context.Context, guest *models.SGuest, err error) { guest.SetStatus(self.UserCred, models.VM_UNKNOWN, err.Error()) self.SetStageComplete(ctx, nil) - logclient.AddActionLog(ctx, self.UserCred, logclient.ACT_VM_SYNC_STATUS, "", guest, err.Error()) + logclient.AddActionLog(self.UserCred, logclient.ACT_VM_SYNC_STATUS, "", guest, err.Error()) } diff --git a/pkg/util/logclient/logclient.go b/pkg/util/logclient/logclient.go index b7b52ec23f..658bc2887f 100644 --- a/pkg/util/logclient/logclient.go +++ b/pkg/util/logclient/logclient.go @@ -1,16 +1,12 @@ package logclient import ( - "context" "fmt" - "log" - "net/http" "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" - "yunion.io/x/onecloud/pkg/util/httputils" + "yunion.io/x/onecloud/pkg/mcclient/modules" ) const ( @@ -57,7 +53,7 @@ type IObject interface { Keyword() string } -func AddActionLog(ctx context.Context, userCred mcclient.TokenCredential, action, notes string, obj IObject, e string) { +func AddActionLog(userCred mcclient.TokenCredential, action, notes string, obj IObject, e string) { token := userCred logentry := jsonutils.NewDict() @@ -69,8 +65,11 @@ func AddActionLog(ctx context.Context, userCred mcclient.TokenCredential, action logentry.Add(jsonutils.NewString(token.GetUserName()), "user") logentry.Add(jsonutils.NewString(token.GetTenantId()), "tenant_id") logentry.Add(jsonutils.NewString(token.GetTenantName()), "tenant") - // todo: 正式版去掉下面这行。 - notes = "[region2]" + notes + + // TODO delete following line later + notes = "[a2]" + notes + + s := auth.GetSession(userCred, "", "") if len(e) > 0 { // 失败日志 @@ -83,18 +82,10 @@ func AddActionLog(ctx context.Context, userCred mcclient.TokenCredential, action logentry.Add(jsonutils.NewString(notes), "notes") } - uri, err := auth.GetServiceURL("log", options.Options.Region, "", "") + _, err := modules.Actions.Create(s, logentry) if err != nil { - log.Println("log service not ready", err) - return - } - - uri = fmt.Sprintf("%s/actions", uri) - header := http.Header{} - header.Add("X-Auth-Token", userCred.GetTokenString()) - _, _, err = httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", uri, header, logentry, false) - if err != nil { - log.Println("post log error", err) - return + fmt.Printf("create action log failed %s", err) + } else { + fmt.Println("create action log success") } } From eb135f71dc29d31bcdd4d6bbba76e7e9e71e0c64 Mon Sep 17 00:00:00 2001 From: Zhang Dongliang Date: Mon, 27 Aug 2018 18:00:13 +0800 Subject: [PATCH 06/32] =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E9=87=8D=E6=9E=84?= =?UTF-8?q?=EF=BC=8C=E4=B8=8EOpsLog.LogEvent=20=E4=BF=9D=E6=8C=81=E4=B8=80?= =?UTF-8?q?=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/cloudcommon/db/db_dispatcher.go | 20 +++++++------- pkg/cloudcommon/db/statusstandalone.go | 2 +- pkg/compute/tasks/guest_create_task.go | 6 ++--- pkg/compute/tasks/guest_delete_task.go | 4 +-- pkg/compute/tasks/guest_rebuild_root_task.go | 18 ++++++------- pkg/compute/tasks/guest_start_task.go | 4 +-- pkg/compute/tasks/guest_stop_task.go | 4 +-- pkg/compute/tasks/guest_syncstatus_task.go | 8 ++---- pkg/util/logclient/logclient.go | 28 +++++++++++--------- 9 files changed, 46 insertions(+), 48 deletions(-) diff --git a/pkg/cloudcommon/db/db_dispatcher.go b/pkg/cloudcommon/db/db_dispatcher.go index fa4ae37536..bc1db0d727 100644 --- a/pkg/cloudcommon/db/db_dispatcher.go +++ b/pkg/cloudcommon/db/db_dispatcher.go @@ -741,7 +741,7 @@ func (dispatcher *DBModelDispatcher) Create(ctx context.Context, query jsonutils return nil, httperrors.NewGeneralError(err) } OpsLog.LogEvent(model, ACT_CREATE, model.GetShortDesc(), userCred) - logclient.AddActionLog(userCred, logclient.ACT_CREATE, "", model, "") + logclient.AddActionLog(model, logclient.ACT_CREATE, "", userCred) dispatcher.modelManager.OnCreateComplete(ctx, []IModel{model}, userCred, query, data) return getItemDetails(dispatcher.modelManager, model, ctx, userCred, query) } @@ -960,13 +960,13 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre if err != nil { log.Errorf("validate update condition error: %s", err) - logclient.AddActionLog(userCred, logclient.ACT_UPDATE, "", item, err.Error()) + logclient.AddActionLog(item, logclient.ACT_UPDATE, err.Error(), userCred) return nil, httperrors.NewGeneralError(err) } dataDict, ok := data.(*jsonutils.JSONDict) if !ok { - logclient.AddActionLog(userCred, logclient.ACT_UPDATE, "", item, "Invalid data JSONObject") + logclient.AddActionLog(item, logclient.ACT_UPDATE, "Invalid data JSONObject", userCred) return nil, httperrors.NewInternalServerError("Invalid data JSONObject") } @@ -974,7 +974,7 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre if len(name) > 0 { err = alterNameValidator(item, name) if err != nil { - logclient.AddActionLog(userCred, logclient.ACT_UPDATE, "", item, err.Error()) + logclient.AddActionLog(item, logclient.ACT_UPDATE, err.Error(), userCred) return nil, err } } @@ -983,7 +983,7 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre if err != nil { errMsg := fmt.Sprintf("validate update data error: %s", err) log.Errorf(errMsg) - logclient.AddActionLog(userCred, logclient.ACT_UPDATE, "", item, errMsg) + logclient.AddActionLog(item, logclient.ACT_UPDATE, errMsg, userCred) return nil, httperrors.NewGeneralError(err) } item.PreUpdate(ctx, userCred, query, dataDict) @@ -993,7 +993,7 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre err = filterData.Unmarshal(item) if err != nil { errMsg := fmt.Sprintf("unmarshal fail: %s", err) - logclient.AddActionLog(userCred, logclient.ACT_UPDATE, "", item, errMsg) + logclient.AddActionLog(item, logclient.ACT_UPDATE, errMsg, userCred) log.Errorf(errMsg) return httperrors.NewGeneralError(err) } @@ -1008,10 +1008,10 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre diffStr := sqlchemy.UpdateDiffString(diff) if len(diffStr) > 0 { OpsLog.LogEvent(item, ACT_UPDATE, diffStr, userCred) - logclient.AddActionLog(userCred, logclient.ACT_UPDATE, "", item, diffStr) + logclient.AddActionLog(item, logclient.ACT_UPDATE, diffStr, userCred) } } - logclient.AddActionLog(userCred, logclient.ACT_UPDATE, dataDict.String(), item, "") + logclient.AddActionLog(item, logclient.ACT_UPDATE, "", userCred) return getItemDetails(manager, item, ctx, userCred, query) } @@ -1040,11 +1040,11 @@ func DeleteModel(ctx context.Context, userCred mcclient.TokenCredential, item IM if err != nil { msg := fmt.Sprintf("save update error %s", err) log.Errorf(msg) - logclient.AddActionLog(userCred, logclient.ACT_DELETE, "", item, msg) + logclient.AddActionLog(item, logclient.ACT_DELETE, msg, userCred) return httperrors.NewGeneralError(err) } OpsLog.LogEvent(item, ACT_DELETE, item.GetShortDesc(), userCred) - logclient.AddActionLog(userCred, logclient.ACT_DELETE, "", item, "") + logclient.AddActionLog(item, logclient.ACT_DELETE, "", userCred) return nil } diff --git a/pkg/cloudcommon/db/statusstandalone.go b/pkg/cloudcommon/db/statusstandalone.go index 588bd88999..7c683e36f7 100644 --- a/pkg/cloudcommon/db/statusstandalone.go +++ b/pkg/cloudcommon/db/statusstandalone.go @@ -43,7 +43,7 @@ func (model *SStatusStandaloneResourceBase) SetStatus(userCred mcclient.TokenCre } OpsLog.LogEvent(model, ACT_UPDATE_STATUS, notes, userCred) if strings.Contains(notes, "fail") { - logclient.AddActionLog(userCred, logclient.ACT_VM_SYNC_STATUS, "", model, notes) + logclient.AddActionLog(model, logclient.ACT_VM_SYNC_STATUS, notes, userCred) } } return nil diff --git a/pkg/compute/tasks/guest_create_task.go b/pkg/compute/tasks/guest_create_task.go index 9f104a12ef..2f1bc713e0 100644 --- a/pkg/compute/tasks/guest_create_task.go +++ b/pkg/compute/tasks/guest_create_task.go @@ -50,7 +50,7 @@ func (self *GuestCreateTask) OnDiskPreparedFailed(ctx context.Context, obj db.IS guest := obj.(*models.SGuest) guest.SetStatus(self.UserCred, models.VM_DISK_FAILED, "allocation failed") db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, data, self.UserCred) - logclient.AddActionLog(self.UserCred, logclient.ACT_ALLOCATE, "", guest, data.String()) + logclient.AddActionLog(guest, logclient.ACT_ALLOCATE, data, self.UserCred) notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_DISK_FAILED, data.String()) } @@ -78,7 +78,7 @@ func (self *GuestCreateTask) OnCdromPreparedFailed(ctx context.Context, obj db.I guest := obj.(*models.SGuest) guest.SetStatus(self.UserCred, models.VM_DISK_FAILED, "") db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, data, self.UserCred) - logclient.AddActionLog(self.UserCred, logclient.ACT_ALLOCATE, "", guest, data.String()) + logclient.AddActionLog(guest, logclient.ACT_ALLOCATE, data, self.UserCred) notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_DISK_FAILED, fmt.Sprintf("cdrom_failed %s", data)) } @@ -105,7 +105,7 @@ func (self *GuestCreateTask) OnDeployGuestDescCompleteFailed(ctx context.Context guest := obj.(*models.SGuest) guest.SetStatus(self.UserCred, models.VM_DEPLOY_FAILED, "deploy_failed") db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, data, self.UserCred) - logclient.AddActionLog(self.UserCred, logclient.ACT_ALLOCATE, "", guest, data.String()) + logclient.AddActionLog(guest, logclient.ACT_ALLOCATE, data, self.UserCred) notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_DEPLOY_FAILED, data.String()) } diff --git a/pkg/compute/tasks/guest_delete_task.go b/pkg/compute/tasks/guest_delete_task.go index 1e502edce2..e663bf990d 100644 --- a/pkg/compute/tasks/guest_delete_task.go +++ b/pkg/compute/tasks/guest_delete_task.go @@ -89,7 +89,7 @@ func (self *GuestDeleteTask) OnGuestDeleteCompleteFailed(ctx context.Context, ob guest := obj.(*models.SGuest) guest.SetStatus(self.UserCred, models.VM_DELETE_FAIL, err.String()) db.OpsLog.LogEvent(guest, db.ACT_DELOCATE_FAIL, err, self.UserCred) - logclient.AddActionLog(self.UserCred, logclient.ACT_DELETE, "", guest, err.String()) + logclient.AddActionLog(guest, logclient.ACT_DELETE, err, self.UserCred) } func (self *GuestDeleteTask) OnGuestDeleteComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { @@ -105,7 +105,7 @@ func (self *GuestDeleteTask) DeleteGuest(ctx context.Context, guest *models.SGue guest.RealDelete(ctx, self.UserCred) guest.RemoveAllMetadata(ctx, self.UserCred) db.OpsLog.LogEvent(guest, db.ACT_DELOCATE, nil, self.UserCred) - logclient.AddActionLog(self.UserCred, logclient.ACT_DELETE, "", guest, "") + logclient.AddActionLog(guest, logclient.ACT_DELETE, "", self.UserCred) if !guest.IsSystem && !guest.PendingDeleted { self.NotifyServerDeleted(ctx, guest) } diff --git a/pkg/compute/tasks/guest_rebuild_root_task.go b/pkg/compute/tasks/guest_rebuild_root_task.go index 1bd7c81249..8f61dcaf4f 100644 --- a/pkg/compute/tasks/guest_rebuild_root_task.go +++ b/pkg/compute/tasks/guest_rebuild_root_task.go @@ -49,7 +49,7 @@ func (self *GuestRebuildRootTask) StartRebuildRootDisk(ctx context.Context, gues }) if err != nil { self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, err, self.UserCred) return } else { db.OpsLog.LogEvent(gds.Root, db.ACT_UPDATE_STATUS, @@ -66,19 +66,19 @@ func (self *GuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Context, imginfo, err := models.CachedimageManager.GetImageById(ctx, self.UserCred, imgId, false) if err != nil { self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, err, self.UserCred) return } osprof, err := osprofile.GetOSProfileFromImageProperties(imginfo.Properties, guest.Hypervisor) if err != nil { self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, err, self.UserCred) return } err = guest.SetMetadata(ctx, "__os_profile__", osprof, self.UserCred) if err != nil { self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, err, self.UserCred) return } if guest.OsType != osprof.OSType { @@ -88,7 +88,7 @@ func (self *GuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Context, }) if err != nil { self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(self.UserCred, logclient.ACT_VM_REBUILD, "", guest, err.Error()) + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, err, self.UserCred) return } } @@ -99,9 +99,9 @@ func (self *GuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Context, } func (self *GuestRebuildRootTask) OnRebuildRootDiskCompleteFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { - db.OpsLog.LogEvent(guest, db.ACT_REBUILD_ROOT_FAIL, data.String(), self.UserCred) + db.OpsLog.LogEvent(guest, db.ACT_REBUILD_ROOT_FAIL, data, self.UserCred) guest.SetStatus(self.UserCred, models.VM_REBUILD_ROOT_FAIL, "") - logclient.AddActionLog(self.UserCred, logclient.ACT_VM_REBUILD, "", guest, data.String()) + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, data, self.UserCred) } func (self *GuestRebuildRootTask) OnSyncStatusComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { @@ -111,7 +111,7 @@ func (self *GuestRebuildRootTask) OnSyncStatusComplete(ctx context.Context, gues } else { self.SetStageComplete(ctx, nil) } - logclient.AddActionLog(self.UserCred, logclient.ACT_VM_REBUILD, "", guest, "") + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, "", self.UserCred) } func (self *GuestRebuildRootTask) OnGuestStartComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { @@ -143,7 +143,7 @@ func (self *KVMGuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Conte func (self *KVMGuestRebuildRootTask) OnRebuildRootDiskCompleteFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { self.SetStageFailed(ctx, data.String()) - logclient.AddActionLog(self.UserCred, logclient.ACT_VM_REBUILD, "", guest, data.String()) + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, data, self.UserCred) } func (self *KVMGuestRebuildRootTask) OnGuestDeployComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { diff --git a/pkg/compute/tasks/guest_start_task.go b/pkg/compute/tasks/guest_start_task.go index d5af7cadb3..71147afdac 100644 --- a/pkg/compute/tasks/guest_start_task.go +++ b/pkg/compute/tasks/guest_start_task.go @@ -59,7 +59,7 @@ func (self *GuestStartTask) OnStartComplete(ctx context.Context, obj db.IStandal db.OpsLog.LogEvent(guest, db.ACT_START, guest.GetShortDesc(), self.UserCred) self.SetStage("on_guest_syncstatus_after_start", nil) guest.StartSyncstatus(ctx, self.UserCred, self.GetTaskId()) - logclient.AddActionLog(self.UserCred, logclient.ACT_VM_START, "", guest, "") + logclient.AddActionLog(guest, logclient.ACT_VM_START, "", self.UserCred) // self.taskComplete(ctx, guest) } @@ -76,7 +76,7 @@ func (self *GuestStartTask) OnStartCompleteFailed(ctx context.Context, obj db.IS func (self *GuestStartTask) onStartGuestFailed(ctx context.Context, guest *models.SGuest, err error) { self.SetStageFailed(ctx, err.Error()) self.OnStartCompleteFailed(ctx, guest, jsonutils.NewString(err.Error())) - logclient.AddActionLog(self.UserCred, logclient.ACT_VM_START, "", guest, err.Error()) + logclient.AddActionLog(guest, logclient.ACT_VM_START, err, self.UserCred) } func (self *GuestStartTask) taskComplete(ctx context.Context, guest *models.SGuest) { diff --git a/pkg/compute/tasks/guest_stop_task.go b/pkg/compute/tasks/guest_stop_task.go index 303c48b2e0..f50838d64c 100644 --- a/pkg/compute/tasks/guest_stop_task.go +++ b/pkg/compute/tasks/guest_stop_task.go @@ -58,12 +58,12 @@ func (self *GuestStopTask) OnGuestStopTaskComplete(ctx context.Context, obj db.I if guest.Status == models.VM_READY && guest.DisableDelete.IsFalse() && guest.ShutdownBehavior == models.SHUTDOWN_TERMINATE { guest.StartAutoDeleteGuestTask(ctx, self.UserCred, "") } - logclient.AddActionLog(self.UserCred, logclient.ACT_VM_STOP, "", guest, "") + logclient.AddActionLog(guest, logclient.ACT_VM_STOP, "", self.UserCred) } func (self *GuestStopTask) OnStopGuestFail(ctx context.Context, guest *models.SGuest, err error) { guest.SetStatus(self.UserCred, models.VM_STOP_FAILED, err.Error()) db.OpsLog.LogEvent(guest, db.ACT_STOP_FAIL, err.Error(), self.UserCred) self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(self.UserCred, logclient.ACT_VM_STOP, "", guest, err.Error()) + logclient.AddActionLog(guest, logclient.ACT_VM_STOP, err, self.UserCred) } diff --git a/pkg/compute/tasks/guest_syncstatus_task.go b/pkg/compute/tasks/guest_syncstatus_task.go index c315525baf..78dfd85a51 100644 --- a/pkg/compute/tasks/guest_syncstatus_task.go +++ b/pkg/compute/tasks/guest_syncstatus_task.go @@ -2,7 +2,6 @@ package tasks import ( "context" - "fmt" "yunion.io/x/jsonutils" "yunion.io/x/log" @@ -55,14 +54,11 @@ func (self *GuestSyncstatusTask) OnGetStatusSucc(ctx context.Context, guest *mod statusData.Add(jsonutils.NewString(statusStr), "status") guest.PerformStatus(ctx, self.UserCred, nil, statusData) self.SetStageComplete(ctx, nil) - fmt.Println(" \n*\n*\n*\n*\n*\n*\n*\n*\n*\n*\n*\\n*n* * * * * * * * * * * * * ") - fmt.Println("* * * * * * * * * * * * * server obj:", guest) - fmt.Println(" \n*\n*\n*\n*\n*\n*\n*\n*\n*\n*\n*\\n*n* * * * * * * * * * * * * ") - logclient.AddActionLog(self.UserCred, logclient.ACT_VM_SYNC_STATUS, "", guest, "") + logclient.AddActionLog(guest, logclient.ACT_VM_SYNC_STATUS, "", self.UserCred) } func (self *GuestSyncstatusTask) OnGetStatusFail(ctx context.Context, guest *models.SGuest, err error) { guest.SetStatus(self.UserCred, models.VM_UNKNOWN, err.Error()) self.SetStageComplete(ctx, nil) - logclient.AddActionLog(self.UserCred, logclient.ACT_VM_SYNC_STATUS, "", guest, err.Error()) + logclient.AddActionLog(guest, logclient.ACT_VM_SYNC_STATUS, err, self.UserCred) } diff --git a/pkg/util/logclient/logclient.go b/pkg/util/logclient/logclient.go index 658bc2887f..aaf551b831 100644 --- a/pkg/util/logclient/logclient.go +++ b/pkg/util/logclient/logclient.go @@ -7,6 +7,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/pkg/util/stringutils" ) const ( @@ -53,34 +54,35 @@ type IObject interface { Keyword() string } -func AddActionLog(userCred mcclient.TokenCredential, action, notes string, obj IObject, e string) { +func AddActionLog(model IObject, action string, iErr interface{}, userCred mcclient.TokenCredential) { + // (model IModel, action string, notes interface{}, userCred mcclient.TokenCredential + //func AddActionLog(userCred mcclient.TokenCredential, action, notes string, obj IObject, e string) { // originalk token := userCred + notes := stringutils.Interface2String(iErr) + + s := auth.GetSession(userCred, "", "") + logentry := jsonutils.NewDict() - logentry.Add(jsonutils.NewString(obj.GetName()), "obj_name") - logentry.Add(jsonutils.NewString(obj.Keyword()), "obj_type") - logentry.Add(jsonutils.NewString(obj.GetId()), "obj_id") + logentry.Add(jsonutils.NewString(model.GetName()), "obj_name") + logentry.Add(jsonutils.NewString(model.Keyword()), "obj_type") + logentry.Add(jsonutils.NewString(model.GetId()), "obj_id") logentry.Add(jsonutils.NewString(action), "action") logentry.Add(jsonutils.NewString(token.GetUserId()), "user_id") logentry.Add(jsonutils.NewString(token.GetUserName()), "user") logentry.Add(jsonutils.NewString(token.GetTenantId()), "tenant_id") logentry.Add(jsonutils.NewString(token.GetTenantName()), "tenant") - // TODO delete following line later - notes = "[a2]" + notes - - s := auth.GetSession(userCred, "", "") - - if len(e) > 0 { + if len(notes) > 0 { // 失败日志 logentry.Add(jsonutils.JSONFalse, "success") - notes = fmt.Sprintf("%s%s", notes, e) - logentry.Add(jsonutils.NewString(notes), "notes") } else { // 成功日志 logentry.Add(jsonutils.JSONTrue, "success") - logentry.Add(jsonutils.NewString(notes), "notes") } + // TODO delete tag when done. + notes = fmt.Sprintf("[a2]%s", notes) + logentry.Add(jsonutils.NewString(notes), "notes") _, err := modules.Actions.Create(s, logentry) if err != nil { From 3b8562a22c4f5caf06608115602c1daabff8c4f9 Mon Sep 17 00:00:00 2001 From: Zhang Dongliang Date: Wed, 29 Aug 2018 15:43:59 +0800 Subject: [PATCH 07/32] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/cloudcommon/db/opslog.go | 2 + pkg/compute/tasks/guest_deploy_task.go | 2 + pkg/util/logclient/logclient.go | 60 +++++++++++++------------- 3 files changed, 34 insertions(+), 30 deletions(-) diff --git a/pkg/cloudcommon/db/opslog.go b/pkg/cloudcommon/db/opslog.go index 11ad4edf6e..d1fe6d5da9 100644 --- a/pkg/cloudcommon/db/opslog.go +++ b/pkg/cloudcommon/db/opslog.go @@ -10,6 +10,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/logclient" "yunion.io/x/pkg/util/stringutils" "yunion.io/x/sqlchemy" ) @@ -302,6 +303,7 @@ func (manager *SOpsLogManager) SyncOwner(m IModel, former *STenant, userCred mcc notes.Add(jsonutils.NewString(former.GetId()), "former_project_id") notes.Add(jsonutils.NewString(former.GetName()), "form_project") manager.LogEvent(m, ACT_CHANGE_OWNER, notes, userCred) + logclient.AddActionLog(m, logclient.ACT_CHANGE_OWNER, nil, userCred) } func (manager *SOpsLogManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { diff --git a/pkg/compute/tasks/guest_deploy_task.go b/pkg/compute/tasks/guest_deploy_task.go index 47fd39b7c7..5f5dab563d 100644 --- a/pkg/compute/tasks/guest_deploy_task.go +++ b/pkg/compute/tasks/guest_deploy_task.go @@ -9,6 +9,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" ) type GuestDeployTask struct { @@ -56,6 +57,7 @@ func (self *GuestDeployTask) StartDeployGuestOnHost(ctx context.Context, guest * } else { self.OnDeployGuestSucc(guest) } + logclient.AddActionLog(guest, logclient.ACT_VM_DEPLOY, err, self.UserCred) } func (self *GuestDeployTask) OnDeployGuestSucc(guest *models.SGuest) { diff --git a/pkg/util/logclient/logclient.go b/pkg/util/logclient/logclient.go index aaf551b831..391408305a 100644 --- a/pkg/util/logclient/logclient.go +++ b/pkg/util/logclient/logclient.go @@ -11,41 +11,43 @@ import ( ) const ( - ACT_VM_RESET_PSWD = "重置密码" - ACT_VM_REBUILD = "重装系统" - ACT_VM_START = "开机" - ACT_VM_STOP = "关机" - ACT_VM_PURGE = "清除" - ACT_VM_CHANGE_FLAVOR = "调整配置" - ACT_VM_SYNC_CONF = "同步配置" - ACT_GUEST_ATTACH_ISOLATED_DEVICE = "挂载透传设备" - ACT_GUEST_DETACH_ISOLATED_DEVICE = "卸载透传设备" - ACT_VM_SYNC_STATUS = "同步状态" + ACT_ADDTAG = "添加标签" + ACT_ALLOCATE = "分配" + ACT_BM_CONVERT_HYPER = "转换为宿主机" + ACT_BM_MAINTENANCE = "进入离线状态" + ACT_BM_UNCONVERT_HYPER = "转换为受管物理机" + ACT_BM_UNMAINTENANCE = "退出离线状态" + ACT_CANCEL_DELETE = "恢复" + ACT_CHANGE_OWNER = "更改项目" ACT_CREATE = "创建" ACT_DELETE = "删除" - ACT_UPDATE = "更新" - ACT_RESERVE_IP = "预留IP" - ACT_RELEASE_IP = "释放IP" - ACT_CANCEL_DELETE = "恢复" - ACT_UNCACHED_IMAGE = "清除缓存" - ACT_ENABLE = "启用" ACT_DISABLE = "禁用" - ACT_ONLINE = "上线" - ACT_OFFLINE = "下线" - ACT_PUBLIC = "设为共享" - ACT_PRIVATE = "设为私有" + ACT_ENABLE = "启用" + ACT_GUEST_ATTACH_ISOLATED_DEVICE = "挂载透传设备" + ACT_GUEST_DETACH_ISOLATED_DEVICE = "卸载透传设备" ACT_MERGE = "合并" - ACT_SPLIT = "分割" - ACT_ALLOCATE = "分配" - ACT_BM_MAINTENANCE = "进入离线状态" - ACT_BM_UNMAINTENANCE = "退出离线状态" - ACT_BM_CONVERT_HYPER = "转换为宿主机" - ACT_BM_UNCONVERT_HYPER = "转换为受管物理机" - ACT_ADDTAG = "添加标签" - ACT_RMTAG = "删除标签" + ACT_OFFLINE = "下线" + ACT_ONLINE = "上线" + ACT_PRIVATE = "设为私有" + ACT_PUBLIC = "设为共享" + ACT_RELEASE_IP = "释放IP" + ACT_RESERVE_IP = "预留IP" ACT_RESIZE = "扩容" + ACT_RMTAG = "删除标签" + ACT_SPLIT = "分割" + ACT_UNCACHED_IMAGE = "清除缓存" + ACT_UPDATE = "更新" ACT_VM_ATTACH_DISK = "挂载磁盘" + ACT_VM_CHANGE_FLAVOR = "调整配置" + ACT_VM_DEPLOY = "启用" ACT_VM_DETACH_DISK = "卸载磁盘" + ACT_VM_PURGE = "清除" + ACT_VM_REBUILD = "重装系统" + ACT_VM_RESET_PSWD = "重置密码" + ACT_VM_START = "开机" + ACT_VM_STOP = "关机" + ACT_VM_SYNC_CONF = "同步配置" + ACT_VM_SYNC_STATUS = "同步状态" ) type IObject interface { @@ -55,8 +57,6 @@ type IObject interface { } func AddActionLog(model IObject, action string, iErr interface{}, userCred mcclient.TokenCredential) { - // (model IModel, action string, notes interface{}, userCred mcclient.TokenCredential - //func AddActionLog(userCred mcclient.TokenCredential, action, notes string, obj IObject, e string) { // originalk token := userCred notes := stringutils.Interface2String(iErr) From e2d405436754ad070ea4112f79abec87420d5d20 Mon Sep 17 00:00:00 2001 From: wanyaoqi Date: Wed, 29 Aug 2018 17:55:13 +0800 Subject: [PATCH 08/32] extend joint filter --- Gopkg.lock | 8 ++--- cmd/climc/shell/shell.go | 2 +- pkg/cloudcommon/db/db_dispatcher.go | 4 +-- .../x/pkg/util/filterclause/filterclause.go | 11 +++--- vendor/yunion.io/x/structarg/structarg.go | 34 ++++++++++++++++--- 5 files changed, 44 insertions(+), 15 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index b67bf4ca82..29c5b0c497 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1061,7 +1061,7 @@ [[projects]] branch = "master" - digest = "1:8a2992edca980cb03eb9dc89f62c03c8ab6fe0c5ca4fc1da71eb736aae635f65" + digest = "1:f640bec6e2c558f83117e88f16753d54685c95b8fb83d5660ed6c43e04adde72" name = "yunion.io/x/pkg" packages = [ "gotypes", @@ -1096,7 +1096,7 @@ "utils", ] pruneopts = "UT" - revision = "1e97a2736e5b90c0274b7d391b8d97aa9107725c" + revision = "3bcf68100d212545f2f16b91bb3962bc8b228da7" [[projects]] branch = "master" @@ -1108,11 +1108,11 @@ [[projects]] branch = "master" - digest = "1:71e1b62648868a9083f9e4693145a0154a600591ca548aaf64cae32a10e956e5" + digest = "1:64b263a23f3c35521bb811b2aa9f93f8c7ce1ff06487db12d6aa3fc25705ad2e" name = "yunion.io/x/structarg" packages = ["."] pruneopts = "UT" - revision = "4a5eb8e2cdfbf7f6511561a3c710c116b171f405" + revision = "ec02b19c0bccfc991fc9e850f5a2a543ae43254b" [solve-meta] analyzer-name = "dep" diff --git a/cmd/climc/shell/shell.go b/cmd/climc/shell/shell.go index 03246aa46c..4b0ebbad22 100644 --- a/cmd/climc/shell/shell.go +++ b/cmd/climc/shell/shell.go @@ -28,7 +28,7 @@ type BaseListOptions struct { Search string `help:"Filter results by a simple keyword search"` Meta bool `help:"Piggyback metadata information"` Filter []string `help:"Filters"` - JointFilter []string `help:"Filters with joint table col; joint_tbl(related_key).filter_col.filter_cond(filters)"` + JointFilter []string `help:"Filters with joint table col; joint_tbl.related_key(origin_key).filter_col.filter_cond(filters)"` FilterAny bool `help:"If true, match if any of the filters matches; otherwise, match if all of the filters match"` Admin bool `help:"Is an admin call?"` Tenant string `help:"Tenant ID or Name"` diff --git a/pkg/cloudcommon/db/db_dispatcher.go b/pkg/cloudcommon/db/db_dispatcher.go index 6c8c336a87..5fcbd2dbcd 100644 --- a/pkg/cloudcommon/db/db_dispatcher.go +++ b/pkg/cloudcommon/db/db_dispatcher.go @@ -264,9 +264,9 @@ func applyListItemsGeneralJointFilters(manager IModelManager, q *sqlchemy.SQuery if cond != nil { sq = sq.Filter(cond) if filterAny { - q = q.Filter(sqlchemy.OR(sqlchemy.In(q.Field("id"), sq))) + q = q.Filter(sqlchemy.OR(sqlchemy.In(q.Field(jfc.OriginKey), sq))) } else { - q = q.Filter(sqlchemy.AND(sqlchemy.In(q.Field("id"), sq))) + q = q.Filter(sqlchemy.AND(sqlchemy.In(q.Field(jfc.OriginKey), sq))) } } } diff --git a/vendor/yunion.io/x/pkg/util/filterclause/filterclause.go b/vendor/yunion.io/x/pkg/util/filterclause/filterclause.go index a0928f6527..1bddde5c61 100644 --- a/vendor/yunion.io/x/pkg/util/filterclause/filterclause.go +++ b/vendor/yunion.io/x/pkg/util/filterclause/filterclause.go @@ -16,10 +16,12 @@ type SFilterClause struct { params []string } +// "guestnetworks.guest_id(id).ip_addr.equals(10.168.222.232)" type SJointFilterClause struct { SFilterClause JointModel string RelatedKey string + OriginKey string } func (jfc *SJointFilterClause) GetJointFilter(q *sqlchemy.SQuery) sqlchemy.ICondition { @@ -83,7 +85,7 @@ var ( func init() { filterClausePattern = regexp.MustCompile(`^(\w+)\.(\w+)\((.*)\)`) - jointFilterClausePattern = regexp.MustCompile(`^(\w+)\((\w+)\).(\w+)\.(\w+)\((.*)\)`) + jointFilterClausePattern = regexp.MustCompile(`^(\w+)\.(\w+)\((\w+)\).(\w+)\.(\w+)\((.*)\)`) } func ParseFilterClause(filter string) *SFilterClause { @@ -101,15 +103,16 @@ func ParseJointFilterClause(jointFilter string) *SJointFilterClause { if matches == nil { return nil } - params := utils.FindWords([]byte(matches[5]), 0) + params := utils.FindWords([]byte(matches[6]), 0) jfc := SJointFilterClause{ SFilterClause: SFilterClause{ - field: matches[3], - funcName: matches[4], + field: matches[4], + funcName: matches[5], params: params, }, JointModel: matches[1], RelatedKey: matches[2], + OriginKey: matches[3], } return &jfc } diff --git a/vendor/yunion.io/x/structarg/structarg.go b/vendor/yunion.io/x/structarg/structarg.go index 7f7f6c6414..7eb514b3f0 100644 --- a/vendor/yunion.io/x/structarg/structarg.go +++ b/vendor/yunion.io/x/structarg/structarg.go @@ -423,8 +423,32 @@ func (this *ArgumentParser) Options() interface{} { return this.target } +func (this *SingleArgument) valueIsBool() bool { + rv := this.value + if rv.Kind() == reflect.Bool { + return true + } + + if rv.Kind() == reflect.Ptr && rv.Type().Elem().Kind() == reflect.Bool { + return true + } + return false +} + +func (this *SingleArgument) defaultBoolValue() bool { + rv := this.defValue + if rv.Kind() == reflect.Bool { + return rv.Bool() + } + + if rv.Kind() == reflect.Ptr && rv.Type().Elem().Kind() == reflect.Bool { + return rv.Elem().Bool() + } + panic("expecting bool or *bool type: got " + rv.Type().String()) +} + func (this *SingleArgument) NeedData() bool { - if this.value.Kind() == reflect.Bool { + if this.valueIsBool() { return false } else { return true @@ -539,12 +563,14 @@ func (this *SingleArgument) Reset() { } func (this *SingleArgument) DoAction() error { - if this.value.Type() == gotypes.BoolType { + if this.valueIsBool() { + var v bool if this.useDefault { - this.value.SetBool(!this.defValue.Bool()) + v = !this.defaultBoolValue() } else { - this.value.SetBool(true) + v = true } + gotypes.SetValue(this.value, fmt.Sprintf("%t", v)) this.isSet = true } return nil From bfdfbe283335836f91488896c7708306999f1994 Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Tue, 28 Aug 2018 12:36:09 +0000 Subject: [PATCH 09/32] dep: -update pkg, structarg, sqlchemy --- Gopkg.lock | 12 +++--- vendor/yunion.io/x/pkg/gotypes/gotypes.go | 20 +++++++++- .../x/pkg/util/filterclause/filterclause.go | 39 ++++++++++++++++++- .../x/pkg/util/sysutils/storagetypes.go | 8 +++- vendor/yunion.io/x/sqlchemy/update.go | 10 ++++- vendor/yunion.io/x/structarg/structarg.go | 34 ++++++++++++++-- 6 files changed, 108 insertions(+), 15 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 5e1701f1f6..465f2beb19 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1053,7 +1053,7 @@ [[projects]] branch = "master" - digest = "1:47670c70d0326f624de21c8f29d0f73850062f0752f27e146308db62fbb540d3" + digest = "1:f640bec6e2c558f83117e88f16753d54685c95b8fb83d5660ed6c43e04adde72" name = "yunion.io/x/pkg" packages = [ "gotypes", @@ -1088,23 +1088,23 @@ "utils", ] pruneopts = "UT" - revision = "6c349ecbdb90d5f6ecc9b86596428176c1937b32" + revision = "3bcf68100d212545f2f16b91bb3962bc8b228da7" [[projects]] branch = "master" - digest = "1:e23019db2cda58480528738c86bc7abbff09d10488c2a51dd5d500f8686815f0" + digest = "1:a8a402e8c9d4a7bf8efbdb81ae2da8fb72ebbe07bbfc1168a124905ace456ed0" name = "yunion.io/x/sqlchemy" packages = ["."] pruneopts = "UT" - revision = "19a3c90524d3638f8e3580231396dda46088aebc" + revision = "1e2883d085d6d449d4df7d28b61073dec11c5dbb" [[projects]] branch = "master" - digest = "1:71e1b62648868a9083f9e4693145a0154a600591ca548aaf64cae32a10e956e5" + digest = "1:64b263a23f3c35521bb811b2aa9f93f8c7ce1ff06487db12d6aa3fc25705ad2e" name = "yunion.io/x/structarg" packages = ["."] pruneopts = "UT" - revision = "4a5eb8e2cdfbf7f6511561a3c710c116b171f405" + revision = "ec02b19c0bccfc991fc9e850f5a2a543ae43254b" [solve-meta] analyzer-name = "dep" diff --git a/vendor/yunion.io/x/pkg/gotypes/gotypes.go b/vendor/yunion.io/x/pkg/gotypes/gotypes.go index e589aa7c61..615499fa4a 100644 --- a/vendor/yunion.io/x/pkg/gotypes/gotypes.go +++ b/vendor/yunion.io/x/pkg/gotypes/gotypes.go @@ -120,6 +120,15 @@ func ParseValue(val string, tp reflect.Type) (reflect.Value, error) { } case reflect.String: return reflect.ValueOf(val), nil + case reflect.Ptr: + tpElem := tp.Elem() + rv, err := ParseValue(val, tpElem) + if err != nil { + return reflect.ValueOf(val), fmt.Errorf("Cannot parse %s to %s", val, tp) + } + rvv := reflect.New(tpElem) + rvv.Elem().Set(rv) + return rvv, nil default: if tp == TimeType { tm, e := timeutils.ParseTimeStr(val) @@ -173,7 +182,16 @@ func SetValue(value reflect.Value, valStr string) error { Float32SliceType, Float64SliceType, StringSliceType: reflect.Append(value, reflect.ValueOf(valStr)) default: - return fmt.Errorf("Unsupported type: %v", value.Type()) + if value.Kind() == reflect.Ptr && value.Elem().Kind() != reflect.Slice { + newVal := reflect.New(value.Type().Elem()) + newValElem := newVal.Elem() + if err := SetValue(newValElem, valStr); err != nil { + return err + } + value.Set(newVal) + } else { + return fmt.Errorf("Unsupported type: %v", value.Type()) + } } return nil } diff --git a/vendor/yunion.io/x/pkg/util/filterclause/filterclause.go b/vendor/yunion.io/x/pkg/util/filterclause/filterclause.go index 2a3a1ccd10..1bddde5c61 100644 --- a/vendor/yunion.io/x/pkg/util/filterclause/filterclause.go +++ b/vendor/yunion.io/x/pkg/util/filterclause/filterclause.go @@ -16,6 +16,22 @@ type SFilterClause struct { params []string } +// "guestnetworks.guest_id(id).ip_addr.equals(10.168.222.232)" +type SJointFilterClause struct { + SFilterClause + JointModel string + RelatedKey string + OriginKey string +} + +func (jfc *SJointFilterClause) GetJointFilter(q *sqlchemy.SQuery) sqlchemy.ICondition { + return jfc.QueryCondition(q) +} + +func (jfc *SJointFilterClause) GetJointModelName() string { + return jfc.JointModel[:len(jfc.JointModel)-1] +} + func (fc *SFilterClause) QueryCondition(q *sqlchemy.SQuery) sqlchemy.ICondition { field := q.Field(fc.field) if field == nil { @@ -63,11 +79,13 @@ func (fc *SFilterClause) String() string { } var ( - filterClausePattern *regexp.Regexp + filterClausePattern *regexp.Regexp + jointFilterClausePattern *regexp.Regexp ) func init() { filterClausePattern = regexp.MustCompile(`^(\w+)\.(\w+)\((.*)\)`) + jointFilterClausePattern = regexp.MustCompile(`^(\w+)\.(\w+)\((\w+)\).(\w+)\.(\w+)\((.*)\)`) } func ParseFilterClause(filter string) *SFilterClause { @@ -79,3 +97,22 @@ func ParseFilterClause(filter string) *SFilterClause { fc := SFilterClause{field: matches[1], funcName: matches[2], params: params} return &fc } + +func ParseJointFilterClause(jointFilter string) *SJointFilterClause { + matches := jointFilterClausePattern.FindStringSubmatch(jointFilter) + if matches == nil { + return nil + } + params := utils.FindWords([]byte(matches[6]), 0) + jfc := SJointFilterClause{ + SFilterClause: SFilterClause{ + field: matches[4], + funcName: matches[5], + params: params, + }, + JointModel: matches[1], + RelatedKey: matches[2], + OriginKey: matches[3], + } + return &jfc +} diff --git a/vendor/yunion.io/x/pkg/util/sysutils/storagetypes.go b/vendor/yunion.io/x/pkg/util/sysutils/storagetypes.go index 476aa53bff..16baa403d2 100644 --- a/vendor/yunion.io/x/pkg/util/sysutils/storagetypes.go +++ b/vendor/yunion.io/x/pkg/util/sysutils/storagetypes.go @@ -9,12 +9,18 @@ const ( STORAGE_NAS = "nas" STORAGE_VSAN = "vsan" + STORAGE_CLOUD = "cloud" STORAGE_CLOUD_SSD = "cloud_ssd" STORAGE_CLOUD_EFFICIENCY = "cloud_efficiency" + + STORAGE_STANDARD = "standard" //Azure hdd storage type + STORAGE_PREMIUM = "premium" //Azure ssd storage type ) var STORAGE_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_SHEEPDOG, - STORAGE_RBD, STORAGE_DOCKER, STORAGE_NAS, STORAGE_VSAN, STORAGE_CLOUD_SSD, STORAGE_CLOUD_EFFICIENCY} + STORAGE_RBD, STORAGE_DOCKER, STORAGE_NAS, STORAGE_VSAN, + STORAGE_CLOUD, STORAGE_CLOUD_SSD, STORAGE_CLOUD_EFFICIENCY, + STORAGE_STANDARD, STORAGE_PREMIUM} var LOCAL_STORAGE_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL} diff --git a/vendor/yunion.io/x/sqlchemy/update.go b/vendor/yunion.io/x/sqlchemy/update.go index e40e0f6eff..f88e1a6bde 100644 --- a/vendor/yunion.io/x/sqlchemy/update.go +++ b/vendor/yunion.io/x/sqlchemy/update.go @@ -28,7 +28,10 @@ func (ts *STableSpec) prepareUpdate(dt interface{}) (*SUpdateSession, error) { zeroKeyIndex := make([]string, 0) for _, c := range ts.columns { k := c.Name() - ov := fields[k] + ov, ok := fields[k] + if !ok { + continue + } if c.IsPrimary() && c.IsZero(ov) { zeroPrimary = append(zeroPrimary, k) } else if c.IsKeyIndex() && c.IsZero(ov) { @@ -80,7 +83,10 @@ func (us *SUpdateSession) saveUpdate(dt interface{}) (map[string]SUpdateDiff, er setters := make(map[string]SUpdateDiff) for _, c := range us.tableSpec.columns { k := c.Name() - of := ofields[k] + of, ok := ofields[k] + if !ok { + continue + } nf := fields[k] if c.IsPrimary() && !c.IsZero(of) { // skip update primary key primaries[k] = of diff --git a/vendor/yunion.io/x/structarg/structarg.go b/vendor/yunion.io/x/structarg/structarg.go index 7f7f6c6414..7eb514b3f0 100644 --- a/vendor/yunion.io/x/structarg/structarg.go +++ b/vendor/yunion.io/x/structarg/structarg.go @@ -423,8 +423,32 @@ func (this *ArgumentParser) Options() interface{} { return this.target } +func (this *SingleArgument) valueIsBool() bool { + rv := this.value + if rv.Kind() == reflect.Bool { + return true + } + + if rv.Kind() == reflect.Ptr && rv.Type().Elem().Kind() == reflect.Bool { + return true + } + return false +} + +func (this *SingleArgument) defaultBoolValue() bool { + rv := this.defValue + if rv.Kind() == reflect.Bool { + return rv.Bool() + } + + if rv.Kind() == reflect.Ptr && rv.Type().Elem().Kind() == reflect.Bool { + return rv.Elem().Bool() + } + panic("expecting bool or *bool type: got " + rv.Type().String()) +} + func (this *SingleArgument) NeedData() bool { - if this.value.Kind() == reflect.Bool { + if this.valueIsBool() { return false } else { return true @@ -539,12 +563,14 @@ func (this *SingleArgument) Reset() { } func (this *SingleArgument) DoAction() error { - if this.value.Type() == gotypes.BoolType { + if this.valueIsBool() { + var v bool if this.useDefault { - this.value.SetBool(!this.defValue.Bool()) + v = !this.defaultBoolValue() } else { - this.value.SetBool(true) + v = true } + gotypes.SetValue(this.value, fmt.Sprintf("%t", v)) this.isSet = true } return nil From 5f6fa5be965a8348bb2c34ae5ba898f2b2014c31 Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Tue, 28 Aug 2018 12:36:32 +0000 Subject: [PATCH 10/32] mcclient: options: initial version --- pkg/mcclient/options/base.go | 179 ++++++++++++++++++++++++++ pkg/mcclient/options/base_test.go | 203 ++++++++++++++++++++++++++++++ 2 files changed, 382 insertions(+) create mode 100644 pkg/mcclient/options/base.go create mode 100644 pkg/mcclient/options/base_test.go diff --git a/pkg/mcclient/options/base.go b/pkg/mcclient/options/base.go new file mode 100644 index 0000000000..35cee54cef --- /dev/null +++ b/pkg/mcclient/options/base.go @@ -0,0 +1,179 @@ +package options + +import ( + "fmt" + "reflect" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/gotypes" + "yunion.io/x/pkg/util/reflectutils" +) + +// Int returns a pointer to int type with the same value as the argument. This +// is intended to be used for literal initialization of options +func Int(v int) *int { + return &v +} + +// Bool returns a pointer to bool type with the same value as the argument. +// This is intended to be used for literal initialization of options +func Bool(v bool) *bool { + return &v +} + +// IntV returns the integer value as pointed to by the argument if it's +// non-nil, return 0 otherwise +func IntV(p *int) int { + if p != nil { + return *p + } + return 0 +} + +// BoolV returns the bool value as pointed to by the argument if it's non-nil, +// return false otherwise +func BoolV(p *bool) bool { + if p != nil { + return *p + } + return false +} + +type IParamsOptions interface { + Params() (*jsonutils.JSONDict, error) +} + +var BaseListOptionsType = reflect.TypeOf((*BaseListOptions)(nil)).Elem() + +func optionsStructRvToParams(rv reflect.Value) (*jsonutils.JSONDict, error) { + p := jsonutils.NewDict() + rvType := rv.Type() + for i := 0; i < rvType.NumField(); i++ { + ft := rvType.Field(i) + name := reflectutils.GetStructFieldName(&ft) + if name == "" { + continue + } + f := rv.Field(i) + begin: + switch f.Kind() { + case reflect.Ptr: + if f.IsNil() { + continue + } + f = f.Elem() + goto begin + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + rv64 := f.Convert(gotypes.Int64Type) + i64 := rv64.Interface().(int64) + p.Set(name, jsonutils.NewInt(i64)) + case reflect.Bool: + b := f.Interface().(bool) + p.Set(name, jsonutils.NewBool(b)) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + // NOTE uint64 converted to int64 + rv64 := f.Convert(gotypes.Uint64Type) + i64 := rv64.Interface().(uint64) + p.Set(name, jsonutils.NewInt(int64(i64))) + case reflect.Float32, reflect.Float64: + rv64 := f.Convert(gotypes.Float64Type) + f64 := rv64.Interface().(float64) + p.Set(name, jsonutils.NewFloat(f64)) + case reflect.String: + s := f.Interface().(string) + if len(s) > 0 { + p.Set(name, jsonutils.NewString(s)) + } + case reflect.Struct: + if ft.Anonymous { + continue + } + // TODO + msg := fmt.Sprintf("do not know what to do with non-anonymous struct field: %s", ft.Name) + panic(msg) + case reflect.Slice, reflect.Array: + l := f.Len() + for i := 0; i < l; i++ { + namei := fmt.Sprintf("%s.%d", name, i) + vali := jsonutils.Marshal(f.Index(i).Interface()) + p.Set(namei, vali) + } + default: + msg := fmt.Sprintf("unsupported field type %s: %s", ft.Name, ft.Type) + panic(msg) + } + } + return p, nil +} + +func optionsStructToParams(v interface{}) (*jsonutils.JSONDict, error) { + rv := reflect.ValueOf(v).Elem() + return optionsStructRvToParams(rv) +} + +// StructToParams converts the struct as pointed to by the argument to JSON +// dict params, ignoring any embedded in struct +func StructToParams(v interface{}) (*jsonutils.JSONDict, error) { + return optionsStructToParams(v) +} + +// ListStructToParams converts the struct as pointed to by the argument to JSON +// dict params, taking into account .BaseListOptions.Params() if it exists +func ListStructToParams(v interface{}) (*jsonutils.JSONDict, error) { + rv := reflect.ValueOf(v).Elem() + params, err := optionsStructRvToParams(rv) + if err != nil { + return nil, err + } + { + f := rv.FieldByName("BaseListOptions") + if f.IsValid() { + listOpts, ok := f.Addr().Interface().(*BaseListOptions) + if ok { + listParams, err := listOpts.Params() + if err != nil { + return nil, err + } + params.Update(listParams) + } + } + } + return params, nil +} + +type BaseListOptions struct { + Limit *int `default:"20" help:"Page limit"` + Offset *int `default:"0" help:"Page offset"` + OrderBy string `help:"Name of the field to be ordered by"` + Order string `help:"List order" choices:"desc|asc"` + Details *bool `help:"Show more details"` + Search string `help:"Filter results by a simple keyword search"` + Meta *bool `help:"Piggyback metadata information"` + Filter []string `help:"Filters"` + JointFilter []string `help:"Filters with joint table col; joint_tbl(related_key).filter_col.filter_cond(filters)"` + FilterAny *bool `help:"If true, match if any of the filters matches; otherwise, match if all of the filters match"` + Admin *bool `help:"Is an admin call?"` + Tenant string `help:"Tenant ID or Name"` + User string `help:"User ID or Name"` + System *bool `help:"Show system resource"` + PendingDelete *bool `help:"Show pending deleted resource"` + Field []string `help:"Show only specified fields"` + ShowEmulated *bool `help:"Show all resources including the emulated resources"` +} + +func (opts *BaseListOptions) Params() (*jsonutils.JSONDict, error) { + params, err := optionsStructToParams(opts) + if err != nil { + return nil, err + } + if len(opts.Filter) == 0 { + params.Remove("filter_any") + } + if opts.Admin == nil { + requiresSystem := len(opts.Tenant) > 0 || BoolV(opts.System) || BoolV(opts.PendingDelete) + if requiresSystem { + params.Set("admin", jsonutils.NewBool(true)) + } + } + return params, nil +} diff --git a/pkg/mcclient/options/base_test.go b/pkg/mcclient/options/base_test.go new file mode 100644 index 0000000000..9383385f62 --- /dev/null +++ b/pkg/mcclient/options/base_test.go @@ -0,0 +1,203 @@ +package options + +import ( + "reflect" + "testing" + + "yunion.io/x/jsonutils" +) + +type S struct { + In interface{} + Want string +} + +func testS(t *testing.T, c *S) { + jsonGot, err := StructToParams(c.In) + if err != nil { + t.Errorf("StructToParams failed: in: %#v: err: %s", + c.In, err) + } + jsonWant, _ := jsonutils.ParseString(c.Want) + if !reflect.DeepEqual(jsonGot, jsonWant) { + t.Errorf("json not equal, want %s, got %s", + jsonWant.String(), jsonGot.String()) + } +} + +func testSs(t *testing.T, cs []*S) { + for _, c := range cs { + testS(t, c) + } +} + +func TestOptionsStructToParams(t *testing.T) { + t.Run("int", func(t *testing.T) { + type s struct { + Int int + } + cases := []*S{ + { + In: &s{100}, + Want: "{int: 100}", + }, + { + In: &s{0}, + Want: "{int: 0}", + }, + } + testSs(t, cases) + }) + t.Run("int ptr", func(t *testing.T) { + type s struct { + IntP *int + } + cases := []*S{ + { + In: &s{}, + Want: "{}", + }, + { + In: &s{Int(100)}, + Want: "{int_p: 100}", + }, + { + In: &s{Int(0)}, + Want: "{int_p: 0}", + }, + } + testSs(t, cases) + }) + t.Run("bool", func(t *testing.T) { + type s struct { + Bool bool + } + cases := []*S{ + { + In: &s{}, + Want: "{bool: false}", + }, + { + In: &s{true}, + Want: "{bool: true}", + }, + { + In: &s{false}, + Want: "{bool: false}", + }, + } + testSs(t, cases) + }) + t.Run("bool ptr", func(t *testing.T) { + type s struct { + BoolP *bool + } + cases := []*S{ + { + In: &s{}, + Want: "{}", + }, + { + In: &s{Bool(true)}, + Want: "{bool_p: true}", + }, + { + In: &s{Bool(false)}, + Want: "{bool_p: false}", + }, + } + testSs(t, cases) + }) + t.Run("string", func(t *testing.T) { + type s struct { + String string + } + cases := []*S{ + { + In: &s{}, + Want: `{}`, + }, + { + In: &s{""}, + Want: `{}`, + }, + { + In: &s{"holy"}, + Want: `{string: "holy"}`, + }, + } + testSs(t, cases) + }) + t.Run("string slice", func(t *testing.T) { + type s struct { + StringSlice []string + } + cases := []*S{ + { + In: &s{}, + Want: `{}`, + }, + { + In: &s{[]string{}}, + Want: `{}`, + }, + { + In: &s{[]string{"holy"}}, + Want: `{"string_slice.0": "holy"}`, + }, + { + In: &s{[]string{"holy", "goblet"}}, + Want: `{"string_slice.0": "holy", "string_slice.1": "goblet"}`, + }, + } + testSs(t, cases) + }) + t.Run("json tag", func(t *testing.T) { + type s struct { + StringSlice []string `json:"string"` + } + cases := []*S{ + { + In: &s{}, + Want: `{}`, + }, + { + In: &s{[]string{}}, + Want: `{}`, + }, + { + In: &s{[]string{"holy"}}, + Want: `{"string.0": "holy"}`, + }, + { + In: &s{[]string{"holy", "goblet"}}, + Want: `{"string.0": "holy", "string.1": "goblet"}`, + }, + } + testSs(t, cases) + }) + t.Run("json tag ignore", func(t *testing.T) { + type s struct { + StringSliceIgnored []string `json:"-"` + } + cases := []*S{ + { + In: &s{}, + Want: `{}`, + }, + { + In: &s{[]string{}}, + Want: `{}`, + }, + { + In: &s{[]string{"holy"}}, + Want: `{}`, + }, + { + In: &s{[]string{"holy", "goblet"}}, + Want: `{}`, + }, + } + testSs(t, cases) + }) +} From 60c40963597eae8a1bfca52ffa253b22ee5c7a00 Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Thu, 30 Aug 2018 02:29:55 +0000 Subject: [PATCH 11/32] climc: use BaseListOptions from mcclient/options --- cmd/climc/shell/alarmlogs.go | 8 +- cmd/climc/shell/alarms.go | 13 ++- cmd/climc/shell/alarmtemplates.go | 13 ++- cmd/climc/shell/baremetalnetworks.go | 14 ++- cmd/climc/shell/baremetalstorages.go | 14 ++- cmd/climc/shell/cachedimages.go | 14 ++- cmd/climc/shell/cloudproviders.go | 13 ++- cmd/climc/shell/cloudregions.go | 13 ++- cmd/climc/shell/contactgroups.go | 14 ++- cmd/climc/shell/contacts.go | 25 ++++- cmd/climc/shell/disks.go | 13 ++- cmd/climc/shell/dnsrecords.go | 13 ++- cmd/climc/shell/hostcachedimages.go | 13 ++- cmd/climc/shell/hosts.go | 13 ++- cmd/climc/shell/hoststorages.go | 13 ++- cmd/climc/shell/hostwires.go | 13 ++- cmd/climc/shell/instances.go | 14 ++- cmd/climc/shell/isolatedevices.go | 13 ++- cmd/climc/shell/k8s/clusters.go | 18 +++- cmd/climc/shell/k8s/k8s.go | 7 -- cmd/climc/shell/k8s/nodes.go | 16 +++- cmd/climc/shell/k8s/repos.go | 13 ++- cmd/climc/shell/keypairs.go | 13 ++- cmd/climc/shell/labels.go | 13 ++- cmd/climc/shell/metrics.go | 38 ++++++-- cmd/climc/shell/monitor_types.go | 14 ++- cmd/climc/shell/monitorinputs.go | 26 ++++- cmd/climc/shell/monitortemplates.go | 25 ++++- cmd/climc/shell/networks.go | 13 ++- cmd/climc/shell/nodes.go | 13 ++- cmd/climc/shell/notification.go | 3 +- cmd/climc/shell/operations.go | 13 ++- cmd/climc/shell/processes.go | 14 ++- cmd/climc/shell/processlogs.go | 14 ++- cmd/climc/shell/project_admin.go | 14 ++- cmd/climc/shell/project_admin_candidates.go | 14 ++- cmd/climc/shell/rates.go | 13 ++- cmd/climc/shell/recipient.go | 13 ++- cmd/climc/shell/reservedips.go | 13 ++- cmd/climc/shell/resource_details.go | 13 ++- cmd/climc/shell/resource_fees.go | 13 ++- cmd/climc/shell/schedtaghosts.go | 14 ++- cmd/climc/shell/schedtags.go | 13 ++- cmd/climc/shell/secgrouprules.go | 13 ++- cmd/climc/shell/secgroups.go | 13 ++- cmd/climc/shell/serverdisks.go | 13 ++- cmd/climc/shell/servernetworks.go | 13 ++- cmd/climc/shell/service_hosts.go | 13 ++- cmd/climc/shell/service_name_suggestions.go | 14 ++- cmd/climc/shell/servicetrees.go | 13 ++- cmd/climc/shell/shell.go | 101 -------------------- cmd/climc/shell/specs.go | 37 +++++-- cmd/climc/shell/storagecachedimages.go | 13 ++- cmd/climc/shell/storagecaches.go | 13 ++- cmd/climc/shell/storages.go | 13 ++- cmd/climc/shell/tasks.go | 24 ++++- cmd/climc/shell/treenodes.go | 13 ++- cmd/climc/shell/vcenters.go | 13 ++- cmd/climc/shell/vpcs.go | 13 ++- cmd/climc/shell/wires.go | 13 ++- cmd/climc/shell/zones.go | 13 ++- 61 files changed, 730 insertions(+), 247 deletions(-) diff --git a/cmd/climc/shell/alarmlogs.go b/cmd/climc/shell/alarmlogs.go index 9ceb4c8398..ef6f68e2c6 100644 --- a/cmd/climc/shell/alarmlogs.go +++ b/cmd/climc/shell/alarmlogs.go @@ -7,6 +7,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -15,7 +16,7 @@ func init() { * 列出报警日志 */ type AlarmLogListOptions struct { - BaseListOptions + options.BaseListOptions Host string `help:"Name of the host"` Id int64 `help:"ID of tree node"` Label []string `help:"Labels to this tree node"` @@ -26,7 +27,10 @@ func init() { ThisTimeUntil string `help:"This time until the alarm event"` } R(&AlarmLogListOptions{}, "alarmlog-list", "List all alarm's event", func(s *mcclient.ClientSession, args *AlarmLogListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + params, err := args.BaseListOptions.Params() + if err != nil { + return err + } if len(args.Host) > 0 { params.Add(jsonutils.NewString(args.Host), "host") } diff --git a/cmd/climc/shell/alarms.go b/cmd/climc/shell/alarms.go index 876fbdb714..f321805f96 100644 --- a/cmd/climc/shell/alarms.go +++ b/cmd/climc/shell/alarms.go @@ -5,6 +5,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -116,10 +117,18 @@ func init() { * 列出报警规则 */ type AlarmListOptions struct { - BaseListOptions + options.BaseListOptions } R(&AlarmListOptions{}, "alarm-list", "List all alarms", func(s *mcclient.ClientSession, args *AlarmListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.Alarms.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/alarmtemplates.go b/cmd/climc/shell/alarmtemplates.go index fe5e88f93a..a1e474248a 100644 --- a/cmd/climc/shell/alarmtemplates.go +++ b/cmd/climc/shell/alarmtemplates.go @@ -7,6 +7,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -78,12 +79,20 @@ func init() { * 列出报警模板 */ type AlarmTemplateListOptions struct { - BaseListOptions + options.BaseListOptions LIST_TYPE string `help:"Type of list: avaliable|applied|created "` LABELS string `help:"Labels for node(split by comma)"` } R(&AlarmTemplateListOptions{}, "alarmtemplate-list", "List all alarm templates ", func(s *mcclient.ClientSession, args *AlarmTemplateListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } params.Add(jsonutils.NewString(args.LIST_TYPE), "type") params.Add(jsonutils.NewString(args.LABELS), "node_labels") diff --git a/cmd/climc/shell/baremetalnetworks.go b/cmd/climc/shell/baremetalnetworks.go index e50649b058..24a3ef65bf 100644 --- a/cmd/climc/shell/baremetalnetworks.go +++ b/cmd/climc/shell/baremetalnetworks.go @@ -2,19 +2,27 @@ package shell import ( "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type HostNetworkListOptions struct { - BaseListOptions + options.BaseListOptions Host string `help:"ID or Name of Host"` Network string `help:"ID or name of network"` } R(&HostNetworkListOptions{}, "host-network-list", "List baremetal network pairs", func(s *mcclient.ClientSession, args *HostNetworkListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if len(args.Network) > 0 { params.Add(jsonutils.NewString(args.Network), "network_id") } diff --git a/cmd/climc/shell/baremetalstorages.go b/cmd/climc/shell/baremetalstorages.go index d2ff553bad..28a4705aa3 100644 --- a/cmd/climc/shell/baremetalstorages.go +++ b/cmd/climc/shell/baremetalstorages.go @@ -1,17 +1,27 @@ package shell import ( + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type BaremetalStorageListOptions struct { - BaseListOptions + options.BaseListOptions Host string `help:"ID or Name of Host"` } R(&BaremetalStorageListOptions{}, "baremetal-storage-list", "List baremetal storage pairs", func(s *mcclient.ClientSession, args *BaremetalStorageListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } var result *modules.ListResult var err error if len(args.Host) > 0 { diff --git a/cmd/climc/shell/cachedimages.go b/cmd/climc/shell/cachedimages.go index 8f0da36818..0e2323086a 100644 --- a/cmd/climc/shell/cachedimages.go +++ b/cmd/climc/shell/cachedimages.go @@ -1,16 +1,26 @@ package shell import ( + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type CachedImageListOptions struct { - BaseListOptions + options.BaseListOptions } R(&CachedImageListOptions{}, "cached-image-list", "List cached images", func(s *mcclient.ClientSession, args *CachedImageListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.Cachedimages.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/cloudproviders.go b/cmd/climc/shell/cloudproviders.go index 36c986ddf2..38e36bd697 100644 --- a/cmd/climc/shell/cloudproviders.go +++ b/cmd/climc/shell/cloudproviders.go @@ -5,15 +5,24 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type CloudproviderListOptions struct { - BaseListOptions + options.BaseListOptions } R(&CloudproviderListOptions{}, "cloud-provider-list", "List cloud providers", func(s *mcclient.ClientSession, args *CloudproviderListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.Cloudproviders.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/cloudregions.go b/cmd/climc/shell/cloudregions.go index 3093838000..48223281d7 100644 --- a/cmd/climc/shell/cloudregions.go +++ b/cmd/climc/shell/cloudregions.go @@ -5,18 +5,27 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type CloudregionListOptions struct { - BaseListOptions + options.BaseListOptions Private bool `help:"show private cloud regions only"` Public bool `help:"show public cloud regions only"` Manager string `help:"Show regions belongs to the cloud provider"` Usable bool `help:"List regions that are usable"` } R(&CloudregionListOptions{}, "cloud-region-list", "List cloud regions", func(s *mcclient.ClientSession, args *CloudregionListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if args.Usable { params.Add(jsonutils.JSONTrue, "usable") } diff --git a/cmd/climc/shell/contactgroups.go b/cmd/climc/shell/contactgroups.go index db2af9df11..9841ffaa8f 100644 --- a/cmd/climc/shell/contactgroups.go +++ b/cmd/climc/shell/contactgroups.go @@ -1,8 +1,10 @@ package shell import ( + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -11,10 +13,18 @@ func init() { * 获得一个全部通信地址组 */ type ContactGroupsListOptions struct { - BaseListOptions + options.BaseListOptions } R(&ContactGroupsListOptions{}, "contact-group-list", "List all contact groups for all the domainsconta", func(s *mcclient.ClientSession, args *ContactGroupsListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.ContactGroups.List(s, params) if err != nil { diff --git a/cmd/climc/shell/contacts.go b/cmd/climc/shell/contacts.go index 69b000f0fa..bde3f7f035 100644 --- a/cmd/climc/shell/contacts.go +++ b/cmd/climc/shell/contacts.go @@ -5,6 +5,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -70,10 +71,18 @@ func init() { * 获得所有用户的所有通信地址列表 */ type ContactsListOptions struct { - BaseListOptions + options.BaseListOptions } R(&ContactsListOptions{}, "contact-list", "List all contacts for all users", func(s *mcclient.ClientSession, args *ContactsListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.Contacts.List(s, params) if err != nil { @@ -88,11 +97,19 @@ func init() { * 获得一个用户全部通信地址 */ type ContactsListForUserOptions struct { - BaseListOptions + options.BaseListOptions UID string `help:"The user you wanna find contact from (Keystone User ID)"` } R(&ContactsListForUserOptions{}, "contact-show", "List all contacts for the users", func(s *mcclient.ClientSession, args *ContactsListForUserOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.Contacts.Get(s, args.UID, params) if err != nil { diff --git a/cmd/climc/shell/disks.go b/cmd/climc/shell/disks.go index 3f4d35033b..131224c7c7 100644 --- a/cmd/climc/shell/disks.go +++ b/cmd/climc/shell/disks.go @@ -5,11 +5,12 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type DiskListOptions struct { - BaseListOptions + options.BaseListOptions Unused bool `help:"Show unused disks"` Share bool `help:"Show Share storage disks"` Local bool `help:"Show Local storage disks"` @@ -17,7 +18,15 @@ func init() { Storage string `help:"Storage ID or name"` } R(&DiskListOptions{}, "disk-list", "List virtual disks", func(s *mcclient.ClientSession, suboptions *DiskListOptions) error { - params := FetchPagingParams(suboptions.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = suboptions.BaseListOptions.Params() + if err != nil { + return err + + } + } if suboptions.Unused { params.Add(jsonutils.JSONTrue, "unused") } diff --git a/cmd/climc/shell/dnsrecords.go b/cmd/climc/shell/dnsrecords.go index 05185894ef..f856a11603 100644 --- a/cmd/climc/shell/dnsrecords.go +++ b/cmd/climc/shell/dnsrecords.go @@ -7,6 +7,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) type DNSRecordOptions struct { @@ -38,10 +39,18 @@ func parseDNSRecords(args *DNSRecordOptions, params *jsonutils.JSONDict) { func init() { type DNSListOptions struct { - BaseListOptions + options.BaseListOptions } R(&DNSListOptions{}, "dns-list", "List dns records", func(s *mcclient.ClientSession, suboptions *DNSListOptions) error { - params := FetchPagingParams(suboptions.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = suboptions.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.DNSRecords.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/hostcachedimages.go b/cmd/climc/shell/hostcachedimages.go index fbfa6cc69c..0eeb17cea6 100644 --- a/cmd/climc/shell/hostcachedimages.go +++ b/cmd/climc/shell/hostcachedimages.go @@ -4,16 +4,25 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type HostCachedImageListOptions struct { - BaseListOptions + options.BaseListOptions Host string `help:"ID or Name of Host"` Image string `help:"ID or Name of image"` } R(&HostCachedImageListOptions{}, "host-cachedimage-list", "List host cached image pairs", func(s *mcclient.ClientSession, args *HostCachedImageListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } var result *modules.ListResult var err error if len(args.Host) > 0 { diff --git a/cmd/climc/shell/hosts.go b/cmd/climc/shell/hosts.go index 1f12bc8433..c7a44ccf07 100644 --- a/cmd/climc/shell/hosts.go +++ b/cmd/climc/shell/hosts.go @@ -6,6 +6,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -26,10 +27,18 @@ func init() { Manager string `help:"Show regions belongs to the cloud provider"` - BaseListOptions + options.BaseListOptions } R(&HostListOptions{}, "host-list", "List hosts", func(s *mcclient.ClientSession, args *HostListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if len(args.Schedtag) > 0 { params.Add(jsonutils.NewString(args.Schedtag), "schedtag") } diff --git a/cmd/climc/shell/hoststorages.go b/cmd/climc/shell/hoststorages.go index 3085b10d0a..88d25a21a9 100644 --- a/cmd/climc/shell/hoststorages.go +++ b/cmd/climc/shell/hoststorages.go @@ -4,16 +4,25 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type HostStorageListOptions struct { - BaseListOptions + options.BaseListOptions Host string `help:"ID or Name of Host"` Storage string `help:"ID or Name of Storage"` } R(&HostStorageListOptions{}, "host-storage-list", "List host storage pairs", func(s *mcclient.ClientSession, args *HostStorageListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } var result *modules.ListResult var err error if len(args.Storage) > 0 { diff --git a/cmd/climc/shell/hostwires.go b/cmd/climc/shell/hostwires.go index f27163f1a0..acc6e9bf3f 100644 --- a/cmd/climc/shell/hostwires.go +++ b/cmd/climc/shell/hostwires.go @@ -4,16 +4,25 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type HostWireListOptions struct { - BaseListOptions + options.BaseListOptions Host string `help:"ID or Name of Host"` Wire string `help:"ID or Name of Wire"` } R(&HostWireListOptions{}, "host-wire-list", "List host wire", func(s *mcclient.ClientSession, args *HostWireListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } var result *modules.ListResult var err error if len(args.Host) > 0 { diff --git a/cmd/climc/shell/instances.go b/cmd/climc/shell/instances.go index ce2f6a7c70..2453a7939f 100644 --- a/cmd/climc/shell/instances.go +++ b/cmd/climc/shell/instances.go @@ -1,16 +1,26 @@ package shell import ( + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type InstanceListOptions struct { - BaseListOptions + options.BaseListOptions } R(&InstanceListOptions{}, "instance-list", "List instances", func(s *mcclient.ClientSession, suboptions *InstanceListOptions) error { - params := FetchPagingParams(suboptions.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = suboptions.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.Instances.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/isolatedevices.go b/cmd/climc/shell/isolatedevices.go index 65ddfddc19..8b4c3e8da1 100644 --- a/cmd/climc/shell/isolatedevices.go +++ b/cmd/climc/shell/isolatedevices.go @@ -4,17 +4,26 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type DeviceListOptions struct { - BaseListOptions + options.BaseListOptions Unused bool `help:"Only show unused devices"` Gpu bool `help:"Only show gpu devices"` Host string `help:"Host ID or Name"` } R(&DeviceListOptions{}, "isolated-device-list", "List isolated devices like GPU", func(s *mcclient.ClientSession, args *DeviceListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if len(args.Host) > 0 { params.Add(jsonutils.NewString(args.Host), "host") } diff --git a/cmd/climc/shell/k8s/clusters.go b/cmd/climc/shell/k8s/clusters.go index 96d203d294..bd290b8ecf 100644 --- a/cmd/climc/shell/k8s/clusters.go +++ b/cmd/climc/shell/k8s/clusters.go @@ -6,10 +6,10 @@ import ( "strings" "yunion.io/x/jsonutils" - "yunion.io/x/pkg/util/sets" - "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" + "yunion.io/x/onecloud/pkg/mcclient/options" + "yunion.io/x/pkg/util/sets" ) func initCluster() { @@ -17,11 +17,19 @@ func initCluster() { return resourceCmdN("cluster", suffix) } type listOpt struct { - BaseListOptions + options.BaseListOptions } R(&listOpt{}, cmdN("list"), "List k8s clusters", func(s *mcclient.ClientSession, args *listOpt) error { - args.Details = true - params := FetchPagingParams(args.BaseListOptions) + args.Details = options.Bool(true) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := k8s.Clusters.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/k8s/k8s.go b/cmd/climc/shell/k8s/k8s.go index 9449483ddf..3b8dc9d72c 100644 --- a/cmd/climc/shell/k8s/k8s.go +++ b/cmd/climc/shell/k8s/k8s.go @@ -4,7 +4,6 @@ import ( "fmt" "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/cmd/climc/shell" "yunion.io/x/onecloud/pkg/mcclient/modules" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" @@ -30,8 +29,6 @@ func init() { initService() } -type BaseListOptions shell.BaseListOptions - type clusterBaseOptions struct { Cluster string `default:"$K8S_CLUSTER|default" help:"Kubernetes cluster name"` } @@ -99,10 +96,6 @@ var ( printBatchResults = printutils.PrintJSONBatchResults ) -func FetchPagingParams(o BaseListOptions) *jsonutils.JSONDict { - return shell.FetchPagingParams(shell.BaseListOptions(o)) -} - func resourceCmdN(prefix, suffix string) string { return fmt.Sprintf("k8s-%s-%s", prefix, suffix) } diff --git a/cmd/climc/shell/k8s/nodes.go b/cmd/climc/shell/k8s/nodes.go index 9ad1510472..59af25159b 100644 --- a/cmd/climc/shell/k8s/nodes.go +++ b/cmd/climc/shell/k8s/nodes.go @@ -7,6 +7,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func initNode() { @@ -14,14 +15,19 @@ func initNode() { return resourceCmdN("node", suffix) } type listOpt struct { - BaseListOptions + options.BaseListOptions Cluster string `help:"Filter by cluster"` } R(&listOpt{}, cmdN("list"), "List k8s node", func(s *mcclient.ClientSession, args *listOpt) error { - args.Details = true - params := FetchPagingParams(args.BaseListOptions) - if args.Cluster != "" { - params.Add(jsonutils.NewString(args.Cluster), "cluster") + args.Details = options.Bool(true) + var params *jsonutils.JSONDict + { + var err error + params, err = options.ListStructToParams(args) + if err != nil { + return err + + } } result, err := k8s.Nodes.List(s, params) if err != nil { diff --git a/cmd/climc/shell/k8s/repos.go b/cmd/climc/shell/k8s/repos.go index ee34d8a2f9..1c94ee8b4a 100644 --- a/cmd/climc/shell/k8s/repos.go +++ b/cmd/climc/shell/k8s/repos.go @@ -5,6 +5,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func initRepo() { @@ -12,10 +13,18 @@ func initRepo() { return resourceCmdN("repo", suffix) } type listOpt struct { - BaseListOptions + options.BaseListOptions } R(&listOpt{}, cmdN("list"), "List k8s global helm repos", func(s *mcclient.ClientSession, args *listOpt) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := k8s.Repos.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/keypairs.go b/cmd/climc/shell/keypairs.go index d56d2122a2..a45abec9c4 100644 --- a/cmd/climc/shell/keypairs.go +++ b/cmd/climc/shell/keypairs.go @@ -7,15 +7,24 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type KeypairList struct { - BaseListOptions + options.BaseListOptions } R(&KeypairList{}, "keypair-list", "List keypairs.", func(s *mcclient.ClientSession, args *KeypairList) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.Keypairs.List(s, params) if err != nil { diff --git a/cmd/climc/shell/labels.go b/cmd/climc/shell/labels.go index 9a0a96e242..169111bd2d 100644 --- a/cmd/climc/shell/labels.go +++ b/cmd/climc/shell/labels.go @@ -4,6 +4,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -81,10 +82,18 @@ func init() { * 列出所有的标签 */ type LabelListOptions struct { - BaseListOptions + options.BaseListOptions } R(&LabelListOptions{}, "label-list", "List labels", func(s *mcclient.ClientSession, args *LabelListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.Labels.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/metrics.go b/cmd/climc/shell/metrics.go index 0509bffbe4..8b8b410271 100644 --- a/cmd/climc/shell/metrics.go +++ b/cmd/climc/shell/metrics.go @@ -1,8 +1,10 @@ package shell import ( + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -26,10 +28,18 @@ func init() { * 列出所有监控指标 */ type MetricsListOptions struct { - BaseListOptions + options.BaseListOptions } R(&MetricsListOptions{}, "metric-list", "List all metrics", func(s *mcclient.ClientSession, args *MetricsListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.Metrics.List(s, params) if err != nil { @@ -44,11 +54,19 @@ func init() { * 查看监控指标详情 */ type MetricsShowOptions struct { - BaseListOptions + options.BaseListOptions ID string `help:"The ID of the metric"` } R(&MetricsShowOptions{}, "metric-show", "Show metric details", func(s *mcclient.ClientSession, args *MetricsShowOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.Metrics.Get(s, args.ID, params) if err != nil { @@ -63,11 +81,19 @@ func init() { * 根据name查看监控指标详情 */ type MetricsShowByNameOptions struct { - BaseListOptions + options.BaseListOptions NAME string `help:"The NAME of the metric"` } R(&MetricsShowByNameOptions{}, "metric-details", "Show metric details by name", func(s *mcclient.ClientSession, args *MetricsShowByNameOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.Metrics.GetSpecific(s, "", args.NAME, params) if err != nil { diff --git a/cmd/climc/shell/monitor_types.go b/cmd/climc/shell/monitor_types.go index 7004926d28..9aa06a8943 100644 --- a/cmd/climc/shell/monitor_types.go +++ b/cmd/climc/shell/monitor_types.go @@ -1,8 +1,10 @@ package shell import ( + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -11,10 +13,18 @@ func init() { * 列出全部的监控类型 */ type MonitorTypesOptions struct { - BaseListOptions + options.BaseListOptions } R(&MonitorTypesOptions{}, "monitortype-list", "List all monitor types", func(s *mcclient.ClientSession, args *MonitorTypesOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.MonitorTypes.List(s, params) if err != nil { diff --git a/cmd/climc/shell/monitorinputs.go b/cmd/climc/shell/monitorinputs.go index e0bfc28a49..6809637f99 100644 --- a/cmd/climc/shell/monitorinputs.go +++ b/cmd/climc/shell/monitorinputs.go @@ -1,8 +1,10 @@ package shell import ( + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -11,10 +13,18 @@ func init() { * 列出所有监控数据源 */ type MonitorInputsListOptions struct { - BaseListOptions + options.BaseListOptions } R(&MonitorInputsListOptions{}, "monitorinputs-list", "List all monitor-inputs", func(s *mcclient.ClientSession, args *MonitorInputsListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.MonitorInputs.List(s, params) if err != nil { @@ -29,11 +39,19 @@ func init() { * 查看监控数据源下的监控项 */ type MonitorInputsShowOptions struct { - BaseListOptions + options.BaseListOptions ID string `help:"The ID of the monitor-input"` } R(&MonitorInputsShowOptions{}, "monitorinputs-metrics-list", "List all metrics for the monitor-inputs", func(s *mcclient.ClientSession, args *MonitorInputsShowOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.MonitorInputs.GetSpecific(s, args.ID, "metrics", params) if err != nil { diff --git a/cmd/climc/shell/monitortemplates.go b/cmd/climc/shell/monitortemplates.go index b89f32d7d9..4ad2ad2bfa 100644 --- a/cmd/climc/shell/monitortemplates.go +++ b/cmd/climc/shell/monitortemplates.go @@ -6,6 +6,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -47,10 +48,18 @@ func init() { * 列出监控模板 */ type MonitorTemplateListOptions struct { - BaseListOptions + options.BaseListOptions } R(&MonitorTemplateListOptions{}, "monitortemplate-list", "List all monitor-template", func(s *mcclient.ClientSession, args *MonitorTemplateListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.MonitorTemplates.List(s, params) if err != nil { @@ -65,11 +74,19 @@ func init() { * 查看监控模板详情 */ type MonitorTemplateShowOptions struct { - BaseListOptions + options.BaseListOptions ID string `help:"The ID of the monitor-template"` } R(&MonitorTemplateShowOptions{}, "monitortemplate-show", "Show monitor-template", func(s *mcclient.ClientSession, args *MonitorTemplateShowOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.MonitorTemplates.Get(s, args.ID, params) if err != nil { diff --git a/cmd/climc/shell/networks.go b/cmd/climc/shell/networks.go index 52d6900a28..0e093b50a3 100644 --- a/cmd/climc/shell/networks.go +++ b/cmd/climc/shell/networks.go @@ -6,18 +6,27 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type NetworkListOptions struct { - BaseListOptions + options.BaseListOptions Ip string `help:"search networks that contain this IP"` Zone string `help:"search networks in a zone"` Wire string `help:"search networks belongs to a wire"` Vpc string `help:"search networks belongs to a VPC"` } R(&NetworkListOptions{}, "network-list", "List networks", func(s *mcclient.ClientSession, args *NetworkListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if len(args.Ip) > 0 { params.Add(jsonutils.NewString(args.Ip), "ip") } diff --git a/cmd/climc/shell/nodes.go b/cmd/climc/shell/nodes.go index fac2eb66c2..b7a98b7d95 100644 --- a/cmd/climc/shell/nodes.go +++ b/cmd/climc/shell/nodes.go @@ -6,6 +6,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -14,11 +15,19 @@ func init() { * 查看所有的监控节点 | 列出匹配标签的节点列表 */ type NodeListOptions struct { - BaseListOptions + options.BaseListOptions Labels []string `help:"Node labels"` } R(&NodeListOptions{}, "node-list", "List all nodes", func(s *mcclient.ClientSession, args *NodeListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if len(args.Labels) > 0 { for _, f := range args.Labels { parts := strings.Split(f, "=") diff --git a/cmd/climc/shell/notification.go b/cmd/climc/shell/notification.go index b2b21af2b7..d6a0641854 100644 --- a/cmd/climc/shell/notification.go +++ b/cmd/climc/shell/notification.go @@ -5,6 +5,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -71,7 +72,7 @@ func init() { * 查询已发送的通知任务 */ type NotificationListOptions struct { - BaseListOptions + options.BaseListOptions } R(&NotificationListOptions{}, "notify-list", "List notification history", func(s *mcclient.ClientSession, args *NotificationListOptions) error { result, err := modules.Notifications.List(s, nil) diff --git a/cmd/climc/shell/operations.go b/cmd/climc/shell/operations.go index cb08861efa..b778b52e29 100644 --- a/cmd/climc/shell/operations.go +++ b/cmd/climc/shell/operations.go @@ -4,14 +4,23 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type OperationListOptions struct { - BaseListOptions + options.BaseListOptions } R(&OperationListOptions{}, "operation-list", "List operations", func(s *mcclient.ClientSession, suboptions *OperationListOptions) error { - params := FetchPagingParams(suboptions.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = suboptions.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.Operations.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/processes.go b/cmd/climc/shell/processes.go index 84fbc5e82a..efa3f9b08b 100644 --- a/cmd/climc/shell/processes.go +++ b/cmd/climc/shell/processes.go @@ -1,16 +1,26 @@ package shell import ( + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type TaskListOptions struct { - BaseListOptions + options.BaseListOptions } R(&TaskListOptions{}, "process-list", "List processes", func(s *mcclient.ClientSession, suboptions *TaskListOptions) error { - params := FetchPagingParams(suboptions.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = suboptions.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.Processes.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/processlogs.go b/cmd/climc/shell/processlogs.go index d6c038962d..29f92cd850 100644 --- a/cmd/climc/shell/processlogs.go +++ b/cmd/climc/shell/processlogs.go @@ -1,16 +1,26 @@ package shell import ( + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type TaskListOptions struct { - BaseListOptions + options.BaseListOptions } R(&TaskListOptions{}, "prosesslog-list", "List processlogs", func(s *mcclient.ClientSession, suboptions *TaskListOptions) error { - params := FetchPagingParams(suboptions.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = suboptions.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.Processlogs.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/project_admin.go b/cmd/climc/shell/project_admin.go index 21f51564eb..7a7a0c8d25 100644 --- a/cmd/climc/shell/project_admin.go +++ b/cmd/climc/shell/project_admin.go @@ -1,8 +1,10 @@ package shell import ( + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -11,10 +13,18 @@ func init() { * 列出所有监控指标 */ type ProjectAdminListOptions struct { - BaseListOptions + options.BaseListOptions } R(&ProjectAdminListOptions{}, "projectadmin-list", "List all Project Admins", func(s *mcclient.ClientSession, args *ProjectAdminListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.ProjectAdmin.List(s, params) if err != nil { diff --git a/cmd/climc/shell/project_admin_candidates.go b/cmd/climc/shell/project_admin_candidates.go index fcd6be3848..2af2cdfed7 100644 --- a/cmd/climc/shell/project_admin_candidates.go +++ b/cmd/climc/shell/project_admin_candidates.go @@ -1,8 +1,10 @@ package shell import ( + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -11,10 +13,18 @@ func init() { * 列出所有监控指标 */ type ProjectAdminCandidateListOptions struct { - BaseListOptions + options.BaseListOptions } R(&ProjectAdminCandidateListOptions{}, "projectadmincandidate-list", "List all Project Admin Candidates", func(s *mcclient.ClientSession, args *ProjectAdminCandidateListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.ProjectAdminCandidate.List(s, params) if err != nil { diff --git a/cmd/climc/shell/rates.go b/cmd/climc/shell/rates.go index d4c931c2e5..34f52ece8d 100644 --- a/cmd/climc/shell/rates.go +++ b/cmd/climc/shell/rates.go @@ -4,6 +4,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -11,14 +12,22 @@ func init() { * 列出列表 */ type RateListOptions struct { - BaseListOptions + options.BaseListOptions RESTYPE string `"help":"res_type of the rate"` ACTION string `"help":"action of list :querygroup or queryhistory"` SubResType string `"help":"query the subResType"` Id string `"help":"ID of rate"` } R(&RateListOptions{}, "rate-list", "List all rates ", func(s *mcclient.ClientSession, args *RateListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } params.Add(jsonutils.NewString(args.RESTYPE), "res_type") params.Add(jsonutils.NewString(args.ACTION), "action") diff --git a/cmd/climc/shell/recipient.go b/cmd/climc/shell/recipient.go index 5c81470bc9..b870d0629d 100644 --- a/cmd/climc/shell/recipient.go +++ b/cmd/climc/shell/recipient.go @@ -4,6 +4,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -74,12 +75,20 @@ func init() { * 查询树节点的报警接收人信息 */ type TreeNodeRecipientsListOptions struct { - BaseListOptions + options.BaseListOptions LIST_TYPE string `help:"Type of list: junior|senior"` LABELS string `help:"Labels for tree-node(split by comma)"` } R(&TreeNodeRecipientsListOptions{}, "treenode-recipient-list", "List recipient for the tree-node ", func(s *mcclient.ClientSession, args *TreeNodeRecipientsListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } params.Add(jsonutils.NewString(args.LIST_TYPE), "type") params.Add(jsonutils.NewString(args.LABELS), "node_labels") diff --git a/cmd/climc/shell/reservedips.go b/cmd/climc/shell/reservedips.go index 0de0d0f9e8..6ce216ff58 100644 --- a/cmd/climc/shell/reservedips.go +++ b/cmd/climc/shell/reservedips.go @@ -4,6 +4,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -40,11 +41,19 @@ func init() { }) type ReservedIPListOptions struct { - BaseListOptions + options.BaseListOptions Network string `help:"Network filter"` } R(&ReservedIPListOptions{}, "reserved-ip-list", "Show all reserved IPs for any network", func(s *mcclient.ClientSession, args *ReservedIPListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if len(args.Network) > 0 { params.Add(jsonutils.NewString(args.Network), "network") } diff --git a/cmd/climc/shell/resource_details.go b/cmd/climc/shell/resource_details.go index c0fc3eb309..7ea8e8eee7 100644 --- a/cmd/climc/shell/resource_details.go +++ b/cmd/climc/shell/resource_details.go @@ -4,6 +4,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -11,12 +12,20 @@ func init() { * 列出列表 */ type ResourceDetailListOptions struct { - BaseListOptions + options.BaseListOptions QUERYTYPE string `"help":"query type of the resource_detail"` ProjectId string `"help":"project id of the resource_detail"` } R(&ResourceDetailListOptions{}, "resourcedetail-list", "List all resource details", func(s *mcclient.ClientSession, args *ResourceDetailListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if len(args.QUERYTYPE) > 0 { params.Add(jsonutils.NewString(args.QUERYTYPE), "query_type") } diff --git a/cmd/climc/shell/resource_fees.go b/cmd/climc/shell/resource_fees.go index 08c8c324de..49e50764e2 100644 --- a/cmd/climc/shell/resource_fees.go +++ b/cmd/climc/shell/resource_fees.go @@ -4,6 +4,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -11,7 +12,7 @@ func init() { * 列出列表 */ type ResourceFeeListOptions struct { - BaseListOptions + options.BaseListOptions STATTYPE string `"help":"stat type of the resource_fee"` STATMONTH string `"help":"stat month of the resource_fee"` ProjectId string `"help":"project id of the resource_fee"` @@ -19,7 +20,15 @@ func init() { EndDay string `"help":"end day of the resource_fee"` } R(&ResourceFeeListOptions{}, "resourcefee-list", "List all resource fees", func(s *mcclient.ClientSession, args *ResourceFeeListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if len(args.STATTYPE) > 0 { params.Add(jsonutils.NewString(args.STATTYPE), "stat_type") } diff --git a/cmd/climc/shell/schedtaghosts.go b/cmd/climc/shell/schedtaghosts.go index 9ff4f6a1aa..cb719cfb51 100644 --- a/cmd/climc/shell/schedtaghosts.go +++ b/cmd/climc/shell/schedtaghosts.go @@ -1,13 +1,15 @@ package shell import ( + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type SchedtagHostListOptions struct { - BaseListOptions + options.BaseListOptions Schedtag string `help:"ID or Name of schedtag"` } R(&SchedtagHostListOptions{}, "schedtag-host-list", "List all scheduler tag and host pairs", func(s *mcclient.ClientSession, args *SchedtagHostListOptions) error { @@ -15,7 +17,15 @@ func init() { if err != nil { return err } - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } var result *modules.ListResult if len(args.Schedtag) > 0 { result, err = mod.ListDescendent(s, args.Schedtag, params) diff --git a/cmd/climc/shell/schedtags.go b/cmd/climc/shell/schedtags.go index e0ec4648d5..86f4178cc7 100644 --- a/cmd/climc/shell/schedtags.go +++ b/cmd/climc/shell/schedtags.go @@ -5,14 +5,23 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type SchedtagListOptions struct { - BaseListOptions + options.BaseListOptions } R(&SchedtagListOptions{}, "schedtag-list", "List schedule tags", func(s *mcclient.ClientSession, suboptions *SchedtagListOptions) error { - params := FetchPagingParams(suboptions.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = suboptions.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.Schedtags.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/secgrouprules.go b/cmd/climc/shell/secgrouprules.go index eb9fd4b621..222c3c6968 100644 --- a/cmd/climc/shell/secgrouprules.go +++ b/cmd/climc/shell/secgrouprules.go @@ -4,11 +4,12 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type SecGroupRulesListOptions struct { - BaseListOptions + options.BaseListOptions Secgroup string `help:"Secgroup ID or Name"` Direction string `help:"filter Direction of rule" choices:"in|out"` Protocol string `help:"filter Protocol of rule" choices:"any|tcp|udp|icmp"` @@ -16,7 +17,15 @@ func init() { } R(&SecGroupRulesListOptions{}, "secgroup-rule-list", "List all security group", func(s *mcclient.ClientSession, args *SecGroupRulesListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if len(args.Secgroup) > 0 { params.Add(jsonutils.NewString(args.Secgroup), "secgroup") } diff --git a/cmd/climc/shell/secgroups.go b/cmd/climc/shell/secgroups.go index 8090fe5610..a0a5818163 100644 --- a/cmd/climc/shell/secgroups.go +++ b/cmd/climc/shell/secgroups.go @@ -6,15 +6,24 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type SecGroupsListOptions struct { - BaseListOptions + options.BaseListOptions } R(&SecGroupsListOptions{}, "secgroup-list", "List all security group", func(s *mcclient.ClientSession, args *SecGroupsListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.SecGroups.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/serverdisks.go b/cmd/climc/shell/serverdisks.go index eb8cab800d..98186a768d 100644 --- a/cmd/climc/shell/serverdisks.go +++ b/cmd/climc/shell/serverdisks.go @@ -5,15 +5,24 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type ServerDiskListOptions struct { - BaseListOptions + options.BaseListOptions Server string `help:"ID or Name of Server"` } R(&ServerDiskListOptions{}, "server-disk-list", "List server disk pairs", func(s *mcclient.ClientSession, args *ServerDiskListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } var result *modules.ListResult var err error if len(args.Server) > 0 { diff --git a/cmd/climc/shell/servernetworks.go b/cmd/climc/shell/servernetworks.go index c867c57842..2674d48e2b 100644 --- a/cmd/climc/shell/servernetworks.go +++ b/cmd/climc/shell/servernetworks.go @@ -4,18 +4,27 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type ServerNetworkListOptions struct { - BaseListOptions + options.BaseListOptions Server string `help:"ID or Name of Server"` Mac string `help:"search the MAC address"` Ip string `help:"search the IP address"` Network string `help:"Network ID or name"` } R(&ServerNetworkListOptions{}, "server-network-list", "List server network pairs", func(s *mcclient.ClientSession, args *ServerNetworkListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if len(args.Mac) > 0 { params.Add(jsonutils.NewString(args.Mac), "mac_addr") } diff --git a/cmd/climc/shell/service_hosts.go b/cmd/climc/shell/service_hosts.go index 1e3a5d2cc9..77c134fba1 100644 --- a/cmd/climc/shell/service_hosts.go +++ b/cmd/climc/shell/service_hosts.go @@ -4,6 +4,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -72,11 +73,19 @@ func init() { * 查看指定服务树节点的机器 */ type ServiceHostListOptions struct { - BaseListOptions + options.BaseListOptions Labels string `help:"Labels for tree-node(split by comma)"` } R(&ServiceHostListOptions{}, "servicehost-list", "List all hosts for the tree-node", func(s *mcclient.ClientSession, args *ServiceHostListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if len(args.Labels) > 0 { params.Add(jsonutils.NewString(args.Labels), "node_labels") } diff --git a/cmd/climc/shell/service_name_suggestions.go b/cmd/climc/shell/service_name_suggestions.go index 23eb4e155b..fd01ef652e 100644 --- a/cmd/climc/shell/service_name_suggestions.go +++ b/cmd/climc/shell/service_name_suggestions.go @@ -1,8 +1,10 @@ package shell import ( + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -11,10 +13,18 @@ func init() { * 列出所有监控指标 */ type ServiceNameSuggestionListOptions struct { - BaseListOptions + options.BaseListOptions } R(&ServiceNameSuggestionListOptions{}, "servicenamesuggestion-list", "List all serviceNameSuggestion", func(s *mcclient.ClientSession, args *ServiceNameSuggestionListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.ServiceNameSuggestion.List(s, params) if err != nil { diff --git a/cmd/climc/shell/servicetrees.go b/cmd/climc/shell/servicetrees.go index b89767b996..aeda96d62a 100644 --- a/cmd/climc/shell/servicetrees.go +++ b/cmd/climc/shell/servicetrees.go @@ -4,6 +4,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -79,10 +80,18 @@ func init() { * 列出服务树 */ type ServiceTreeListOptions struct { - BaseListOptions + options.BaseListOptions } R(&ServiceTreeListOptions{}, "servicetree-list", "List all service tree", func(s *mcclient.ClientSession, args *ServiceTreeListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.ServiceTrees.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/shell.go b/cmd/climc/shell/shell.go index 03246aa46c..6eea679223 100644 --- a/cmd/climc/shell/shell.go +++ b/cmd/climc/shell/shell.go @@ -2,8 +2,6 @@ package shell import ( "fmt" - - "yunion.io/x/jsonutils" ) type CMD struct { @@ -19,105 +17,6 @@ func R(options interface{}, command string, desc string, callback interface{}) { CommandTable = append(CommandTable, CMD{options, command, desc, callback}) } -type BaseListOptions struct { - Limit int `default:"20" help:"Page limit"` - Offset int `default:"0" help:"Page offset"` - OrderBy string `help:"Name of the field to be ordered by"` - Order string `help:"List order" choices:"desc|asc"` - Details bool `help:"Show more details"` - Search string `help:"Filter results by a simple keyword search"` - Meta bool `help:"Piggyback metadata information"` - Filter []string `help:"Filters"` - JointFilter []string `help:"Filters with joint table col; joint_tbl(related_key).filter_col.filter_cond(filters)"` - FilterAny bool `help:"If true, match if any of the filters matches; otherwise, match if all of the filters match"` - Admin bool `help:"Is an admin call?"` - Tenant string `help:"Tenant ID or Name"` - User string `help:"User ID or Name"` - System bool `help:"Show system resource"` - PendingDelete bool `help:"Show pending deleted resource"` - Field []string `help:"Show only specified fields"` - ShowEmulated bool `help:"Show all resources including the emulated resources"` -} - -func FetchPagingParams(options BaseListOptions) *jsonutils.JSONDict { - params := jsonutils.NewDict() - if options.Limit > 0 { - params.Add(jsonutils.NewInt(int64(options.Limit)), "limit") - } - if options.Offset > 0 { - params.Add(jsonutils.NewInt(int64(options.Offset)), "offset") - } - if len(options.OrderBy) > 0 { - params.Add(jsonutils.NewString(options.OrderBy), "order_by") - } - if len(options.Order) > 0 { - params.Add(jsonutils.NewString(options.Order), "order") - } - if options.Details { - params.Add(jsonutils.JSONTrue, "details") - } else { - params.Add(jsonutils.JSONFalse, "details") - } - if len(options.Search) > 0 { - params.Add(jsonutils.NewString(options.Search), "search") - } - if options.Meta { - params.Add(jsonutils.JSONTrue, "with_meta") - } - if len(options.JointFilter) > 0 { - arr := jsonutils.NewArray() - for _, f := range options.JointFilter { - arr.Add(jsonutils.NewString(f)) - } - params.Add(arr, "joint_filter") - } - if len(options.Filter) > 0 { - arr := jsonutils.NewArray() - for _, f := range options.Filter { - arr.Add(jsonutils.NewString(f)) - } - params.Add(arr, "filter") - if options.FilterAny { - params.Add(jsonutils.JSONTrue, "filter_any") - } - } - if options.Admin { - params.Add(jsonutils.JSONTrue, "admin") - } - if len(options.Tenant) > 0 { - params.Add(jsonutils.NewString(options.Tenant), "tenant") - if !options.Admin { - params.Add(jsonutils.JSONTrue, "admin") - } - } - if len(options.User) > 0 { - params.Add(jsonutils.NewString(options.User), "user") - } - if options.System { - params.Add(jsonutils.JSONTrue, "system") - if !options.Admin { - params.Add(jsonutils.JSONTrue, "admin") - } - } - if options.PendingDelete { - params.Add(jsonutils.JSONTrue, "pending_delete") - if !options.Admin { - params.Add(jsonutils.JSONTrue, "admin") - } - } - if len(options.Field) > 0 { - arr := jsonutils.NewArray() - for _, f := range options.Field { - arr.Add(jsonutils.NewString(f)) - } - params.Add(arr, "field") - } - if options.ShowEmulated { - params.Add(jsonutils.JSONTrue, "show_emulated") - } - return params -} - func InvalidUpdateError() error { return fmt.Errorf("No valid update data") } diff --git a/cmd/climc/shell/specs.go b/cmd/climc/shell/specs.go index bdc61e7029..e5f9094f7b 100644 --- a/cmd/climc/shell/specs.go +++ b/cmd/climc/shell/specs.go @@ -6,17 +6,26 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type ListOptions struct { - BaseListOptions + options.BaseListOptions Model string `help:"Specified model specs" choices:"hosts|isolated_devices|guests"` HostType string `help:"Host type filter" choices:"baremetal|hypervisor|esxi|kubelet|hyperv"` Gpu bool `help:"Only show gpu devices"` } R(&ListOptions{}, "spec", "List all kinds of model specs", func(s *mcclient.ClientSession, args *ListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } model := "" if len(args.Model) != 0 { model = args.Model @@ -36,7 +45,7 @@ func init() { }) type HostsQueryOptions struct { - BaseListOptions + options.BaseListOptions HostType string `help:"Host type filter" choices:"baremetal|hypervisor|esxi|kubelet|hyperv"` Ncpu int64 `help:"#CPU count of host" metavar:""` MemSize string `help:"Memory GB size"` @@ -61,7 +70,15 @@ func init() { } return keys } - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if len(args.HostType) > 0 { params.Add(jsonutils.NewString(args.HostType), "host_type") } @@ -80,7 +97,7 @@ func init() { }) type IsoDevQueryOptions struct { - BaseListOptions + options.BaseListOptions Model string `help:"Device model name"` Vendor string `help:"Device vendor name"` } @@ -95,7 +112,15 @@ func init() { } return keys } - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } resp, err := modules.Specs.SpecsQueryModelObjects(s, "isolated_devices", newSpecKeys(), params) if err != nil { return err diff --git a/cmd/climc/shell/storagecachedimages.go b/cmd/climc/shell/storagecachedimages.go index 504826d14b..0b2579d5b2 100644 --- a/cmd/climc/shell/storagecachedimages.go +++ b/cmd/climc/shell/storagecachedimages.go @@ -4,16 +4,25 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type StorageCachedImageListOptions struct { - BaseListOptions + options.BaseListOptions Storagecache string `help:"ID or Name of Storage"` Image string `help:"ID or Name of image"` } R(&StorageCachedImageListOptions{}, "storage-cached-image-list", "List storage cached image pairs", func(s *mcclient.ClientSession, args *StorageCachedImageListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } var result *modules.ListResult var err error if len(args.Storagecache) > 0 { diff --git a/cmd/climc/shell/storagecaches.go b/cmd/climc/shell/storagecaches.go index 0e10d6ab75..d24a1b31dc 100644 --- a/cmd/climc/shell/storagecaches.go +++ b/cmd/climc/shell/storagecaches.go @@ -4,16 +4,25 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type StoragecacheListOptions struct { - BaseListOptions + options.BaseListOptions Manager string `help:"Show regions belongs to the cloud provider"` } R(&StoragecacheListOptions{}, "storage-cache-list", "List storage caches", func(s *mcclient.ClientSession, args *StoragecacheListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if len(args.Manager) > 0 { params.Add(jsonutils.NewString(args.Manager), "manager") diff --git a/cmd/climc/shell/storages.go b/cmd/climc/shell/storages.go index 4608be45f9..4d0cca8701 100644 --- a/cmd/climc/shell/storages.go +++ b/cmd/climc/shell/storages.go @@ -6,11 +6,12 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type StorageListOptions struct { - BaseListOptions + options.BaseListOptions Share bool `help:"Share storage list"` Local bool `help:"Local storage list"` Usable bool `help:"Usable storage list"` @@ -20,7 +21,15 @@ func init() { Manager string `help:"Show regions belongs to the cloud provider"` } R(&StorageListOptions{}, "storage-list", "List storages", func(s *mcclient.ClientSession, args *StorageListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if args.Share { params.Add(jsonutils.JSONTrue, "share") } diff --git a/cmd/climc/shell/tasks.go b/cmd/climc/shell/tasks.go index d4b3edafef..9d62fcbebe 100644 --- a/cmd/climc/shell/tasks.go +++ b/cmd/climc/shell/tasks.go @@ -1,16 +1,26 @@ package shell import ( + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type TaskListOptions struct { - BaseListOptions + options.BaseListOptions } R(&TaskListOptions{}, "task-list", "List taskman", func(s *mcclient.ClientSession, suboptions *TaskListOptions) error { - params := FetchPagingParams(suboptions.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = suboptions.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.Tasks.List(s, params) if err != nil { return err @@ -20,7 +30,15 @@ func init() { }) R(&TaskListOptions{}, "region-task-list", "List tasks on region server", func(s *mcclient.ClientSession, suboptions *TaskListOptions) error { - params := FetchPagingParams(suboptions.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = suboptions.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.ComputeTasks.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/treenodes.go b/cmd/climc/shell/treenodes.go index 8bbd156b13..75c82042ed 100644 --- a/cmd/climc/shell/treenodes.go +++ b/cmd/climc/shell/treenodes.go @@ -7,6 +7,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { @@ -58,12 +59,20 @@ func init() { }) type ServiceTreeNodeListOptions struct { - BaseListOptions + options.BaseListOptions Label string `help:"Label of node"` Pid int64 `help:"Pid of node" default:"-1"` } R(&ServiceTreeNodeListOptions{}, "servicetree-node-list", "List servicetree nodes", func(s *mcclient.ClientSession, args *ServiceTreeNodeListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if args.Pid >= 0 { params.Add(jsonutils.NewInt(args.Pid), "pid") } diff --git a/cmd/climc/shell/vcenters.go b/cmd/climc/shell/vcenters.go index 134ec4b253..4b33f4e265 100644 --- a/cmd/climc/shell/vcenters.go +++ b/cmd/climc/shell/vcenters.go @@ -4,14 +4,23 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type VCenterListOptions struct { - BaseListOptions + options.BaseListOptions } R(&VCenterListOptions{}, "vcenter-list", "List VMWare vcenters", func(s *mcclient.ClientSession, args *VCenterListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } result, err := modules.VCenters.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/vpcs.go b/cmd/climc/shell/vpcs.go index 1cd7c4b9ae..547a775dd0 100644 --- a/cmd/climc/shell/vpcs.go +++ b/cmd/climc/shell/vpcs.go @@ -4,16 +4,25 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type VpcListOptions struct { - BaseListOptions + options.BaseListOptions Region string `help:"ID or Name of region"` Manager string `help:"Show regions belongs to the cloud provider"` } R(&VpcListOptions{}, "vpc-list", "List VPCs", func(s *mcclient.ClientSession, args *VpcListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if len(args.Manager) > 0 { params.Add(jsonutils.NewString(args.Manager), "manager") diff --git a/cmd/climc/shell/wires.go b/cmd/climc/shell/wires.go index 09eb4f68c0..d83d778cc0 100644 --- a/cmd/climc/shell/wires.go +++ b/cmd/climc/shell/wires.go @@ -4,16 +4,25 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type WireListOptions struct { - BaseListOptions + options.BaseListOptions Zone string `help:"list wires in zone"` Vpc string `help:"List wires in vpc"` } R(&WireListOptions{}, "wire-list", "List wires", func(s *mcclient.ClientSession, args *WireListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if len(args.Vpc) > 0 { params.Add(jsonutils.NewString(args.Vpc), "vpc") } diff --git a/cmd/climc/shell/zones.go b/cmd/climc/shell/zones.go index 16cc1cf3e0..4ca0b2d254 100644 --- a/cmd/climc/shell/zones.go +++ b/cmd/climc/shell/zones.go @@ -4,18 +4,27 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type ZoneListOptions struct { - BaseListOptions + options.BaseListOptions Region string `help:"cloud region ID or Name"` Usable bool `help:"List all zones that is usable"` Private bool `help:"show all zones in private cloud regions only"` Public bool `help:"show all zones in public cloud regions only"` } R(&ZoneListOptions{}, "zone-list", "List zones", func(s *mcclient.ClientSession, args *ZoneListOptions) error { - params := FetchPagingParams(args.BaseListOptions) + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } if args.Usable { params.Add(jsonutils.JSONTrue, "usable") } From f0c706919ae1520a32fc197c262e209c81c8a38d Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Tue, 28 Aug 2018 12:50:30 +0000 Subject: [PATCH 12/32] climc: alarmevents: use options for param serialization --- cmd/climc/shell/alarmevents.go | 43 ++++------------------------- pkg/mcclient/options/alarmevents.go | 13 +++++++++ 2 files changed, 18 insertions(+), 38 deletions(-) create mode 100644 pkg/mcclient/options/alarmevents.go diff --git a/cmd/climc/shell/alarmevents.go b/cmd/climc/shell/alarmevents.go index 488fe39599..10c7d8037e 100644 --- a/cmd/climc/shell/alarmevents.go +++ b/cmd/climc/shell/alarmevents.go @@ -5,51 +5,18 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { /** * 列出报警事件 */ - type AlarmEventListOptions struct { - BaseListOptions - NodeLabels string `help:"Service tree node labels"` - MetricName string `help:"Metric name"` - HostName string `help:"Host name"` - HostIp string `help:"Host IP address"` - AlarmLevel string `help:"Alarm level"` - AlarmCondition string `help:"Concrete alarm rule"` - Template string `help:"Template number of the alarm condition"` - AckStatus string `help:"Alarm event ack status"` - } - R(&AlarmEventListOptions{}, "alarmevent-list", "List all alarm's event", func(s *mcclient.ClientSession, args *AlarmEventListOptions) error { - params := FetchPagingParams(args.BaseListOptions) - - if len(args.NodeLabels) > 0 { - params.Add(jsonutils.NewString(args.NodeLabels), "node_labels") + R(&options.AlarmEventListOptions{}, "alarmevent-list", "List all alarm's event", func(s *mcclient.ClientSession, opts *options.AlarmEventListOptions) error { + params, err := options.ListStructToParams(opts) + if err != nil { + return err } - if len(args.MetricName) > 0 { - params.Add(jsonutils.NewString(args.MetricName), "metric_name") - } - if len(args.HostName) > 0 { - params.Add(jsonutils.NewString(args.HostName), "host_name") - } - if len(args.HostIp) > 0 { - params.Add(jsonutils.NewString(args.HostIp), "host_ip") - } - if len(args.AlarmLevel) > 0 { - params.Add(jsonutils.NewString(args.AlarmLevel), "alarm_level") - } - if len(args.AlarmCondition) > 0 { - params.Add(jsonutils.NewString(args.AlarmCondition), "alarm_condition") - } - if len(args.Template) > 0 { - params.Add(jsonutils.NewString(args.Template), "template") - } - if len(args.AckStatus) > 0 { - params.Add(jsonutils.NewString(args.AckStatus), "ack_status") - } - result, err := modules.AlarmEvents.List(s, params) if err != nil { return err diff --git a/pkg/mcclient/options/alarmevents.go b/pkg/mcclient/options/alarmevents.go new file mode 100644 index 0000000000..f08a8c9476 --- /dev/null +++ b/pkg/mcclient/options/alarmevents.go @@ -0,0 +1,13 @@ +package options + +type AlarmEventListOptions struct { + BaseListOptions + NodeLabels string `help:"Service tree node labels"` + MetricName string `help:"Metric name"` + HostName string `help:"Host name"` + HostIp string `help:"Host IP address"` + AlarmLevel string `help:"Alarm level"` + AlarmCondition string `help:"Concrete alarm rule"` + Template string `help:"Template number of the alarm condition"` + AckStatus string `help:"Alarm event ack status"` +} From 34c2b56ca46ab930329052512d3137f09c62f425 Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Wed, 29 Aug 2018 06:39:40 +0000 Subject: [PATCH 13/32] climc: servers: convert to using mcclient/options --- cmd/climc/shell/servers.go | 596 +++++++------------------------- pkg/mcclient/options/servers.go | 273 +++++++++++++++ 2 files changed, 394 insertions(+), 475 deletions(-) create mode 100644 pkg/mcclient/options/servers.go diff --git a/cmd/climc/shell/servers.go b/cmd/climc/shell/servers.go index 09e610c86f..3ec49abfbc 100644 --- a/cmd/climc/shell/servers.go +++ b/cmd/climc/shell/servers.go @@ -2,105 +2,18 @@ package shell import ( "fmt" - "io/ioutil" - "strings" "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) -type ServerDeployInfo struct { - Action string - Path string - Content string -} - -func parseDeployInfo(info string) (ServerDeployInfo, error) { - sdi := ServerDeployInfo{} - colonPos := strings.IndexByte(info, ':') - if colonPos <= 0 { - return sdi, fmt.Errorf("Malformed deploy string") - } - if info[0] == '+' { - sdi.Action = "append" - sdi.Path = info[1:colonPos] - } else { - sdi.Action = "create" - sdi.Path = info[:colonPos] - } - content := info[colonPos+1:] - bytes, e := ioutil.ReadFile(content) - if e != nil { - sdi.Content = content - } else { - sdi.Content = string(bytes) - } - return sdi, nil -} - -func parseDeployList(list []string, params *jsonutils.JSONDict) error { - for i, info := range list { - ret, e := parseDeployInfo(info) - if e != nil { - return e - } - params.Add(jsonutils.NewString(ret.Action), fmt.Sprintf("deploy.%d.action", i)) - params.Add(jsonutils.NewString(ret.Path), fmt.Sprintf("deploy.%d.path", i)) - params.Add(jsonutils.NewString(ret.Content), fmt.Sprintf("deploy.%d.content", i)) - } - return nil -} - func init() { - type ServerListOptions struct { - Zone string `help:"Zone ID or Name"` - Wire string `help:"Wire ID or Name"` - Network string `help:"Network ID or Name"` - Disk string `help:"Disk ID or Name"` - Host string `help:"Host ID or Name"` - Baremetal bool `help:"Show baremetal servers"` - Gpu bool `help:"Show gpu servers"` - Secgroup string `help:"Secgroup ID or Name"` - AdminSecgroup string `help:"AdminSecgroup ID or Name"` - Hypervisor string `help:"Show server of hypervisor" choices:"kvm|esxi|container|baremetal|aliyun"` - Manager string `help:"Show servers imported from manager"` - BaseListOptions - } - R(&ServerListOptions{}, "server-list", "List virtual servers", func(s *mcclient.ClientSession, args *ServerListOptions) error { - params := FetchPagingParams(args.BaseListOptions) - if len(args.Zone) > 0 { - params.Add(jsonutils.NewString(args.Zone), "zone") - } - if len(args.Disk) > 0 { - params.Add(jsonutils.NewString(args.Disk), "disk") - } - if len(args.Wire) > 0 { - params.Add(jsonutils.NewString(args.Wire), "wire") - } - if len(args.Network) > 0 { - params.Add(jsonutils.NewString(args.Network), "network") - } - if len(args.Host) > 0 { - params.Add(jsonutils.NewString(args.Host), "host") - } - if args.Baremetal { - params.Add(jsonutils.JSONTrue, "baremetal") - } - if args.Gpu { - params.Add(jsonutils.JSONTrue, "gpu") - } - if len(args.Secgroup) > 0 { - params.Add(jsonutils.NewString(args.Secgroup), "secgroup") - } - if len(args.AdminSecgroup) > 0 { - params.Add(jsonutils.NewString(args.AdminSecgroup), "admin_secgroup") - } - if len(args.Hypervisor) > 0 { - params.Add(jsonutils.NewString(args.Hypervisor), "hypervisor") - } - if len(args.Manager) > 0 { - params.Add(jsonutils.NewString(args.Manager), "manager") + R(&options.ServerListOptions{}, "server-list", "List virtual servers", func(s *mcclient.ClientSession, opts *options.ServerListOptions) error { + params, err := options.ListStructToParams(opts) + if err != nil { + return err } result, err := modules.Servers.List(s, params) if err != nil { @@ -110,16 +23,12 @@ func init() { return nil }) - type ServerShowOptions struct { - ID string `help:"ID or name of the server"` - WithMeta bool `help:"With meta data"` - } - R(&ServerShowOptions{}, "server-show", "Show details of a server", func(s *mcclient.ClientSession, args *ServerShowOptions) error { - params := jsonutils.NewDict() - if args.WithMeta { - params.Add(jsonutils.JSONTrue, "with_meta") + R(&options.ServerShowOptions{}, "server-show", "Show details of a server", func(s *mcclient.ClientSession, opts *options.ServerShowOptions) error { + params, err := options.StructToParams(opts) + if err != nil { + return err } - result, err := modules.Servers.Get(s, args.ID, params) + result, err := modules.Servers.Get(s, opts.ID, params) if err != nil { return err } @@ -127,8 +36,8 @@ func init() { return nil }) - R(&ServerShowOptions{}, "server-metadata", "Show metadata of a server", func(s *mcclient.ClientSession, args *ServerShowOptions) error { - result, err := modules.Servers.GetMetadata(s, args.ID, nil) + R(&options.ServerIdOptions{}, "server-metadata", "Show metadata of a server", func(s *mcclient.ClientSession, opts *options.ServerIdOptions) error { + result, err := modules.Servers.GetMetadata(s, opts.ID, nil) if err != nil { return err } @@ -136,146 +45,25 @@ func init() { return nil }) - type ServerCreateOptions struct { - NAME string `help:"Name of server"` - MEM string `help:"Memory size" metavar:"MEMORY"` - Disk []string `help:"Disk descriptions" nargs:"+"` - Net []string `help:"Network descriptions" metavar:"NETWORK"` - IsolatedDevice []string `help:"Isolated device model or ID" metavar:"ISOLATED_DEVICE"` - Keypair string `help:"SSH Keypair"` - Password string `help:"Default user password"` - Iso string `help:"ISO image ID" metavar:"IMAGE_ID"` - Ncpu int64 `help:"#CPU cores of VM server, default 1" default:"1" metavar:""` - Vga string `help:"VGA driver" choices:"std|vmware|cirrus|qxl"` - Vdi string `help:"VDI protocool" choices:"vnc|spice"` - Bios string `help:"BIOS" choices:"BIOS|UEFI"` - Desc string `help:"Description" metavar:""` - Boot string `help:"Boot device" metavar:"" choices:"disk|cdrom"` - NoAccountInit bool `help:"Not reset account password"` - AllowDelete bool `help:"Unlock server to allow deleting"` - ShutdownBehavior string `help:"Behavior after VM server shutdown, stop or terminate server" metavar:"" choices:"stop|terminate"` - AutoStart bool `help:"Auto start server after it is created"` - Zone string `help:"Preferred zone where virtual server should be created"` - Host string `help:"Preferred host where virtual server should be created"` - SchedTag []string `help:"Schedule policy, key = aggregate name, value = require|exclude|prefer|avoid" metavar:""` - Deploy []string `help:"Specify deploy files in virtual server file system"` - Group []string `help:"Group of virtual server"` - Project string `help:"'Owner project ID or Name"` - User string `help:"Owner user ID or Name"` - System bool `help:"Create a system VM, sysadmin ONLY option"` - Hypervisor string `help:"Hypervisor type" choices:"kvm|esxi|baremetal|container|aliyun"` - TaskNotify bool `help:"Setup task notify"` - Count int `help:"Create multiple simultaneously" default:"1"` - DryRun bool `help:"Dry run to test scheduler"` - RaidConfig []string `help:"Baremetal raid config"` - } - R(&ServerCreateOptions{}, "server-create", "Create a server", func(s *mcclient.ClientSession, args *ServerCreateOptions) error { - params := jsonutils.NewDict() - params.Add(jsonutils.NewString(args.NAME), "name") - params.Add(jsonutils.NewString(args.MEM), "vmem_size") - for i, d := range args.Disk { - params.Add(jsonutils.NewString(d), fmt.Sprintf("disk.%d", i)) + R(&options.ServerCreateOptions{}, "server-create", "Create a server", func(s *mcclient.ClientSession, opts *options.ServerCreateOptions) error { + params, err := opts.Params() + if err != nil { + return err } - for i, n := range args.Net { - params.Add(jsonutils.NewString(n), fmt.Sprintf("net.%d", i)) - } - for i, g := range args.IsolatedDevice { - params.Add(jsonutils.NewString(g), fmt.Sprintf("isolated_device.%d", i)) - } - for i, t := range args.SchedTag { - params.Add(jsonutils.NewString(t), fmt.Sprintf("schedtag.%d", i)) - } - if args.Ncpu > 0 { - params.Add(jsonutils.NewInt(args.Ncpu), "vcpu_count") - } - if len(args.Iso) > 0 { - params.Add(jsonutils.NewString(args.Iso), "cdrom") - } - if len(args.Vga) > 0 { - params.Add(jsonutils.NewString(args.Vga), "vga") - } - if args.NoAccountInit { - params.Add(jsonutils.JSONFalse, "reset_password") - } - if args.Password != "" { - params.Add(jsonutils.NewString(args.Password), "password") - } - if len(args.Vdi) > 0 { - params.Add(jsonutils.NewString(args.Vdi), "vdi") - } - if len(args.Bios) > 0 { - params.Add(jsonutils.NewString(args.Bios), "bios") - } - if len(args.Deploy) > 0 { - err := parseDeployList(args.Deploy, params) - if err != nil { - return err - } - } - if len(args.Boot) > 0 { - if args.Boot == "disk" { - params.Add(jsonutils.NewString("cdn"), "boot_order") - } else { - params.Add(jsonutils.NewString("dcn"), "boot_order") - } - } - if len(args.Desc) > 0 { - params.Add(jsonutils.NewString(args.Desc), "description") - } - if args.AllowDelete { - params.Add(jsonutils.JSONFalse, "disable_delete") - } - if len(args.ShutdownBehavior) > 0 { - params.Add(jsonutils.NewString(args.ShutdownBehavior), "shutdown_behavior") - } - if args.AutoStart { - params.Add(jsonutils.JSONTrue, "auto_start") - } - if len(args.Group) > 0 { - for i, g := range args.Group { - params.Add(jsonutils.NewString(g), fmt.Sprintf("group.%d", i)) - } - } - if len(args.Host) > 0 { - params.Add(jsonutils.NewString(args.Host), "prefer_host") - } else { - if len(args.Zone) > 0 { - params.Add(jsonutils.NewString(args.Zone), "prefer_zone") - } - } - if len(args.Project) > 0 { - params.Add(jsonutils.NewString(args.Project), "tenant") - } - if len(args.User) > 0 { - params.Add(jsonutils.NewString(args.User), "user") - } - if args.System { - params.Add(jsonutils.JSONTrue, "is_system") - } - if len(args.Hypervisor) > 0 { - params.Add(jsonutils.NewString(args.Hypervisor), "hypervisor") - } - if len(args.RaidConfig) > 0 { - if args.Hypervisor != "baremetal" { - return fmt.Errorf("RaidConfig is applicable to baremetal ONLY") - } - for i, conf := range args.RaidConfig { - params.Add(jsonutils.NewString(conf), fmt.Sprintf("baremetal_disk_config.%d", i)) - } - } - if args.DryRun { - params.Add(jsonutils.JSONTrue, "suggestion") - results, err := modules.SchedManager.DoScheduleListResult(s, params, args.Count) + count := options.IntV(opts.Count) + if options.BoolV(opts.DryRun) { + results, err := modules.SchedManager.DoScheduleListResult(s, params, count) if err != nil { return err } printList(results, []string{"id", "name", "rank", "capacity", "error"}) } else { - if args.TaskNotify { + taskNotify := options.BoolV(opts.TaskNotify) + if taskNotify { s.PrepareTask() } - if args.Count > 1 { - results := modules.Servers.BatchCreate(s, params, args.Count) + if count > 1 { + results := modules.Servers.BatchCreate(s, params, count) printBatchResults(results, modules.Servers.GetColumns(s)) } else { server, err := modules.Servers.Create(s, params) @@ -284,15 +72,15 @@ func init() { } printObject(server) } - if args.TaskNotify { + if taskNotify { s.WaitTaskNotify() } } return nil }) - R(&ServerShowOptions{}, "server-logininfo", "Get login info of a server", func(s *mcclient.ClientSession, args *ServerShowOptions) error { - srvid, e := modules.Servers.GetId(s, args.ID, nil) + R(&options.ServerIdOptions{}, "server-logininfo", "Get login info of a server", func(s *mcclient.ClientSession, opts *options.ServerIdOptions) error { + srvid, e := modules.Servers.GetId(s, opts.ID, nil) if e != nil { return e } @@ -304,83 +92,70 @@ func init() { return nil }) - type ServerOpsOptions struct { - ID []string `help:"ID of servers to operate" metavar:"SERVER"` - } - R(&ServerOpsOptions{}, "server-start", "Start servers", func(s *mcclient.ClientSession, args *ServerOpsOptions) error { - ret := modules.Servers.BatchPerformAction(s, args.ID, "start", nil) + R(&options.ServerIdsOptions{}, "server-start", "Start servers", func(s *mcclient.ClientSession, opts *options.ServerIdsOptions) error { + ret := modules.Servers.BatchPerformAction(s, opts.ID, "start", nil) printBatchResults(ret, modules.Servers.GetColumns(s)) return nil }) - R(&ServerOpsOptions{}, "server-syncstatus", "Sync servers status", func(s *mcclient.ClientSession, args *ServerOpsOptions) error { - ret := modules.Servers.BatchPerformAction(s, args.ID, "syncstatus", nil) + R(&options.ServerIdsOptions{}, "server-syncstatus", "Sync servers status", func(s *mcclient.ClientSession, opts *options.ServerIdsOptions) error { + ret := modules.Servers.BatchPerformAction(s, opts.ID, "syncstatus", nil) printBatchResults(ret, modules.Servers.GetColumns(s)) return nil }) - R(&ServerOpsOptions{}, "server-sync", "Sync servers status", func(s *mcclient.ClientSession, args *ServerOpsOptions) error { - ret := modules.Servers.BatchPerformAction(s, args.ID, "sync", nil) + R(&options.ServerIdsOptions{}, "server-sync", "Sync servers status", func(s *mcclient.ClientSession, opts *options.ServerIdsOptions) error { + ret := modules.Servers.BatchPerformAction(s, opts.ID, "sync", nil) printBatchResults(ret, modules.Servers.GetColumns(s)) return nil }) - type ServerStopOptions struct { - ID []string `help:"ID or Name of server"` - Force bool `help:"Stop server forcefully"` - } - R(&ServerStopOptions{}, "server-stop", "Stop servers", func(s *mcclient.ClientSession, args *ServerStopOptions) error { - params := jsonutils.NewDict() - if args.Force { - params.Add(jsonutils.JSONTrue, "is_force") - } else { - params.Add(jsonutils.JSONFalse, "is_force") + R(&options.ServerStopOptions{}, "server-stop", "Stop servers", func(s *mcclient.ClientSession, opts *options.ServerStopOptions) error { + params, err := options.StructToParams(opts) + if err != nil { + return err } - ret := modules.Servers.BatchPerformAction(s, args.ID, "stop", params) + ret := modules.Servers.BatchPerformAction(s, opts.ID, "stop", params) printBatchResults(ret, modules.Servers.GetColumns(s)) return nil }) - R(&ServerOpsOptions{}, "server-suspend", "Suspend servers", func(s *mcclient.ClientSession, args *ServerOpsOptions) error { - ret := modules.Servers.BatchPerformAction(s, args.ID, "suspend", nil) + R(&options.ServerIdsOptions{}, "server-suspend", "Suspend servers", func(s *mcclient.ClientSession, opts *options.ServerIdsOptions) error { + ret := modules.Servers.BatchPerformAction(s, opts.ID, "suspend", nil) printBatchResults(ret, modules.Servers.GetColumns(s)) return nil }) - R(&ServerOpsOptions{}, "server-reset", "Reset servers", func(s *mcclient.ClientSession, args *ServerOpsOptions) error { - ret := modules.Servers.BatchPerformAction(s, args.ID, "reset", nil) + R(&options.ServerIdsOptions{}, "server-reset", "Reset servers", func(s *mcclient.ClientSession, opts *options.ServerIdsOptions) error { + ret := modules.Servers.BatchPerformAction(s, opts.ID, "reset", nil) printBatchResults(ret, modules.Servers.GetColumns(s)) return nil }) - R(&ServerOpsOptions{}, "server-purge", "Purge obsolete servers", func(s *mcclient.ClientSession, args *ServerOpsOptions) error { - ret := modules.Servers.BatchPerformAction(s, args.ID, "purge", nil) + R(&options.ServerIdsOptions{}, "server-purge", "Purge obsolete servers", func(s *mcclient.ClientSession, opts *options.ServerIdsOptions) error { + ret := modules.Servers.BatchPerformAction(s, opts.ID, "purge", nil) printBatchResults(ret, modules.Servers.GetColumns(s)) return nil }) - type ServerDeleteOptions struct { - OverridePendingDelete bool `help:"Delete server directly instead of pending delete"` - ServerOpsOptions - } - R(&ServerDeleteOptions{}, "server-delete", "Delete servers", func(s *mcclient.ClientSession, args *ServerDeleteOptions) error { - params := jsonutils.NewDict() - if args.OverridePendingDelete { - params.Add(jsonutils.JSONTrue, "override_pending_delete") + R(&options.ServerDeleteOptions{}, "server-delete", "Delete servers", func(s *mcclient.ClientSession, opts *options.ServerDeleteOptions) error { + params, err := options.StructToParams(opts) + if err != nil { + return err } - ret := modules.Servers.BatchDeleteWithParam(s, args.ID, params, nil) + ret := modules.Servers.BatchDeleteWithParam(s, opts.ID, params, nil) printBatchResults(ret, modules.Servers.GetColumns(s)) return nil }) - R(&ServerOpsOptions{}, "server-cancel-delete", "Cancel pending delete servers", func(s *mcclient.ClientSession, args *ServerOpsOptions) error { - ret := modules.Servers.BatchPerformAction(s, args.ID, "cancel-delete", nil) + R(&options.ServerIdsOptions{}, "server-cancel-delete", "Cancel pending delete servers", func(s *mcclient.ClientSession, opts *options.ServerIdsOptions) error { + ret := modules.Servers.BatchPerformAction(s, opts.ID, "cancel-delete", nil) printBatchResults(ret, modules.Servers.GetColumns(s)) return nil }) - R(&ServerShowOptions{}, "server-vnc", "Show vnc info of server", func(s *mcclient.ClientSession, args *ServerShowOptions) error { - ret, e := modules.Servers.GetSpecific(s, args.ID, "vnc", nil) + R(&options.ServerIdOptions{}, "server-vnc", "Show vnc info of server", func(s *mcclient.ClientSession, opts *options.ServerIdOptions) error { + ret, e := modules.Servers.GetSpecific(s, opts.ID, "vnc", nil) if e != nil { return e } @@ -388,8 +163,8 @@ func init() { return nil }) - R(&ServerShowOptions{}, "server-desc", "Show desc info of server", func(s *mcclient.ClientSession, args *ServerShowOptions) error { - ret, e := modules.Servers.GetSpecific(s, args.ID, "desc", nil) + R(&options.ServerIdOptions{}, "server-desc", "Show desc info of server", func(s *mcclient.ClientSession, opts *options.ServerIdOptions) error { + ret, e := modules.Servers.GetSpecific(s, opts.ID, "desc", nil) if e != nil { return e } @@ -397,8 +172,8 @@ func init() { return nil }) - R(&ServerShowOptions{}, "server-status", "Show status of server", func(s *mcclient.ClientSession, args *ServerShowOptions) error { - ret, e := modules.Servers.GetSpecific(s, args.ID, "status", nil) + R(&options.ServerIdOptions{}, "server-status", "Show status of server", func(s *mcclient.ClientSession, opts *options.ServerIdOptions) error { + ret, e := modules.Servers.GetSpecific(s, opts.ID, "status", nil) if e != nil { return e } @@ -406,79 +181,25 @@ func init() { return nil }) - type ServerUpdateOptions struct { - ID []string `help:"IDs or Names of servers to update"` - Name string `help:"New name to change"` - Vmem string `help:"Memory size"` - Ncpu int64 `help:"CPU count"` - Vga string `help:"VGA driver" choices:"std|vmware|cirrus|qxl"` - Vdi string `help:"VDI protocol" choices:"vnc|spice"` - Bios string `help:"BIOS" choices:"BIOS|UEFI"` - Desc string `help:"Description"` - Boot string `help:"Boot device" choices:"disk|cdrom"` - Delete string `help:"Lock server to prevent from deleting" choices:"enable|disable"` - ShutdownBehavior string `help:"Behavior after VM server shutdown, stop or terminate server" choices:"stop|terminate"` - } - R(&ServerUpdateOptions{}, "server-update", "Update servers", func(s *mcclient.ClientSession, args *ServerUpdateOptions) error { - params := jsonutils.NewDict() - if len(args.Name) > 0 { - params.Add(jsonutils.NewString(args.Name), "name") - } - if args.Ncpu > 0 { - params.Add(jsonutils.NewInt(args.Ncpu), "vcpu_count") - } - if len(args.Vmem) > 0 { - params.Add(jsonutils.NewString(args.Vmem), "vmem_size") - } - if len(args.Vga) > 0 { - params.Add(jsonutils.NewString(args.Vga), "vga") - } - if len(args.Vdi) > 0 { - params.Add(jsonutils.NewString(args.Vdi), "vdi") - } - if len(args.Bios) > 0 { - params.Add(jsonutils.NewString(args.Bios), "bios") - } - if len(args.Desc) > 0 { - params.Add(jsonutils.NewString(args.Desc), "description") - } - if len(args.Boot) > 0 { - if args.Boot == "disk" { - params.Add(jsonutils.NewString("cdn"), "boot_order") - } else { - params.Add(jsonutils.NewString("dcn"), "boot_order") - } - } - if len(args.Delete) > 0 { - if args.Delete == "disable" { - params.Add(jsonutils.JSONTrue, "disable_delete") - } else { - params.Add(jsonutils.JSONFalse, "disable_delete") - } - } - if len(args.ShutdownBehavior) > 0 { - params.Add(jsonutils.NewString(args.ShutdownBehavior), "shutdown_behavior") + R(&options.ServerUpdateOptions{}, "server-update", "Update servers", func(s *mcclient.ClientSession, opts *options.ServerUpdateOptions) error { + params, err := opts.Params() + if err != nil { + return err } if params.Size() == 0 { return InvalidUpdateError() } - result := modules.Servers.BatchPut(s, args.ID, params) + result := modules.Servers.BatchPut(s, opts.ID, params) printBatchResults(result, modules.Servers.GetColumns(s)) return nil }) - type ServerSendKeyOptions struct { - SERVER string `help:"ID of virtual server to get monitor info"` - KEYS string `help:"Special keys to send, eg. ctrl, alt, f12, shift, etc, separated by \"-\""` - Hold int64 `help:"Hold key for specified milliseconds"` - } - R(&ServerSendKeyOptions{}, "server-send-keys", "Send keys to server", func(s *mcclient.ClientSession, args *ServerSendKeyOptions) error { - params := jsonutils.NewDict() - params.Add(jsonutils.NewString(args.KEYS), "keys") - if args.Hold > 0 { - params.Add(jsonutils.NewInt(args.Hold), "duration") + R(&options.ServerSendKeyOptions{}, "server-send-keys", "Send keys to server", func(s *mcclient.ClientSession, opts *options.ServerSendKeyOptions) error { + params, err := options.StructToParams(opts) + if err != nil { + return err } - srv, err := modules.Servers.PerformAction(s, args.SERVER, "sendkeys", params) + srv, err := modules.Servers.PerformAction(s, opts.ID, "sendkeys", params) if err != nil { return err } @@ -486,34 +207,12 @@ func init() { return nil }) - type ServerDeployOptions struct { - ID string `help:"ID or Name of server"` - Keypair string `help:"ssh Keypair used for login"` - DeleteKeypair bool `help:"Remove ssh Keypairs"` - Deploy []string `help:"Specify deploy files in virtual server file system"` - ResetPassword bool `help:"Force reset password"` - Password string `help:"Default user password"` - } - R(&ServerDeployOptions{}, "server-deploy", "Deploy hostname and keypair to a stopped virtual server", func(s *mcclient.ClientSession, args *ServerDeployOptions) error { - params := jsonutils.NewDict() - if args.DeleteKeypair { - params.Add(jsonutils.JSONTrue, "__delete_keypair__") - } else if len(args.Keypair) > 0 { - params.Add(jsonutils.NewString(args.Keypair), "keypair") + R(&options.ServerDeployOptions{}, "server-deploy", "Deploy hostname and keypair to a stopped virtual server", func(s *mcclient.ClientSession, opts *options.ServerDeployOptions) error { + params, err := opts.Params() + if err != nil { + return err } - if len(args.Deploy) > 0 { - e := parseDeployList(args.Deploy, params) - if e != nil { - return e - } - } - if args.ResetPassword { - params.Add(jsonutils.JSONTrue, "reset_password") - } - if args.Password != "" { - params.Add(jsonutils.NewString(args.Password), "password") - } - srv, e := modules.Servers.PerformAction(s, args.ID, "deploy", params) + srv, e := modules.Servers.PerformAction(s, opts.ID, "deploy", params) if e != nil { return e } @@ -521,15 +220,12 @@ func init() { return nil }) - type ServerSecGroupOptions struct { - ID string `help:"ID or Name of server" metavar:"Guest"` - SecGrp string `help:"ID of Security Group" metavar:"Security Group" positional:"true"` - } - - R(&ServerSecGroupOptions{}, "server-assign-secgroup", "Assign security group to a VM", func(s *mcclient.ClientSession, args *ServerSecGroupOptions) error { - params := jsonutils.NewDict() - params.Add(jsonutils.NewString(args.SecGrp), "secgrp") - srv, e := modules.Servers.PerformAction(s, args.ID, "assign-secgroup", params) + R(&options.ServerSecGroupOptions{}, "server-assign-secgroup", "Assign security group to a VM", func(s *mcclient.ClientSession, opts *options.ServerSecGroupOptions) error { + params, err := options.StructToParams(opts) + if err != nil { + return err + } + srv, e := modules.Servers.PerformAction(s, opts.ID, "assign-secgroup", params) if e != nil { return e } @@ -537,10 +233,12 @@ func init() { return nil }) - R(&ServerSecGroupOptions{}, "server-assign-admin-secgroup", "Assign administrative security group to a VM", func(s *mcclient.ClientSession, args *ServerSecGroupOptions) error { - params := jsonutils.NewDict() - params.Add(jsonutils.NewString(args.SecGrp), "secgrp") - srv, e := modules.Servers.PerformAction(s, args.ID, "assign-admin-secgroup", params) + R(&options.ServerSecGroupOptions{}, "server-assign-admin-secgroup", "Assign administrative security group to a VM", func(s *mcclient.ClientSession, opts *options.ServerSecGroupOptions) error { + params, err := options.StructToParams(opts) + if err != nil { + return err + } + srv, e := modules.Servers.PerformAction(s, opts.ID, "assign-admin-secgroup", params) if e != nil { return e } @@ -548,12 +246,8 @@ func init() { return nil }) - type ServerRevokeSecGroupOptions struct { - ID string `help:"ID or Name of server" metavar:"Guest"` - } - - R(&ServerRevokeSecGroupOptions{}, "server-revoke-secgroup", "Assign security group to a VM", func(s *mcclient.ClientSession, args *ServerRevokeSecGroupOptions) error { - srv, e := modules.Servers.PerformAction(s, args.ID, "revoke-secgroup", nil) + R(&options.ServerIdOptions{}, "server-revoke-secgroup", "Assign security group to a VM", func(s *mcclient.ClientSession, opts *options.ServerIdOptions) error { + srv, e := modules.Servers.PerformAction(s, opts.ID, "revoke-secgroup", nil) if e != nil { return e } @@ -561,8 +255,8 @@ func init() { return nil }) - R(&ServerRevokeSecGroupOptions{}, "server-revoke-admin-secgroup", "Assign administrative security group to a VM", func(s *mcclient.ClientSession, args *ServerRevokeSecGroupOptions) error { - srv, e := modules.Servers.PerformAction(s, args.ID, "revoke-admin-secgroup", nil) + R(&options.ServerIdOptions{}, "server-revoke-admin-secgroup", "Assign administrative security group to a VM", func(s *mcclient.ClientSession, opts *options.ServerIdOptions) error { + srv, e := modules.Servers.PerformAction(s, opts.ID, "revoke-admin-secgroup", nil) if e != nil { return e } @@ -570,14 +264,12 @@ func init() { return nil }) - type ServerMonitorOptions struct { - SERVER string `help:"ID or Name of server"` - CMD string `help:"Qemu Monitor command to send"` - } - R(&ServerMonitorOptions{}, "server-monitor", "Send commands to qemu monitor", func(s *mcclient.ClientSession, args *ServerMonitorOptions) error { - query := jsonutils.NewDict() - query.Add(jsonutils.NewString(args.CMD), "command") - ret, err := modules.Servers.GetSpecific(s, args.SERVER, "monitor", query) + R(&options.ServerMonitorOptions{}, "server-monitor", "Send commands to qemu monitor", func(s *mcclient.ClientSession, opts *options.ServerMonitorOptions) error { + params, err := options.StructToParams(opts) + if err != nil { + return err + } + ret, err := modules.Servers.GetSpecific(s, opts.ID, "monitor", params) if err != nil { return err } @@ -589,28 +281,12 @@ func init() { return nil }) - type ServerSaveImageOptions struct { - SERVER string `help:"ID or name of server"` - IMAGE string `help:"Image name"` - Public bool `help:"Make the image public available"` - Format string `help:"image format" choices:"vmdk|qcow2"` - Notes string `help:"Notes about the image"` - } - R(&ServerSaveImageOptions{}, "server-save-image", "Save root disk to new image and upload to glance.", func(s *mcclient.ClientSession, args *ServerSaveImageOptions) error { - params := jsonutils.NewDict() - params.Add(jsonutils.NewString(args.IMAGE), "name") - if args.Public { - params.Add(jsonutils.JSONTrue, "is_public") - } else { - params.Add(jsonutils.JSONFalse, "is_public") + R(&options.ServerSaveImageOptions{}, "server-save-image", "Save root disk to new image and upload to glance.", func(s *mcclient.ClientSession, opts *options.ServerSaveImageOptions) error { + params, err := options.StructToParams(opts) + if err != nil { + return err } - if len(args.Format) > 0 { - params.Add(jsonutils.NewString(args.Format), "format") - } - if len(args.Notes) > 0 { - params.Add(jsonutils.NewString(args.Notes), "notes") - } - srv, err := modules.Servers.PerformAction(s, args.SERVER, "save-image", params) + srv, err := modules.Servers.PerformAction(s, opts.ID, "save-image", params) if err != nil { return err } @@ -619,23 +295,23 @@ func init() { }) type ServerChangeOwnerOptions struct { - SERVER string `help:"Server to change owner"` + ID string `help:"Server to change owner"` PROJECT string `help:"Project ID or change"` RawId bool `help:"User raw ID, instead of name"` } - R(&ServerChangeOwnerOptions{}, "server-change-owner", "Change owner porject of a server", func(s *mcclient.ClientSession, args *ServerChangeOwnerOptions) error { + R(&ServerChangeOwnerOptions{}, "server-change-owner", "Change owner porject of a server", func(s *mcclient.ClientSession, opts *ServerChangeOwnerOptions) error { params := jsonutils.NewDict() - if args.RawId { - projid, err := modules.Projects.GetId(s, args.PROJECT, nil) + if opts.RawId { + projid, err := modules.Projects.GetId(s, opts.PROJECT, nil) if err != nil { return err } params.Add(jsonutils.NewString(projid), "tenant") params.Add(jsonutils.JSONTrue, "raw_id") } else { - params.Add(jsonutils.NewString(args.PROJECT), "tenant") + params.Add(jsonutils.NewString(opts.PROJECT), "tenant") } - srv, err := modules.Servers.PerformAction(s, args.SERVER, "change-owner", params) + srv, err := modules.Servers.PerformAction(s, opts.ID, "change-owner", params) if err != nil { return err } @@ -643,28 +319,12 @@ func init() { return nil }) - type ServerRebuildRootOptions struct { - SERVER string `help:"Server to rebuild root"` - AutoStart bool `help:"Auto start server after it is created"` - Image string `help:"New root Image template ID"` - Keypair string `help:"ssh Keypair used for login"` - Password string `help:"Default user password"` - } - R(&ServerRebuildRootOptions{}, "server-rebuild-root", "Rebuild VM root image with new template", func(s *mcclient.ClientSession, args *ServerRebuildRootOptions) error { - params := jsonutils.NewDict() - if len(args.Image) > 0 { - params.Add(jsonutils.NewString(args.Image), "image_id") + R(&options.ServerRebuildRootOptions{}, "server-rebuild-root", "Rebuild VM root image with new template", func(s *mcclient.ClientSession, opts *options.ServerRebuildRootOptions) error { + params, err := options.StructToParams(opts) + if err != nil { + return err } - if args.AutoStart { - params.Add(jsonutils.JSONTrue, "auto_start") - } - if args.Keypair != "" { - params.Add(jsonutils.NewString(args.Keypair), "keypair") - } - if args.Password != "" { - params.Add(jsonutils.NewString(args.Password), "password") - } - srv, err := modules.Servers.PerformAction(s, args.SERVER, "rebuild-root", params) + srv, err := modules.Servers.PerformAction(s, opts.ID, "rebuild-root", params) if err != nil { return err } @@ -672,29 +332,15 @@ func init() { return nil }) - type ServerChangeConfigOptions struct { - SERVER string `help:"Server to rebuild root"` - Ncpu int64 `help:"New number of Virtual CPU cores"` - Vmem string `help:"New memory size"` - Disk []string `help:"Data disk description, from the 1st data disk to the last one, empty string if no change for this data disk"` - } - R(&ServerChangeConfigOptions{}, "server-change-config", "Change configuration of VM", func(s *mcclient.ClientSession, args *ServerChangeConfigOptions) error { - params := jsonutils.NewDict() - if args.Ncpu > 0 { - params.Add(jsonutils.NewInt(args.Ncpu), "vcpu_count") - } - if len(args.Vmem) > 0 { - params.Add(jsonutils.NewString(args.Vmem), "vmem_size") - } - if len(args.Disk) > 0 { - for idx, disk := range args.Disk { - params.Add(jsonutils.NewString(disk), fmt.Sprintf("disk.%d", (idx+1))) - } + R(&options.ServerChangeConfigOptions{}, "server-change-config", "Change configuration of VM", func(s *mcclient.ClientSession, opts *options.ServerChangeConfigOptions) error { + params, err := options.StructToParams(opts) + if err != nil { + return err } if params.Size() == 0 { return InvalidUpdateError() } - srv, err := modules.Servers.PerformAction(s, args.SERVER, "change-config", params) + srv, err := modules.Servers.PerformAction(s, opts.ID, "change-config", params) if err != nil { return err } @@ -706,8 +352,8 @@ func init() { ID string `help:"server ID or Name"` ISO string `help:"Glance image ID of the ISO"` } - R(&ServerInsertISOOptions{}, "server-insert-iso", "Insert an ISO image into server's cdrom", func(s *mcclient.ClientSession, args *ServerInsertISOOptions) error { - img, err := modules.Images.Get(s, args.ISO, nil) + R(&ServerInsertISOOptions{}, "server-insert-iso", "Insert an ISO image into server's cdrom", func(s *mcclient.ClientSession, opts *ServerInsertISOOptions) error { + img, err := modules.Images.Get(s, opts.ISO, nil) if err != nil { return err } @@ -717,7 +363,7 @@ func init() { } params := jsonutils.NewDict() params.Add(jsonutils.NewString(imgId), "image_id") - result, err := modules.Servers.PerformAction(s, args.ID, "insertiso", params) + result, err := modules.Servers.PerformAction(s, opts.ID, "insertiso", params) if err != nil { return err } @@ -725,8 +371,8 @@ func init() { return nil }) - R(&ServerShowOptions{}, "server-eject-iso", "Eject iso from servers' cdrom", func(s *mcclient.ClientSession, args *ServerShowOptions) error { - result, err := modules.Servers.PerformAction(s, args.ID, "ejectiso", nil) + R(&options.ServerIdOptions{}, "server-eject-iso", "Eject iso from servers' cdrom", func(s *mcclient.ClientSession, opts *options.ServerIdOptions) error { + result, err := modules.Servers.PerformAction(s, opts.ID, "ejectiso", nil) if err != nil { return err } @@ -734,8 +380,8 @@ func init() { return nil }) - R(&ServerShowOptions{}, "server-iso", "Show server's mounting ISO information", func(s *mcclient.ClientSession, args *ServerShowOptions) error { - results, err := modules.Servers.GetSpecific(s, args.ID, "iso", nil) + R(&options.ServerIdOptions{}, "server-iso", "Show server's mounting ISO information", func(s *mcclient.ClientSession, opts *options.ServerIdOptions) error { + results, err := modules.Servers.GetSpecific(s, opts.ID, "iso", nil) if err != nil { return err } diff --git a/pkg/mcclient/options/servers.go b/pkg/mcclient/options/servers.go new file mode 100644 index 0000000000..9018347ab8 --- /dev/null +++ b/pkg/mcclient/options/servers.go @@ -0,0 +1,273 @@ +package options + +import ( + "fmt" + "io/ioutil" + "strings" + + "yunion.io/x/jsonutils" +) + +type ServerListOptions struct { + Zone string `help:"Zone ID or Name"` + Wire string `help:"Wire ID or Name"` + Network string `help:"Network ID or Name"` + Disk string `help:"Disk ID or Name"` + Host string `help:"Host ID or Name"` + Baremetal *bool `help:"Show baremetal servers"` + Gpu *bool `help:"Show gpu servers"` + Secgroup string `help:"Secgroup ID or Name"` + AdminSecgroup string `help:"AdminSecgroup ID or Name"` + Hypervisor string `help:"Show server of hypervisor" choices:"kvm|esxi|container|baremetal|aliyun"` + Manager string `help:"Show servers imported from manager"` + BaseListOptions +} + +type ServerIdOptions struct { + ID string `help:"ID or name of the server" json:"-"` +} + +type ServerIdsOptions struct { + ID []string `help:"ID of servers to operate" metavar:"SERVER" json:"-"` +} + +type ServerShowOptions struct { + ID string `help:"ID or name of the server" json:"-"` + WithMeta *bool `help:"With meta data"` +} + +type ServerDeployInfo struct { + Action string + Path string + Content string +} + +func ParseServerDeployInfo(info string) (*ServerDeployInfo, error) { + sdi := &ServerDeployInfo{} + colon := strings.IndexByte(info, ':') + if colon <= 0 { + return nil, fmt.Errorf("malformed deploy info: %s", info) + } + if info[0] == '+' { + sdi.Action = "append" + sdi.Path = info[1:colon] + } else { + sdi.Action = "create" + sdi.Path = info[:colon] + } + nameOrContent := info[colon+1:] + data, err := ioutil.ReadFile(nameOrContent) + if err != nil { + sdi.Content = nameOrContent + } else { + sdi.Content = string(data) + } + return sdi, nil +} + +func ParseServerDeployInfoList(list []string) (*jsonutils.JSONDict, error) { + params := jsonutils.NewDict() + for i, info := range list { + ret, err := ParseServerDeployInfo(info) + if err != nil { + return nil, err + } + params.Set(fmt.Sprintf("deploy.%d.action", i), jsonutils.NewString(ret.Action)) + params.Set(fmt.Sprintf("deploy.%d.path", i), jsonutils.NewString(ret.Path)) + params.Set(fmt.Sprintf("deploy.%d.content", i), jsonutils.NewString(ret.Content)) + } + return params, nil +} + +type ServerCreateOptions struct { + NAME string `help:"Name of server"` + MEM string `help:"Memory size" metavar:"MEMORY" json:"vmem_size"` + Disk []string `help:"Disk descriptions" nargs:"+"` + Net []string `help:"Network descriptions" metavar:"NETWORK"` + IsolatedDevice []string `help:"Isolated device model or ID" metavar:"ISOLATED_DEVICE"` + Keypair string `help:"SSH Keypair"` + Password string `help:"Default user password"` + Iso string `help:"ISO image ID" metavar:"IMAGE_ID" json:"cdrom"` + Ncpu *int `help:"#CPU cores of VM server, default 1" default:"1" metavar:"" json:"vcpu_count"` + Vga string `help:"VGA driver" choices:"std|vmware|cirrus|qxl"` + Vdi string `help:"VDI protocool" choices:"vnc|spice"` + Bios string `help:"BIOS" choices:"BIOS|UEFI"` + Desc string `help:"Description" metavar:"" json:"description"` + Boot string `help:"Boot device" metavar:"" choices:"disk|cdrom" json:"-"` + NoAccountInit *bool `help:"Not reset account password" json:"reset_password"` + AllowDelete *bool `help:"Unlock server to allow deleting" json:"-"` + ShutdownBehavior string `help:"Behavior after VM server shutdown, stop or terminate server" metavar:"" choices:"stop|terminate"` + AutoStart *bool `help:"Auto start server after it is created"` + Zone string `help:"Preferred zone where virtual server should be created" json:"prefer_zone"` + Host string `help:"Preferred host where virtual server should be created" json:"prefer_host"` + SchedTag []string `help:"Schedule policy, key = aggregate name, value = require|exclude|prefer|avoid" metavar:""` + Deploy []string `help:"Specify deploy files in virtual server file system" json:"-"` + Group []string `help:"Group of virtual server"` + Project string `help:"'Owner project ID or Name" json:"tenant"` + User string `help:"Owner user ID or Name"` + System *bool `help:"Create a system VM, sysadmin ONLY option" json:"is_system"` + Hypervisor string `help:"Hypervisor type" choices:"kvm|esxi|baremetal|container|aliyun"` + TaskNotify *bool `help:"Setup task notify" json:"-"` + Count *int `help:"Create multiple simultaneously" default:"1" json:"-"` + DryRun *bool `help:"Dry run to test scheduler" json:"-"` + RaidConfig []string `help:"Baremetal raid config" json:"-"` +} + +func (opts *ServerCreateOptions) Params() (*jsonutils.JSONDict, error) { + params, err := optionsStructToParams(opts) + if err != nil { + return nil, err + } + + { + deployParams, err := ParseServerDeployInfoList(opts.Deploy) + if err != nil { + return nil, err + } + params.Update(deployParams) + } + + if len(opts.Boot) > 0 { + if opts.Boot == "disk" { + params.Set("boot_order", jsonutils.NewString("cdn")) + } else { + params.Set("boot_order", jsonutils.NewString("dcn")) + } + } + + if BoolV(opts.AllowDelete) { + params.Set("disable_delete", jsonutils.JSONFalse) + } + + if len(opts.RaidConfig) > 0 { + if opts.Hypervisor != "baremetal" { + return nil, fmt.Errorf("RaidConfig is applicable to baremetal ONLY") + } + for i, conf := range opts.RaidConfig { + params.Set(fmt.Sprintf("baremetal_disk_config.%d", i), jsonutils.NewString(conf)) + } + } + + if BoolV(opts.DryRun) { + params.Set("suggestion", jsonutils.JSONTrue) + } + return params, nil +} + +type ServerStopOptions struct { + ID []string `help:"ID or Name of server" json:"-"` + Force *bool `help:"Stop server forcefully" json:"is_force"` +} + +type ServerUpdateOptions struct { + ID []string `help:"IDs or Names of servers to update" json:"-"` + Name string `help:"New name to change"` + Vmem string `help:"Memory size" json:"vmem_size"` + Ncpu *int `help:"CPU count" json:"vcpu_count"` + Vga string `help:"VGA driver" choices:"std|vmware|cirrus|qxl"` + Vdi string `help:"VDI protocol" choices:"vnc|spice"` + Bios string `help:"BIOS" choices:"BIOS|UEFI"` + Desc string `help:"Description" json:"description"` + Boot string `help:"Boot device" choices:"disk|cdrom"` + Delete string `help:"Lock server to prevent from deleting" choices:"enable|disable" json:"-"` + ShutdownBehavior string `help:"Behavior after VM server shutdown, stop or terminate server" choices:"stop|terminate"` +} + +func (opts *ServerUpdateOptions) Params() (*jsonutils.JSONDict, error) { + params, err := optionsStructToParams(opts) + if err != nil { + return nil, err + } + + if len(opts.Boot) > 0 { + if opts.Boot == "disk" { + params.Set("boot_order", jsonutils.NewString("cdn")) + } else { + params.Set("boot_order", jsonutils.NewString("dcn")) + } + } + if len(opts.Delete) > 0 { + if opts.Delete == "disable" { + params.Set("disable_delete", jsonutils.JSONTrue) + } else { + params.Set("disable_delete", jsonutils.JSONFalse) + } + } + return params, nil +} + +type ServerDeleteOptions struct { + ID []string `help:"ID of servers to operate" metavar:"SERVER" json:"-"` + OverridePendingDelete *bool `help:"Delete server directly instead of pending delete"` +} + +type ServerDeployOptions struct { + ID string `help:"ID or Name of server" json:"-"` + Keypair string `help:"ssh Keypair used for login" json:"-"` + DeleteKeypair *bool `help:"Remove ssh Keypairs" json:"-"` + Deploy []string `help:"Specify deploy files in virtual server file system" json:"-"` + ResetPassword *bool `help:"Force reset password"` + Password string `help:"Default user password"` +} + +func (opts *ServerDeployOptions) Params() (*jsonutils.JSONDict, error) { + params, err := optionsStructToParams(opts) + if err != nil { + return nil, err + } + { + deleteKeyPair := BoolV(opts.DeleteKeypair) + if deleteKeyPair { + params.Add(jsonutils.JSONTrue, "__delete_keypair__") + } else if len(opts.Keypair) > 0 { + params.Add(jsonutils.NewString(opts.Keypair), "keypair") + } + } + { + deployParams, err := ParseServerDeployInfoList(opts.Deploy) + if err != nil { + return nil, err + } + params.Update(deployParams) + } + return params, nil +} + +type ServerSecGroupOptions struct { + ID string `help:"ID or Name of server" metavar:"Guest" json:"-"` + SecGrp string `help:"ID of Security Group" metavar:"Security Group" positional:"true"` +} + +type ServerSendKeyOptions struct { + ID string `help:"ID or Name of server" metavar:"Guest" json:"-"` + KEYS string `help:"Special keys to send, eg. ctrl, alt, f12, shift, etc, separated by \"-\""` + Hold *uint `help:"Hold key for specified milliseconds" json:"duration"` +} + +type ServerMonitorOptions struct { + ID string `help:"ID or Name of server" json:"-"` + CMD string `help:"Qemu Monitor command to send"` +} + +type ServerSaveImageOptions struct { + ID string `help:"ID or name of server" json:"-"` + IMAGE string `help:"Image name" json:"name"` + Public *bool `help:"Make the image public available" json:"is_public"` + Format string `help:"image format" choices:"vmdk|qcow2"` + Notes string `help:"Notes about the image"` +} + +type ServerRebuildRootOptions struct { + ID string `help:"Server to rebuild root" json:"-"` + Image string `help:"New root Image template ID" json:"image_id"` + Keypair string `help:"ssh Keypair used for login"` + Password string `help:"Default user password"` + AutoStart *bool `help:"Auto start server after it is created"` +} + +type ServerChangeConfigOptions struct { + ID string `help:"Server to rebuild root" json:"-"` + Ncpu *int `help:"New number of Virtual CPU cores" json:"vcpu_count"` + Vmem string `help:"New memory size" json:"vmem_size"` + Disk []string `help:"Data disk description, from the 1st data disk to the last one, empty string if no change for this data disk"` +} From a1f67a60de4a1419116113db240a00d60a803800 Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Thu, 30 Aug 2018 03:22:48 +0000 Subject: [PATCH 14/32] options: server-reset: pass is_hard only when set --- pkg/mcclient/options/servers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/mcclient/options/servers.go b/pkg/mcclient/options/servers.go index a3c098efbc..6acc7b2dd1 100644 --- a/pkg/mcclient/options/servers.go +++ b/pkg/mcclient/options/servers.go @@ -274,5 +274,5 @@ type ServerChangeConfigOptions struct { type ServerResetOptions struct { ID []string `help:"ID of servers to operate" metavar:"SERVER" json:"-"` - Hard bool `help:"Hard reset or not; default soft" json:"is_hard"` + Hard *bool `help:"Hard reset or not; default soft" json:"is_hard"` } From a301ee4243dce93e2508532251cec744c0a95a9b Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Thu, 30 Aug 2018 14:44:16 +0800 Subject: [PATCH 15/32] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=EF=BC=9Aregion?= =?UTF-8?q?=E5=88=9A=E5=90=AF=E5=8A=A8=E6=9C=AA=E8=8E=B7=E5=BE=97token?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E9=AA=8C=E8=AF=81API=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E6=8A=A5500=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/mcclient/auth/auth.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/mcclient/auth/auth.go b/pkg/mcclient/auth/auth.go index 4e0957e66a..ab37809305 100644 --- a/pkg/mcclient/auth/auth.go +++ b/pkg/mcclient/auth/auth.go @@ -123,6 +123,9 @@ func newAuthManager(cli *mcclient.Client, info *AuthInfo) *authManager { } func (a *authManager) verify(token string) (mcclient.TokenCredential, error) { + if a.adminCredential == nil { + return nil, fmt.Errorf("No valid admin token credential") + } cred, err := a.tokenCacheVerify.Verify(a.client, a.adminCredential.GetTokenString(), token) if err != nil { return nil, err From 7ad2624a7cdbdc13adbab2f2334f0848836f9557 Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Thu, 9 Aug 2018 15:24:40 +0000 Subject: [PATCH 16/32] cloudcommon: add validator helpers --- pkg/cloudcommon/validators/choices.go | 31 ++ pkg/cloudcommon/validators/doc.go | 1 + pkg/cloudcommon/validators/errors.go | 106 ++++ pkg/cloudcommon/validators/validators.go | 427 +++++++++++++++ pkg/cloudcommon/validators/validators_test.go | 500 ++++++++++++++++++ 5 files changed, 1065 insertions(+) create mode 100644 pkg/cloudcommon/validators/choices.go create mode 100644 pkg/cloudcommon/validators/doc.go create mode 100644 pkg/cloudcommon/validators/errors.go create mode 100644 pkg/cloudcommon/validators/validators.go create mode 100644 pkg/cloudcommon/validators/validators_test.go diff --git a/pkg/cloudcommon/validators/choices.go b/pkg/cloudcommon/validators/choices.go new file mode 100644 index 0000000000..83188a7ef0 --- /dev/null +++ b/pkg/cloudcommon/validators/choices.go @@ -0,0 +1,31 @@ +package validators + +import ( + "strings" +) + +type Empty struct{} +type Choices map[string]Empty + +func NewChoices(choices ...string) Choices { + cs := Choices{} + for _, choice := range choices { + cs[choice] = Empty{} + } + return cs +} + +func (cs Choices) Has(choice string) bool { + _, ok := cs[choice] + return ok +} + +func (cs Choices) String() string { + choices := make([]string, len(cs)) + i := 0 + for choice, _ := range cs { + choices[i] = choice + i++ + } + return strings.Join(choices, "|") +} diff --git a/pkg/cloudcommon/validators/doc.go b/pkg/cloudcommon/validators/doc.go new file mode 100644 index 0000000000..6a69b4ede8 --- /dev/null +++ b/pkg/cloudcommon/validators/doc.go @@ -0,0 +1 @@ +package validators // import "yunion.io/x/onecloud/pkg/cloudcommon/validators" diff --git a/pkg/cloudcommon/validators/errors.go b/pkg/cloudcommon/validators/errors.go new file mode 100644 index 0000000000..57c7271ece --- /dev/null +++ b/pkg/cloudcommon/validators/errors.go @@ -0,0 +1,106 @@ +package validators + +import ( + "fmt" +) + +type ErrType uintptr + +const ( + ERR_SUCCESS ErrType = iota + ERR_GENERAL // uncategorized error + ERR_MISSING_KEY + ERR_INVALID_TYPE + ERR_INVALID_CHOICE + ERR_NOT_IN_RANGE + ERR_INVALID_VALUE + ERR_MODEL_MANAGER + ERR_MODEL_NOT_FOUND +) + +var errTypeToString = map[ErrType]string{ + ERR_SUCCESS: "No error", + ERR_GENERAL: "General error", + ERR_MISSING_KEY: "Missing_key error", + ERR_INVALID_TYPE: "Invalid type error", + ERR_INVALID_CHOICE: "Invalid choice error", + ERR_NOT_IN_RANGE: "Not in range error", + ERR_INVALID_VALUE: "Invalid value error", + ERR_MODEL_MANAGER: "Model manager error", + ERR_MODEL_NOT_FOUND: "Model not found error", +} + +func (errType ErrType) String() string { + s, ok := errTypeToString[errType] + if ok { + return s + } + return "unknown error" +} + +type ValidateError struct { + ErrType ErrType + Msg string +} + +func (ve *ValidateError) Error() string { + return ve.Msg +} + +// TODO let each validator provide the error +func newMissingKeyError(key string) error { + msg := fmt.Sprintf("missing %q", key) + return newError(ERR_MISSING_KEY, msg) +} + +func newGeneralError(key string, err error) error { + msg := fmt.Sprintf("general error for %q: %s", key, err) + return newError(ERR_GENERAL, msg) +} + +func newInvalidTypeError(key string, typ string, err error) error { + msg := fmt.Sprintf("expecting %s type for %q: %s", typ, key, err) + return newError(ERR_INVALID_TYPE, msg) +} + +func newInvalidChoiceError(key string, choices Choices, choice string) error { + msg := fmt.Sprintf("invalid %q, want %s, got %s", key, choices, choice) + return newError(ERR_INVALID_CHOICE, msg) +} + +func newNotInRangeError(key string, value, lower, upper int64) error { + msg := fmt.Sprintf("invalid %q: %d, want [%d,%d]", key, value, lower, upper) + return newError(ERR_NOT_IN_RANGE, msg) +} + +func newInvalidValueError(key string, value string) error { + msg := fmt.Sprintf("invalid %q: %s", key, value) + return newError(ERR_INVALID_VALUE, msg) +} + +func newModelManagerError(modelKeyword string) error { + msg := fmt.Sprintf("internal error: getting model manager for %q failed", + modelKeyword) + return newError(ERR_MODEL_MANAGER, msg) +} + +func newModelNotFoundError(modelKeyword, idOrName string, err error) error { + msg := fmt.Sprintf("cannot find %q with id/name %q: %s", + modelKeyword, idOrName, err) + return newError(ERR_MODEL_NOT_FOUND, msg) +} + +func newError(typ ErrType, msg string) error { + return &ValidateError{ + ErrType: typ, + Msg: msg, + } +} + +func IsModelNotFoundError(err error) bool { + ve, ok := err.(*ValidateError) + if ok && ve.ErrType == ERR_MODEL_NOT_FOUND { + return true + } + return false +} diff --git a/pkg/cloudcommon/validators/validators.go b/pkg/cloudcommon/validators/validators.go new file mode 100644 index 0000000000..305beb3a2c --- /dev/null +++ b/pkg/cloudcommon/validators/validators.go @@ -0,0 +1,427 @@ +package validators + +// TODO +// +// email +// uuid +// uri + +import ( + "math" + "net" + "reflect" + "regexp" + + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/pkg/gotypes" + "yunion.io/x/pkg/util/regutils" + "yunion.io/x/sqlchemy" +) + +type ValidatorFunc func(*jsonutils.JSONDict) error + +type IValidatorBase interface { + Validate(data *jsonutils.JSONDict) error +} + +type IValidator interface { + IValidatorBase + getValue() interface{} + setDefault(data *jsonutils.JSONDict) bool +} + +type Validator struct { + parent IValidator + Key string + optional bool + defaultVal interface{} + value jsonutils.JSONObject +} + +func (v *Validator) Optional(optional bool) IValidator { + v.optional = optional + return v.parent +} + +func (v *Validator) Default(defaultVal interface{}) IValidator { + v.defaultVal = defaultVal + return v.parent +} + +func (v *Validator) getValue() interface{} { + return nil +} + +func (v *Validator) setDefault(data *jsonutils.JSONDict) bool { + switch v.defaultVal.(type) { + case string: + s := v.defaultVal.(string) + v.value = jsonutils.NewString(s) + data.Set(v.Key, v.value) + return true + case int, int32, int64, uint, uint32, uint64: + value := reflect.ValueOf(v.defaultVal) + value64 := value.Convert(gotypes.Int64Type) + defaultVal64 := value64.Interface().(int64) + v.value = jsonutils.NewInt(defaultVal64) + data.Set(v.Key, v.value) + return true + } + return false +} + +func (v *Validator) Validate(data *jsonutils.JSONDict) error { + err, _ := v.validateEx(data) + return err +} + +func (v *Validator) validateEx(data *jsonutils.JSONDict) (err error, isSet bool) { + if !data.Contains(v.Key) { + if v.defaultVal != nil { + isSet = v.parent.setDefault(data) + return nil, isSet + } + if !v.optional { + err = newMissingKeyError(v.Key) + return + } + return + } + value, err := data.Get(v.Key) + if err != nil { + return + } + v.value = value + isSet = true + return +} + +type ValidatorStringChoices struct { + Validator + Choices Choices + defaultVal string + Value string +} + +func NewStringChoicesValidator(key string, choices Choices) *ValidatorStringChoices { + v := &ValidatorStringChoices{ + Validator: Validator{Key: key}, + Choices: choices, + } + v.parent = v + return v +} + +func (v *ValidatorStringChoices) Default(s string) IValidator { + if v.Choices.Has(s) { + return v.Validator.Default(s) + } + panic("invalid default for " + v.Key) +} + +func (v *ValidatorStringChoices) getValue() interface{} { + return v.Value +} + +func (v *ValidatorStringChoices) Validate(data *jsonutils.JSONDict) error { + if err, isSet := v.Validator.validateEx(data); err != nil || !isSet { + return err + } + s, err := v.value.GetString() + if err != nil { + return newGeneralError(v.Key, err) + } + if !v.Choices.Has(s) { + return newInvalidChoiceError(v.Key, v.Choices, s) + } + // in case it's stringified from v.value + data.Set(v.Key, jsonutils.NewString(s)) + v.Value = s + return nil +} + +type ValidatorRange struct { + Validator + Lower int64 + Upper int64 + Value int64 +} + +func (v *ValidatorRange) getValue() interface{} { + return v.Value +} + +func (v *ValidatorRange) Default(i int64) IValidator { + if i >= v.Lower && i <= v.Upper { + return v.Validator.Default(i) + } + panic("invalid default for " + v.Key) +} +func (v *ValidatorRange) Validate(data *jsonutils.JSONDict) error { + if err, isSet := v.Validator.validateEx(data); err != nil || !isSet { + return err + } + i, err := v.value.Int() + if err != nil { + return newInvalidTypeError(v.Key, "integer", err) + } + if i < v.Lower || i > v.Upper { + return newNotInRangeError(v.Key, i, v.Lower, v.Upper) + } + data.Set(v.Key, jsonutils.NewInt(i)) + v.Value = i + return nil +} + +func NewRangeValidator(key string, lower int64, upper int64) *ValidatorRange { + v := &ValidatorRange{ + Validator: Validator{Key: key}, + Lower: lower, + Upper: upper, + } + v.parent = v + return v +} + +func NewPortValidator(key string) *ValidatorRange { + return NewRangeValidator(key, 1, 65535) +} + +func NewNonNegativeValidator(key string) *ValidatorRange { + return NewRangeValidator(key, 0, math.MaxInt64) +} + +type ValidatorModelIdOrName struct { + Validator + ModelKeyword string + ProjectId string + ModelManager db.IModelManager + Model db.IModel + modelIdKey string +} + +func (v *ValidatorModelIdOrName) getValue() interface{} { + return v.Model +} + +func NewModelIdOrNameValidator(key string, modelKeyword string, projectId string) *ValidatorModelIdOrName { + v := &ValidatorModelIdOrName{ + Validator: Validator{Key: key}, + ProjectId: projectId, + ModelKeyword: modelKeyword, + modelIdKey: key + "_id", + } + v.parent = v + return v +} + +func (v *ValidatorModelIdOrName) ModelIdKey(modelIdKey string) *ValidatorModelIdOrName { + v.modelIdKey = modelIdKey + return v +} + +func (v *ValidatorModelIdOrName) validate(data *jsonutils.JSONDict) error { + if err, isSet := v.Validator.validateEx(data); err != nil || !isSet { + return err + } + modelIdOrName, err := v.value.GetString() + if err != nil { + return err + } + + modelManager := db.GetModelManager(v.ModelKeyword) + if modelManager == nil { + return newModelManagerError(v.ModelKeyword) + } + v.ModelManager = modelManager + model, err := modelManager.FetchByIdOrName(v.ProjectId, modelIdOrName) + if err != nil { + return newModelNotFoundError(v.ModelKeyword, modelIdOrName, err) + } + v.Model = model + return nil +} + +func (v *ValidatorModelIdOrName) Validate(data *jsonutils.JSONDict) error { + err := v.validate(data) + if err != nil { + return err + } + if v.Model != nil { + if len(v.modelIdKey) > 0 { + data.Remove(v.Key) + data.Set(v.modelIdKey, jsonutils.NewString(v.Model.GetId())) + } + } + return nil +} + +func (v *ValidatorModelIdOrName) QueryFilter(q *sqlchemy.SQuery, data *jsonutils.JSONDict) (*sqlchemy.SQuery, error) { + err := v.validate(data) + if err != nil { + if IsModelNotFoundError(err) { + // hack + q = q.Equals(v.modelIdKey, "0") + q = q.Equals(v.modelIdKey, "1") + return q, nil + } + return nil, err + } + if v.Model != nil { + q = q.Equals(v.modelIdKey, v.Model.GetId()) + } + return q, nil +} + +type ValidatorRegexp struct { + Validator + Regexp *regexp.Regexp + Value string + allowEmpty bool +} + +func (v *ValidatorRegexp) AllowEmpty(allowEmpty bool) *ValidatorRegexp { + v.allowEmpty = allowEmpty + return v +} + +func (v *ValidatorRegexp) getValue() interface{} { + return v.Value +} + +func (v *ValidatorRegexp) Validate(data *jsonutils.JSONDict) error { + if err, isSet := v.Validator.validateEx(data); err != nil || !isSet { + return err + } + value, err := v.value.GetString() + if err != nil { + return newInvalidTypeError(v.Key, "string", err) + } + if v.allowEmpty && len(value) == 0 { + return nil + } + if !v.Regexp.MatchString(value) { + return newInvalidValueError(v.Key, value) + } + v.Value = value + return nil +} + +func NewRegexpValidator(key string, regexp *regexp.Regexp) *ValidatorRegexp { + v := &ValidatorRegexp{ + Validator: Validator{Key: key}, + Regexp: regexp, + } + v.parent = v + return v +} + +type ValidatorDomainName struct { + ValidatorRegexp +} + +func NewDomainNameValidator(key string) *ValidatorDomainName { + v := &ValidatorDomainName{ + ValidatorRegexp: *NewRegexpValidator(key, regutils.DOMAINNAME_REG), + } + v.parent = v + return v +} + +type ValidatorURLPath struct { + ValidatorRegexp +} + +// URI Path as defined in https://tools.ietf.org/html/rfc3986#section-3.3 +var regexpURLPath = regexp.MustCompile(`^(?:/[a-zA-Z0-9.%$&'()*+,;=!~_-]*)*$`) + +func NewURLPathValidator(key string) *ValidatorURLPath { + v := &ValidatorURLPath{ + ValidatorRegexp: *NewRegexpValidator(key, regexpURLPath), + } + v.parent = v + return v +} + +type ValidatorStruct struct { + Validator + Value interface{} +} + +func (v *ValidatorStruct) getValue() interface{} { + return v.Value +} + +func (v *ValidatorStruct) Validate(data *jsonutils.JSONDict) error { + if err, isSet := v.Validator.validateEx(data); err != nil || !isSet { + return err + } + err := v.value.Unmarshal(v.Value) + if err != nil { + return newGeneralError(v.Key, err) + } + if valueValidator, ok := v.Value.(IValidatorBase); ok { + err = valueValidator.Validate(data) + if err != nil { + return err + } + } + return nil +} + +func NewStructValidator(key string, value interface{}) *ValidatorStruct { + v := &ValidatorStruct{ + Validator: Validator{Key: key}, + Value: value, + } + v.parent = v + return v +} + +type ValidatorIPv4Addr struct { + Validator + IP net.IP +} + +func (v *ValidatorIPv4Addr) getValue() interface{} { + return v.IP +} + +func (v *ValidatorIPv4Addr) setDefault(data *jsonutils.JSONDict) bool { + if v.defaultVal == nil { + return false + } + defaultIP, ok := v.defaultVal.(net.IP) + if !ok { + return false + } + value := jsonutils.NewString(defaultIP.String()) + v.value = value + data.Set(v.Key, value) + return true +} + +func (v *ValidatorIPv4Addr) Validate(data *jsonutils.JSONDict) error { + if err, isSet := v.Validator.validateEx(data); err != nil || !isSet { + return err + } + s, err := v.value.GetString() + if err != nil { + return newInvalidTypeError(v.Key, "string", err) + } + ip := net.ParseIP(s).To4() + if ip == nil { + return newInvalidValueError(v.Key, s) + } + v.IP = ip + return nil +} + +func NewIPv4AddrValidator(key string) *ValidatorIPv4Addr { + v := &ValidatorIPv4Addr{ + Validator: Validator{Key: key}, + } + v.parent = v + return v +} diff --git a/pkg/cloudcommon/validators/validators_test.go b/pkg/cloudcommon/validators/validators_test.go new file mode 100644 index 0000000000..1323554b5b --- /dev/null +++ b/pkg/cloudcommon/validators/validators_test.go @@ -0,0 +1,500 @@ +package validators + +// TODO +// +// - strict type, no implicit conversion +// - test model validator +// - invalid default for string choice, range + +import ( + "net" + "reflect" + "testing" + + "yunion.io/x/jsonutils" +) + +func TestURLPathRegexp(t *testing.T) { + cases := []struct { + in string + match bool + }{ + {in: "", match: true}, + {in: "/", match: true}, + {in: "/p", match: true}, + {in: "/p/", match: true}, + {in: "p", match: false}, + {in: "p/", match: false}, + {in: "/p?", match: false}, + {in: "/p#", match: false}, + } + for _, c := range cases { + got := regexpURLPath.MatchString(c.in) + if got != c.match { + t.Errorf("%q match, want %v, got %v", c.in, c.match, got) + } + } +} + +type C struct { + Name string + In string + Out string + Optional bool + Default interface{} + ValueWant interface{} + Err ErrType +} + +func testS(t *testing.T, v IValidator, c *C) { + j, _ := jsonutils.ParseString(c.In) + jd := j.(*jsonutils.JSONDict) + err := v.Validate(jd) + if err != nil { + verr, ok := err.(*ValidateError) + if ok { + if verr.ErrType != c.Err { + t.Errorf("error want %q, got %q", + c.Err, verr.ErrType) + } + } else { + t.Errorf("want error type ValidateError") + } + } else { + if c.Err != ERR_SUCCESS { + t.Errorf("expect error: %s", c.Err) + } + } + jWant, _ := jsonutils.ParseString(c.Out) + if !reflect.DeepEqual(j, jWant) { + t.Errorf("json out want %s, got %s", + jWant.String(), j.String()) + } + value := v.getValue() + if !reflect.DeepEqual(value, c.ValueWant) { + t.Errorf("value want %#v, got %#v", c.ValueWant, value) + } +} + +func TestStringChoicesValidator(t *testing.T) { + choices := NewChoices("choice0", "choice1", "100") + cases := []*C{ + { + Name: "missing non-optional", + In: `{}`, + Out: `{}`, + Optional: false, + Err: ERR_MISSING_KEY, + ValueWant: "", + }, + { + Name: "missing optional", + In: `{}`, + Out: `{}`, + Optional: true, + ValueWant: "", + }, + { + Name: "missing with default", + In: `{}`, + Out: `{s: "choice0"}`, + Default: "choice0", + ValueWant: "choice0", + }, + { + Name: "stringified", + In: `{"s": 100}`, + Out: `{s: "100"}`, + ValueWant: "100", + }, + { + Name: "stringified invalid choice", + In: `{"s": 101}`, + Out: `{"s": 101}`, + Err: ERR_INVALID_CHOICE, + ValueWant: "", + }, + { + Name: "good choice", + In: `{"s": "choice1"}`, + Out: `{"s": "choice1"}`, + ValueWant: "choice1", + }, + { + Name: "bad choice", + In: `{"s": "badchoice"}`, + Out: `{"s": "badchoice"}`, + Err: ERR_INVALID_CHOICE, + ValueWant: "", + }, + } + for _, c := range cases { + t.Run(c.Name, func(t *testing.T) { + v := NewStringChoicesValidator("s", choices) + if c.Default != nil { + s := c.Default.(string) + v.Default(s) + } + if c.Optional { + v.Optional(true) + } + testS(t, v, c) + }) + } +} + +func TestRangeValidator(t *testing.T) { + cases := []*C{ + { + Name: "missing non-optional", + In: `{}`, + Out: `{}`, + Err: ERR_MISSING_KEY, + ValueWant: int64(0), + }, + { + Name: "missing optional", + In: `{}`, + Out: `{}`, + Optional: true, + ValueWant: int64(0), + }, + { + Name: "missing with default", + In: `{}`, + Out: `{s: 1}`, + Default: int64(1), + ValueWant: int64(1), + }, + { + Name: "parsed", + In: `{s: "100"}`, + Out: `{s: 100}`, + ValueWant: int64(100), + }, + { + Name: "parsed invalid int", + In: `{s: "abc"}`, + Out: `{s: "abc"}`, + Err: ERR_INVALID_TYPE, + ValueWant: int64(0), + }, + { + Name: "parsed not in range", + In: `{s: "65536"}`, + Out: `{s: "65536"}`, + Err: ERR_NOT_IN_RANGE, + ValueWant: int64(0), + }, + { + Name: "in range", + In: `{s: 100}`, + Out: `{s: 100}`, + ValueWant: int64(100), + }, + { + Name: "not in range", + In: `{s: 0}`, + Out: `{s: 0}`, + Err: ERR_NOT_IN_RANGE, + ValueWant: int64(0), + }, + } + for _, c := range cases { + t.Run(c.Name, func(t *testing.T) { + v := NewPortValidator("s") + if c.Default != nil { + i := c.Default.(int64) + v.Default(i) + } + if c.Optional { + v.Optional(true) + } + testS(t, v, c) + }) + } +} + +func TestRegexValidator(t *testing.T) { + type RegexC struct { + *C + AllowEmpty bool + } + cases := []*RegexC{ + { + C: &C{ + Name: "missing non-optional", + In: `{}`, + Out: `{}`, + Err: ERR_MISSING_KEY, + ValueWant: "", + }, + }, + { + C: &C{ + Name: "missing optional", + In: `{}`, + Out: `{}`, + Optional: true, + ValueWant: "", + }, + }, + { + C: &C{ + Name: "missing with default", + In: `{}`, + Out: `{s: "example.com"}`, + Default: "example.com", + ValueWant: "example.com", + }, + }, + { + C: &C{ + Name: "valid", + In: `{s: "a.example.com"}`, + Out: `{s: "a.example.com"}`, + ValueWant: "a.example.com", + }, + }, + { + C: &C{ + Name: "valid (allow empty)", + In: `{s: ""}`, + Out: `{s: ""}`, + ValueWant: "", + }, + AllowEmpty: true, + }, + { + C: &C{ + Name: "invalid", + In: `{s: "/.example.com"}`, + Out: `{s: "/.example.com"}`, + ValueWant: "", + Err: ERR_INVALID_VALUE, + }, + }, + { + C: &C{ + Name: "invalid (disallow empty)", + In: `{s: ""}`, + Out: `{s: ""}`, + ValueWant: "", + Err: ERR_INVALID_VALUE, + }, + }, + } + for _, c := range cases { + t.Run(c.Name, func(t *testing.T) { + v := NewDomainNameValidator("s") + if c.Default != nil { + i := c.Default.(string) + v.Default(i) + } + if c.Optional { + v.Optional(true) + } + if c.AllowEmpty { + v.AllowEmpty(true) + } + testS(t, v, c.C) + }) + } +} + +func TestIPv4Validator(t *testing.T) { + var nilIP net.IP + localIP := net.IPv4(127, 0, 0, 1).To4() + cases := []*C{ + { + Name: "missing non-optional", + In: `{}`, + Out: `{}`, + Err: ERR_MISSING_KEY, + ValueWant: nilIP, + }, + { + Name: "missing optional", + In: `{}`, + Out: `{}`, + Optional: true, + ValueWant: nilIP, + }, + { + Name: "missing with default", + In: `{}`, + Out: `{s: "127.0.0.1"}`, + Default: localIP, + ValueWant: localIP, + }, + { + Name: "valid", + In: `{s: "127.0.0.1"}`, + Out: `{s: "127.0.0.1"}`, + ValueWant: localIP, + }, + { + Name: "valid (v4 in v6)", + In: `{s: "::ffff:127.0.0.1"}`, + Out: `{s: "::ffff:127.0.0.1"}`, + ValueWant: localIP, + }, + { + Name: "invalid", + In: `{s: "127.0.0"}`, + Out: `{s: "127.0.0"}`, + Err: ERR_INVALID_VALUE, + ValueWant: nilIP, + }, + { + Name: "invalid (empty string)", + In: `{s: ""}`, + Out: `{s: ""}`, + Err: ERR_INVALID_VALUE, + ValueWant: nilIP, + }, + { + Name: "invalid (wrong type)", + In: `{s: 100}`, + Out: `{s: 100}`, + Err: ERR_INVALID_VALUE, + ValueWant: nilIP, + }, + } + for _, c := range cases { + t.Run(c.Name, func(t *testing.T) { + v := NewIPv4AddrValidator("s") + if c.Default != nil { + i := c.Default.(net.IP) + v.Default(i) + } + if c.Optional { + v.Optional(true) + } + testS(t, v, c) + }) + } +} + +type TestStruct struct { + F0 string + F1 int + F2 bool +} + +type TestVStruct TestStruct + +func (v *TestVStruct) Validate(data *jsonutils.JSONDict) error { + if v.F2 { + return nil + } else { + return newInvalidValueError("F2", v.F0) + } +} + +func TestStructValidator(t *testing.T) { + type StructC struct { + *C + Value interface{} + } + defaultVal := &TestStruct{ + F0: "holy", + F1: 100, + F2: true, + } + var defaultValMiss *TestStruct + { + defaultValMissCopy := *defaultVal + defaultValMissCopy.F2 = false + defaultValMiss = &defaultValMissCopy + } + defaultValJsonStr := `{s: {"F0": "holy", "F1": 100, "F2": true}}` + defaultValJsonStrMiss := `{s: {"F0": "holy", "F1": 100}}` + defaultValJsonStrMore := `{s: {"F0": "holy", "F1": 100, "F2": true, "Foo": "bar"}}` + + defaultVVal := (*TestVStruct)(defaultVal) + var defaultVValBad *TestVStruct + { + defaultVValBadCopy := *defaultVVal + defaultVValBadCopy.F2 = false + defaultVValBad = &defaultVValBadCopy + } + defaultVValJsonStrBad := `{s: {"F0": "holy", "F1": 100, "F2": false}}` + cases := []*StructC{ + { + C: &C{ + Name: "missing non-optional", + In: `{}`, + Out: `{}`, + Err: ERR_MISSING_KEY, + ValueWant: &TestStruct{}, + }, + Value: &TestStruct{}, + }, + { + C: &C{ + Name: "missing optional", + In: `{}`, + Out: `{}`, + Optional: true, + ValueWant: &TestStruct{}, + }, + Value: &TestStruct{}, + }, + { + C: &C{ + Name: "valid", + In: defaultValJsonStr, + Out: defaultValJsonStr, + ValueWant: defaultVal, + }, + Value: &TestStruct{}, + }, + { + C: &C{ + Name: "valid (missing fields)", + In: defaultValJsonStrMiss, + Out: defaultValJsonStrMiss, + ValueWant: defaultValMiss, + }, + Value: &TestStruct{}, + }, + { + C: &C{ + Name: "valid (more fields)", + In: defaultValJsonStrMore, + Out: defaultValJsonStrMore, + ValueWant: defaultVal, + }, + Value: &TestStruct{}, + }, + { + C: &C{ + Name: "valid (struct says valid)", + In: defaultValJsonStr, + Out: defaultValJsonStr, + ValueWant: defaultVVal, + }, + Value: &TestVStruct{}, + }, + { + C: &C{ + Name: "invalid (struct says invalid)", + In: defaultVValJsonStrBad, + Out: defaultVValJsonStrBad, + ValueWant: defaultVValBad, + Err: ERR_INVALID_VALUE, + }, + Value: &TestVStruct{}, + }, + } + for _, c := range cases { + t.Run(c.Name, func(t *testing.T) { + v := NewStructValidator("s", c.Value) + if c.Optional { + v.Optional(true) + } + testS(t, v, c.C) + }) + } +} From c81aafb9bce31d1e77d567d0563240ab5e292d23 Mon Sep 17 00:00:00 2001 From: Zhang Dongliang Date: Fri, 31 Aug 2018 09:32:46 +0800 Subject: [PATCH 17/32] =?UTF-8?q?=E9=98=BF=E9=87=8C=E4=BA=91=E5=8F=98?= =?UTF-8?q?=E6=9B=B4=E9=85=8D=E7=BD=AE=E5=A2=9E=E5=8A=A0=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/compute/tasks/guest_change_config_task.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pkg/compute/tasks/guest_change_config_task.go b/pkg/compute/tasks/guest_change_config_task.go index 44ba532ae1..78963011d8 100644 --- a/pkg/compute/tasks/guest_change_config_task.go +++ b/pkg/compute/tasks/guest_change_config_task.go @@ -9,6 +9,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" ) type GuestChangeConfigTask struct { @@ -41,37 +42,44 @@ func (self *GuestChangeConfigTask) OnDisksResizeComplete(ctx context.Context, ob iResizeSet, err := resizeDisks.GetAt(i) if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(obj, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) return } resizeSet := iResizeSet.(*jsonutils.JSONArray) diskId, err := resizeSet.GetAt(0) if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(obj, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) return } idStr, err := diskId.GetString() if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(obj, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) return } jSize, err := resizeSet.GetAt(1) if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(obj, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) return } size, err := jSize.Int() if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(obj, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) return } iDisk, err := models.DiskManager.FetchById(idStr) if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(obj, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) return } disk := iDisk.(*models.SDisk) if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(disk, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) return } if disk.DiskSize < int(size) { @@ -79,6 +87,7 @@ func (self *GuestChangeConfigTask) OnDisksResizeComplete(ctx context.Context, ob err = self.GetPendingUsage(&pendingUsage) if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(disk, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) return } disk.StartDiskResizeTask(ctx, self.UserCred, size, self.GetTaskId(), &pendingUsage) @@ -112,6 +121,7 @@ func (self *GuestChangeConfigTask) OnCreateDisksComplete(ctx context.Context, ob vcpuCount, err = iVcpuCount.Int() if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) return } } @@ -119,12 +129,14 @@ func (self *GuestChangeConfigTask) OnCreateDisksComplete(ctx context.Context, ob vmemSize, err = iVmemSize.Int() if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) return } } err = guest.GetDriver().RequestChangeVmConfig(ctx, guest, self, vcpuCount, vmemSize) if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) return } var addCpu, addMem = 0, 0 @@ -151,12 +163,14 @@ func (self *GuestChangeConfigTask) OnCreateDisksComplete(ctx context.Context, ob }) if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) return } var pendingUsage models.SQuota err = self.GetPendingUsage(&pendingUsage) if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) return } // ownerCred := guest.GetOwnerUserCred() @@ -172,11 +186,13 @@ func (self *GuestChangeConfigTask) OnCreateDisksComplete(ctx context.Context, ob err = models.QuotaManager.CancelPendingUsage(ctx, self.UserCred, guest.ProjectId, &pendingUsage, &cancelUsage) if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) return } err = self.SetPendingUsage(&pendingUsage) if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) return } } @@ -184,6 +200,7 @@ func (self *GuestChangeConfigTask) OnCreateDisksComplete(ctx context.Context, ob err = guest.StartSyncstatus(ctx, self.UserCred, self.GetTaskId()) if err != nil { self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false) return } } @@ -193,10 +210,12 @@ func (self *GuestChangeConfigTask) OnSyncStatusComplete(ctx context.Context, obj if guest.Status == models.VM_READY && jsonutils.QueryBoolean(self.Params, "auto_start", false) { self.SetStage("on_guest_start_complete", nil) guest.StartGueststartTask(ctx, self.UserCred, nil, self.GetTaskId()) + logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, "", self.UserCred, true) } else { dt := jsonutils.NewDict() dt.Add(jsonutils.NewString(guest.Id), "id") self.SetStageComplete(ctx, dt) + logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, "", self.UserCred, true) } } From adfb5ae36457f327b53738656185f1687c20f460 Mon Sep 17 00:00:00 2001 From: Zhang Dongliang Date: Fri, 31 Aug 2018 09:39:11 +0800 Subject: [PATCH 18/32] =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E9=87=8D=E6=9E=84=EF=BC=9B=E9=98=BF=E9=87=8C=E4=BA=91=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=AF=86=E7=A0=81=E3=80=81=E5=8F=98=E6=9B=B4=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=8A=A0=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/cloudcommon/db/db_dispatcher.go | 21 ++++++++++---------- pkg/cloudcommon/db/opslog.go | 2 +- pkg/cloudcommon/db/statusstandalone.go | 2 +- pkg/compute/guestdrivers/aliyun.go | 4 +--- pkg/compute/tasks/guest_create_task.go | 6 +++--- pkg/compute/tasks/guest_delete_task.go | 5 ++--- pkg/compute/tasks/guest_deploy_task.go | 18 ++++++++++++++++- pkg/compute/tasks/guest_rebuild_root_task.go | 17 ++++++++-------- pkg/compute/tasks/guest_start_task.go | 4 ++-- pkg/compute/tasks/guest_stop_task.go | 4 ++-- pkg/compute/tasks/guest_syncstatus_task.go | 4 ++-- pkg/util/logclient/logclient.go | 9 +++++---- 12 files changed, 56 insertions(+), 40 deletions(-) diff --git a/pkg/cloudcommon/db/db_dispatcher.go b/pkg/cloudcommon/db/db_dispatcher.go index 6b990ef325..90b4999a51 100644 --- a/pkg/cloudcommon/db/db_dispatcher.go +++ b/pkg/cloudcommon/db/db_dispatcher.go @@ -769,7 +769,7 @@ func (dispatcher *DBModelDispatcher) Create(ctx context.Context, query jsonutils return nil, httperrors.NewGeneralError(err) } OpsLog.LogEvent(model, ACT_CREATE, model.GetShortDesc(), userCred) - logclient.AddActionLog(model, logclient.ACT_CREATE, "", userCred) + logclient.AddActionLog(model, logclient.ACT_CREATE, "", userCred, true) dispatcher.modelManager.OnCreateComplete(ctx, []IModel{model}, userCred, query, data) return getItemDetails(dispatcher.modelManager, model, ctx, userCred, query) } @@ -988,13 +988,13 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre if err != nil { log.Errorf("validate update condition error: %s", err) - logclient.AddActionLog(item, logclient.ACT_UPDATE, err.Error(), userCred) + logclient.AddActionLog(item, logclient.ACT_UPDATE, err.Error(), userCred, false) return nil, httperrors.NewGeneralError(err) } dataDict, ok := data.(*jsonutils.JSONDict) if !ok { - logclient.AddActionLog(item, logclient.ACT_UPDATE, "Invalid data JSONObject", userCred) + logclient.AddActionLog(item, logclient.ACT_UPDATE, "Invalid data JSONObject", userCred, false) return nil, httperrors.NewInternalServerError("Invalid data JSONObject") } @@ -1002,7 +1002,7 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre if len(name) > 0 { err = alterNameValidator(item, name) if err != nil { - logclient.AddActionLog(item, logclient.ACT_UPDATE, err.Error(), userCred) + logclient.AddActionLog(item, logclient.ACT_UPDATE, err.Error(), userCred, false) return nil, err } } @@ -1011,7 +1011,7 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre if err != nil { errMsg := fmt.Sprintf("validate update data error: %s", err) log.Errorf(errMsg) - logclient.AddActionLog(item, logclient.ACT_UPDATE, errMsg, userCred) + logclient.AddActionLog(item, logclient.ACT_UPDATE, errMsg, userCred, false) return nil, httperrors.NewGeneralError(err) } item.PreUpdate(ctx, userCred, query, dataDict) @@ -1020,7 +1020,7 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre err = filterData.Unmarshal(item) if err != nil { errMsg := fmt.Sprintf("unmarshal fail: %s", err) - logclient.AddActionLog(item, logclient.ACT_UPDATE, errMsg, userCred) + logclient.AddActionLog(item, logclient.ACT_UPDATE, errMsg, userCred, false) log.Errorf(errMsg) return httperrors.NewGeneralError(err) } @@ -1035,10 +1035,11 @@ func updateItem(manager IModelManager, item IModel, ctx context.Context, userCre diffStr := sqlchemy.UpdateDiffString(diff) if len(diffStr) > 0 { OpsLog.LogEvent(item, ACT_UPDATE, diffStr, userCred) - logclient.AddActionLog(item, logclient.ACT_UPDATE, diffStr, userCred) + logclient.AddActionLog(item, logclient.ACT_UPDATE, diffStr, userCred, true) } + } else { + logclient.AddActionLog(item, logclient.ACT_UPDATE, "", userCred, true) } - logclient.AddActionLog(item, logclient.ACT_UPDATE, "", userCred) return getItemDetails(manager, item, ctx, userCred, query) } @@ -1067,11 +1068,11 @@ func DeleteModel(ctx context.Context, userCred mcclient.TokenCredential, item IM if err != nil { msg := fmt.Sprintf("save update error %s", err) log.Errorf(msg) - logclient.AddActionLog(item, logclient.ACT_DELETE, msg, userCred) + logclient.AddActionLog(item, logclient.ACT_DELETE, msg, userCred, false) return httperrors.NewGeneralError(err) } OpsLog.LogEvent(item, ACT_DELETE, item.GetShortDesc(), userCred) - logclient.AddActionLog(item, logclient.ACT_DELETE, "", userCred) + logclient.AddActionLog(item, logclient.ACT_DELETE, item.GetShortDesc(), userCred, true) return nil } diff --git a/pkg/cloudcommon/db/opslog.go b/pkg/cloudcommon/db/opslog.go index d1fe6d5da9..1a9d76986c 100644 --- a/pkg/cloudcommon/db/opslog.go +++ b/pkg/cloudcommon/db/opslog.go @@ -303,7 +303,7 @@ func (manager *SOpsLogManager) SyncOwner(m IModel, former *STenant, userCred mcc notes.Add(jsonutils.NewString(former.GetId()), "former_project_id") notes.Add(jsonutils.NewString(former.GetName()), "form_project") manager.LogEvent(m, ACT_CHANGE_OWNER, notes, userCred) - logclient.AddActionLog(m, logclient.ACT_CHANGE_OWNER, nil, userCred) + logclient.AddActionLog(m, logclient.ACT_CHANGE_OWNER, nil, userCred, true) } func (manager *SOpsLogManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { diff --git a/pkg/cloudcommon/db/statusstandalone.go b/pkg/cloudcommon/db/statusstandalone.go index 7c683e36f7..2fe6b2256b 100644 --- a/pkg/cloudcommon/db/statusstandalone.go +++ b/pkg/cloudcommon/db/statusstandalone.go @@ -43,7 +43,7 @@ func (model *SStatusStandaloneResourceBase) SetStatus(userCred mcclient.TokenCre } OpsLog.LogEvent(model, ACT_UPDATE_STATUS, notes, userCred) if strings.Contains(notes, "fail") { - logclient.AddActionLog(model, logclient.ACT_VM_SYNC_STATUS, notes, userCred) + logclient.AddActionLog(model, logclient.ACT_VM_SYNC_STATUS, notes, userCred, false) } } return nil diff --git a/pkg/compute/guestdrivers/aliyun.go b/pkg/compute/guestdrivers/aliyun.go index f149f322ec..bedd718860 100644 --- a/pkg/compute/guestdrivers/aliyun.go +++ b/pkg/compute/guestdrivers/aliyun.go @@ -112,7 +112,6 @@ func (self *SAliyunGuestDriver) GetJsonDescAtHost(ctx context.Context, guest *mo config.DataDisks[i-1] = disk.DiskSize / 1024 // MB => GB } } - return jsonutils.Marshal(&config) } @@ -250,10 +249,9 @@ func (self *SAliyunGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu } publicKey := "" - if k, e := config.GetString("public_key"); e != nil { + if k, e := config.GetString("public_key"); e == nil { publicKey = k } - taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { encpasswd, err := utils.EncryptAESBase64(guest.Id, password) if err != nil { diff --git a/pkg/compute/tasks/guest_create_task.go b/pkg/compute/tasks/guest_create_task.go index 2f1bc713e0..0906f65072 100644 --- a/pkg/compute/tasks/guest_create_task.go +++ b/pkg/compute/tasks/guest_create_task.go @@ -50,7 +50,7 @@ func (self *GuestCreateTask) OnDiskPreparedFailed(ctx context.Context, obj db.IS guest := obj.(*models.SGuest) guest.SetStatus(self.UserCred, models.VM_DISK_FAILED, "allocation failed") db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, data, self.UserCred) - logclient.AddActionLog(guest, logclient.ACT_ALLOCATE, data, self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_ALLOCATE, data, self.UserCred, false) notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_DISK_FAILED, data.String()) } @@ -78,7 +78,7 @@ func (self *GuestCreateTask) OnCdromPreparedFailed(ctx context.Context, obj db.I guest := obj.(*models.SGuest) guest.SetStatus(self.UserCred, models.VM_DISK_FAILED, "") db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, data, self.UserCred) - logclient.AddActionLog(guest, logclient.ACT_ALLOCATE, data, self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_ALLOCATE, data, self.UserCred, false) notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_DISK_FAILED, fmt.Sprintf("cdrom_failed %s", data)) } @@ -105,7 +105,7 @@ func (self *GuestCreateTask) OnDeployGuestDescCompleteFailed(ctx context.Context guest := obj.(*models.SGuest) guest.SetStatus(self.UserCred, models.VM_DEPLOY_FAILED, "deploy_failed") db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, data, self.UserCred) - logclient.AddActionLog(guest, logclient.ACT_ALLOCATE, data, self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_ALLOCATE, data, self.UserCred, false) notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_DEPLOY_FAILED, data.String()) } diff --git a/pkg/compute/tasks/guest_delete_task.go b/pkg/compute/tasks/guest_delete_task.go index 548388eaac..8d9a2ce11a 100644 --- a/pkg/compute/tasks/guest_delete_task.go +++ b/pkg/compute/tasks/guest_delete_task.go @@ -5,7 +5,6 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" - "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" @@ -95,7 +94,7 @@ func (self *GuestDeleteTask) OnGuestDeleteCompleteFailed(ctx context.Context, ob guest := obj.(*models.SGuest) guest.SetStatus(self.UserCred, models.VM_DELETE_FAIL, err.String()) db.OpsLog.LogEvent(guest, db.ACT_DELOCATE_FAIL, err, self.UserCred) - logclient.AddActionLog(guest, logclient.ACT_DELETE, err, self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_DELETE, err, self.UserCred, false) } func (self *GuestDeleteTask) OnGuestDeleteComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { @@ -111,7 +110,7 @@ func (self *GuestDeleteTask) DeleteGuest(ctx context.Context, guest *models.SGue guest.RealDelete(ctx, self.UserCred) guest.RemoveAllMetadata(ctx, self.UserCred) db.OpsLog.LogEvent(guest, db.ACT_DELOCATE, nil, self.UserCred) - logclient.AddActionLog(guest, logclient.ACT_DELETE, "", self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_DELETE, nil, self.UserCred, true) if !guest.IsSystem && !guest.PendingDeleted { self.NotifyServerDeleted(ctx, guest) } diff --git a/pkg/compute/tasks/guest_deploy_task.go b/pkg/compute/tasks/guest_deploy_task.go index 2b9c98f190..bd40cf4c3e 100644 --- a/pkg/compute/tasks/guest_deploy_task.go +++ b/pkg/compute/tasks/guest_deploy_task.go @@ -57,12 +57,12 @@ func (self *GuestDeployTask) StartDeployGuestOnHost(ctx context.Context, guest * } else { guest.SetStatus(self.UserCred, models.VM_DEPLOYING, "") } - logclient.AddActionLog(guest, logclient.ACT_VM_DEPLOY, err, self.UserCred) } func (self *GuestDeployTask) OnDeployGuestFail(ctx context.Context, guest *models.SGuest, err error) { guest.SetStatus(self.UserCred, models.VM_DEPLOY_FAILED, err.Error()) self.SetStageFailed(ctx, err.Error()) + logclient.AddActionLog(guest, logclient.ACT_VM_DEPLOY, err, self.UserCred, false) } func (self *GuestDeployTask) OnDeployGuestComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { @@ -70,6 +70,22 @@ func (self *GuestDeployTask) OnDeployGuestComplete(ctx context.Context, obj db.I guest := obj.(*models.SGuest) guest.GetDriver().OnGuestDeployTaskDataReceived(ctx, guest, self, data) guest.GetDriver().OnGuestDeployTaskComplete(ctx, guest, self) + action, _ := self.Params.GetString("deploy_action") + keypair, _ := self.Params.GetString("keypair") + log.Debugf("KeyPair:", keypair, "lenof key", len(keypair)) + reset_password := jsonutils.QueryBoolean(self.Params, "reset_password", false) + + if action == "deploy" && reset_password { + keypair, _ := self.Params.GetString("keypair") + if len(keypair) > 0 { + logclient.AddActionLog(guest, logclient.ACT_VM_BIND_KEYPAIR, self.Params, self.UserCred, true) + } else { + logclient.AddActionLog(guest, logclient.ACT_VM_RESET_PSWD, self.Params, self.UserCred, true) + } + } else { + logclient.AddActionLog(guest, "misc部署", self.Params, self.UserCred, true) + } + } func (self *GuestDeployTask) OnDeployGuestCompleteFailed(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { diff --git a/pkg/compute/tasks/guest_rebuild_root_task.go b/pkg/compute/tasks/guest_rebuild_root_task.go index 8f61dcaf4f..a2a7e5c6fd 100644 --- a/pkg/compute/tasks/guest_rebuild_root_task.go +++ b/pkg/compute/tasks/guest_rebuild_root_task.go @@ -49,7 +49,7 @@ func (self *GuestRebuildRootTask) StartRebuildRootDisk(ctx context.Context, gues }) if err != nil { self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, err, self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, err, self.UserCred, false) return } else { db.OpsLog.LogEvent(gds.Root, db.ACT_UPDATE_STATUS, @@ -66,19 +66,19 @@ func (self *GuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Context, imginfo, err := models.CachedimageManager.GetImageById(ctx, self.UserCred, imgId, false) if err != nil { self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, err, self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, err, self.UserCred, false) return } osprof, err := osprofile.GetOSProfileFromImageProperties(imginfo.Properties, guest.Hypervisor) if err != nil { self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, err, self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, err, self.UserCred, false) return } err = guest.SetMetadata(ctx, "__os_profile__", osprof, self.UserCred) if err != nil { self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, err, self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, err, self.UserCred, false) return } if guest.OsType != osprof.OSType { @@ -88,7 +88,7 @@ func (self *GuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Context, }) if err != nil { self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, err, self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, err, self.UserCred, false) return } } @@ -101,7 +101,7 @@ func (self *GuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Context, func (self *GuestRebuildRootTask) OnRebuildRootDiskCompleteFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { db.OpsLog.LogEvent(guest, db.ACT_REBUILD_ROOT_FAIL, data, self.UserCred) guest.SetStatus(self.UserCred, models.VM_REBUILD_ROOT_FAIL, "") - logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, data, self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, data, self.UserCred, false) } func (self *GuestRebuildRootTask) OnSyncStatusComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { @@ -111,7 +111,7 @@ func (self *GuestRebuildRootTask) OnSyncStatusComplete(ctx context.Context, gues } else { self.SetStageComplete(ctx, nil) } - logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, "", self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, "", self.UserCred, true) } func (self *GuestRebuildRootTask) OnGuestStartComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { @@ -143,9 +143,10 @@ func (self *KVMGuestRebuildRootTask) OnRebuildRootDiskComplete(ctx context.Conte func (self *KVMGuestRebuildRootTask) OnRebuildRootDiskCompleteFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { self.SetStageFailed(ctx, data.String()) - logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, data, self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, data, self.UserCred, false) } func (self *KVMGuestRebuildRootTask) OnGuestDeployComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { self.SetStageComplete(ctx, nil) + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, nil, self.UserCred, true) } diff --git a/pkg/compute/tasks/guest_start_task.go b/pkg/compute/tasks/guest_start_task.go index 980af93c9b..99dae67cf3 100644 --- a/pkg/compute/tasks/guest_start_task.go +++ b/pkg/compute/tasks/guest_start_task.go @@ -59,7 +59,7 @@ func (self *GuestStartTask) OnStartComplete(ctx context.Context, obj db.IStandal db.OpsLog.LogEvent(guest, db.ACT_START, guest.GetShortDesc(), self.UserCred) self.SetStage("on_guest_syncstatus_after_start", nil) guest.StartSyncstatus(ctx, self.UserCred, self.GetTaskId()) - logclient.AddActionLog(guest, logclient.ACT_VM_START, "", self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_VM_START, "", self.UserCred, true) // self.taskComplete(ctx, guest) } @@ -77,7 +77,7 @@ func (self *GuestStartTask) onStartGuestFailed(ctx context.Context, guest *model guest.SetStatus(self.UserCred, models.VM_START_FAILED, err.Error()) self.SetStageFailed(ctx, err.Error()) self.OnStartCompleteFailed(ctx, guest, jsonutils.NewString(err.Error())) - logclient.AddActionLog(guest, logclient.ACT_VM_START, err, self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_VM_START, err, self.UserCred, false) } func (self *GuestStartTask) taskComplete(ctx context.Context, guest *models.SGuest) { diff --git a/pkg/compute/tasks/guest_stop_task.go b/pkg/compute/tasks/guest_stop_task.go index ebdf37d936..1368f24082 100644 --- a/pkg/compute/tasks/guest_stop_task.go +++ b/pkg/compute/tasks/guest_stop_task.go @@ -58,12 +58,12 @@ func (self *GuestStopTask) OnGuestStopTaskComplete(ctx context.Context, obj db.I if guest.Status == models.VM_READY && guest.DisableDelete.IsFalse() && guest.ShutdownBehavior == models.SHUTDOWN_TERMINATE { guest.StartAutoDeleteGuestTask(ctx, self.UserCred, "") } - logclient.AddActionLog(guest, logclient.ACT_VM_STOP, "", self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_VM_STOP, "", self.UserCred, true) } func (self *GuestStopTask) OnStopGuestFail(ctx context.Context, guest *models.SGuest, err error) { guest.SetStatus(self.UserCred, models.VM_STOP_FAILED, err.Error()) db.OpsLog.LogEvent(guest, db.ACT_STOP_FAIL, err.Error(), self.UserCred) self.SetStageFailed(ctx, err.Error()) - logclient.AddActionLog(guest, logclient.ACT_VM_STOP, err, self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_VM_STOP, err, self.UserCred, false) } diff --git a/pkg/compute/tasks/guest_syncstatus_task.go b/pkg/compute/tasks/guest_syncstatus_task.go index 78dfd85a51..18849cc4e0 100644 --- a/pkg/compute/tasks/guest_syncstatus_task.go +++ b/pkg/compute/tasks/guest_syncstatus_task.go @@ -54,11 +54,11 @@ func (self *GuestSyncstatusTask) OnGetStatusSucc(ctx context.Context, guest *mod statusData.Add(jsonutils.NewString(statusStr), "status") guest.PerformStatus(ctx, self.UserCred, nil, statusData) self.SetStageComplete(ctx, nil) - logclient.AddActionLog(guest, logclient.ACT_VM_SYNC_STATUS, "", self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_VM_SYNC_STATUS, "", self.UserCred, true) } func (self *GuestSyncstatusTask) OnGetStatusFail(ctx context.Context, guest *models.SGuest, err error) { guest.SetStatus(self.UserCred, models.VM_UNKNOWN, err.Error()) self.SetStageComplete(ctx, nil) - logclient.AddActionLog(guest, logclient.ACT_VM_SYNC_STATUS, err, self.UserCred) + logclient.AddActionLog(guest, logclient.ACT_VM_SYNC_STATUS, err, self.UserCred, false) } diff --git a/pkg/util/logclient/logclient.go b/pkg/util/logclient/logclient.go index 391408305a..6c873896ce 100644 --- a/pkg/util/logclient/logclient.go +++ b/pkg/util/logclient/logclient.go @@ -39,11 +39,12 @@ const ( ACT_UPDATE = "更新" ACT_VM_ATTACH_DISK = "挂载磁盘" ACT_VM_CHANGE_FLAVOR = "调整配置" - ACT_VM_DEPLOY = "启用" + ACT_VM_DEPLOY = "部署" ACT_VM_DETACH_DISK = "卸载磁盘" ACT_VM_PURGE = "清除" ACT_VM_REBUILD = "重装系统" ACT_VM_RESET_PSWD = "重置密码" + ACT_VM_BIND_KEYPAIR = "绑定密钥" ACT_VM_START = "开机" ACT_VM_STOP = "关机" ACT_VM_SYNC_CONF = "同步配置" @@ -56,10 +57,10 @@ type IObject interface { Keyword() string } -func AddActionLog(model IObject, action string, iErr interface{}, userCred mcclient.TokenCredential) { +func AddActionLog(model IObject, action string, iNotes interface{}, userCred mcclient.TokenCredential, success bool) { token := userCred - notes := stringutils.Interface2String(iErr) + notes := stringutils.Interface2String(iNotes) s := auth.GetSession(userCred, "", "") @@ -73,7 +74,7 @@ func AddActionLog(model IObject, action string, iErr interface{}, userCred mccli logentry.Add(jsonutils.NewString(token.GetTenantId()), "tenant_id") logentry.Add(jsonutils.NewString(token.GetTenantName()), "tenant") - if len(notes) > 0 { + if !success { // 失败日志 logentry.Add(jsonutils.JSONFalse, "success") } else { From 4e070f5c9124a952d722d1207d38729be2c93b6e Mon Sep 17 00:00:00 2001 From: Zhang Dongliang Date: Fri, 31 Aug 2018 09:40:51 +0800 Subject: [PATCH 19/32] rm log --- pkg/compute/tasks/guest_deploy_task.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/compute/tasks/guest_deploy_task.go b/pkg/compute/tasks/guest_deploy_task.go index bd40cf4c3e..bea1290b3b 100644 --- a/pkg/compute/tasks/guest_deploy_task.go +++ b/pkg/compute/tasks/guest_deploy_task.go @@ -72,7 +72,6 @@ func (self *GuestDeployTask) OnDeployGuestComplete(ctx context.Context, obj db.I guest.GetDriver().OnGuestDeployTaskComplete(ctx, guest, self) action, _ := self.Params.GetString("deploy_action") keypair, _ := self.Params.GetString("keypair") - log.Debugf("KeyPair:", keypair, "lenof key", len(keypair)) reset_password := jsonutils.QueryBoolean(self.Params, "reset_password", false) if action == "deploy" && reset_password { From 2653a0645a3489e37cceb2c0c5749d28955182ad Mon Sep 17 00:00:00 2001 From: Zhang Dongliang Date: Fri, 31 Aug 2018 10:02:56 +0800 Subject: [PATCH 20/32] =?UTF-8?q?=E9=98=BF=E9=87=8C=E4=BA=91=E8=A7=A3?= =?UTF-8?q?=E7=BB=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/compute/tasks/guest_deploy_task.go | 25 +++++++++++++++++-------- pkg/util/logclient/logclient.go | 1 + 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/pkg/compute/tasks/guest_deploy_task.go b/pkg/compute/tasks/guest_deploy_task.go index bea1290b3b..b2156a763a 100644 --- a/pkg/compute/tasks/guest_deploy_task.go +++ b/pkg/compute/tasks/guest_deploy_task.go @@ -73,18 +73,27 @@ func (self *GuestDeployTask) OnDeployGuestComplete(ctx context.Context, obj db.I action, _ := self.Params.GetString("deploy_action") keypair, _ := self.Params.GetString("keypair") reset_password := jsonutils.QueryBoolean(self.Params, "reset_password", false) + unbind_kp := jsonutils.QueryBoolean(self.Params, "__delete_keypair__", false) + _log := false + if action == "deploy" { + if len(keypair) >= 32 { + if unbind_kp { + logclient.AddActionLog(guest, logclient.ACT_VM_UNBIND_KEYPAIR, nil, self.UserCred, true) + _log = true + } else { + logclient.AddActionLog(guest, logclient.ACT_VM_BIND_KEYPAIR, nil, self.UserCred, true) + _log = true + } - if action == "deploy" && reset_password { - keypair, _ := self.Params.GetString("keypair") - if len(keypair) > 0 { - logclient.AddActionLog(guest, logclient.ACT_VM_BIND_KEYPAIR, self.Params, self.UserCred, true) - } else { - logclient.AddActionLog(guest, logclient.ACT_VM_RESET_PSWD, self.Params, self.UserCred, true) + } else if reset_password { + logclient.AddActionLog(guest, logclient.ACT_VM_RESET_PSWD, "", self.UserCred, true) + _log = true } - } else { + } + if !_log { + // 如果 deploy 有其他事件,统一记在这里。 logclient.AddActionLog(guest, "misc部署", self.Params, self.UserCred, true) } - } func (self *GuestDeployTask) OnDeployGuestCompleteFailed(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { diff --git a/pkg/util/logclient/logclient.go b/pkg/util/logclient/logclient.go index 6c873896ce..6113cecf86 100644 --- a/pkg/util/logclient/logclient.go +++ b/pkg/util/logclient/logclient.go @@ -45,6 +45,7 @@ const ( ACT_VM_REBUILD = "重装系统" ACT_VM_RESET_PSWD = "重置密码" ACT_VM_BIND_KEYPAIR = "绑定密钥" + ACT_VM_UNBIND_KEYPAIR = "解绑密钥" ACT_VM_START = "开机" ACT_VM_STOP = "关机" ACT_VM_SYNC_CONF = "同步配置" From 4249e2486a04bd080218b59fc12ffe1f416ad6fa Mon Sep 17 00:00:00 2001 From: Zhang Dongliang Date: Fri, 31 Aug 2018 18:00:07 +0800 Subject: [PATCH 21/32] =?UTF-8?q?=E9=98=BF=E9=87=8C=E4=BA=91=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=99=A8=E5=90=8C=E6=AD=A5=E3=80=81=E5=85=A8=E9=87=8F?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E6=93=8D=E4=BD=9C=E6=97=A5=E5=BF=97=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tasks/cloud_provider_sync_info_task.go | 84 ++++++++++++++----- pkg/util/logclient/logclient.go | 6 +- 2 files changed, 69 insertions(+), 21 deletions(-) diff --git a/pkg/compute/tasks/cloud_provider_sync_info_task.go b/pkg/compute/tasks/cloud_provider_sync_info_task.go index 997f0792f3..51700d543f 100644 --- a/pkg/compute/tasks/cloud_provider_sync_info_task.go +++ b/pkg/compute/tasks/cloud_provider_sync_info_task.go @@ -10,6 +10,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" "yunion.io/x/pkg/utils" ) @@ -21,6 +22,25 @@ func init() { taskman.RegisterTask(CloudProviderSyncInfoTask{}) } +func getAction(params *jsonutils.JSONDict) string { + fullSync := jsonutils.QueryBoolean(params, "full_sync", false) + if !fullSync { + syncRangeJson, _ := params.Get("sync_range") + if syncRangeJson != nil { + fullSync = jsonutils.QueryBoolean(syncRangeJson, "full_sync", false) + } + } + + action := "" + + if fullSync { + action = logclient.ACT_CLOUD_FULLSYNC + } else { + action = logclient.ACT_CLOUD_SYNC + } + return action +} + func taskFail(ctx context.Context, task *CloudProviderSyncInfoTask, provider *models.SCloudprovider, reason string) { provider.SetStatus(task.UserCred, models.CLOUD_PROVIDER_DISCONNECTED, reason) task.SetStageFailed(ctx, reason) @@ -31,7 +51,8 @@ func (self *CloudProviderSyncInfoTask) OnInit(ctx context.Context, obj db.IStand provider.MarkStartSync(self.UserCred) // do sync - log.Infof("Start sync cloud provider status ...") + notes := fmt.Sprintf("Start sync cloud provider status ...") + log.Infof(notes) driver, err := provider.GetDriver() if err != nil { reason := fmt.Sprintf("Invalid cloud provider %s", err) @@ -60,16 +81,18 @@ func (self *CloudProviderSyncInfoTask) OnInit(ctx context.Context, obj db.IStand provider.SetStatus(self.UserCred, models.CLOUD_PROVIDER_CONNECTED, "") self.SetStageComplete(ctx, nil) + logclient.AddActionLog(provider, getAction(self.Params), body, self.UserCred, true) } func logSyncFailed(provider *models.SCloudprovider, task taskman.ITask, reason string) { db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, reason, task.GetUserCred()) + logclient.AddActionLog(provider, getAction(task.GetParams()), reason, task.GetUserCred(), false) } func syncCloudProviderInfo(ctx context.Context, provider *models.SCloudprovider, task *CloudProviderSyncInfoTask, driver cloudprovider.ICloudProvider, syncRange *models.SSyncRange) { - log.Infof("Start sync host info ...") + notes := fmt.Sprintf("Start sync host info ...") + log.Infof(notes) db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_START, "", task.UserCred) - regions := driver.GetIRegions() localRegions, remoteRegions, result := models.CloudregionManager.SyncRegions(ctx, task.UserCred, provider.Provider, regions) msg := result.Result() @@ -80,6 +103,7 @@ func syncCloudProviderInfo(ctx context.Context, provider *models.SCloudprovider, } db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.UserCred) + logclient.AddActionLog(provider, getAction(task.Params), "", task.UserCred, true) for i := 0; i < len(localRegions); i += 1 { if len(syncRange.Region) > 0 && !utils.IsInStringArray(localRegions[i].Id, syncRange.Region) { continue @@ -112,12 +136,14 @@ func syncRegionZones(ctx context.Context, provider *models.SCloudprovider, task } localZones, remoteZones, result := models.ZoneManager.SyncZones(ctx, task.UserCred, localRegion, zones) msg := result.Result() - log.Infof("SyncZones for region %s result: %s", localRegion.Name, msg) + notes := fmt.Sprintf("SyncZones for region %s result: %s", localRegion.Name, msg) + log.Infof(notes) if result.IsError() { logSyncFailed(provider, task, msg) return nil, nil } db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.UserCred) + logclient.AddActionLog(provider, getAction(task.Params), notes, task.UserCred, true) return localZones, remoteZones } @@ -132,13 +158,14 @@ func syncRegionVPCs(ctx context.Context, provider *models.SCloudprovider, task * localVpcs, remoteVpcs, result := models.VpcManager.SyncVPCs(ctx, task.UserCred, provider, localRegion, vpcs) msg := result.Result() - log.Infof("SyncVPCs for region %s result: %s", localRegion.Name, msg) + notes := fmt.Sprintf("SyncVPCs for region %s result: %s", localRegion.Name, msg) + log.Infof(notes) if result.IsError() { logSyncFailed(provider, task, msg) return } db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.UserCred) - + logclient.AddActionLog(provider, getAction(task.Params), notes, task.UserCred, true) for j := 0; j < len(localVpcs); j += 1 { syncVpcWires(ctx, provider, task, &localVpcs[j], remoteVpcs[j]) syncVpcSecGroup(ctx, provider, task, &localVpcs[j], remoteVpcs[j]) @@ -154,7 +181,8 @@ func syncVpcSecGroup(ctx context.Context, provider *models.SCloudprovider, task } else { _, _, result := models.SecurityGroupManager.SyncSecgroups(ctx, task.UserCred, secgroups) msg := result.Result() - log.Infof("SyncSecurityGroup for VPC %s result: %s", localVpc.Name, msg) + notes := fmt.Sprintf("SyncSecurityGroup for VPC %s result: %s", localVpc.Name, msg) + log.Infof(notes) if result.IsError() { logSyncFailed(provider, task, msg) return @@ -172,12 +200,14 @@ func syncVpcWires(ctx context.Context, provider *models.SCloudprovider, task tas } localWires, remoteWires, result := models.WireManager.SyncWires(ctx, task.GetUserCred(), localVpc, wires) msg := result.Result() - log.Infof("SyncWires for VPC %s result: %s", localVpc.Name, msg) + notes := fmt.Sprintf("SyncWires for VPC %s result: %s", localVpc.Name, msg) + log.Infof(notes) if result.IsError() { logSyncFailed(provider, task, msg) return } db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.GetUserCred()) + logclient.AddActionLog(provider, getAction(task.GetParams()), notes, task.GetUserCred(), true) for i := 0; i < len(localWires); i += 1 { syncWireNetworks(ctx, provider, task, &localWires[i], remoteWires[i]) } @@ -193,12 +223,14 @@ func syncWireNetworks(ctx context.Context, provider *models.SCloudprovider, task } _, _, result := models.NetworkManager.SyncNetworks(ctx, task.GetUserCred(), localWire, nets) msg := result.Result() - log.Infof("SyncNetworks for wire %s result: %s", localWire.Name, msg) + notes := fmt.Sprintf("SyncNetworks for wire %s result: %s", localWire.Name, msg) + log.Infof(notes) if result.IsError() { logSyncFailed(provider, task, msg) return } db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.GetUserCred()) + logclient.AddActionLog(provider, getAction(task.GetParams()), notes, task.GetUserCred(), true) } func syncZoneStorages(ctx context.Context, provider *models.SCloudprovider, task *CloudProviderSyncInfoTask, localZone *models.SZone, remoteZone cloudprovider.ICloudZone) { @@ -211,12 +243,14 @@ func syncZoneStorages(ctx context.Context, provider *models.SCloudprovider, task } localStorages, remoteStorages, result := models.StorageManager.SyncStorages(ctx, task.UserCred, provider, localZone, storages) msg := result.Result() - log.Infof("SyncZones for region %s result: %s", localZone.Name, msg) + notes := fmt.Sprintf("SyncZones for region %s result: %s", localZone.Name, msg) + log.Infof(notes) if result.IsError() { logSyncFailed(provider, task, msg) return } db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.UserCred) + logclient.AddActionLog(provider, getAction(task.GetParams()), notes, task.GetUserCred(), true) for i := 0; i < len(localStorages); i += 1 { syncStorageCaches(ctx, provider, task, &localStorages[i], remoteStorages[i]) @@ -251,12 +285,14 @@ func syncStorageDisks(ctx context.Context, provider *models.SCloudprovider, task } _, _, result := models.DiskManager.SyncDisks(ctx, task.UserCred, localStorage, disks) msg := result.Result() - log.Infof("SyncDisks for storage %s result: %s", localStorage.Name, msg) + notes := fmt.Sprintf("SyncDisks for storage %s result: %s", localStorage.Name, msg) + log.Infof(notes) if result.IsError() { logSyncFailed(provider, task, msg) return } db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.UserCred) + logclient.AddActionLog(provider, getAction(task.Params), notes, task.UserCred, true) } func syncZoneHosts(ctx context.Context, provider *models.SCloudprovider, task *CloudProviderSyncInfoTask, localZone *models.SZone, remoteZone cloudprovider.ICloudZone, syncRange *models.SSyncRange) { @@ -269,13 +305,14 @@ func syncZoneHosts(ctx context.Context, provider *models.SCloudprovider, task *C } localHosts, remoteHosts, result := models.HostManager.SyncHosts(ctx, task.UserCred, provider, localZone, hosts) msg := result.Result() - log.Infof("SyncHosts for zone %s result: %s", localZone.Name, msg) + notes := fmt.Sprintf("SyncHosts for zone %s result: %s", localZone.Name, msg) + log.Infof(notes) if result.IsError() { logSyncFailed(provider, task, msg) return } db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.UserCred) - + logclient.AddActionLog(provider, getAction(task.Params), notes, task.UserCred, true) for i := 0; i < len(localHosts); i += 1 { if len(syncRange.Host) > 0 && !utils.IsInStringArray(localHosts[i].Id, syncRange.Host) { continue @@ -296,12 +333,14 @@ func syncHostStorages(ctx context.Context, provider *models.SCloudprovider, task } result := localHost.SyncHostStorages(ctx, task.UserCred, storages) msg := result.Result() - log.Infof("SyncHostStorages for host %s result: %s", localHost.Name, msg) + notes := fmt.Sprintf("SyncHostStorages for host %s result: %s", localHost.Name, msg) + log.Infof(notes) if result.IsError() { logSyncFailed(provider, task, msg) return } db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.UserCred) + logclient.AddActionLog(provider, getAction(task.Params), notes, task.UserCred, true) } func syncHostWires(ctx context.Context, provider *models.SCloudprovider, task taskman.ITask, localHost *models.SHost, remoteHost cloudprovider.ICloudHost) { @@ -314,12 +353,14 @@ func syncHostWires(ctx context.Context, provider *models.SCloudprovider, task ta } result := localHost.SyncHostWires(ctx, task.GetUserCred(), wires) msg := result.Result() - log.Infof("SyncHostWires for host %s result: %s", localHost.Name, msg) + notes := fmt.Sprintf("SyncHostWires for host %s result: %s", localHost.Name, msg) + log.Infof(notes) if result.IsError() { logSyncFailed(provider, task, msg) return } db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.GetUserCred()) + logclient.AddActionLog(provider, getAction(task.GetParams()), notes, task.GetUserCred(), true) } func syncHostVMs(ctx context.Context, provider *models.SCloudprovider, task *CloudProviderSyncInfoTask, localHost *models.SHost, remoteHost cloudprovider.ICloudHost) { @@ -332,13 +373,14 @@ func syncHostVMs(ctx context.Context, provider *models.SCloudprovider, task *Clo } localVMs, remoteVMs, result := localHost.SyncHostVMs(ctx, task.UserCred, vms) msg := result.Result() - log.Infof("SyncHostVMs for host %s result: %s", localHost.Name, msg) + notes := fmt.Sprintf("SyncHostVMs for host %s result: %s", localHost.Name, msg) + log.Infof(notes) if result.IsError() { logSyncFailed(provider, task, msg) return } db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.UserCred) - + logclient.AddActionLog(provider, getAction(task.Params), notes, task.UserCred, true) for i := 0; i < len(localVMs); i += 1 { syncVMNics(ctx, provider, task, localHost, &localVMs[i], remoteVMs[i]) syncVMDisks(ctx, provider, task, localHost, &localVMs[i], remoteVMs[i]) @@ -355,12 +397,14 @@ func syncVMNics(ctx context.Context, provider *models.SCloudprovider, task *Clou } result := localVM.SyncVMNics(ctx, task.UserCred, host, nics) msg := result.Result() - log.Infof("syncVMNics for VM %s result: %s", localVM.Name, msg) + notes := fmt.Sprintf("syncVMNics for VM %s result: %s", localVM.Name, msg) + log.Infof(notes) if result.IsError() { logSyncFailed(provider, task, msg) return } db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.UserCred) + logclient.AddActionLog(provider, getAction(task.Params), notes, task.UserCred, true) } func syncVMDisks(ctx context.Context, provider *models.SCloudprovider, task *CloudProviderSyncInfoTask, host *models.SHost, localVM *models.SGuest, remoteVM cloudprovider.ICloudVM) { @@ -373,10 +417,12 @@ func syncVMDisks(ctx context.Context, provider *models.SCloudprovider, task *Clo } result := localVM.SyncVMDisks(ctx, task.UserCred, host, disks) msg := result.Result() - log.Infof("syncVMNics for VM %s result: %s", localVM.Name, msg) + notes := fmt.Sprintf("syncVMNics for VM %s result: %s", localVM.Name, msg) + log.Infof(notes) if result.IsError() { logSyncFailed(provider, task, msg) return } db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.UserCred) + logclient.AddActionLog(provider, getAction(task.Params), notes, task.UserCred, true) } diff --git a/pkg/util/logclient/logclient.go b/pkg/util/logclient/logclient.go index 6113cecf86..3e070285b3 100644 --- a/pkg/util/logclient/logclient.go +++ b/pkg/util/logclient/logclient.go @@ -19,6 +19,8 @@ const ( ACT_BM_UNMAINTENANCE = "退出离线状态" ACT_CANCEL_DELETE = "恢复" ACT_CHANGE_OWNER = "更改项目" + ACT_CLOUD_FULLSYNC = "全量同步" + ACT_CLOUD_SYNC = "同步" ACT_CREATE = "创建" ACT_DELETE = "删除" ACT_DISABLE = "禁用" @@ -38,18 +40,18 @@ const ( ACT_UNCACHED_IMAGE = "清除缓存" ACT_UPDATE = "更新" ACT_VM_ATTACH_DISK = "挂载磁盘" + ACT_VM_BIND_KEYPAIR = "绑定密钥" ACT_VM_CHANGE_FLAVOR = "调整配置" ACT_VM_DEPLOY = "部署" ACT_VM_DETACH_DISK = "卸载磁盘" ACT_VM_PURGE = "清除" ACT_VM_REBUILD = "重装系统" ACT_VM_RESET_PSWD = "重置密码" - ACT_VM_BIND_KEYPAIR = "绑定密钥" - ACT_VM_UNBIND_KEYPAIR = "解绑密钥" ACT_VM_START = "开机" ACT_VM_STOP = "关机" ACT_VM_SYNC_CONF = "同步配置" ACT_VM_SYNC_STATUS = "同步状态" + ACT_VM_UNBIND_KEYPAIR = "解绑密钥" ) type IObject interface { From c559bcd9331deca9af276e5fa50ebe1c933a01b2 Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Fri, 31 Aug 2018 10:01:37 +0000 Subject: [PATCH 22/32] resourcebase: updated_at: set list:"user" --- pkg/cloudcommon/db/resourcebase.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cloudcommon/db/resourcebase.go b/pkg/cloudcommon/db/resourcebase.go index 4c8bbcb480..a4289f2df6 100644 --- a/pkg/cloudcommon/db/resourcebase.go +++ b/pkg/cloudcommon/db/resourcebase.go @@ -13,7 +13,7 @@ type SResourceBase struct { SModelBase CreatedAt time.Time `nullable:"false" created_at:"true" get:"user"` - UpdatedAt time.Time `nullable:"false" updated_at:"true"` + UpdatedAt time.Time `nullable:"false" updated_at:"true" list:"user"` UpdateVersion int `default:"0" nullable:"false" auto_version:"true"` DeletedAt time.Time `` Deleted bool `nullable:"false" default:"false"` From 0094a5cffc925796cc7ef1095f0c12592054c30e Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Fri, 31 Aug 2018 10:00:48 +0000 Subject: [PATCH 23/32] mcclient: options: BaseListOptions: make OrderBy a list option --- pkg/mcclient/options/base.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/mcclient/options/base.go b/pkg/mcclient/options/base.go index 35cee54cef..aeacdce442 100644 --- a/pkg/mcclient/options/base.go +++ b/pkg/mcclient/options/base.go @@ -144,7 +144,7 @@ func ListStructToParams(v interface{}) (*jsonutils.JSONDict, error) { type BaseListOptions struct { Limit *int `default:"20" help:"Page limit"` Offset *int `default:"0" help:"Page offset"` - OrderBy string `help:"Name of the field to be ordered by"` + OrderBy []string `help:"Name of the field to be ordered by"` Order string `help:"List order" choices:"desc|asc"` Details *bool `help:"Show more details"` Search string `help:"Filter results by a simple keyword search"` From 3356e3b1148e258a7559287331e75a39374f581e Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Fri, 31 Aug 2018 22:58:49 +0800 Subject: [PATCH 24/32] =?UTF-8?q?=E8=B0=83=E5=BA=A6=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?=E5=90=8E=E4=B8=BB=E6=9C=BA=E8=87=AA=E5=8A=A8=E5=85=81=E8=AE=B8?= =?UTF-8?q?=E5=88=A0=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/compute/models/guests.go | 12 ++++++++++++ pkg/compute/tasks/guest_batch_create_task.go | 1 + 2 files changed, 13 insertions(+) diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 7676350d30..454e438dfe 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -2733,3 +2733,15 @@ func (manager *SGuestManager) CleanPendingDeleteServers(ctx context.Context, use guests[i].StartDeleteGuestTask(ctx, userCred, "", false, true) } } + +func (self *SGuest) SetDisableDelete(val bool) error { + _, err := self.GetModelManager().TableSpec().Update(self, func() error { + if val { + self.DisableDelete = tristate.True + } else { + self.DisableDelete = tristate.False + } + return nil + }) + return err +} diff --git a/pkg/compute/tasks/guest_batch_create_task.go b/pkg/compute/tasks/guest_batch_create_task.go index b13c695e16..a91f6ab4de 100644 --- a/pkg/compute/tasks/guest_batch_create_task.go +++ b/pkg/compute/tasks/guest_batch_create_task.go @@ -77,6 +77,7 @@ func (self *GuestBatchCreateTask) onScheduleFail(ctx context.Context, guest *mod if len(msg) > 0 { reason = fmt.Sprintf("%s: %s", reason, msg) } + guest.SetDisableDelete(false) guest.SetStatus(self.UserCred, models.VM_SCHEDULE_FAILED, reason) db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, reason, self.UserCred) notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_SCHEDULE_FAILED, reason) From 6eee82ab3fca515d58026b9ba548524aa8597326 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Sun, 2 Sep 2018 19:58:33 +0800 Subject: [PATCH 25/32] =?UTF-8?q?=E5=8F=AA=E6=9C=89guest.DisableDelete=3D?= =?UTF-8?q?=3Dtrue=E7=9A=84=E6=97=B6=E5=80=99=E6=89=8D=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/compute/tasks/guest_batch_create_task.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/compute/tasks/guest_batch_create_task.go b/pkg/compute/tasks/guest_batch_create_task.go index a91f6ab4de..b3a6c10dba 100644 --- a/pkg/compute/tasks/guest_batch_create_task.go +++ b/pkg/compute/tasks/guest_batch_create_task.go @@ -77,7 +77,9 @@ func (self *GuestBatchCreateTask) onScheduleFail(ctx context.Context, guest *mod if len(msg) > 0 { reason = fmt.Sprintf("%s: %s", reason, msg) } - guest.SetDisableDelete(false) + if guest.DisableDelete.IsTrue() { + guest.SetDisableDelete(false) + } guest.SetStatus(self.UserCred, models.VM_SCHEDULE_FAILED, reason) db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, reason, self.UserCred) notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_SCHEDULE_FAILED, reason) From 4f024ad28223386d0581d3d0a6c1f6038ba8f44e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=88=E8=BD=A9?= Date: Mon, 3 Sep 2018 10:53:19 +0800 Subject: [PATCH 26/32] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=90=8C=E6=AD=A5log?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/cloudcommon/db/opslog.go | 3 +++ pkg/compute/models/disks.go | 9 +++++++++ pkg/compute/models/guests.go | 5 +++++ pkg/util/aliyun/disk.go | 2 ++ 4 files changed, 19 insertions(+) diff --git a/pkg/cloudcommon/db/opslog.go b/pkg/cloudcommon/db/opslog.go index 11ad4edf6e..c531f74f40 100644 --- a/pkg/cloudcommon/db/opslog.go +++ b/pkg/cloudcommon/db/opslog.go @@ -113,6 +113,9 @@ const ( ACT_UNCACHE_IMAGE_FAIL = "uncache_image_fail" ACT_UNCACHED_IMAGE = "uncached_image" + ACT_SYNC_CLOUD_DISK = "sync_cloud_disk" + ACT_SYNC_CLOUD_SERVER = "sync_cloud_server" + ACT_SPLIT = "net_split" ACT_PENDING_DELETE = "pending_delete" diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index b05fa85b5e..d8a21a6664 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -591,6 +591,7 @@ func (manager *SDiskManager) newFromCloudDisk(ctx context.Context, userCred mccl } } + db.OpsLog.LogEvent(&disk, db.ACT_SYNC_CLOUD_DISK, disk.GetShortDesc(), userCred) return &disk, nil } @@ -925,6 +926,14 @@ func (self *SDisk) GetShortDesc() *jsonutils.JSONDict { desc.Add(jsonutils.NewString(priceKey), "price_key") } + if hypervisor := self.GetMetadata("hypervisor", nil); len(hypervisor) > 0 { + desc.Add(jsonutils.NewString(hypervisor), "hypervisor") + } + + if len(self.ExternalId) > 0 { + desc.Add(jsonutils.NewString(self.ExternalId), "externalId") + } + fs := self.GetFsFormat() if len(fs) > 0 { desc.Add(jsonutils.NewString(fs), "fs_format") diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 5706dedf53..655d215806 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -1305,6 +1305,7 @@ func (manager *SGuestManager) newCloudVM(ctx context.Context, userCred mcclient. } } + db.OpsLog.LogEvent(&guest, db.ACT_SYNC_CLOUD_SERVER, guest.GetShortDesc(), userCred) return &guest, nil } @@ -3185,6 +3186,10 @@ func (self *SGuest) GetShortDesc() *jsonutils.JSONDict { desc.Add(jsonutils.NewString(priceKey), "price_key") } + if len(self.ExternalId) > 0 { + desc.Add(jsonutils.NewString(self.ExternalId), "externalId") + } + desc.Set("hypervisor", jsonutils.NewString(self.GetHypervisor())) spec := self.GetSpec(false) if self.GetHypervisor() == HYPERVISOR_BAREMETAL { diff --git a/pkg/util/aliyun/disk.go b/pkg/util/aliyun/disk.go index 7349b8c7c0..74fe06c4f8 100644 --- a/pkg/util/aliyun/disk.go +++ b/pkg/util/aliyun/disk.go @@ -61,6 +61,8 @@ func (self *SDisk) GetMetadata() *jsonutils.JSONDict { priceKey := fmt.Sprintf("%s::%s::%s", self.RegionId, self.Category, self.Type) data.Add(jsonutils.NewString(priceKey), "price_key") + data.Add(jsonutils.NewString(models.HYPERVISOR_ALIYUN), "hypervisor") + return data } From 6a5ad9208d0b0e65c9daaaedd3e7df46fcc7bf08 Mon Sep 17 00:00:00 2001 From: Zexi Li Date: Mon, 3 Sep 2018 12:18:53 +0800 Subject: [PATCH 27/32] =?UTF-8?q?region:=20=E6=94=AF=E6=8C=81=20container?= =?UTF-8?q?=20network?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/compute/models/networks.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/compute/models/networks.go b/pkg/compute/models/networks.go index e4df6a1ea0..c4864dd3ee 100644 --- a/pkg/compute/models/networks.go +++ b/pkg/compute/models/networks.go @@ -13,6 +13,7 @@ import ( "yunion.io/x/pkg/util/fileutils" "yunion.io/x/pkg/util/netutils" "yunion.io/x/pkg/util/regutils" + "yunion.io/x/pkg/util/sets" "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" @@ -30,6 +31,7 @@ const ( SERVER_TYPE_GUEST = "guest" SERVER_TYPE_BAREMETAL = "baremetal" + SERVER_TYPE_CONTAINER = "container" STATIC_ALLOC = "static" @@ -965,7 +967,7 @@ func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred serverTypeStr, _ := data.GetString("server_type") if len(serverTypeStr) == 0 { serverTypeStr = SERVER_TYPE_GUEST - } else if serverTypeStr != SERVER_TYPE_GUEST && serverTypeStr != SERVER_TYPE_BAREMETAL { + } else if !sets.NewString(SERVER_TYPE_GUEST, SERVER_TYPE_BAREMETAL, SERVER_TYPE_CONTAINER).Has(serverTypeStr) { return nil, httperrors.NewInputParameterError("Invalid server_type: %s", serverTypeStr) } data.Add(jsonutils.NewString(serverTypeStr), "server_type") From 67fc4d1ba9b8fbfb9e59292ee64d09319056e929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=88=E8=BD=A9?= Date: Wed, 29 Aug 2018 14:24:05 +0800 Subject: [PATCH 28/32] =?UTF-8?q?=E6=94=AF=E6=8C=81server-save-image?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/cloudprovider/resources.go | 13 +++ pkg/compute/guestdrivers/baremetals.go | 5 + pkg/compute/guestdrivers/virtualization.go | 9 ++ pkg/compute/hostdrivers/aliyun.go | 49 ++++++++ pkg/compute/hostdrivers/kvm.go | 23 ++++ pkg/compute/models/disks.go | 90 +++++++++++++++ pkg/compute/models/guestdrivers.go | 2 + pkg/compute/models/guests.go | 37 ++++++ pkg/compute/models/hostdrivers.go | 2 + pkg/compute/tasks/disk_save_task.go | 107 +++++++++++++++++ pkg/compute/tasks/guest_save_image_task.go | 65 +++++++++++ pkg/mcclient/modules/mod_images.go | 47 ++++---- pkg/util/aliyun/disk.go | 107 +++++++++++++++++ pkg/util/aliyun/image.go | 31 +++++ pkg/util/aliyun/shell/snapshot.go | 45 ++++++++ pkg/util/aliyun/snapshot.go | 73 ++++++++++++ pkg/util/aliyun/storagecache.go | 128 +++++++++++++++++++++ 17 files changed, 813 insertions(+), 20 deletions(-) create mode 100644 pkg/compute/tasks/disk_save_task.go create mode 100644 pkg/compute/tasks/guest_save_image_task.go create mode 100644 pkg/util/aliyun/shell/snapshot.go create mode 100644 pkg/util/aliyun/snapshot.go diff --git a/pkg/cloudprovider/resources.go b/pkg/cloudprovider/resources.go index 3c333f8946..54877f315a 100644 --- a/pkg/cloudprovider/resources.go +++ b/pkg/cloudprovider/resources.go @@ -56,6 +56,7 @@ type ICloudZone interface { type ICloudImage interface { ICloudResource + Delete() error GetIStoragecache() ICloudStoragecache } @@ -66,6 +67,9 @@ type ICloudStoragecache interface { GetManagerId() string + CreateIImage(snapshotId, imageName, imageDesc string) (ICloudImage, error) + + DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string) (jsonutils.JSONObject, error) UploadImage(userCred mcclient.TokenCredential, imageId string, extId string, isForce bool) (string, error) } @@ -200,9 +204,18 @@ type ICloudDisk interface { GetMountpoint() string Delete() error + CreateISnapshot(name string, desc string) (ICloudSnapshot, error) + GetISnapshot(idStr string) (ICloudSnapshot, error) + GetISnapshots() ([]ICloudSnapshot, error) + Resize(newSize int64) error } +type ICloudSnapshot interface { + ICloudResource + Delete() error +} + type ICloudVpc interface { ICloudResource diff --git a/pkg/compute/guestdrivers/baremetals.go b/pkg/compute/guestdrivers/baremetals.go index 2ec935e955..d12ebc0716 100644 --- a/pkg/compute/guestdrivers/baremetals.go +++ b/pkg/compute/guestdrivers/baremetals.go @@ -9,6 +9,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" ) @@ -172,3 +173,7 @@ func (self *SBaremetalGuestDriver) StartGuestDetachdiskTask(ctx context.Context, func (self *SBaremetalGuestDriver) StartSuspendTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error { return fmt.Errorf("Cannot suspend a baremetal serer") } + +func (self *SBaremetalGuestDriver) StartGuestSaveImage(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error { + return httperrors.NewUnsupportOperationError("Cannot save image for baremtal") +} diff --git a/pkg/compute/guestdrivers/virtualization.go b/pkg/compute/guestdrivers/virtualization.go index 7efdd6d475..a9ef20f3f1 100644 --- a/pkg/compute/guestdrivers/virtualization.go +++ b/pkg/compute/guestdrivers/virtualization.go @@ -193,3 +193,12 @@ func (self *SVirtualizedGuestDriver) StartSuspendTask(ctx context.Context, userC task.ScheduleRun(nil) return nil } + +func (self *SVirtualizedGuestDriver) StartGuestSaveImage(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error { + if task, err := taskman.TaskManager.NewTask(ctx, "GuestSaveImageTask", guest, userCred, params, parentTaskId, "", nil); err != nil { + return err + } else { + task.ScheduleRun(nil) + } + return nil +} diff --git a/pkg/compute/hostdrivers/aliyun.go b/pkg/compute/hostdrivers/aliyun.go index 4c1d7bf029..e0977b298b 100644 --- a/pkg/compute/hostdrivers/aliyun.go +++ b/pkg/compute/hostdrivers/aliyun.go @@ -2,11 +2,13 @@ package hostdrivers import ( "context" + "fmt" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/httperrors" ) type SAliyunHostDriver struct { @@ -48,6 +50,53 @@ func (self *SAliyunHostDriver) CheckAndSetCacheImage(ctx context.Context, host * return nil } +func (self *SAliyunHostDriver) RequestPrepareSaveDiskOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask) error { + task.ScheduleRun(nil) + return nil +} + +func (self *SAliyunHostDriver) RequestSaveUploadImageOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask, data jsonutils.JSONObject) error { + if iDisk, err := disk.GetIDisk(); err != nil { + return err + } else if iStorage, err := disk.GetIStorage(); err != nil { + return err + } else if iStoragecache := iStorage.GetIStoragecache(); iStoragecache == nil { + return httperrors.NewResourceNotFoundError("fail to find iStoragecache for storage: %s", iStorage.GetName()) + } else { + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + if snapshot, err := iDisk.CreateISnapshot(fmt.Sprintf("Snapshot-%s", imageId), "PrepareSaveImage"); err != nil { + return nil, err + } else { + scimg := models.StoragecachedimageManager.Register(ctx, task.GetUserCred(), iStoragecache.GetId(), imageId) + if scimg.Status != models.CACHED_IMAGE_STATUS_READY { + scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHING, "request_prepare_save_disk_on_host") + } + if iImage, err := iStoragecache.CreateIImage(snapshot.GetId(), fmt.Sprintf("Image-%s", imageId), ""); err != nil { + log.Errorf("fail to create iImage: %v", err) + scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHE_FAILED, err.Error()) + return nil, err + } else { + scimg.SetExternalId(iImage.GetId()) + if result, err := iStoragecache.DownloadImage(task.GetUserCred(), imageId, iImage.GetId()); err != nil { + scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHE_FAILED, err.Error()) + return nil, err + } else { + if err := iImage.Delete(); err != nil { + log.Errorf("Delete iImage %s failed: %v", iImage.GetId(), err) + } + if err := snapshot.Delete(); err != nil { + log.Errorf("Delete snapshot %s failed: %v", snapshot.GetId(), err) + } + scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_READY, "") + return result, nil + } + } + } + }) + } + return nil +} + func (self *SAliyunHostDriver) RequestAllocateDiskOnStorage(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask, content *jsonutils.JSONDict) error { if iCloudStorage, err := storage.GetIStorage(); err != nil { return err diff --git a/pkg/compute/hostdrivers/kvm.go b/pkg/compute/hostdrivers/kvm.go index ed08542a36..9bcd07cce3 100644 --- a/pkg/compute/hostdrivers/kvm.go +++ b/pkg/compute/hostdrivers/kvm.go @@ -124,3 +124,26 @@ func (self *SKVMHostDriver) RequestResizeDiskOnHostOnline(host *models.SHost, st } return nil } + +func (self *SKVMHostDriver) RequestPrepareSaveDiskOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask) error { + body := jsonutils.NewDict() + body.Add(jsonutils.Marshal(map[string]string{"image_id": imageId}), "disk") + url := fmt.Sprintf("/disks/%s/save-prepare/%s", disk.StorageId, disk.Id) + header := http.Header{"X-Task-Id": []string{task.GetTaskId()}, "X-Region-Version": []string{"v2"}} + _, err := host.Request(task.GetUserCred(), "POST", url, header, body) + return err +} + +func (self *SKVMHostDriver) RequestSaveUploadImageOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask, data jsonutils.JSONObject) error { + body := jsonutils.NewDict() + backup, _ := data.GetString("backup") + content := map[string]string{"image_path": backup, "image_id": imageId, "storagecached_id": disk.GetStorage().StoragecacheId} + if data.Contains("format") { + content["format"], _ = data.GetString("format") + } + body.Add(jsonutils.Marshal(content), "disk") + url := fmt.Sprintf("/disks/%s/upload", disk.StorageId) + header := http.Header{"X-Task-Id": []string{task.GetTaskId()}, "X-Region-Version": []string{"v2"}} + _, err := host.Request(task.GetUserCred(), "POST", url, header, body) + return err +} diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index b05fa85b5e..badf077755 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -27,6 +27,8 @@ import ( "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" + "yunion.io/x/onecloud/pkg/mcclient/modules" ) const ( @@ -358,6 +360,94 @@ func (self *SDisk) PerformResize(ctx context.Context, userCred mcclient.TokenCre } } +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + if storage := self.GetStorage(); storage == nil { + return nil, httperrors.NewResourceNotFoundError("fail to find storage for disk %s", self.GetName()) + } else if provider, err := storage.GetDriver(); err != nil { + return nil, err + } else { + return provider.GetIStorageById(storage.GetExternalId()) + } +} + +func (self *SDisk) GetIDisk() (cloudprovider.ICloudDisk, error) { + if iStorage, err := self.GetIStorage(); err != nil { + log.Errorf("fail to find iStorage: %v", err) + return nil, err + } else { + return iStorage.GetIDisk(self.GetExternalId()) + } +} + +func (self *SDisk) GetZone() *SZone { + if storage := self.GetStorage(); storage != nil { + return storage.getZone() + } + return nil +} + +func (self *SDisk) PrepareSaveImage(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (string, error) { + if zone := self.GetZone(); zone == nil { + return "", httperrors.NewResourceNotFoundError("No zone for this disk") + } + data.Add(jsonutils.NewString(self.DiskFormat), "disk_format") + name, _ := data.GetString("name") + s := auth.GetAdminSession(options.Options.Region, "") + if imageList, err := modules.Images.List(s, jsonutils.Marshal(map[string]string{"name": name, "admin": "true"})); err != nil { + return "", err + } else if imageList.Total > 0 { + return "", httperrors.NewConflictError("Duplicate image name %s", name) + } + quota := SQuota{Image: 1} + if _, err := QuotaManager.CheckQuota(ctx, userCred, userCred.GetProjectId(), "a); err != nil { + return "", err + } + data.Add(jsonutils.NewInt(int64(self.DiskSize)), "virtual_size") + if result, err := modules.Images.Create(s, data); err != nil { + return "", err + } else if imageId, err := result.GetString("id"); err != nil { + return "", err + } else { + return imageId, nil + } +} + +func (self *SDisk) AllowPerformSave(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return self.IsOwner(userCred) +} + +func (self *SDisk) PerformSave(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + if self.Status != DISK_READY { + return nil, httperrors.NewResourceNotReadyError("Save disk when disk is READY") + + } + if self.GetRuningGuestCount() > 0 { + return nil, httperrors.NewResourceNotReadyError("Save disk when not being USED") + } + + if name, err := data.GetString("name"); err != nil || len(name) == 0 { + return nil, httperrors.NewInputParameterError("Image name is required") + } + kwargs := data.(*jsonutils.JSONDict) + if imageId, err := self.PrepareSaveImage(ctx, userCred, kwargs); err != nil { + return nil, err + } else { + kwargs.Add(jsonutils.NewString(imageId), "image_id") + return nil, self.StartDiskSaveTask(ctx, userCred, kwargs, "") + } +} + +func (self *SDisk) StartDiskSaveTask(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error { + self.SetStatus(userCred, DISK_START_SAVE, "") + if task, err := taskman.TaskManager.NewTask(ctx, "DiskSaveTask", self, userCred, data, parentTaskId, "", nil); err != nil { + log.Errorf("Start DiskSaveTask failed:%v", err) + return err + } else { + task.ScheduleRun(nil) + } + return nil +} + func (self *SDisk) ValidateDeleteCondition(ctx context.Context) error { if self.GetGuestDiskCount() > 0 { return httperrors.NewNotEmptyError("Virtual disk used by virtual servers") diff --git a/pkg/compute/models/guestdrivers.go b/pkg/compute/models/guestdrivers.go index 48406df24f..4d841ddae7 100644 --- a/pkg/compute/models/guestdrivers.go +++ b/pkg/compute/models/guestdrivers.go @@ -61,6 +61,8 @@ type IGuestDriver interface { StartDeleteGuestTask(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, params *jsonutils.JSONDict, parentTaskId string) error + StartGuestSaveImage(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, params *jsonutils.JSONDict, parentTaskId string) error + RequestStopGuestForDelete(ctx context.Context, guest *SGuest, task taskman.ITask) error RequestDetachDisksFromGuestForDelete(ctx context.Context, guest *SGuest, task taskman.ITask) error diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index afd50582dc..1423bfa7ba 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -1560,6 +1560,43 @@ func (self *SGuest) attach2Disk(disk *SDisk, userCred mcclient.TokenCredential, return err } +func (self *SGuest) AllowPerformSaveImage(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + log.Infof("permission: %s", self.IsOwner(userCred)) + return self.IsOwner(userCred) +} + +func (self *SGuest) PerformSaveImage(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + if !utils.IsInStringArray(self.Status, []string{VM_READY}) { + return nil, httperrors.NewInputParameterError("Cannot save image in status %s", self.Status) + } else if !data.Contains("name") { + return nil, httperrors.NewInputParameterError("Image name is required") + } else if disks := self.CategorizeDisks(); disks.Root == nil { + return nil, httperrors.NewInputParameterError("No root image") + } else { + kwargs := data.(*jsonutils.JSONDict) + restart := self.Status == VM_RUNNING + properties := jsonutils.NewDict() + if notes, err := data.GetString("notes"); err != nil && len(notes) > 0 { + properties.Add(jsonutils.NewString(notes), "notes") + } + properties.Add(jsonutils.NewString(self.OsType), "os_type") + kwargs.Add(properties, "properties") + kwargs.Add(jsonutils.NewBool(restart), "restart") + lockman.LockObject(ctx, disks.Root) + defer lockman.ReleaseObject(ctx, disks.Root) + if imageId, err := disks.Root.PrepareSaveImage(ctx, userCred, kwargs); err != nil { + return nil, err + } else { + kwargs.Add(jsonutils.NewString(imageId), "image_id") + } + return nil, self.StartGuestSaveImage(ctx, userCred, kwargs, "") + } +} + +func (self *SGuest) StartGuestSaveImage(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error { + return self.GetDriver().StartGuestSaveImage(ctx, userCred, self, data, parentTaskId) +} + func (self *SGuest) AllowPerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { return self.IsOwner(userCred) } diff --git a/pkg/compute/models/hostdrivers.go b/pkg/compute/models/hostdrivers.go index 6749e5ac68..1d125b0cba 100644 --- a/pkg/compute/models/hostdrivers.go +++ b/pkg/compute/models/hostdrivers.go @@ -12,6 +12,8 @@ import ( type IHostDriver interface { GetHostType() string CheckAndSetCacheImage(ctx context.Context, host *SHost, storagecache *SStoragecache, scimg *SStoragecachedimage, task taskman.ITask) error + RequestPrepareSaveDiskOnHost(ctx context.Context, host *SHost, disk *SDisk, imageId string, task taskman.ITask) error + RequestSaveUploadImageOnHost(ctx context.Context, host *SHost, disk *SDisk, imageId string, task taskman.ITask, data jsonutils.JSONObject) error RequestAllocateDiskOnStorage(ctx context.Context, host *SHost, storage *SStorage, disk *SDisk, task taskman.ITask, content *jsonutils.JSONDict) error RequestDeallocateDiskOnHost(host *SHost, storage *SStorage, disk *SDisk, task taskman.ITask) error RequestResizeDiskOnHostOnline(host *SHost, storage *SStorage, disk *SDisk, size int64, task taskman.ITask) error diff --git a/pkg/compute/tasks/disk_save_task.go b/pkg/compute/tasks/disk_save_task.go new file mode 100644 index 0000000000..8990ae8ff2 --- /dev/null +++ b/pkg/compute/tasks/disk_save_task.go @@ -0,0 +1,107 @@ +package tasks + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" + "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/onecloud/pkg/mcclient/auth" + mc "yunion.io/x/onecloud/pkg/mcclient/modules" +) + +type DiskSaveTask struct { + SDiskBaseTask +} + +func init() { + taskman.RegisterTask(DiskSaveTask{}) +} + +func (self *DiskSaveTask) GetMasterHost(disk *models.SDisk) *models.SHost { + if guests := disk.GetGuests(); len(guests) == 1 { + if host := guests[0].GetHost(); host == nil { + if storage := disk.GetStorage(); storage != nil { + return storage.GetMasterHost() + } + } else { + return host + } + } + return nil +} + +func (self *DiskSaveTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + disk := obj.(*models.SDisk) + if host := self.GetMasterHost(disk); host == nil { + resion := "Cannot find host for disk" + disk.SetDiskReady(ctx, self.GetUserCred(), resion) + self.TaskFailed(ctx, resion) + db.OpsLog.LogEvent(disk, db.ACT_SAVE_FAIL, resion, self.GetUserCred()) + } else { + disk.SetStatus(self.GetUserCred(), models.DISK_START_SAVE, "") + for _, guest := range disk.GetGuests() { + guest.SetStatus(self.GetUserCred(), models.VM_SAVE_DISK, "") + } + self.StartBackupDisk(ctx, disk, host) + } +} + +func (self *DiskSaveTask) StartBackupDisk(ctx context.Context, disk *models.SDisk, host *models.SHost) { + self.SetStage("on_disk_backup_complete", nil) + disk.SetStatus(self.GetUserCred(), models.DISK_SAVING, "") + imageId, _ := self.GetParams().GetString("image_id") + if err := host.GetHostDriver().RequestPrepareSaveDiskOnHost(ctx, host, disk, imageId, self); err != nil { + log.Errorf("Backup failed: %v", err) + disk.SetDiskReady(ctx, self.GetUserCred(), err.Error()) + self.TaskFailed(ctx, err.Error()) + db.OpsLog.LogEvent(disk, db.ACT_SAVE_FAIL, err.Error(), self.GetUserCred()) + } +} + +func (self *DiskSaveTask) OnDiskBackupCompleteFailed(ctx context.Context, disk *models.SDisk, data jsonutils.JSONObject) { + disk.SetDiskReady(ctx, self.GetUserCred(), data.String()) + db.OpsLog.LogEvent(disk, db.ACT_SAVE_FAIL, data.String(), self.GetUserCred()) +} + +func (self *DiskSaveTask) OnDiskBackupComplete(ctx context.Context, disk *models.SDisk, data *jsonutils.JSONDict) { + disk.SetDiskReady(ctx, self.GetUserCred(), "") + db.OpsLog.LogEvent(disk, db.ACT_SAVE, disk.GetShortDesc(), self.GetUserCred()) + self.SetStageComplete(ctx, nil) + imageId, _ := self.GetParams().GetString("image_id") + if host := self.GetMasterHost(disk); host == nil { + log.Errorf("Saved disk Host mast not be nil") + self.TaskFailed(ctx, "Saved disk Host mast not be nil") + } else { + if self.Params.Contains("format") { + format, _ := self.Params.Get("format") + data.Add(format, "format") + } + if err := self.UploadDisk(ctx, host, disk, imageId, data); err != nil { + log.Errorf("UploadDisk failed: %v", err) + self.TaskFailed(ctx, err.Error()) + } + self.RefreshImageCache(ctx, imageId) + } +} + +func (self *DiskSaveTask) RefreshImageCache(ctx context.Context, imageId string) { + models.CachedimageManager.GetImageById(ctx, self.GetUserCred(), imageId, true) +} + +func (self *DiskSaveTask) UploadDisk(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, data *jsonutils.JSONDict) error { + return host.GetHostDriver().RequestSaveUploadImageOnHost(ctx, host, disk, imageId, self, jsonutils.Marshal(data)) +} + +func (self *DiskSaveTask) TaskFailed(ctx context.Context, resion string) { + self.SetStageFailed(ctx, resion) + if imageId, err := self.GetParams().GetString("image_id"); err != nil && len(imageId) > 0 { + log.Errorf("save disk task failed, set image %s killed", imageId) + s := auth.GetAdminSession(options.Options.Region, "") + mc.Images.Update(s, imageId, jsonutils.Marshal(map[string]string{"status": "killed"})) + } +} diff --git a/pkg/compute/tasks/guest_save_image_task.go b/pkg/compute/tasks/guest_save_image_task.go new file mode 100644 index 0000000000..c6c13bfc2b --- /dev/null +++ b/pkg/compute/tasks/guest_save_image_task.go @@ -0,0 +1,65 @@ +package tasks + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" + "yunion.io/x/onecloud/pkg/compute/models" +) + +type GuestSaveImageTask struct { + SGuestBaseTask +} + +func init() { + taskman.RegisterTask(GuestSaveImageTask{}) +} + +func (self *GuestSaveImageTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) { + guest := obj.(*models.SGuest) + log.Infof("Saving server image: %s", guest.Name) + if restart, _ := self.GetParams().Bool("restart"); restart { + self.SetStage("on_stop_server_complete", nil) + guest.StartGuestStopTask(ctx, self.GetUserCred(), false, self.GetTaskId()) + } else { + self.OnStopServerComplete(ctx, guest, nil) + } +} + +func (self *GuestSaveImageTask) OnStopServerComplete(ctx context.Context, guest *models.SGuest, body jsonutils.JSONObject) { + if guest.Status != models.VM_READY { + resion := fmt.Sprintf("Server %s not in ready status", guest.Name) + log.Errorf(resion) + self.SetStageFailed(ctx, resion) + } else { + self.SetStage("on_save_root_image_complete", nil) + guest.SetStatus(self.GetUserCred(), models.VM_START_SAVE_DISK, "") + disks := guest.CategorizeDisks() + if err := disks.Root.StartDiskSaveTask(ctx, self.GetUserCred(), self.GetParams(), self.GetTaskId()); err != nil { + self.SetStageFailed(ctx, err.Error()) + } + } +} + +func (self *GuestSaveImageTask) OnSaveRootImageComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { + if restart, _ := self.GetParams().Bool("restart"); restart { + self.SetStage("on_start_server_complete", nil) + guest.StartGueststartTask(ctx, self.GetUserCred(), nil, self.GetTaskId()) + } else { + self.SetStageComplete(ctx, nil) + } +} + +func (self *GuestSaveImageTask) OnSaveRootImageCompleteFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { + log.Errorf("Guest save root image failed: %s", data.PrettyString()) + guest.SetStatus(self.GetUserCred(), models.VM_SAVE_DISK_FAILED, data.PrettyString()) + self.SetStageFailed(ctx, data.PrettyString()) +} + +func (self *GuestSaveImageTask) OnStartServerCompleteFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { + self.SetStageComplete(ctx, nil) +} diff --git a/pkg/mcclient/modules/mod_images.go b/pkg/mcclient/modules/mod_images.go index c7423c2436..ae06aff2ab 100644 --- a/pkg/mcclient/modules/mod_images.go +++ b/pkg/mcclient/modules/mod_images.go @@ -428,24 +428,32 @@ func (this *ImageManager) _create(s *mcclient.ClientSession, params jsonutils.JS if !exists { return nil, fmt.Errorf("Unsupported image format %s", format) } - osType, err := params.GetString("properties", "os_type") - if err != nil { - return nil, fmt.Errorf("Can't get os_type from params: %s", params.String()) - } - exists, _ = utils.InStringArray(osType, []string{"Windows", "Linux", "Freebsd", "Android", "macOS", "VMWare"}) - if !exists { - return nil, fmt.Errorf("OS type must be specified") - } - name, _ := params.GetString("name") - if len(name) == 0 { - return nil, fmt.Errorf("Missing name") - } - dupName, e := this.IsNameDuplicate(s, name) - if dupName { - return nil, fmt.Errorf("Duplicate name %s", name) - } - if e != nil { - return nil, fmt.Errorf("Check name duplicate error %s", e) + imageId, _ := params.GetString("image_id") + path := fmt.Sprintf("/%s", this.URLPath()) + method := "POST" + if len(imageId) == 0 { + osType, err := params.GetString("properties", "os_type") + if err != nil { + return nil, fmt.Errorf("Can't get os_type from params: %s", params.String()) + } + exists, _ = utils.InStringArray(osType, []string{"Windows", "Linux", "Freebsd", "Android", "macOS", "VMWare"}) + if !exists { + return nil, fmt.Errorf("OS type must be specified") + } + name, _ := params.GetString("name") + if len(name) == 0 { + return nil, fmt.Errorf("Missing name") + } + dupName, e := this.IsNameDuplicate(s, name) + if dupName { + return nil, fmt.Errorf("Duplicate name %s", name) + } + if e != nil { + return nil, fmt.Errorf("Check name duplicate error %s", e) + } + } else { + path = fmt.Sprintf("/%s/%s", this.URLPath(), imageId) + method = "PUT" } headers, e := setImageMeta(params) if e != nil { @@ -467,8 +475,7 @@ func (this *ImageManager) _create(s *mcclient.ClientSession, params jsonutils.JS headers.Add("Content-Length", fmt.Sprintf("%d", size)) } } - path := fmt.Sprintf("/%s", this.URLPath()) - resp, err := this.rawRequest(s, "POST", path, headers, body) + resp, err := this.rawRequest(s, method, path, headers, body) _, json, err := s.ParseJSONResponse(resp, err) if err != nil { return nil, err diff --git a/pkg/util/aliyun/disk.go b/pkg/util/aliyun/disk.go index 7349b8c7c0..7975916e80 100644 --- a/pkg/util/aliyun/disk.go +++ b/pkg/util/aliyun/disk.go @@ -260,3 +260,110 @@ func (self *SRegion) resizeDisk(diskId string, size int64) error { return nil } + +func (self *SDisk) CreateISnapshot(name, desc string) (cloudprovider.ICloudSnapshot, error) { + if snapshotId, err := self.storage.zone.region.CreateSnapshot(self.DiskId, name, desc); err != nil { + log.Errorf("createSnapshot fail %s", err) + return nil, err + } else if snapshot, err := self.getSnapshot(snapshotId); err != nil { + return nil, err + } else { + snapshot.disk = self + if err := cloudprovider.WaitStatus(snapshot, string(SnapshotStatusAccoplished), 15*time.Second, 3600*time.Second); err != nil { + return nil, err + } + return snapshot, nil + } +} + +func (self *SRegion) CreateSnapshot(diskId, name, desc string) (string, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["DiskId"] = diskId + params["SnapshotName"] = name + params["Description"] = desc + + if body, err := self.ecsRequest("CreateSnapshot", params); err != nil { + log.Errorf("CreateSnapshot fail %s", err) + return "", err + } else { + return body.GetString("SnapshotId") + } +} + +func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + if snapshot, err := self.getSnapshot(snapshotId); err != nil { + return nil, err + } else { + snapshot.disk = self + return snapshot, nil + } +} + +func (self *SDisk) getSnapshot(snapshotId string) (*SSnapshot, error) { + if snapshots, total, err := self.storage.zone.region.GetSnapshots("", "", "", []string{snapshotId}, 0, 1); err != nil { + return nil, err + } else if total != 1 { + return nil, cloudprovider.ErrNotFound + } else { + return &snapshots[0], nil + } +} + +func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots := make([]SSnapshot, 0) + for { + if parts, total, err := self.storage.zone.region.GetSnapshots("", self.DiskId, "", []string{}, 0, 20); err != nil { + log.Errorf("GetDisks fail %s", err) + return nil, err + } else { + snapshots = append(snapshots, parts...) + if len(snapshots) >= total { + break + } + } + } + isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots)) + for i := 0; i < len(snapshots); i++ { + snapshots[i].disk = self + isnapshots[i] = &snapshots[i] + } + return isnapshots, nil +} + +func (self *SRegion) GetSnapshots(instanceId string, diskId string, snapshotName string, snapshotIds []string, offset int, limit int) ([]SSnapshot, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + if len(instanceId) > 0 { + params["InstanceId"] = instanceId + } + if len(diskId) > 0 { + params["diskId"] = diskId + } + if len(snapshotName) > 0 { + params["SnapshotName"] = snapshotName + } + if snapshotIds != nil && len(snapshotIds) > 0 { + params["SnapshotIds"] = jsonutils.Marshal(snapshotIds).String() + } + + if body, err := self.ecsRequest("DescribeSnapshots", params); err != nil { + log.Errorf("GetSnapshots fail %s", err) + return nil, 0, err + } else { + snapshots := make([]SSnapshot, 0) + if err := body.Unmarshal(&snapshots, "Snapshots", "Snapshot"); err != nil { + log.Errorf("Unmarshal snapshot details fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return snapshots, int(total), nil + } + +} diff --git a/pkg/util/aliyun/image.go b/pkg/util/aliyun/image.go index 849e9eb570..dfdddbcbfd 100644 --- a/pkg/util/aliyun/image.go +++ b/pkg/util/aliyun/image.go @@ -5,6 +5,7 @@ import ( "strings" "time" + "github.com/aliyun/aliyun-oss-go-sdk/oss" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudprovider" @@ -71,6 +72,10 @@ func (self *SImage) IsEmulated() bool { return false } +func (self *SImage) Delete() error { + return self.storageCache.region.DeleteImage(self.ImageId) +} + func (self *SImage) GetGlobalId() string { return fmt.Sprintf("%s-%s") } @@ -102,6 +107,32 @@ func (self *SImage) Refresh() error { return jsonutils.Update(self, new) } +type ImageExportTask struct { + ImageId string + RegionId string + // RequestId string + TaskId string +} + +func (self *SRegion) ExportImage(imageId string, bucket *oss.Bucket) (*ImageExportTask, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["ImageId"] = imageId + params["OssBucket"] = bucket.BucketName + params["OssPrefix"] = fmt.Sprintf("%sexport", strings.Replace(imageId, "-", "", -1)) + + if body, err := self.ecsRequest("ExportImage", params); err != nil { + return nil, err + } else { + result := ImageExportTask{} + if err := body.Unmarshal(&result); err != nil { + log.Errorf("unmarshal result error %s", err) + return nil, err + } + return &result, nil + } +} + // {"ImageId":"m-j6c1qlpa7oebbg1n2k60","RegionId":"cn-hongkong","RequestId":"F8B2F6A1-F6AA-4C92-A54C-C4A309CF811F","TaskId":"t-j6c1qlpa7oebbg1rcl9t"} type ImageImportTask struct { diff --git a/pkg/util/aliyun/shell/snapshot.go b/pkg/util/aliyun/shell/snapshot.go new file mode 100644 index 0000000000..5bfe219871 --- /dev/null +++ b/pkg/util/aliyun/shell/snapshot.go @@ -0,0 +1,45 @@ +package shell + +import ( + "yunion.io/x/onecloud/pkg/util/aliyun" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type SnapshotListOptions struct { + DiskId string `help:"Disk ID"` + InstanceId string `help:"Instance ID"` + SnapshotIds []string `helo:"Snapshot ids"` + Name string `help:"Snapshot Name"` + Limit int `help:"page size"` + Offset int `help:"page offset"` + } + shellutils.R(&SnapshotListOptions{}, "snapshot-list", "List snapshot", func(cli *aliyun.SRegion, args *SnapshotListOptions) error { + if snapshots, total, err := cli.GetSnapshots(args.InstanceId, args.DiskId, args.Name, args.SnapshotIds, args.Offset, args.Limit); err != nil { + return err + } else { + printList(snapshots, total, args.Offset, args.Limit, []string{}) + return nil + } + }) + + type SnapshotDeleteOptions struct { + ID string `help:"Snapshot ID"` + } + + shellutils.R(&SnapshotDeleteOptions{}, "snapshot-delete", "Delete snapshot", func(cli *aliyun.SRegion, args *SnapshotDeleteOptions) error { + return cli.DeleteSnapshot(args.ID) + }) + + type SnapshotCreateOptions struct { + DiskId string `help:"Disk ID"` + Name string `help:"Snapeshot Name"` + Desc string `help:"Snapshot Desc"` + } + + shellutils.R(&SnapshotCreateOptions{}, "snapshot-create", "Create snapshot", func(cli *aliyun.SRegion, args *SnapshotCreateOptions) error { + _, err := cli.CreateSnapshot(args.DiskId, args.Name, args.Desc) + return err + }) + +} diff --git a/pkg/util/aliyun/snapshot.go b/pkg/util/aliyun/snapshot.go new file mode 100644 index 0000000000..bfab3ae94d --- /dev/null +++ b/pkg/util/aliyun/snapshot.go @@ -0,0 +1,73 @@ +package aliyun + +import ( + "fmt" + + "yunion.io/x/jsonutils" +) + +type SnapshotStatusType string + +const ( + SnapshotStatusAccoplished SnapshotStatusType = "accomplished" + SnapshotStatusProgress SnapshotStatusType = "progressing" +) + +type SSnapshot struct { + disk *SDisk + Progress string + SnapshotId string + SnapshotName string + SourceDiskId string + SourceDiskSize int32 + SourceDiskType string + Status SnapshotStatusType + Usage string +} + +func (self *SSnapshot) GetId() string { + return self.SnapshotId +} + +func (self *SSnapshot) GetName() string { + return self.SnapshotName +} + +func (self *SSnapshot) GetStatus() string { + return string(self.Status) +} + +func (self *SSnapshot) Refresh() error { + if snapshot, err := self.disk.getSnapshot(self.SnapshotId); err != nil { + return err + } else if err := jsonutils.Update(self, snapshot); err != nil { + return err + } + return nil +} + +func (self *SSnapshot) GetGlobalId() string { + return fmt.Sprintf("%s", self.SnapshotId) +} + +func (self *SSnapshot) IsEmulated() bool { + return false +} + +func (self *SRegion) DeleteSnapshot(snapshotId string) error { + params := make(map[string]string) + params["SnapshotId"] = snapshotId + _, err := self.ecsRequest("DeleteSnapshot", params) + return err +} + +func (self *SSnapshot) Delete() error { + if self.disk == nil { + return fmt.Errorf("not init disk for snapshot %s", self.SnapshotId) + } + return self.disk.storage.zone.region.DeleteSnapshot(self.SnapshotId) +} + +func (self *SSnapshot) GetMetadata() *jsonutils.JSONDict { + return nil +} diff --git a/pkg/util/aliyun/storagecache.go b/pkg/util/aliyun/storagecache.go index fab2072253..cab1cbd7ab 100644 --- a/pkg/util/aliyun/storagecache.go +++ b/pkg/util/aliyun/storagecache.go @@ -2,13 +2,17 @@ package aliyun import ( "fmt" + "os" "strings" "time" + "github.com/aliyun/aliyun-oss-go-sdk/oss" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudprovider" + compute "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/mcclient/modules" @@ -173,3 +177,127 @@ func (self *SStoragecache) uploadImage(userCred mcclient.TokenCredential, imageI return task.ImageId, nil } + +func (self *SStoragecache) CreateIImage(snapshoutId, imageName, imageDesc string) (cloudprovider.ICloudImage, error) { + if imageId, err := self.region.createIImage(snapshoutId, imageName, imageDesc); err != nil { + return nil, err + } else if image, err := self.region.GetImage(imageId); err != nil { + return nil, err + } else { + image.storageCache = self + iimage := make([]cloudprovider.ICloudImage, 1) + iimage[0] = image + if err := cloudprovider.WaitStatus(iimage[0], compute.IMAGE_STATUS_ACTIVE, 15*time.Second, 3600*time.Second); err != nil { + return nil, err + } + return iimage[0], nil + } +} + +func (self *SRegion) CheckBucket(bucketName string) (*oss.Bucket, error) { + return self.checkBucket(bucketName) +} + +func (self *SRegion) checkBucket(bucketName string) (*oss.Bucket, error) { + oss, err := self.GetOssClient() + if err != nil { + log.Errorf("GetOssClient err %s", err) + return nil, err + } + if exist, err := oss.IsBucketExist(bucketName); err != nil { + log.Errorf("IsBucketExist err %s", err) + return nil, err + } else if !exist { + log.Debugf("Bucket %s not exists, to create ...", bucketName) + if err := oss.CreateBucket(bucketName); err != nil { + log.Errorf("Create bucket error %s", err) + return nil, err + } + } + log.Debugf("Bucket %s exists", bucketName) + if bucket, err := oss.Bucket(bucketName); err != nil { + log.Errorf("Bucket error %s %s", bucketName, err) + return nil, err + } else { + return bucket, nil + } +} + +func (self *SRegion) createIImage(snapshoutId, imageName, imageDesc string) (string, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["OssBucket"] = strings.ToLower(fmt.Sprintf("imgcache-%s", self.GetId())) + params["SnapshotId"] = snapshoutId + params["ImageName"] = imageName + params["Description"] = imageDesc + + if _, err := self.checkBucket(params["OssBucket"]); err != nil { + return "", err + } + + if body, err := self.ecsRequest("CreateImage", params); err != nil { + log.Errorf("CreateImage fail %s", err) + return "", err + } else { + log.Infof("%s", body) + return body.GetString("ImageId") + } +} + +func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string) (jsonutils.JSONObject, error) { + return self.downloadImage(userCred, imageId, extId) +} + +// 定义进度条监听器。 +type OssProgressListener struct { +} + +// 定义进度变更事件处理函数。 +func (listener *OssProgressListener) ProgressChanged(event *oss.ProgressEvent) { + switch event.EventType { + case oss.TransferStartedEvent: + log.Debugf("Transfer Started, ConsumedBytes: %d, TotalBytes %d.\n", + event.ConsumedBytes, event.TotalBytes) + case oss.TransferDataEvent: + log.Debugf("\rTransfer Data, ConsumedBytes: %d, TotalBytes %d, %d%%.", + event.ConsumedBytes, event.TotalBytes, event.ConsumedBytes*100/event.TotalBytes) + case oss.TransferCompletedEvent: + log.Debugf("\nTransfer Completed, ConsumedBytes: %d, TotalBytes %d.\n", + event.ConsumedBytes, event.TotalBytes) + case oss.TransferFailedEvent: + log.Debugf("\nTransfer Failed, ConsumedBytes: %d, TotalBytes %d.\n", + event.ConsumedBytes, event.TotalBytes) + default: + } +} + +func (self *SStoragecache) downloadImage(userCred mcclient.TokenCredential, imageId string, extId string) (jsonutils.JSONObject, error) { + tmpImageFile := fmt.Sprintf("/tmp/%s", extId) + bucketName := strings.ToLower(fmt.Sprintf("imgcache-%s", self.region.GetId())) + if bucket, err := self.region.checkBucket(bucketName); err != nil { + return nil, err + } else if _, err := self.region.GetImage(extId); err != nil { + return nil, err + } else if task, err := self.region.ExportImage(extId, bucket); err != nil { + return nil, err + } else if err := self.region.waitTaskStatus(ExportImageTask, task.TaskId, "Finished", 15*time.Second, 3600*time.Second); err != nil { + return nil, err + } else if imageList, err := bucket.ListObjects(oss.Prefix(fmt.Sprintf("%sexport", strings.Replace(extId, "-", "", -1)))); err != nil { + return nil, err + } else if len(imageList.Objects) != 1 { + return nil, httperrors.NewResourceNotFoundError("exported image not find") + } else if err := bucket.DownloadFile(imageList.Objects[0].Key, tmpImageFile, 12*1024*1024, oss.Routines(3), oss.Progress(&OssProgressListener{})); err != nil { + return nil, err + } else { + s := auth.GetAdminSession(options.Options.Region, "") + params := jsonutils.Marshal(map[string]string{"image_id": imageId, "disk-format": "raw"}) + if file, err := os.Open(tmpImageFile); err != nil { + return nil, err + } else if result, err := modules.Images.Upload(s, params, file, imageList.Objects[0].Size); err != nil { + return nil, err + } else { + os.Remove(tmpImageFile) + return result, nil + } + } +} From 289db3be8eb9fb60690c2bf497fe713dfc3d7ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=88=E8=BD=A9?= Date: Mon, 3 Sep 2018 18:20:33 +0800 Subject: [PATCH 29/32] =?UTF-8?q?=E9=81=BF=E5=85=8Daliyun=E7=A3=81?= =?UTF-8?q?=E7=9B=98=E5=BE=AA=E7=8E=AF=E5=88=A0=E9=99=A4=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/util/aliyun/disk.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/util/aliyun/disk.go b/pkg/util/aliyun/disk.go index 74fe06c4f8..a27de87d4f 100644 --- a/pkg/util/aliyun/disk.go +++ b/pkg/util/aliyun/disk.go @@ -109,6 +109,11 @@ func (self *SDisk) GetId() string { } func (self *SDisk) Delete() error { + if _, err := self.storage.zone.region.getDisk(self.DiskId); err == cloudprovider.ErrNotFound { + // 未找到disk, 说明disk已经被删除了. 避免回收站中disk-delete循环删除失败 + log.Errorf("Failed to find disk %s when delete", self.DiskId) + return nil + } return self.storage.zone.region.deleteDisk(self.DiskId) } From dad762db6143a7475176d36bf4592cd21094d94a Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Mon, 3 Sep 2018 21:06:54 +0800 Subject: [PATCH 30/32] =?UTF-8?q?=E5=A2=9E=E5=8A=A0network-set-static-rout?= =?UTF-8?q?es=E7=AD=89=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/climc/shell/hosts.go | 34 ++++++++++++ cmd/climc/shell/networks.go | 107 ++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) diff --git a/cmd/climc/shell/hosts.go b/cmd/climc/shell/hosts.go index c7a44ccf07..5644f29465 100644 --- a/cmd/climc/shell/hosts.go +++ b/cmd/climc/shell/hosts.go @@ -474,4 +474,38 @@ func init() { return nil }) + type HostCreateOptions struct { + ZONE string `help:"Zone where the host is located"` + NAME string `help:"Name of baremetal"` + MAC string `help:"Default MAC address of baremetal"` + Rack string `help:"Rack number of baremetal"` + Slots string `help:"Slots number of baremetal"` + IpmiPasswd string `help:"IPMI user password"` + IpmiAddr string `help:"IPMI IP address"` + } + R(&HostCreateOptions{}, "host-create", "Create a baremetal host", func(s *mcclient.ClientSession, args *HostCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + params.Add(jsonutils.NewString(args.MAC), "access_mac") + params.Add(jsonutils.NewString("baremetal"), "host_type") + if len(args.Rack) > 0 { + params.Add(jsonutils.NewString(args.Rack), "rack") + } + if len(args.Slots) > 0 { + params.Add(jsonutils.NewString(args.Slots), "slots") + } + if len(args.IpmiPasswd) > 0 { + params.Add(jsonutils.NewString(args.IpmiPasswd), "ipmi_password") + } + if len(args.IpmiAddr) > 0 { + params.Add(jsonutils.NewString(args.IpmiAddr), "ipmi_ip_addr") + } + result, err := modules.Hosts.CreateInContext(s, params, &modules.Zones, args.ZONE) + if err != nil { + return err + } + printObject(result) + return nil + }) + } diff --git a/cmd/climc/shell/networks.go b/cmd/climc/shell/networks.go index 0e093b50a3..4fb19e8143 100644 --- a/cmd/climc/shell/networks.go +++ b/cmd/climc/shell/networks.go @@ -142,6 +142,15 @@ func init() { return nil }) + R(&NetworkShowOptions{}, "network-metadata", "Show metadata of a network", func(s *mcclient.ClientSession, args *NetworkShowOptions) error { + result, err := modules.Networks.GetMetadata(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + R(&NetworkShowOptions{}, "network-private", "Make a network private", func(s *mcclient.ClientSession, args *NetworkShowOptions) error { result, err := modules.Networks.PerformAction(s, args.ID, "private", nil) if err != nil { @@ -288,4 +297,102 @@ func init() { return nil }) + type NetworkStaticRoutesOptions struct { + NETWORK string `help:"ID or name of the network"` + Net []string `help:"destination network of static route"` + Gw []string `help:"gateway address for the static route"` + } + R(&NetworkStaticRoutesOptions{}, "network-set-static-routes", "Set static routes for a network", func(s *mcclient.ClientSession, args *NetworkStaticRoutesOptions) error { + params := jsonutils.NewDict() + if len(args.Net) > 0 && len(args.Gw) > 0 { + if len(args.Net) != len(args.Gw) { + return fmt.Errorf("Inconsistent network and gateway pairs") + } + routes := jsonutils.NewDict() + for i := 0; i < len(args.Net); i += 1 { + routes.Add(jsonutils.NewString(args.Gw[i]), args.Net[i]) + } + params.Add(routes, "static_routes") + } else { + params.Add(jsonutils.JSONNull, "static_routes") + } + result, err := modules.Networks.PerformAction(s, args.NETWORK, "metadata", params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type NetworkAddDnsUpdateTargetOptions struct { + ID string `help:"Network ID or name"` + DNS string `help:"DNS server address" metavar:"DNS_SERVER"` + KEY string `help:"DNS update key name" metavar:"DNS_UPDATE_KEY"` + SECRET string `help:"DNS update key secret" metavar:"DNS_UPDATE_SECRET"` + } + R(&NetworkAddDnsUpdateTargetOptions{}, "network-add-dns-update-target", "Add a dns update target to a network", func(s *mcclient.ClientSession, args *NetworkAddDnsUpdateTargetOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.DNS), "server") + params.Add(jsonutils.NewString(args.KEY), "key") + params.Add(jsonutils.NewString(args.SECRET), "secret") + result, err := modules.Networks.PerformAction(s, args.ID, "add-dns-update-target", params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type NetworkRemoveDnsUpdateTargetOptions struct { + ID string `help:"Network ID or name"` + DNS string `help:"DNS server address" metavar:"DNS_SERVER"` + KEY string `help:"DNS update key name" metavar:"DNS_UPDATE_KEY"` + } + R(&NetworkRemoveDnsUpdateTargetOptions{}, "network-remove-dns-update-target", "Remove a dns update target from a network", func(s *mcclient.ClientSession, args *NetworkRemoveDnsUpdateTargetOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.DNS), "server") + params.Add(jsonutils.NewString(args.KEY), "key") + result, err := modules.Networks.PerformAction(s, args.ID, "remove-dns-update-target", params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type NetworkSetDnsUpdateKeyOptions struct { + ID string `help:"ID of virtual network to update"` + KEY string `help:"Key name of secret" metavar:"KEYNAME"` + SECRET string `help:"Key secret"` + SERVER string `help:"Alternate DNS update server"` + } + R(&NetworkSetDnsUpdateKeyOptions{}, "network-set-dns-update-key", "Set DNS update key info for a virtual network", func(s *mcclient.ClientSession, args *NetworkSetDnsUpdateKeyOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.KEY), "dns_update_key_name") + params.Add(jsonutils.NewString(args.SECRET), "dns_update_key_secret") + params.Add(jsonutils.NewString(args.SERVER), "dns_update_server") + result, err := modules.Networks.PerformAction(s, args.ID, "metadata", params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type NetworkRemoveDnsUpdateKeyOptions struct { + ID string `help:"ID of virtual network"` + } + R(&NetworkRemoveDnsUpdateKeyOptions{}, "network-remove-dns-update-key", "Set DNS update key info for a virtual network", func(s *mcclient.ClientSession, args *NetworkRemoveDnsUpdateKeyOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.JSONNull, "dns_update_key_name") + params.Add(jsonutils.JSONNull, "dns_update_key_secret") + params.Add(jsonutils.JSONNull, "dns_update_server") + result, err := modules.Networks.PerformAction(s, args.ID, "metadata", params) + if err != nil { + return err + } + printObject(result) + return nil + }) + } From 77d4b477bf739700b95934bc85624bb2ece83c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=88=E8=BD=A9?= Date: Mon, 3 Sep 2018 17:51:13 +0800 Subject: [PATCH 31/32] =?UTF-8?q?storage-list=E6=98=BE=E7=A4=BA=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/compute/models/storages.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/pkg/compute/models/storages.go b/pkg/compute/models/storages.go index 3797e8a33e..313797ab1d 100644 --- a/pkg/compute/models/storages.go +++ b/pkg/compute/models/storages.go @@ -101,6 +101,30 @@ func (manager *SStorageManager) AllowListItems(ctx context.Context, userCred mcc return true } +func (self *SStorage) getMoreDetails(extra *jsonutils.JSONDict) *jsonutils.JSONDict { + used := self.GetUsedCapacity(tristate.True) + waste := self.GetUsedCapacity(tristate.False) + vcapa := float32(self.GetCapacity()) * self.GetOvercommitBound() + extra.Add(jsonutils.NewInt(int64(used)), "used_capacity") + extra.Add(jsonutils.NewInt(int64(waste)), "waste_capacity") + extra.Add(jsonutils.NewFloat(float64(vcapa)), "virtual_capacity") + extra.Add(jsonutils.NewFloat(float64(vcapa-float32(used)-float32(waste))), "free_capacity") + if self.GetCapacity() > 0 { + value := float64(used * 1.0 / self.GetCapacity()) + value = float64(int(value*100+0.5) / 100.0) + extra.Add(jsonutils.NewFloat(value), "commit_rate") + } else { + extra.Add(jsonutils.NewFloat(0.0), "commit_rate") + } + extra.Add(jsonutils.NewFloat(float64(self.GetOvercommitBound())), "commit_bound") + return extra +} + +func (self *SStorage) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict { + extra := self.SEnabledStatusStandaloneResourceBase.GetCustomizeColumns(ctx, userCred, query) + return self.getMoreDetails(extra) +} + func (self *SStorage) GetUsedCapacity(isReady tristate.TriState) int { disks := DiskManager.Query().SubQuery() q := disks.Query(sqlchemy.SUM("sum", disks.Field("disk_size"))).Equals("storage_id", self.Id) From b0c62d55124f8aeed565342c76fdbe81787c72c3 Mon Sep 17 00:00:00 2001 From: Zexi Li Date: Tue, 4 Sep 2018 16:25:38 +0800 Subject: [PATCH 32/32] climc: k8s resources cluster in query or data --- cmd/climc/shell/k8s/configmap.go | 3 ++- cmd/climc/shell/k8s/deployment.go | 11 +++++---- cmd/climc/shell/k8s/k8s.go | 8 ++++--- cmd/climc/shell/k8s/pods.go | 5 ++-- cmd/climc/shell/k8s/raw.go | 4 ++-- cmd/climc/shell/k8s/releases.go | 13 +++++++---- cmd/climc/shell/k8s/service.go | 3 ++- cmd/climc/shell/k8s/tiller.go | 4 ++-- pkg/mcclient/modules/k8s/raw.go | 38 +++++++++++-------------------- 9 files changed, 43 insertions(+), 46 deletions(-) diff --git a/cmd/climc/shell/k8s/configmap.go b/cmd/climc/shell/k8s/configmap.go index 30d8fd6d9e..6162aa1dc4 100644 --- a/cmd/climc/shell/k8s/configmap.go +++ b/cmd/climc/shell/k8s/configmap.go @@ -17,7 +17,8 @@ func initConfigMap() { R(&listOpt{}, cmdN("list"), "List k8s configmap", func(s *mcclient.ClientSession, args *listOpt) error { params := fetchNamespaceParams(args.namespaceListOptions) params.Update(fetchPagingParams(args.baseListOptions)) - ret, err := k8s.ConfigMaps.ListInContexts(s, params, args.ClusterContext()) + params.Update(args.ClusterParams()) + ret, err := k8s.ConfigMaps.List(s, params) if err != nil { return err } diff --git a/cmd/climc/shell/k8s/deployment.go b/cmd/climc/shell/k8s/deployment.go index 6063b59739..87e027725b 100644 --- a/cmd/climc/shell/k8s/deployment.go +++ b/cmd/climc/shell/k8s/deployment.go @@ -25,7 +25,8 @@ func initDeployment() { R(&listOpt{}, cmdN("list"), "List k8s deployment", func(s *mcclient.ClientSession, args *listOpt) error { params := fetchNamespaceParams(args.namespaceListOptions) params.Update(fetchPagingParams(args.baseListOptions)) - ret, err := k8s.Deployments.ListInContexts(s, params, args.ClusterContext()) + params.Update(args.ClusterParams()) + ret, err := k8s.Deployments.List(s, params) if err != nil { return err } @@ -45,7 +46,7 @@ func initDeployment() { Net string `help:"Network config, e.g. net1, net1:10.168.222.171"` } R(&createOpt{}, cmdN("create"), "Create deployment resource", func(s *mcclient.ClientSession, args *createOpt) error { - params := jsonutils.NewDict() + params := args.ClusterParams() if len(args.Image) == 0 { return fmt.Errorf("Image must provided") } @@ -74,7 +75,7 @@ func initDeployment() { } params.Add(net, "networkConfig") } - ret, err := k8s.Deployments.CreateInContexts(s, params, args.ClusterContext()) + ret, err := k8s.Deployments.Create(s, params) if err != nil { return err } @@ -87,11 +88,11 @@ func initDeployment() { } R(&getOpt{}, cmdN("show"), "Get deployment details", func(s *mcclient.ClientSession, args *getOpt) error { id := args.NAME - params := jsonutils.NewDict() + params := args.ClusterParams() if args.Namespace != "" { params.Add(jsonutils.NewString(args.Namespace), "namespace") } - ret, err := k8s.Deployments.GetInContexts(s, id, params, args.ClusterContext()) + ret, err := k8s.Deployments.Get(s, id, params) if err != nil { return err } diff --git a/cmd/climc/shell/k8s/k8s.go b/cmd/climc/shell/k8s/k8s.go index 3b8dc9d72c..b48d68e45e 100644 --- a/cmd/climc/shell/k8s/k8s.go +++ b/cmd/climc/shell/k8s/k8s.go @@ -33,8 +33,10 @@ type clusterBaseOptions struct { Cluster string `default:"$K8S_CLUSTER|default" help:"Kubernetes cluster name"` } -func (o clusterBaseOptions) ClusterContext() []modules.ManagerContext { - return []modules.ManagerContext{clusterContext(o.Cluster)} +func (o clusterBaseOptions) ClusterParams() *jsonutils.JSONDict { + ret := jsonutils.NewDict() + ret.Add(jsonutils.NewString(o.Cluster), "cluster") + return ret } type baseListOptions struct { @@ -70,7 +72,7 @@ type resourceGetOptions struct { } func (o resourceGetOptions) ToJSON() *jsonutils.JSONDict { - params := jsonutils.NewDict() + params := o.ClusterParams() if o.Namespace != "" { params.Add(jsonutils.NewString(o.Namespace), "namespace") } diff --git a/cmd/climc/shell/k8s/pods.go b/cmd/climc/shell/k8s/pods.go index 5620609826..5376147feb 100644 --- a/cmd/climc/shell/k8s/pods.go +++ b/cmd/climc/shell/k8s/pods.go @@ -19,7 +19,8 @@ func initPod() { R(&listOpt{}, cmdN("list"), "List k8s pod", func(s *mcclient.ClientSession, args *listOpt) error { params := fetchNamespaceParams(args.namespaceListOptions) params.Update(fetchPagingParams(args.baseListOptions)) - ret, err := k8s.Pods.ListInContexts(s, params, args.ClusterContext()) + params.Update(args.ClusterParams()) + ret, err := k8s.Pods.List(s, params) if err != nil { return err } @@ -32,7 +33,7 @@ func initPod() { } R(&deleteOpt{}, cmdN("delete"), "Delete pod", func(s *mcclient.ClientSession, args *deleteOpt) error { id := args.NAME - ret, err := k8s.Pods.DeleteInContexts(s, id, args.ToJSON(), args.ClusterContext()) + ret, err := k8s.Pods.Delete(s, id, args.ToJSON()) if err != nil { return err } diff --git a/cmd/climc/shell/k8s/raw.go b/cmd/climc/shell/k8s/raw.go index 6aeb500f91..79c6f8537d 100644 --- a/cmd/climc/shell/k8s/raw.go +++ b/cmd/climc/shell/k8s/raw.go @@ -17,7 +17,7 @@ type rawDeleteOpt struct { func initRaw() { R(&rawGetOpt{}, "k8s-get", "Get k8s resource instance raw info", func(s *mcclient.ClientSession, args *rawGetOpt) error { - obj, err := k8s.RawResource.Get(s, args.KIND, args.Namespace, args.NAME, nil, args.ClusterContext()) + obj, err := k8s.RawResource.Get(s, args.KIND, args.Namespace, args.NAME, args.ClusterParams()) if err != nil { return err } @@ -26,7 +26,7 @@ func initRaw() { }) R(&rawDeleteOpt{}, "k8s-delete", "Delete k8s resource instance", func(s *mcclient.ClientSession, args *rawDeleteOpt) error { - err := k8s.RawResource.Delete(s, args.KIND, args.Namespace, args.NAME, nil, args.ClusterContext()) + err := k8s.RawResource.Delete(s, args.KIND, args.Namespace, args.NAME, args.ClusterParams()) if err != nil { return err } diff --git a/cmd/climc/shell/k8s/releases.go b/cmd/climc/shell/k8s/releases.go index 179fb199b4..cbbcc52d87 100644 --- a/cmd/climc/shell/k8s/releases.go +++ b/cmd/climc/shell/k8s/releases.go @@ -29,6 +29,7 @@ func initRelease() { R(&listOpt{}, cmdN("list"), "List k8s cluster helm releases", func(s *mcclient.ClientSession, args *listOpt) error { params := fetchNamespaceParams(args.namespaceListOptions) params.Update(fetchPagingParams(args.baseListOptions)) + params.Update(args.ClusterParams()) if args.Filter != "" { params.Add(json.NewString(args.Filter), "filter") } @@ -57,7 +58,7 @@ func initRelease() { if args.Pending { params.Add(json.JSONTrue, "pending") } - ret, err := k8s.Releases.ListInContexts(s, params, args.ClusterContext()) + ret, err := k8s.Releases.List(s, params) if err != nil { return err } @@ -70,7 +71,7 @@ func initRelease() { NAME string `help:"Release instance name"` } R(&showOpt{}, cmdN("show"), "Get helm release details", func(s *mcclient.ClientSession, args *showOpt) error { - ret, err := k8s.Releases.GetInContexts(s, args.NAME, nil, args.ClusterContext()) + ret, err := k8s.Releases.Get(s, args.NAME, args.ClusterParams()) if err != nil { return err } @@ -121,6 +122,7 @@ func initRelease() { if err != nil { return err } + params.Update(args.ClusterParams()) params.Add(json.NewString(args.CHARTNAME), "chart_name") if args.Namespace != "" { params.Add(json.NewString(args.Namespace), "namespace") @@ -128,7 +130,7 @@ func initRelease() { if args.Name != "" { params.Add(json.NewString(args.Name), "release_name") } - ret, err := k8s.Releases.CreateInContexts(s, params, args.ClusterContext()) + ret, err := k8s.Releases.Create(s, params) if err != nil { return err } @@ -149,6 +151,7 @@ func initRelease() { if err != nil { return err } + params.Update(args.ClusterParams()) params.Add(json.NewString(args.CHARTNAME), "chart_name") params.Add(json.NewString(args.NAME), "release_name") if args.ReuseValues { @@ -158,7 +161,7 @@ func initRelease() { params.Add(json.JSONTrue, "reset_values") } - res, err := k8s.Releases.PutInContexts(s, args.NAME, params, args.ClusterContext()) + res, err := k8s.Releases.Put(s, args.NAME, params) if err != nil { return err } @@ -171,7 +174,7 @@ func initRelease() { NAME string `help:"Release instance name"` } R(&deleteOpt{}, cmdN("delete"), "Delete release", func(s *mcclient.ClientSession, args *deleteOpt) error { - _, err := k8s.Releases.DeleteInContexts(s, args.NAME, nil, args.ClusterContext()) + _, err := k8s.Releases.Delete(s, args.NAME, args.ClusterParams()) return err }) } diff --git a/cmd/climc/shell/k8s/service.go b/cmd/climc/shell/k8s/service.go index 3dc22e94c4..8803d17607 100644 --- a/cmd/climc/shell/k8s/service.go +++ b/cmd/climc/shell/k8s/service.go @@ -17,7 +17,8 @@ func initService() { R(&listOpt{}, cmdN("list"), "List k8s service", func(s *mcclient.ClientSession, args *listOpt) error { params := fetchNamespaceParams(args.namespaceListOptions) params.Update(fetchPagingParams(args.baseListOptions)) - ret, err := k8s.Services.ListInContexts(s, params, args.ClusterContext()) + params.Update(args.ClusterParams()) + ret, err := k8s.Services.List(s, params) if err != nil { return err } diff --git a/cmd/climc/shell/k8s/tiller.go b/cmd/climc/shell/k8s/tiller.go index 247e5fba13..610dcb0e5e 100644 --- a/cmd/climc/shell/k8s/tiller.go +++ b/cmd/climc/shell/k8s/tiller.go @@ -28,7 +28,7 @@ func initTiller() { MaxHistory int `json:"history_max"` } R(&createOpt{}, cmdN("create"), "Install helm tiller server to Kubernetes cluster", func(s *mcclient.ClientSession, args *createOpt) error { - params := json.NewDict() + params := args.ClusterParams() if len(args.KubeContext) > 0 { params.Add(json.NewString(args.KubeContext), "kube_context") } @@ -46,7 +46,7 @@ func initTiller() { if args.MaxHistory > 0 { params.Add(json.NewInt(int64(args.MaxHistory)), "history_max") } - ret, err := k8s.Tiller.CreateInContexts(s, params, args.ClusterContext()) + ret, err := k8s.Tiller.Create(s, params) if err != nil { return err } diff --git a/pkg/mcclient/modules/k8s/raw.go b/pkg/mcclient/modules/k8s/raw.go index 8853a18742..1f91f1092a 100644 --- a/pkg/mcclient/modules/k8s/raw.go +++ b/pkg/mcclient/modules/k8s/raw.go @@ -2,13 +2,11 @@ package k8s import ( "fmt" - "net/url" "strings" "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/mcclient/modules" ) var RawResource *RawResourceManager @@ -19,33 +17,23 @@ func init() { } } -type rawResourceContext struct { +type rawResource struct { kind string name string query jsonutils.JSONObject - ctxs []modules.ManagerContext } -func newRawResourceContext(kind, namespace, name string, query jsonutils.JSONObject, ctxs []modules.ManagerContext) *rawResourceContext { +func newRawResource(kind, namespace, name string, query jsonutils.JSONObject) *rawResource { nsQuery := getNamespaceQuery(namespace) if query != nil { nsQuery.Update(query) } - ctx := &rawResourceContext{kind: kind, name: name, query: nsQuery, ctxs: ctxs} + ctx := &rawResource{kind: kind, name: name, query: nsQuery} return ctx } -func (ctx rawResourceContext) contextPath() string { +func (ctx rawResource) path() string { segs := make([]string, 0) - ctxs := ctx.ctxs - if ctxs != nil && len(ctxs) > 0 { - for _, c := range ctxs { - segs = append(segs, c.InstanceManager.KeyString()) - if len(c.InstanceId) > 0 { - segs = append(segs, url.PathEscape(c.InstanceId)) - } - } - } segs = append(segs, "_raw", ctx.kind, ctx.name) path := fmt.Sprintf("/%s", strings.Join(segs, "/")) if ctx.query != nil { @@ -74,22 +62,22 @@ func getNamespaceQuery(namespace string) *jsonutils.JSONDict { return query } -func (m *RawResourceManager) Get(s *mcclient.ClientSession, kind string, namespace string, name string, query jsonutils.JSONObject, ctxs []modules.ManagerContext) (jsonutils.JSONObject, error) { - ctx := newRawResourceContext(kind, namespace, name, query, ctxs) - return m.request(s, "GET", ctx.contextPath(), nil) +func (m *RawResourceManager) Get(s *mcclient.ClientSession, kind string, namespace string, name string, query jsonutils.JSONObject) (jsonutils.JSONObject, error) { + ctx := newRawResource(kind, namespace, name, query) + return m.request(s, "GET", ctx.path(), nil) } -func (m *RawResourceManager) Put(s *mcclient.ClientSession, kind string, namespace string, name string, body jsonutils.JSONObject, ctxs []modules.ManagerContext) error { +func (m *RawResourceManager) Put(s *mcclient.ClientSession, kind string, namespace string, name string, body jsonutils.JSONObject) error { rawBytes := body.String() newBody := jsonutils.NewDict() newBody.Add(jsonutils.NewString(rawBytes), "raw") - ctx := newRawResourceContext(kind, namespace, name, nil, ctxs) - _, err := m.request(s, "PUT", ctx.contextPath(), newBody) + ctx := newRawResource(kind, namespace, name, nil) + _, err := m.request(s, "PUT", ctx.path(), newBody) return err } -func (m *RawResourceManager) Delete(s *mcclient.ClientSession, kind string, namespace string, name string, query jsonutils.JSONObject, ctxs []modules.ManagerContext) error { - ctx := newRawResourceContext(kind, namespace, name, query, ctxs) - _, err := m.request(s, "DELETE", ctx.contextPath(), nil) +func (m *RawResourceManager) Delete(s *mcclient.ClientSession, kind string, namespace string, name string, query jsonutils.JSONObject) error { + ctx := newRawResource(kind, namespace, name, query) + _, err := m.request(s, "DELETE", ctx.path(), nil) return err }