virtualresource.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package db
  15. import (
  16. "context"
  17. "database/sql"
  18. "yunion.io/x/jsonutils"
  19. "yunion.io/x/log"
  20. "yunion.io/x/pkg/errors"
  21. "yunion.io/x/pkg/util/rbacscope"
  22. "yunion.io/x/pkg/utils"
  23. "yunion.io/x/sqlchemy"
  24. "yunion.io/x/onecloud/pkg/apis"
  25. "yunion.io/x/onecloud/pkg/cloudcommon/consts"
  26. "yunion.io/x/onecloud/pkg/cloudcommon/policy"
  27. "yunion.io/x/onecloud/pkg/httperrors"
  28. "yunion.io/x/onecloud/pkg/mcclient"
  29. "yunion.io/x/onecloud/pkg/util/logclient"
  30. "yunion.io/x/onecloud/pkg/util/stringutils2"
  31. )
  32. type SVirtualResourceBaseManager struct {
  33. SStatusStandaloneResourceBaseManager
  34. SProjectizedResourceBaseManager
  35. SPendingDeletedBaseManager
  36. }
  37. func NewVirtualResourceBaseManager(dt interface{}, tableName string, keyword string, keywordPlural string) SVirtualResourceBaseManager {
  38. return SVirtualResourceBaseManager{
  39. SStatusStandaloneResourceBaseManager: NewStatusStandaloneResourceBaseManager(dt,
  40. tableName, keyword, keywordPlural),
  41. }
  42. }
  43. type SVirtualResourceBase struct {
  44. SStatusStandaloneResourceBase
  45. SProjectizedResourceBase
  46. SPendingDeletedBase
  47. // 云上同步资源是否在本地被更改过配置, local: 更改过, cloud: 未更改过
  48. // example: local
  49. ProjectSrc string `width:"10" charset:"ascii" nullable:"false" list:"user" default:"" json:"project_src"`
  50. // 是否是系统资源
  51. IsSystem bool `nullable:"true" default:"false" list:"admin" create:"optional" json:"is_system"`
  52. // 资源是否被冻结
  53. Freezed bool `nullable:"false" default:"false" get:"user" list:"user" json:"freezed"`
  54. }
  55. func (model *SVirtualResourceBase) IsOwner(userCred mcclient.TokenCredential) bool {
  56. return userCred.GetProjectId() == model.ProjectId
  57. }
  58. func (manager *SVirtualResourceBaseManager) GetIVirtualModelManager() IVirtualModelManager {
  59. return manager.GetVirtualObject().(IVirtualModelManager)
  60. }
  61. // +onecloud:swagger-gen-ignore
  62. func (manager *SVirtualResourceBaseManager) GetPropertyStatistics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*apis.StatusStatistic, error) {
  63. im, ok := manager.GetVirtualObject().(IModelManager)
  64. if !ok {
  65. im = manager
  66. }
  67. var err error
  68. q := manager.Query()
  69. q, err = ListItemQueryFilters(im, ctx, q, userCred, query, policy.PolicyActionList)
  70. if err != nil {
  71. return nil, err
  72. }
  73. sq := q.SubQuery()
  74. statQ := sq.Query(sq.Field("status"), sqlchemy.COUNT("total_count", sq.Field("id")), sqlchemy.SUM("pending_deleted_count", sq.Field("pending_deleted")))
  75. statQ = statQ.GroupBy(sq.Field("status"))
  76. ret := []struct {
  77. Status string
  78. TotalCount int64
  79. PendingDeletedCount int64
  80. }{}
  81. err = statQ.All(&ret)
  82. if err != nil {
  83. return nil, errors.Wrapf(err, "q.All")
  84. }
  85. type sStatistic struct {
  86. TotalCount int64
  87. PendingDeletedCount int64
  88. }
  89. result := &apis.StatusStatistic{
  90. StatusInfo: []apis.StatusStatisticStatusInfo{},
  91. }
  92. for _, s := range ret {
  93. result.StatusInfo = append(result.StatusInfo, apis.StatusStatisticStatusInfo{
  94. Status: s.Status,
  95. TotalCount: s.TotalCount,
  96. PendingDeletedCount: s.PendingDeletedCount,
  97. })
  98. }
  99. return result, nil
  100. }
  101. func (manager *SVirtualResourceBaseManager) CustomizedTotalCount(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, totalQ *sqlchemy.SQuery) (int, jsonutils.JSONObject, error) {
  102. results := struct {
  103. apis.TotalCountBase
  104. StatusInfo []apis.StatusStatisticStatusInfo
  105. }{}
  106. err := totalQ.First(&results.TotalCountBase)
  107. if err != nil && errors.Cause(err) != sql.ErrNoRows {
  108. return -1, nil, errors.Wrapf(err, "First")
  109. }
  110. totalSQ := totalQ.ResetFields().SubQuery()
  111. statQ := totalSQ.Query(totalSQ.Field("status"), sqlchemy.COUNT("total_count", totalSQ.Field("id")), sqlchemy.SUM("pending_deleted_count", totalSQ.Field("pending_deleted")))
  112. statQ = statQ.GroupBy(totalSQ.Field("status"))
  113. err = statQ.All(&results.StatusInfo)
  114. if err != nil {
  115. return -1, nil, errors.Wrapf(err, "status query")
  116. }
  117. return results.Count, jsonutils.Marshal(results), nil
  118. }
  119. // +onecloud:swagger-gen-ignore
  120. func (manager *SVirtualResourceBaseManager) GetPropertyProjectStatistics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) ([]apis.ProjectStatistic, error) {
  121. im, ok := manager.GetVirtualObject().(IModelManager)
  122. if !ok {
  123. im = manager
  124. }
  125. tenants := TenantCacheManager.GetTenantQuery().Equals("domain_id", userCred.GetProjectDomainId()).SubQuery()
  126. _q, err := ListItemQueryFilters(im, ctx, im.Query(), userCred, query, policy.PolicyActionList)
  127. if err != nil {
  128. return nil, err
  129. }
  130. sq := _q.SubQuery()
  131. q := sq.Query(
  132. sq.Field("tenant_id"),
  133. sqlchemy.COUNT("count"),
  134. ).GroupBy(sq.Field("tenant_id"))
  135. q.Join(tenants, sqlchemy.Equals(q.Field("tenant_id"), tenants.Field("id")))
  136. q.AppendField(tenants.Field("id"))
  137. q.AppendField(tenants.Field("name"))
  138. result := []apis.ProjectStatistic{}
  139. return result, q.All(&result)
  140. }
  141. // +onecloud:swagger-gen-ignore
  142. func (manager *SVirtualResourceBaseManager) GetPropertyDomainStatistics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) ([]apis.ProjectStatistic, error) {
  143. im, ok := manager.GetVirtualObject().(IModelManager)
  144. if !ok {
  145. im = manager
  146. }
  147. domains := TenantCacheManager.GetDomainQuery().SubQuery()
  148. _q, err := ListItemQueryFilters(im, ctx, im.Query(), userCred, query, policy.PolicyActionList)
  149. if err != nil {
  150. return nil, err
  151. }
  152. sq := _q.SubQuery()
  153. q := sq.Query(
  154. sq.Field("domain_id"),
  155. sqlchemy.COUNT("count"),
  156. ).GroupBy(sq.Field("domain_id"))
  157. q.Join(domains, sqlchemy.Equals(q.Field("domain_id"), domains.Field("id")))
  158. q.AppendField(domains.Field("id"))
  159. q.AppendField(domains.Field("name"))
  160. result := []apis.ProjectStatistic{}
  161. return result, q.All(&result)
  162. }
  163. func (manager *SVirtualResourceBaseManager) FilterByHiddenSystemAttributes(q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject, scope rbacscope.TRbacScope) *sqlchemy.SQuery {
  164. q = manager.SStatusStandaloneResourceBaseManager.FilterByHiddenSystemAttributes(q, userCred, query, scope)
  165. isSystem := jsonutils.QueryBoolean(query, "system", false)
  166. if isSystem {
  167. var isAllow bool
  168. allowScope, result := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), manager.KeywordPlural(), policy.PolicyActionList, "system")
  169. if result.Result.IsAllow() && !scope.HigherThan(allowScope) {
  170. isAllow = true
  171. }
  172. if !isAllow {
  173. isSystem = false
  174. }
  175. }
  176. if !isSystem {
  177. q = q.Filter(sqlchemy.OR(sqlchemy.IsNull(q.Field("is_system")), sqlchemy.IsFalse(q.Field("is_system"))))
  178. }
  179. return q
  180. }
  181. func (model *SVirtualResourceBase) SetSystemInfo(isSystem bool) error {
  182. _, err := Update(model, func() error {
  183. model.IsSystem = isSystem
  184. return nil
  185. })
  186. return err
  187. }
  188. func (model *SVirtualResourceBase) SetProjectInfo(ctx context.Context, userCred mcclient.TokenCredential, projectId, domainId string) error {
  189. _, err := Update(model, func() error {
  190. model.ProjectId = projectId
  191. model.DomainId = domainId
  192. return nil
  193. })
  194. return err
  195. }
  196. func (manager *SVirtualResourceBaseManager) FilterBySystemAttributes(q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject, scope rbacscope.TRbacScope) *sqlchemy.SQuery {
  197. q = manager.SStatusStandaloneResourceBaseManager.FilterBySystemAttributes(q, userCred, query, scope)
  198. q = manager.SPendingDeletedBaseManager.FilterBySystemAttributes(manager.GetIStandaloneModelManager(), q, userCred, query, scope)
  199. return q
  200. }
  201. func (manager *SVirtualResourceBaseManager) FetchByName(ctx context.Context, userCred mcclient.IIdentityProvider, idStr string) (IModel, error) {
  202. return FetchByName(ctx, manager, userCred, idStr)
  203. }
  204. func (manager *SVirtualResourceBaseManager) FetchByIdOrName(ctx context.Context, userCred mcclient.IIdentityProvider, idStr string) (IModel, error) {
  205. return FetchByIdOrName(ctx, manager, userCred, idStr)
  206. }
  207. func (manager *SVirtualResourceBaseManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input apis.VirtualResourceCreateInput) (apis.VirtualResourceCreateInput, error) {
  208. var err error
  209. if input.IsSystem != nil && *input.IsSystem && IsAdminAllowCreate(userCred, manager).Result.IsDeny() {
  210. return input, httperrors.NewNotSufficientPrivilegeError("non-admin user not allowed to create system object")
  211. }
  212. input.StatusStandaloneResourceCreateInput, err = manager.SStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StatusStandaloneResourceCreateInput)
  213. if err != nil {
  214. return input, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ValidateCreateData")
  215. }
  216. return input, nil
  217. }
  218. func (model *SVirtualResourceBase) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  219. model.DomainId = ownerId.GetProjectDomainId()
  220. model.ProjectId = ownerId.GetProjectId()
  221. isSystem, err := data.Bool("is_system")
  222. if err == nil && isSystem {
  223. model.IsSystem = true
  224. } else {
  225. model.IsSystem = false
  226. }
  227. model.ProjectSrc = string(apis.OWNER_SOURCE_LOCAL)
  228. return model.SStatusStandaloneResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
  229. }
  230. func (model *SVirtualResourceBase) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  231. project, err := model.GetTenantCache(ctx)
  232. if err != nil {
  233. log.Errorf("unable to GetTenantCache: %s", err.Error())
  234. return
  235. }
  236. err = InheritFromTo(ctx, userCred, project, model)
  237. if err != nil {
  238. log.Errorf("unable to inherit class metadata from poject %s: %s", project.GetId(), err.Error())
  239. }
  240. model.SStatusStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
  241. }
  242. func (manager *SVirtualResourceBaseManager) FetchCustomizeColumns(
  243. ctx context.Context,
  244. userCred mcclient.TokenCredential,
  245. query jsonutils.JSONObject,
  246. objs []interface{},
  247. fields stringutils2.SSortedStrings,
  248. isList bool,
  249. ) []apis.VirtualResourceDetails {
  250. ret := make([]apis.VirtualResourceDetails, len(objs))
  251. stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  252. projRows := manager.SProjectizedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  253. for i := range objs {
  254. ret[i] = apis.VirtualResourceDetails{
  255. StatusStandaloneResourceDetails: stdRows[i],
  256. ProjectizedResourceInfo: projRows[i],
  257. }
  258. }
  259. return ret
  260. }
  261. func (model *SVirtualResourceBase) PreCheckPerformAction(
  262. ctx context.Context, userCred mcclient.TokenCredential,
  263. action string, query jsonutils.JSONObject, data jsonutils.JSONObject,
  264. ) error {
  265. if err := model.SStandaloneResourceBase.PreCheckPerformAction(ctx, userCred, action, query, data); err != nil {
  266. return err
  267. }
  268. if model.Freezed && action != "unfreeze" {
  269. return httperrors.NewBadRequestError("Virtual resource freezed, can't do %s", action)
  270. }
  271. return nil
  272. }
  273. func (model *SVirtualResourceBase) GetTenantCache(ctx context.Context) (*STenant, error) {
  274. // log.Debugf("Get tenant by Id %s", model.ProjectId)
  275. return TenantCacheManager.FetchTenantById(ctx, model.ProjectId)
  276. }
  277. // +onecloud:swagger-gen-ignore
  278. // freezed update and perform action operation except for unfreeze
  279. func (model *SVirtualResourceBase) PerformFreeze(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformFreezeInput) (jsonutils.JSONObject, error) {
  280. if model.Freezed {
  281. return nil, httperrors.NewBadRequestError("virtual resource already freezed")
  282. }
  283. _, err := Update(model, func() error {
  284. model.Freezed = true
  285. return nil
  286. })
  287. if err != nil {
  288. return nil, err
  289. }
  290. vm := model.GetIVirtualModel()
  291. OpsLog.LogEvent(model, ACT_FREEZE, vm.GetShortDesc(ctx), userCred)
  292. logclient.AddActionLogWithContext(ctx, model, logclient.ACT_FREEZE, "perform freeze", userCred, true)
  293. return nil, nil
  294. }
  295. // +onecloud:swagger-gen-ignore
  296. func (model *SVirtualResourceBase) PerformUnfreeze(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformUnfreezeInput) (jsonutils.JSONObject, error) {
  297. if !model.Freezed {
  298. return nil, httperrors.NewBadRequestError("virtual resource not freezed")
  299. }
  300. _, err := Update(model, func() error {
  301. model.Freezed = false
  302. return nil
  303. })
  304. if err != nil {
  305. return nil, err
  306. }
  307. vm := model.GetIVirtualModel()
  308. OpsLog.LogEvent(model, ACT_UNFREEZE, vm.GetShortDesc(ctx), userCred)
  309. logclient.AddActionLogWithContext(ctx, model, logclient.ACT_UNFREEZE, "perform unfreeze", userCred, true)
  310. return nil, nil
  311. }
  312. // 更改项目
  313. func (model *SVirtualResourceBase) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) (jsonutils.JSONObject, error) {
  314. if model.GetIStandaloneModel().IsShared() {
  315. return nil, errors.Wrap(httperrors.ErrForbidden, "cannot change owner of shared resource")
  316. }
  317. manager := model.GetModelManager()
  318. data := jsonutils.Marshal(input)
  319. log.Debugf("SVirtualResourceBase change_owner %s %s %#v", query, data, manager)
  320. ownerId, err := manager.FetchOwnerId(ctx, data)
  321. if err != nil {
  322. return nil, httperrors.NewGeneralError(err)
  323. }
  324. if len(ownerId.GetProjectId()) == 0 {
  325. return nil, httperrors.NewInputParameterError("missing new project/tenant")
  326. }
  327. if ownerId.GetProjectId() == model.ProjectId {
  328. // do nothing
  329. Update(model, func() error {
  330. model.ProjectSrc = string(apis.OWNER_SOURCE_LOCAL)
  331. return nil
  332. })
  333. return nil, nil
  334. }
  335. var requireScope rbacscope.TRbacScope
  336. if ownerId.GetProjectDomainId() != model.DomainId {
  337. // change domain, do check
  338. candidates := model.GetIVirtualModel().GetChangeOwnerCandidateDomainIds()
  339. if len(candidates) > 0 && !utils.IsInStringArray(ownerId.GetProjectDomainId(), candidates) {
  340. return nil, errors.Wrap(httperrors.ErrForbidden, "target domain not in change owner candidate list")
  341. }
  342. requireScope = rbacscope.ScopeSystem
  343. } else {
  344. requireScope = rbacscope.ScopeDomain
  345. }
  346. allowScope, policyTags := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), model.KeywordPlural(), policy.PolicyActionPerform, "change-owner")
  347. if requireScope.HigherThan(allowScope) {
  348. return nil, errors.Wrapf(httperrors.ErrNotSufficientPrivilege, "require %s allow %s", requireScope, allowScope)
  349. }
  350. err = objectConfirmPolicyTags(ctx, model, policyTags)
  351. if err != nil {
  352. return nil, errors.Wrap(err, "objectConfirmPolicyTags")
  353. }
  354. if !consts.GetChangeOwnerAutoRename() {
  355. q := manager.Query().Equals("name", model.GetName())
  356. q = manager.FilterByOwner(ctx, q, manager, userCred, ownerId, manager.NamespaceScope())
  357. q = manager.FilterBySystemAttributes(q, nil, nil, manager.ResourceScope())
  358. q = q.NotEquals("id", model.GetId())
  359. cnt, err := q.CountWithError()
  360. if err != nil {
  361. return nil, httperrors.NewInternalServerError("check name duplication error: %s", err)
  362. }
  363. if cnt > 0 {
  364. return nil, httperrors.NewDuplicateNameError("name", model.GetName())
  365. }
  366. }
  367. former, _ := TenantCacheManager.FetchTenantById(ctx, model.ProjectId)
  368. if former == nil {
  369. log.Warningf("tenant_id %s not found", model.ProjectId)
  370. formerObj := NewTenant(model.ProjectId, "unknown", model.DomainId, "unknown")
  371. former = &formerObj
  372. } else {
  373. // check fromer's class metadata
  374. cm, err := former.GetAllClassMetadata()
  375. if err != nil {
  376. return nil, errors.Wrap(err, "unable to GetAllClassMetadata")
  377. }
  378. if len(cm) > 0 {
  379. return nil, httperrors.NewForbiddenError("can't change owner for resource in project with class metadata")
  380. }
  381. }
  382. toer, err := TenantCacheManager.FetchTenantById(ctx, ownerId.GetProjectId())
  383. if err != nil {
  384. return nil, errors.Wrapf(err, "unable to get project %s", ownerId.GetProjectId())
  385. }
  386. toCm, err := toer.GetAllClassMetadata()
  387. if err != nil {
  388. return nil, errors.Wrap(err, "unable to GetAllClassMetadata")
  389. }
  390. if model.Keyword() != "image" && len(toCm) > 0 {
  391. return nil, httperrors.NewForbiddenError("can't change resource's owner as that in project with class metadata")
  392. }
  393. // clean shared projects before update project id
  394. if sharedModel, ok := model.GetIVirtualModel().(ISharableBaseModel); ok {
  395. if err := SharedResourceManager.CleanModelShares(ctx, userCred, sharedModel); err != nil {
  396. return nil, err
  397. }
  398. }
  399. // cancel usage
  400. model.cleanModelUsages(ctx, userCred)
  401. oldName := model.Name
  402. newName, err := GenerateName2(ctx, manager, ownerId, oldName, model, 1)
  403. if err != nil {
  404. return nil, errors.Wrap(err, "GenerateName2")
  405. }
  406. _, err = Update(model, func() error {
  407. if newName != oldName {
  408. model.Name = newName
  409. }
  410. model.DomainId = ownerId.GetProjectDomainId()
  411. model.ProjectId = ownerId.GetProjectId()
  412. model.ProjectSrc = string(apis.OWNER_SOURCE_LOCAL)
  413. return nil
  414. })
  415. if err != nil {
  416. return nil, errors.Wrap(err, "Update")
  417. }
  418. if oldName != model.Name {
  419. model.SetMetadata(ctx, "old_name", oldName, userCred)
  420. }
  421. // add usage
  422. model.RecoverUsages(ctx, userCred)
  423. OpsLog.SyncOwner(model, former, userCred)
  424. notes := struct {
  425. OldProjectId string
  426. OldProject string
  427. NewProjectId string
  428. NewProject string
  429. OldDomainId string
  430. OldDomain string
  431. NewDomainId string
  432. NewDomain string
  433. }{
  434. OldProjectId: former.Id,
  435. OldProject: former.Name,
  436. NewProjectId: ownerId.GetProjectId(),
  437. NewProject: ownerId.GetProjectName(),
  438. OldDomainId: former.DomainId,
  439. OldDomain: former.Domain,
  440. NewDomainId: ownerId.GetProjectDomainId(),
  441. NewDomain: ownerId.GetProjectDomain(),
  442. }
  443. // set class metadata
  444. err = model.SetClassMetadataAll(ctx, toCm, userCred)
  445. if err != nil {
  446. return nil, errors.Wrap(err, "unable to SetClassMetadataAll")
  447. }
  448. logclient.AddActionLogWithContext(ctx, model, logclient.ACT_CHANGE_OWNER, notes, userCred, true)
  449. return nil, nil
  450. }
  451. func (model *SVirtualResourceBase) DoPendingDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  452. if !model.PendingDeleted {
  453. return model.SPendingDeletedBase.MarkPendingDelete(model.GetIStandaloneModel(), ctx, userCred, "")
  454. }
  455. return nil
  456. }
  457. func (model *SVirtualResourceBase) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  458. err := model.DoPendingDelete(ctx, userCred)
  459. if err != nil {
  460. return errors.Wrap(err, "DoPendingDelete")
  461. }
  462. return DeleteModel(ctx, userCred, model.GetIVirtualModel())
  463. }
  464. // +onecloud:swagger-gen-ignore
  465. func (model *SVirtualResourceBase) PerformCancelDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  466. if model.PendingDeleted && !model.Deleted {
  467. err := model.DoCancelPendingDelete(ctx, userCred)
  468. if err != nil {
  469. return nil, errors.Wrap(err, "model.DoCancelPendingDelete")
  470. }
  471. model.RecoverUsages(ctx, userCred)
  472. }
  473. return nil, nil
  474. }
  475. func (model *SVirtualResourceBase) DoCancelPendingDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  476. if model.PendingDeleted && !model.Deleted {
  477. err := model.SPendingDeletedBase.MarkCancelPendingDelete(model.GetIStandaloneModel(), ctx, userCred)
  478. if err != nil {
  479. return errors.Wrap(err, "MarkCancelPendingDelete")
  480. }
  481. }
  482. return nil
  483. }
  484. func (model *SVirtualResourceBase) VirtualModelManager() IVirtualModelManager {
  485. return model.GetModelManager().(IVirtualModelManager)
  486. }
  487. func (model *SVirtualResourceBase) GetIVirtualModel() IVirtualModel {
  488. return model.GetVirtualObject().(IVirtualModel)
  489. }
  490. func (model *SVirtualResourceBase) GetShortDesc(ctx context.Context) *jsonutils.JSONDict {
  491. desc := model.SStatusStandaloneResourceBase.GetShortDesc(ctx)
  492. desc.Add(jsonutils.NewString(model.ProjectId), "owner_tenant_id")
  493. tc, _ := TenantCacheManager.FetchTenantById(ctx, model.ProjectId)
  494. if tc != nil {
  495. desc.Add(jsonutils.NewString(tc.GetName()), "owner_tenant")
  496. metadata, _ := GetVisibleMetadata(ctx, tc, nil)
  497. desc.Set("project_tags", jsonutils.Marshal(metadata))
  498. }
  499. return desc
  500. }
  501. func (model *SVirtualResourceBase) SetProjectSrc(src apis.TOwnerSource) {
  502. if model.ProjectSrc != string(src) {
  503. Update(model, func() error {
  504. model.ProjectSrc = string(apis.OWNER_SOURCE_CLOUD)
  505. return nil
  506. })
  507. }
  508. }
  509. func (model *SVirtualResourceBase) SyncCloudProjectId(userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider) {
  510. if model.ProjectSrc != string(apis.OWNER_SOURCE_LOCAL) && ownerId != nil && len(ownerId.GetProjectId()) > 0 {
  511. diff, _ := Update(model, func() error {
  512. model.ProjectSrc = string(apis.OWNER_SOURCE_CLOUD)
  513. model.ProjectId = ownerId.GetProjectId()
  514. model.DomainId = ownerId.GetProjectDomainId()
  515. return nil
  516. })
  517. if len(diff) > 0 {
  518. OpsLog.LogEvent(model, ACT_SYNC_OWNER, diff, userCred)
  519. }
  520. }
  521. }
  522. func (manager *SVirtualResourceBaseManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query apis.VirtualResourceListInput) (*sqlchemy.SQuery, error) {
  523. q, err := manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput)
  524. if err != nil {
  525. return nil, err
  526. }
  527. q, err = manager.SProjectizedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ProjectizedResourceListInput)
  528. if err != nil {
  529. return nil, err
  530. }
  531. return q, nil
  532. }
  533. func (manager *SVirtualResourceBaseManager) ListItemFilter(
  534. ctx context.Context,
  535. q *sqlchemy.SQuery,
  536. userCred mcclient.TokenCredential,
  537. query apis.VirtualResourceListInput,
  538. ) (*sqlchemy.SQuery, error) {
  539. q, err := manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput)
  540. if err != nil {
  541. return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter")
  542. }
  543. q, err = manager.SProjectizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ProjectizedResourceListInput)
  544. if err != nil {
  545. return nil, errors.Wrap(err, "SProjectizedResourceBaseManager.ListItemFilter")
  546. }
  547. return q, nil
  548. }
  549. func (manager *SVirtualResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  550. q, err := manager.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
  551. if err == nil {
  552. return q, nil
  553. }
  554. q, err = manager.SProjectizedResourceBaseManager.QueryDistinctExtraField(q, field)
  555. if err == nil {
  556. return q, nil
  557. }
  558. return q, httperrors.ErrNotFound
  559. }
  560. func (model *SVirtualResourceBase) ValidateUpdateData(
  561. ctx context.Context,
  562. userCred mcclient.TokenCredential,
  563. query jsonutils.JSONObject,
  564. input apis.VirtualResourceBaseUpdateInput,
  565. ) (apis.VirtualResourceBaseUpdateInput, error) {
  566. var err error
  567. input.StatusStandaloneResourceBaseUpdateInput, err = model.SStatusStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.StatusStandaloneResourceBaseUpdateInput)
  568. if err != nil {
  569. return input, errors.Wrap(err, "SStatusStandaloneResourceBase.ValidateUpdateData")
  570. }
  571. return input, nil
  572. }
  573. // +onecloud:swagger-gen-ignore
  574. func (model *SVirtualResourceBase) GetDetailsChangeOwnerCandidateDomains(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (apis.ChangeOwnerCandidateDomainsOutput, error) {
  575. return IOwnerResourceBaseModelGetChangeOwnerCandidateDomains(model.GetIVirtualModel())
  576. }
  577. func (manager *SVirtualResourceBaseManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, keys stringutils2.SSortedStrings) (*sqlchemy.SQuery, error) {
  578. q, err := manager.SStatusStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  579. if err != nil {
  580. return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemExportKeys")
  581. }
  582. q, err = manager.SProjectizedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  583. if err != nil {
  584. return nil, errors.Wrap(err, "SProjectizedResourceBaseManager.ListItemExportKeys")
  585. }
  586. return q, nil
  587. }
  588. func (manager *SVirtualResourceBaseManager) GetExportExtraKeys(ctx context.Context, keys stringutils2.SSortedStrings, rowMap map[string]string) *jsonutils.JSONDict {
  589. res := manager.SStatusStandaloneResourceBaseManager.GetExportExtraKeys(ctx, keys, rowMap)
  590. if userTags, ok := rowMap["user_tags"]; ok && len(userTags) > 0 {
  591. res.Set("user_tags", jsonutils.NewString(userTags))
  592. }
  593. return res
  594. }
  595. // +onecloud:swagger-gen-ignore
  596. func (manager *SVirtualResourceBaseManager) GetPropertyProjectTagValuePairs(
  597. ctx context.Context,
  598. userCred mcclient.TokenCredential,
  599. query jsonutils.JSONObject,
  600. ) (jsonutils.JSONObject, error) {
  601. return GetPropertyTagValuePairs(
  602. manager.GetIVirtualModelManager(),
  603. "project",
  604. "tenant_id",
  605. ctx,
  606. userCred,
  607. query,
  608. )
  609. }
  610. // +onecloud:swagger-gen-ignore
  611. func (manager *SVirtualResourceBaseManager) GetPropertyProjectTagValueTree(
  612. ctx context.Context,
  613. userCred mcclient.TokenCredential,
  614. query jsonutils.JSONObject,
  615. ) (jsonutils.JSONObject, error) {
  616. return GetPropertyTagValueTree(
  617. manager.GetIVirtualModelManager(),
  618. "project",
  619. "tenant_id",
  620. "",
  621. ctx,
  622. userCred,
  623. query,
  624. )
  625. }