metric.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  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 models
  15. import (
  16. "context"
  17. "sync"
  18. "golang.org/x/sync/errgroup"
  19. "yunion.io/x/jsonutils"
  20. "yunion.io/x/log"
  21. "yunion.io/x/pkg/errors"
  22. "yunion.io/x/pkg/util/rbacscope"
  23. "yunion.io/x/pkg/utils"
  24. "yunion.io/x/sqlchemy"
  25. "yunion.io/x/onecloud/pkg/apis/monitor"
  26. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  27. "yunion.io/x/onecloud/pkg/httperrors"
  28. "yunion.io/x/onecloud/pkg/mcclient"
  29. "yunion.io/x/onecloud/pkg/mcclient/auth"
  30. "yunion.io/x/onecloud/pkg/monitor/dbinit"
  31. "yunion.io/x/onecloud/pkg/monitor/registry"
  32. "yunion.io/x/onecloud/pkg/util/stringutils2"
  33. )
  34. var MetricMeasurementManager *SMetricMeasurementManager
  35. func init() {
  36. MetricMeasurementManager = &SMetricMeasurementManager{
  37. SStatusStandaloneResourceBaseManager: db.NewStatusStandaloneResourceBaseManager(
  38. SMetricMeasurement{},
  39. "metricmeasurement_tbl",
  40. "metricmeasurement",
  41. "metricmeasurements",
  42. ),
  43. measurementsCache: &sMetricMeasurementCache{},
  44. }
  45. MetricMeasurementManager.SetVirtualObject(MetricMeasurementManager)
  46. registry.RegisterService(MetricMeasurementManager)
  47. }
  48. // +onecloud:swagger-gen-model-singular=metricmeasurement
  49. // +onecloud:swagger-gen-model-plural=metricmeasurements
  50. type SMetricMeasurementManager struct {
  51. db.SEnabledResourceBaseManager
  52. db.SStatusStandaloneResourceBaseManager
  53. db.SScopedResourceBaseManager
  54. // measurementsCache records all cache measurement and related info
  55. measurementsCache *sMetricMeasurementCache
  56. }
  57. type SMetricMeasurement struct {
  58. //db.SVirtualResourceBase
  59. db.SEnabledResourceBase
  60. db.SStatusStandaloneResourceBase
  61. db.SScopedResourceBase
  62. ResType string `width:"32" list:"user" update:"user"`
  63. Database string `width:"32" list:"user" update:"user"`
  64. DisplayName string `width:"256" list:"user" update:"user"`
  65. Score int `width:"32" list:"user" update:"user" default:"99"`
  66. }
  67. type IMetricMeasurementCache interface {
  68. Get(measurementName string) (*SMetricMeasurement, bool)
  69. }
  70. type sMetricMeasurementCache struct {
  71. sync.Map
  72. }
  73. func (c *sMetricMeasurementCache) set(measurementName string, obj *SMetricMeasurement) {
  74. c.Store(measurementName, obj)
  75. }
  76. func (c *sMetricMeasurementCache) Get(measurementName string) (*SMetricMeasurement, bool) {
  77. obj, ok := c.Load(measurementName)
  78. if !ok {
  79. return nil, false
  80. }
  81. return obj.(*SMetricMeasurement), true
  82. }
  83. func (manager *SMetricMeasurementManager) GetCache() IMetricMeasurementCache {
  84. return manager.measurementsCache
  85. }
  86. func (manager *SMetricMeasurementManager) NamespaceScope() rbacscope.TRbacScope {
  87. return rbacscope.ScopeSystem
  88. }
  89. func (manager *SMetricMeasurementManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, keys stringutils2.SSortedStrings) (*sqlchemy.SQuery, error) {
  90. q, err := manager.SStatusStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  91. if err != nil {
  92. return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemExportKeys")
  93. }
  94. q, err = manager.SScopedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  95. if err != nil {
  96. return nil, errors.Wrap(err, "SScopedResourceBaseManager.ListItemExportKeys")
  97. }
  98. return q, nil
  99. }
  100. func (man *SMetricMeasurementManager) ValidateCreateData(
  101. ctx context.Context, userCred mcclient.TokenCredential,
  102. ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject,
  103. data monitor.MetricCreateInput) (monitor.MetricMeasurementCreateInput, error) {
  104. enable := true
  105. if data.Measurement.Enabled == nil {
  106. data.Measurement.Enabled = &enable
  107. }
  108. return data.Measurement, nil
  109. }
  110. func (measurement *SMetricMeasurement) CustomizeCreate(
  111. ctx context.Context, userCred mcclient.TokenCredential,
  112. ownerId mcclient.IIdentityProvider,
  113. query jsonutils.JSONObject,
  114. data jsonutils.JSONObject,
  115. ) error {
  116. err := measurement.SScopedResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
  117. if err != nil {
  118. return err
  119. }
  120. input := new(monitor.MetricCreateInput)
  121. if err := data.Unmarshal(input); err != nil {
  122. return err
  123. }
  124. for _, fieldInput := range input.MetricFields {
  125. field, err := measurement.SaveMetricField(ctx, userCred, ownerId, fieldInput)
  126. if err != nil {
  127. return errors.Wrap(err, "SMetricMeasurement CustomizeCreate to save field error")
  128. }
  129. err = measurement.attachMetricField(ctx, userCred, field)
  130. if err != nil {
  131. return errors.Wrap(err, "attachMetricField error")
  132. }
  133. }
  134. return nil
  135. }
  136. func (measurement *SMetricMeasurement) attachMetricField(ctx context.Context, userCred mcclient.TokenCredential,
  137. field *SMetricField) error {
  138. count, err := measurement.isAttachMetricField(field)
  139. if err != nil {
  140. return err
  141. }
  142. if count {
  143. return httperrors.ErrDuplicateName
  144. }
  145. metric := new(SMetric)
  146. if len(measurement.GetId()) == 0 {
  147. measurement.Id = db.DefaultUUIDGenerator()
  148. }
  149. metric.MeasurementId = measurement.GetId()
  150. metric.FieldId = field.GetId()
  151. return metric.DoSave(ctx)
  152. }
  153. func (measurement *SMetricMeasurement) isAttachMetricField(field *SMetricField) (bool, error) {
  154. q := MetricManager.Query().Equals(MetricManager.GetMasterFieldName(), measurement.GetId()).Equals(MetricManager.
  155. GetSlaveFieldName(), field.GetId())
  156. count, err := q.CountWithError()
  157. if err != nil {
  158. return false, err
  159. }
  160. return count > 0, nil
  161. }
  162. func (measurement *SMetricMeasurement) SaveMetricField(ctx context.Context, userCred mcclient.TokenCredential,
  163. ownerId mcclient.IIdentityProvider, fieldInput monitor.MetricFieldCreateInput) (*SMetricField, error) {
  164. return MetricFieldManager.SaveMetricField(ctx, userCred, ownerId, fieldInput)
  165. }
  166. func (manager *SMetricMeasurementManager) ListItemFilter(
  167. ctx context.Context, q *sqlchemy.SQuery,
  168. userCred mcclient.TokenCredential,
  169. query monitor.MetricListInput,
  170. ) (*sqlchemy.SQuery, error) {
  171. var err error
  172. q, err = manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.Measurement.StandaloneResourceListInput)
  173. if err != nil {
  174. return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter")
  175. }
  176. q, err = manager.SEnabledResourceBaseManager.ListItemFilter(ctx, q, userCred,
  177. query.Measurement.EnabledResourceBaseListInput)
  178. if err != nil {
  179. return nil, errors.Wrap(err, "SEnabledResourceBaseManager.ListItemFilter")
  180. }
  181. q, err = manager.SScopedResourceBaseManager.ListItemFilter(ctx, q, userCred,
  182. query.Measurement.ScopedResourceBaseListInput)
  183. if err != nil {
  184. return nil, errors.Wrap(err, "SScopedResourceBaseManager.ListItemFilter")
  185. }
  186. if len(query.Measurement.ResType) != 0 {
  187. q = q.Equals("res_type", query.Measurement.ResType)
  188. }
  189. if len(query.Measurement.DisplayName) != 0 {
  190. q = q.Equals("display_name", query.Measurement.DisplayName)
  191. }
  192. joinQuery, err := manager.listFilterMetricField(ctx, userCred, query.MetricFields)
  193. if err != nil {
  194. return q, err
  195. }
  196. joinSubQuery := joinQuery.SubQuery()
  197. q = q.Join(joinSubQuery, sqlchemy.Equals(q.Field("id"), joinSubQuery.Field(MetricManager.GetMasterFieldName())))
  198. return q, nil
  199. }
  200. func (man *SMetricMeasurementManager) OrderByExtraFields(
  201. ctx context.Context,
  202. q *sqlchemy.SQuery,
  203. userCred mcclient.TokenCredential,
  204. input monitor.AlertListInput,
  205. ) (*sqlchemy.SQuery, error) {
  206. var err error
  207. q, err = man.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.StatusStandaloneResourceListInput)
  208. if err != nil {
  209. return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields")
  210. }
  211. q, err = man.SScopedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.ScopedResourceBaseListInput)
  212. if err != nil {
  213. return nil, errors.Wrap(err, "SScopedResourceBaseManager.OrderByExtraFields")
  214. }
  215. return q, nil
  216. }
  217. func (manager *SMetricMeasurementManager) listFilterMetricField(ctx context.Context, userCred mcclient.TokenCredential, query monitor.MetricFieldListInput) (*sqlchemy.SQuery, error) {
  218. joinQuery := MetricManager.Query(MetricManager.GetMasterFieldName()).Distinct()
  219. fieldQuery, err := MetricFieldManager.ListItemFilter(ctx, MetricFieldManager.Query(), userCred, query)
  220. if err != nil {
  221. return nil, err
  222. }
  223. fieldSubQuery := fieldQuery.SubQuery()
  224. joinQuery = joinQuery.Join(fieldSubQuery, sqlchemy.Equals(joinQuery.Field(MetricManager.
  225. GetSlaveFieldName()), fieldSubQuery.Field("id")))
  226. return joinQuery, nil
  227. }
  228. func (man *SMetricMeasurementManager) FetchCustomizeColumns(
  229. ctx context.Context,
  230. userCred mcclient.TokenCredential,
  231. query jsonutils.JSONObject,
  232. objs []interface{},
  233. fields stringutils2.SSortedStrings,
  234. isList bool,
  235. ) []monitor.MetricDetails {
  236. rows := make([]monitor.MetricDetails, len(objs))
  237. stdRows := man.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  238. scopedRows := man.SScopedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  239. for i := range rows {
  240. rows[i] = monitor.MetricDetails{
  241. StatusStandaloneResourceDetails: stdRows[i],
  242. ScopedResourceBaseInfo: scopedRows[i],
  243. }
  244. rows[i], _ = objs[i].(*SMetricMeasurement).GetMoreDetails(rows[i])
  245. }
  246. return rows
  247. }
  248. func (measurement *SMetricMeasurement) GetMoreDetails(out monitor.MetricDetails) (monitor.MetricDetails, error) {
  249. fields, err := measurement.getFields()
  250. if err != nil {
  251. log.Errorln(err)
  252. return out, err
  253. }
  254. fieldDetails := make([]monitor.MetricFieldDetail, 0)
  255. for _, field := range fields {
  256. fieldObj := jsonutils.Marshal(&field)
  257. fieldDetail := new(monitor.MetricFieldDetail)
  258. err := fieldObj.Unmarshal(fieldDetail)
  259. if err != nil {
  260. log.Errorln(err)
  261. return out, err
  262. }
  263. fieldDetails = append(fieldDetails, *fieldDetail)
  264. }
  265. out.MetricFields = fieldDetails
  266. return out, nil
  267. }
  268. func (measurement *SMetricMeasurement) ValidateUpdateData(
  269. ctx context.Context,
  270. userCred mcclient.TokenCredential,
  271. query jsonutils.JSONObject,
  272. data monitor.MetricUpdateInput,
  273. ) (monitor.MetricMeasurementUpdateInput, error) {
  274. if len(data.Measurement.ResType) == 0 {
  275. return data.Measurement, errors.Wrap(httperrors.ErrNotEmpty, "res_type")
  276. }
  277. if !utils.IsInStringArray(data.Measurement.ResType, monitor.MetricResType) {
  278. return data.Measurement, errors.Wrap(httperrors.ErrBadRequest, "res_type")
  279. }
  280. if len(data.Measurement.DisplayName) == 0 {
  281. return data.Measurement, errors.Wrap(httperrors.ErrNotEmpty, "display_name")
  282. }
  283. return data.Measurement, nil
  284. }
  285. func (measurement *SMetricMeasurement) PreUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject,
  286. data jsonutils.JSONObject) {
  287. input := new(monitor.MetricUpdateInput)
  288. if err := data.Unmarshal(input); err != nil {
  289. return
  290. }
  291. for _, fieldUpdateInput := range input.MetricFields {
  292. field, err := measurement.getMetricField(fieldUpdateInput.Name)
  293. if err != nil {
  294. log.Errorln(err, "metric measurement getMetricFields error")
  295. continue
  296. }
  297. if field == nil {
  298. log.Errorf("field:%s do not attach with measurement:%s", fieldUpdateInput.Name, measurement.Name)
  299. continue
  300. }
  301. err = measurement.updateMetricField(ctx, userCred, field, fieldUpdateInput)
  302. if err != nil {
  303. log.Errorln(err, "measurement updateMetricField")
  304. }
  305. }
  306. }
  307. func (measurement *SMetricMeasurement) getMetricField(name string) (*SMetricField, error) {
  308. fields := make([]SMetricField, 0)
  309. q := measurement.getFieldsQuery()
  310. q = q.Equals("name", name)
  311. err := db.FetchModelObjects(MetricFieldManager, q, &fields)
  312. if err != nil {
  313. return nil, err
  314. }
  315. if len(fields) == 0 {
  316. return nil, nil
  317. }
  318. if len(fields) != 1 {
  319. return nil, errors.Wrapf(sqlchemy.ErrDuplicateEntry, "found %d, metric field name: %s", len(fields), name)
  320. }
  321. return &fields[0], nil
  322. }
  323. func (measurement *SMetricMeasurement) getFields() ([]SMetricField, error) {
  324. fields := make([]SMetricField, 0)
  325. q := measurement.getFieldsQuery()
  326. q.Asc("score")
  327. err := db.FetchModelObjects(MetricFieldManager, q, &fields)
  328. if err != nil {
  329. return nil, err
  330. }
  331. return fields, nil
  332. }
  333. func (manager *SMetricMeasurementManager) getMeasurement(query *sqlchemy.SQuery) ([]SMetricMeasurement, error) {
  334. measurements := make([]SMetricMeasurement, 0)
  335. err := db.FetchModelObjects(MetricMeasurementManager, query, &measurements)
  336. if err != nil {
  337. return nil, err
  338. }
  339. return measurements, nil
  340. }
  341. func (manager *SMetricMeasurementManager) getMeasurementsFromDB() ([]monitor.InfluxMeasurement, error) {
  342. ms, err := manager.getMeasurement(manager.Query())
  343. if err != nil {
  344. return nil, errors.Wrap(err, "getMeasurement")
  345. }
  346. ret := make([]monitor.InfluxMeasurement, len(ms))
  347. for i := range ms {
  348. m := ms[i]
  349. fields, _ := m.getFields()
  350. if len(fields) == 0 {
  351. continue
  352. }
  353. fieldsKey := make([]string, len(fields))
  354. for i, field := range fields {
  355. fieldsKey[i] = field.Name
  356. }
  357. ret[i] = monitor.InfluxMeasurement{
  358. Database: m.Database,
  359. Measurement: m.Name,
  360. ResType: m.ResType,
  361. FieldKey: fieldsKey,
  362. }
  363. }
  364. return ret, nil
  365. }
  366. func (measurement *SMetricMeasurement) getFieldsQuery() *sqlchemy.SQuery {
  367. metricJoinQuery := MetricManager.Query().Equals(MetricManager.GetMasterFieldName(), measurement.GetId()).SubQuery()
  368. q := MetricFieldManager.Query()
  369. q = q.Join(metricJoinQuery, sqlchemy.Equals(q.Field("id"), metricJoinQuery.Field(MetricManager.GetSlaveFieldName())))
  370. return q
  371. }
  372. func (measurement *SMetricMeasurement) updateMetricField(ctx context.Context, userCred mcclient.TokenCredential,
  373. field *SMetricField, input monitor.MetricFieldUpdateInput) error {
  374. _, err := field.ValidateUpdateData(ctx, userCred, nil, input)
  375. if err != nil {
  376. return err
  377. }
  378. _, err = db.Update(field, func() error {
  379. field.Unit = input.Unit
  380. field.DisplayName = input.DisplayName
  381. return nil
  382. })
  383. return err
  384. }
  385. func (manager *SMetricMeasurementManager) Init() error {
  386. return nil
  387. }
  388. func (man *SMetricMeasurementManager) Run(ctx context.Context) error {
  389. err := man.initJsonMetricInfo(ctx)
  390. if err != nil {
  391. return errors.Wrap(err, "init metric json error")
  392. }
  393. log.Infoln("========metric_measurement_field init finish==========")
  394. err = CommonAlertManager.UpdateAlertsResType(ctx, auth.AdminCredential())
  395. if err != nil {
  396. return errors.Wrap(err, "CommonAlertManager UpdateAlertsResType err")
  397. }
  398. log.Infoln("========UpdateAlertsResType Finish==========")
  399. return nil
  400. }
  401. func (manager *SMetricMeasurementManager) initJsonMetricInfo(ctx context.Context) error {
  402. metricInitInputs := dbinit.GetRegistryMetricInput()
  403. if len(metricInitInputs) == 0 {
  404. log.Infoln("not init anything")
  405. return nil
  406. }
  407. if err := manager.initMetrics(ctx, metricInitInputs); err != nil {
  408. return errors.Wrap(err, "initMetrics")
  409. }
  410. if err := manager.deleteUnusedMetricDescriptions(); err != nil {
  411. return errors.Wrap(err, "deleteUnusedMetricDescriptions")
  412. }
  413. if err := manager.reloadCache(); err != nil {
  414. return errors.Wrap(err, "reload measurement cache")
  415. }
  416. return nil
  417. }
  418. func (manager *SMetricMeasurementManager) reloadCache() error {
  419. objs := make([]SMetricMeasurement, 0)
  420. q := manager.Query()
  421. if err := db.FetchModelObjects(manager, q, &objs); err != nil {
  422. return errors.Wrap(err, "Fetch all measurements")
  423. }
  424. for i, obj := range objs {
  425. manager.measurementsCache.set(obj.Name, &objs[i])
  426. }
  427. return nil
  428. }
  429. func (manager *SMetricMeasurementManager) deleteUnusedMetricDescriptions() error {
  430. metricMeasurements, err := manager.getMeasurementByName(dbinit.MetricNeedDeleteDescriptions...)
  431. if err != nil {
  432. return err
  433. }
  434. userCred := auth.AdminCredential()
  435. for i, _ := range metricMeasurements {
  436. err := (&metricMeasurements[i]).CustomizeDelete(context.Background(), userCred, jsonutils.NewDict(),
  437. jsonutils.NewDict())
  438. if err != nil {
  439. return errors.Wrap(err, "init deleteUnusedMetricDescriptions error")
  440. }
  441. err = (&metricMeasurements[i]).Delete(context.Background(), userCred)
  442. if err != nil {
  443. return errors.Wrap(err, "init deleteUnusedMetricDescriptions error")
  444. }
  445. }
  446. return nil
  447. }
  448. func (manager *SMetricMeasurementManager) initMetrics(ctx context.Context, metrics []monitor.MetricCreateInput) (err error) {
  449. measurementGroup, _ := errgroup.WithContext(ctx)
  450. count := 0
  451. for mIndex, _ := range metrics {
  452. measurementTmp := metrics[mIndex]
  453. if mIndex < len(metrics) && count < 10 {
  454. count++
  455. measurementGroup.Go(func() error {
  456. return manager.initMeasurementAndFieldInfo(measurementTmp)
  457. })
  458. }
  459. if count == 1 {
  460. err := measurementGroup.Wait()
  461. if err != nil {
  462. return err
  463. }
  464. count = 0
  465. }
  466. }
  467. err = measurementGroup.Wait()
  468. return
  469. }
  470. func (manager *SMetricMeasurementManager) initMeasurementAndFieldInfo(createInput monitor.MetricCreateInput) error {
  471. userCred := auth.AdminCredential()
  472. measurements, err := manager.getMeasurementByName(createInput.Measurement.Name)
  473. if err != nil {
  474. return errors.Wrap(err, "join query get measurement error")
  475. }
  476. unInsertFields := createInput.MetricFields
  477. updateFields := make([]monitor.MetricFieldCreateInput, 0)
  478. deleteFields := make([]string, 0)
  479. if len(measurements) != 0 {
  480. unInsertFields, updateFields, deleteFields = measurements[0].getInsertAndUpdateFields(userCred, createInput)
  481. }
  482. if len(measurements) == 0 {
  483. _, err := db.DoCreate(manager, context.Background(), userCred, jsonutils.NewDict(),
  484. jsonutils.Marshal(&createInput),
  485. userCred)
  486. if err != nil {
  487. err = errors.Wrap(err, "create metricdescription error")
  488. }
  489. return err
  490. }
  491. createInput.MetricFields = unInsertFields
  492. return measurements[0].insertOrUpdateMetric(userCred, createInput, updateFields, deleteFields)
  493. }
  494. func (manager *SMetricMeasurementManager) getMeasurementByName(names ...string) ([]SMetricMeasurement, error) {
  495. userCred := auth.AdminCredential()
  496. listInput := new(monitor.MetricListInput)
  497. if len(names) == 0 {
  498. return []SMetricMeasurement{}, nil
  499. }
  500. listInput.Measurement.Names = names
  501. query, err := MetricMeasurementManager.ListItemFilter(context.Background(), MetricMeasurementManager.Query(), userCred,
  502. *listInput)
  503. if err != nil {
  504. return nil, err
  505. }
  506. return manager.getMeasurement(query)
  507. }
  508. func (self *SMetricMeasurement) getInsertAndUpdateFields(userCred mcclient.TokenCredential, input monitor.MetricCreateInput) (unInsertFields,
  509. updateFields []monitor.MetricFieldCreateInput, deleteFields []string) {
  510. measurementsIns := []interface{}{self}
  511. details := MetricMeasurementManager.FetchCustomizeColumns(context.Background(), userCred, jsonutils.NewDict(), measurementsIns,
  512. stringutils2.NewSortedStrings([]string{}), true)
  513. unInsertFields, updateFields, deleteFields = getUnInsertFields(input.MetricFields, details[0])
  514. return
  515. }
  516. func (self *SMetricMeasurement) insertOrUpdateMetric(userCred mcclient.TokenCredential,
  517. createInput monitor.MetricCreateInput, updateFields []monitor.MetricFieldCreateInput, deleteFields []string) error {
  518. _, err := db.Update(self, func() error {
  519. if len(createInput.Measurement.DisplayName) != 0 {
  520. self.DisplayName = createInput.Measurement.DisplayName
  521. }
  522. if len(createInput.Measurement.ResType) != 0 {
  523. self.ResType = createInput.Measurement.ResType
  524. }
  525. if len(createInput.Measurement.Database) != 0 {
  526. self.Database = createInput.Measurement.Database
  527. }
  528. if createInput.Measurement.Score != 0 {
  529. self.Score = createInput.Measurement.Score
  530. }
  531. return nil
  532. })
  533. if err != nil {
  534. return errors.Wrap(err, "update metric measurement error")
  535. }
  536. err = self.CustomizeCreate(context.Background(), userCred, userCred, jsonutils.NewDict(),
  537. jsonutils.Marshal(&createInput))
  538. if err != nil {
  539. return errors.Wrap(err, "create metric field error")
  540. }
  541. dbFields, _ := self.getFields()
  542. for i, _ := range dbFields {
  543. for upIndex, _ := range updateFields {
  544. if dbFields[i].Name == updateFields[upIndex].Name {
  545. _, err := db.Update(&dbFields[i], func() error {
  546. if len(updateFields[upIndex].DisplayName) != 0 {
  547. dbFields[i].DisplayName = updateFields[upIndex].DisplayName
  548. }
  549. if len(updateFields[upIndex].Unit) != 0 {
  550. dbFields[i].Unit = updateFields[upIndex].Unit
  551. }
  552. if updateFields[upIndex].Score != 0 {
  553. dbFields[i].Score = updateFields[upIndex].Score
  554. }
  555. return nil
  556. })
  557. if err != nil {
  558. return errors.Wrap(err, "update metric field error")
  559. }
  560. }
  561. }
  562. for _, field := range deleteFields {
  563. if field == dbFields[i].Name {
  564. err := dbFields[i].CustomizeDelete(context.Background(), userCred, nil, nil)
  565. if err != nil {
  566. return errors.Wrap(err, "CustomizeDelete fields error")
  567. }
  568. err = dbFields[i].Delete(context.Background(), userCred)
  569. if err != nil {
  570. return errors.Wrap(err, "Delete fields error")
  571. }
  572. }
  573. }
  574. }
  575. return nil
  576. }
  577. func getUnInsertFields(searchFields []monitor.MetricFieldCreateInput,
  578. dbFields monitor.MetricDetails) (unInsertFields, updateFields []monitor.
  579. MetricFieldCreateInput, deleteFields []string) {
  580. fieldCountMap := make(map[string]int)
  581. fieldMap := make(map[string]monitor.MetricFieldCreateInput, 0)
  582. for _, field := range searchFields {
  583. fieldCountMap[field.Name]++
  584. fieldMap[field.Name] = field
  585. }
  586. for _, dbField := range dbFields.MetricFields {
  587. count, _ := fieldCountMap[dbField.Name]
  588. if count == 1 {
  589. if field, ok := fieldMap[dbField.Name]; ok {
  590. updateFields = append(updateFields, field)
  591. }
  592. delete(fieldCountMap, dbField.Name)
  593. } else {
  594. deleteFields = append(deleteFields, dbField.Name)
  595. }
  596. }
  597. for fieldName, _ := range fieldCountMap {
  598. if field, ok := fieldMap[fieldName]; ok {
  599. unInsertFields = append(unInsertFields, field)
  600. }
  601. }
  602. return unInsertFields, updateFields, deleteFields
  603. }
  604. func (self *SMetricMeasurement) getMetricJoint() ([]SMetric, error) {
  605. metricJoint := make([]SMetric, 0)
  606. q := MetricManager.Query().Equals(MetricManager.GetMasterFieldName(), self.Id)
  607. if err := db.FetchModelObjects(MetricManager, q, &metricJoint); err != nil {
  608. return nil, err
  609. }
  610. return metricJoint, nil
  611. }
  612. func (self *SMetricMeasurement) CustomizeDelete(
  613. ctx context.Context, userCred mcclient.TokenCredential,
  614. query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  615. metricJoint, err := self.getMetricJoint()
  616. if err != nil {
  617. return err
  618. }
  619. for _, joint := range metricJoint {
  620. field, err := joint.GetMetricField(ctx)
  621. if err != nil {
  622. return err
  623. }
  624. if err := field.CustomizeDelete(ctx, userCred, query, data); err != nil {
  625. return err
  626. }
  627. if err := field.Delete(ctx, userCred); err != nil {
  628. return err
  629. }
  630. if err := joint.Detach(ctx, userCred); err != nil {
  631. return err
  632. }
  633. }
  634. return nil
  635. }