cloudregions.go 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330
  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. "strings"
  19. "time"
  20. "yunion.io/x/cloudmux/pkg/cloudprovider"
  21. "yunion.io/x/jsonutils"
  22. "yunion.io/x/log"
  23. "yunion.io/x/pkg/errors"
  24. "yunion.io/x/pkg/gotypes"
  25. "yunion.io/x/pkg/util/compare"
  26. "yunion.io/x/pkg/util/rbacscope"
  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/cloudcommon/db/taskman"
  33. "yunion.io/x/onecloud/pkg/compute/options"
  34. "yunion.io/x/onecloud/pkg/httperrors"
  35. "yunion.io/x/onecloud/pkg/mcclient"
  36. "yunion.io/x/onecloud/pkg/mcclient/auth"
  37. "yunion.io/x/onecloud/pkg/util/stringutils2"
  38. "yunion.io/x/onecloud/pkg/util/yunionmeta"
  39. )
  40. type SCloudregionManager struct {
  41. db.SEnabledStatusStandaloneResourceBaseManager
  42. db.SExternalizedResourceBaseManager
  43. SI18nResourceBaseManager
  44. }
  45. var CloudregionManager *SCloudregionManager
  46. func init() {
  47. CloudregionManager = &SCloudregionManager{
  48. SEnabledStatusStandaloneResourceBaseManager: db.NewEnabledStatusStandaloneResourceBaseManager(
  49. SCloudregion{},
  50. "cloudregions_tbl",
  51. "cloudregion",
  52. "cloudregions",
  53. ),
  54. }
  55. CloudregionManager.SetVirtualObject(CloudregionManager)
  56. }
  57. type SCloudregion struct {
  58. db.SEnabledStatusStandaloneResourceBase
  59. SI18nResourceBase
  60. db.SExternalizedResourceBase
  61. cloudprovider.SGeographicInfo
  62. // 云环境
  63. // example: ChinaCloud
  64. Environment string `width:"32" charset:"ascii" list:"user"`
  65. // 云平台
  66. // example: Huawei
  67. Provider string `width:"64" charset:"ascii" list:"user" nullable:"false" default:"OneCloud"`
  68. }
  69. func (self *SCloudregion) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  70. idstr, _ := data.GetString("id")
  71. if len(idstr) > 0 {
  72. self.Id = idstr
  73. }
  74. return nil
  75. }
  76. func (self *SCloudregion) ValidateDeleteCondition(ctx context.Context, info *api.CloudregionDetails) error {
  77. if self.Id == api.DEFAULT_REGION_ID {
  78. return httperrors.NewProtectedResourceError("not allow to delete default cloud region")
  79. }
  80. if gotypes.IsNil(info) {
  81. info = &api.CloudregionDetails{}
  82. usage, err := CloudregionManager.TotalResourceCount([]string{self.Id})
  83. if err != nil {
  84. return err
  85. }
  86. info.SCloudregionUsage, _ = usage[self.Id]
  87. }
  88. if info.ZoneCount > 0 || info.VpcCount > 0 {
  89. return httperrors.NewNotEmptyError("not empty cloud region")
  90. }
  91. return self.SEnabledStatusStandaloneResourceBase.ValidateDeleteCondition(ctx, nil)
  92. }
  93. func (self *SCloudregion) GetElasticIps(managerId, eipMode string) ([]SElasticip, error) {
  94. q := ElasticipManager.Query().Equals("cloudregion_id", self.Id)
  95. if len(managerId) > 0 {
  96. q = q.Equals("manager_id", managerId)
  97. }
  98. if len(eipMode) > 0 {
  99. q = q.Equals("mode", eipMode)
  100. }
  101. eips := []SElasticip{}
  102. err := db.FetchModelObjects(ElasticipManager, q, &eips)
  103. if err != nil {
  104. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  105. }
  106. return eips, nil
  107. }
  108. func (self *SCloudregion) GetZoneQuery() *sqlchemy.SQuery {
  109. zones := ZoneManager.Query()
  110. if self.Id == api.DEFAULT_REGION_ID {
  111. return zones.Filter(sqlchemy.OR(sqlchemy.IsNull(zones.Field("cloudregion_id")),
  112. sqlchemy.IsEmpty(zones.Field("cloudregion_id")),
  113. sqlchemy.Equals(zones.Field("cloudregion_id"), self.Id)))
  114. } else {
  115. return zones.Equals("cloudregion_id", self.Id)
  116. }
  117. }
  118. func (self *SCloudregion) GetZoneCount() (int, error) {
  119. return self.GetZoneQuery().CountWithError()
  120. }
  121. func (self *SCloudregion) GetZones() ([]SZone, error) {
  122. q := self.GetZoneQuery()
  123. zones := []SZone{}
  124. err := db.FetchModelObjects(ZoneManager, q, &zones)
  125. if err != nil {
  126. return nil, err
  127. }
  128. return zones, nil
  129. }
  130. func (self *SCloudregion) GetZoneBySuffix(suffix string) (*SZone, error) {
  131. sq := ZoneManager.Query().SubQuery()
  132. q := sq.Query().Filter(
  133. sqlchemy.AND(
  134. sqlchemy.Equals(sq.Field("cloudregion_id"), self.Id),
  135. sqlchemy.Endswith(sq.Field("external_id"), suffix),
  136. ),
  137. )
  138. count, err := q.CountWithError()
  139. if err != nil {
  140. return nil, err
  141. }
  142. msg := suffix
  143. if count == 0 {
  144. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", msg)
  145. }
  146. if count > 1 {
  147. return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, "%s", msg)
  148. }
  149. zone := &SZone{}
  150. zone.SetModelManager(ZoneManager, zone)
  151. return zone, q.First(zone)
  152. }
  153. func (self *SCloudregion) GetGuestCount() (int, error) {
  154. return self.getGuestCountInternal(false)
  155. }
  156. func (self *SCloudregion) GetManagedGuestsQuery(managerId string) *sqlchemy.SQuery {
  157. q := GuestManager.Query().IsNotEmpty("external_id")
  158. hosts := HostManager.Query().Equals("manager_id", managerId).SubQuery()
  159. zones := ZoneManager.Query().Equals("cloudregion_id", self.Id).SubQuery()
  160. q = q.Join(hosts, sqlchemy.Equals(q.Field("host_id"), hosts.Field("id")))
  161. q = q.Join(zones, sqlchemy.Equals(hosts.Field("zone_id"), zones.Field("id")))
  162. return q
  163. }
  164. func (self *SCloudregion) GetManagedGuests(managerId string) ([]SGuest, error) {
  165. q := self.GetManagedGuestsQuery(managerId)
  166. ret := []SGuest{}
  167. err := db.FetchModelObjects(GuestManager, q, &ret)
  168. if err != nil {
  169. return nil, err
  170. }
  171. return ret, nil
  172. }
  173. func (self *SCloudregion) GetManagedGuestsCount(managerId string) (int, error) {
  174. return self.GetManagedGuestsQuery(managerId).CountWithError()
  175. }
  176. func (self *SCloudregion) GetManagedLoadbalancerQuery(managerId string) *sqlchemy.SQuery {
  177. return LoadbalancerManager.Query().
  178. IsNotEmpty("external_id").
  179. Equals("cloudregion_id", self.Id).
  180. Equals("manager_id", managerId)
  181. }
  182. func (self *SCloudregion) GetManagedLoadbalancers(managerId string) ([]SLoadbalancer, error) {
  183. q := self.GetManagedLoadbalancerQuery(managerId)
  184. ret := []SLoadbalancer{}
  185. err := db.FetchModelObjects(LoadbalancerManager, q, &ret)
  186. if err != nil {
  187. return nil, err
  188. }
  189. return ret, nil
  190. }
  191. func (self *SCloudregion) GetManagedLoadbalancerCount(managerId string) (int, error) {
  192. return self.GetManagedLoadbalancerQuery(managerId).CountWithError()
  193. }
  194. func (self *SCloudregion) GetGuestIncrementCount() (int, error) {
  195. return self.getGuestCountInternal(true)
  196. }
  197. func (self *SCloudregion) GetNetworkInterfaces() ([]SNetworkInterface, error) {
  198. interfaces := []SNetworkInterface{}
  199. q := NetworkInterfaceManager.Query().Equals("cloudregion_id", self.Id)
  200. err := db.FetchModelObjects(NetworkInterfaceManager, q, &interfaces)
  201. if err != nil {
  202. return nil, err
  203. }
  204. return interfaces, nil
  205. }
  206. func (self *SCloudregion) GetDBInstances(provider *SCloudprovider) ([]SDBInstance, error) {
  207. instances := []SDBInstance{}
  208. q := DBInstanceManager.Query().Equals("cloudregion_id", self.Id)
  209. if provider != nil {
  210. q = q.Equals("manager_id", provider.Id)
  211. }
  212. err := db.FetchModelObjects(DBInstanceManager, q, &instances)
  213. if err != nil {
  214. return nil, errors.Wrapf(err, "FetchModelObjects for region %s", self.Id)
  215. }
  216. return instances, nil
  217. }
  218. func (self *SCloudregion) GetDBInstanceBackups(provider *SCloudprovider, instance *SDBInstance) ([]SDBInstanceBackup, error) {
  219. backups := []SDBInstanceBackup{}
  220. q := DBInstanceBackupManager.Query().Equals("cloudregion_id", self.Id)
  221. if provider != nil {
  222. q = q.Equals("manager_id", provider.Id)
  223. }
  224. if instance != nil {
  225. q = q.Equals("dbinstance_id", instance.Id)
  226. }
  227. err := db.FetchModelObjects(DBInstanceBackupManager, q, &backups)
  228. if err != nil {
  229. return nil, errors.Wrapf(err, "FetchModelObjects for region %s", self.Id)
  230. }
  231. return backups, nil
  232. }
  233. func (self *SCloudregion) GetElasticcaches(provider *SCloudprovider) ([]SElasticcache, error) {
  234. instances := []SElasticcache{}
  235. q := ElasticcacheManager.Query().Equals("cloudregion_id", self.Id)
  236. if provider != nil {
  237. q = q.Equals("manager_id", provider.Id)
  238. }
  239. err := db.FetchModelObjects(ElasticcacheManager, q, &instances)
  240. if err != nil {
  241. return nil, errors.Wrapf(err, "GetElasticcaches for region %s", self.Id)
  242. }
  243. return instances, nil
  244. }
  245. func (self *SCloudregion) getGuestCountInternal(increment bool) (int, error) {
  246. zoneTable := ZoneManager.Query("id")
  247. if self.Id == api.DEFAULT_REGION_ID {
  248. zoneTable = zoneTable.Filter(sqlchemy.OR(sqlchemy.IsNull(zoneTable.Field("cloudregion_id")),
  249. sqlchemy.IsEmpty(zoneTable.Field("cloudregion_id")),
  250. sqlchemy.Equals(zoneTable.Field("cloudregion_id"), self.Id)))
  251. } else {
  252. zoneTable = zoneTable.Equals("cloudregion_id", self.Id)
  253. }
  254. sq := HostManager.Query("id").In("zone_id", zoneTable)
  255. query := GuestManager.Query().In("host_id", sq)
  256. if increment {
  257. year, month, _ := time.Now().UTC().Date()
  258. startOfMonth := time.Date(year, month, 1, 0, 0, 0, 0, time.UTC)
  259. query.GE("created_at", startOfMonth)
  260. }
  261. return query.CountWithError()
  262. }
  263. func (self *SCloudregion) GetVpcQuery() *sqlchemy.SQuery {
  264. vpcs := VpcManager.Query()
  265. if self.Id == api.DEFAULT_REGION_ID {
  266. return vpcs.Filter(sqlchemy.OR(sqlchemy.IsNull(vpcs.Field("cloudregion_id")),
  267. sqlchemy.IsEmpty(vpcs.Field("cloudregion_id")),
  268. sqlchemy.Equals(vpcs.Field("cloudregion_id"), self.Id)))
  269. }
  270. return vpcs.Equals("cloudregion_id", self.Id)
  271. }
  272. func (self *SCloudregion) GetVpcCount() (int, error) {
  273. return self.GetVpcQuery().CountWithError()
  274. }
  275. func (self *SCloudregion) GetVpcs() ([]SVpc, error) {
  276. vpcs := []SVpc{}
  277. q := self.GetVpcQuery()
  278. err := db.FetchModelObjects(VpcManager, q, &vpcs)
  279. if err != nil {
  280. return nil, errors.Wrap(err, "db.FetchModelObjects")
  281. }
  282. return vpcs, nil
  283. }
  284. func (self *SCloudregion) GetCloudproviderVpcs(managerId string) ([]SVpc, error) {
  285. vpcs := []SVpc{}
  286. q := self.GetVpcQuery().Equals("manager_id", managerId)
  287. err := db.FetchModelObjects(VpcManager, q, &vpcs)
  288. if err != nil {
  289. return nil, errors.Wrap(err, "db.FetchModelObjects")
  290. }
  291. return vpcs, nil
  292. }
  293. func (self *SCloudregion) GetDriver() IRegionDriver {
  294. provider := self.Provider
  295. if len(provider) == 0 {
  296. provider = api.CLOUD_PROVIDER_ONECLOUD
  297. }
  298. if !utils.IsInStringArray(provider, api.CLOUD_PROVIDERS) {
  299. log.Fatalf("Unsupported region provider %s", provider)
  300. }
  301. return GetRegionDriver(provider)
  302. }
  303. func (self *SCloudregion) getUsage(ctx context.Context) api.SCloudregionUsage {
  304. out := api.SCloudregionUsage{}
  305. out.VpcCount, _ = self.GetVpcCount()
  306. out.ZoneCount, _ = self.GetZoneCount()
  307. out.GuestCount, _ = self.GetGuestCount()
  308. out.NetworkCount, _ = self.GetNetworkCount(ctx)
  309. out.GuestIncrementCount, _ = self.GetGuestIncrementCount()
  310. return out
  311. }
  312. type SRegionUsageCount struct {
  313. Id string
  314. api.SCloudregionUsage
  315. }
  316. func (cm *SCloudregionManager) query(manager db.IModelManager, field string, regionIds []string, filter func(*sqlchemy.SQuery) *sqlchemy.SQuery) *sqlchemy.SSubQuery {
  317. q := manager.Query()
  318. if filter != nil {
  319. q = filter(q)
  320. }
  321. sq := q.SubQuery()
  322. return sq.Query(
  323. sq.Field("cloudregion_id"),
  324. sqlchemy.COUNT(field),
  325. ).In("cloudregion_id", regionIds).GroupBy(sq.Field("cloudregion_id")).SubQuery()
  326. }
  327. func (manager *SCloudregionManager) TotalResourceCount(regionIds []string) (map[string]api.SCloudregionUsage, error) {
  328. vpcSQ := manager.query(VpcManager, "vpc_cnt", regionIds, nil)
  329. zoneSQ := manager.query(ZoneManager, "zone_cnt", regionIds, nil)
  330. guestSQ := manager.query(GuestManager, "guest_cnt", regionIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  331. hosts := HostManager.Query().SubQuery()
  332. zones := ZoneManager.Query().SubQuery()
  333. sq := q.SubQuery()
  334. return sq.Query(
  335. sq.Field("id"),
  336. zones.Field("cloudregion_id").Label("cloudregion_id"),
  337. ).Join(hosts, sqlchemy.Equals(sq.Field("host_id"), hosts.Field("id"))).Join(zones, sqlchemy.Equals(zones.Field("id"), hosts.Field("zone_id")))
  338. })
  339. guestIncSQ := manager.query(GuestManager, "guest_increment_cnt", regionIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  340. hosts := HostManager.Query().SubQuery()
  341. zones := ZoneManager.Query().SubQuery()
  342. year, month, _ := time.Now().UTC().Date()
  343. startOfMonth := time.Date(year, month, 1, 0, 0, 0, 0, time.UTC)
  344. q = q.GE("created_at", startOfMonth)
  345. sq := q.SubQuery()
  346. return sq.Query(
  347. sq.Field("id"),
  348. zones.Field("cloudregion_id").Label("cloudregion_id"),
  349. ).Join(hosts, sqlchemy.Equals(sq.Field("host_id"), hosts.Field("id"))).Join(zones, sqlchemy.Equals(zones.Field("id"), hosts.Field("zone_id")))
  350. })
  351. networkSQ := manager.query(NetworkManager, "network_cnt", regionIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  352. wires := WireManager.Query().SubQuery()
  353. vpcs := VpcManager.Query().SubQuery()
  354. sq := q.SubQuery()
  355. return sq.Query(
  356. sq.Field("id"),
  357. vpcs.Field("cloudregion_id").Label("cloudregion_id"),
  358. ).Join(wires, sqlchemy.Equals(sq.Field("wire_id"), wires.Field("id"))).Join(vpcs, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id")))
  359. })
  360. regions := manager.Query().SubQuery()
  361. regionQ := regions.Query(
  362. sqlchemy.SUM("vpc_count", vpcSQ.Field("vpc_cnt")),
  363. sqlchemy.SUM("zone_count", zoneSQ.Field("zone_cnt")),
  364. sqlchemy.SUM("guest_count", guestSQ.Field("guest_cnt")),
  365. sqlchemy.SUM("guest_increment_count", guestIncSQ.Field("guest_increment_cnt")),
  366. sqlchemy.SUM("network_count", networkSQ.Field("network_cnt")),
  367. )
  368. regionQ.AppendField(regionQ.Field("id"))
  369. regionQ = regionQ.LeftJoin(vpcSQ, sqlchemy.Equals(regionQ.Field("id"), vpcSQ.Field("cloudregion_id")))
  370. regionQ = regionQ.LeftJoin(zoneSQ, sqlchemy.Equals(regionQ.Field("id"), zoneSQ.Field("cloudregion_id")))
  371. regionQ = regionQ.LeftJoin(guestSQ, sqlchemy.Equals(regionQ.Field("id"), guestSQ.Field("cloudregion_id")))
  372. regionQ = regionQ.LeftJoin(guestIncSQ, sqlchemy.Equals(regionQ.Field("id"), guestIncSQ.Field("cloudregion_id")))
  373. regionQ = regionQ.LeftJoin(networkSQ, sqlchemy.Equals(regionQ.Field("id"), networkSQ.Field("cloudregion_id")))
  374. regionQ = regionQ.Filter(sqlchemy.In(regionQ.Field("id"), regionIds)).GroupBy(regionQ.Field("id"))
  375. regionCount := []SRegionUsageCount{}
  376. err := regionQ.All(&regionCount)
  377. if err != nil {
  378. return nil, errors.Wrapf(err, "regionQ.All")
  379. }
  380. result := map[string]api.SCloudregionUsage{}
  381. for i := range regionCount {
  382. result[regionCount[i].Id] = regionCount[i].SCloudregionUsage
  383. }
  384. return result, nil
  385. }
  386. func (manager *SCloudregionManager) FetchCustomizeColumns(
  387. ctx context.Context,
  388. userCred mcclient.TokenCredential,
  389. query jsonutils.JSONObject,
  390. objs []interface{},
  391. fields stringutils2.SSortedStrings,
  392. isList bool,
  393. ) []api.CloudregionDetails {
  394. rows := make([]api.CloudregionDetails, len(objs))
  395. stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  396. regionIds := make([]string, len(objs))
  397. for i := range rows {
  398. region := objs[i].(*SCloudregion)
  399. rows[i] = api.CloudregionDetails{
  400. EnabledStatusStandaloneResourceDetails: stdRows[i],
  401. CloudEnv: region.GetCloudEnv(),
  402. }
  403. regionIds[i] = region.Id
  404. }
  405. count, err := manager.TotalResourceCount(regionIds)
  406. if err != nil {
  407. log.Errorf("TotalResourceCount")
  408. return rows
  409. }
  410. for i := range rows {
  411. rows[i].SCloudregionUsage, _ = count[regionIds[i]]
  412. }
  413. return rows
  414. }
  415. func (self *SCloudregion) GetServerSkus() ([]SServerSku, error) {
  416. skus := []SServerSku{}
  417. q := ServerSkuManager.Query().Equals("cloudregion_id", self.Id)
  418. err := db.FetchModelObjects(ServerSkuManager, q, &skus)
  419. if err != nil {
  420. return nil, err
  421. }
  422. return skus, nil
  423. }
  424. func (self *SCloudprovider) GetRegionByExternalIdPrefix(prefix string) ([]SCloudregion, error) {
  425. prefix = strings.TrimSuffix(prefix, "/")
  426. regions := make([]SCloudregion, 0)
  427. q := CloudregionManager.Query()
  428. q = q.Filter(
  429. sqlchemy.OR(
  430. sqlchemy.Startswith(q.Field("external_id"), prefix+"/"),
  431. sqlchemy.Equals(q.Field("external_id"), prefix),
  432. ),
  433. )
  434. err := db.FetchModelObjects(CloudregionManager, q, &regions)
  435. if err != nil {
  436. return nil, err
  437. }
  438. return regions, nil
  439. }
  440. func (manager *SCloudregionManager) GetRegionByProvider(provider string) ([]SCloudregion, error) {
  441. regions := make([]SCloudregion, 0)
  442. q := manager.Query().Equals("provider", provider)
  443. err := db.FetchModelObjects(manager, q, &regions)
  444. if err != nil {
  445. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  446. }
  447. return regions, nil
  448. }
  449. func (manager *SCloudregionManager) SyncRegions(
  450. ctx context.Context,
  451. userCred mcclient.TokenCredential,
  452. cloudProvider *SCloudprovider,
  453. externalIdPrefix string,
  454. regions []cloudprovider.ICloudRegion,
  455. ) (
  456. []SCloudregion,
  457. []cloudprovider.ICloudRegion,
  458. []SCloudproviderregion,
  459. compare.SyncResult,
  460. ) {
  461. lockman.LockRawObject(ctx, manager.Keyword(), externalIdPrefix)
  462. defer lockman.ReleaseRawObject(ctx, manager.Keyword(), externalIdPrefix)
  463. syncResult := compare.SyncResult{}
  464. localRegions := make([]SCloudregion, 0)
  465. remoteRegions := make([]cloudprovider.ICloudRegion, 0)
  466. cloudProviderRegions := make([]SCloudproviderregion, 0)
  467. dbRegions, err := cloudProvider.GetRegionByExternalIdPrefix(externalIdPrefix)
  468. if err != nil {
  469. syncResult.Error(err)
  470. return nil, nil, nil, syncResult
  471. }
  472. log.Debugf("Region with provider %s %d -> %d", externalIdPrefix, len(regions), len(dbRegions))
  473. removed := make([]SCloudregion, 0)
  474. commondb := make([]SCloudregion, 0)
  475. commonext := make([]cloudprovider.ICloudRegion, 0)
  476. added := make([]cloudprovider.ICloudRegion, 0)
  477. err = compare.CompareSets(dbRegions, regions, &removed, &commondb, &commonext, &added)
  478. if err != nil {
  479. syncResult.Error(errors.Wrapf(err, "CompareSets"))
  480. return nil, nil, nil, syncResult
  481. }
  482. for i := 0; i < len(removed); i += 1 {
  483. err = removed[i].syncRemoveCloudRegion(ctx, userCred, cloudProvider)
  484. if err != nil {
  485. syncResult.DeleteError(err)
  486. } else {
  487. syncResult.Delete()
  488. }
  489. }
  490. for i := 0; i < len(commondb); i += 1 {
  491. // update
  492. err = commondb[i].syncWithCloudRegion(ctx, userCred, commonext[i])
  493. if err != nil {
  494. syncResult.UpdateError(err)
  495. } else {
  496. cpr, err := CloudproviderRegionManager.FetchByIdsOrCreate(cloudProvider.Id, commondb[i].Id)
  497. if err != nil {
  498. syncResult.UpdateError(err)
  499. } else {
  500. cpr.setCapabilities(ctx, userCred, commonext[i].GetCapabilities())
  501. cloudProviderRegions = append(cloudProviderRegions, *cpr)
  502. }
  503. localRegions = append(localRegions, commondb[i])
  504. remoteRegions = append(remoteRegions, commonext[i])
  505. syncResult.Update()
  506. }
  507. }
  508. for i := 0; i < len(added); i += 1 {
  509. new, err := manager.newFromCloudRegion(ctx, userCred, added[i], cloudProvider)
  510. if err != nil {
  511. syncResult.AddError(err)
  512. } else {
  513. cpr, err := CloudproviderRegionManager.FetchByIdsOrCreate(cloudProvider.Id, new.Id)
  514. if err != nil {
  515. syncResult.AddError(err)
  516. } else {
  517. cpr.setCapabilities(ctx, userCred, added[i].GetCapabilities())
  518. cloudProviderRegions = append(cloudProviderRegions, *cpr)
  519. }
  520. localRegions = append(localRegions, *new)
  521. remoteRegions = append(remoteRegions, added[i])
  522. syncResult.Add()
  523. }
  524. }
  525. return localRegions, remoteRegions, cloudProviderRegions, syncResult
  526. }
  527. func (self *SCloudregion) syncRemoveCloudRegion(ctx context.Context, userCred mcclient.TokenCredential, cloudProvider *SCloudprovider) error {
  528. lockman.LockObject(ctx, self)
  529. defer lockman.ReleaseObject(ctx, self)
  530. return self.purgeAll(ctx, cloudProvider.Id)
  531. }
  532. func (self *SCloudregion) syncWithCloudRegion(ctx context.Context, userCred mcclient.TokenCredential, cloudRegion cloudprovider.ICloudRegion) error {
  533. err := CloudregionManager.SyncI18ns(ctx, userCred, self, cloudRegion.GetI18n())
  534. if err != nil {
  535. return errors.Wrap(err, "SyncI18ns")
  536. }
  537. diff, err := db.UpdateWithLock(ctx, self, func() error {
  538. if !utils.IsInStringArray(self.Provider, api.PRIVATE_CLOUD_PROVIDERS) {
  539. self.Name = cloudRegion.GetName()
  540. }
  541. self.Status = cloudRegion.GetStatus()
  542. geoInfo := cloudRegion.GetGeographicInfo()
  543. if !self.SGeographicInfo.IsEquals(geoInfo) {
  544. self.SGeographicInfo = geoInfo
  545. }
  546. self.Provider = cloudRegion.GetProvider()
  547. self.Environment = cloudRegion.GetCloudEnv()
  548. self.SetEnabled(true)
  549. self.IsEmulated = cloudRegion.IsEmulated()
  550. return nil
  551. })
  552. if err != nil && errors.Cause(err) != sqlchemy.ErrNoDataToUpdate {
  553. log.Errorf("syncWithCloudRegion %s", err)
  554. return err
  555. }
  556. db.OpsLog.LogSyncUpdate(self, diff, userCred)
  557. return nil
  558. }
  559. func (manager *SCloudregionManager) newFromCloudRegion(ctx context.Context, userCred mcclient.TokenCredential, cloudRegion cloudprovider.ICloudRegion, provider *SCloudprovider) (*SCloudregion, error) {
  560. region := SCloudregion{}
  561. region.SetModelManager(manager, &region)
  562. region.ExternalId = cloudRegion.GetGlobalId()
  563. region.SGeographicInfo = cloudRegion.GetGeographicInfo()
  564. region.Status = cloudRegion.GetStatus()
  565. region.SetEnabled(true)
  566. region.Provider = cloudRegion.GetProvider()
  567. region.Environment = cloudRegion.GetCloudEnv()
  568. region.IsEmulated = cloudRegion.IsEmulated()
  569. var err error
  570. err = func() error {
  571. lockman.LockRawObject(ctx, manager.Keyword(), "name")
  572. defer lockman.ReleaseRawObject(ctx, manager.Keyword(), "name")
  573. region.Name, err = db.GenerateName(ctx, manager, nil, cloudRegion.GetName())
  574. if err != nil {
  575. return errors.Wrapf(err, "db.GenerateName")
  576. }
  577. return manager.TableSpec().Insert(ctx, &region)
  578. }()
  579. if err != nil {
  580. return nil, err
  581. }
  582. err = manager.SyncI18ns(ctx, userCred, &region, cloudRegion.GetI18n())
  583. if err != nil {
  584. return nil, errors.Wrap(err, "SyncI18ns")
  585. }
  586. db.OpsLog.LogEvent(&region, db.ACT_CREATE, region.GetShortDesc(ctx), userCred)
  587. return &region, nil
  588. }
  589. func (self *SCloudregion) PerformDefaultVpc(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  590. vpcs, err := self.GetVpcs()
  591. if err != nil {
  592. return nil, err
  593. }
  594. vpcStr, _ := data.GetString("vpc")
  595. if len(vpcStr) == 0 {
  596. return nil, httperrors.NewMissingParameterError("vpc")
  597. }
  598. findVpc := false
  599. for _, vpc := range vpcs {
  600. if vpc.Id == vpcStr || vpc.Name == vpcStr {
  601. findVpc = true
  602. break
  603. }
  604. }
  605. if !findVpc {
  606. return nil, httperrors.NewResourceNotFoundError("VPC %s not found", vpcStr)
  607. }
  608. for _, vpc := range vpcs {
  609. if vpc.Id == vpcStr || vpc.Name == vpcStr {
  610. err = vpc.setDefault(true)
  611. } else {
  612. err = vpc.setDefault(false)
  613. }
  614. if err != nil {
  615. return nil, err
  616. }
  617. }
  618. return nil, nil
  619. }
  620. func (manager *SCloudregionManager) FetchRegionById(id string) *SCloudregion {
  621. obj, err := manager.FetchById(id)
  622. if err != nil {
  623. log.Errorf("region %s %s", id, err)
  624. return nil
  625. }
  626. return obj.(*SCloudregion)
  627. }
  628. func (manager *SCloudregionManager) InitializeData() error {
  629. // check if default region exists
  630. obj, err := manager.FetchById(api.DEFAULT_REGION_ID)
  631. if err != nil {
  632. if err == sql.ErrNoRows {
  633. defRegion := SCloudregion{}
  634. defRegion.Id = api.DEFAULT_REGION_ID
  635. defRegion.Name = "Default"
  636. defRegion.SetEnabled(true)
  637. defRegion.Description = "Default Region"
  638. defRegion.Status = api.CLOUD_REGION_STATUS_INSERVER
  639. defRegion.Provider = api.CLOUD_PROVIDER_ONECLOUD
  640. defRegion.SetModelManager(manager, &defRegion)
  641. err := manager.TableSpec().Insert(context.TODO(), &defRegion)
  642. if err != nil {
  643. return errors.Wrap(err, "insert default region")
  644. }
  645. } else {
  646. return errors.Wrap(err, "fetch default region")
  647. }
  648. } else if region := obj.(*SCloudregion); region.Provider != api.CLOUD_PROVIDER_ONECLOUD {
  649. _, err := db.Update(region, func() error {
  650. region.Provider = api.CLOUD_PROVIDER_ONECLOUD
  651. return nil
  652. })
  653. if err != nil {
  654. return errors.Wrap(err, "update default region provider")
  655. }
  656. }
  657. return nil
  658. }
  659. func getCloudRegionIdByDomainId(domainId string) *sqlchemy.SSubQuery {
  660. cloudproviderregions := CloudproviderRegionManager.Query().SubQuery()
  661. // not managed region
  662. q1 := CloudregionManager.Query("id").Equals("provider", api.CLOUD_PROVIDER_ONECLOUD)
  663. // managed region
  664. q2 := cloudproviderregions.Query(cloudproviderregions.Field("cloudregion_id", "id"))
  665. providerIds := CloudproviderManager.Query("id")
  666. providerIds = CloudproviderManager.filterByDomainId(providerIds, domainId)
  667. providersIdsQ := providerIds.Distinct().SubQuery()
  668. q2 = q2.Join(providersIdsQ, sqlchemy.Equals(providersIdsQ.Field("id"), cloudproviderregions.Field("cloudprovider_id")))
  669. return sqlchemy.Union(q1, q2).Query().SubQuery()
  670. }
  671. func queryCloudregionIdsByProviders(providerField string, providerStrs []string) *sqlchemy.SQuery {
  672. q := CloudregionManager.Query("id")
  673. oneCloud, providers := splitProviders(providerStrs)
  674. conds := make([]sqlchemy.ICondition, 0)
  675. if len(providers) > 0 {
  676. cloudproviders := CloudproviderManager.Query().SubQuery()
  677. cloudaccounts := CloudaccountManager.Query().SubQuery()
  678. subq := CloudproviderRegionManager.Query("cloudregion_id")
  679. subq = subq.Join(cloudproviders, sqlchemy.Equals(subq.Field("cloudprovider_id"), cloudproviders.Field("id")))
  680. subq = subq.Join(cloudaccounts, sqlchemy.Equals(cloudproviders.Field("cloudaccount_id"), cloudaccounts.Field("id")))
  681. subq = subq.Filter(sqlchemy.In(cloudaccounts.Field(providerField), providers))
  682. conds = append(conds, sqlchemy.In(q.Field("id"), subq.SubQuery()))
  683. }
  684. if oneCloud {
  685. conds = append(conds, sqlchemy.Equals(q.Field("provider"), api.CLOUD_PROVIDER_ONECLOUD))
  686. }
  687. if len(conds) == 1 {
  688. q = q.Filter(conds[0])
  689. } else if len(conds) == 2 {
  690. q = q.Filter(sqlchemy.OR(conds...))
  691. }
  692. return q
  693. }
  694. func (manager *SCloudregionManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  695. if field == "region" {
  696. q = q.AppendField(q.Field("name").Label("region")).Distinct()
  697. return q, nil
  698. }
  699. q, err := manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
  700. if err == nil {
  701. return q, nil
  702. }
  703. return q, httperrors.ErrNotFound
  704. }
  705. func (manager *SCloudregionManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.CloudregionListInput) (*sqlchemy.SQuery, error) {
  706. q, err := manager.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
  707. if err != nil {
  708. return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields")
  709. }
  710. if db.NeedOrderQuery([]string{query.OrderByZoneCount}) {
  711. zQ := ZoneManager.Query()
  712. zQ = zQ.AppendField(zQ.Field("cloudregion_id"), sqlchemy.COUNT("zone_count", zQ.Field("cloudregion_id")))
  713. zQ = zQ.GroupBy(zQ.Field("cloudregion_id"))
  714. zSQ := zQ.SubQuery()
  715. q = q.LeftJoin(zSQ, sqlchemy.Equals(zSQ.Field("cloudregion_id"), q.Field("id")))
  716. q = q.AppendField(q.QueryFields()...)
  717. q = q.AppendField(zSQ.Field("zone_count"))
  718. q = db.OrderByFields(q, []string{query.OrderByZoneCount}, []sqlchemy.IQueryField{q.Field("zone_count")})
  719. }
  720. if db.NeedOrderQuery([]string{query.OrderByVpcCount}) {
  721. vQ := VpcManager.Query()
  722. vQ = vQ.AppendField(vQ.Field("cloudregion_id"), sqlchemy.COUNT("vpc_count", vQ.Field("cloudregion_id")))
  723. vQ = vQ.GroupBy(vQ.Field("cloudregion_id"))
  724. vSQ := vQ.SubQuery()
  725. q = q.LeftJoin(vSQ, sqlchemy.Equals(vSQ.Field("cloudregion_id"), q.Field("id")))
  726. q = q.AppendField(q.QueryFields()...)
  727. q = q.AppendField(vSQ.Field("vpc_count"))
  728. q = db.OrderByFields(q, []string{query.OrderByZoneCount}, []sqlchemy.IQueryField{q.Field("vpc_count")})
  729. }
  730. if db.NeedOrderQuery([]string{query.OrderByGuestCount}) {
  731. guestQ := GuestManager.Query()
  732. guestQ = guestQ.AppendField(guestQ.Field("host_id"), sqlchemy.COUNT("guest_count"))
  733. guestQ = guestQ.GroupBy(guestQ.Field("host_id"))
  734. guestSQ := guestQ.SubQuery()
  735. hostQ := HostManager.Query()
  736. hostQ = hostQ.LeftJoin(guestSQ, sqlchemy.Equals(guestSQ.Field("host_id"), hostQ.Field("id")))
  737. hostQ = hostQ.AppendField(hostQ.QueryFields()...)
  738. hostQ = hostQ.AppendField(hostQ.Field("zone_id"), sqlchemy.COUNT("guest_count", guestSQ.Field("guest_count")))
  739. hostQ = hostQ.GroupBy("zone_id")
  740. hostSQ := hostQ.SubQuery()
  741. zQ := ZoneManager.Query()
  742. zQ = zQ.AppendField(zQ.Field("cloudregion_id"), sqlchemy.COUNT("guest_count", hostSQ.Field("guest_count")))
  743. zQ = zQ.GroupBy(zQ.Field("cloudregion_id"))
  744. zQ = zQ.LeftJoin(hostSQ, sqlchemy.Equals(zQ.Field("id"), hostSQ.Field("zone_id")))
  745. zSQ := zQ.SubQuery()
  746. q = q.LeftJoin(zSQ, sqlchemy.Equals(zSQ.Field("cloudregion_id"), q.Field("id")))
  747. q = q.AppendField(q.QueryFields()...)
  748. q = q.AppendField(zSQ.Field("guest_count"))
  749. q = db.OrderByFields(q, []string{query.OrderByGuestCount}, []sqlchemy.IQueryField{q.Field("guest_count")})
  750. }
  751. return q, nil
  752. }
  753. // 云平台区域列表
  754. func (manager *SCloudregionManager) ListItemFilter(
  755. ctx context.Context,
  756. q *sqlchemy.SQuery,
  757. userCred mcclient.TokenCredential,
  758. query api.CloudregionListInput,
  759. ) (*sqlchemy.SQuery, error) {
  760. var err error
  761. providerStrs := query.Providers
  762. if len(providerStrs) > 0 {
  763. subq := queryCloudregionIdsByProviders("provider", providerStrs)
  764. q = q.In("id", subq.SubQuery())
  765. }
  766. brandStrs := query.Brands
  767. if len(brandStrs) > 0 {
  768. subq := queryCloudregionIdsByProviders("brand", brandStrs)
  769. q = q.In("id", subq.SubQuery())
  770. }
  771. q, err = manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
  772. if err != nil {
  773. return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemFilter")
  774. }
  775. q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
  776. if err != nil {
  777. return nil, errors.Wrap(err, "")
  778. }
  779. cloudEnvStr := query.CloudEnv
  780. if cloudEnvStr == api.CLOUD_ENV_PUBLIC_CLOUD {
  781. q = q.In("provider", cloudprovider.GetPublicProviders())
  782. }
  783. if cloudEnvStr == api.CLOUD_ENV_PRIVATE_CLOUD {
  784. q = q.In("provider", cloudprovider.GetPrivateProviders())
  785. }
  786. if cloudEnvStr == api.CLOUD_ENV_ON_PREMISE {
  787. q = q.Filter(sqlchemy.OR(
  788. sqlchemy.In(q.Field("provider"), cloudprovider.GetOnPremiseProviders()),
  789. sqlchemy.Equals(q.Field("provider"), api.CLOUD_PROVIDER_ONECLOUD),
  790. ))
  791. }
  792. if cloudEnvStr == api.CLOUD_ENV_PRIVATE_ON_PREMISE {
  793. q = q.Filter(sqlchemy.OR(
  794. sqlchemy.In(q.Field("provider"), cloudprovider.GetPrivateProviders()),
  795. sqlchemy.In(q.Field("provider"), cloudprovider.GetOnPremiseProviders()),
  796. sqlchemy.Equals(q.Field("provider"), api.CLOUD_PROVIDER_ONECLOUD),
  797. ))
  798. }
  799. if query.IsManaged != nil {
  800. if *query.IsManaged {
  801. q = q.IsNotEmpty("external_id")
  802. } else {
  803. q = q.IsNullOrEmpty("external_id")
  804. }
  805. }
  806. managerStr := query.CloudproviderId
  807. if len(managerStr) > 0 {
  808. subq := CloudproviderRegionManager.QueryRelatedRegionIds(nil, managerStr...)
  809. q = q.In("id", subq)
  810. }
  811. accountArr := query.CloudaccountId
  812. if len(accountArr) > 0 {
  813. subq := CloudproviderRegionManager.QueryRelatedRegionIds(accountArr)
  814. q = q.In("id", subq)
  815. }
  816. domainId, err := db.FetchQueryDomain(ctx, userCred, jsonutils.Marshal(query))
  817. if len(domainId) > 0 {
  818. q = q.In("id", getCloudRegionIdByDomainId(domainId))
  819. }
  820. usableNet := (query.Usable != nil && *query.Usable)
  821. usableVpc := (query.UsableVpc != nil && *query.UsableVpc)
  822. if usableNet || usableVpc {
  823. providers := usableCloudProviders().SubQuery()
  824. networks := NetworkManager.Query().SubQuery()
  825. wires := WireManager.Query().SubQuery()
  826. vpcs := VpcManager.Query().SubQuery()
  827. sq := vpcs.Query(sqlchemy.DISTINCT("cloudregion_id", vpcs.Field("cloudregion_id")))
  828. if usableNet {
  829. sq = sq.Join(wires, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id")))
  830. sq = sq.Join(networks, sqlchemy.Equals(wires.Field("id"), networks.Field("wire_id")))
  831. }
  832. sq = sq.Join(providers, sqlchemy.Equals(vpcs.Field("manager_id"), providers.Field("id")))
  833. if usableNet {
  834. sq = sq.Filter(sqlchemy.Equals(networks.Field("status"), api.NETWORK_STATUS_AVAILABLE))
  835. }
  836. if usableVpc {
  837. sq = sq.Filter(sqlchemy.Equals(vpcs.Field("status"), api.VPC_STATUS_AVAILABLE))
  838. }
  839. sq2 := vpcs.Query(sqlchemy.DISTINCT("cloudregion_id", vpcs.Field("cloudregion_id")))
  840. if usableNet {
  841. sq2 = sq2.Join(wires, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id")))
  842. sq2 = sq2.Join(networks, sqlchemy.Equals(wires.Field("id"), networks.Field("wire_id")))
  843. sq2 = sq2.Filter(sqlchemy.Equals(networks.Field("status"), api.NETWORK_STATUS_AVAILABLE))
  844. }
  845. sq2 = sq2.Filter(sqlchemy.IsNullOrEmpty(vpcs.Field("manager_id")))
  846. if usableVpc {
  847. sq2 = sq2.Filter(sqlchemy.Equals(vpcs.Field("status"), api.VPC_STATUS_AVAILABLE))
  848. }
  849. q = q.Filter(sqlchemy.OR(
  850. sqlchemy.In(q.Field("id"), sq.SubQuery()),
  851. sqlchemy.In(q.Field("id"), sq2.SubQuery()),
  852. ))
  853. service := query.Service
  854. switch service {
  855. case DBInstanceManager.KeywordPlural():
  856. regionSQ := CloudproviderCapabilityManager.Query("cloudregion_id").Equals("capability", cloudprovider.CLOUD_CAPABILITY_RDS).SubQuery()
  857. q = q.In("id", regionSQ)
  858. case ElasticcacheManager.KeywordPlural():
  859. regionSQ := CloudproviderCapabilityManager.Query("cloudregion_id").Equals("capability", cloudprovider.CLOUD_CAPABILITY_CACHE).SubQuery()
  860. q = q.In("id", regionSQ)
  861. default:
  862. break
  863. }
  864. }
  865. cityStr := query.City
  866. if cityStr == "Other" {
  867. q = q.IsNullOrEmpty("city")
  868. } else if len(cityStr) > 0 {
  869. q = q.Equals("city", cityStr)
  870. }
  871. if len(query.Environment) > 0 {
  872. q = q.In("environment", query.Environment)
  873. }
  874. if len(query.Capability) > 0 {
  875. subq := CloudproviderCapabilityManager.Query("cloudregion_id").In("capability", query.Capability).Distinct().SubQuery()
  876. q = q.In("id", subq)
  877. }
  878. return q, nil
  879. }
  880. /*func (manager *SCloudregionManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
  881. return manager.SEnabledStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, data)
  882. }*/
  883. func (self *SCloudregion) isManaged() bool {
  884. if len(self.ExternalId) > 0 {
  885. return true
  886. } else {
  887. return false
  888. }
  889. }
  890. func (self *SCloudregion) getCloudaccounts() []SCloudaccount {
  891. providers := CloudproviderManager.Query().SubQuery()
  892. providerregions := CloudproviderRegionManager.Query().SubQuery()
  893. q := CloudaccountManager.Query()
  894. q = q.Join(providers, sqlchemy.Equals(q.Field("id"), providers.Field("cloudaccount_id")))
  895. q = q.Join(providerregions, sqlchemy.Equals(providers.Field("id"), providerregions.Field("cloudprovider_id")))
  896. q = q.Filter(sqlchemy.Equals(providerregions.Field("cloudregion_id"), self.Id))
  897. q = q.Distinct()
  898. accounts := make([]SCloudaccount, 0)
  899. err := db.FetchModelObjects(CloudaccountManager, q, &accounts)
  900. if err != nil {
  901. if errors.Cause(err) != sql.ErrNoRows {
  902. log.Errorf("get cloudregion's cloudaccounts fail: %s", err)
  903. }
  904. return nil
  905. }
  906. return accounts
  907. }
  908. func (self *SCloudregion) GetRegionCloudenvInfo() api.CloudenvResourceInfo {
  909. info := api.CloudenvResourceInfo{
  910. CloudEnv: self.GetCloudEnv(),
  911. Provider: self.Provider,
  912. Environment: self.Environment,
  913. }
  914. return info
  915. }
  916. func (self *SCloudregion) GetI18N(ctx context.Context) *jsonutils.JSONDict {
  917. return self.GetModelI18N(ctx, self)
  918. }
  919. func (self *SCloudregion) GetRegionInfo(ctx context.Context) api.CloudregionResourceInfo {
  920. name := self.Name
  921. if v, ok := self.GetModelKeyI18N(ctx, self, "name"); ok {
  922. name = v
  923. }
  924. return api.CloudregionResourceInfo{
  925. Region: name,
  926. Cloudregion: name,
  927. RegionId: self.Id,
  928. RegionExtId: fetchExternalId(self.ExternalId),
  929. RegionExternalId: self.ExternalId,
  930. }
  931. }
  932. func (self *SCloudregion) GetRegionExtId() string {
  933. return fetchExternalId(self.ExternalId)
  934. }
  935. func (self *SCloudregion) ValidateUpdateCondition(ctx context.Context) error {
  936. if len(self.ExternalId) > 0 {
  937. return httperrors.NewConflictError("Cannot update external resource")
  938. }
  939. return self.SEnabledStatusStandaloneResourceBase.ValidateUpdateCondition(ctx)
  940. }
  941. func (self *SCloudregion) SyncVpcs(ctx context.Context, userCred mcclient.TokenCredential, iregion cloudprovider.ICloudRegion, provider *SCloudprovider) error {
  942. syncResults, syncRange := SSyncResultSet{}, &SSyncRange{}
  943. syncRegionVPCs(ctx, userCred, syncResults, provider, self, iregion, syncRange)
  944. return nil
  945. }
  946. func (self *SCloudregion) GetDetailsCapability(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  947. capa, err := GetCapabilities(ctx, userCred, query, self, nil)
  948. if err != nil {
  949. return nil, err
  950. }
  951. return jsonutils.Marshal(&capa), nil
  952. }
  953. func (self *SCloudregion) GetDetailsDiskCapability(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  954. capa, err := GetDiskCapabilities(ctx, userCred, query, self, nil)
  955. if err != nil {
  956. return nil, err
  957. }
  958. return jsonutils.Marshal(&capa), nil
  959. }
  960. func (self *SCloudregion) GetNetworkCount(ctx context.Context) (int, error) {
  961. return getNetworkCount(ctx, nil, nil, rbacscope.ScopeSystem, self, nil)
  962. }
  963. func (self *SCloudregion) getMinNicCount() int {
  964. return options.Options.MinNicCount
  965. }
  966. func (self *SCloudregion) getMaxNicCount() int {
  967. if self.isManaged() {
  968. return options.Options.MaxManagedNicCount
  969. }
  970. return options.Options.MaxNormalNicCount
  971. }
  972. func (self *SCloudregion) getMinDataDiskCount() int {
  973. return options.Options.MinDataDiskCount
  974. }
  975. func (self *SCloudregion) getMaxDataDiskCount() int {
  976. return options.Options.MaxDataDiskCount
  977. }
  978. func (manager *SCloudregionManager) FetchDefaultRegion() *SCloudregion {
  979. return manager.FetchRegionById(api.DEFAULT_REGION_ID)
  980. }
  981. func (self *SCloudregion) GetCloudEnv() string {
  982. return cloudprovider.GetProviderCloudEnv(self.Provider)
  983. }
  984. func (self *SCloudregion) GetSchedtags() []SSchedtag {
  985. return GetSchedtags(CloudregionschedtagManager, self.Id)
  986. }
  987. func (self *SCloudregion) GetDynamicConditionInput() *jsonutils.JSONDict {
  988. return jsonutils.Marshal(self).(*jsonutils.JSONDict)
  989. }
  990. func (self *SCloudregion) PerformSetSchedtag(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  991. return PerformSetResourceSchedtag(self, ctx, userCred, query, data)
  992. }
  993. func (self *SCloudregion) PerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.CloudregionPurgeInput) (jsonutils.JSONObject, error) {
  994. if self.Id == api.DEFAULT_REGION_ID {
  995. return nil, httperrors.NewProtectedResourceError("not allow to delete default cloud region")
  996. }
  997. if len(input.ManagerId) == 0 {
  998. return nil, httperrors.NewMissingParameterError("manager_id")
  999. }
  1000. return nil, self.purgeAll(ctx, input.ManagerId)
  1001. }
  1002. func (self *SCloudregion) GetSchedtagJointManager() ISchedtagJointManager {
  1003. return CloudregionschedtagManager
  1004. }
  1005. func (self *SCloudregion) ClearSchedDescCache() error {
  1006. zones, err := self.GetZones()
  1007. if err != nil {
  1008. return errors.Wrap(err, "get zones")
  1009. }
  1010. for i := range zones {
  1011. if err := zones[i].ClearSchedDescCache(); err != nil {
  1012. return errors.Wrapf(err, "clean zone %s sched cache", zones[i].GetName())
  1013. }
  1014. }
  1015. return nil
  1016. }
  1017. func (self *SCloudregion) GetCloudimages() ([]SCloudimage, error) {
  1018. q := CloudimageManager.Query().Equals("cloudregion_id", self.Id)
  1019. images := []SCloudimage{}
  1020. err := db.FetchModelObjects(CloudimageManager, q, &images)
  1021. if err != nil {
  1022. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  1023. }
  1024. return images, nil
  1025. }
  1026. func (self *SCloudregion) GetSystemImageCount() (int, error) {
  1027. sq := CloudimageManager.Query("external_id").Equals("cloudregion_id", self.Id)
  1028. q := CachedimageManager.Query().Equals("image_type", cloudprovider.ImageTypeSystem).In("external_id", sq.SubQuery())
  1029. return q.CountWithError()
  1030. }
  1031. func (self *SCloudregion) SyncCloudImages(ctx context.Context, userCred mcclient.TokenCredential, refresh, xor bool) error {
  1032. lockman.LockRawObject(ctx, CloudimageManager.Keyword(), self.Id)
  1033. defer lockman.ReleaseRawObject(ctx, CloudimageManager.Keyword(), self.Id)
  1034. systemImageCount, err := self.GetSystemImageCount()
  1035. if err != nil {
  1036. return errors.Wrapf(err, "GetSystemImageCount")
  1037. }
  1038. dbImages, err := self.GetCloudimages()
  1039. if err != nil {
  1040. return errors.Wrapf(err, "GetCloudimages")
  1041. }
  1042. if len(dbImages) > 0 && systemImageCount > 0 && !refresh {
  1043. return nil
  1044. }
  1045. meta, err := yunionmeta.FetchYunionmeta(ctx)
  1046. if err != nil {
  1047. return errors.Wrapf(err, "FetchYunionmeta")
  1048. }
  1049. iImages := []SCachedimage{}
  1050. err = meta.List(CloudimageManager.Keyword(), self.ExternalId, &iImages)
  1051. if err != nil {
  1052. return errors.Wrapf(err, "GetCloudimages")
  1053. }
  1054. removed := make([]SCloudimage, 0)
  1055. commondb := make([]SCloudimage, 0)
  1056. commonext := make([]SCachedimage, 0)
  1057. added := make([]SCachedimage, 0)
  1058. err = compare.CompareSets(dbImages, iImages, &removed, &commondb, &commonext, &added)
  1059. if err != nil {
  1060. return errors.Wrapf(err, "compare.CompareSets")
  1061. }
  1062. result := compare.SyncResult{}
  1063. for i := 0; i < len(removed); i++ {
  1064. err := removed[i].syncRemove(ctx, userCred)
  1065. if err != nil {
  1066. result.DeleteError(err)
  1067. continue
  1068. }
  1069. result.Delete()
  1070. }
  1071. if !xor {
  1072. for i := 0; i < len(commonext); i++ {
  1073. err := commondb[i].syncWithImage(ctx, userCred, commonext[i], self)
  1074. if err != nil {
  1075. result.UpdateError(errors.Wrapf(err, "updateCachedImage"))
  1076. continue
  1077. }
  1078. result.Update()
  1079. }
  1080. }
  1081. for i := 0; i < len(added); i++ {
  1082. err = self.newCloudimage(ctx, userCred, added[i])
  1083. if err != nil {
  1084. result.AddError(errors.Wrapf(err, "newCloudimage"))
  1085. continue
  1086. }
  1087. result.Add()
  1088. }
  1089. log.Infof("Sync Cloudimages for region %s result: %s", self.Name, result.Result())
  1090. return nil
  1091. }
  1092. func (self *SCloudregion) GetStoragecaches() ([]SStoragecache, error) {
  1093. zones := ZoneManager.Query("id").Equals("cloudregion_id", self.Id).SubQuery()
  1094. sq := StorageManager.Query("storagecache_id").In("zone_id", zones).SubQuery()
  1095. q := StoragecacheManager.Query().In("id", sq)
  1096. caches := []SStoragecache{}
  1097. err := db.FetchModelObjects(StoragecacheManager, q, &caches)
  1098. if err != nil {
  1099. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  1100. }
  1101. return caches, nil
  1102. }
  1103. func (self *SCloudregion) newCloudimage(ctx context.Context, userCred mcclient.TokenCredential, iImage SCachedimage) error {
  1104. externalId := iImage.GetGlobalId()
  1105. lockman.LockRawObject(ctx, CachedimageManager.Keyword(), externalId)
  1106. defer lockman.ReleaseRawObject(ctx, CachedimageManager.Keyword(), externalId)
  1107. _, err := db.FetchByExternalId(CachedimageManager, externalId)
  1108. if err != nil {
  1109. if errors.Cause(err) != sql.ErrNoRows {
  1110. return errors.Wrapf(err, "db.FetchModelObjects(%s)", externalId)
  1111. }
  1112. image := &iImage
  1113. image.SetModelManager(CachedimageManager, image)
  1114. meta, err := yunionmeta.FetchYunionmeta(ctx)
  1115. if err != nil {
  1116. return err
  1117. }
  1118. skuUrl := self.getMetaUrl(meta.ImageBase, externalId)
  1119. err = meta.Get(skuUrl, image)
  1120. if err != nil {
  1121. return errors.Wrapf(err, "Get")
  1122. }
  1123. image.IsPublic = true
  1124. s := auth.GetAdminSession(ctx, options.Options.Region)
  1125. image.ProjectId = s.GetProjectId()
  1126. err = CachedimageManager.TableSpec().Insert(ctx, image)
  1127. if err != nil {
  1128. return errors.Wrapf(err, "Insert cachedimage")
  1129. }
  1130. }
  1131. cloudimage := &SCloudimage{}
  1132. cloudimage.SetModelManager(CloudimageManager, cloudimage)
  1133. cloudimage.Name = iImage.Name
  1134. cloudimage.CloudregionId = self.Id
  1135. cloudimage.ExternalId = externalId
  1136. err = CloudimageManager.TableSpec().Insert(ctx, cloudimage)
  1137. if err != nil {
  1138. return errors.Wrapf(err, "Insert cloudimage")
  1139. }
  1140. return nil
  1141. }
  1142. func (manager *SCloudregionManager) PerformSyncSkus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudregionSkuSyncInput) (jsonutils.JSONObject, error) {
  1143. return PerformActionSyncSkus(ctx, userCred, input.Resource, input.SkuSyncInput)
  1144. }
  1145. func (manager *SCloudregionManager) GetPropertySyncTasks(ctx context.Context, userCred mcclient.TokenCredential, query api.SkuTaskQueryInput) (jsonutils.JSONObject, error) {
  1146. return GetPropertySkusSyncTasks(ctx, userCred, query)
  1147. }
  1148. func (self *SCloudregion) PerformSyncImages(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.SyncImagesInput) (jsonutils.JSONObject, error) {
  1149. return nil, self.StartSyncImagesTask(ctx, userCred, "")
  1150. }
  1151. func (self *SCloudregion) StartSyncImagesTask(ctx context.Context, userCred mcclient.TokenCredential, parentId string) error {
  1152. task, err := taskman.TaskManager.NewTask(ctx, "CloudregionSyncImagesTask", self, userCred, nil, "", "", nil)
  1153. if err != nil {
  1154. return errors.Wrapf(err, "NewTask")
  1155. }
  1156. task.ScheduleRun(nil)
  1157. return nil
  1158. }
  1159. func (self *SCloudregion) StartSyncSkusTask(ctx context.Context, userCred mcclient.TokenCredential, res string) error {
  1160. params := jsonutils.NewDict()
  1161. params.Set("resource", jsonutils.NewString(res))
  1162. task, err := taskman.TaskManager.NewTask(ctx, "CloudRegionSyncSkusTask", self, userCred, params, "", "", nil)
  1163. if err != nil {
  1164. return errors.Wrapf(err, "CloudRegionSyncSkusTask")
  1165. }
  1166. return task.ScheduleRun(nil)
  1167. }
  1168. func (self *SCloudregion) GetCloudproviders() ([]SCloudprovider, error) {
  1169. sq := CloudproviderRegionManager.Query().Equals("cloudregion_id", self.Id).SubQuery()
  1170. q := CloudproviderManager.Query()
  1171. q = q.Join(sq, sqlchemy.Equals(sq.Field("cloudprovider_id"), q.Field("id")))
  1172. ret := []SCloudprovider{}
  1173. err := db.FetchModelObjects(CloudproviderManager, q, &ret)
  1174. if err != nil {
  1175. return nil, err
  1176. }
  1177. return ret, nil
  1178. }