mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-06-20 11:22:19 +08:00
393 lines
14 KiB
Go
393 lines
14 KiB
Go
package db
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/util/stringutils"
|
|
"yunion.io/x/sqlchemy"
|
|
|
|
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
|
|
"yunion.io/x/onecloud/pkg/httperrors"
|
|
"yunion.io/x/onecloud/pkg/mcclient"
|
|
)
|
|
|
|
const (
|
|
ACT_CREATE = "create"
|
|
ACT_DELETE = "delete"
|
|
ACT_UPDATE = "update"
|
|
ACT_FETCH = "fetch"
|
|
ACT_ENABLE = "enable"
|
|
ACT_DISABLE = "disable"
|
|
ACT_OFFLINE = "offline"
|
|
ACT_ONLINE = "online"
|
|
ACT_ATTACH = "attach"
|
|
ACT_DETACH = "detach"
|
|
|
|
ACT_START_CREATE_BACKUP = "start_create_backup"
|
|
ACT_CREATE_BACKUP = "create_backup"
|
|
ACT_CREATE_BACKUP_FAILED = "create_backup_failed"
|
|
|
|
ACT_UPDATE_STATUS = "updatestatus"
|
|
ACT_STARTING = "starting"
|
|
ACT_START = "start"
|
|
ACT_START_FAIL = "start_fail"
|
|
ACT_BACKUP_START = "backup_start"
|
|
ACT_BACKUP_START_FAILED = "backup_start_fail"
|
|
|
|
ACT_STOPPING = "stopping"
|
|
ACT_STOP = "stop"
|
|
ACT_STOP_FAIL = "stop_fail"
|
|
|
|
ACT_RESIZING = "resizing"
|
|
ACT_RESIZE = "resize"
|
|
ACT_RESIZE_FAIL = "resize_fail"
|
|
|
|
ACT_MIGRATING = "migrating"
|
|
ACT_MIGRATE = "migrate"
|
|
ACT_MIGRATE_FAIL = "migrate_fail"
|
|
|
|
ACT_SPLIT = "net_split"
|
|
ACT_MERGE = "net_merge"
|
|
|
|
ACT_SAVING = "saving"
|
|
ACT_SAVE = "save"
|
|
ACT_SAVE_FAIL = "save_fail"
|
|
|
|
ACT_SWITCHED = "switched"
|
|
ACT_SWITCH_FAILED = "switch_failed"
|
|
|
|
ACT_SNAPSHOTING = "snapshoting"
|
|
ACT_SNAPSHOT_STREAM = "snapshot_stream"
|
|
ACT_SNAPSHOT_DONE = "snapshot"
|
|
ACT_SNAPSHOT_READY = "snapshot_ready"
|
|
ACT_SNAPSHOT_SYNC = "snapshot_sync"
|
|
ACT_SNAPSHOT_FAIL = "snapshot_fail"
|
|
ACT_SNAPSHOT_DELETING = "snapshot_deling"
|
|
ACT_SNAPSHOT_DELETE = "snapshot_del"
|
|
ACT_SNAPSHOT_DELETE_FAIL = "snapshot_del_fail"
|
|
ACT_SNAPSHOT_UNLINK = "snapshot_unlink"
|
|
|
|
ACT_DISK_CLEAN_UP_SNAPSHOTS = "disk_clean_up_snapshots"
|
|
ACT_DISK_CLEAN_UP_SNAPSHOTS_FAIL = "disk_clean_up_snapshots_fail"
|
|
|
|
ACT_ALLOCATING = "allocating"
|
|
ACT_BACKUP_ALLOCATING = "backup_allocating"
|
|
ACT_ALLOCATE = "allocate"
|
|
ACT_BACKUP_ALLOCATE = "backup_allocate"
|
|
ACT_ALLOCATE_FAIL = "alloc_fail"
|
|
ACT_BACKUP_ALLOCATE_FAIL = "backup_alloc_fail"
|
|
|
|
ACT_DELOCATING = "delocating"
|
|
ACT_DELOCATE = "delocate"
|
|
ACT_DELOCATE_FAIL = "delocate_fail"
|
|
|
|
ACT_ISO_PREPARING = "iso_preparing"
|
|
ACT_ISO_PREPARE_FAIL = "iso_prepare_fail"
|
|
ACT_ISO_ATTACH = "iso_attach"
|
|
ACT_ISO_DETACH = "iso_detach"
|
|
|
|
ACT_EIP_ATTACH = "eip_attach"
|
|
ACT_EIP_DETACH = "eip_detach"
|
|
|
|
ACT_SET_METADATA = "set_meta"
|
|
ACT_DEL_METADATA = "del_meta"
|
|
|
|
ACT_REBUILDING_ROOT = "rebuilding_root"
|
|
ACT_REBUILD_ROOT = "rebuild_root"
|
|
ACT_REBUILD_ROOT_FAIL = "rebuild_root_fail"
|
|
|
|
ACT_CHANGING_FLAVOR = "changing_flavor"
|
|
ACT_CHANGE_FLAVOR = "change_flavor"
|
|
ACT_CHANGE_FLAVOR_FAIL = "change_flavor_fail"
|
|
|
|
ACT_SYNCING_CONF = "syncing_conf"
|
|
ACT_SYNC_CONF = "sync_conf"
|
|
ACT_SYNC_CONF_FAIL = "sync_conf_fail"
|
|
ACT_SYNC_STATUS = "sync_status"
|
|
|
|
ACT_CHANGE_OWNER = "change_owner"
|
|
|
|
ACT_RESERVE_IP = "reserve_ip"
|
|
ACT_RELEASE_IP = "release_ip"
|
|
|
|
ACT_CONVERT_START = "converting"
|
|
ACT_CONVERT_COMPLETE = "converted"
|
|
ACT_CONVERT_FAIL = "convert_fail"
|
|
ACT_UNCONVERT_START = "unconverting"
|
|
ACT_UNCONVERT_COMPLETE = "unconverted"
|
|
ACT_UNCONVERT_FAIL = "unconvert_fail"
|
|
|
|
ACT_SYNC_HOST_START = "sync_host_start"
|
|
ACT_SYNCING_HOST = "syncing_host"
|
|
ACT_SYNC_HOST_COMPLETE = "sync_host_end"
|
|
|
|
ACT_SYNC_LB_START = "sync_lb_start"
|
|
ACT_SYNCING_LB = "syncing_lb"
|
|
ACT_SYNC_LB_COMPLETE = "sync_lb_end"
|
|
|
|
ACT_CACHING_IMAGE = "caching_image"
|
|
ACT_CACHE_IMAGE_FAIL = "cache_image_fail"
|
|
ACT_CACHED_IMAGE = "cached_image"
|
|
ACT_UNCACHING_IMAGE = "uncaching_image"
|
|
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_SYNC_CLOUD_EIP = "sync_cloud_eip"
|
|
|
|
ACT_PENDING_DELETE = "pending_delete"
|
|
ACT_CANCEL_DELETE = "cancel_delete"
|
|
|
|
// # isolated device (host)
|
|
ACT_HOST_ATTACH_ISOLATED_DEVICE = "host_attach_isolated_deivce"
|
|
ACT_HOST_ATTACH_ISOLATED_DEVICE_FAIL = "host_attach_isolated_deivce_fail"
|
|
ACT_HOST_DETACH_ISOLATED_DEVICE = "host_detach_isolated_deivce"
|
|
ACT_HOST_DETACH_ISOLATED_DEVICE_FAIL = "host_detach_isolated_deivce_fail"
|
|
|
|
// # isolated device (guest)
|
|
ACT_GUEST_ATTACH_ISOLATED_DEVICE = "guest_attach_isolated_deivce"
|
|
ACT_GUEST_ATTACH_ISOLATED_DEVICE_FAIL = "guest_attach_isolated_deivce_fail"
|
|
ACT_GUEST_DETACH_ISOLATED_DEVICE = "guest_detach_isolated_deivce"
|
|
ACT_GUEST_DETACH_ISOLATED_DEVICE_FAIL = "guest_detach_isolated_deivce_fail"
|
|
|
|
ACT_CHANGE_BANDWIDTH = "eip_change_bandwidth"
|
|
|
|
ACT_RENEW = "renew"
|
|
|
|
ACT_SCHEDULE = "schedule"
|
|
|
|
ACT_RECYCLE_PREPAID = "recycle_prepaid"
|
|
ACT_UNDO_RECYCLE_PREPAID = "undo_recycle_prepaid"
|
|
)
|
|
|
|
type SOpsLogManager struct {
|
|
SModelBaseManager
|
|
}
|
|
|
|
type SOpsLog struct {
|
|
SModelBase
|
|
|
|
Id int64 `primary:"true" auto_increment:"true" list:"user"` // = Column(BigInteger, primary_key=True)
|
|
ObjType string `width:"40" charset:"ascii" nullable:"false" list:"user" create:"required"` // = Column(VARCHAR(40, charset='ascii'), nullable=False)
|
|
ObjId string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"required"` // = Column(VARCHAR(ID_LENGTH, charset='ascii'), nullable=False)
|
|
ObjName string `width:"128" charset:"utf8" nullable:"false" list:"user" create:"required"` //= Column(VARCHAR(128, charset='utf8'), nullable=False)
|
|
Action string `width:"32" charset:"utf8" nullable:"false" list:"user" create:"required"` //= Column(VARCHAR(32, charset='ascii'), nullable=False)
|
|
Notes string `width:"2048" charset:"utf8" list:"user" create:"required"` // = Column(VARCHAR(2048, charset='utf8'))
|
|
ProjectId string `name:"tenant_id" width:"128" charset:"ascii" list:"user" create:"required"` // = Column(VARCHAR(ID_LENGTH, charset='ascii'))
|
|
Project string `name:"tenant" width:"128" charset:"utf8" list:"user" create:"required"` // tenant = Column(VARCHAR(128, charset='utf8'))
|
|
UserId string `width:"128" charset:"ascii" list:"user" create:"required"` // = Column(VARCHAR(ID_LENGTH, charset='ascii'))
|
|
User string `width:"128" charset:"utf8" list:"user" create:"required"` // = Column(VARCHAR(128, charset='utf8'))
|
|
DomainId string `width:"128" charset:"ascii" list:"user" create:"optional"`
|
|
Domain string `width:"128" charset:"utf8" list:"user" create:"optional"`
|
|
Roles string `width:"64" charset:"ascii" list:"user" create:"optional"` // = Column(VARCHAR(64, charset='ascii'))
|
|
|
|
// BillingType string `width:"64" charset:"ascii" default:"postpaid" list:"user" create:"user"` // billing_type = Column(VARCHAR(64, charset='ascii'), nullable=True)
|
|
OpsTime time.Time `nullable:"false" list:"user"` // = Column(DateTime, nullable=False)
|
|
OwnerProjectId string `name:"owner_tenant_id" width:"128" charset:"ascii" list:"user" create:"optional"` // = Column(VARCHAR(ID_LENGTH, charset='ascii'))
|
|
// owner_user_id = Column(VARCHAR(ID_LENGTH, charset='ascii'))
|
|
}
|
|
|
|
var OpsLog *SOpsLogManager
|
|
|
|
var _ IModelManager = (*SOpsLogManager)(nil)
|
|
var _ IModel = (*SOpsLog)(nil)
|
|
|
|
func init() {
|
|
OpsLog = &SOpsLogManager{NewModelBaseManager(SOpsLog{}, "opslog_tbl", "event", "events")}
|
|
}
|
|
|
|
func (opslog *SOpsLog) GetId() string {
|
|
return fmt.Sprintf("%d", opslog.Id)
|
|
}
|
|
|
|
func (opslog *SOpsLog) GetName() string {
|
|
return fmt.Sprintf("%s-%s", opslog.ObjType, opslog.Action)
|
|
}
|
|
|
|
func (opslog *SOpsLog) GetModelManager() IModelManager {
|
|
return OpsLog
|
|
}
|
|
|
|
/* @classmethod
|
|
def list_fields(cls, user_cred):
|
|
return ['id', 'obj_type', 'obj_id', 'obj_name', 'action', 'notes',
|
|
'tenant_id', 'tenant', 'user_id', 'user', 'roles',
|
|
'billing_type', 'ops_time', 'owner_tenant_id',
|
|
'owner_user_id', ]
|
|
*/
|
|
|
|
func (manager *SOpsLogManager) LogEvent(model IModel, action string, notes interface{}, userCred mcclient.TokenCredential) {
|
|
if !consts.OpsLogEnabled() {
|
|
return
|
|
}
|
|
if len(model.GetId()) == 0 || len(model.GetName()) == 0 {
|
|
return
|
|
}
|
|
opslog := SOpsLog{}
|
|
opslog.ObjType = model.Keyword()
|
|
opslog.ObjId = model.GetId()
|
|
opslog.ObjName = model.GetName()
|
|
opslog.Action = action
|
|
opslog.Notes = stringutils.Interface2String(notes)
|
|
opslog.ProjectId = userCred.GetProjectId()
|
|
opslog.Project = userCred.GetProjectName()
|
|
opslog.UserId = userCred.GetUserId()
|
|
opslog.User = userCred.GetUserName()
|
|
opslog.DomainId = userCred.GetDomainId()
|
|
opslog.Domain = userCred.GetDomainName()
|
|
opslog.Roles = strings.Join(userCred.GetRoles(), ",")
|
|
opslog.OpsTime = time.Now().UTC()
|
|
|
|
if virtualModel, ok := model.(IVirtualModel); ok && virtualModel != nil {
|
|
opslog.OwnerProjectId = virtualModel.GetOwnerProjectId()
|
|
}
|
|
|
|
err := manager.TableSpec().Insert(&opslog)
|
|
if err != nil {
|
|
log.Errorf("fail to insert opslog: %s", err)
|
|
}
|
|
}
|
|
|
|
func combineNotes(ctx context.Context, m2 IModel, notes jsonutils.JSONObject) *jsonutils.JSONDict {
|
|
desc := m2.GetShortDesc(ctx)
|
|
if notes != nil {
|
|
if notesDict, ok := notes.(*jsonutils.JSONDict); ok {
|
|
notesMap, _ := notesDict.GetMap()
|
|
if notesMap != nil {
|
|
for k, v := range notesMap {
|
|
desc.Add(v, k)
|
|
}
|
|
}
|
|
} else if notesArray, ok := notes.(*jsonutils.JSONArray); ok {
|
|
noteList, _ := notesArray.GetArray()
|
|
if noteList != nil {
|
|
for i, v := range noteList {
|
|
desc.Add(v, fmt.Sprintf("notes.%d", i))
|
|
}
|
|
}
|
|
} else {
|
|
desc.Add(jsonutils.NewString(notes.String()), "notes")
|
|
}
|
|
}
|
|
return desc
|
|
}
|
|
|
|
func (manager *SOpsLogManager) logOneJointEvent(ctx context.Context, m1, m2 IModel, event string, userCred mcclient.TokenCredential, notes jsonutils.JSONObject) {
|
|
nn := notes
|
|
if m2 != nil {
|
|
nn = combineNotes(ctx, m2, notes)
|
|
}
|
|
manager.LogEvent(m1, event, nn, userCred)
|
|
}
|
|
|
|
func (manager *SOpsLogManager) logJoinEvent(ctx context.Context, m1, m2 IModel, event string, userCred mcclient.TokenCredential, notes jsonutils.JSONObject) {
|
|
if m1 != nil {
|
|
manager.logOneJointEvent(ctx, m1, m2, event, userCred, notes)
|
|
}
|
|
if m2 != nil {
|
|
manager.logOneJointEvent(ctx, m2, m1, event, userCred, notes)
|
|
}
|
|
}
|
|
|
|
func (manager *SOpsLogManager) LogAttachEvent(ctx context.Context, m1, m2 IModel, userCred mcclient.TokenCredential, notes jsonutils.JSONObject) {
|
|
manager.logJoinEvent(ctx, m1, m2, ACT_ATTACH, userCred, notes)
|
|
}
|
|
|
|
func (manager *SOpsLogManager) LogDetachEvent(ctx context.Context, m1, m2 IModel, userCred mcclient.TokenCredential, notes jsonutils.JSONObject) {
|
|
manager.logJoinEvent(ctx, m1, m2, ACT_DETACH, userCred, notes)
|
|
}
|
|
|
|
func (manager *SOpsLogManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) {
|
|
queryDict, ok := query.(*jsonutils.JSONDict)
|
|
if !ok {
|
|
return nil, fmt.Errorf("invalid query string")
|
|
}
|
|
objTypes := jsonutils.GetQueryStringArray(queryDict, "obj_type")
|
|
if objTypes != nil && len(objTypes) > 0 {
|
|
queryDict.RemoveIgnoreCase("obj_type")
|
|
q = q.Filter(sqlchemy.In(q.Field("obj_type"), objTypes))
|
|
}
|
|
objIds := jsonutils.GetQueryStringArray(queryDict, "obj_id")
|
|
if objIds != nil && len(objIds) > 0 {
|
|
queryDict.RemoveIgnoreCase("obj_id")
|
|
q = q.Filter(sqlchemy.OR(sqlchemy.In(q.Field("obj_id"), objIds), sqlchemy.In(q.Field("obj_name"), objIds)))
|
|
}
|
|
action := jsonutils.GetQueryStringArray(queryDict, "action")
|
|
if action != nil && len(action) > 0 {
|
|
queryDict.RemoveIgnoreCase("action")
|
|
q = q.Filter(sqlchemy.In(q.Field("action"), action))
|
|
}
|
|
if !IsAdminAllowList(userCred, manager) {
|
|
q = q.Filter(sqlchemy.OR(sqlchemy.AND(sqlchemy.IsNotNull(q.Field("owner_tenant_id")), sqlchemy.Equals(q.Field("owner_tenant_id"), userCred.GetProjectId())), sqlchemy.Equals(q.Field("tenant_id"), userCred.GetProjectId())))
|
|
}
|
|
since, _ := query.GetTime("since")
|
|
if !since.IsZero() {
|
|
q = q.GT("ops_time", since)
|
|
}
|
|
until, _ := query.GetTime("until")
|
|
if !until.IsZero() {
|
|
q = q.LE("ops_time", until)
|
|
}
|
|
return q, nil
|
|
}
|
|
|
|
func (manager *SOpsLogManager) SyncOwner(m IModel, former *STenant, userCred mcclient.TokenCredential) {
|
|
notes := jsonutils.NewDict()
|
|
notes.Add(jsonutils.NewString(former.GetId()), "former_project_id")
|
|
notes.Add(jsonutils.NewString(former.GetName()), "former_project")
|
|
manager.LogEvent(m, ACT_CHANGE_OWNER, notes, userCred)
|
|
}
|
|
|
|
func (manager *SOpsLogManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
|
|
return true
|
|
}
|
|
|
|
func (manager *SOpsLogManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
|
return false
|
|
}
|
|
|
|
func (self *SOpsLog) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
|
|
return IsAdminAllowGet(userCred, self) || userCred.GetProjectId() == self.ProjectId || userCred.GetProjectId() == self.OwnerProjectId
|
|
}
|
|
|
|
func (self *SOpsLog) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool {
|
|
return false
|
|
}
|
|
|
|
func (self *SOpsLog) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
|
return false
|
|
}
|
|
|
|
func (self *SOpsLog) ValidateDeleteCondition(ctx context.Context) error {
|
|
return httperrors.NewForbiddenError("not allow to delete log")
|
|
}
|
|
|
|
func (self *SOpsLogManager) FilterById(q *sqlchemy.SQuery, idStr string) *sqlchemy.SQuery {
|
|
id, _ := strconv.Atoi(idStr)
|
|
return q.Equals("id", id)
|
|
}
|
|
|
|
func (self *SOpsLogManager) FilterByNotId(q *sqlchemy.SQuery, idStr string) *sqlchemy.SQuery {
|
|
id, _ := strconv.Atoi(idStr)
|
|
return q.NotEquals("id", id)
|
|
}
|
|
|
|
func (self *SOpsLogManager) FilterByName(q *sqlchemy.SQuery, name string) *sqlchemy.SQuery {
|
|
return q
|
|
}
|
|
|
|
func (self *SOpsLogManager) FilterByOwner(q *sqlchemy.SQuery, owner string) *sqlchemy.SQuery {
|
|
if len(owner) > 0 {
|
|
return q.Equals("owner_project_id", owner)
|
|
} else {
|
|
return q
|
|
}
|
|
}
|