migration_alert.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  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 monitor
  15. import (
  16. "fmt"
  17. "strings"
  18. "sync"
  19. "time"
  20. "yunion.io/x/jsonutils"
  21. )
  22. func init() {
  23. for _, drv := range []IMigrationAlertMetric{
  24. newMMemAailable(),
  25. newMCPUUsageActive(),
  26. } {
  27. GetMigrationAlertMetricDrivers().register(drv)
  28. }
  29. }
  30. var (
  31. migMetricDrivers *MigrationMetricDrivers
  32. )
  33. func GetMigrationAlertMetricDrivers() *MigrationMetricDrivers {
  34. if migMetricDrivers == nil {
  35. migMetricDrivers = newMigrationMetricDrivers()
  36. }
  37. return migMetricDrivers
  38. }
  39. type MigrationMetricDrivers struct {
  40. *sync.Map
  41. }
  42. func newMigrationMetricDrivers() *MigrationMetricDrivers {
  43. return &MigrationMetricDrivers{
  44. Map: new(sync.Map),
  45. }
  46. }
  47. func (d *MigrationMetricDrivers) register(di IMigrationAlertMetric) *MigrationMetricDrivers {
  48. d.Store(di.GetType(), di)
  49. return d
  50. }
  51. func (d *MigrationMetricDrivers) Get(t MigrationAlertMetricType) (IMigrationAlertMetric, error) {
  52. obj, ok := d.Load(t)
  53. if !ok {
  54. return nil, fmt.Errorf("driver type %q not found", t)
  55. }
  56. return obj.(IMigrationAlertMetric), nil
  57. }
  58. type MigrationAlertMetricType string
  59. const (
  60. MigrationAlertMetricTypeCPUUsageActive = "cpu.usage_active"
  61. MigrationAlertMetricTypeMemAvailable = "mem.available"
  62. )
  63. type MetricQueryFields struct {
  64. ResourceType MigrationAlertResourceType `json:"resource_type"`
  65. Database string `json:"database"`
  66. Measurement string `json:"measurement"`
  67. Field string `json:"field"`
  68. Comparator string `json:"comparator"`
  69. }
  70. type IMigrationAlertMetric interface {
  71. GetType() MigrationAlertMetricType
  72. GetQueryFields() *MetricQueryFields
  73. }
  74. type mMemAvailable struct{}
  75. func newMMemAailable() IMigrationAlertMetric {
  76. return new(mMemAvailable)
  77. }
  78. func (_ mMemAvailable) GetType() MigrationAlertMetricType {
  79. return MigrationAlertMetricTypeMemAvailable
  80. }
  81. func (_ mMemAvailable) GetQueryFields() *MetricQueryFields {
  82. return &MetricQueryFields{
  83. ResourceType: MigrationAlertResourceTypeHost,
  84. Database: METRIC_DATABASE_TELE,
  85. Measurement: "mem",
  86. Field: "available",
  87. Comparator: ConditionLessThan, // <
  88. }
  89. }
  90. type mCPUUsageActive struct{}
  91. func newMCPUUsageActive() IMigrationAlertMetric {
  92. return new(mCPUUsageActive)
  93. }
  94. func (_ mCPUUsageActive) GetType() MigrationAlertMetricType {
  95. return MigrationAlertMetricTypeCPUUsageActive
  96. }
  97. func (_ mCPUUsageActive) GetQueryFields() *MetricQueryFields {
  98. return &MetricQueryFields{
  99. ResourceType: MigrationAlertResourceTypeHost,
  100. Database: METRIC_DATABASE_TELE,
  101. Measurement: "cpu",
  102. Field: "usage_active",
  103. Comparator: ConditionGreaterThan, // >
  104. }
  105. }
  106. func IsValidMigrationAlertMetricType(t MigrationAlertMetricType) error {
  107. _, err := GetMigrationAlertMetricDrivers().Get(t)
  108. return err
  109. }
  110. type MigrationAlertResourceType string
  111. const (
  112. MigrationAlertResourceTypeHost = "host"
  113. )
  114. type MigrationAlertCreateInput struct {
  115. AlertCreateInput
  116. // Threshold is the value to trigger migration
  117. Threshold float64 `json:"threshold"`
  118. // Period of querying metrics
  119. Period string `json:"period"`
  120. // MetricType is supported metric type by auto migration
  121. MetricType MigrationAlertMetricType `json:"metric_type"`
  122. // MigrationAlertSettings contain migration configuration
  123. MigrationSettings *MigrationAlertSettings `json:"migration_settings"`
  124. }
  125. func (m MigrationAlertCreateInput) GetMetricDriver() IMigrationAlertMetric {
  126. d, err := GetMigrationAlertMetricDrivers().Get(m.MetricType)
  127. if err != nil {
  128. panic(err)
  129. }
  130. return d
  131. }
  132. func (m MigrationAlertCreateInput) ToAlertCreateInput() *AlertCreateInput {
  133. freq, _ := time.ParseDuration(m.Period)
  134. ret := new(AlertCreateInput)
  135. ret.Name = m.Name
  136. ret.Frequency = int64(freq / time.Second)
  137. ret.Level = m.Level
  138. ret.CustomizeConfig = jsonutils.Marshal(m.MigrationSettings)
  139. drv := m.GetMetricDriver()
  140. fs := drv.GetQueryFields()
  141. ret.Settings = AlertSetting{
  142. Conditions: []AlertCondition{
  143. {
  144. Type: "query",
  145. Operator: "and",
  146. Query: AlertQuery{
  147. Model: m.getQuery(fs),
  148. From: m.Period,
  149. To: "now",
  150. },
  151. Evaluator: m.GetEvaluator(fs),
  152. Reducer: Condition{Type: "avg"},
  153. },
  154. },
  155. }
  156. return ret
  157. }
  158. func (m MigrationAlertCreateInput) GetEvaluator(fs *MetricQueryFields) Condition {
  159. return Condition{
  160. Type: fs.Comparator,
  161. Operators: nil,
  162. Params: []float64{m.Threshold},
  163. }
  164. }
  165. func (m MigrationAlertCreateInput) getQuery(fs *MetricQueryFields) MetricQuery {
  166. sels := make([]MetricQuerySelect, 0)
  167. sels = append(sels, NewMetricQuerySelect(
  168. MetricQueryPart{
  169. Type: "field",
  170. Params: []string{fs.Field},
  171. },
  172. MetricQueryPart{
  173. Type: "mean",
  174. Params: nil,
  175. },
  176. ))
  177. q := MetricQuery{
  178. Selects: sels,
  179. GroupBy: []MetricQueryPart{
  180. {
  181. Type: "field",
  182. Params: []string{"*"},
  183. },
  184. {
  185. Type: "fill",
  186. Params: []string{"null"},
  187. },
  188. },
  189. Measurement: fs.Measurement,
  190. Database: fs.Database,
  191. }
  192. q.Tags = []MetricQueryTag{
  193. {
  194. Condition: "and",
  195. Key: "res_type",
  196. Operator: "=",
  197. Value: "host",
  198. },
  199. }
  200. if m.MigrationSettings != nil {
  201. if m.MigrationSettings.Source != nil && len(m.MigrationSettings.Source.HostIds) > 0 {
  202. ids := strings.Join(m.MigrationSettings.Source.HostIds, "|")
  203. q.Tags = append(q.Tags, MetricQueryTag{
  204. Key: "host_id",
  205. Operator: "=~",
  206. Value: fmt.Sprintf("/%s/", ids),
  207. })
  208. }
  209. }
  210. return q
  211. }
  212. type MigrationAlertSettings struct {
  213. Source *MigrationAlertSettingsSource `json:"source"`
  214. Target *MigrationAlertSettingsTarget `json:"target"`
  215. }
  216. type MigrationAlertSettingsSource struct {
  217. GuestIds []string `json:"guest_ids"`
  218. HostIds []string `json:"host_ids"`
  219. }
  220. type MigrationAlertSettingsTarget struct {
  221. HostIds []string `json:"host_ids"`
  222. }
  223. type MigrationAlertListInput struct {
  224. AlertListInput
  225. MetricType string `json:"metric_type"`
  226. }