cloudproviders.go 73 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207
  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. "time"
  22. "yunion.io/x/cloudmux/pkg/cloudprovider"
  23. "yunion.io/x/jsonutils"
  24. "yunion.io/x/log"
  25. "yunion.io/x/pkg/errors"
  26. "yunion.io/x/pkg/tristate"
  27. "yunion.io/x/pkg/util/compare"
  28. "yunion.io/x/pkg/util/rbacscope"
  29. "yunion.io/x/pkg/util/timeutils"
  30. "yunion.io/x/pkg/utils"
  31. "yunion.io/x/sqlchemy"
  32. "yunion.io/x/onecloud/pkg/apis"
  33. api "yunion.io/x/onecloud/pkg/apis/compute"
  34. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  35. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  36. "yunion.io/x/onecloud/pkg/cloudcommon/db/proxy"
  37. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  38. "yunion.io/x/onecloud/pkg/cloudcommon/validators"
  39. "yunion.io/x/onecloud/pkg/compute/options"
  40. "yunion.io/x/onecloud/pkg/httperrors"
  41. "yunion.io/x/onecloud/pkg/mcclient"
  42. "yunion.io/x/onecloud/pkg/mcclient/auth"
  43. "yunion.io/x/onecloud/pkg/mcclient/modules/identity"
  44. "yunion.io/x/onecloud/pkg/util/logclient"
  45. "yunion.io/x/onecloud/pkg/util/stringutils2"
  46. )
  47. type SCloudproviderManager struct {
  48. db.SEnabledStatusStandaloneResourceBaseManager
  49. db.SProjectizedResourceBaseManager
  50. db.SExternalizedResourceBaseManager
  51. SProjectMappingResourceBaseManager
  52. SSyncableBaseResourceManager
  53. }
  54. var CloudproviderManager *SCloudproviderManager
  55. func init() {
  56. CloudproviderManager = &SCloudproviderManager{
  57. SEnabledStatusStandaloneResourceBaseManager: db.NewEnabledStatusStandaloneResourceBaseManager(
  58. SCloudprovider{},
  59. "cloudproviders_tbl",
  60. "cloudprovider",
  61. "cloudproviders",
  62. ),
  63. }
  64. CloudproviderManager.SetVirtualObject(CloudproviderManager)
  65. }
  66. type SCloudprovider struct {
  67. db.SEnabledStatusStandaloneResourceBase
  68. db.SProjectizedResourceBase
  69. db.SExternalizedResourceBase
  70. SSyncableBaseResource
  71. // 云端服务健康状态。例如欠费、项目冻结都属于不健康状态。
  72. //
  73. // | HealthStatus | 说明 |
  74. // |---------------|----------------------|
  75. // | normal | 远端处于健康状态 |
  76. // | insufficient | 不足按需资源余额 |
  77. // | suspended | 远端处于冻结状态 |
  78. // | arrears | 远端处于欠费状态 |
  79. // | unknown | 未知状态,查询失败 |
  80. // | no permission | 没有权限获取账单信息 |
  81. //
  82. HealthStatus string `width:"16" charset:"ascii" default:"normal" nullable:"false" list:"domain"`
  83. // Hostname string `width:"64" charset:"ascii" nullable:"true"` // Column(VARCHAR(64, charset='ascii'), nullable=False)
  84. // port = Column(Integer, nullable=False)
  85. // Version string `width:"32" charset:"ascii" nullable:"true" list:"domain"` // Column(VARCHAR(32, charset='ascii'), nullable=True)
  86. // Sysinfo jsonutils.JSONObject `get:"domain"` // Column(JSONEncodedDict, nullable=True)
  87. AccessUrl string `width:"128" charset:"ascii" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
  88. // 云账号的用户信息,例如用户名,access key等
  89. Account string `width:"256" charset:"ascii" nullable:"false" list:"domain" create:"domain_required"`
  90. // 云账号的密码信息,例如密码,access key secret等。该字段在数据库加密存储。Google需要存储秘钥证书,需要此字段比较长
  91. Secret string `length:"0" charset:"ascii" nullable:"false" list:"domain" create:"domain_required"`
  92. // 归属云账号ID
  93. CloudaccountId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"`
  94. // ProjectId string `name:"tenant_id" width:"128" charset:"ascii" nullable:"true" list:"domain"`
  95. // LastSync time.Time `get:"domain" list:"domain"` // = Column(DateTime, nullable=True)
  96. // 云账号的平台信息
  97. Provider string `width:"64" charset:"ascii" list:"domain" create:"domain_required"`
  98. // 云上同步资源是否在本地被更改过配置, local: 更改过, cloud: 未更改过
  99. // example: local
  100. ProjectSrc string `width:"10" charset:"ascii" nullable:"false" list:"user" default:"cloud" json:"project_src"`
  101. SProjectMappingResourceBase
  102. }
  103. type pmCache struct {
  104. Id string
  105. CloudaccountId string
  106. AccountProjectMappingId string
  107. ManagerProjectMappingId string
  108. AccountEnableProjectSync bool
  109. ManagerEnableProjectSync bool
  110. AccountEnableResourceSync bool
  111. ManagerEnableResourceSync bool
  112. }
  113. type sProjectMapping struct {
  114. *SProjectMapping
  115. EnableProjectSync bool
  116. EnableResourceSync bool
  117. }
  118. func (cprvd *sProjectMapping) IsNeedResourceSync() bool {
  119. return cprvd.EnableResourceSync || !cprvd.EnableProjectSync
  120. }
  121. func (cprvd *sProjectMapping) IsNeedProjectSync() bool {
  122. return cprvd.EnableProjectSync
  123. }
  124. func (cprvd *pmCache) GetProjectMapping() (*sProjectMapping, error) {
  125. if len(cprvd.ManagerProjectMappingId) > 0 {
  126. pm, err := GetRuleMapping(cprvd.ManagerProjectMappingId)
  127. if err != nil {
  128. return nil, errors.Wrapf(err, "GetRuleMapping(%s)", cprvd.ManagerProjectMappingId)
  129. }
  130. ret := &sProjectMapping{
  131. SProjectMapping: pm,
  132. EnableProjectSync: cprvd.ManagerEnableProjectSync,
  133. EnableResourceSync: cprvd.ManagerEnableResourceSync,
  134. }
  135. return ret, nil
  136. }
  137. if len(cprvd.AccountProjectMappingId) > 0 {
  138. ret := &sProjectMapping{
  139. EnableProjectSync: cprvd.AccountEnableProjectSync,
  140. EnableResourceSync: cprvd.AccountEnableResourceSync,
  141. }
  142. var err error
  143. ret.SProjectMapping, err = GetRuleMapping(cprvd.AccountProjectMappingId)
  144. return ret, err
  145. }
  146. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty project mapping id")
  147. }
  148. var pmCaches map[string]*pmCache = map[string]*pmCache{}
  149. func refreshPmCaches() error {
  150. q := CloudproviderManager.Query().SubQuery()
  151. providers := q.Query(
  152. q.Field("cloudaccount_id"),
  153. q.Field("id"),
  154. q.Field("project_mapping_id").Label("manager_project_mapping_id"),
  155. q.Field("enable_project_sync").Label("manager_enable_project_sync"),
  156. q.Field("enable_resource_sync").Label("manager_enable_resource_sync"),
  157. )
  158. sq := CloudaccountManager.Query().SubQuery()
  159. mq := providers.LeftJoin(sq, sqlchemy.Equals(q.Field("cloudaccount_id"), sq.Field("id"))).
  160. AppendField(sq.Field("project_mapping_id").Label("account_project_mapping_id")).
  161. AppendField(sq.Field("enable_project_sync").Label("account_enable_project_sync")).
  162. AppendField(sq.Field("enable_resource_sync").Label("account_enable_resource_sync"))
  163. caches := []pmCache{}
  164. err := mq.All(&caches)
  165. if err != nil {
  166. return errors.Wrapf(err, "q.All")
  167. }
  168. for i := range caches {
  169. pmCaches[caches[i].Id] = &caches[i]
  170. }
  171. return nil
  172. }
  173. func (cprvd *SCloudaccount) GetProjectMapping() (*sProjectMapping, error) {
  174. cache, err := func() (*pmCache, error) {
  175. for id := range pmCaches {
  176. if pmCaches[id].CloudaccountId == cprvd.Id {
  177. return pmCaches[id], nil
  178. }
  179. }
  180. err := refreshPmCaches()
  181. if err != nil {
  182. return nil, errors.Wrapf(err, "refreshPmCaches")
  183. }
  184. for id := range pmCaches {
  185. if pmCaches[id].CloudaccountId == cprvd.Id {
  186. return pmCaches[id], nil
  187. }
  188. }
  189. return nil, cloudprovider.ErrNotFound
  190. }()
  191. if err != nil {
  192. return nil, errors.Wrapf(err, "get project mapping cache")
  193. }
  194. return cache.GetProjectMapping()
  195. }
  196. func (cprvd *SCloudprovider) GetProjectMapping() (*sProjectMapping, error) {
  197. cache, err := func() (*pmCache, error) {
  198. mp, ok := pmCaches[cprvd.Id]
  199. if ok {
  200. return mp, nil
  201. }
  202. err := refreshPmCaches()
  203. if err != nil {
  204. return nil, errors.Wrapf(err, "refreshPmCaches")
  205. }
  206. return pmCaches[cprvd.Id], nil
  207. }()
  208. if err != nil {
  209. return nil, errors.Wrapf(err, "get project mapping cache")
  210. }
  211. return cache.GetProjectMapping()
  212. }
  213. func (cprvd *SCloudprovider) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
  214. if cprvd.GetEnabled() {
  215. return httperrors.NewInvalidStatusError("provider is enabled")
  216. }
  217. if cprvd.SyncStatus != api.CLOUD_PROVIDER_SYNC_STATUS_IDLE {
  218. return httperrors.NewInvalidStatusError("provider is not idle")
  219. }
  220. return cprvd.SEnabledStatusStandaloneResourceBase.ValidateDeleteCondition(ctx, nil)
  221. }
  222. func (manager *SCloudproviderManager) GetPublicProviderIdsQuery() *sqlchemy.SSubQuery {
  223. return manager.GetProviderIdsQuery(tristate.True, tristate.None, nil, nil)
  224. }
  225. func (manager *SCloudproviderManager) GetPrivateProviderIdsQuery() *sqlchemy.SSubQuery {
  226. return manager.GetProviderIdsQuery(tristate.False, tristate.False, nil, nil)
  227. }
  228. func (manager *SCloudproviderManager) GetOnPremiseProviderIdsQuery() *sqlchemy.SSubQuery {
  229. return manager.GetProviderIdsQuery(tristate.None, tristate.True, nil, nil)
  230. }
  231. func (manager *SCloudproviderManager) GetPrivateOrOnPremiseProviderIdsQuery() *sqlchemy.SSubQuery {
  232. return manager.GetProviderIdsQuery(tristate.False, tristate.None, nil, nil)
  233. }
  234. func (manager *SCloudproviderManager) GetProviderIdsQuery(isPublic tristate.TriState, isOnPremise tristate.TriState, providers []string, brands []string) *sqlchemy.SSubQuery {
  235. return manager.GetProviderFieldQuery("id", isPublic, isOnPremise, providers, brands)
  236. }
  237. func (manager *SCloudproviderManager) GetPublicProviderProvidersQuery() *sqlchemy.SSubQuery {
  238. return manager.GetProviderProvidersQuery(tristate.True, tristate.None)
  239. }
  240. func (manager *SCloudproviderManager) GetPrivateProviderProvidersQuery() *sqlchemy.SSubQuery {
  241. return manager.GetProviderProvidersQuery(tristate.False, tristate.False)
  242. }
  243. func (manager *SCloudproviderManager) GetOnPremiseProviderProvidersQuery() *sqlchemy.SSubQuery {
  244. return manager.GetProviderProvidersQuery(tristate.None, tristate.True)
  245. }
  246. func (manager *SCloudproviderManager) GetProviderProvidersQuery(isPublic tristate.TriState, isOnPremise tristate.TriState) *sqlchemy.SSubQuery {
  247. return manager.GetProviderFieldQuery("provider", isPublic, isOnPremise, nil, nil)
  248. }
  249. func (manager *SCloudproviderManager) GetProviderFieldQuery(field string, isPublic tristate.TriState, isOnPremise tristate.TriState, providers []string, brands []string) *sqlchemy.SSubQuery {
  250. q := manager.Query(field).Distinct()
  251. account := CloudaccountManager.Query().SubQuery()
  252. q = q.Join(account, sqlchemy.Equals(
  253. account.Field("id"), q.Field("cloudaccount_id")),
  254. )
  255. if isPublic.IsTrue() {
  256. q = q.Filter(sqlchemy.IsTrue(account.Field("is_public_cloud")))
  257. } else if isPublic.IsFalse() {
  258. q = q.Filter(sqlchemy.IsFalse(account.Field("is_public_cloud")))
  259. }
  260. if isOnPremise.IsTrue() {
  261. q = q.Filter(sqlchemy.IsTrue(account.Field("is_on_premise")))
  262. } else if isOnPremise.IsFalse() {
  263. q = q.Filter(sqlchemy.IsFalse(account.Field("is_on_premise")))
  264. }
  265. if len(providers) > 0 || len(brands) > 0 {
  266. q = q.Filter(sqlchemy.OR(
  267. sqlchemy.In(account.Field("provider"), providers),
  268. sqlchemy.In(account.Field("brand"), brands),
  269. ))
  270. }
  271. return q.SubQuery()
  272. }
  273. func CloudProviderFilter(q *sqlchemy.SQuery, managerIdField sqlchemy.IQueryField, providers []string, brands []string, cloudEnv string) *sqlchemy.SQuery {
  274. if len(cloudEnv) == 0 && len(providers) == 0 && len(brands) == 0 {
  275. return q
  276. }
  277. isPublic := tristate.None
  278. isOnPremise := tristate.None
  279. includeOneCloud := false
  280. switch cloudEnv {
  281. case api.CLOUD_ENV_PUBLIC_CLOUD:
  282. isPublic = tristate.True
  283. case api.CLOUD_ENV_PRIVATE_CLOUD:
  284. isPublic = tristate.False
  285. isOnPremise = tristate.False
  286. case api.CLOUD_ENV_ON_PREMISE:
  287. isOnPremise = tristate.True
  288. includeOneCloud = true
  289. default:
  290. includeOneCloud = true
  291. }
  292. if includeOneCloud && len(providers) > 0 && !utils.IsInStringArray(api.CLOUD_PROVIDER_ONECLOUD, providers) {
  293. includeOneCloud = false
  294. }
  295. if includeOneCloud && len(brands) > 0 && !utils.IsInStringArray(api.CLOUD_PROVIDER_ONECLOUD, brands) {
  296. includeOneCloud = false
  297. }
  298. subq := CloudproviderManager.GetProviderIdsQuery(isPublic, isOnPremise, providers, brands)
  299. if includeOneCloud {
  300. return q.Filter(sqlchemy.OR(
  301. sqlchemy.In(managerIdField, subq),
  302. sqlchemy.IsNullOrEmpty(managerIdField),
  303. ))
  304. } else {
  305. return q.Filter(sqlchemy.In(managerIdField, subq))
  306. }
  307. }
  308. func (cprvd *SCloudprovider) CleanSchedCache() {
  309. hosts := []SHost{}
  310. q := HostManager.Query().Equals("manager_id", cprvd.Id)
  311. if err := db.FetchModelObjects(HostManager, q, &hosts); err != nil {
  312. log.Errorf("failed to get hosts for cloudprovider %s error: %v", cprvd.Name, err)
  313. return
  314. }
  315. for _, host := range hosts {
  316. host.ClearSchedDescCache()
  317. }
  318. }
  319. func (cprvd *SCloudprovider) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudproviderUpdateInput) (api.CloudproviderUpdateInput, error) {
  320. var err error
  321. input.EnabledStatusStandaloneResourceBaseUpdateInput, err = cprvd.SEnabledStatusStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.EnabledStatusStandaloneResourceBaseUpdateInput)
  322. if err != nil {
  323. return input, errors.Wrap(err, "SEnabledStatusStandaloneResourceBase.ValidateUpdateData")
  324. }
  325. return input, nil
  326. }
  327. // +onecloud:swagger-gen-ignore
  328. func (cprvd *SCloudproviderManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.CloudproviderCreateInput) (api.CloudproviderCreateInput, error) {
  329. return input, httperrors.NewUnsupportOperationError("Directly creating cloudprovider is not supported, create cloudaccount instead")
  330. }
  331. func (cprvd *SCloudprovider) getAccessUrl() string {
  332. if len(cprvd.AccessUrl) > 0 {
  333. return cprvd.AccessUrl
  334. }
  335. account, _ := cprvd.GetCloudaccount()
  336. if account != nil {
  337. return account.AccessUrl
  338. }
  339. return ""
  340. }
  341. func (cprvd *SCloudprovider) getPassword() (string, error) {
  342. if len(cprvd.Secret) == 0 {
  343. account, err := cprvd.GetCloudaccount()
  344. if err != nil {
  345. return "", errors.Wrapf(err, "GetCloudaccount")
  346. }
  347. return account.getPassword()
  348. }
  349. return utils.DescryptAESBase64(cprvd.Id, cprvd.Secret)
  350. }
  351. func getTenant(ctx context.Context, projectId string, name string, domainId string) (*db.STenant, error) {
  352. if len(projectId) > 0 {
  353. tenant, err := db.TenantCacheManager.FetchTenantById(ctx, projectId)
  354. if err != nil {
  355. return nil, errors.Wrap(err, "TenantCacheManager.FetchTenantById")
  356. }
  357. return tenant, nil
  358. }
  359. if len(name) == 0 {
  360. return nil, errors.Error("cannot syncProject for empty name")
  361. }
  362. return db.TenantCacheManager.FetchTenantByNameInDomain(ctx, name, domainId)
  363. }
  364. func createTenant(ctx context.Context, name, domainId, desc string, tags map[string]string) (string, string, error) {
  365. s := auth.GetAdminSession(ctx, options.Options.Region)
  366. params := jsonutils.NewDict()
  367. params.Add(jsonutils.NewString(name), "generate_name")
  368. params.Add(jsonutils.NewString(domainId), "domain_id")
  369. params.Add(jsonutils.NewString(desc), "description")
  370. meta := map[string]string{}
  371. for k, v := range tags {
  372. k = db.USER_TAG_PREFIX + strings.TrimPrefix(k, db.USER_TAG_PREFIX)
  373. meta[k] = v
  374. }
  375. params.Set("__meta__", jsonutils.Marshal(meta))
  376. resp, err := identity.Projects.Create(s, params)
  377. if err != nil {
  378. return "", "", errors.Wrap(err, "Projects.Create")
  379. }
  380. projectId, err := resp.GetString("id")
  381. if err != nil {
  382. return "", "", errors.Wrap(err, "resp.GetString")
  383. }
  384. _, err = db.TenantCacheManager.FetchTenantById(ctx, projectId)
  385. if err != nil {
  386. log.Errorf("fetch tenant %s error: %v", name, err)
  387. }
  388. return domainId, projectId, nil
  389. }
  390. func (cprvd *SCloudprovider) syncProject(ctx context.Context, userCred mcclient.TokenCredential) error {
  391. account, err := cprvd.GetCloudaccount()
  392. if err != nil {
  393. return errors.Wrapf(err, "GetCloudaccount")
  394. }
  395. desc := fmt.Sprintf("auto create from cloud provider %s (%s)", cprvd.Name, cprvd.Id)
  396. domainId, projectId, err := account.getOrCreateTenant(ctx, cprvd.Name, "", cprvd.ProjectId, desc, nil)
  397. if err != nil {
  398. return errors.Wrap(err, "getOrCreateTenant")
  399. }
  400. return cprvd.saveProject(userCred, domainId, projectId, true)
  401. }
  402. func (cprvd *SCloudprovider) saveProject(userCred mcclient.TokenCredential, domainId, projectId string, auto bool) error {
  403. if projectId != cprvd.ProjectId {
  404. diff, err := db.Update(cprvd, func() error {
  405. cprvd.DomainId = domainId
  406. cprvd.ProjectId = projectId
  407. // 自动改变项目时不改变配置,仅在performChangeOnwer(手动更改项目)时改变
  408. if !auto {
  409. cprvd.ProjectSrc = string(apis.OWNER_SOURCE_LOCAL)
  410. }
  411. return nil
  412. })
  413. if err != nil {
  414. log.Errorf("update projectId fail: %s", err)
  415. return err
  416. }
  417. db.OpsLog.LogEvent(cprvd, db.ACT_UPDATE, diff, userCred)
  418. }
  419. return nil
  420. }
  421. type SSyncRange struct {
  422. api.SyncRangeInput
  423. }
  424. func (sr *SSyncRange) GetRegionIds() ([]string, error) {
  425. regionIds := []string{}
  426. if len(sr.Host) == 0 && len(sr.Zone) == 0 && len(sr.Region) == 0 {
  427. return regionIds, nil
  428. }
  429. hostQ := HostManager.Query().SubQuery()
  430. hosts := hostQ.Query().Filter(sqlchemy.OR(
  431. sqlchemy.In(hostQ.Field("id"), sr.Host),
  432. sqlchemy.In(hostQ.Field("name"), sr.Host),
  433. )).SubQuery()
  434. zoneQ := ZoneManager.Query().SubQuery()
  435. zones := zoneQ.Query().Filter(sqlchemy.OR(
  436. sqlchemy.In(zoneQ.Field("id"), sr.Zone),
  437. sqlchemy.In(zoneQ.Field("name"), sr.Zone),
  438. sqlchemy.In(zoneQ.Field("id"), hosts.Query(hosts.Field("zone_id")).SubQuery()),
  439. )).SubQuery()
  440. regionQ := CloudregionManager.Query().SubQuery()
  441. q := regionQ.Query(regionQ.Field("id")).Filter(sqlchemy.OR(
  442. sqlchemy.In(regionQ.Field("id"), sr.Region),
  443. sqlchemy.In(regionQ.Field("name"), sr.Region),
  444. sqlchemy.In(regionQ.Field("id"), zones.Query(zones.Field("cloudregion_id")).SubQuery()),
  445. ))
  446. rows, err := q.Rows()
  447. if err != nil {
  448. return nil, errors.Wrap(err, "q.Rows")
  449. }
  450. defer rows.Close()
  451. for rows.Next() {
  452. var regionId string
  453. err = rows.Scan(&regionId)
  454. if err != nil {
  455. return nil, errors.Wrap(err, "rows.Scan")
  456. }
  457. regionIds = append(regionIds, regionId)
  458. }
  459. return regionIds, nil
  460. }
  461. func (sr *SSyncRange) NeedSyncResource(res string) bool {
  462. if sr.FullSync {
  463. return true
  464. }
  465. if len(sr.Resources) == 0 {
  466. return true
  467. }
  468. return utils.IsInStringArray(res, sr.Resources)
  469. }
  470. func (sr *SSyncRange) NeedSyncInfo() bool {
  471. if sr.FullSync {
  472. return true
  473. }
  474. if len(sr.Region) > 0 || len(sr.Zone) > 0 || len(sr.Host) > 0 || len(sr.Resources) > 0 {
  475. return true
  476. }
  477. return false
  478. }
  479. func (sr *SSyncRange) normalizeRegionIds(ctx context.Context) error {
  480. for i := 0; i < len(sr.Region); i += 1 {
  481. obj, err := CloudregionManager.FetchByIdOrName(ctx, nil, sr.Region[i])
  482. if err != nil {
  483. if err == sql.ErrNoRows {
  484. return httperrors.NewResourceNotFoundError("Region %s not found", sr.Region[i])
  485. } else {
  486. return err
  487. }
  488. }
  489. sr.Region[i] = obj.GetId()
  490. }
  491. return nil
  492. }
  493. func (sr *SSyncRange) normalizeZoneIds(ctx context.Context) error {
  494. for i := 0; i < len(sr.Zone); i += 1 {
  495. obj, err := ZoneManager.FetchByIdOrName(ctx, nil, sr.Zone[i])
  496. if err != nil {
  497. if err == sql.ErrNoRows {
  498. return httperrors.NewResourceNotFoundError("Zone %s not found", sr.Zone[i])
  499. } else {
  500. return err
  501. }
  502. }
  503. zone := obj.(*SZone)
  504. region, _ := zone.GetRegion()
  505. if region == nil {
  506. continue
  507. }
  508. sr.Zone[i] = zone.GetId()
  509. if !utils.IsInStringArray(region.Id, sr.Region) {
  510. sr.Region = append(sr.Region, region.Id)
  511. }
  512. }
  513. return nil
  514. }
  515. func (sr *SSyncRange) normalizeHostIds(ctx context.Context) error {
  516. for i := 0; i < len(sr.Host); i += 1 {
  517. obj, err := HostManager.FetchByIdOrName(ctx, nil, sr.Host[i])
  518. if err != nil {
  519. if err == sql.ErrNoRows {
  520. return httperrors.NewResourceNotFoundError("Host %s not found", sr.Host[i])
  521. } else {
  522. return err
  523. }
  524. }
  525. host := obj.(*SHost)
  526. zone, _ := host.GetZone()
  527. if zone == nil {
  528. continue
  529. }
  530. region, _ := zone.GetRegion()
  531. if region == nil {
  532. continue
  533. }
  534. sr.Host[i] = host.GetId()
  535. if !utils.IsInStringArray(zone.Id, sr.Zone) {
  536. sr.Zone = append(sr.Zone, zone.Id)
  537. }
  538. if !utils.IsInStringArray(region.Id, sr.Region) {
  539. sr.Region = append(sr.Region, region.Id)
  540. }
  541. }
  542. return nil
  543. }
  544. func (sr *SSyncRange) Normalize(ctx context.Context) error {
  545. if sr.Region != nil && len(sr.Region) > 0 {
  546. err := sr.normalizeRegionIds(ctx)
  547. if err != nil {
  548. return err
  549. }
  550. } else {
  551. sr.Region = make([]string, 0)
  552. }
  553. if sr.Zone != nil && len(sr.Zone) > 0 {
  554. err := sr.normalizeZoneIds(ctx)
  555. if err != nil {
  556. return err
  557. }
  558. } else {
  559. sr.Zone = make([]string, 0)
  560. }
  561. if sr.Host != nil && len(sr.Host) > 0 {
  562. err := sr.normalizeHostIds(ctx)
  563. if err != nil {
  564. return err
  565. }
  566. } else {
  567. sr.Host = make([]string, 0)
  568. }
  569. return nil
  570. }
  571. func (cprvd *SCloudprovider) PerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.SyncRangeInput) (jsonutils.JSONObject, error) {
  572. if !cprvd.GetEnabled() {
  573. return nil, httperrors.NewInvalidStatusError("Cloudprovider disabled")
  574. }
  575. account, err := cprvd.GetCloudaccount()
  576. if err != nil {
  577. return nil, errors.Wrapf(err, "GetCloudaccount")
  578. }
  579. if !account.GetEnabled() {
  580. return nil, httperrors.NewInvalidStatusError("Cloudaccount disabled")
  581. }
  582. syncRange := SSyncRange{input}
  583. if syncRange.FullSync || len(syncRange.Region) > 0 || len(syncRange.Zone) > 0 || len(syncRange.Host) > 0 || len(syncRange.Resources) > 0 {
  584. syncRange.DeepSync = true
  585. }
  586. syncRange.SkipSyncResources = []string{}
  587. if account.SkipSyncResources != nil {
  588. for _, res := range *account.SkipSyncResources {
  589. syncRange.SkipSyncResources = append(syncRange.SkipSyncResources, res)
  590. }
  591. }
  592. if cprvd.CanSync() || syncRange.Force {
  593. return nil, cprvd.StartSyncCloudProviderInfoTask(ctx, userCred, &syncRange, "")
  594. }
  595. return nil, httperrors.NewInvalidStatusError("Unable to synchronize frequently")
  596. }
  597. func (cprvd *SCloudprovider) StartSyncCloudProviderInfoTask(ctx context.Context, userCred mcclient.TokenCredential, syncRange *SSyncRange, parentTaskId string) error {
  598. params := jsonutils.NewDict()
  599. if syncRange != nil {
  600. params.Add(jsonutils.Marshal(syncRange), "sync_range")
  601. }
  602. task, err := taskman.TaskManager.NewTask(ctx, "CloudProviderSyncInfoTask", cprvd, userCred, params, parentTaskId, "", nil)
  603. if err != nil {
  604. return errors.Wrapf(err, "NewTask")
  605. }
  606. if cloudaccount, _ := cprvd.GetCloudaccount(); cloudaccount != nil {
  607. cloudaccount.MarkSyncing(userCred)
  608. }
  609. cprvd.markStartSync(userCred, syncRange)
  610. db.OpsLog.LogEvent(cprvd, db.ACT_SYNC_HOST_START, "", userCred)
  611. return task.ScheduleRun(nil)
  612. }
  613. func (cprvd *SCloudprovider) PerformChangeProject(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) (jsonutils.JSONObject, error) {
  614. project := input.ProjectId
  615. domain := input.ProjectDomainId
  616. if len(domain) == 0 {
  617. domain = cprvd.DomainId
  618. }
  619. tenant, err := db.TenantCacheManager.FetchTenantByIdOrNameInDomain(ctx, project, domain)
  620. if err != nil {
  621. return nil, httperrors.NewNotFoundError("project %s not found", project)
  622. }
  623. if cprvd.ProjectId == tenant.Id {
  624. return nil, nil
  625. }
  626. account, err := cprvd.GetCloudaccount()
  627. if err != nil {
  628. return nil, err
  629. }
  630. if cprvd.DomainId != tenant.DomainId {
  631. if !db.IsAdminAllowPerform(ctx, userCred, cprvd, "change-project") {
  632. return nil, httperrors.NewForbiddenError("not allow to change project across domain")
  633. }
  634. if account.ShareMode == api.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN && account.DomainId != tenant.DomainId {
  635. return nil, httperrors.NewInvalidStatusError("cannot change to a different domain from a private cloud account")
  636. }
  637. // if account's public_scope=domain and share_mode=provider_domain, only allow to share to specific domains
  638. if account.PublicScope == string(rbacscope.ScopeDomain) {
  639. sharedDomains := account.GetSharedDomains()
  640. if !utils.IsInStringArray(tenant.DomainId, sharedDomains) && account.DomainId != tenant.DomainId {
  641. return nil, errors.Wrap(httperrors.ErrForbidden, "cannot set to domain outside of the shared domains")
  642. }
  643. }
  644. // otherwise, allow change project across domain
  645. }
  646. notes := struct {
  647. OldProjectId string
  648. OldDomainId string
  649. NewProjectId string
  650. NewProject string
  651. NewDomainId string
  652. NewDomain string
  653. }{
  654. OldProjectId: cprvd.ProjectId,
  655. OldDomainId: cprvd.DomainId,
  656. NewProjectId: tenant.Id,
  657. NewProject: tenant.Name,
  658. NewDomainId: tenant.DomainId,
  659. NewDomain: tenant.Domain,
  660. }
  661. err = cprvd.saveProject(userCred, tenant.DomainId, tenant.Id, false)
  662. if err != nil {
  663. log.Errorf("Update cloudprovider error: %v", err)
  664. return nil, httperrors.NewGeneralError(err)
  665. }
  666. logclient.AddSimpleActionLog(cprvd, logclient.ACT_CHANGE_OWNER, notes, userCred, true)
  667. return nil, cprvd.StartSyncCloudProviderInfoTask(ctx, userCred, &SSyncRange{SyncRangeInput: api.SyncRangeInput{
  668. FullSync: true, DeepSync: true,
  669. }}, "")
  670. }
  671. func (cprvd *SCloudprovider) markStartingSync(userCred mcclient.TokenCredential, syncRange *SSyncRange) error {
  672. _, err := db.Update(cprvd, func() error {
  673. cprvd.SyncStatus = api.CLOUD_PROVIDER_SYNC_STATUS_QUEUING
  674. return nil
  675. })
  676. if err != nil {
  677. return errors.Wrap(err, "db.Update")
  678. }
  679. cprs := cprvd.GetCloudproviderRegions()
  680. for i := range cprs {
  681. if cprs[i].Enabled {
  682. err := cprs[i].markStartingSync(userCred, syncRange)
  683. if err != nil {
  684. return errors.Wrap(err, "cprs[i].markStartingSync")
  685. }
  686. }
  687. }
  688. return nil
  689. }
  690. func (cprvd *SCloudprovider) markStartSync(userCred mcclient.TokenCredential, syncRange *SSyncRange) error {
  691. _, err := db.Update(cprvd, func() error {
  692. cprvd.SyncStatus = api.CLOUD_PROVIDER_SYNC_STATUS_QUEUED
  693. return nil
  694. })
  695. if err != nil {
  696. return errors.Wrapf(err, "db.Update")
  697. }
  698. cprs := cprvd.GetCloudproviderRegions()
  699. for i := range cprs {
  700. if cprs[i].Enabled {
  701. err := cprs[i].markStartingSync(userCred, syncRange)
  702. if err != nil {
  703. return errors.Wrap(err, "cprs[i].markStartingSync")
  704. }
  705. }
  706. }
  707. return nil
  708. }
  709. func (cprvd *SCloudprovider) markSyncing(userCred mcclient.TokenCredential) error {
  710. _, err := db.Update(cprvd, func() error {
  711. cprvd.SyncStatus = api.CLOUD_PROVIDER_SYNC_STATUS_SYNCING
  712. cprvd.LastSync = timeutils.UtcNow()
  713. cprvd.LastSyncEndAt = time.Time{}
  714. return nil
  715. })
  716. if err != nil {
  717. log.Errorf("Failed to markSyncing error: %v", err)
  718. return err
  719. }
  720. return nil
  721. }
  722. func (cprvd *SCloudprovider) markEndSyncWithLock(ctx context.Context, userCred mcclient.TokenCredential, deepSync bool) error {
  723. err := func() error {
  724. lockman.LockObject(ctx, cprvd)
  725. defer lockman.ReleaseObject(ctx, cprvd)
  726. if cprvd.SyncStatus == api.CLOUD_PROVIDER_SYNC_STATUS_IDLE {
  727. return nil
  728. }
  729. if cprvd.GetSyncStatus2() != api.CLOUD_PROVIDER_SYNC_STATUS_IDLE {
  730. return nil
  731. }
  732. err := cprvd.markEndSync(userCred)
  733. if err != nil {
  734. return err
  735. }
  736. return nil
  737. }()
  738. if err != nil {
  739. return err
  740. }
  741. account, err := cprvd.GetCloudaccount()
  742. if err != nil {
  743. return errors.Wrapf(err, "GetCloudaccount")
  744. }
  745. return account.MarkEndSyncWithLock(ctx, userCred, deepSync)
  746. }
  747. func (cprvd *SCloudprovider) markEndSync(userCred mcclient.TokenCredential) error {
  748. _, err := db.Update(cprvd, func() error {
  749. cprvd.SyncStatus = api.CLOUD_PROVIDER_SYNC_STATUS_IDLE
  750. cprvd.LastSyncEndAt = timeutils.UtcNow()
  751. return nil
  752. })
  753. if err != nil {
  754. return errors.Wrapf(err, "markEndSync")
  755. }
  756. return nil
  757. }
  758. func (cprvd *SCloudprovider) cancelStartingSync(userCred mcclient.TokenCredential) error {
  759. if cprvd.SyncStatus == api.CLOUD_PROVIDER_SYNC_STATUS_QUEUING {
  760. cprs := cprvd.GetCloudproviderRegions()
  761. for i := range cprs {
  762. err := cprs[i].cancelStartingSync(userCred)
  763. if err != nil {
  764. return errors.Wrap(err, "cprs[i].cancelStartingSync")
  765. }
  766. }
  767. _, err := db.Update(cprvd, func() error {
  768. cprvd.SyncStatus = api.CLOUD_PROVIDER_SYNC_STATUS_IDLE
  769. return nil
  770. })
  771. if err != nil {
  772. return errors.Wrap(err, "db.Update")
  773. }
  774. }
  775. return nil
  776. }
  777. func (cprvd *SCloudprovider) GetProviderFactory() (cloudprovider.ICloudProviderFactory, error) {
  778. return cloudprovider.GetProviderFactory(cprvd.Provider)
  779. }
  780. func (cprvd *SCloudprovider) GetProvider(ctx context.Context) (cloudprovider.ICloudProvider, error) {
  781. if !cprvd.GetEnabled() {
  782. return nil, errors.Wrap(httperrors.ErrInvalidStatus, "Cloud provider is not enabled")
  783. }
  784. accessUrl := cprvd.getAccessUrl()
  785. passwd, err := cprvd.getPassword()
  786. if err != nil {
  787. return nil, err
  788. }
  789. account, err := cprvd.GetCloudaccount()
  790. if err != nil {
  791. return nil, errors.Wrapf(err, "GetCloudaccount")
  792. }
  793. return cloudprovider.GetProvider(cloudprovider.ProviderConfig{
  794. Id: cprvd.Id,
  795. Name: cprvd.Name,
  796. Vendor: cprvd.Provider,
  797. URL: accessUrl,
  798. Account: cprvd.Account,
  799. Secret: passwd,
  800. ProxyFunc: account.proxyFunc(),
  801. AliyunResourceGroupIds: options.Options.AliyunResourceGroups,
  802. ReadOnly: account.ReadOnly,
  803. RegionId: account.regionId(),
  804. Options: account.Options,
  805. UpdatePermission: account.UpdatePermission(ctx),
  806. })
  807. }
  808. func (cprvd *SCloudprovider) savePassword(secret string) error {
  809. sec, err := utils.EncryptAESBase64(cprvd.Id, secret)
  810. if err != nil {
  811. return err
  812. }
  813. _, err = db.Update(cprvd, func() error {
  814. cprvd.Secret = sec
  815. return nil
  816. })
  817. return err
  818. }
  819. func (cprvd *SCloudprovider) GetCloudaccount() (*SCloudaccount, error) {
  820. obj, err := CloudaccountManager.FetchById(cprvd.CloudaccountId)
  821. if err != nil {
  822. return nil, errors.Wrapf(err, "FetchById(%s)", cprvd.CloudaccountId)
  823. }
  824. return obj.(*SCloudaccount), nil
  825. }
  826. func (manager *SCloudproviderManager) FetchCloudproviderById(providerId string) *SCloudprovider {
  827. providerObj, err := manager.FetchById(providerId)
  828. if err != nil {
  829. return nil
  830. }
  831. return providerObj.(*SCloudprovider)
  832. }
  833. func IsProviderAccountEnabled(providerId string) bool {
  834. if len(providerId) == 0 {
  835. return true
  836. }
  837. return CloudproviderManager.IsProviderAccountEnabled(providerId)
  838. }
  839. func (manager *SCloudproviderManager) IsProviderAccountEnabled(providerId string) bool {
  840. providerObj := manager.FetchCloudproviderById(providerId)
  841. if providerObj == nil {
  842. return false
  843. }
  844. if !providerObj.GetEnabled() {
  845. return false
  846. }
  847. account, _ := providerObj.GetCloudaccount()
  848. if account == nil {
  849. return false
  850. }
  851. return account.GetEnabled()
  852. }
  853. func (manager *SCloudproviderManager) FetchCloudproviderByIdOrName(ctx context.Context, providerId string) *SCloudprovider {
  854. providerObj, err := manager.FetchByIdOrName(ctx, nil, providerId)
  855. if err != nil {
  856. if err != sql.ErrNoRows {
  857. log.Errorf("%s", err)
  858. }
  859. return nil
  860. }
  861. return providerObj.(*SCloudprovider)
  862. }
  863. func (cm *SCloudproviderManager) query(manager db.IModelManager, field string, providerIds []string, filter func(*sqlchemy.SQuery) *sqlchemy.SQuery) *sqlchemy.SSubQuery {
  864. q := manager.Query()
  865. if filter != nil {
  866. q = filter(q)
  867. }
  868. sq := q.SubQuery()
  869. key := "manager_id"
  870. if manager.Keyword() == CloudproviderRegionManager.Keyword() {
  871. key = "cloudprovider_id"
  872. }
  873. return sq.Query(
  874. sq.Field(key),
  875. sqlchemy.COUNT(field),
  876. ).In(key, providerIds).GroupBy(sq.Field(key)).SubQuery()
  877. }
  878. type SCloudproviderUsageCount struct {
  879. Id string
  880. api.SCloudproviderUsage
  881. }
  882. func (cm *SCloudproviderManager) TotalResourceCount(providerIds []string) (map[string]api.SCloudproviderUsage, error) {
  883. ret := map[string]api.SCloudproviderUsage{}
  884. guestSQ := cm.query(GuestManager, "guest_cnt", providerIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  885. hosts := HostManager.Query().SubQuery()
  886. sq := q.SubQuery()
  887. return sq.Query(
  888. sq.Field("id").Label("guest_id"),
  889. sq.Field("host_id").Label("host_id"),
  890. hosts.Field("manager_id").Label("manager_id"),
  891. ).LeftJoin(hosts, sqlchemy.Equals(sq.Field("host_id"), hosts.Field("id")))
  892. })
  893. hostSQ := cm.query(HostManager, "host_cnt", providerIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  894. return q.IsFalse("is_emulated")
  895. })
  896. vpcSQ := cm.query(VpcManager, "vpc_cnt", providerIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  897. return q.IsFalse("is_emulated")
  898. })
  899. storageSQ := cm.query(StorageManager, "storage_cnt", providerIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  900. return q.IsFalse("is_emulated")
  901. })
  902. storagecacheSQ := cm.query(StoragecacheManager, "storage_cache_cnt", providerIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  903. return q.IsFalse("is_emulated")
  904. })
  905. redisSQ := cm.query(ElasticcacheManager, "elasticcache_cnt", providerIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  906. vpcs := VpcManager.Query().SubQuery()
  907. sq := q.SubQuery()
  908. return sq.Query(
  909. sq.Field("id").Label("redis_id"),
  910. sq.Field("vpc_id").Label("vpc_id"),
  911. vpcs.Field("manager_id").Label("manager_id"),
  912. ).LeftJoin(vpcs, sqlchemy.Equals(sq.Field("vpc_id"), vpcs.Field("id")))
  913. })
  914. eipSQ := cm.query(ElasticipManager, "eip_cnt", providerIds, nil)
  915. snapshotSQ := cm.query(SnapshotManager, "snapshot_cnt", providerIds, nil)
  916. lbSQ := cm.query(LoadbalancerManager, "loadbalancer_cnt", providerIds, nil)
  917. rdsSQ := cm.query(DBInstanceManager, "dbinstance_cnt", providerIds, nil)
  918. projectSQ := cm.query(ExternalProjectManager, "project_cnt", providerIds, nil)
  919. sregionSQ := cm.query(CloudproviderRegionManager, "sync_region_cnt", providerIds, nil)
  920. providers := cm.Query().SubQuery()
  921. providerQ := providers.Query(
  922. sqlchemy.SUM("guest_count", guestSQ.Field("guest_cnt")),
  923. sqlchemy.SUM("host_count", hostSQ.Field("host_cnt")),
  924. sqlchemy.SUM("vpc_count", vpcSQ.Field("vpc_cnt")),
  925. sqlchemy.SUM("storage_count", storageSQ.Field("storage_cnt")),
  926. sqlchemy.SUM("storage_cache_count", storagecacheSQ.Field("storage_cache_cnt")),
  927. sqlchemy.SUM("eip_count", eipSQ.Field("eip_cnt")),
  928. sqlchemy.SUM("snapshot_count", snapshotSQ.Field("snapshot_cnt")),
  929. sqlchemy.SUM("loadbalancer_count", lbSQ.Field("loadbalancer_cnt")),
  930. sqlchemy.SUM("dbinstance_count", rdsSQ.Field("dbinstance_cnt")),
  931. sqlchemy.SUM("elasticcache_count", redisSQ.Field("elasticcache_cnt")),
  932. sqlchemy.SUM("project_count", projectSQ.Field("project_cnt")),
  933. sqlchemy.SUM("sync_region_count", sregionSQ.Field("sync_region_cnt")),
  934. )
  935. providerQ.AppendField(providerQ.Field("id"))
  936. providerQ = providerQ.LeftJoin(guestSQ, sqlchemy.Equals(providerQ.Field("id"), guestSQ.Field("manager_id")))
  937. providerQ = providerQ.LeftJoin(hostSQ, sqlchemy.Equals(providerQ.Field("id"), hostSQ.Field("manager_id")))
  938. providerQ = providerQ.LeftJoin(vpcSQ, sqlchemy.Equals(providerQ.Field("id"), vpcSQ.Field("manager_id")))
  939. providerQ = providerQ.LeftJoin(storageSQ, sqlchemy.Equals(providerQ.Field("id"), storageSQ.Field("manager_id")))
  940. providerQ = providerQ.LeftJoin(storagecacheSQ, sqlchemy.Equals(providerQ.Field("id"), storagecacheSQ.Field("manager_id")))
  941. providerQ = providerQ.LeftJoin(eipSQ, sqlchemy.Equals(providerQ.Field("id"), eipSQ.Field("manager_id")))
  942. providerQ = providerQ.LeftJoin(snapshotSQ, sqlchemy.Equals(providerQ.Field("id"), snapshotSQ.Field("manager_id")))
  943. providerQ = providerQ.LeftJoin(lbSQ, sqlchemy.Equals(providerQ.Field("id"), lbSQ.Field("manager_id")))
  944. providerQ = providerQ.LeftJoin(rdsSQ, sqlchemy.Equals(providerQ.Field("id"), rdsSQ.Field("manager_id")))
  945. providerQ = providerQ.LeftJoin(redisSQ, sqlchemy.Equals(providerQ.Field("id"), redisSQ.Field("manager_id")))
  946. providerQ = providerQ.LeftJoin(projectSQ, sqlchemy.Equals(providerQ.Field("id"), projectSQ.Field("manager_id")))
  947. providerQ = providerQ.LeftJoin(sregionSQ, sqlchemy.Equals(providerQ.Field("id"), sregionSQ.Field("cloudprovider_id")))
  948. providerQ = providerQ.Filter(sqlchemy.In(providerQ.Field("id"), providerIds)).GroupBy(providerQ.Field("id"))
  949. counts := []SCloudproviderUsageCount{}
  950. err := providerQ.All(&counts)
  951. if err != nil {
  952. return nil, errors.Wrapf(err, "providerQ.All")
  953. }
  954. for i := range counts {
  955. ret[counts[i].Id] = counts[i].SCloudproviderUsage
  956. }
  957. return ret, nil
  958. }
  959. func (cprvd *SCloudprovider) getProject(ctx context.Context) *db.STenant {
  960. proj, _ := db.TenantCacheManager.FetchTenantById(ctx, cprvd.ProjectId)
  961. return proj
  962. }
  963. func (manager *SCloudproviderManager) FetchCustomizeColumns(
  964. ctx context.Context,
  965. userCred mcclient.TokenCredential,
  966. query jsonutils.JSONObject,
  967. objs []interface{},
  968. fields stringutils2.SSortedStrings,
  969. isList bool,
  970. ) []api.CloudproviderDetails {
  971. rows := make([]api.CloudproviderDetails, len(objs))
  972. stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  973. projRows := manager.SProjectizedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  974. pmRows := manager.SProjectMappingResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  975. accountIds := make([]string, len(objs))
  976. providerIds := make([]string, len(objs))
  977. for i := range rows {
  978. provider := objs[i].(*SCloudprovider)
  979. accountIds[i] = provider.CloudaccountId
  980. providerIds[i] = provider.Id
  981. rows[i] = api.CloudproviderDetails{
  982. EnabledStatusStandaloneResourceDetails: stdRows[i],
  983. ProjectizedResourceInfo: projRows[i],
  984. ProjectMappingResourceInfo: pmRows[i],
  985. LastSyncCost: provider.GetLastSyncCost(),
  986. }
  987. }
  988. q := CloudproviderRegionManager.Query()
  989. q = q.In("cloudprovider_id", providerIds)
  990. q = q.NotEquals("sync_status", api.CLOUD_PROVIDER_SYNC_STATUS_IDLE)
  991. cprs := []SCloudproviderregion{}
  992. err := q.All(&cprs)
  993. if err != nil {
  994. return rows
  995. }
  996. cprsMap := map[string]int{}
  997. for i := range cprs {
  998. _, ok := cprsMap[cprs[i].CloudproviderId]
  999. if !ok {
  1000. cprsMap[cprs[i].CloudproviderId] = 0
  1001. }
  1002. cprsMap[cprs[i].CloudproviderId] += 1
  1003. }
  1004. accounts := make(map[string]SCloudaccount)
  1005. err = db.FetchStandaloneObjectsByIds(CloudaccountManager, accountIds, &accounts)
  1006. if err != nil {
  1007. log.Errorf("FetchStandaloneObjectsByIds (%s) fail %s",
  1008. CloudaccountManager.KeywordPlural(), err)
  1009. return rows
  1010. }
  1011. proxySettingIds := make([]string, len(accounts))
  1012. for i := range accounts {
  1013. proxySettingId := accounts[i].ProxySettingId
  1014. if !utils.IsInStringArray(proxySettingId, proxySettingIds) {
  1015. proxySettingIds = append(proxySettingIds, proxySettingId)
  1016. }
  1017. }
  1018. proxySettings := make(map[string]proxy.SProxySetting)
  1019. err = db.FetchStandaloneObjectsByIds(proxy.ProxySettingManager, proxySettingIds, &proxySettings)
  1020. if err != nil {
  1021. log.Errorf("FetchStandaloneObjectsByIds (%s) fail %s",
  1022. proxy.ProxySettingManager.KeywordPlural(), err)
  1023. return rows
  1024. }
  1025. usages, err := manager.TotalResourceCount(providerIds)
  1026. if err != nil {
  1027. return rows
  1028. }
  1029. capabilities, err := CloudproviderCapabilityManager.getProvidersCapabilities(providerIds)
  1030. if err != nil {
  1031. return rows
  1032. }
  1033. for i := range rows {
  1034. if account, ok := accounts[accountIds[i]]; ok {
  1035. rows[i].Cloudaccount = account.Name
  1036. rows[i].ReadOnly = account.ReadOnly
  1037. rows[i].Brand = account.Brand
  1038. ps := &rows[i].ProxySetting
  1039. if proxySetting, ok := proxySettings[account.ProxySettingId]; ok {
  1040. ps.Id = proxySetting.Id
  1041. ps.Name = proxySetting.Name
  1042. ps.HTTPProxy = proxySetting.HTTPProxy
  1043. ps.HTTPSProxy = proxySetting.HTTPSProxy
  1044. ps.NoProxy = proxySetting.NoProxy
  1045. }
  1046. }
  1047. rows[i].SyncStatus2 = api.CLOUD_PROVIDER_SYNC_STATUS_IDLE
  1048. if _, ok := cprsMap[providerIds[i]]; ok {
  1049. rows[i].SyncStatus2 = api.CLOUD_PROVIDER_SYNC_STATUS_SYNCING
  1050. }
  1051. if usage, ok := usages[providerIds[i]]; ok {
  1052. rows[i].SCloudproviderUsage = usage
  1053. }
  1054. if capas, ok := capabilities[providerIds[i]]; ok {
  1055. rows[i].Capabilities = capas
  1056. }
  1057. }
  1058. return rows
  1059. }
  1060. func (manager *SCloudproviderManager) initializeDefaultTenantId() error {
  1061. // init accountid
  1062. q := manager.Query().IsNullOrEmpty("tenant_id")
  1063. providers := make([]SCloudprovider, 0)
  1064. err := db.FetchModelObjects(manager, q, &providers)
  1065. if err != nil {
  1066. return errors.Wrap(err, "fetch empty defaullt tenant_id fail")
  1067. }
  1068. for i := range providers {
  1069. provider := providers[i]
  1070. domainId := provider.DomainId
  1071. if len(domainId) == 0 {
  1072. account, err := provider.GetCloudaccount()
  1073. if err != nil {
  1074. log.Errorf("GetCloudaccount fail %s", err)
  1075. continue
  1076. }
  1077. domainId = account.DomainId
  1078. }
  1079. // auto fix accounts without default project
  1080. defaultTenant, err := db.TenantCacheManager.FindFirstProjectOfDomain(context.Background(), domainId)
  1081. if err != nil {
  1082. return errors.Wrapf(err, "FindFirstProjectOfDomain(%s)", provider.DomainId)
  1083. }
  1084. _, err = db.Update(&provider, func() error {
  1085. provider.ProjectId = defaultTenant.Id
  1086. provider.DomainId = defaultTenant.DomainId
  1087. return nil
  1088. })
  1089. if err != nil {
  1090. return errors.Wrap(err, "db.Update for account")
  1091. }
  1092. }
  1093. return nil
  1094. }
  1095. func (manager *SCloudproviderManager) InitializeData() error {
  1096. err := manager.initializeDefaultTenantId()
  1097. if err != nil {
  1098. log.Errorf("initializeDefaultTenantId %s", err)
  1099. }
  1100. return nil
  1101. }
  1102. // 云订阅列表
  1103. func (manager *SCloudproviderManager) ListItemFilter(
  1104. ctx context.Context,
  1105. q *sqlchemy.SQuery,
  1106. userCred mcclient.TokenCredential,
  1107. query api.CloudproviderListInput,
  1108. ) (*sqlchemy.SQuery, error) {
  1109. accountArr := query.CloudaccountId
  1110. if len(accountArr) > 0 {
  1111. cpq := CloudaccountManager.Query().SubQuery()
  1112. subcpq := cpq.Query(cpq.Field("id")).Filter(sqlchemy.OR(
  1113. sqlchemy.In(cpq.Field("id"), stringutils2.RemoveUtf8Strings(accountArr)),
  1114. sqlchemy.In(cpq.Field("name"), accountArr),
  1115. )).SubQuery()
  1116. q = q.In("cloudaccount_id", subcpq)
  1117. }
  1118. var zone *SZone
  1119. var region *SCloudregion
  1120. if len(query.ZoneId) > 0 {
  1121. zoneObj, err := validators.ValidateModel(ctx, userCred, ZoneManager, &query.ZoneId)
  1122. if err != nil {
  1123. return nil, err
  1124. }
  1125. zone = zoneObj.(*SZone)
  1126. region, err = zone.GetRegion()
  1127. if err != nil {
  1128. return nil, err
  1129. }
  1130. vpcs := VpcManager.Query("manager_id").Equals("cloudregion_id", region.Id).Distinct()
  1131. if !utils.IsInStringArray(region.Provider, api.REGIONAL_NETWORK_PROVIDERS) {
  1132. wires := WireManager.Query().Equals("zone_id", query.ZoneId).SubQuery()
  1133. vpcs = vpcs.Join(wires, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id")))
  1134. }
  1135. wireManager := WireManager.Query("manager_id").Equals("zone_id", query.ZoneId).Distinct().SubQuery()
  1136. q = q.Filter(
  1137. sqlchemy.OR(
  1138. sqlchemy.In(q.Field("id"), vpcs.SubQuery()),
  1139. sqlchemy.In(q.Field("id"), wireManager), //vmware
  1140. ),
  1141. )
  1142. } else if len(query.CloudregionId) > 0 {
  1143. regionObj, err := CloudregionManager.FetchByIdOrName(ctx, userCred, query.CloudregionId)
  1144. if err != nil {
  1145. if err == sql.ErrNoRows {
  1146. return nil, httperrors.NewResourceNotFoundError2("cloudregion", query.CloudregionId)
  1147. }
  1148. return nil, httperrors.NewGeneralError(err)
  1149. }
  1150. region = regionObj.(*SCloudregion)
  1151. pr := CloudproviderRegionManager.Query().SubQuery()
  1152. sq := pr.Query(pr.Field("cloudprovider_id")).Equals("cloudregion_id", region.Id).Distinct()
  1153. q = q.In("id", sq)
  1154. }
  1155. if query.Usable != nil && *query.Usable {
  1156. providers := usableCloudProviders().SubQuery()
  1157. networks := NetworkManager.Query().SubQuery()
  1158. wires := WireManager.Query().SubQuery()
  1159. vpcs := VpcManager.Query().SubQuery()
  1160. providerRegions := CloudproviderRegionManager.Query().SubQuery()
  1161. sq := providers.Query(sqlchemy.DISTINCT("id", providers.Field("id")))
  1162. sq = sq.Join(providerRegions, sqlchemy.Equals(providers.Field("id"), providerRegions.Field("cloudprovider_id")))
  1163. sq = sq.Join(vpcs, sqlchemy.Equals(providerRegions.Field("cloudregion_id"), vpcs.Field("cloudregion_id")))
  1164. sq = sq.Join(wires, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id")))
  1165. sq = sq.Join(networks, sqlchemy.Equals(wires.Field("id"), networks.Field("wire_id")))
  1166. sq = sq.Filter(sqlchemy.Equals(vpcs.Field("status"), api.VPC_STATUS_AVAILABLE))
  1167. sq = sq.Filter(sqlchemy.Equals(networks.Field("status"), api.NETWORK_STATUS_AVAILABLE))
  1168. sq = sq.Filter(sqlchemy.OR(
  1169. sqlchemy.IsNullOrEmpty(vpcs.Field("manager_id")),
  1170. sqlchemy.Equals(vpcs.Field("manager_id"), providers.Field("id")),
  1171. ))
  1172. if zone != nil {
  1173. zoneFilter := sqlchemy.OR(sqlchemy.Equals(wires.Field("zone_id"), zone.GetId()), sqlchemy.IsNullOrEmpty(wires.Field("zone_id")))
  1174. sq = sq.Filter(zoneFilter)
  1175. } else if region != nil {
  1176. sq = sq.Filter(sqlchemy.Equals(vpcs.Field("cloudregion_id"), region.GetId()))
  1177. }
  1178. q = q.Filter(sqlchemy.In(q.Field("id"), sq.SubQuery()))
  1179. }
  1180. q, err := manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
  1181. if err != nil {
  1182. return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemFilter")
  1183. }
  1184. q, err = manager.SProjectizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ProjectizedResourceListInput)
  1185. if err != nil {
  1186. return nil, errors.Wrapf(err, "SProjectizedResourceBaseManager.ListItemFilter")
  1187. }
  1188. q, err = manager.SSyncableBaseResourceManager.ListItemFilter(ctx, q, userCred, query.SyncableBaseResourceListInput)
  1189. if err != nil {
  1190. return nil, errors.Wrap(err, "SSyncableBaseResourceManager.ListItemFilter")
  1191. }
  1192. q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
  1193. if err != nil {
  1194. return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
  1195. }
  1196. managerStrs := query.CloudproviderId
  1197. conditions := []sqlchemy.ICondition{}
  1198. for _, managerStr := range managerStrs {
  1199. if len(managerStr) == 0 {
  1200. continue
  1201. }
  1202. providerObj, err := manager.FetchByIdOrName(ctx, userCred, managerStr)
  1203. if err != nil {
  1204. if err == sql.ErrNoRows {
  1205. return nil, httperrors.NewResourceNotFoundError2(CloudproviderManager.Keyword(), managerStr)
  1206. } else {
  1207. return nil, httperrors.NewGeneralError(err)
  1208. }
  1209. }
  1210. conditions = append(conditions, sqlchemy.Equals(q.Field("id"), providerObj.GetId()))
  1211. }
  1212. if len(conditions) > 0 {
  1213. q = q.Filter(sqlchemy.OR(conditions...))
  1214. }
  1215. cloudEnvStr := query.CloudEnv
  1216. if cloudEnvStr == api.CLOUD_ENV_PUBLIC_CLOUD {
  1217. cloudaccounts := CloudaccountManager.Query().SubQuery()
  1218. q = q.Join(cloudaccounts, sqlchemy.Equals(cloudaccounts.Field("id"), q.Field("cloudaccount_id")))
  1219. q = q.Filter(sqlchemy.IsTrue(cloudaccounts.Field("is_public_cloud")))
  1220. q = q.Filter(sqlchemy.IsFalse(cloudaccounts.Field("is_on_premise")))
  1221. }
  1222. if cloudEnvStr == api.CLOUD_ENV_PRIVATE_CLOUD {
  1223. cloudaccounts := CloudaccountManager.Query().SubQuery()
  1224. q = q.Join(cloudaccounts, sqlchemy.Equals(cloudaccounts.Field("id"), q.Field("cloudaccount_id")))
  1225. q = q.Filter(sqlchemy.IsFalse(cloudaccounts.Field("is_public_cloud")))
  1226. q = q.Filter(sqlchemy.IsFalse(cloudaccounts.Field("is_on_premise")))
  1227. }
  1228. if cloudEnvStr == api.CLOUD_ENV_ON_PREMISE {
  1229. cloudaccounts := CloudaccountManager.Query().SubQuery()
  1230. q = q.Join(cloudaccounts, sqlchemy.Equals(cloudaccounts.Field("id"), q.Field("cloudaccount_id")))
  1231. q = q.Filter(sqlchemy.IsFalse(cloudaccounts.Field("is_public_cloud")))
  1232. q = q.Filter(sqlchemy.IsTrue(cloudaccounts.Field("is_on_premise")))
  1233. }
  1234. capabilities := query.Capability
  1235. if len(capabilities) > 0 {
  1236. subq := CloudproviderCapabilityManager.Query("cloudprovider_id").In("capability", capabilities).Distinct().SubQuery()
  1237. q = q.In("id", subq)
  1238. }
  1239. if len(query.HealthStatus) > 0 {
  1240. q = q.In("health_status", query.HealthStatus)
  1241. }
  1242. if len(query.Providers) > 0 {
  1243. subq := CloudaccountManager.Query("id").In("provider", query.Providers).SubQuery()
  1244. q = q.In("cloudaccount_id", subq)
  1245. }
  1246. if len(query.Brands) > 0 {
  1247. subq := CloudaccountManager.Query("id").In("brand", query.Brands).SubQuery()
  1248. q = q.In("cloudaccount_id", subq)
  1249. }
  1250. if len(query.HostSchedtagId) > 0 {
  1251. schedTagObj, err := SchedtagManager.FetchByIdOrName(ctx, userCred, query.HostSchedtagId)
  1252. if err != nil {
  1253. if errors.Cause(err) == sql.ErrNoRows {
  1254. return nil, errors.Wrapf(httperrors.ErrResourceNotFound, "%s %s", SchedtagManager.Keyword(), query.HostSchedtagId)
  1255. } else {
  1256. return nil, errors.Wrap(err, "SchedtagManager.FetchByIdOrName")
  1257. }
  1258. }
  1259. subq := HostManager.Query("manager_id")
  1260. hostschedtags := HostschedtagManager.Query().Equals("schedtag_id", schedTagObj.GetId()).SubQuery()
  1261. subq = subq.Join(hostschedtags, sqlchemy.Equals(hostschedtags.Field("host_id"), subq.Field("id")))
  1262. log.Debugf("%s", subq.String())
  1263. q = q.In("id", subq.SubQuery())
  1264. }
  1265. if query.ReadOnly != nil {
  1266. sq := CloudaccountManager.Query("id").Equals("read_only", *query.ReadOnly).SubQuery()
  1267. q = q.In("cloudaccount_id", sq)
  1268. }
  1269. return q, nil
  1270. }
  1271. func (manager *SCloudproviderManager) OrderByExtraFields(
  1272. ctx context.Context,
  1273. q *sqlchemy.SQuery,
  1274. userCred mcclient.TokenCredential,
  1275. query api.CloudproviderListInput,
  1276. ) (*sqlchemy.SQuery, error) {
  1277. var err error
  1278. q, err = manager.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
  1279. if err != nil {
  1280. return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields")
  1281. }
  1282. return q, nil
  1283. }
  1284. func (manager *SCloudproviderManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  1285. var err error
  1286. if field == "manager" {
  1287. q = q.AppendField(q.Field("name").Label("manager")).Distinct()
  1288. return q, nil
  1289. }
  1290. if field == "account" {
  1291. accounts := CloudaccountManager.Query("name", "id").SubQuery()
  1292. q.AppendField(accounts.Field("name", field)).Distinct()
  1293. q = q.Join(accounts, sqlchemy.Equals(q.Field("cloudaccount_id"), accounts.Field("id")))
  1294. return q, nil
  1295. }
  1296. q, err = manager.SProjectizedResourceBaseManager.QueryDistinctExtraField(q, field)
  1297. if err == nil {
  1298. return q, nil
  1299. }
  1300. q, err = manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
  1301. if err == nil {
  1302. return q, nil
  1303. }
  1304. return q, httperrors.ErrNotFound
  1305. }
  1306. func (provider *SCloudprovider) markProviderDisconnected(ctx context.Context, userCred mcclient.TokenCredential, reason string) error {
  1307. _, err := db.UpdateWithLock(ctx, provider, func() error {
  1308. provider.HealthStatus = api.CLOUD_PROVIDER_HEALTH_UNKNOWN
  1309. return nil
  1310. })
  1311. if err != nil {
  1312. return err
  1313. }
  1314. if provider.Status != api.CLOUD_PROVIDER_DISCONNECTED {
  1315. provider.SetStatus(ctx, userCred, api.CLOUD_PROVIDER_DISCONNECTED, reason)
  1316. return provider.ClearSchedDescCache()
  1317. }
  1318. return nil
  1319. }
  1320. func (cprvd *SCloudprovider) updateName(ctx context.Context, userCred mcclient.TokenCredential, name, desc string) error {
  1321. if cprvd.Name != name || cprvd.Description != desc {
  1322. diff, err := db.Update(cprvd, func() error {
  1323. cprvd.Name = name
  1324. if len(cprvd.Description) == 0 {
  1325. cprvd.Description = desc
  1326. }
  1327. return nil
  1328. })
  1329. if err != nil {
  1330. return errors.Wrapf(err, "db.Update")
  1331. }
  1332. db.OpsLog.LogEvent(cprvd, db.ACT_UPDATE, diff, userCred)
  1333. }
  1334. return nil
  1335. }
  1336. func (provider *SCloudprovider) markProviderConnected(ctx context.Context, userCred mcclient.TokenCredential, healthStatus string) error {
  1337. if healthStatus != provider.HealthStatus {
  1338. diff, err := db.Update(provider, func() error {
  1339. provider.HealthStatus = healthStatus
  1340. return nil
  1341. })
  1342. if err != nil {
  1343. return err
  1344. }
  1345. db.OpsLog.LogEvent(provider, db.ACT_UPDATE, diff, userCred)
  1346. }
  1347. if provider.Status != api.CLOUD_PROVIDER_CONNECTED {
  1348. provider.SetStatus(ctx, userCred, api.CLOUD_PROVIDER_CONNECTED, "")
  1349. return provider.ClearSchedDescCache()
  1350. }
  1351. return nil
  1352. }
  1353. func (provider *SCloudprovider) prepareCloudproviderRegions(ctx context.Context, userCred mcclient.TokenCredential) ([]SCloudproviderregion, error) {
  1354. driver, err := provider.GetProvider(ctx)
  1355. if err != nil {
  1356. return nil, errors.Wrap(err, "provider.GetProvider")
  1357. }
  1358. err = CloudproviderCapabilityManager.setCapabilities(ctx, userCred, provider.Id, driver.GetCapabilities())
  1359. if err != nil {
  1360. return nil, errors.Wrap(err, "CloudproviderCapabilityManager.setCapabilities")
  1361. }
  1362. if driver.GetFactory().IsOnPremise() {
  1363. cpr, err := CloudproviderRegionManager.FetchByIdsOrCreate(provider.Id, api.DEFAULT_REGION_ID)
  1364. if err != nil {
  1365. return nil, errors.Wrapf(err, "FetchByIdsOrCreate")
  1366. }
  1367. cpr.setCapabilities(ctx, userCred, driver.GetCapabilities())
  1368. return []SCloudproviderregion{*cpr}, nil
  1369. }
  1370. iregions, err := driver.GetIRegions()
  1371. if err != nil {
  1372. return nil, errors.Wrapf(err, "GetIRegions")
  1373. }
  1374. externalIdPrefix := driver.GetCloudRegionExternalIdPrefix()
  1375. _, _, cprs, result := CloudregionManager.SyncRegions(ctx, userCred, provider, externalIdPrefix, iregions)
  1376. if result.IsError() {
  1377. log.Errorf("syncRegion fail %s", result.Result())
  1378. }
  1379. return cprs, nil
  1380. }
  1381. func (provider *SCloudprovider) GetCloudproviderRegions() []SCloudproviderregion {
  1382. q := CloudproviderRegionManager.Query()
  1383. q = q.Equals("cloudprovider_id", provider.Id)
  1384. // q = q.IsTrue("enabled")
  1385. // q = q.Equals("sync_status", api.CLOUD_PROVIDER_SYNC_STATUS_IDLE)
  1386. return CloudproviderRegionManager.fetchRecordsByQuery(q)
  1387. }
  1388. func (provider *SCloudprovider) GetRegions() ([]SCloudregion, error) {
  1389. q := CloudregionManager.Query()
  1390. crcp := CloudproviderRegionManager.Query().SubQuery()
  1391. q = q.Join(crcp, sqlchemy.Equals(q.Field("id"), crcp.Field("cloudregion_id"))).Filter(sqlchemy.Equals(crcp.Field("cloudprovider_id"), provider.Id))
  1392. ret := []SCloudregion{}
  1393. return ret, db.FetchModelObjects(CloudregionManager, q, &ret)
  1394. }
  1395. func (provider *SCloudprovider) GetUsableRegions() ([]SCloudregion, error) {
  1396. q := CloudregionManager.Query()
  1397. crcp := CloudproviderRegionManager.Query().SubQuery()
  1398. q = q.Join(crcp, sqlchemy.Equals(q.Field("id"), crcp.Field("cloudregion_id"))).Filter(
  1399. sqlchemy.AND(
  1400. sqlchemy.Equals(crcp.Field("cloudprovider_id"), provider.Id),
  1401. sqlchemy.IsTrue(crcp.Field("enabled")),
  1402. ),
  1403. )
  1404. ret := []SCloudregion{}
  1405. err := db.FetchModelObjects(CloudregionManager, q, &ret)
  1406. if err != nil {
  1407. return nil, err
  1408. }
  1409. return ret, nil
  1410. }
  1411. func (provider *SCloudprovider) resetAutoSync() {
  1412. cprs := provider.GetCloudproviderRegions()
  1413. for i := range cprs {
  1414. cprs[i].resetAutoSync()
  1415. }
  1416. }
  1417. func (provider *SCloudprovider) syncCloudproviderRegions(ctx context.Context, userCred mcclient.TokenCredential, syncRange SSyncRange, wg *sync.WaitGroup) {
  1418. provider.markSyncing(userCred)
  1419. cprs := provider.GetCloudproviderRegions()
  1420. regionIds, _ := syncRange.GetRegionIds()
  1421. syncCnt := 0
  1422. for i := range cprs {
  1423. if cprs[i].Enabled && cprs[i].CanSync() && (len(regionIds) == 0 || utils.IsInStringArray(cprs[i].CloudregionId, regionIds)) {
  1424. syncCnt += 1
  1425. if wg != nil {
  1426. wg.Add(1)
  1427. }
  1428. cprs[i].submitSyncTask(ctx, userCred, syncRange)
  1429. if wg != nil {
  1430. wg.Done()
  1431. }
  1432. }
  1433. }
  1434. if syncCnt == 0 {
  1435. err := provider.markEndSyncWithLock(ctx, userCred, false)
  1436. if err != nil {
  1437. log.Errorf("markEndSyncWithLock for %s error: %v", provider.Name, err)
  1438. }
  1439. }
  1440. }
  1441. func (provider *SCloudprovider) SyncCallSyncCloudproviderRegions(ctx context.Context, userCred mcclient.TokenCredential, syncRange SSyncRange) {
  1442. var wg sync.WaitGroup
  1443. provider.syncCloudproviderRegions(ctx, userCred, syncRange, &wg)
  1444. wg.Wait()
  1445. }
  1446. func (cprvd *SCloudprovider) IsAvailable() bool {
  1447. if !cprvd.GetEnabled() {
  1448. return false
  1449. }
  1450. if !utils.IsInStringArray(cprvd.Status, api.CLOUD_PROVIDER_VALID_STATUS) {
  1451. return false
  1452. }
  1453. if !utils.IsInStringArray(cprvd.HealthStatus, api.CLOUD_PROVIDER_VALID_HEALTH_STATUS) {
  1454. return false
  1455. }
  1456. return true
  1457. }
  1458. func (cprvd *SCloudprovider) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  1459. // override
  1460. log.Infof("cloud provider delete do nothing")
  1461. return nil
  1462. }
  1463. func (cprvd *SCloudprovider) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  1464. regions, err := cprvd.GetRegions()
  1465. if err != nil {
  1466. return errors.Wrapf(err, "GetRegions")
  1467. }
  1468. for i := range regions {
  1469. err = regions[i].purgeAll(ctx, cprvd.Id)
  1470. if err != nil {
  1471. return err
  1472. }
  1473. }
  1474. return cprvd.purge(ctx, userCred)
  1475. }
  1476. func (cprvd *SCloudprovider) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  1477. return cprvd.StartCloudproviderDeleteTask(ctx, userCred, "")
  1478. }
  1479. func (cprvd *SCloudprovider) StartCloudproviderDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  1480. params := jsonutils.NewDict()
  1481. task, err := taskman.TaskManager.NewTask(ctx, "CloudProviderDeleteTask", cprvd, userCred, params, parentTaskId, "", nil)
  1482. if err != nil {
  1483. return errors.Wrapf(err, "NewTask")
  1484. }
  1485. cprvd.SetStatus(ctx, userCred, api.CLOUD_PROVIDER_START_DELETE, "StartCloudproviderDeleteTask")
  1486. return task.ScheduleRun(nil)
  1487. }
  1488. func (cprvd *SCloudprovider) GetRegionDriver() (IRegionDriver, error) {
  1489. driver := GetRegionDriver(cprvd.Provider)
  1490. if driver == nil {
  1491. return nil, fmt.Errorf("failed to found region driver for %s", cprvd.Provider)
  1492. }
  1493. return driver, nil
  1494. }
  1495. func (cprvd *SCloudprovider) ClearSchedDescCache() error {
  1496. hosts := make([]SHost, 0)
  1497. q := HostManager.Query().Equals("manager_id", cprvd.Id)
  1498. err := db.FetchModelObjects(HostManager, q, &hosts)
  1499. if err != nil {
  1500. return err
  1501. }
  1502. for i := range hosts {
  1503. err := hosts[i].ClearSchedDescCache()
  1504. if err != nil {
  1505. log.Errorf("host CleanHostSchedCache error: %v", err)
  1506. return err
  1507. }
  1508. }
  1509. return nil
  1510. }
  1511. func (cprvd *SCloudprovider) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) (jsonutils.JSONObject, error) {
  1512. if strings.Index(cprvd.Status, "delet") >= 0 {
  1513. return nil, httperrors.NewInvalidStatusError("Cannot enable deleting account")
  1514. }
  1515. _, err := cprvd.SEnabledStatusStandaloneResourceBase.PerformEnable(ctx, userCred, query, input)
  1516. if err != nil {
  1517. return nil, err
  1518. }
  1519. account, err := cprvd.GetCloudaccount()
  1520. if err != nil {
  1521. return nil, err
  1522. }
  1523. if !account.GetEnabled() {
  1524. return account.enableAccountOnly(ctx, userCred, nil, input)
  1525. }
  1526. return nil, nil
  1527. }
  1528. func (cprvd *SCloudprovider) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) (jsonutils.JSONObject, error) {
  1529. _, err := cprvd.SEnabledStatusStandaloneResourceBase.PerformDisable(ctx, userCred, query, input)
  1530. if err != nil {
  1531. return nil, err
  1532. }
  1533. account, err := cprvd.GetCloudaccount()
  1534. if err != nil {
  1535. return nil, err
  1536. }
  1537. allDisable := true
  1538. providers := account.GetCloudproviders()
  1539. for i := range providers {
  1540. if providers[i].GetEnabled() {
  1541. allDisable = false
  1542. break
  1543. }
  1544. }
  1545. if allDisable && account.GetEnabled() {
  1546. return account.PerformDisable(ctx, userCred, nil, input)
  1547. }
  1548. return nil, nil
  1549. }
  1550. func (manager *SCloudproviderManager) filterByDomainId(q *sqlchemy.SQuery, domainId string) *sqlchemy.SQuery {
  1551. subq := db.SharedResourceManager.Query("resource_id")
  1552. subq = subq.Equals("resource_type", CloudaccountManager.Keyword())
  1553. subq = subq.Equals("target_project_id", domainId)
  1554. subq = subq.Equals("target_type", db.SharedTargetDomain)
  1555. cloudaccounts := CloudaccountManager.Query().SubQuery()
  1556. q = q.Join(cloudaccounts, sqlchemy.Equals(
  1557. q.Field("cloudaccount_id"),
  1558. cloudaccounts.Field("id"),
  1559. ))
  1560. q = q.Filter(sqlchemy.OR(
  1561. sqlchemy.AND(
  1562. sqlchemy.Equals(q.Field("domain_id"), domainId),
  1563. sqlchemy.Equals(cloudaccounts.Field("share_mode"), api.CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN),
  1564. ),
  1565. sqlchemy.AND(
  1566. sqlchemy.Equals(cloudaccounts.Field("share_mode"), api.CLOUD_ACCOUNT_SHARE_MODE_SYSTEM),
  1567. sqlchemy.OR(
  1568. sqlchemy.AND(
  1569. sqlchemy.Equals(cloudaccounts.Field("public_scope"), rbacscope.ScopeNone),
  1570. sqlchemy.Equals(cloudaccounts.Field("domain_id"), domainId),
  1571. ),
  1572. sqlchemy.AND(
  1573. sqlchemy.Equals(cloudaccounts.Field("public_scope"), rbacscope.ScopeDomain),
  1574. sqlchemy.OR(
  1575. sqlchemy.Equals(cloudaccounts.Field("domain_id"), domainId),
  1576. sqlchemy.In(cloudaccounts.Field("id"), subq.SubQuery()),
  1577. ),
  1578. ),
  1579. sqlchemy.Equals(cloudaccounts.Field("public_scope"), rbacscope.ScopeSystem),
  1580. ),
  1581. ),
  1582. sqlchemy.AND(
  1583. sqlchemy.Equals(cloudaccounts.Field("domain_id"), domainId),
  1584. sqlchemy.Equals(cloudaccounts.Field("share_mode"), api.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN),
  1585. ),
  1586. ))
  1587. return q
  1588. }
  1589. func (manager *SCloudproviderManager) FilterByOwner(ctx context.Context, q *sqlchemy.SQuery, man db.FilterByOwnerProvider, userCred mcclient.TokenCredential, owner mcclient.IIdentityProvider, scope rbacscope.TRbacScope) *sqlchemy.SQuery {
  1590. if owner != nil {
  1591. switch scope {
  1592. case rbacscope.ScopeProject, rbacscope.ScopeDomain:
  1593. if len(owner.GetProjectDomainId()) > 0 {
  1594. q = manager.filterByDomainId(q, owner.GetProjectDomainId())
  1595. }
  1596. }
  1597. }
  1598. return q
  1599. }
  1600. func (cprvd *SCloudprovider) GetSyncStatus2() string {
  1601. q := CloudproviderRegionManager.Query()
  1602. q = q.Equals("cloudprovider_id", cprvd.Id)
  1603. q = q.NotEquals("sync_status", api.CLOUD_PROVIDER_SYNC_STATUS_IDLE)
  1604. cnt, err := q.CountWithError()
  1605. if err != nil {
  1606. return api.CLOUD_PROVIDER_SYNC_STATUS_ERROR
  1607. }
  1608. if cnt > 0 {
  1609. return api.CLOUD_PROVIDER_SYNC_STATUS_SYNCING
  1610. } else {
  1611. return api.CLOUD_PROVIDER_SYNC_STATUS_IDLE
  1612. }
  1613. }
  1614. func (manager *SCloudproviderManager) fetchRecordsByQuery(q *sqlchemy.SQuery) []SCloudprovider {
  1615. recs := make([]SCloudprovider, 0)
  1616. err := db.FetchModelObjects(manager, q, &recs)
  1617. if err != nil {
  1618. return nil
  1619. }
  1620. return recs
  1621. }
  1622. func (manager *SCloudproviderManager) initAllRecords() {
  1623. recs := manager.fetchRecordsByQuery(manager.Query())
  1624. for i := range recs {
  1625. db.Update(&recs[i], func() error {
  1626. recs[i].SyncStatus = api.CLOUD_PROVIDER_SYNC_STATUS_IDLE
  1627. return nil
  1628. })
  1629. }
  1630. }
  1631. func (provider *SCloudprovider) GetDetailsClirc(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1632. accessUrl := provider.getAccessUrl()
  1633. passwd, err := provider.getPassword()
  1634. if err != nil {
  1635. return nil, err
  1636. }
  1637. account, err := provider.GetCloudaccount()
  1638. if err != nil {
  1639. return nil, err
  1640. }
  1641. info := cloudprovider.SProviderInfo{
  1642. Name: provider.Name,
  1643. Url: accessUrl,
  1644. Account: provider.Account,
  1645. Secret: passwd,
  1646. Options: account.Options,
  1647. }
  1648. regions, err := provider.GetRegions()
  1649. if err != nil {
  1650. return nil, errors.Wrapf(err, "GetRegions")
  1651. }
  1652. if len(regions) > 0 {
  1653. info.Region = fetchExternalId(regions[0].ExternalId)
  1654. }
  1655. rc, err := cloudprovider.GetClientRC(provider.Provider, info)
  1656. if err != nil {
  1657. return nil, err
  1658. }
  1659. return jsonutils.Marshal(rc), nil
  1660. }
  1661. func (manager *SCloudproviderManager) ResourceScope() rbacscope.TRbacScope {
  1662. return rbacscope.ScopeDomain
  1663. }
  1664. func (provider *SCloudprovider) GetDetailsStorageClasses(
  1665. ctx context.Context,
  1666. userCred mcclient.TokenCredential,
  1667. input api.CloudproviderGetStorageClassInput,
  1668. ) (api.CloudproviderGetStorageClassOutput, error) {
  1669. output := api.CloudproviderGetStorageClassOutput{}
  1670. driver, err := provider.GetProvider(ctx)
  1671. if err != nil {
  1672. return output, httperrors.NewInternalServerError("fail to get provider driver %s", err)
  1673. }
  1674. if len(input.CloudregionId) > 0 {
  1675. _, input.CloudregionResourceInput, err = ValidateCloudregionResourceInput(ctx, userCred, input.CloudregionResourceInput)
  1676. if err != nil {
  1677. return output, errors.Wrap(err, "ValidateCloudregionResourceInput")
  1678. }
  1679. }
  1680. sc := driver.GetStorageClasses(input.CloudregionId)
  1681. if sc == nil {
  1682. return output, httperrors.NewInternalServerError("storage classes not supported")
  1683. }
  1684. output.StorageClasses = sc
  1685. return output, nil
  1686. }
  1687. func (provider *SCloudprovider) GetDetailsCannedAcls(
  1688. ctx context.Context,
  1689. userCred mcclient.TokenCredential,
  1690. input api.CloudproviderGetCannedAclInput,
  1691. ) (api.CloudproviderGetCannedAclOutput, error) {
  1692. output := api.CloudproviderGetCannedAclOutput{}
  1693. driver, err := provider.GetProvider(ctx)
  1694. if err != nil {
  1695. return output, httperrors.NewInternalServerError("fail to get provider driver %s", err)
  1696. }
  1697. if len(input.CloudregionId) > 0 {
  1698. _, input.CloudregionResourceInput, err = ValidateCloudregionResourceInput(ctx, userCred, input.CloudregionResourceInput)
  1699. if err != nil {
  1700. return output, errors.Wrap(err, "ValidateCloudregionResourceInput")
  1701. }
  1702. }
  1703. output.BucketCannedAcls = driver.GetBucketCannedAcls(input.CloudregionId)
  1704. output.ObjectCannedAcls = driver.GetObjectCannedAcls(input.CloudregionId)
  1705. return output, nil
  1706. }
  1707. func (provider *SCloudprovider) getAccountShareInfo() apis.SAccountShareInfo {
  1708. account, _ := provider.GetCloudaccount()
  1709. if account != nil {
  1710. return account.getAccountShareInfo()
  1711. }
  1712. return apis.SAccountShareInfo{}
  1713. }
  1714. func (provider *SCloudprovider) IsSharable(reqUsrId mcclient.IIdentityProvider) bool {
  1715. account, _ := provider.GetCloudaccount()
  1716. if account != nil {
  1717. if account.ShareMode == api.CLOUD_ACCOUNT_SHARE_MODE_SYSTEM {
  1718. return account.IsSharable(reqUsrId)
  1719. }
  1720. }
  1721. return false
  1722. }
  1723. func (provider *SCloudprovider) GetDetailsChangeOwnerCandidateDomains(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (apis.ChangeOwnerCandidateDomainsOutput, error) {
  1724. return db.IOwnerResourceBaseModelGetChangeOwnerCandidateDomains(provider)
  1725. }
  1726. func (provider *SCloudprovider) GetChangeOwnerCandidateDomainIds() []string {
  1727. account, _ := provider.GetCloudaccount()
  1728. if account == nil {
  1729. return []string{}
  1730. }
  1731. if account.ShareMode == api.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN {
  1732. return []string{account.DomainId}
  1733. }
  1734. // if account's public_scope=domain and share_mode=provider_domain, only allow to share to specific domains
  1735. if account.PublicScope == string(rbacscope.ScopeDomain) {
  1736. sharedDomains := account.GetSharedDomains()
  1737. return append(sharedDomains, account.DomainId)
  1738. }
  1739. return []string{}
  1740. }
  1741. func (cprvd *SCloudprovider) GetExternalProjectsByProjectIdOrName(projectId, name string) ([]SExternalProject, error) {
  1742. projects := []SExternalProject{}
  1743. q := ExternalProjectManager.Query().Equals("manager_id", cprvd.Id)
  1744. q = q.Filter(
  1745. sqlchemy.OR(
  1746. sqlchemy.Equals(q.Field("name"), name),
  1747. sqlchemy.Equals(q.Field("tenant_id"), projectId),
  1748. ),
  1749. ).Desc("priority")
  1750. err := db.FetchModelObjects(ExternalProjectManager, q, &projects)
  1751. if err != nil {
  1752. return nil, errors.Wrap(err, "db.FetchModelObjects")
  1753. }
  1754. return projects, nil
  1755. }
  1756. // 若本地项目映射了多个云上项目,则在根据优先级找优先级最大的云上项目
  1757. // 若本地项目没有映射云上任何项目,则在云上新建一个同名项目
  1758. // 若本地项目a映射云上项目b,但b项目不可用,则看云上是否有a项目,有则直接使用,若没有则在云上创建a-1, a-2类似项目
  1759. func (cprvd *SCloudprovider) SyncProject(ctx context.Context, userCred mcclient.TokenCredential, id string) (string, error) {
  1760. lockman.LockRawObject(ctx, ExternalProjectManager.Keyword(), cprvd.Id)
  1761. defer lockman.ReleaseRawObject(ctx, ExternalProjectManager.Keyword(), cprvd.Id)
  1762. provider, err := cprvd.GetProvider(ctx)
  1763. if err != nil {
  1764. return "", errors.Wrap(err, "GetProvider")
  1765. }
  1766. project, err := db.TenantCacheManager.FetchTenantById(ctx, id)
  1767. if err != nil {
  1768. return "", errors.Wrapf(err, "FetchTenantById(%s)", id)
  1769. }
  1770. projects, err := cprvd.GetExternalProjectsByProjectIdOrName(id, project.Name)
  1771. if err != nil {
  1772. return "", errors.Wrapf(err, "GetExternalProjectsByProjectIdOrName(%s,%s)", id, project.Name)
  1773. }
  1774. extProj := GetAvailableExternalProject(project, projects)
  1775. if extProj != nil {
  1776. idx := strings.Index(extProj.ExternalId, "/")
  1777. if idx > -1 {
  1778. return extProj.ExternalId[idx+1:], nil
  1779. }
  1780. return extProj.ExternalId, nil
  1781. }
  1782. retry := 1
  1783. if len(projects) > 0 {
  1784. retry = 10
  1785. }
  1786. var iProject cloudprovider.ICloudProject = nil
  1787. projectName := project.Name
  1788. for i := 0; i < retry; i++ {
  1789. iProject, err = provider.CreateIProject(projectName)
  1790. if err == nil {
  1791. break
  1792. }
  1793. projectName = fmt.Sprintf("%s-%d", project.Name, i)
  1794. }
  1795. if err != nil {
  1796. if errors.Cause(err) != cloudprovider.ErrNotImplemented && errors.Cause(err) != cloudprovider.ErrNotSupported {
  1797. logclient.AddSimpleActionLog(cprvd, logclient.ACT_CREATE, err, userCred, false)
  1798. }
  1799. return "", errors.Wrapf(err, "CreateIProject(%s)", projectName)
  1800. }
  1801. extProj, err = cprvd.newFromCloudProject(ctx, userCred, project, iProject)
  1802. if err != nil {
  1803. return "", errors.Wrap(err, "newFromCloudProject")
  1804. }
  1805. db.Update(extProj, func() error {
  1806. extProj.ManagerId = cprvd.Id
  1807. return nil
  1808. })
  1809. idx := strings.Index(extProj.ExternalId, "/")
  1810. if idx > -1 {
  1811. return extProj.ExternalId[idx+1:], nil
  1812. }
  1813. return extProj.ExternalId, nil
  1814. }
  1815. func (cprvd *SCloudprovider) GetSchedtags() []SSchedtag {
  1816. return GetSchedtags(CloudproviderschedtagManager, cprvd.Id)
  1817. }
  1818. func (cprvd *SCloudprovider) GetDynamicConditionInput() *jsonutils.JSONDict {
  1819. return jsonutils.Marshal(cprvd).(*jsonutils.JSONDict)
  1820. }
  1821. func (cprvd *SCloudprovider) PerformSetSchedtag(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1822. return PerformSetResourceSchedtag(cprvd, ctx, userCred, query, data)
  1823. }
  1824. func (cprvd *SCloudprovider) GetSchedtagJointManager() ISchedtagJointManager {
  1825. return CloudproviderschedtagManager
  1826. }
  1827. func (cprvd *SCloudprovider) GetInterVpcNetworks() ([]SInterVpcNetwork, error) {
  1828. networks := []SInterVpcNetwork{}
  1829. q := InterVpcNetworkManager.Query().Equals("manager_id", cprvd.Id)
  1830. err := db.FetchModelObjects(InterVpcNetworkManager, q, &networks)
  1831. if err != nil {
  1832. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  1833. }
  1834. return networks, nil
  1835. }
  1836. func (cprvd *SCloudprovider) SyncInterVpcNetwork(ctx context.Context, userCred mcclient.TokenCredential, interVpcNetworks []cloudprovider.ICloudInterVpcNetwork, xor bool) ([]SInterVpcNetwork, []cloudprovider.ICloudInterVpcNetwork, compare.SyncResult) {
  1837. lockman.LockRawObject(ctx, cprvd.Keyword(), fmt.Sprintf("%s-interVpcNetwork", cprvd.Id))
  1838. defer lockman.ReleaseRawObject(ctx, cprvd.Keyword(), fmt.Sprintf("%s-interVpcNetwork", cprvd.Id))
  1839. result := compare.SyncResult{}
  1840. localNetworks := []SInterVpcNetwork{}
  1841. remoteNetworks := []cloudprovider.ICloudInterVpcNetwork{}
  1842. dbNetworks, err := cprvd.GetInterVpcNetworks()
  1843. if err != nil {
  1844. result.Error(errors.Wrapf(err, "GetInterVpcNetworks"))
  1845. return nil, nil, result
  1846. }
  1847. removed := make([]SInterVpcNetwork, 0)
  1848. commondb := make([]SInterVpcNetwork, 0)
  1849. commonext := make([]cloudprovider.ICloudInterVpcNetwork, 0)
  1850. added := make([]cloudprovider.ICloudInterVpcNetwork, 0)
  1851. err = compare.CompareSets(dbNetworks, interVpcNetworks, &removed, &commondb, &commonext, &added)
  1852. if err != nil {
  1853. result.Error(err)
  1854. return nil, nil, result
  1855. }
  1856. for i := 0; i < len(removed); i += 1 {
  1857. err = removed[i].syncRemove(ctx, userCred)
  1858. if err != nil {
  1859. result.DeleteError(err)
  1860. continue
  1861. }
  1862. result.Delete()
  1863. }
  1864. for i := 0; i < len(commondb); i += 1 {
  1865. if !xor {
  1866. err = commondb[i].SyncWithCloudInterVpcNetwork(ctx, userCred, commonext[i])
  1867. if err != nil {
  1868. result.UpdateError(errors.Wrapf(err, "SyncWithCloudInterVpcNetwork"))
  1869. continue
  1870. }
  1871. }
  1872. localNetworks = append(localNetworks, commondb[i])
  1873. remoteNetworks = append(remoteNetworks, commonext[i])
  1874. result.Update()
  1875. }
  1876. for i := 0; i < len(added); i += 1 {
  1877. network, err := InterVpcNetworkManager.newFromCloudInterVpcNetwork(ctx, userCred, added[i], cprvd)
  1878. if err != nil {
  1879. result.AddError(err)
  1880. continue
  1881. }
  1882. localNetworks = append(localNetworks, *network)
  1883. remoteNetworks = append(remoteNetworks, added[i])
  1884. result.Add()
  1885. }
  1886. return localNetworks, remoteNetworks, result
  1887. }
  1888. func (manager *SCloudproviderManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, keys stringutils2.SSortedStrings) (*sqlchemy.SQuery, error) {
  1889. q, err := manager.SEnabledStatusStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1890. if err != nil {
  1891. return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemExportKeys")
  1892. }
  1893. q, err = manager.SProjectizedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1894. if err != nil {
  1895. return nil, errors.Wrapf(err, "SProjectizedResourceBaseManager.ListItemExportKeys")
  1896. }
  1897. q, err = manager.SProjectMappingResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1898. if err != nil {
  1899. return nil, errors.Wrapf(err, "SProjectMappingResourceBaseManager.ListItemExportKeys")
  1900. }
  1901. return q, nil
  1902. }
  1903. // 绑定同步策略
  1904. func (cprvd *SCloudprovider) PerformProjectMapping(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudaccountProjectMappingInput) (jsonutils.JSONObject, error) {
  1905. if len(input.ProjectMappingId) > 0 {
  1906. _, err := validators.ValidateModel(ctx, userCred, ProjectMappingManager, &input.ProjectMappingId)
  1907. if err != nil {
  1908. return nil, err
  1909. }
  1910. if len(cprvd.ProjectMappingId) > 0 && cprvd.ProjectMappingId != input.ProjectMappingId {
  1911. return nil, httperrors.NewInputParameterError("cloudprovider %s has aleady bind project mapping %s", cprvd.Name, cprvd.ProjectMappingId)
  1912. }
  1913. }
  1914. _, err := db.Update(cprvd, func() error {
  1915. cprvd.ProjectMappingId = input.ProjectMappingId
  1916. if input.EnableProjectSync != nil {
  1917. cprvd.EnableProjectSync = tristate.NewFromBool(*input.EnableProjectSync)
  1918. }
  1919. if input.EnableResourceSync != nil {
  1920. cprvd.EnableResourceSync = tristate.NewFromBool(*input.EnableResourceSync)
  1921. }
  1922. return nil
  1923. })
  1924. if err != nil {
  1925. return nil, err
  1926. }
  1927. return nil, refreshPmCaches()
  1928. }
  1929. func (cprvd *SCloudprovider) PerformSetSyncing(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudproviderSync) (jsonutils.JSONObject, error) {
  1930. regionIds := []string{}
  1931. for i := range input.CloudregionIds {
  1932. _, err := validators.ValidateModel(ctx, userCred, CloudregionManager, &input.CloudregionIds[i])
  1933. if err != nil {
  1934. return nil, err
  1935. }
  1936. regionIds = append(regionIds, input.CloudregionIds[i])
  1937. }
  1938. if len(regionIds) == 0 {
  1939. return nil, nil
  1940. }
  1941. q := CloudproviderRegionManager.Query().Equals("cloudprovider_id", cprvd.Id).In("cloudregion_id", regionIds)
  1942. cpcds := []SCloudproviderregion{}
  1943. err := db.FetchModelObjects(CloudproviderRegionManager, q, &cpcds)
  1944. if err != nil {
  1945. return nil, err
  1946. }
  1947. for i := range cpcds {
  1948. _, err := db.Update(&cpcds[i], func() error {
  1949. cpcds[i].Enabled = input.Enabled
  1950. return nil
  1951. })
  1952. if err != nil {
  1953. return nil, errors.Wrapf(err, "db.Update")
  1954. }
  1955. }
  1956. return nil, nil
  1957. }
  1958. func (cprvd *SCloudprovider) SyncError(result compare.SyncResult, iNotes interface{}, userCred mcclient.TokenCredential) {
  1959. if result.IsGenerateError() {
  1960. account := &SCloudaccount{}
  1961. account.Id = cprvd.CloudaccountId
  1962. account.Name = cprvd.Account
  1963. if len(account.Name) == 0 {
  1964. account.Name = cprvd.Name
  1965. }
  1966. account.SetModelManager(CloudaccountManager, account)
  1967. logclient.AddSimpleActionLog(account, logclient.ACT_CLOUD_SYNC, iNotes, userCred, false)
  1968. }
  1969. }
  1970. func (cprvd *SCloudaccount) SyncError(result compare.SyncResult, iNotes interface{}, userCred mcclient.TokenCredential) {
  1971. if result.IsError() {
  1972. logclient.AddSimpleActionLog(cprvd, logclient.ACT_CLOUD_SYNC, iNotes, userCred, false)
  1973. }
  1974. }