usageservice.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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 misc
  15. import (
  16. "context"
  17. "fmt"
  18. "strings"
  19. "time"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/log"
  22. "yunion.io/x/pkg/errors"
  23. "yunion.io/x/onecloud/pkg/cloudcommon/tsdb"
  24. "yunion.io/x/onecloud/pkg/cloudmon/options"
  25. "yunion.io/x/onecloud/pkg/mcclient"
  26. "yunion.io/x/onecloud/pkg/mcclient/auth"
  27. "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
  28. "yunion.io/x/onecloud/pkg/mcclient/modules/image"
  29. "yunion.io/x/onecloud/pkg/util/influxdb"
  30. )
  31. var config map[string]string = map[string]string{
  32. "hypervisors": "host-type",
  33. "compute_engine_brands": "provider",
  34. }
  35. var measureMent string = "usage"
  36. func UsegReport(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
  37. err := func() error {
  38. dataList := make([]influxdb.SMetricData, 0)
  39. nowTime := time.Now()
  40. s := auth.GetAdminSession(ctx, options.Options.Region)
  41. //镜像使用量信息
  42. imageUsageFields, err := getImageUsageFields(s)
  43. if err != nil {
  44. return errors.Wrapf(err, "getImageUsageFields")
  45. }
  46. //查询到的Usage信息统一放置在metric中
  47. imageUsageFieldsDict := imageUsageFields.(*jsonutils.JSONDict)
  48. capabilitesQuery := jsonutils.NewDict()
  49. capabilitesQuery.Add(jsonutils.NewString("system"), "scope")
  50. capabilites, err := compute.Capabilities.List(s, capabilitesQuery)
  51. if err != nil {
  52. return errors.Wrapf(err, "Capabilities.List")
  53. }
  54. //通过capabilities中的信息遍历hypevisors和brands
  55. for i := 0; i < len(capabilites.Data); i++ {
  56. capabilitesObj := capabilites.Data[i]
  57. capDict, ok := capabilitesObj.(*jsonutils.JSONDict)
  58. if !ok {
  59. return errors.ErrClient
  60. }
  61. for _, capKey := range capDict.SortedKeys() {
  62. if _, ok := config[capKey]; ok {
  63. hypeOrBrandObj, _ := capDict.Get(capKey)
  64. if hypeOrBrandObj != nil {
  65. hypeOrBrandArr, _ := hypeOrBrandObj.(*jsonutils.JSONArray)
  66. for i := 0; i < len(hypeOrBrandArr.Value()); i++ {
  67. hypeOrBrand := hypeOrBrandArr.Value()[i].(*jsonutils.JSONString)
  68. dataList, err = packMetricList(s, dataList, imageUsageFieldsDict, config[capKey],
  69. hypeOrBrand.String(), nowTime)
  70. if err != nil {
  71. return err
  72. }
  73. }
  74. }
  75. }
  76. }
  77. }
  78. //查询host-type==""的情况,对应onecloud-控制面板-全部 要展示的内容
  79. dataList, err = packMetricList(s, dataList, imageUsageFieldsDict, "host-type", "", nowTime)
  80. //获取域/项目 虚拟机usage
  81. data, err := getDomainAndProjectServerUsage(s, nowTime)
  82. if err != nil {
  83. return errors.Wrap(err, "getDomainAndProjectServerUsage err")
  84. }
  85. dataList = append(dataList, data...)
  86. // 写入 influxdb 或者 VictoriaMetrics
  87. urls, err := tsdb.GetDefaultServiceSourceURLs(s, options.Options.SessionEndpointType)
  88. if err != nil {
  89. return errors.Wrap(err, "GetServiceURLs")
  90. }
  91. return influxdb.SendMetrics(urls, options.Options.InfluxDatabase, dataList, false)
  92. }()
  93. if err != nil {
  94. log.Errorf("report usage error: %v", err)
  95. }
  96. }
  97. // 根据capabilities中的hypevisors和brands中的对应属性,组装Metric
  98. func packMetricList(session *mcclient.ClientSession, dataList []influxdb.SMetricData,
  99. imageUsageFieldsDict *jsonutils.JSONDict, paramKey string,
  100. paramValue string, nowTime time.Time) (rtnList []influxdb.SMetricData, err error) {
  101. //query,sql信息,查询主机compute的使用信息
  102. query := jsonutils.NewDict()
  103. query.Add(jsonutils.NewString("system"), "scope")
  104. if paramValue != "" {
  105. if paramKey == "host-type" {
  106. if paramValue == "kvm" {
  107. query.Add(jsonutils.NewString("hypervisor"), paramKey)
  108. }
  109. query.Add(jsonutils.NewString(paramValue), paramKey)
  110. }
  111. query.Add(jsonutils.NewString(paramValue), paramKey)
  112. }
  113. metric := &influxdb.SMetricData{Name: measureMent, Timestamp: nowTime}
  114. //查询到的镜像的使用信息放到SMetricData中的metric
  115. metric, _ = jsonTometricData(imageUsageFieldsDict, metric, "metric")
  116. //compute主机使用量
  117. respObj, err := compute.Usages.GetGeneralUsage(session, query)
  118. if err != nil {
  119. return nil, err
  120. }
  121. respObjDict := respObj.(*jsonutils.JSONDict)
  122. //查询到的主机的使用信息放到SMetricData中的metric
  123. metric, _ = jsonTometricData(respObjDict, metric, "metric")
  124. if paramValue != "" {
  125. metric.Tags = append(metric.Tags, influxdb.SKeyValue{
  126. Key: paramKey, Value: paramValue,
  127. })
  128. } else {
  129. metric.Tags = append(metric.Tags, influxdb.SKeyValue{
  130. Key: paramKey, Value: "all",
  131. })
  132. }
  133. dataList = append(dataList, *metric)
  134. return dataList, nil
  135. }
  136. // 获得镜像使用量
  137. func getImageUsageFields(session *mcclient.ClientSession) (jsonutils.JSONObject, error) {
  138. respObj, e := (&image.ImageUsages).GetUsage(session, nil)
  139. if e != nil {
  140. return nil, e
  141. }
  142. respDict, ok := respObj.(*jsonutils.JSONDict)
  143. if !ok {
  144. return nil, jsonutils.ErrInvalidJsonDict
  145. }
  146. return respDict, nil
  147. }
  148. // 将JSONDict的信息放置到SMetricData中
  149. func jsonTometricData(obj *jsonutils.JSONDict, metric *influxdb.SMetricData,
  150. metricDataType string) (*influxdb.SMetricData, error) {
  151. objMap, err := obj.GetMap()
  152. if err != nil {
  153. return nil, errors.Wrap(err, "obj.GetMap")
  154. }
  155. tagPairs := make([]influxdb.SKeyValue, 0)
  156. metricPairs := make([]influxdb.SKeyValue, 0)
  157. for k, v := range objMap {
  158. val, _ := v.GetString()
  159. if metricDataType == "tag" {
  160. tagPairs = append(tagPairs, influxdb.SKeyValue{
  161. Key: k, Value: val,
  162. })
  163. } else if metricDataType == "metric" {
  164. metricPairs = append(metricPairs, influxdb.SKeyValue{
  165. Key: k, Value: val,
  166. })
  167. }
  168. }
  169. metric.Tags = append(metric.Tags, tagPairs...)
  170. metric.Metrics = append(metric.Metrics, metricPairs...)
  171. return metric, nil
  172. }
  173. type resourceUsage struct {
  174. Count string
  175. Id string
  176. Name string
  177. }
  178. func getDomainAndProjectServerUsage(session *mcclient.ClientSession, nowTime time.Time) ([]influxdb.SMetricData, error) {
  179. metrics := make([]influxdb.SMetricData, 0)
  180. param := jsonutils.NewDict()
  181. param.Set("scope", jsonutils.NewString("system"))
  182. for urlKey, tag := range map[string]string{
  183. "domain-statistics": "domain_id.project_domain",
  184. "project-statistics": "tenant_id.tenant",
  185. } {
  186. jsonObject, err := compute.Servers.GetById(session, urlKey, param)
  187. if err != nil {
  188. return nil, errors.Wrapf(err, "get server-%s err", urlKey)
  189. }
  190. usageArr := jsonObject.(*jsonutils.JSONArray)
  191. for i := 0; i < usageArr.Size(); i++ {
  192. metric := influxdb.SMetricData{Name: measureMent, Timestamp: nowTime}
  193. usageObj, _ := usageArr.GetAt(i)
  194. usage := new(resourceUsage)
  195. usageObj.Unmarshal(usage)
  196. key := ""
  197. if strings.Contains(urlKey, "domain") {
  198. key = "domain"
  199. } else {
  200. key = "project"
  201. }
  202. metric.Metrics = append(metric.Metrics, influxdb.SKeyValue{
  203. Key: fmt.Sprintf("%s.servers", key),
  204. Value: usage.Count,
  205. })
  206. tagArr := strings.Split(tag, ".")
  207. metric.Tags = append(metric.Tags, influxdb.SKeyValue{
  208. Key: tagArr[0],
  209. Value: usage.Id,
  210. }, influxdb.SKeyValue{
  211. Key: tagArr[1],
  212. Value: usage.Name,
  213. })
  214. metrics = append(metrics, metric)
  215. }
  216. }
  217. return metrics, nil
  218. }