hostpinger.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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 hostpinger
  15. import (
  16. "context"
  17. "time"
  18. "github.com/shirou/gopsutil/cpu"
  19. "github.com/shirou/gopsutil/mem"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/log"
  22. "yunion.io/x/pkg/errors"
  23. api "yunion.io/x/onecloud/pkg/apis/compute"
  24. "yunion.io/x/onecloud/pkg/hostman/guestman"
  25. "yunion.io/x/onecloud/pkg/hostman/hostutils"
  26. "yunion.io/x/onecloud/pkg/hostman/options"
  27. "yunion.io/x/onecloud/pkg/hostman/storageman"
  28. "yunion.io/x/onecloud/pkg/httperrors"
  29. "yunion.io/x/onecloud/pkg/mcclient"
  30. modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
  31. )
  32. type SHostPingTask struct {
  33. interval int // second
  34. running bool
  35. host hostutils.IHost
  36. // masterHostStorages for shared storages
  37. masterHostStorages []string
  38. lastStatAt time.Time
  39. }
  40. type SEndpoint struct {
  41. Id string `json:"id"`
  42. Interface string `json:"interface"`
  43. Region string `json:"region"`
  44. Region_id string `json:"region_id"`
  45. Url string `json:"url"`
  46. Name string `json:"name"`
  47. }
  48. type SCatalog struct {
  49. Id string `json:"id"`
  50. Name string `json:"name"`
  51. Type string `json:"type"`
  52. Endpoints []SEndpoint `json:"endpoint"`
  53. }
  54. func NewCatalog() *SCatalog {
  55. return &SCatalog{
  56. Endpoints: make([]SEndpoint, 0),
  57. }
  58. }
  59. func NewHostPingTask(interval int, host hostutils.IHost) *SHostPingTask {
  60. if interval <= 0 {
  61. return nil
  62. }
  63. return &SHostPingTask{
  64. interval: interval,
  65. running: true,
  66. host: host,
  67. }
  68. }
  69. func (p *SHostPingTask) Start() {
  70. log.Infof("Start host pinger ...")
  71. var (
  72. div = 1
  73. hostId = p.host.GetHostId()
  74. err error
  75. )
  76. for {
  77. if !p.running {
  78. return
  79. }
  80. if err = p.ping(div, hostId); err != nil {
  81. log.Errorf("host ping failed %s", err)
  82. div = 3
  83. } else {
  84. div = 1
  85. }
  86. time.Sleep(time.Duration(p.interval/div) * time.Second)
  87. }
  88. }
  89. func (p *SHostPingTask) payload() api.SHostPingInput {
  90. data := api.SHostPingInput{}
  91. now := time.Now()
  92. if !p.lastStatAt.IsZero() && now.Before(p.lastStatAt.Add(time.Duration(options.HostOptions.SyncStorageInfoDurationSecond)*time.Second)) {
  93. return data
  94. }
  95. p.lastStatAt = now
  96. data = storageman.GatherHostStorageStats(p.masterHostStorages)
  97. data.WithData = true
  98. data.QgaRunningGuestIds = guestman.GetGuestManager().GetQgaRunningGuests()
  99. info, err := mem.VirtualMemory()
  100. if err != nil {
  101. return data
  102. }
  103. memTotal := int(info.Total / 1024 / 1024)
  104. memFree := int(info.Available / 1024 / 1024)
  105. memUsed := memTotal - memFree
  106. data.MemoryUsedMb = memUsed
  107. cpuUsage, err := cpu.Percent(time.Second, false)
  108. if err != nil {
  109. return data
  110. }
  111. if len(cpuUsage) > 0 {
  112. data.CpuUsagePercent = cpuUsage[0]
  113. }
  114. return data
  115. }
  116. func (p *SHostPingTask) ping(div int, hostId string) error {
  117. // log.Debugf("ping region at %d...", div)
  118. res, err := modules.Hosts.PerformAction(hostutils.GetComputeSession(context.Background()),
  119. hostId, "ping", jsonutils.Marshal(p.payload()))
  120. if err != nil {
  121. if errors.Cause(err) == httperrors.ErrResourceNotFound {
  122. log.Errorf("host seemd removed from region ...")
  123. return nil
  124. } else {
  125. return errors.Wrap(err, "ping")
  126. }
  127. } else {
  128. // name, err := res.GetString("name")
  129. // if err != nil {
  130. // Instance().setHostname(name)
  131. // }
  132. if res.Contains("master_host_storages") {
  133. storages := make([]string, 0)
  134. res.Unmarshal(&storages, "master_host_storages")
  135. p.masterHostStorages = storages
  136. }
  137. catalog, err := res.Get("catalog")
  138. if err == nil {
  139. cl := make(mcclient.KeystoneServiceCatalogV3, 0)
  140. err = catalog.Unmarshal(&cl)
  141. if err != nil {
  142. log.Errorln(err)
  143. return nil
  144. }
  145. p.host.OnCatalogChanged(cl)
  146. } else {
  147. log.Errorf("get catalog from res %s: %v", res.String(), err)
  148. }
  149. if res.Contains("host_files") {
  150. hostfiles := make([]api.SHostFile, 0)
  151. res.Unmarshal(&hostfiles, "host_files")
  152. err := p.host.OnHostFilesChanged(hostfiles)
  153. if err != nil {
  154. log.Errorf("on host files changed failed %s", err)
  155. }
  156. }
  157. }
  158. return nil
  159. }
  160. func (p *SHostPingTask) Stop() {
  161. if p.running {
  162. p.running = false
  163. }
  164. }