query.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844
  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 conditions
  15. import (
  16. "context"
  17. "fmt"
  18. "sort"
  19. "strings"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/log"
  22. "yunion.io/x/pkg/errors"
  23. "yunion.io/x/pkg/util/sets"
  24. "yunion.io/x/pkg/utils"
  25. "yunion.io/x/onecloud/pkg/apis/compute"
  26. "yunion.io/x/onecloud/pkg/apis/monitor"
  27. "yunion.io/x/onecloud/pkg/hostman/hostinfo/hostconsts"
  28. "yunion.io/x/onecloud/pkg/mcclient"
  29. "yunion.io/x/onecloud/pkg/mcclient/modulebase"
  30. mc_mds "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
  31. "yunion.io/x/onecloud/pkg/mcclient/modules/identity"
  32. "yunion.io/x/onecloud/pkg/monitor/alerting"
  33. "yunion.io/x/onecloud/pkg/monitor/datasource"
  34. "yunion.io/x/onecloud/pkg/monitor/models"
  35. "yunion.io/x/onecloud/pkg/monitor/options"
  36. "yunion.io/x/onecloud/pkg/monitor/tsdb"
  37. "yunion.io/x/onecloud/pkg/monitor/validators"
  38. )
  39. func init() {
  40. alerting.RegisterCondition("query", func(model *monitor.AlertCondition, index int) (alerting.Condition, error) {
  41. return newQueryCondition(model, index)
  42. })
  43. RestryFetchImp(monitor.METRIC_DATABASE_METER, &meterFetchImp{})
  44. }
  45. // QueryCondition is responsible for issue and query. reduce the
  46. // timeseries into single values and evaluate if they are firing or not.
  47. type QueryCondition struct {
  48. Index int
  49. Query AlertQuery
  50. Reducer Reducer
  51. ReducerOrder monitor.ResultReducerOrder
  52. Evaluator AlertEvaluator
  53. Operator string
  54. HandleRequest tsdb.HandleRequestFunc
  55. ResType string
  56. }
  57. // AlertQuery contains information about what datasource a query
  58. // should be send to and the query object.
  59. type AlertQuery struct {
  60. Model monitor.MetricQuery
  61. From string
  62. To string
  63. }
  64. type FormatCond struct {
  65. QueryMeta *monitor.QueryResultMeta
  66. QueryKeyInfo string
  67. Reducer string
  68. Evaluator AlertEvaluator
  69. }
  70. type iEvalMatchFetch interface {
  71. FetchCustomizeEvalMatch(context *alerting.EvalContext, evalMatch *monitor.EvalMatch,
  72. alertDetails *monitor.CommonAlertMetricDetails) error
  73. }
  74. var iFetchImp map[string]iEvalMatchFetch
  75. func RestryFetchImp(db string, imp iEvalMatchFetch) {
  76. if iFetchImp == nil {
  77. iFetchImp = make(map[string]iEvalMatchFetch)
  78. }
  79. iFetchImp[db] = imp
  80. }
  81. func GetFetchImpByDb(db string) iEvalMatchFetch {
  82. if iFetchImp == nil {
  83. return nil
  84. }
  85. return iFetchImp[db]
  86. }
  87. func (c *QueryCondition) GenerateFormatCond(meta *monitor.QueryResultMeta, metric string) *FormatCond {
  88. return &FormatCond{
  89. QueryMeta: meta,
  90. QueryKeyInfo: metric,
  91. Reducer: string(c.Reducer.GetType()),
  92. Evaluator: c.Evaluator,
  93. }
  94. }
  95. func (c *QueryCondition) IsCloudResource() bool {
  96. if c.ResType == "" {
  97. return false
  98. }
  99. return monitor.MetricCloudResTypes.Has(c.ResType)
  100. }
  101. func (c FormatCond) String() string {
  102. if c.QueryMeta != nil {
  103. return fmt.Sprintf("%s(%q) %s", c.Reducer, c.QueryMeta.RawQuery, c.Evaluator.String())
  104. }
  105. return "no_data"
  106. }
  107. func (c *QueryCondition) filterTags(tags map[string]string, cloudTags map[string]string, details monitor.CommonAlertMetricDetails) map[string]string {
  108. ret := make(map[string]string)
  109. allTags := make(map[string]string)
  110. for _, ts := range []map[string]string{tags, cloudTags} {
  111. for k, v := range ts {
  112. allTags[k] = v
  113. }
  114. }
  115. for key, val := range allTags {
  116. //if strings.HasSuffix(key, "_id") {
  117. // continue
  118. //}
  119. if len(val) == 0 {
  120. continue
  121. }
  122. if tag, ok := monitor.MEASUREMENT_TAG_KEYWORD[details.ResType]; ok {
  123. if key == tag {
  124. ret["name"] = val
  125. }
  126. }
  127. if strings.Contains(key, "ip") && key != "host_ip" {
  128. ret["ip"] = val
  129. }
  130. ret[key] = val
  131. }
  132. if _, ok := ret["ip"]; !ok {
  133. ret["ip"] = tags["host_ip"]
  134. }
  135. if _, ok := ret["name"]; !ok {
  136. ret["name"] = tags["host"]
  137. }
  138. for _, tag := range []string{"brand", "platform", "hypervisor"} {
  139. if val, ok := ret[tag]; ok {
  140. ret["brand"] = val
  141. break
  142. }
  143. }
  144. return ret
  145. }
  146. // Eval evaluates te `QueryCondition`.
  147. func (c *QueryCondition) Eval(context *alerting.EvalContext) (*alerting.ConditionResult, error) {
  148. timeRange := tsdb.NewTimeRange(c.Query.From, c.Query.To)
  149. ret, err := c.executeQuery(context, timeRange)
  150. if err != nil {
  151. return nil, err
  152. }
  153. seriesList := ret.series
  154. metas := ret.metas
  155. emptySeriesCount := 0
  156. evalMatchCount := 0
  157. var matches []*monitor.EvalMatch
  158. var alertOkmatches []*monitor.EvalMatch
  159. alert, err := models.CommonAlertManager.GetAlert(context.Rule.Id)
  160. if err != nil {
  161. return nil, errors.Wrap(err, "GetAlert to NewEvalMatch error")
  162. }
  163. for _, series := range seriesList {
  164. if c.IsCloudResource() {
  165. isLatestOfSerie, resource := c.serieIsLatestResource(nil, series)
  166. if !isLatestOfSerie {
  167. continue
  168. }
  169. c.FillSerieByResourceField(resource, series)
  170. }
  171. reducedValue, valStrArr := c.Reducer.Reduce(series)
  172. evalMatch := c.Evaluator.Eval(reducedValue)
  173. if reducedValue == nil {
  174. emptySeriesCount++
  175. }
  176. if context.IsTestRun {
  177. context.Logs = append(context.Logs, &monitor.ResultLogEntry{
  178. Message: fmt.Sprintf("Condition[%d]: EvalMatch: %v, Metric: %s, Value: %s", c.Index, evalMatch, series.Name, jsonutils.Marshal(reducedValue)),
  179. })
  180. }
  181. if evalMatch {
  182. evalMatchCount++
  183. }
  184. var meta *monitor.QueryResultMeta
  185. if len(metas) > 0 {
  186. //the relation metas with series is 1 to more
  187. meta = &metas[0]
  188. }
  189. if evalMatch {
  190. match, err := c.NewEvalMatch(alert, context, *series, meta, reducedValue, valStrArr, evalMatch)
  191. if err != nil {
  192. return nil, errors.Wrap(err, "NewEvalMatch error")
  193. }
  194. matches = append(matches, match)
  195. }
  196. if reducedValue != nil && !evalMatch {
  197. match, err := c.NewEvalMatch(alert, context, *series, meta, reducedValue, valStrArr, evalMatch)
  198. if err != nil {
  199. return nil, errors.Wrap(err, "NewEvalMatch error")
  200. }
  201. resId := monitor.GetResourceIdFromTagWithDefault(match.Tags, c.ResType)
  202. if err := OkEvalMatchSetIsRecovery(alert, resId, match); err != nil {
  203. log.Warningf("[Query] set eval match %s to recovered: %v", jsonutils.Marshal(match), err)
  204. }
  205. alertOkmatches = append(alertOkmatches, match)
  206. }
  207. }
  208. // handle no series special case
  209. if len(seriesList) == 0 {
  210. // eval condition for null value
  211. evalMatch := c.Evaluator.Eval(nil)
  212. if context.IsTestRun {
  213. context.Logs = append(context.Logs, &monitor.ResultLogEntry{
  214. Message: fmt.Sprintf("Condition: Eval: %v, Query returned No Series (reduced to null/no value)", evalMatch),
  215. })
  216. }
  217. if evalMatch {
  218. evalMatchCount++
  219. matches = append(matches, &monitor.EvalMatch{
  220. Metric: "NoData",
  221. Value: nil,
  222. })
  223. }
  224. }
  225. if evalMatchCount == 0 && len(seriesList) != 0 {
  226. log.Debugf("sql-meta: %s", metas[0].RawQuery)
  227. }
  228. return &alerting.ConditionResult{
  229. Firing: evalMatchCount > 0,
  230. NoDataFound: emptySeriesCount == len(seriesList),
  231. Operator: c.Operator,
  232. EvalMatches: matches,
  233. AlertOkEvalMatches: alertOkmatches,
  234. }, nil
  235. }
  236. func (c *QueryCondition) serieIsLatestResource(resources map[string]jsonutils.JSONObject, series *monitor.TimeSeries) (bool, jsonutils.JSONObject) {
  237. resId := monitor.GetResourceIdFromTagWithDefault(series.Tags, c.ResType)
  238. if len(resources) != 0 {
  239. resource, ok := resources[resId]
  240. if !ok {
  241. return false, nil
  242. }
  243. got, obj := models.MonitorResourceManager.GetResourceObj(resId)
  244. if got {
  245. return true, obj
  246. } else {
  247. log.Warningf("not found resource %s %s from cache, use list item directly", c.ResType, resId)
  248. return true, resource
  249. }
  250. }
  251. return models.MonitorResourceManager.GetResourceObj(resId)
  252. }
  253. func (c *QueryCondition) FillSerieByResourceField(resource jsonutils.JSONObject,
  254. series *monitor.TimeSeries) {
  255. //startTime := time.Now()
  256. //defer func() {
  257. // log.Debugf("--FillSerieByResourceField: %s", time.Since(startTime))
  258. //}()
  259. tagKeyRelationMap := c.getTagKeyRelationMap()
  260. for tagKey, resourceKey := range tagKeyRelationMap {
  261. val, err := resource.Get(resourceKey)
  262. if err != nil {
  263. continue
  264. }
  265. if series.CloudTags == nil {
  266. series.CloudTags = map[string]string{}
  267. }
  268. series.CloudTags[tagKey], _ = val.GetString()
  269. }
  270. }
  271. func (c *QueryCondition) NewEvalMatch(
  272. alert *models.SCommonAlert,
  273. context *alerting.EvalContext,
  274. series monitor.TimeSeries,
  275. meta *monitor.QueryResultMeta,
  276. value *float64, valStrArr []string, isMatch bool) (*monitor.EvalMatch, error) {
  277. evalMatch := new(monitor.EvalMatch)
  278. alertDetails, err := c.GetCommonAlertDetails(alert)
  279. if err != nil {
  280. return nil, errors.Wrap(err, "GetAlert to NewEvalMatch error")
  281. }
  282. evalMatch.Metric = fmt.Sprintf("%s.%s", alertDetails.Measurement, alertDetails.Field)
  283. queryKeyInfo := ""
  284. if len(alertDetails.MeasurementDisplayName) > 0 && len(alertDetails.FieldDescription.DisplayName) > 0 {
  285. queryKeyInfo = fmt.Sprintf("%s.%s", alertDetails.MeasurementDisplayName, alertDetails.FieldDescription.DisplayName)
  286. }
  287. if len(queryKeyInfo) == 0 {
  288. queryKeyInfo = evalMatch.Metric
  289. }
  290. evalMatch.Unit = alertDetails.FieldDescription.Unit
  291. evalMatch.Tags = c.filterTags(series.Tags, series.CloudTags, *alertDetails)
  292. evalMatch.Value = value
  293. evalMatch.ValueStr = models.RationalizeValueFromUnit(*value, alertDetails.FieldDescription.Unit,
  294. alertDetails.FieldOpt)
  295. if alertDetails.GetPointStr {
  296. evalMatch.ValueStr = c.jointPointStr(series, evalMatch.ValueStr, valStrArr)
  297. }
  298. c.FetchCustomizeEvalMatch(context, evalMatch, alertDetails)
  299. //c.newRuleDescription(context, alertDetails)
  300. //evalMatch.Condition = c.GenerateFormatCond(meta, queryKeyInfo).String()
  301. var thresholdStr string
  302. // 处理 ranged types (within_range, outside_range)
  303. if utils.IsInStringArray(alertDetails.Comparator, validators.EvaluatorRangedTypes) {
  304. if len(alertDetails.ThresholdRange) >= 2 {
  305. lowerStr := models.RationalizeValueFromUnit(alertDetails.ThresholdRange[0], evalMatch.Unit, "")
  306. upperStr := models.RationalizeValueFromUnit(alertDetails.ThresholdRange[1], evalMatch.Unit, "")
  307. thresholdStr = fmt.Sprintf("[%s, %s]", lowerStr, upperStr)
  308. } else {
  309. thresholdStr = models.RationalizeValueFromUnit(alertDetails.Threshold, evalMatch.Unit, "")
  310. }
  311. } else {
  312. // 处理默认 types (gt, lt, eq)
  313. thresholdStr = models.RationalizeValueFromUnit(alertDetails.Threshold, evalMatch.Unit, "")
  314. }
  315. msg := fmt.Sprintf("%s.%s %s %s", alertDetails.Measurement, alertDetails.Field,
  316. alertDetails.Comparator, thresholdStr)
  317. // 为每个 EvalMatch 记录自身的触发条件,便于在通知模板中按 metric 精确展示
  318. evalMatch.Condition = msg
  319. if len(context.Rule.Message) == 0 {
  320. context.Rule.Message = msg
  321. }
  322. // 避免重复指标
  323. if isMatch {
  324. op := alertDetails.Operator
  325. if op != "" && c.Index > 0 {
  326. msg = fmt.Sprintf("%s %s", strings.ToUpper(op), msg)
  327. }
  328. msgSet := sets.NewString(context.Rule.TriggeredMessages...)
  329. if !msgSet.Has(msg) {
  330. context.Rule.TriggeredMessages = append(context.Rule.TriggeredMessages, msg)
  331. }
  332. }
  333. evalMatch.AlertDetails = jsonutils.Marshal(alertDetails)
  334. return evalMatch, nil
  335. }
  336. func (c *QueryCondition) FetchCustomizeEvalMatch(context *alerting.EvalContext, evalMatch *monitor.EvalMatch,
  337. alertDetails *monitor.CommonAlertMetricDetails) {
  338. imp := GetFetchImpByDb(alertDetails.DB)
  339. if imp != nil {
  340. err := imp.FetchCustomizeEvalMatch(context, evalMatch, alertDetails)
  341. if err != nil {
  342. log.Errorf("%s FetchCustomizeEvalMatch err:%v", alertDetails.DB, err)
  343. }
  344. }
  345. }
  346. type meterFetchImp struct {
  347. }
  348. func (m *meterFetchImp) FetchCustomizeEvalMatch(context *alerting.EvalContext, evalMatch *monitor.EvalMatch,
  349. alertDetails *monitor.CommonAlertMetricDetails) error {
  350. meterCustomizeConfig := new(monitor.MeterCustomizeConfig)
  351. if context.Rule.CustomizeConfig == nil {
  352. return nil
  353. }
  354. err := context.Rule.CustomizeConfig.Unmarshal(meterCustomizeConfig)
  355. if err != nil {
  356. return err
  357. }
  358. //evalMatch.ValueStr = evalMatch.ValueStr + " " + meterCustomizeConfig.UnitDesc
  359. evalMatch.Unit = meterCustomizeConfig.UnitDesc
  360. return nil
  361. }
  362. func (c *QueryCondition) GetCommonAlertDetails(alert *models.SCommonAlert) (*monitor.CommonAlertMetricDetails, error) {
  363. settings, _ := alert.GetSettings()
  364. alertDetails := alert.GetCommonAlertMetricDetailsFromAlertCondition(c.Index, &settings.Conditions[c.Index])
  365. return alertDetails, nil
  366. }
  367. func (c *QueryCondition) jointPointStr(series monitor.TimeSeries, value string, valStrArr []string) string {
  368. str := ""
  369. for i := 0; i < len(valStrArr); i++ {
  370. if i == 0 {
  371. str = fmt.Sprintf("%s=%s", series.Columns[i], value)
  372. continue
  373. }
  374. str = fmt.Sprintf("%s,%s=%s", str, series.Columns[i], valStrArr[i])
  375. }
  376. return str
  377. }
  378. type queryResult struct {
  379. series monitor.TimeSeriesSlice
  380. metas []monitor.QueryResultMeta
  381. reducedResult *monitor.ReducedResult
  382. }
  383. func (c *QueryCondition) executeQuery(evalCtx *alerting.EvalContext, timeRange *tsdb.TimeRange) (*queryResult, error) {
  384. req := c.getRequestForAlertRule(timeRange, evalCtx.IsDebug)
  385. result := make(monitor.TimeSeriesSlice, 0)
  386. metas := make([]monitor.QueryResultMeta, 0)
  387. if evalCtx.IsDebug {
  388. data := jsonutils.NewDict()
  389. if req.TimeRange != nil {
  390. data.Set("from", jsonutils.NewInt(req.TimeRange.GetFromAsMsEpoch()))
  391. data.Set("to", jsonutils.NewInt(req.TimeRange.GetToAsMsEpoch()))
  392. }
  393. type queryDto struct {
  394. RefId string `json:"refId"`
  395. Model monitor.MetricQuery `json:"model"`
  396. Datasource tsdb.DataSource `json:"datasource"`
  397. MaxDataPoints int64 `json:"maxDataPoints"`
  398. IntervalMs int64 `json:"intervalMs"`
  399. }
  400. queries := []*queryDto{}
  401. for _, q := range req.Queries {
  402. queries = append(queries, &queryDto{
  403. RefId: q.RefId,
  404. Model: q.MetricQuery,
  405. Datasource: q.DataSource,
  406. MaxDataPoints: q.MaxDataPoints,
  407. IntervalMs: q.IntervalMs,
  408. })
  409. }
  410. data.Set("queries", jsonutils.Marshal(queries))
  411. evalCtx.Logs = append(evalCtx.Logs, &monitor.ResultLogEntry{
  412. Message: fmt.Sprintf("Condition[%d]: Query", c.Index),
  413. Data: data,
  414. })
  415. }
  416. ds, err := datasource.GetDefaultSource(c.Query.Model.Database)
  417. if err != nil {
  418. return nil, errors.Wrap(err, "GetDefaultDataSource")
  419. }
  420. resp, err := c.HandleRequest(evalCtx.Ctx, ds, req)
  421. if err != nil {
  422. if err == context.DeadlineExceeded {
  423. return nil, errors.Error("Alert execution exceeded the timeout")
  424. }
  425. return nil, errors.Wrap(err, "tsdb.HandleRequest() error")
  426. }
  427. for _, v := range resp.Results {
  428. if v.Error != nil {
  429. return nil, errors.Wrap(err, "tsdb.HandleResult() response")
  430. }
  431. result = append(result, v.Series...)
  432. metas = append(metas, v.Meta)
  433. queryResultData := map[string]interface{}{}
  434. if evalCtx.IsTestRun {
  435. queryResultData["series"] = v.Series
  436. }
  437. if evalCtx.IsDebug {
  438. queryResultData["meta"] = v.Meta
  439. }
  440. if evalCtx.IsTestRun || evalCtx.IsDebug {
  441. evalCtx.Logs = append(evalCtx.Logs, &monitor.ResultLogEntry{
  442. Message: fmt.Sprintf("Condition[%d]: Query Result", c.Index),
  443. Data: queryResultData,
  444. })
  445. }
  446. }
  447. return &queryResult{
  448. series: result,
  449. metas: metas,
  450. }, nil
  451. }
  452. func (c *QueryCondition) getRequestForAlertRule(timeRange *tsdb.TimeRange, debug bool) *tsdb.TsdbQuery {
  453. ds, _ := datasource.GetDefaultSource(c.Query.Model.Database)
  454. req := &tsdb.TsdbQuery{
  455. TimeRange: timeRange,
  456. Queries: []*tsdb.Query{
  457. {
  458. RefId: "A",
  459. MetricQuery: c.Query.Model,
  460. DataSource: *ds,
  461. },
  462. },
  463. Debug: debug,
  464. }
  465. return req
  466. }
  467. func newQueryCondition(model *monitor.AlertCondition, index int) (*QueryCondition, error) {
  468. cond := new(QueryCondition)
  469. cond.Index = index
  470. cond.HandleRequest = tsdb.HandleRequest
  471. q := model.Query
  472. cond.Query.Model = q.Model
  473. cond.Query.From = q.From
  474. cond.Query.To = q.To
  475. if err := validators.ValidateFromValue(cond.Query.From); err != nil {
  476. return nil, errors.Wrapf(err, "from value %q", cond.Query.From)
  477. }
  478. if err := validators.ValidateToValue(cond.Query.To); err != nil {
  479. return nil, errors.Wrapf(err, "to value %q", cond.Query.To)
  480. }
  481. //reducer := model.Reducer
  482. //cond.Reducer = newSimpleReducer(reducer.Type)
  483. reducer, err := NewAlertReducer(&model.Reducer)
  484. if err != nil {
  485. return nil, fmt.Errorf("error in condition %v: %v", index, err)
  486. }
  487. cond.Reducer = reducer
  488. cond.ReducerOrder = model.ReducerOrder
  489. evaluator, err := NewAlertEvaluator(&model.Evaluator)
  490. if err != nil {
  491. return nil, fmt.Errorf("error in condition %v: %v", index, err)
  492. }
  493. cond.Evaluator = evaluator
  494. operator := model.Operator
  495. if operator == "" {
  496. operator = "and"
  497. }
  498. cond.Operator = operator
  499. cond.checkGroupByField()
  500. cond.setResType()
  501. return cond, nil
  502. }
  503. func (c *QueryCondition) checkGroupByField() {
  504. metricMeasurement, _ := models.MetricMeasurementManager.GetCache().Get(c.Query.Model.Measurement)
  505. if metricMeasurement == nil {
  506. return
  507. }
  508. for i, group := range c.Query.Model.GroupBy {
  509. if group.Params[0] == "*" {
  510. tagId := monitor.GetMeasurementTagIdKeyByResType(metricMeasurement.ResType)
  511. if tagId == "" {
  512. tagId = "*"
  513. }
  514. c.Query.Model.GroupBy[i].Params = []string{tagId}
  515. }
  516. }
  517. }
  518. func (c *QueryCondition) setResType() {
  519. metricMeasurement, _ := models.MetricMeasurementManager.GetCache().Get(c.Query.Model.Measurement)
  520. if metricMeasurement != nil {
  521. c.ResType = metricMeasurement.ResType
  522. }
  523. var resType = monitor.METRIC_RES_TYPE_HOST
  524. if len(c.Query.Model.GroupBy) == 0 {
  525. return
  526. }
  527. // NOTE: shouldn't set ResType when tenant_id and domain_id within GroupBy
  528. /* if len(resType) != 0 && c.Query.Model.GroupBy[0].Params[0] != monitor.
  529. MEASUREMENT_TAG_ID[resType] {
  530. for _, groupBy := range c.Query.Model.GroupBy {
  531. tag := groupBy.Params[0]
  532. if tag == "tenant_id" {
  533. resType = monitor.METRIC_RES_TYPE_TENANT
  534. break
  535. }
  536. if tag == "domain_id" {
  537. resType = monitor.METRIC_RES_TYPE_DOMAIN
  538. break
  539. }
  540. }
  541. } */
  542. if c.Query.Model.Database == monitor.METRIC_DATABASE_TELE {
  543. if c.ResType == "" {
  544. c.ResType = resType
  545. }
  546. }
  547. }
  548. func (c *QueryCondition) GetQueryResources(s *mcclient.ClientSession, scope string, showDetails bool) ([]jsonutils.JSONObject, error) {
  549. allRes, err := c.getOnecloudResources(s, scope, showDetails)
  550. if err != nil {
  551. return nil, errors.Wrap(err, "getOnecloudResources error")
  552. }
  553. allRes = c.filterAllResources(allRes)
  554. return allRes, nil
  555. }
  556. func (c *QueryCondition) getOnecloudResources(s *mcclient.ClientSession, scope string, showDetails bool) ([]jsonutils.JSONObject, error) {
  557. query := jsonutils.NewDict()
  558. queryStatus := []string{"running", "ready"}
  559. // query.Add(jsonutils.NewString("true"), "admin")
  560. //if len(c.Query.Model.Tags) != 0 {
  561. // query, err = c.convertTagsQuery(evalContext, query)
  562. // if err != nil {
  563. // return nil, errors.Wrap(err, "NoDataQueryCondition convertTagsQuery error")
  564. // }
  565. //}
  566. var (
  567. err error
  568. manager modulebase.Manager
  569. allResources = make([]jsonutils.JSONObject, 0)
  570. )
  571. switch c.ResType {
  572. case monitor.METRIC_RES_TYPE_HOST:
  573. // models.SetQueryHostType(query)
  574. queryStatus = append(queryStatus, "unknown")
  575. query.Set("filter.0", jsonutils.NewString(fmt.Sprintf("host_type.notequals('%s')", compute.HOST_TYPE_BAREMETAL)))
  576. query.Set("enabled", jsonutils.NewInt(1))
  577. manager = &mc_mds.Hosts
  578. case monitor.METRIC_RES_TYPE_GUEST:
  579. manager = &mc_mds.Servers
  580. case monitor.METRIC_RES_TYPE_AGENT:
  581. manager = &mc_mds.Servers
  582. case monitor.METRIC_RES_TYPE_RDS:
  583. manager = &mc_mds.DBInstance
  584. case monitor.METRIC_RES_TYPE_REDIS:
  585. manager = &mc_mds.ElasticCache
  586. case monitor.METRIC_RES_TYPE_OSS:
  587. manager = &mc_mds.Buckets
  588. case monitor.METRIC_RES_TYPE_CLOUDACCOUNT:
  589. query.Remove("status")
  590. query.Add(jsonutils.NewBool(true), "enabled")
  591. manager = &mc_mds.Cloudaccounts
  592. case monitor.METRIC_RES_TYPE_TENANT:
  593. manager = &identity.Projects
  594. case monitor.METRIC_RES_TYPE_DOMAIN:
  595. manager = &identity.Domains
  596. case monitor.METRIC_RES_TYPE_STORAGE:
  597. query.Remove("status")
  598. manager = &mc_mds.Storages
  599. default:
  600. query := jsonutils.NewDict()
  601. query.Set("brand", jsonutils.NewString(hostconsts.TELEGRAF_TAG_ONECLOUD_BRAND))
  602. models.SetQueryHostType(query)
  603. manager = &mc_mds.Hosts
  604. }
  605. query.Add(jsonutils.NewStringArray(queryStatus), "status")
  606. allResources, err = ListAllResources(s, manager, query, scope, showDetails)
  607. if err != nil {
  608. return nil, errors.Wrapf(err, "ListAllResources for %s with query %s, scope: %s, showDetails: %v", manager.GetKeyword(), query, scope, showDetails)
  609. }
  610. return allResources, nil
  611. }
  612. func ListAllResources(s *mcclient.ClientSession, manager modulebase.Manager, params *jsonutils.JSONDict, scope string, showDetails bool) ([]jsonutils.JSONObject, error) {
  613. if params == nil {
  614. params = jsonutils.NewDict()
  615. }
  616. if s.GetToken().HasSystemAdminPrivilege() {
  617. params.Add(jsonutils.NewString("system"), "scope")
  618. }
  619. if scope != "" {
  620. params.Add(jsonutils.NewString(scope), "scope")
  621. }
  622. params.Add(jsonutils.NewInt(int64(options.Options.APIListBatchSize)), "limit")
  623. params.Add(jsonutils.NewBool(showDetails), "details")
  624. var count int
  625. objs := make([]jsonutils.JSONObject, 0)
  626. for {
  627. params.Set("offset", jsonutils.NewInt(int64(count)))
  628. result, err := manager.List(s, params)
  629. if err != nil {
  630. return nil, errors.Wrapf(err, "list %s resources with params %s", manager.KeyString(), params.String())
  631. }
  632. objs = append(objs, result.Data...)
  633. total := result.Total
  634. count = count + len(result.Data)
  635. if count >= total {
  636. break
  637. }
  638. }
  639. return objs, nil
  640. }
  641. func (c *QueryCondition) filterAllResources(resources []jsonutils.JSONObject) []jsonutils.JSONObject {
  642. if len(c.Query.Model.Tags) == 0 {
  643. return resources
  644. }
  645. filterIdMap := make(map[string]jsonutils.JSONObject)
  646. filterQuery := c.getFilterQuery()
  647. intKey := make([]int, 0)
  648. if len(filterQuery) != 0 {
  649. for key, _ := range filterQuery {
  650. intKey = append(intKey, key)
  651. }
  652. sort.Ints(intKey)
  653. minKey := intKey[0]
  654. if minKey != 0 {
  655. filterQuery[0] = minKey - 1
  656. }
  657. } else {
  658. filterQuery[0] = len(c.Query.Model.Tags) - 1
  659. }
  660. for start, end := range filterQuery {
  661. filterResources := c.getFilterResources(start, end, resources)
  662. filterIdMap = c.fillFilterRes(filterResources, filterIdMap)
  663. }
  664. filterRes := make([]jsonutils.JSONObject, 0)
  665. for _, obj := range filterIdMap {
  666. filterRes = append(filterRes, obj)
  667. }
  668. return filterRes
  669. }
  670. func (c *QueryCondition) getFilterQuery() map[int]int {
  671. length := len(c.Query.Model.Tags)
  672. tagIndexMap := make(map[int]int)
  673. for i := 0; i < length; i++ {
  674. if c.Query.Model.Tags[i].Condition == "OR" {
  675. andIndex := c.getTheAndOfConditionor(i + 1)
  676. if andIndex == i+1 {
  677. tagIndexMap[i] = i
  678. continue
  679. }
  680. if andIndex == length {
  681. for j := i; j < length; j++ {
  682. tagIndexMap[j] = j
  683. }
  684. break
  685. }
  686. tagIndexMap[i] = andIndex
  687. i = andIndex
  688. }
  689. }
  690. return tagIndexMap
  691. }
  692. func (c *QueryCondition) getFilterResources(start int, end int,
  693. resources []jsonutils.JSONObject) []jsonutils.JSONObject {
  694. relationMap := c.getTagKeyRelationMap()
  695. tmp := resources
  696. for i := start; i <= end; i++ {
  697. tag := c.Query.Model.Tags[i]
  698. if tag.Key == hostconsts.TELEGRAF_TAG_KEY_RES_TYPE {
  699. continue
  700. }
  701. relationKey := relationMap[tag.Key]
  702. if len(relationKey) == 0 {
  703. continue
  704. }
  705. filterObj := make([]jsonutils.JSONObject, 0)
  706. for _, res := range tmp {
  707. val, _ := res.GetString(relationKey)
  708. op := c.Query.Model.Tags[i].Operator
  709. if op == "=" || len(op) == 0 {
  710. if val == c.Query.Model.Tags[i].Value {
  711. filterObj = append(filterObj, res)
  712. }
  713. }
  714. if c.Query.Model.Tags[i].Operator == "!=" {
  715. if val != c.Query.Model.Tags[i].Value {
  716. filterObj = append(filterObj, res)
  717. }
  718. }
  719. }
  720. tmp = filterObj
  721. if len(tmp) == 0 {
  722. return tmp
  723. }
  724. }
  725. return tmp
  726. }
  727. func (c *QueryCondition) fillFilterRes(filterRes []jsonutils.JSONObject,
  728. filterIdMap map[string]jsonutils.JSONObject) map[string]jsonutils.JSONObject {
  729. for _, res := range filterRes {
  730. id, _ := res.GetString("id")
  731. if _, ok := filterIdMap[id]; !ok {
  732. filterIdMap[id] = res
  733. }
  734. }
  735. return filterIdMap
  736. }
  737. func (c *QueryCondition) getTheAndOfConditionor(start int) int {
  738. for i := start; i < len(c.Query.Model.Tags); i++ {
  739. if c.Query.Model.Tags[i].Condition != "AND" {
  740. return i
  741. }
  742. }
  743. return len(c.Query.Model.Tags)
  744. }
  745. func (c *QueryCondition) getTagKeyRelationMap() map[string]string {
  746. relationMap := make(map[string]string)
  747. switch c.ResType {
  748. case monitor.METRIC_RES_TYPE_HOST:
  749. relationMap = monitor.HostTags
  750. case monitor.METRIC_RES_TYPE_GUEST:
  751. relationMap = monitor.ServerTags
  752. case monitor.METRIC_RES_TYPE_RDS:
  753. relationMap = monitor.RdsTags
  754. case monitor.METRIC_RES_TYPE_REDIS:
  755. relationMap = monitor.RedisTags
  756. case monitor.METRIC_RES_TYPE_OSS:
  757. relationMap = monitor.OssTags
  758. case monitor.METRIC_RES_TYPE_CLOUDACCOUNT:
  759. relationMap = monitor.CloudAccountTags
  760. case monitor.METRIC_RES_TYPE_TENANT:
  761. relationMap = monitor.TenantTags
  762. case monitor.METRIC_RES_TYPE_DOMAIN:
  763. relationMap = monitor.DomainTags
  764. case monitor.METRIC_RES_TYPE_STORAGE:
  765. relationMap = monitor.StorageTags
  766. case monitor.METRIC_RES_TYPE_AGENT:
  767. relationMap = monitor.ServerTags
  768. default:
  769. relationMap = monitor.HostTags
  770. }
  771. return relationMap
  772. }