meta.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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 yunionmeta
  15. import (
  16. "context"
  17. "fmt"
  18. "net/http"
  19. "strconv"
  20. "strings"
  21. "time"
  22. "yunion.io/x/cloudmux/pkg/cloudprovider"
  23. "yunion.io/x/jsonutils"
  24. "yunion.io/x/pkg/errors"
  25. "yunion.io/x/pkg/gotypes"
  26. "yunion.io/x/pkg/util/httputils"
  27. "yunion.io/x/pkg/util/version"
  28. api "yunion.io/x/onecloud/pkg/apis/compute"
  29. "yunion.io/x/onecloud/pkg/compute/options"
  30. "yunion.io/x/onecloud/pkg/mcclient/auth"
  31. "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
  32. )
  33. const (
  34. EMPTY_MD5 = "d751713988987e9331980363e24189ce"
  35. )
  36. var meta *SSkuResourcesMeta
  37. type SSkuResourcesMeta struct {
  38. // RDS套餐
  39. DBInstanceBase string `json:"dbinstance_base"`
  40. // 虚拟机套餐
  41. ServerBase string `json:"server_base"`
  42. // Redis套餐
  43. ElasticCacheBase string `json:"elastic_cache_base"`
  44. // 公有云镜像
  45. ImageBase string `json:"image_base"`
  46. NatBase string `json:"nat_base"`
  47. NasBase string `json:"nas_base"`
  48. WafBase string `json:"waf_base"`
  49. CloudpolicyBase string `json:"cloudpolicy_base"`
  50. RateBase string `json:"rate_base"`
  51. // 汇率转换
  52. CurrencyExchangeBase string `json:"currency_exchange_base"`
  53. // 3天过期, 重新刷新
  54. expire time.Time
  55. }
  56. func GetZoneIdBySuffix(zoneMaps map[string]string, suffix string) string {
  57. for externalId, id := range zoneMaps {
  58. if strings.HasSuffix(externalId, suffix) {
  59. return id
  60. }
  61. }
  62. return ""
  63. }
  64. func FetchYunionmeta(ctx context.Context) (*SSkuResourcesMeta, error) {
  65. if !gotypes.IsNil(meta) && meta.expire.After(time.Now()) {
  66. return meta, nil
  67. }
  68. s := auth.GetAdminSession(ctx, "")
  69. transport := httputils.GetTransport(true)
  70. transport.Proxy = options.Options.HttpTransportProxyFunc()
  71. client := &http.Client{Transport: transport}
  72. resp, err := compute.OfflineCloudmeta.GetSkuSourcesMeta(s, client)
  73. if err != nil {
  74. return nil, errors.Wrap(err, "fetchSkuSourceUrls.GetSkuSourcesMeta")
  75. }
  76. meta = &SSkuResourcesMeta{}
  77. err = resp.Unmarshal(meta)
  78. if err != nil {
  79. return nil, errors.Wrap(err, "fetchSkuSourceUrls.Unmarshal")
  80. }
  81. meta.expire = time.Now().AddDate(0, 0, 3)
  82. return meta, nil
  83. }
  84. func (self *SSkuResourcesMeta) request(url string) (jsonutils.JSONObject, error) {
  85. client := httputils.GetAdaptiveTimeoutClient()
  86. header := http.Header{}
  87. header.Set("User-Agent", "vendor/yunion-OneCloud@"+version.Get().GitVersion)
  88. _, resp, err := httputils.JSONRequest(client, context.TODO(), httputils.GET, url, header, nil, false)
  89. return resp, err
  90. }
  91. func (self *SSkuResourcesMeta) head(url string) (http.Header, jsonutils.JSONObject, error) {
  92. client := httputils.GetAdaptiveTimeoutClient()
  93. header := http.Header{}
  94. header.Set("User-Agent", "vendor/yunion-OneCloud@"+version.Get().GitVersion)
  95. _header, resp, err := httputils.JSONRequest(client, context.TODO(), httputils.HEAD, url, header, nil, false)
  96. return _header, resp, err
  97. }
  98. func (self *SSkuResourcesMeta) GetCurrencyRate(src, dest string) (float64, error) {
  99. url := fmt.Sprintf("%s/%s-%s", self.CurrencyExchangeBase, src, dest)
  100. header, _, err := self.head(url)
  101. if err != nil {
  102. return 0.0, errors.Wrapf(err, "head %s", url)
  103. }
  104. rate := header.Get("x-oss-meta-rate")
  105. if len(rate) == 0 {
  106. return 0.0, errors.Wrapf(cloudprovider.ErrNotFound, "x-oss-meta-rate %s -> %s", src, dest)
  107. }
  108. return strconv.ParseFloat(rate, 64)
  109. }
  110. func (self *SSkuResourcesMeta) _get(url string) ([]jsonutils.JSONObject, error) {
  111. objs, err := self.request(url)
  112. if err != nil {
  113. return nil, errors.Wrapf(err, "request %s", url)
  114. }
  115. var ret []jsonutils.JSONObject
  116. return ret, objs.Unmarshal(&ret)
  117. }
  118. func (self *SSkuResourcesMeta) Get(url string, retVal interface{}) error {
  119. obj, err := self.request(url)
  120. if err != nil {
  121. return errors.Wrapf(err, "request %s", url)
  122. }
  123. return obj.Unmarshal(retVal)
  124. }
  125. func (self *SSkuResourcesMeta) Index(resType string) (map[string]string, error) {
  126. var url string
  127. switch resType {
  128. case "dbinstance_sku":
  129. url = fmt.Sprintf("%s/index.json", self.DBInstanceBase)
  130. case "serversku":
  131. url = fmt.Sprintf("%s/index.json", self.ServerBase)
  132. case "elasticcachesku":
  133. url = fmt.Sprintf("%s/index.json", self.ElasticCacheBase)
  134. case "cloudimage":
  135. url = fmt.Sprintf("%s/index.json", self.ImageBase)
  136. case "nat_sku":
  137. url = fmt.Sprintf("%s/index.json", self.NatBase)
  138. case "nas_sku":
  139. url = fmt.Sprintf("%s/index.json", self.NasBase)
  140. case "waf_rule":
  141. url = fmt.Sprintf("%s/index.json", self.WafBase)
  142. case "cloudpolicy":
  143. url = fmt.Sprintf("%s/index.json", self.CloudpolicyBase)
  144. case "cloudrate":
  145. url = fmt.Sprintf("%s/index.json", self.RateBase)
  146. default:
  147. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%v", resType)
  148. }
  149. ret := map[string]string{}
  150. resp, err := self.request(url)
  151. if err != nil {
  152. return nil, errors.Wrapf(err, "url")
  153. }
  154. return ret, resp.Unmarshal(ret)
  155. }
  156. func (self *SSkuResourcesMeta) List(resType string, regionId string, retVal interface{}) error {
  157. if strings.HasPrefix(regionId, api.CLOUD_PROVIDER_HUAWEI) && strings.Contains(regionId, "_") {
  158. idx := strings.Index(regionId, "_")
  159. regionId = regionId[:idx]
  160. }
  161. var url string
  162. switch resType {
  163. case "dbinstance_sku":
  164. url = fmt.Sprintf("%s/%s.status.json", self.DBInstanceBase, regionId)
  165. case "serversku":
  166. url = fmt.Sprintf("%s/%s.status.new.json", self.ServerBase, regionId)
  167. case "elasticcachesku":
  168. url = fmt.Sprintf("%s/%s.status.json", self.ElasticCacheBase, regionId)
  169. case "cloudimage":
  170. url = fmt.Sprintf("%s/%s.status.json", self.ImageBase, regionId)
  171. case "nat_sku":
  172. url = fmt.Sprintf("%s/%s.status.json", self.NatBase, regionId)
  173. case "nas_sku":
  174. url = fmt.Sprintf("%s/%s.status.json", self.NasBase, regionId)
  175. case "waf_rule":
  176. url = fmt.Sprintf("%s/%s.json", self.WafBase, regionId)
  177. case "cloudpolicy":
  178. url = fmt.Sprintf("%s/%s.json", self.CloudpolicyBase, regionId)
  179. default:
  180. return errors.Wrapf(cloudprovider.ErrNotFound, "%v", resType)
  181. }
  182. resp, err := self._get(url)
  183. if err != nil {
  184. return errors.Wrapf(err, "%v", resType)
  185. }
  186. return jsonutils.Update(retVal, resp)
  187. }