You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

trigger.go 4.6 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. Copyright 2021 The KubeEdge Authors.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package trigger
  14. import (
  15. "fmt"
  16. "math"
  17. "reflect"
  18. "strconv"
  19. "strings"
  20. "time"
  21. )
  22. type Base interface {
  23. Trigger(stats map[string]interface{}) bool
  24. }
  25. type BinaryTrigger struct {
  26. Operator string
  27. Metric string
  28. Threshold float64
  29. }
  30. func convertFloat(v interface{}) (float64, error) {
  31. var realValue float64
  32. var err error
  33. switch v := v.(type) {
  34. case int:
  35. realValue = float64(v)
  36. case float32:
  37. realValue = float64(v)
  38. case float64:
  39. realValue = v
  40. case string:
  41. realValue, err = strconv.ParseFloat(v, 64)
  42. }
  43. return realValue, err
  44. }
  45. func (bt *BinaryTrigger) Trigger(stats map[string]interface{}) bool {
  46. var value interface{}
  47. var ok bool
  48. left := strings.Index(bt.Metric, "[")
  49. if left == -1 {
  50. value, ok = stats[bt.Metric]
  51. if !ok {
  52. return false
  53. }
  54. } else {
  55. // e.g. metric = precisions[3]
  56. right := strings.LastIndex(bt.Metric, "]")
  57. metric := strings.TrimSpace(bt.Metric[:left])
  58. topValue, ok := stats[metric]
  59. if !ok {
  60. return false
  61. }
  62. // only support the integer index
  63. subMetric := bt.Metric[left+1 : right]
  64. idx, err := strconv.Atoi(subMetric)
  65. if err != nil {
  66. return false
  67. }
  68. s := reflect.ValueOf(topValue)
  69. switch s.Kind() {
  70. case reflect.Slice, reflect.Array:
  71. default:
  72. return false
  73. }
  74. if !ok {
  75. return false
  76. }
  77. if idx >= s.Len() {
  78. return false
  79. }
  80. value = s.Index(idx).Interface()
  81. }
  82. realValue, err := convertFloat(value)
  83. if err != nil {
  84. return false
  85. }
  86. isEqual := math.Abs(realValue-bt.Threshold) < 1e-6
  87. switch bt.Operator {
  88. case "gt", ">":
  89. return !isEqual && realValue > bt.Threshold
  90. case "ge", ">=":
  91. return isEqual || realValue >= bt.Threshold
  92. case "eq", "=", "==":
  93. return isEqual
  94. case "ne", "!=":
  95. return !isEqual
  96. case "le", "<=":
  97. return isEqual || realValue <= bt.Threshold
  98. case "lt", "<":
  99. return !isEqual && realValue < bt.Threshold
  100. default:
  101. return false
  102. }
  103. }
  104. type TimerRangeTrigger struct {
  105. Start string
  106. End string
  107. Type string
  108. }
  109. func (tt *TimerRangeTrigger) Trigger(stats map[string]interface{}) bool {
  110. now := time.Now()
  111. start := tt.Start
  112. end := tt.End
  113. // now only support the 'daily' type
  114. var format string
  115. switch tt.Type {
  116. case "daily":
  117. default:
  118. format = "15:04"
  119. }
  120. v := now.Format(format)
  121. if start > end {
  122. // for daily type: [23:00, 01:00]
  123. return start <= v || v <= end
  124. }
  125. // for daily type: [01:00, 02:00]
  126. return start <= v && v <= end
  127. }
  128. type AndTrigger struct {
  129. Triggers []Base
  130. }
  131. func (at *AndTrigger) Trigger(stats map[string]interface{}) bool {
  132. for _, t := range at.Triggers {
  133. if !t.Trigger(stats) {
  134. return false
  135. }
  136. }
  137. return true
  138. }
  139. func newAndTrigger(triggers ...Base) *AndTrigger {
  140. var valid []Base
  141. for _, t := range triggers {
  142. if t != nil {
  143. valid = append(valid, t)
  144. }
  145. }
  146. return &AndTrigger{
  147. Triggers: valid,
  148. }
  149. }
  150. func NewTrigger(trigger map[string]interface{}) (Base, error) {
  151. var err error
  152. checkPeriodSeconds, ok := trigger["checkPeriodSeconds"]
  153. if !ok {
  154. checkPeriodSeconds = 60
  155. }
  156. _ = checkPeriodSeconds
  157. condVal, ok := trigger["condition"]
  158. var conditionTrigger Base
  159. if ok {
  160. cond, ok := condVal.(map[string]interface{})
  161. if !ok {
  162. return nil, fmt.Errorf("invalid condition value:%v",
  163. condVal)
  164. }
  165. threshold, err := convertFloat(cond["threshold"])
  166. if err != nil {
  167. return nil, fmt.Errorf("invalid threshold value:%v", cond["threshold"])
  168. }
  169. conditionTrigger = &BinaryTrigger{
  170. Operator: cond["operator"].(string),
  171. Metric: cond["metric"].(string),
  172. Threshold: threshold,
  173. }
  174. }
  175. var timerTrigger Base
  176. _, ok = trigger["timer"]
  177. if ok {
  178. timer := make(map[string]string)
  179. switch t := trigger["timer"].(type) {
  180. case map[string]interface{}:
  181. for k, v := range t {
  182. timer[k] = v.(string)
  183. }
  184. case map[string]string:
  185. for k, v := range t {
  186. timer[k] = v
  187. }
  188. default:
  189. err = fmt.Errorf("invalid timer %v", trigger["timer"])
  190. }
  191. timerTrigger = &TimerRangeTrigger{
  192. Start: timer["start"],
  193. End: timer["end"],
  194. Type: timer["type"],
  195. }
  196. }
  197. if err != nil {
  198. return nil, err
  199. }
  200. return newAndTrigger(timerTrigger, conditionTrigger), err
  201. }