cronjobs.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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 baremetal
  15. import (
  16. "context"
  17. "time"
  18. "yunion.io/x/jsonutils"
  19. "yunion.io/x/log"
  20. "yunion.io/x/pkg/errors"
  21. "yunion.io/x/pkg/util/timeutils"
  22. api "yunion.io/x/onecloud/pkg/apis/compute"
  23. o "yunion.io/x/onecloud/pkg/baremetal/options"
  24. "yunion.io/x/onecloud/pkg/cloudcommon/consts"
  25. "yunion.io/x/onecloud/pkg/cloudcommon/tsdb"
  26. "yunion.io/x/onecloud/pkg/mcclient"
  27. "yunion.io/x/onecloud/pkg/mcclient/auth"
  28. modules "yunion.io/x/onecloud/pkg/mcclient/modules/logger"
  29. "yunion.io/x/onecloud/pkg/util/influxdb"
  30. "yunion.io/x/onecloud/pkg/util/redfish"
  31. )
  32. type IBaremetalCronJob interface {
  33. Name() string
  34. NeedsToRun(now time.Time) bool
  35. StartRun()
  36. Do(ctx context.Context, now time.Time) error
  37. StopRun()
  38. }
  39. func DoCronJobs(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
  40. if isStart {
  41. return
  42. }
  43. for _, bm := range GetBaremetalManager().GetBaremetals() {
  44. if bm.GetTask() == nil {
  45. bm.doCronJobs(ctx)
  46. }
  47. }
  48. }
  49. type SBaseBaremetalCronJob struct {
  50. lastTime time.Time
  51. running bool
  52. interval time.Duration
  53. baremetal *SBaremetalInstance
  54. }
  55. func (job *SBaseBaremetalCronJob) NeedsToRun(now time.Time) bool {
  56. if (job.lastTime.IsZero() || now.Sub(job.lastTime) > job.interval) && !job.running {
  57. return true
  58. }
  59. return false
  60. }
  61. func (job *SBaseBaremetalCronJob) StartRun() {
  62. job.running = true
  63. }
  64. func (job *SBaseBaremetalCronJob) StopRun() {
  65. job.running = false
  66. }
  67. type SStatusProbeJob struct {
  68. SBaseBaremetalCronJob
  69. }
  70. func NewStatusProbeJob(baremetal *SBaremetalInstance, interval time.Duration) IBaremetalCronJob {
  71. return &SStatusProbeJob{
  72. SBaseBaremetalCronJob: SBaseBaremetalCronJob{
  73. baremetal: baremetal,
  74. interval: interval,
  75. },
  76. }
  77. }
  78. func (job *SStatusProbeJob) Name() string {
  79. return "StatusProbeJob"
  80. }
  81. func (job *SStatusProbeJob) Do(ctx context.Context, now time.Time) error {
  82. if job.baremetal.IsHypervisorHost() {
  83. log.Debugf("baremetal %q is host, skipping status probe", job.baremetal.GetName())
  84. return nil
  85. }
  86. bStatus := job.baremetal.GetStatus()
  87. if bStatus == api.BAREMETAL_READY || bStatus == api.BAREMETAL_RUNNING || bStatus == api.BAREMETAL_UNKNOWN {
  88. ps, err := job.baremetal.GetPowerStatus()
  89. if err != nil {
  90. return errors.Wrap(err, "StatusProbeJob get power status")
  91. }
  92. job.lastTime = now
  93. pps := PowerStatusToBaremetalStatus(ps)
  94. if pps != bStatus {
  95. log.Debugf("Detected baremetal status change!")
  96. job.baremetal.SyncAllStatus(ctx, ps)
  97. return nil
  98. }
  99. }
  100. return nil
  101. }
  102. type SLogFetchJob struct {
  103. SBaseBaremetalCronJob
  104. }
  105. func NewLogFetchJob(baremetal *SBaremetalInstance, interval time.Duration) IBaremetalCronJob {
  106. return &SLogFetchJob{
  107. SBaseBaremetalCronJob: SBaseBaremetalCronJob{
  108. baremetal: baremetal,
  109. interval: interval,
  110. },
  111. }
  112. }
  113. func (job *SLogFetchJob) Name() string {
  114. return "LogFetchJob"
  115. }
  116. func eventToJson(e redfish.SEvent) *jsonutils.JSONDict {
  117. json := jsonutils.NewDict()
  118. json.Add(jsonutils.NewString(timeutils.IsoTime(e.Created)), "created")
  119. json.Add(jsonutils.NewString(e.EventId), "event_id")
  120. json.Add(jsonutils.NewString(e.Message), "message")
  121. json.Add(jsonutils.NewString(e.Severity), "severity")
  122. json.Add(jsonutils.NewString(e.Type), "type")
  123. return json
  124. }
  125. func fetchLogs(baremetal *SBaremetalInstance, ctx context.Context, logType string) error {
  126. params := jsonutils.NewDict()
  127. s := auth.GetAdminSession(ctx, consts.GetRegion())
  128. params.Add(jsonutils.NewInt(1), "limit")
  129. params.Add(jsonutils.NewString(baremetal.GetId()), "host_id")
  130. params.Add(jsonutils.NewString(logType), "type")
  131. result, err := modules.BaremetalEvents.List(s, params)
  132. if err != nil {
  133. return errors.Wrap(err, "modules.BaremetalEvents.List")
  134. }
  135. log.Debugf("%s", result.Data)
  136. var eventId string
  137. var since time.Time
  138. if len(result.Data) > 0 {
  139. since, _ = result.Data[0].GetTime("created")
  140. eventId, _ = result.Data[0].GetString("event_id")
  141. }
  142. offset := 0
  143. logs, err := baremetal.fetchLogs(ctx, logType, since)
  144. if err != nil {
  145. return errors.Wrap(err, "job.baremetal.FetchLogs")
  146. }
  147. if len(eventId) > 0 {
  148. // latset eventId
  149. for i := range logs {
  150. if logs[i].EventId == eventId {
  151. offset = i + 1
  152. break
  153. }
  154. }
  155. }
  156. for i := offset; i < len(logs); i += 1 {
  157. eventData := eventToJson(logs[i])
  158. eventData.Add(jsonutils.NewString(baremetal.GetId()), "host_id")
  159. eventData.Add(jsonutils.NewString(baremetal.GetName()), "host_name")
  160. eventData.Add(jsonutils.NewString(baremetal.GetIPMINicIPAddr()), "ipmi_ip")
  161. log.Debugf("%s", eventData)
  162. _, err := modules.BaremetalEvents.Create(s, eventData)
  163. if err != nil {
  164. return errors.Wrap(err, "modules.BaremetalEvents.Create")
  165. }
  166. }
  167. return nil
  168. }
  169. func (job *SLogFetchJob) Do(ctx context.Context, now time.Time) error {
  170. if !job.baremetal.isRedfishCapable() {
  171. return nil
  172. }
  173. err := fetchLogs(job.baremetal, ctx, redfish.EVENT_TYPE_SYSTEM)
  174. if err != nil {
  175. return errors.Wrap(err, "fetchLogs api.EVENT_TYPE_SYSTEM")
  176. }
  177. // no longer fetch management logs
  178. // err = fetchLogs(job.baremetal, ctx, redfish.EVENT_TYPE_MANAGER)
  179. // if err != nil {
  180. // return errors.Wrap(err, "fetchLogs api.EVENT_TYPE_MANAGER")
  181. // }
  182. job.lastTime = now
  183. return nil
  184. }
  185. type SSendMetricsJob struct {
  186. SBaseBaremetalCronJob
  187. }
  188. func NewSendMetricsJob(baremetal *SBaremetalInstance, interval time.Duration) IBaremetalCronJob {
  189. return &SSendMetricsJob{
  190. SBaseBaremetalCronJob: SBaseBaremetalCronJob{
  191. baremetal: baremetal,
  192. interval: interval,
  193. },
  194. }
  195. }
  196. func (job *SSendMetricsJob) Name() string {
  197. return "SendMetricsJob"
  198. }
  199. func (job *SSendMetricsJob) Do(ctx context.Context, now time.Time) error {
  200. s := auth.GetAdminSession(ctx, consts.GetRegion())
  201. src, err := tsdb.GetDefaultServiceSource(s, o.Options.SessionEndpointType)
  202. if err != nil {
  203. return errors.Wrap(err, "tsdb.GetDefaultServiceSource")
  204. }
  205. if len(src.URLs) == 0 {
  206. return nil
  207. }
  208. if !job.baremetal.isRedfishCapable() {
  209. return nil
  210. }
  211. powerMetrics, thermalMetrics, err := job.baremetal.fetchPowerThermalMetrics(ctx)
  212. if err != nil {
  213. return errors.Wrap(err, "fetchPowerThermalMetrics")
  214. }
  215. tags := job.baremetal.getTags()
  216. metrics := []influxdb.SMetricData{}
  217. if len(powerMetrics) > 0 {
  218. metrics = append(metrics, influxdb.SMetricData{
  219. Name: "power",
  220. Tags: tags,
  221. Metrics: powerMetrics,
  222. Timestamp: now,
  223. })
  224. }
  225. if len(thermalMetrics) > 0 {
  226. metrics = append(metrics, influxdb.SMetricData{
  227. Name: "thermal",
  228. Tags: tags,
  229. Metrics: thermalMetrics,
  230. Timestamp: now,
  231. })
  232. }
  233. err = influxdb.SendMetrics(src.URLs, "telegraf", metrics, false)
  234. if err != nil {
  235. return errors.Wrapf(err, "tsdb.SendMetrics %q", src.Type)
  236. }
  237. job.lastTime = now
  238. return nil
  239. }