loadbalancer_backendstatus.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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 models
  15. import (
  16. "context"
  17. "fmt"
  18. "yunion.io/x/jsonutils"
  19. "yunion.io/x/pkg/errors"
  20. "yunion.io/x/pkg/utils"
  21. api "yunion.io/x/onecloud/pkg/apis/compute"
  22. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  23. "yunion.io/x/onecloud/pkg/mcclient"
  24. "yunion.io/x/onecloud/pkg/util/influxdb"
  25. )
  26. func (lblis *SLoadbalancerListener) GetDetailsBackendStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  27. provider := lblis.GetCloudprovider()
  28. if provider != nil {
  29. return jsonutils.NewArray(), nil
  30. }
  31. if lblis.BackendGroupId == "" {
  32. return jsonutils.NewArray(), nil
  33. }
  34. lb, err := lblis.GetLoadbalancer()
  35. if err != nil {
  36. return nil, errors.Wrapf(err, "GetLoadbalancer")
  37. }
  38. var pxname string
  39. switch lblis.ListenerType {
  40. case api.LB_LISTENER_TYPE_TCP:
  41. pxname = fmt.Sprintf("backends_listener-%s", lblis.Id)
  42. case api.LB_LISTENER_TYPE_HTTP, api.LB_LISTENER_TYPE_HTTPS:
  43. pxname = fmt.Sprintf("backends_listener_default-%s", lblis.Id)
  44. }
  45. return lb.GetBackendGroupCheckStatus(ctx, userCred, pxname, lblis.BackendGroupId)
  46. }
  47. func (lbr *SLoadbalancerListenerRule) GetDetailsBackendStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  48. provider := lbr.GetCloudprovider()
  49. if provider != nil {
  50. return jsonutils.NewArray(), nil
  51. }
  52. lblis, err := lbr.GetLoadbalancerListener()
  53. if err != nil {
  54. return nil, err
  55. }
  56. lb, err := lblis.GetLoadbalancer()
  57. if err != nil {
  58. return nil, errors.Wrapf(err, "GetLoadbalancer")
  59. }
  60. pxname := fmt.Sprintf("backends_rule-%s", lbr.Id)
  61. return lb.GetBackendGroupCheckStatus(ctx, userCred, pxname, lbr.BackendGroupId)
  62. }
  63. func (lb *SLoadbalancer) GetInfluxdbByLbId() (*influxdb.SInfluxdb, string, error) {
  64. lbagents, err := LoadbalancerAgentManager.getByClusterId(lb.ClusterId)
  65. if err != nil {
  66. return nil, "", err
  67. }
  68. if len(lbagents) == 0 {
  69. return nil, "", errors.Wrapf(errors.ErrNotFound, "lbcluster %s has no agent", lb.ClusterId)
  70. }
  71. var (
  72. dbUrl string
  73. dbName string
  74. )
  75. for i := range lbagents {
  76. lbagent := &lbagents[i]
  77. params := lbagent.Params
  78. if params == nil {
  79. continue
  80. }
  81. paramsTelegraf := params.Telegraf
  82. if paramsTelegraf.InfluxDbOutputUrl != "" && paramsTelegraf.InfluxDbOutputName != "" {
  83. dbUrl = paramsTelegraf.InfluxDbOutputUrl
  84. dbName = paramsTelegraf.InfluxDbOutputName
  85. if lbagent.HaState == api.LB_HA_STATE_MASTER {
  86. // prefer the one on master
  87. break
  88. }
  89. }
  90. }
  91. if dbUrl == "" || dbName == "" {
  92. return nil, "", errors.Wrap(errors.ErrNotFound, "no lbagent has influxdb url or db name")
  93. }
  94. dbinst := influxdb.NewInfluxdb(dbUrl)
  95. return dbinst, dbName, nil
  96. }
  97. func (lb *SLoadbalancer) GetBackendGroupCheckStatus(ctx context.Context, userCred mcclient.TokenCredential, pxname string, groupId string) (*jsonutils.JSONArray, error) {
  98. var (
  99. backendJsons []jsonutils.JSONObject
  100. backendIds []string
  101. )
  102. {
  103. var err error
  104. q := LoadbalancerBackendManager.Query().Equals("backend_group_id", groupId)
  105. backendJsons, err = db.Query2List(LoadbalancerBackendManager, ctx, userCred, q, jsonutils.NewDict(), false)
  106. if err != nil {
  107. return nil, errors.Wrapf(err, "query backends of backend group %s", groupId)
  108. }
  109. if len(backendJsons) == 0 {
  110. return jsonutils.NewArray(), nil
  111. }
  112. for _, backendJson := range backendJsons {
  113. id, err := backendJson.GetString("id")
  114. if err != nil {
  115. return nil, errors.Wrap(err, "get backend id from json")
  116. }
  117. if id == "" {
  118. return nil, errors.Wrap(err, "get backend id from json: id empty")
  119. }
  120. backendIds = append(backendIds, id)
  121. }
  122. }
  123. dbinst, dbName, err := lb.GetInfluxdbByLbId()
  124. if err != nil {
  125. return nil, errors.Wrapf(err, "find influxdb for loadbalancer %s", lb.Id)
  126. }
  127. queryFmt := "select check_status, check_code from %s..haproxy where pxname = '%s' and svname =~ /........-....-....-....-............/ group by pxname, svname order by time desc limit 1"
  128. querySql := fmt.Sprintf(queryFmt, dbName, pxname)
  129. queryRes, err := dbinst.Query(querySql)
  130. if err != nil {
  131. return nil, errors.Wrap(err, "query influxdb")
  132. }
  133. if len(queryRes) != 1 {
  134. return nil, fmt.Errorf("query influxdb: expecting 1 set of results, got %d", len(queryRes))
  135. }
  136. type Tags struct {
  137. PxName string `json:"pxname"`
  138. SvName string `json:"svname"`
  139. }
  140. for _, resSeries := range queryRes[0] {
  141. if len(resSeries.Values) == 0 {
  142. continue
  143. }
  144. resColumns := resSeries.Values[0]
  145. if len(resColumns) != 3 {
  146. continue
  147. }
  148. tags := Tags{}
  149. if err := resSeries.Tags.Unmarshal(&tags); err != nil {
  150. return nil, errors.Wrap(err, "unmarshal tags in influxdb query result")
  151. }
  152. ok, i := utils.InStringArray(tags.SvName, backendIds)
  153. if !ok {
  154. continue
  155. }
  156. backendJson := backendJsons[i].(*jsonutils.JSONDict)
  157. for j, colName := range resSeries.Columns {
  158. colVal := resColumns[j]
  159. if colVal == nil {
  160. colVal = jsonutils.JSONNull
  161. }
  162. if colName == "time" {
  163. colName = "check_time"
  164. }
  165. backendJson.Set(colName, colVal)
  166. }
  167. }
  168. return jsonutils.NewArray(backendJsons...), nil
  169. }