dbinstance_skus.go 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  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. "database/sql"
  18. "fmt"
  19. "strings"
  20. "sync"
  21. "yunion.io/x/cloudmux/pkg/cloudprovider"
  22. "yunion.io/x/jsonutils"
  23. "yunion.io/x/log"
  24. "yunion.io/x/pkg/errors"
  25. "yunion.io/x/pkg/tristate"
  26. "yunion.io/x/pkg/util/compare"
  27. "yunion.io/x/pkg/utils"
  28. "yunion.io/x/sqlchemy"
  29. api "yunion.io/x/onecloud/pkg/apis/compute"
  30. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  31. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  32. "yunion.io/x/onecloud/pkg/compute/options"
  33. "yunion.io/x/onecloud/pkg/httperrors"
  34. "yunion.io/x/onecloud/pkg/mcclient"
  35. "yunion.io/x/onecloud/pkg/util/stringutils2"
  36. "yunion.io/x/onecloud/pkg/util/yunionmeta"
  37. )
  38. // +onecloud:swagger-gen-model-singular=dbinstance_sku
  39. // +onecloud:swagger-gen-model-plural=dbinstance_skus
  40. type SDBInstanceSkuManager struct {
  41. db.SEnabledStatusStandaloneResourceBaseManager
  42. db.SExternalizedResourceBaseManager
  43. SCloudregionResourceBaseManager
  44. }
  45. var DBInstanceSkuManager *SDBInstanceSkuManager
  46. func init() {
  47. DBInstanceSkuManager = &SDBInstanceSkuManager{
  48. SEnabledStatusStandaloneResourceBaseManager: db.NewEnabledStatusStandaloneResourceBaseManager(
  49. SDBInstanceSku{},
  50. "dbinstance_skus_tbl",
  51. "dbinstance_sku",
  52. "dbinstance_skus",
  53. ),
  54. }
  55. DBInstanceSkuManager.SetVirtualObject(DBInstanceSkuManager)
  56. DBInstanceSkuManager.NameRequireAscii = false
  57. DBInstanceSkuManager.TableSpec().AddIndex(false, "cloudregion_id", "deleted", "provider")
  58. }
  59. type SDBInstanceSku struct {
  60. db.SEnabledStatusStandaloneResourceBase
  61. db.SExternalizedResourceBase
  62. SCloudregionResourceBase
  63. Provider string `width:"32" charset:"ascii" nullable:"false" list:"user" create:"admin_required" update:"admin"`
  64. StorageType string `width:"32" index:"true" list:"user" create:"optional"`
  65. DiskSizeStep int `list:"user" default:"1" create:"optional"` //步长
  66. MaxDiskSizeGb int `list:"user" create:"optional"`
  67. MinDiskSizeGb int `list:"user" create:"optional"`
  68. IOPS int `list:"user" create:"optional"`
  69. TPS int `list:"user" create:"optional"`
  70. QPS int `list:"user" create:"optional"`
  71. MaxConnections int `list:"user" create:"optional"`
  72. VcpuCount int `nullable:"false" default:"1" list:"user" create:"optional"`
  73. VmemSizeMb int `nullable:"false" list:"user" create:"required"`
  74. Category string `width:"32" index:"true" nullable:"false" list:"user" create:"optional"`
  75. Engine string `width:"16" index:"true" charset:"ascii" nullable:"false" list:"user" create:"required"`
  76. EngineVersion string `width:"64" index:"true" charset:"ascii" nullable:"false" list:"user" create:"required"`
  77. Zone1 string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
  78. Zone2 string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
  79. Zone3 string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
  80. ZoneId string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"`
  81. MultiAZ tristate.TriState `default:"false" list:"user" create:"optional"`
  82. }
  83. func (manager *SDBInstanceSkuManager) fetchDBInstanceSkus(provider string, region *SCloudregion) ([]SDBInstanceSku, error) {
  84. skus := []SDBInstanceSku{}
  85. q := manager.Query().Equals("provider", provider).Equals("cloudregion_id", region.Id)
  86. err := db.FetchModelObjects(manager, q, &skus)
  87. if err != nil {
  88. return nil, err
  89. }
  90. return skus, nil
  91. }
  92. // RDS套餐类型列表
  93. func (manager *SDBInstanceSkuManager) ListItemFilter(
  94. ctx context.Context,
  95. q *sqlchemy.SQuery,
  96. userCred mcclient.TokenCredential,
  97. query api.DBInstanceSkuListInput,
  98. ) (*sqlchemy.SQuery, error) {
  99. q, err := manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
  100. if err != nil {
  101. return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemFilter")
  102. }
  103. q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
  104. if err != nil {
  105. return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
  106. }
  107. if domainStr := query.ProjectDomainId; len(domainStr) > 0 {
  108. domain, err := db.TenantCacheManager.FetchDomainByIdOrName(ctx, domainStr)
  109. if err != nil {
  110. if errors.Cause(err) == sql.ErrNoRows {
  111. return nil, httperrors.NewResourceNotFoundError2("domains", domainStr)
  112. }
  113. return nil, httperrors.NewGeneralError(err)
  114. }
  115. query.ProjectDomainId = domain.GetId()
  116. }
  117. q = listItemDomainFilter(q, query.Providers, query.ProjectDomainId)
  118. q, err = managedResourceFilterByRegion(ctx, q, query.RegionalFilterListInput, "", nil)
  119. if err != nil {
  120. return nil, errors.Wrap(err, "managedResourceFilterByRegion")
  121. }
  122. // StorageType
  123. if len(query.StorageType) > 0 {
  124. q = q.In("storage_type", query.StorageType)
  125. }
  126. if len(query.VcpuCount) > 0 {
  127. q = q.In("vcpu_count", query.VcpuCount)
  128. }
  129. if len(query.VmemSizeMb) > 0 {
  130. q = q.In("vmem_size_mb", query.VmemSizeMb)
  131. }
  132. if len(query.Category) > 0 {
  133. q = q.In("category", query.Category)
  134. }
  135. if len(query.Engine) > 0 {
  136. q = q.In("engine", query.Engine)
  137. }
  138. if len(query.EngineVersion) > 0 {
  139. q = q.In("engine_version", query.EngineVersion)
  140. }
  141. if len(query.Providers) > 0 {
  142. q = q.In("provider", query.Providers)
  143. }
  144. for k, zoneIds := range map[string][]string{"zone1": query.Zone1, "zone2": query.Zone2, "zone3": query.Zone3} {
  145. ids := []string{}
  146. for _, zoneId := range zoneIds {
  147. zone, err := ZoneManager.FetchByIdOrName(ctx, userCred, zoneId)
  148. if err != nil {
  149. if errors.Cause(err) == sql.ErrNoRows {
  150. return nil, httperrors.NewResourceNotFoundError2("zone", zoneId)
  151. }
  152. return nil, httperrors.NewGeneralError(err)
  153. }
  154. ids = append(ids, zone.GetId())
  155. }
  156. if len(ids) > 0 {
  157. q = q.In(k, ids)
  158. }
  159. }
  160. return q, nil
  161. }
  162. func (manager *SDBInstanceSkuManager) FetchCustomizeColumns(
  163. ctx context.Context,
  164. userCred mcclient.TokenCredential,
  165. query jsonutils.JSONObject,
  166. objs []interface{},
  167. fields stringutils2.SSortedStrings,
  168. isList bool,
  169. ) []api.DBInstanceSkuDetails {
  170. rows := make([]api.DBInstanceSkuDetails, len(objs))
  171. enableRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  172. regionRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  173. zoneIds := map[string]string{}
  174. for i := range rows {
  175. rows[i] = api.DBInstanceSkuDetails{
  176. EnabledStatusStandaloneResourceDetails: enableRows[i],
  177. CloudregionResourceInfo: regionRows[i],
  178. }
  179. rows[i].CloudEnv = strings.Split(regionRows[i].RegionExternalId, "/")[0]
  180. sku := objs[i].(*SDBInstanceSku)
  181. for _, zoneId := range []string{sku.Zone1, sku.Zone2, sku.Zone3} {
  182. if _, ok := zoneIds[zoneId]; !ok {
  183. zoneIds[zoneId] = ""
  184. }
  185. }
  186. }
  187. var err error
  188. zoneIds, err = db.FetchIdNameMap(ZoneManager, zoneIds)
  189. if err != nil {
  190. log.Errorf("db.FetchIdNameMap fail %s", err)
  191. return rows
  192. }
  193. for i := range rows {
  194. sku := objs[i].(*SDBInstanceSku)
  195. rows[i].Zone1Name, _ = zoneIds[sku.Zone1]
  196. rows[i].Zone2Name, _ = zoneIds[sku.Zone2]
  197. rows[i].Zone3Name, _ = zoneIds[sku.Zone3]
  198. }
  199. return rows
  200. }
  201. func (manager *SDBInstanceSkuManager) OrderByExtraFields(
  202. ctx context.Context,
  203. q *sqlchemy.SQuery,
  204. userCred mcclient.TokenCredential,
  205. query api.DBInstanceSkuListInput,
  206. ) (*sqlchemy.SQuery, error) {
  207. var err error
  208. q, err = manager.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
  209. if err != nil {
  210. return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields")
  211. }
  212. return q, nil
  213. }
  214. func (manager *SDBInstanceSkuManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  215. var err error
  216. q, err = manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
  217. if err == nil {
  218. return q, nil
  219. }
  220. return q, httperrors.ErrNotFound
  221. }
  222. func (manager *SDBInstanceSkuManager) GetDBStringArray(q *sqlchemy.SQuery) ([]string, error) {
  223. array := []string{}
  224. rows, err := q.Rows()
  225. if err != nil {
  226. return nil, errors.Wrap(err, "q.Rows")
  227. }
  228. defer rows.Close()
  229. for rows.Next() {
  230. data := ""
  231. err = rows.Scan(&data)
  232. if err != nil {
  233. return nil, errors.Wrap(err, "rows.Scan")
  234. }
  235. array = append(array, data)
  236. }
  237. return array, err
  238. }
  239. func (manager *SDBInstanceSkuManager) GetPropertyInstanceSpecs(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  240. listQuery := api.DBInstanceSkuListInput{}
  241. err := query.Unmarshal(&listQuery)
  242. if err != nil {
  243. return nil, errors.Wrap(err, "query.Unmarshal")
  244. }
  245. q, err := manager.ListItemFilter(ctx, manager.Query(), userCred, listQuery)
  246. if err != nil {
  247. return nil, errors.Wrap(err, "manager.ListItemFilter")
  248. }
  249. q2, err := manager.ListItemFilter(ctx, manager.Query(), userCred, listQuery)
  250. if err != nil {
  251. return nil, errors.Wrap(err, "manager.ListItemFilter")
  252. }
  253. input := &SDBInstanceSku{}
  254. query.Unmarshal(input)
  255. for k, v := range map[string]interface{}{
  256. "provider": input.Provider,
  257. "storage_type": input.StorageType,
  258. "category": input.Category,
  259. "engine": input.Engine,
  260. "engine_version": input.EngineVersion,
  261. "iops": input.IOPS,
  262. "qps": input.QPS,
  263. "tps": input.TPS,
  264. "vcpu_count": input.VcpuCount,
  265. "vmem_size_mb": input.VmemSizeMb,
  266. } {
  267. switch v.(type) {
  268. case string:
  269. value := v.(string)
  270. if len(value) > 0 {
  271. q = q.Equals(k, v)
  272. q2 = q2.Equals(k, v)
  273. }
  274. case int, int64:
  275. value := fmt.Sprintf("%d", v)
  276. if value != "0" {
  277. q = q.Equals(k, v)
  278. q2 = q2.Equals(k, v)
  279. }
  280. }
  281. }
  282. sq := q2.SubQuery()
  283. q2 = sq.Query(sq.Field("zone1"), sq.Field("zone2"), sq.Field("zone3")).Distinct()
  284. skuZones := []struct {
  285. Zone1 string
  286. Zone2 string
  287. Zone3 string
  288. }{}
  289. err = q2.All(&skuZones)
  290. if err != nil {
  291. return nil, errors.Wrapf(err, "query sku zones")
  292. }
  293. skus := []SDBInstanceSku{}
  294. q = q.GroupBy(q.Field("vcpu_count"), q.Field("vmem_size_mb"))
  295. q = q.Asc(q.Field("vcpu_count"), q.Field("vmem_size_mb"))
  296. err = db.FetchModelObjects(manager, q, &skus)
  297. if err != nil {
  298. return nil, httperrors.NewGeneralError(errors.Wrap(err, "db.FetchModelObjects"))
  299. }
  300. result := struct {
  301. CpuMemsMb map[string][]int
  302. cpuMemsMb map[int]map[int]bool
  303. Cpus []int
  304. MemsMb []int
  305. memsMb map[int]bool
  306. Zones struct {
  307. Zones map[string]string
  308. Zone1 map[string]string
  309. Zone2 map[string]string
  310. Zone3 map[string]string
  311. }
  312. zones []string
  313. zoneNames map[string]string
  314. }{
  315. CpuMemsMb: map[string][]int{},
  316. cpuMemsMb: map[int]map[int]bool{},
  317. Cpus: []int{},
  318. MemsMb: []int{},
  319. memsMb: map[int]bool{},
  320. zones: []string{},
  321. zoneNames: map[string]string{},
  322. }
  323. result.Zones.Zones = map[string]string{}
  324. result.Zones.Zone1 = map[string]string{}
  325. result.Zones.Zone2 = map[string]string{}
  326. result.Zones.Zone3 = map[string]string{}
  327. for _, sku := range skuZones {
  328. if _, ok := result.Zones.Zone1[sku.Zone1]; !ok && len(sku.Zone1) > 0 {
  329. result.Zones.Zone1[sku.Zone1] = sku.Zone1
  330. }
  331. if _, ok := result.Zones.Zone2[sku.Zone2]; !ok && len(sku.Zone2) > 0 {
  332. result.Zones.Zone2[sku.Zone2] = sku.Zone2
  333. }
  334. if _, ok := result.Zones.Zone3[sku.Zone3]; !ok && len(sku.Zone3) > 0 {
  335. result.Zones.Zone3[sku.Zone3] = sku.Zone3
  336. }
  337. zoneIds := []string{}
  338. for _, zone := range []string{sku.Zone1, sku.Zone2, sku.Zone3} {
  339. if len(zone) > 0 {
  340. zoneIds = append(zoneIds, zone)
  341. if !utils.IsInStringArray(zone, result.zones) {
  342. result.zones = append(result.zones, zone)
  343. }
  344. }
  345. }
  346. zoneId := strings.Join(zoneIds, "+")
  347. if _, ok := result.Zones.Zones[zoneId]; !ok && len(zoneId) > 0 {
  348. result.Zones.Zones[zoneId] = zoneId
  349. }
  350. }
  351. for _, sku := range skus {
  352. if _, ok := result.cpuMemsMb[sku.VcpuCount]; !ok {
  353. result.cpuMemsMb[sku.VcpuCount] = map[int]bool{}
  354. result.CpuMemsMb[fmt.Sprintf("%d", sku.VcpuCount)] = []int{}
  355. result.Cpus = append(result.Cpus, sku.VcpuCount)
  356. }
  357. if _, ok := result.cpuMemsMb[sku.VcpuCount][sku.VmemSizeMb]; !ok {
  358. result.cpuMemsMb[sku.VcpuCount][sku.VmemSizeMb] = true
  359. result.CpuMemsMb[fmt.Sprintf("%d", sku.VcpuCount)] = append(result.CpuMemsMb[fmt.Sprintf("%d", sku.VcpuCount)], sku.VmemSizeMb)
  360. }
  361. if _, ok := result.memsMb[sku.VmemSizeMb]; !ok {
  362. result.memsMb[sku.VmemSizeMb] = true
  363. result.MemsMb = append(result.MemsMb, sku.VmemSizeMb)
  364. }
  365. }
  366. zones := []struct {
  367. Id string
  368. Name string
  369. }{}
  370. err = ZoneManager.Query("id", "name").In("id", result.zones).All(&zones)
  371. if err != nil {
  372. return nil, errors.Wrapf(err, "query zones")
  373. }
  374. for _, zone := range zones {
  375. result.zoneNames[zone.Id] = zone.Name
  376. }
  377. for _, zoneId := range result.Zones.Zone1 {
  378. result.Zones.Zone1[zoneId] = result.zoneNames[zoneId]
  379. }
  380. for _, zoneId := range result.Zones.Zone2 {
  381. result.Zones.Zone2[zoneId] = result.zoneNames[zoneId]
  382. }
  383. for _, zoneId := range result.Zones.Zone3 {
  384. result.Zones.Zone3[zoneId] = result.zoneNames[zoneId]
  385. }
  386. for _, zoneId := range result.Zones.Zones {
  387. zoneIds := strings.Split(zoneId, "+")
  388. zoneNames := []string{}
  389. for _, id := range zoneIds {
  390. zoneNames = append(zoneNames, result.zoneNames[id])
  391. }
  392. result.Zones.Zones[zoneId] = strings.Join(zoneNames, "+")
  393. }
  394. return jsonutils.Marshal(result), nil
  395. }
  396. func (manager *SDBInstanceSkuManager) GetEngines(provider, cloudregionId string) ([]string, error) {
  397. q := manager.Query("engine").Equals("provider", provider).Equals("cloudregion_id", cloudregionId).Distinct()
  398. return manager.GetDBStringArray(q)
  399. }
  400. func (manager *SDBInstanceSkuManager) GetEngineVersions(provider, cloudregionId, engine string) ([]string, error) {
  401. q := manager.Query("engine_version").Equals("provider", provider).Equals("cloudregion_id", cloudregionId).Equals("engine", engine).Distinct()
  402. return manager.GetDBStringArray(q)
  403. }
  404. func (manager *SDBInstanceSkuManager) GetCategories(provider, cloudregionId, engine, version string) ([]string, error) {
  405. q := manager.Query("category").Equals("provider", provider).Equals("cloudregion_id", cloudregionId).Equals("engine", engine).Equals("engine_version", version).Distinct()
  406. return manager.GetDBStringArray(q)
  407. }
  408. func (manager *SDBInstanceSkuManager) GetStorageTypes(provider, cloudregionId, engine, version, category string) ([]string, error) {
  409. q := manager.Query("storage_type").Equals("provider", provider).Equals("cloudregion_id", cloudregionId).Equals("engine", engine).Equals("engine_version", version).Distinct()
  410. q = q.Equals("category", category)
  411. return manager.GetDBStringArray(q)
  412. }
  413. func (manager *SDBInstanceSkuManager) GetInstanceTypes(provider, cloudregionId, engine, version, category, storageType string) ([]string, error) {
  414. q := manager.Query("name").Equals("provider", provider).Equals("cloudregion_id", cloudregionId).Equals("engine", engine).Equals("engine_version", version).Distinct()
  415. q = q.Equals("category", category).Equals("storage_type", storageType)
  416. return manager.GetDBStringArray(q)
  417. }
  418. func (manager *SDBInstanceSkuManager) GetSkuCountByRegion(regionId string) (int, error) {
  419. q := manager.Query().Equals("cloudregion_id", regionId)
  420. return q.CountWithError()
  421. }
  422. func (manager *SDBInstanceSkuManager) GetDBInstanceSkus(provider, cloudregionId, engine, version, category, storageType string) ([]SDBInstanceSku, error) {
  423. skus := []SDBInstanceSku{}
  424. q := manager.Query("name").Equals("provider", provider).Equals("cloudregion_id", cloudregionId).Equals("engine", engine).Equals("engine_version", version).Distinct()
  425. q = q.Equals("category", category).Equals("storage_type", storageType)
  426. err := db.FetchModelObjects(manager, q, &skus)
  427. if err != nil {
  428. return nil, err
  429. }
  430. return skus, nil
  431. }
  432. func (manager *SDBInstanceSkuManager) SyncDBInstanceSkus(
  433. ctx context.Context,
  434. userCred mcclient.TokenCredential,
  435. region *SCloudregion,
  436. xor bool,
  437. ) compare.SyncResult {
  438. lockman.LockRawObject(ctx, manager.Keyword(), region.Id)
  439. defer lockman.ReleaseRawObject(ctx, manager.Keyword(), region.Id)
  440. result := compare.SyncResult{}
  441. meta, err := yunionmeta.FetchYunionmeta(ctx)
  442. if err != nil {
  443. result.Error(errors.Wrapf(err, "FetchYunionmeta"))
  444. return result
  445. }
  446. iskus := []SDBInstanceSku{}
  447. err = meta.List(manager.Keyword(), region.ExternalId, &iskus)
  448. if err != nil {
  449. result.Error(err)
  450. return result
  451. }
  452. dbSkus, err := manager.fetchDBInstanceSkus(region.Provider, region)
  453. if err != nil {
  454. result.Error(err)
  455. return result
  456. }
  457. removed := make([]SDBInstanceSku, 0)
  458. commondb := make([]SDBInstanceSku, 0)
  459. commonext := make([]SDBInstanceSku, 0)
  460. added := make([]SDBInstanceSku, 0)
  461. err = compare.CompareSets(dbSkus, iskus, &removed, &commondb, &commonext, &added)
  462. if err != nil {
  463. result.Error(err)
  464. return result
  465. }
  466. for i := 0; i < len(removed); i += 1 {
  467. err = db.RealDeleteModel(ctx, userCred, &removed[i])
  468. if err != nil {
  469. result.DeleteError(err)
  470. } else {
  471. result.Delete()
  472. }
  473. }
  474. if !xor {
  475. for i := 0; i < len(commondb); i += 1 {
  476. err = commondb[i].syncWithCloudSku(ctx, userCred, commonext[i])
  477. if err != nil {
  478. result.UpdateError(err)
  479. } else {
  480. result.Update()
  481. }
  482. }
  483. }
  484. for i := 0; i < len(added); i += 1 {
  485. err = region.newDBInstanceSkuFromCloudSku(ctx, userCred, added[i].GetGlobalId())
  486. if err != nil {
  487. result.AddError(err)
  488. } else {
  489. result.Add()
  490. }
  491. }
  492. return result
  493. }
  494. func (sku SDBInstanceSku) GetGlobalId() string {
  495. return sku.ExternalId
  496. }
  497. func (sku *SDBInstanceSku) syncWithCloudSku(ctx context.Context, userCred mcclient.TokenCredential, isku SDBInstanceSku) error {
  498. _, err := db.Update(sku, func() error {
  499. sku.Status = isku.Status
  500. return nil
  501. })
  502. return err
  503. }
  504. func (self *SCloudregion) newDBInstanceSkuFromCloudSku(ctx context.Context, userCred mcclient.TokenCredential, externalId string) error {
  505. meta, err := yunionmeta.FetchYunionmeta(ctx)
  506. if err != nil {
  507. return err
  508. }
  509. zones, err := self.GetZones()
  510. if err != nil {
  511. return errors.Wrap(err, "GetZones")
  512. }
  513. zoneMaps := map[string]string{}
  514. for _, zone := range zones {
  515. zoneMaps[zone.ExternalId] = zone.Id
  516. }
  517. sku := &SDBInstanceSku{}
  518. sku.SetModelManager(DBInstanceSkuManager, sku)
  519. skuUrl := self.getMetaUrl(meta.DBInstanceBase, externalId)
  520. err = meta.Get(skuUrl, sku)
  521. if err != nil {
  522. return errors.Wrapf(err, "Get")
  523. }
  524. if len(sku.Zone1) > 0 {
  525. zoneId := yunionmeta.GetZoneIdBySuffix(zoneMaps, sku.Zone1)
  526. if len(zoneId) == 0 {
  527. return errors.Wrapf(err, "GetZoneIdBySuffix(%s)", sku.Zone1)
  528. }
  529. sku.Zone1 = zoneId
  530. }
  531. if len(sku.Zone2) > 0 {
  532. zoneId := yunionmeta.GetZoneIdBySuffix(zoneMaps, sku.Zone2)
  533. if len(zoneId) == 0 {
  534. return errors.Wrapf(err, "GetZoneIdBySuffix(%s)", sku.Zone2)
  535. }
  536. sku.Zone2 = zoneId
  537. }
  538. if len(sku.Zone3) > 0 {
  539. zoneId := yunionmeta.GetZoneIdBySuffix(zoneMaps, sku.Zone3)
  540. if len(zoneId) == 0 {
  541. return errors.Wrapf(err, "GetZoneIdBySuffix(%s)", sku.Zone3)
  542. }
  543. sku.Zone3 = zoneId
  544. }
  545. sku.CloudregionId = self.Id
  546. sku.Provider = self.Provider
  547. sku.Enabled = tristate.True
  548. return DBInstanceSkuManager.TableSpec().Insert(ctx, sku)
  549. }
  550. func SyncRegionDBInstanceSkus(ctx context.Context, userCred mcclient.TokenCredential, regionId string, isStart, xor bool) {
  551. if isStart {
  552. q := DBInstanceSkuManager.Query()
  553. if len(regionId) > 0 {
  554. q = q.Equals("cloudregion_id", regionId)
  555. }
  556. cnt, err := q.Limit(1).CountWithError()
  557. if err != nil && err != sql.ErrNoRows {
  558. log.Errorf("SyncDBInstanceSkus.QueryDBInstanceSku %s", err)
  559. return
  560. }
  561. if cnt > 0 {
  562. log.Debugf("sync rds sku for %s synced skus, skip...", regionId)
  563. return
  564. }
  565. }
  566. q := CloudregionManager.Query()
  567. q = q.In("provider", CloudproviderManager.GetPublicProviderProvidersQuery())
  568. if len(regionId) > 0 {
  569. q = q.Equals("id", regionId)
  570. }
  571. cloudregions := []SCloudregion{}
  572. err := db.FetchModelObjects(CloudregionManager, q, &cloudregions)
  573. if err != nil {
  574. log.Errorf("failed to fetch cloudregions: %v", err)
  575. return
  576. }
  577. if len(cloudregions) == 0 {
  578. return
  579. }
  580. meta, err := yunionmeta.FetchYunionmeta(ctx)
  581. if err != nil {
  582. log.Errorf("FetchYunionmeta: %v", err)
  583. return
  584. }
  585. index, err := meta.Index(DBInstanceSkuManager.Keyword())
  586. if err != nil {
  587. log.Errorf("get rds sku index error: %v", err)
  588. return
  589. }
  590. for _, region := range cloudregions {
  591. if !region.GetDriver().IsSupportedDBInstance() {
  592. log.Debugf("region %s(%s) not support dbinstance, skip sync", region.Name, region.Id)
  593. continue
  594. }
  595. skuMeta := &SDBInstanceSku{}
  596. skuMeta.SetModelManager(DBInstanceSkuManager, skuMeta)
  597. skuMeta.Id = region.ExternalId
  598. oldMd5 := db.Metadata.GetStringValue(ctx, skuMeta, db.SKU_METADAT_KEY, userCred)
  599. newMd5, ok := index[region.ExternalId]
  600. if !ok || newMd5 == yunionmeta.EMPTY_MD5 || len(oldMd5) > 0 && newMd5 == oldMd5 {
  601. continue
  602. }
  603. db.Metadata.SetValue(ctx, skuMeta, db.SKU_METADAT_KEY, newMd5, userCred)
  604. result := DBInstanceSkuManager.SyncDBInstanceSkus(ctx, userCred, &region, xor)
  605. notes := fmt.Sprintf("sync rds sku for region %s result: %s", region.Name, result.Result())
  606. log.Debugf("%s", notes)
  607. }
  608. }
  609. func SyncDBInstanceSkus(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
  610. SyncRegionDBInstanceSkus(ctx, userCred, "", isStart, false)
  611. }
  612. func (manager *SDBInstanceSkuManager) ListItemExportKeys(ctx context.Context,
  613. q *sqlchemy.SQuery,
  614. userCred mcclient.TokenCredential,
  615. keys stringutils2.SSortedStrings,
  616. ) (*sqlchemy.SQuery, error) {
  617. var err error
  618. q, err = manager.SEnabledStatusStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  619. if err != nil {
  620. return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemExportKeys")
  621. }
  622. if keys.ContainsAny(manager.SCloudregionResourceBaseManager.GetExportKeys()...) {
  623. q, err = manager.SCloudregionResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  624. if err != nil {
  625. return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemExportKeys")
  626. }
  627. }
  628. return q, nil
  629. }
  630. func (self *SDBInstanceSku) GetZoneInfo() (cloudprovider.SZoneInfo, error) {
  631. zoneInfo := cloudprovider.SZoneInfo{ZoneId: self.ZoneId}
  632. region, err := self.GetRegion()
  633. if err != nil {
  634. return zoneInfo, nil
  635. }
  636. var cloudZoneId = func(id string) (string, error) {
  637. if len(id) == 0 {
  638. return "", nil
  639. }
  640. _zone, err := ZoneManager.FetchById(id)
  641. if err != nil {
  642. log.Errorf("ZoneManager.FetchById(%s) error: %v", id, err)
  643. return "", errors.Wrapf(err, "ZoneManager.FetchById(%s)", id)
  644. }
  645. zone := _zone.(*SZone)
  646. return strings.TrimPrefix(zone.ExternalId, region.ExternalId+"/"), nil
  647. }
  648. zoneInfo.Zone1, _ = cloudZoneId(self.Zone1)
  649. zoneInfo.Zone2, _ = cloudZoneId(self.Zone2)
  650. zoneInfo.Zone3, _ = cloudZoneId(self.Zone3)
  651. return zoneInfo, nil
  652. }
  653. func (manager *SDBInstanceSkuManager) PerformSyncSkus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.SkuSyncInput) (jsonutils.JSONObject, error) {
  654. return PerformActionSyncSkus(ctx, userCred, manager.Keyword(), input)
  655. }
  656. func (manager *SDBInstanceSkuManager) GetPropertySyncTasks(ctx context.Context, userCred mcclient.TokenCredential, query api.SkuTaskQueryInput) (jsonutils.JSONObject, error) {
  657. return GetPropertySkusSyncTasks(ctx, userCred, query)
  658. }
  659. func (self *SCloudregion) GetDBInstanceSkus() ([]SDBInstanceSku, error) {
  660. q := DBInstanceSkuManager.Query().Equals("cloudregion_id", self.Id)
  661. skus := []SDBInstanceSku{}
  662. err := db.FetchModelObjects(DBInstanceSkuManager, q, &skus)
  663. if err != nil {
  664. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  665. }
  666. return skus, nil
  667. }
  668. func (self *SCloudregion) SyncDBInstanceSkus(
  669. ctx context.Context,
  670. userCred mcclient.TokenCredential,
  671. provider *SCloudprovider,
  672. exts []cloudprovider.ICloudDBInstanceSku,
  673. ) compare.SyncResult {
  674. lockman.LockRawObject(ctx, DBInstanceSkuManager.Keyword(), self.Id)
  675. defer lockman.ReleaseRawObject(ctx, DBInstanceSkuManager.Keyword(), self.Id)
  676. result := compare.SyncResult{}
  677. dbSkus, err := self.GetDBInstanceSkus()
  678. if err != nil {
  679. result.Error(err)
  680. return result
  681. }
  682. removed := make([]SDBInstanceSku, 0)
  683. commondb := make([]SDBInstanceSku, 0)
  684. commonext := make([]cloudprovider.ICloudDBInstanceSku, 0)
  685. added := make([]cloudprovider.ICloudDBInstanceSku, 0)
  686. err = compare.CompareSets(dbSkus, exts, &removed, &commondb, &commonext, &added)
  687. if err != nil {
  688. result.Error(err)
  689. return result
  690. }
  691. for i := 0; i < len(removed); i += 1 {
  692. err = removed[i].Delete(ctx, userCred)
  693. if err != nil {
  694. result.DeleteError(err)
  695. continue
  696. }
  697. result.Delete()
  698. }
  699. ch := make(chan struct{}, options.Options.SkuBatchSync)
  700. defer close(ch)
  701. var wg sync.WaitGroup
  702. for i := 0; i < len(added); i += 1 {
  703. ch <- struct{}{}
  704. wg.Add(1)
  705. go func(sku cloudprovider.ICloudDBInstanceSku) {
  706. defer func() {
  707. wg.Done()
  708. <-ch
  709. }()
  710. err = self.newFromCloudSku(ctx, userCred, sku)
  711. if err != nil {
  712. result.AddError(err)
  713. return
  714. }
  715. result.Add()
  716. }(added[i])
  717. }
  718. wg.Wait()
  719. return result
  720. }
  721. func (self *SCloudregion) newFromCloudSku(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudDBInstanceSku) error {
  722. sku := &SDBInstanceSku{}
  723. sku.SetModelManager(DBInstanceSkuManager, sku)
  724. sku.Name = ext.GetName()
  725. sku.Status = ext.GetStatus()
  726. sku.CloudregionId = self.Id
  727. sku.Enabled = tristate.True
  728. sku.ExternalId = ext.GetGlobalId()
  729. sku.Engine = ext.GetEngine()
  730. sku.EngineVersion = ext.GetEngineVersion()
  731. sku.StorageType = ext.GetStorageType()
  732. sku.DiskSizeStep = ext.GetDiskSizeStep()
  733. sku.MaxDiskSizeGb = ext.GetMaxDiskSizeGb()
  734. sku.MinDiskSizeGb = ext.GetMinDiskSizeGb()
  735. sku.IOPS = ext.GetIOPS()
  736. sku.TPS = ext.GetTPS()
  737. sku.QPS = ext.GetQPS()
  738. sku.MaxConnections = ext.GetMaxConnections()
  739. sku.VcpuCount = ext.GetVcpuCount()
  740. sku.VmemSizeMb = ext.GetVmemSizeMb()
  741. sku.Category = ext.GetCategory()
  742. sku.ZoneId = ext.GetZoneId()
  743. sku.Provider = self.Provider
  744. zones, _ := self.GetZones()
  745. if zone1 := ext.GetZone1Id(); len(zone1) > 0 {
  746. for _, zone := range zones {
  747. if strings.HasSuffix(zone.ExternalId, zone1) {
  748. sku.Zone1 = zone.Id
  749. break
  750. }
  751. }
  752. }
  753. if zone2 := ext.GetZone2Id(); len(zone2) > 0 {
  754. for _, zone := range zones {
  755. if strings.HasSuffix(zone.ExternalId, zone2) {
  756. sku.Zone2 = zone.Id
  757. break
  758. }
  759. }
  760. }
  761. if zone3 := ext.GetZone3Id(); len(zone3) > 0 {
  762. for _, zone := range zones {
  763. if strings.HasSuffix(zone.ExternalId, zone3) {
  764. sku.Zone3 = zone.Id
  765. break
  766. }
  767. }
  768. }
  769. return DBInstanceSkuManager.TableSpec().Insert(ctx, sku)
  770. }