diff --git a/pkg/cloudcommon/db/db_dispatcher.go b/pkg/cloudcommon/db/db_dispatcher.go index 5fcbd2dbcd..32b133341f 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 { @@ -768,6 +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, true) dispatcher.modelManager.OnCreateComplete(ctx, []IModel{model}, userCred, query, data) return getItemDetails(dispatcher.modelManager, model, ctx, userCred, query) } @@ -986,11 +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, false) return nil, httperrors.NewGeneralError(err) } dataDict, ok := data.(*jsonutils.JSONDict) if !ok { + logclient.AddActionLog(item, logclient.ACT_UPDATE, "Invalid data JSONObject", userCred, false) return nil, httperrors.NewInternalServerError("Invalid data JSONObject") } @@ -998,13 +1002,16 @@ 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, false) 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(item, logclient.ACT_UPDATE, errMsg, userCred, false) return nil, httperrors.NewGeneralError(err) } item.PreUpdate(ctx, userCred, query, dataDict) @@ -1012,7 +1019,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(item, logclient.ACT_UPDATE, errMsg, userCred, false) + log.Errorf(errMsg) return httperrors.NewGeneralError(err) } return nil @@ -1026,7 +1035,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(item, logclient.ACT_UPDATE, diffStr, userCred, true) } + } else { + logclient.AddActionLog(item, logclient.ACT_UPDATE, "", userCred, true) } return getItemDetails(manager, item, ctx, userCred, query) } @@ -1054,10 +1066,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(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, item.GetShortDesc(), userCred, true) return nil } diff --git a/pkg/cloudcommon/db/opslog.go b/pkg/cloudcommon/db/opslog.go index c531f74f40..f201f4e9c4 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" ) @@ -305,6 +306,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, 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 cc7ea853a3..2fe6b2256b 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(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 38b0123006..a9f84fce48 100644 --- a/pkg/compute/guestdrivers/aliyun.go +++ b/pkg/compute/guestdrivers/aliyun.go @@ -121,7 +121,6 @@ func (self *SAliyunGuestDriver) GetJsonDescAtHost(ctx context.Context, guest *mo config.DataDisks[i-1] = disk.DiskSize / 1024 // MB => GB } } - return jsonutils.Marshal(&config) } @@ -259,10 +258,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/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/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) } } diff --git a/pkg/compute/tasks/guest_create_task.go b/pkg/compute/tasks/guest_create_task.go index a57f49afca..0906f65072 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(guest, logclient.ACT_ALLOCATE, data, self.UserCred, false) 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(guest, logclient.ACT_ALLOCATE, data, self.UserCred, false) 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(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 bd9ce9eec1..8d9a2ce11a 100644 --- a/pkg/compute/tasks/guest_delete_task.go +++ b/pkg/compute/tasks/guest_delete_task.go @@ -5,13 +5,14 @@ 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" "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" ) type GuestDeleteTask struct { @@ -93,6 +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, false) } func (self *GuestDeleteTask) OnGuestDeleteComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { @@ -108,6 +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, 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 037a909a1c..b2156a763a 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 { @@ -61,6 +62,7 @@ func (self *GuestDeployTask) StartDeployGuestOnHost(ctx context.Context, guest * 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) { @@ -68,6 +70,30 @@ 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") + 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 + } + + } else if reset_password { + logclient.AddActionLog(guest, logclient.ACT_VM_RESET_PSWD, "", self.UserCred, true) + _log = true + } + } + 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/compute/tasks/guest_rebuild_root_task.go b/pkg/compute/tasks/guest_rebuild_root_task.go index 50de80c0e9..a2a7e5c6fd 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(guest, logclient.ACT_VM_REBUILD, err, self.UserCred, false) 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(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, 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, false) return } if guest.OsType != osprof.OSType { @@ -83,20 +88,20 @@ 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, false) 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()) } 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, "") - // TODO: logclient + logclient.AddActionLog(guest, logclient.ACT_VM_REBUILD, data, self.UserCred, false) } 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(guest, logclient.ACT_VM_REBUILD, "", self.UserCred, true) } func (self *GuestRebuildRootTask) OnGuestStartComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { @@ -137,8 +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, false) } func (self *KVMGuestRebuildRootTask) OnGuestDeployComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { self.SetStageComplete(ctx, nil) -} \ No newline at end of file + 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 4e2cad8135..99dae67cf3 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(guest, logclient.ACT_VM_START, "", self.UserCred, true) // self.taskComplete(ctx, guest) } @@ -76,6 +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, 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 e8c3e8c1e6..1368f24082 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(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, false) } diff --git a/pkg/compute/tasks/guest_syncstatus_task.go b/pkg/compute/tasks/guest_syncstatus_task.go index 478f4afe6d..18849cc4e0 100644 --- a/pkg/compute/tasks/guest_syncstatus_task.go +++ b/pkg/compute/tasks/guest_syncstatus_task.go @@ -9,6 +9,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 +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, 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, false) } 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..3e070285b3 --- /dev/null +++ b/pkg/util/logclient/logclient.go @@ -0,0 +1,97 @@ +package logclient + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "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 ( + 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_CLOUD_FULLSYNC = "全量同步" + ACT_CLOUD_SYNC = "同步" + ACT_CREATE = "创建" + ACT_DELETE = "删除" + ACT_DISABLE = "禁用" + ACT_ENABLE = "启用" + ACT_GUEST_ATTACH_ISOLATED_DEVICE = "挂载透传设备" + ACT_GUEST_DETACH_ISOLATED_DEVICE = "卸载透传设备" + ACT_MERGE = "合并" + 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_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_START = "开机" + ACT_VM_STOP = "关机" + ACT_VM_SYNC_CONF = "同步配置" + ACT_VM_SYNC_STATUS = "同步状态" + ACT_VM_UNBIND_KEYPAIR = "解绑密钥" +) + +type IObject interface { + GetId() string + GetName() string + Keyword() string +} + +func AddActionLog(model IObject, action string, iNotes interface{}, userCred mcclient.TokenCredential, success bool) { + + token := userCred + notes := stringutils.Interface2String(iNotes) + + s := auth.GetSession(userCred, "", "") + + logentry := jsonutils.NewDict() + 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") + + if !success { + // 失败日志 + logentry.Add(jsonutils.JSONFalse, "success") + } else { + // 成功日志 + logentry.Add(jsonutils.JSONTrue, "success") + } + // 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 { + fmt.Printf("create action log failed %s", err) + } else { + fmt.Println("create action log success") + } +}