| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package models
- import (
- "context"
- "database/sql"
- "fmt"
- "strings"
- "sync"
- "time"
- "yunion.io/x/cloudmux/pkg/cloudprovider"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/tristate"
- "yunion.io/x/pkg/util/compare"
- "yunion.io/x/pkg/util/rbacscope"
- "yunion.io/x/pkg/util/timeutils"
- "yunion.io/x/pkg/utils"
- "yunion.io/x/sqlchemy"
- "yunion.io/x/onecloud/pkg/apis"
- api "yunion.io/x/onecloud/pkg/apis/compute"
- "yunion.io/x/onecloud/pkg/cloudcommon/db"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/proxy"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
- "yunion.io/x/onecloud/pkg/cloudcommon/validators"
- "yunion.io/x/onecloud/pkg/compute/options"
- "yunion.io/x/onecloud/pkg/httperrors"
- "yunion.io/x/onecloud/pkg/mcclient"
- "yunion.io/x/onecloud/pkg/mcclient/auth"
- "yunion.io/x/onecloud/pkg/mcclient/modules/identity"
- "yunion.io/x/onecloud/pkg/util/logclient"
- "yunion.io/x/onecloud/pkg/util/stringutils2"
- )
- type SCloudproviderManager struct {
- db.SEnabledStatusStandaloneResourceBaseManager
- db.SProjectizedResourceBaseManager
- db.SExternalizedResourceBaseManager
- SProjectMappingResourceBaseManager
- SSyncableBaseResourceManager
- }
- var CloudproviderManager *SCloudproviderManager
- func init() {
- CloudproviderManager = &SCloudproviderManager{
- SEnabledStatusStandaloneResourceBaseManager: db.NewEnabledStatusStandaloneResourceBaseManager(
- SCloudprovider{},
- "cloudproviders_tbl",
- "cloudprovider",
- "cloudproviders",
- ),
- }
- CloudproviderManager.SetVirtualObject(CloudproviderManager)
- }
- type SCloudprovider struct {
- db.SEnabledStatusStandaloneResourceBase
- db.SProjectizedResourceBase
- db.SExternalizedResourceBase
- SSyncableBaseResource
- // 云端服务健康状态。例如欠费、项目冻结都属于不健康状态。
- //
- // | HealthStatus | 说明 |
- // |---------------|----------------------|
- // | normal | 远端处于健康状态 |
- // | insufficient | 不足按需资源余额 |
- // | suspended | 远端处于冻结状态 |
- // | arrears | 远端处于欠费状态 |
- // | unknown | 未知状态,查询失败 |
- // | no permission | 没有权限获取账单信息 |
- //
- HealthStatus string `width:"16" charset:"ascii" default:"normal" nullable:"false" list:"domain"`
- // Hostname string `width:"64" charset:"ascii" nullable:"true"` // Column(VARCHAR(64, charset='ascii'), nullable=False)
- // port = Column(Integer, nullable=False)
- // Version string `width:"32" charset:"ascii" nullable:"true" list:"domain"` // Column(VARCHAR(32, charset='ascii'), nullable=True)
- // Sysinfo jsonutils.JSONObject `get:"domain"` // Column(JSONEncodedDict, nullable=True)
- AccessUrl string `width:"128" charset:"ascii" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
- // 云账号的用户信息,例如用户名,access key等
- Account string `width:"256" charset:"ascii" nullable:"false" list:"domain" create:"domain_required"`
- // 云账号的密码信息,例如密码,access key secret等。该字段在数据库加密存储。Google需要存储秘钥证书,需要此字段比较长
- Secret string `length:"0" charset:"ascii" nullable:"false" list:"domain" create:"domain_required"`
- // 归属云账号ID
- CloudaccountId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"`
- // ProjectId string `name:"tenant_id" width:"128" charset:"ascii" nullable:"true" list:"domain"`
- // LastSync time.Time `get:"domain" list:"domain"` // = Column(DateTime, nullable=True)
- // 云账号的平台信息
- Provider string `width:"64" charset:"ascii" list:"domain" create:"domain_required"`
- // 云上同步资源是否在本地被更改过配置, local: 更改过, cloud: 未更改过
- // example: local
- ProjectSrc string `width:"10" charset:"ascii" nullable:"false" list:"user" default:"cloud" json:"project_src"`
- SProjectMappingResourceBase
- }
- type pmCache struct {
- Id string
- CloudaccountId string
- AccountProjectMappingId string
- ManagerProjectMappingId string
- AccountEnableProjectSync bool
- ManagerEnableProjectSync bool
- AccountEnableResourceSync bool
- ManagerEnableResourceSync bool
- }
- type sProjectMapping struct {
- *SProjectMapping
- EnableProjectSync bool
- EnableResourceSync bool
- }
- func (cprvd *sProjectMapping) IsNeedResourceSync() bool {
- return cprvd.EnableResourceSync || !cprvd.EnableProjectSync
- }
- func (cprvd *sProjectMapping) IsNeedProjectSync() bool {
- return cprvd.EnableProjectSync
- }
- func (cprvd *pmCache) GetProjectMapping() (*sProjectMapping, error) {
- if len(cprvd.ManagerProjectMappingId) > 0 {
- pm, err := GetRuleMapping(cprvd.ManagerProjectMappingId)
- if err != nil {
- return nil, errors.Wrapf(err, "GetRuleMapping(%s)", cprvd.ManagerProjectMappingId)
- }
- ret := &sProjectMapping{
- SProjectMapping: pm,
- EnableProjectSync: cprvd.ManagerEnableProjectSync,
- EnableResourceSync: cprvd.ManagerEnableResourceSync,
- }
- return ret, nil
- }
- if len(cprvd.AccountProjectMappingId) > 0 {
- ret := &sProjectMapping{
- EnableProjectSync: cprvd.AccountEnableProjectSync,
- EnableResourceSync: cprvd.AccountEnableResourceSync,
- }
- var err error
- ret.SProjectMapping, err = GetRuleMapping(cprvd.AccountProjectMappingId)
- return ret, err
- }
- return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty project mapping id")
- }
- var pmCaches map[string]*pmCache = map[string]*pmCache{}
- func refreshPmCaches() error {
- q := CloudproviderManager.Query().SubQuery()
- providers := q.Query(
- q.Field("cloudaccount_id"),
- q.Field("id"),
- q.Field("project_mapping_id").Label("manager_project_mapping_id"),
- q.Field("enable_project_sync").Label("manager_enable_project_sync"),
- q.Field("enable_resource_sync").Label("manager_enable_resource_sync"),
- )
- sq := CloudaccountManager.Query().SubQuery()
- mq := providers.LeftJoin(sq, sqlchemy.Equals(q.Field("cloudaccount_id"), sq.Field("id"))).
- AppendField(sq.Field("project_mapping_id").Label("account_project_mapping_id")).
- AppendField(sq.Field("enable_project_sync").Label("account_enable_project_sync")).
- AppendField(sq.Field("enable_resource_sync").Label("account_enable_resource_sync"))
- caches := []pmCache{}
- err := mq.All(&caches)
- if err != nil {
- return errors.Wrapf(err, "q.All")
- }
- for i := range caches {
- pmCaches[caches[i].Id] = &caches[i]
- }
- return nil
- }
- func (cprvd *SCloudaccount) GetProjectMapping() (*sProjectMapping, error) {
- cache, err := func() (*pmCache, error) {
- for id := range pmCaches {
- if pmCaches[id].CloudaccountId == cprvd.Id {
- return pmCaches[id], nil
- }
- }
- err := refreshPmCaches()
- if err != nil {
- return nil, errors.Wrapf(err, "refreshPmCaches")
- }
- for id := range pmCaches {
- if pmCaches[id].CloudaccountId == cprvd.Id {
- return pmCaches[id], nil
- }
- }
- return nil, cloudprovider.ErrNotFound
- }()
- if err != nil {
- return nil, errors.Wrapf(err, "get project mapping cache")
- }
- return cache.GetProjectMapping()
- }
- func (cprvd *SCloudprovider) GetProjectMapping() (*sProjectMapping, error) {
- cache, err := func() (*pmCache, error) {
- mp, ok := pmCaches[cprvd.Id]
- if ok {
- return mp, nil
- }
- err := refreshPmCaches()
- if err != nil {
- return nil, errors.Wrapf(err, "refreshPmCaches")
- }
- return pmCaches[cprvd.Id], nil
- }()
- if err != nil {
- return nil, errors.Wrapf(err, "get project mapping cache")
- }
- return cache.GetProjectMapping()
- }
- func (cprvd *SCloudprovider) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
- if cprvd.GetEnabled() {
- return httperrors.NewInvalidStatusError("provider is enabled")
- }
- if cprvd.SyncStatus != api.CLOUD_PROVIDER_SYNC_STATUS_IDLE {
- return httperrors.NewInvalidStatusError("provider is not idle")
- }
- return cprvd.SEnabledStatusStandaloneResourceBase.ValidateDeleteCondition(ctx, nil)
- }
- func (manager *SCloudproviderManager) GetPublicProviderIdsQuery() *sqlchemy.SSubQuery {
- return manager.GetProviderIdsQuery(tristate.True, tristate.None, nil, nil)
- }
- func (manager *SCloudproviderManager) GetPrivateProviderIdsQuery() *sqlchemy.SSubQuery {
- return manager.GetProviderIdsQuery(tristate.False, tristate.False, nil, nil)
- }
- func (manager *SCloudproviderManager) GetOnPremiseProviderIdsQuery() *sqlchemy.SSubQuery {
- return manager.GetProviderIdsQuery(tristate.None, tristate.True, nil, nil)
- }
- func (manager *SCloudproviderManager) GetPrivateOrOnPremiseProviderIdsQuery() *sqlchemy.SSubQuery {
- return manager.GetProviderIdsQuery(tristate.False, tristate.None, nil, nil)
- }
- func (manager *SCloudproviderManager) GetProviderIdsQuery(isPublic tristate.TriState, isOnPremise tristate.TriState, providers []string, brands []string) *sqlchemy.SSubQuery {
- return manager.GetProviderFieldQuery("id", isPublic, isOnPremise, providers, brands)
- }
- func (manager *SCloudproviderManager) GetPublicProviderProvidersQuery() *sqlchemy.SSubQuery {
- return manager.GetProviderProvidersQuery(tristate.True, tristate.None)
- }
- func (manager *SCloudproviderManager) GetPrivateProviderProvidersQuery() *sqlchemy.SSubQuery {
- return manager.GetProviderProvidersQuery(tristate.False, tristate.False)
- }
- func (manager *SCloudproviderManager) GetOnPremiseProviderProvidersQuery() *sqlchemy.SSubQuery {
- return manager.GetProviderProvidersQuery(tristate.None, tristate.True)
- }
- func (manager *SCloudproviderManager) GetProviderProvidersQuery(isPublic tristate.TriState, isOnPremise tristate.TriState) *sqlchemy.SSubQuery {
- return manager.GetProviderFieldQuery("provider", isPublic, isOnPremise, nil, nil)
- }
- func (manager *SCloudproviderManager) GetProviderFieldQuery(field string, isPublic tristate.TriState, isOnPremise tristate.TriState, providers []string, brands []string) *sqlchemy.SSubQuery {
- q := manager.Query(field).Distinct()
- account := CloudaccountManager.Query().SubQuery()
- q = q.Join(account, sqlchemy.Equals(
- account.Field("id"), q.Field("cloudaccount_id")),
- )
- if isPublic.IsTrue() {
- q = q.Filter(sqlchemy.IsTrue(account.Field("is_public_cloud")))
- } else if isPublic.IsFalse() {
- q = q.Filter(sqlchemy.IsFalse(account.Field("is_public_cloud")))
- }
- if isOnPremise.IsTrue() {
- q = q.Filter(sqlchemy.IsTrue(account.Field("is_on_premise")))
- } else if isOnPremise.IsFalse() {
- q = q.Filter(sqlchemy.IsFalse(account.Field("is_on_premise")))
- }
- if len(providers) > 0 || len(brands) > 0 {
- q = q.Filter(sqlchemy.OR(
- sqlchemy.In(account.Field("provider"), providers),
- sqlchemy.In(account.Field("brand"), brands),
- ))
- }
- return q.SubQuery()
- }
- func CloudProviderFilter(q *sqlchemy.SQuery, managerIdField sqlchemy.IQueryField, providers []string, brands []string, cloudEnv string) *sqlchemy.SQuery {
- if len(cloudEnv) == 0 && len(providers) == 0 && len(brands) == 0 {
- return q
- }
- isPublic := tristate.None
- isOnPremise := tristate.None
- includeOneCloud := false
- switch cloudEnv {
- case api.CLOUD_ENV_PUBLIC_CLOUD:
- isPublic = tristate.True
- case api.CLOUD_ENV_PRIVATE_CLOUD:
- isPublic = tristate.False
- isOnPremise = tristate.False
- case api.CLOUD_ENV_ON_PREMISE:
- isOnPremise = tristate.True
- includeOneCloud = true
- default:
- includeOneCloud = true
- }
- if includeOneCloud && len(providers) > 0 && !utils.IsInStringArray(api.CLOUD_PROVIDER_ONECLOUD, providers) {
- includeOneCloud = false
- }
- if includeOneCloud && len(brands) > 0 && !utils.IsInStringArray(api.CLOUD_PROVIDER_ONECLOUD, brands) {
- includeOneCloud = false
- }
- subq := CloudproviderManager.GetProviderIdsQuery(isPublic, isOnPremise, providers, brands)
- if includeOneCloud {
- return q.Filter(sqlchemy.OR(
- sqlchemy.In(managerIdField, subq),
- sqlchemy.IsNullOrEmpty(managerIdField),
- ))
- } else {
- return q.Filter(sqlchemy.In(managerIdField, subq))
- }
- }
- func (cprvd *SCloudprovider) CleanSchedCache() {
- hosts := []SHost{}
- q := HostManager.Query().Equals("manager_id", cprvd.Id)
- if err := db.FetchModelObjects(HostManager, q, &hosts); err != nil {
- log.Errorf("failed to get hosts for cloudprovider %s error: %v", cprvd.Name, err)
- return
- }
- for _, host := range hosts {
- host.ClearSchedDescCache()
- }
- }
- func (cprvd *SCloudprovider) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudproviderUpdateInput) (api.CloudproviderUpdateInput, error) {
- var err error
- input.EnabledStatusStandaloneResourceBaseUpdateInput, err = cprvd.SEnabledStatusStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.EnabledStatusStandaloneResourceBaseUpdateInput)
- if err != nil {
- return input, errors.Wrap(err, "SEnabledStatusStandaloneResourceBase.ValidateUpdateData")
- }
- return input, nil
- }
- // +onecloud:swagger-gen-ignore
- func (cprvd *SCloudproviderManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.CloudproviderCreateInput) (api.CloudproviderCreateInput, error) {
- return input, httperrors.NewUnsupportOperationError("Directly creating cloudprovider is not supported, create cloudaccount instead")
- }
- func (cprvd *SCloudprovider) getAccessUrl() string {
- if len(cprvd.AccessUrl) > 0 {
- return cprvd.AccessUrl
- }
- account, _ := cprvd.GetCloudaccount()
- if account != nil {
- return account.AccessUrl
- }
- return ""
- }
- func (cprvd *SCloudprovider) getPassword() (string, error) {
- if len(cprvd.Secret) == 0 {
- account, err := cprvd.GetCloudaccount()
- if err != nil {
- return "", errors.Wrapf(err, "GetCloudaccount")
- }
- return account.getPassword()
- }
- return utils.DescryptAESBase64(cprvd.Id, cprvd.Secret)
- }
- func getTenant(ctx context.Context, projectId string, name string, domainId string) (*db.STenant, error) {
- if len(projectId) > 0 {
- tenant, err := db.TenantCacheManager.FetchTenantById(ctx, projectId)
- if err != nil {
- return nil, errors.Wrap(err, "TenantCacheManager.FetchTenantById")
- }
- return tenant, nil
- }
- if len(name) == 0 {
- return nil, errors.Error("cannot syncProject for empty name")
- }
- return db.TenantCacheManager.FetchTenantByNameInDomain(ctx, name, domainId)
- }
- func createTenant(ctx context.Context, name, domainId, desc string, tags map[string]string) (string, string, error) {
- s := auth.GetAdminSession(ctx, options.Options.Region)
- params := jsonutils.NewDict()
- params.Add(jsonutils.NewString(name), "generate_name")
- params.Add(jsonutils.NewString(domainId), "domain_id")
- params.Add(jsonutils.NewString(desc), "description")
- meta := map[string]string{}
- for k, v := range tags {
- k = db.USER_TAG_PREFIX + strings.TrimPrefix(k, db.USER_TAG_PREFIX)
- meta[k] = v
- }
- params.Set("__meta__", jsonutils.Marshal(meta))
- resp, err := identity.Projects.Create(s, params)
- if err != nil {
- return "", "", errors.Wrap(err, "Projects.Create")
- }
- projectId, err := resp.GetString("id")
- if err != nil {
- return "", "", errors.Wrap(err, "resp.GetString")
- }
- _, err = db.TenantCacheManager.FetchTenantById(ctx, projectId)
- if err != nil {
- log.Errorf("fetch tenant %s error: %v", name, err)
- }
- return domainId, projectId, nil
- }
- func (cprvd *SCloudprovider) syncProject(ctx context.Context, userCred mcclient.TokenCredential) error {
- account, err := cprvd.GetCloudaccount()
- if err != nil {
- return errors.Wrapf(err, "GetCloudaccount")
- }
- desc := fmt.Sprintf("auto create from cloud provider %s (%s)", cprvd.Name, cprvd.Id)
- domainId, projectId, err := account.getOrCreateTenant(ctx, cprvd.Name, "", cprvd.ProjectId, desc, nil)
- if err != nil {
- return errors.Wrap(err, "getOrCreateTenant")
- }
- return cprvd.saveProject(userCred, domainId, projectId, true)
- }
- func (cprvd *SCloudprovider) saveProject(userCred mcclient.TokenCredential, domainId, projectId string, auto bool) error {
- if projectId != cprvd.ProjectId {
- diff, err := db.Update(cprvd, func() error {
- cprvd.DomainId = domainId
- cprvd.ProjectId = projectId
- // 自动改变项目时不改变配置,仅在performChangeOnwer(手动更改项目)时改变
- if !auto {
- cprvd.ProjectSrc = string(apis.OWNER_SOURCE_LOCAL)
- }
- return nil
- })
- if err != nil {
- log.Errorf("update projectId fail: %s", err)
- return err
- }
- db.OpsLog.LogEvent(cprvd, db.ACT_UPDATE, diff, userCred)
- }
- return nil
- }
- type SSyncRange struct {
- api.SyncRangeInput
- }
- func (sr *SSyncRange) GetRegionIds() ([]string, error) {
- regionIds := []string{}
- if len(sr.Host) == 0 && len(sr.Zone) == 0 && len(sr.Region) == 0 {
- return regionIds, nil
- }
- hostQ := HostManager.Query().SubQuery()
- hosts := hostQ.Query().Filter(sqlchemy.OR(
- sqlchemy.In(hostQ.Field("id"), sr.Host),
- sqlchemy.In(hostQ.Field("name"), sr.Host),
- )).SubQuery()
- zoneQ := ZoneManager.Query().SubQuery()
- zones := zoneQ.Query().Filter(sqlchemy.OR(
- sqlchemy.In(zoneQ.Field("id"), sr.Zone),
- sqlchemy.In(zoneQ.Field("name"), sr.Zone),
- sqlchemy.In(zoneQ.Field("id"), hosts.Query(hosts.Field("zone_id")).SubQuery()),
- )).SubQuery()
- regionQ := CloudregionManager.Query().SubQuery()
- q := regionQ.Query(regionQ.Field("id")).Filter(sqlchemy.OR(
- sqlchemy.In(regionQ.Field("id"), sr.Region),
- sqlchemy.In(regionQ.Field("name"), sr.Region),
- sqlchemy.In(regionQ.Field("id"), zones.Query(zones.Field("cloudregion_id")).SubQuery()),
- ))
- rows, err := q.Rows()
- if err != nil {
- return nil, errors.Wrap(err, "q.Rows")
- }
- defer rows.Close()
- for rows.Next() {
- var regionId string
- err = rows.Scan(®ionId)
- if err != nil {
- return nil, errors.Wrap(err, "rows.Scan")
- }
- regionIds = append(regionIds, regionId)
- }
- return regionIds, nil
- }
- func (sr *SSyncRange) NeedSyncResource(res string) bool {
- if sr.FullSync {
- return true
- }
- if len(sr.Resources) == 0 {
- return true
- }
- return utils.IsInStringArray(res, sr.Resources)
- }
- func (sr *SSyncRange) NeedSyncInfo() bool {
- if sr.FullSync {
- return true
- }
- if len(sr.Region) > 0 || len(sr.Zone) > 0 || len(sr.Host) > 0 || len(sr.Resources) > 0 {
- return true
- }
- return false
- }
- func (sr *SSyncRange) normalizeRegionIds(ctx context.Context) error {
- for i := 0; i < len(sr.Region); i += 1 {
- obj, err := CloudregionManager.FetchByIdOrName(ctx, nil, sr.Region[i])
- if err != nil {
- if err == sql.ErrNoRows {
- return httperrors.NewResourceNotFoundError("Region %s not found", sr.Region[i])
- } else {
- return err
- }
- }
- sr.Region[i] = obj.GetId()
- }
- return nil
- }
- func (sr *SSyncRange) normalizeZoneIds(ctx context.Context) error {
- for i := 0; i < len(sr.Zone); i += 1 {
- obj, err := ZoneManager.FetchByIdOrName(ctx, nil, sr.Zone[i])
- if err != nil {
- if err == sql.ErrNoRows {
- return httperrors.NewResourceNotFoundError("Zone %s not found", sr.Zone[i])
- } else {
- return err
- }
- }
- zone := obj.(*SZone)
- region, _ := zone.GetRegion()
- if region == nil {
- continue
- }
- sr.Zone[i] = zone.GetId()
- if !utils.IsInStringArray(region.Id, sr.Region) {
- sr.Region = append(sr.Region, region.Id)
- }
- }
- return nil
- }
- func (sr *SSyncRange) normalizeHostIds(ctx context.Context) error {
- for i := 0; i < len(sr.Host); i += 1 {
- obj, err := HostManager.FetchByIdOrName(ctx, nil, sr.Host[i])
- if err != nil {
- if err == sql.ErrNoRows {
- return httperrors.NewResourceNotFoundError("Host %s not found", sr.Host[i])
- } else {
- return err
- }
- }
- host := obj.(*SHost)
- zone, _ := host.GetZone()
- if zone == nil {
- continue
- }
- region, _ := zone.GetRegion()
- if region == nil {
- continue
- }
- sr.Host[i] = host.GetId()
- if !utils.IsInStringArray(zone.Id, sr.Zone) {
- sr.Zone = append(sr.Zone, zone.Id)
- }
- if !utils.IsInStringArray(region.Id, sr.Region) {
- sr.Region = append(sr.Region, region.Id)
- }
- }
- return nil
- }
- func (sr *SSyncRange) Normalize(ctx context.Context) error {
- if sr.Region != nil && len(sr.Region) > 0 {
- err := sr.normalizeRegionIds(ctx)
- if err != nil {
- return err
- }
- } else {
- sr.Region = make([]string, 0)
- }
- if sr.Zone != nil && len(sr.Zone) > 0 {
- err := sr.normalizeZoneIds(ctx)
- if err != nil {
- return err
- }
- } else {
- sr.Zone = make([]string, 0)
- }
- if sr.Host != nil && len(sr.Host) > 0 {
- err := sr.normalizeHostIds(ctx)
- if err != nil {
- return err
- }
- } else {
- sr.Host = make([]string, 0)
- }
- return nil
- }
- func (cprvd *SCloudprovider) PerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.SyncRangeInput) (jsonutils.JSONObject, error) {
- if !cprvd.GetEnabled() {
- return nil, httperrors.NewInvalidStatusError("Cloudprovider disabled")
- }
- account, err := cprvd.GetCloudaccount()
- if err != nil {
- return nil, errors.Wrapf(err, "GetCloudaccount")
- }
- if !account.GetEnabled() {
- return nil, httperrors.NewInvalidStatusError("Cloudaccount disabled")
- }
- syncRange := SSyncRange{input}
- if syncRange.FullSync || len(syncRange.Region) > 0 || len(syncRange.Zone) > 0 || len(syncRange.Host) > 0 || len(syncRange.Resources) > 0 {
- syncRange.DeepSync = true
- }
- syncRange.SkipSyncResources = []string{}
- if account.SkipSyncResources != nil {
- for _, res := range *account.SkipSyncResources {
- syncRange.SkipSyncResources = append(syncRange.SkipSyncResources, res)
- }
- }
- if cprvd.CanSync() || syncRange.Force {
- return nil, cprvd.StartSyncCloudProviderInfoTask(ctx, userCred, &syncRange, "")
- }
- return nil, httperrors.NewInvalidStatusError("Unable to synchronize frequently")
- }
- func (cprvd *SCloudprovider) StartSyncCloudProviderInfoTask(ctx context.Context, userCred mcclient.TokenCredential, syncRange *SSyncRange, parentTaskId string) error {
- params := jsonutils.NewDict()
- if syncRange != nil {
- params.Add(jsonutils.Marshal(syncRange), "sync_range")
- }
- task, err := taskman.TaskManager.NewTask(ctx, "CloudProviderSyncInfoTask", cprvd, userCred, params, parentTaskId, "", nil)
- if err != nil {
- return errors.Wrapf(err, "NewTask")
- }
- if cloudaccount, _ := cprvd.GetCloudaccount(); cloudaccount != nil {
- cloudaccount.MarkSyncing(userCred)
- }
- cprvd.markStartSync(userCred, syncRange)
- db.OpsLog.LogEvent(cprvd, db.ACT_SYNC_HOST_START, "", userCred)
- return task.ScheduleRun(nil)
- }
- func (cprvd *SCloudprovider) PerformChangeProject(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) (jsonutils.JSONObject, error) {
- project := input.ProjectId
- domain := input.ProjectDomainId
- if len(domain) == 0 {
- domain = cprvd.DomainId
- }
- tenant, err := db.TenantCacheManager.FetchTenantByIdOrNameInDomain(ctx, project, domain)
- if err != nil {
- return nil, httperrors.NewNotFoundError("project %s not found", project)
- }
- if cprvd.ProjectId == tenant.Id {
- return nil, nil
- }
- account, err := cprvd.GetCloudaccount()
- if err != nil {
- return nil, err
- }
- if cprvd.DomainId != tenant.DomainId {
- if !db.IsAdminAllowPerform(ctx, userCred, cprvd, "change-project") {
- return nil, httperrors.NewForbiddenError("not allow to change project across domain")
- }
- if account.ShareMode == api.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN && account.DomainId != tenant.DomainId {
- return nil, httperrors.NewInvalidStatusError("cannot change to a different domain from a private cloud account")
- }
- // if account's public_scope=domain and share_mode=provider_domain, only allow to share to specific domains
- if account.PublicScope == string(rbacscope.ScopeDomain) {
- sharedDomains := account.GetSharedDomains()
- if !utils.IsInStringArray(tenant.DomainId, sharedDomains) && account.DomainId != tenant.DomainId {
- return nil, errors.Wrap(httperrors.ErrForbidden, "cannot set to domain outside of the shared domains")
- }
- }
- // otherwise, allow change project across domain
- }
- notes := struct {
- OldProjectId string
- OldDomainId string
- NewProjectId string
- NewProject string
- NewDomainId string
- NewDomain string
- }{
- OldProjectId: cprvd.ProjectId,
- OldDomainId: cprvd.DomainId,
- NewProjectId: tenant.Id,
- NewProject: tenant.Name,
- NewDomainId: tenant.DomainId,
- NewDomain: tenant.Domain,
- }
- err = cprvd.saveProject(userCred, tenant.DomainId, tenant.Id, false)
- if err != nil {
- log.Errorf("Update cloudprovider error: %v", err)
- return nil, httperrors.NewGeneralError(err)
- }
- logclient.AddSimpleActionLog(cprvd, logclient.ACT_CHANGE_OWNER, notes, userCred, true)
- return nil, cprvd.StartSyncCloudProviderInfoTask(ctx, userCred, &SSyncRange{SyncRangeInput: api.SyncRangeInput{
- FullSync: true, DeepSync: true,
- }}, "")
- }
- func (cprvd *SCloudprovider) markStartingSync(userCred mcclient.TokenCredential, syncRange *SSyncRange) error {
- _, err := db.Update(cprvd, func() error {
- cprvd.SyncStatus = api.CLOUD_PROVIDER_SYNC_STATUS_QUEUING
- return nil
- })
- if err != nil {
- return errors.Wrap(err, "db.Update")
- }
- cprs := cprvd.GetCloudproviderRegions()
- for i := range cprs {
- if cprs[i].Enabled {
- err := cprs[i].markStartingSync(userCred, syncRange)
- if err != nil {
- return errors.Wrap(err, "cprs[i].markStartingSync")
- }
- }
- }
- return nil
- }
- func (cprvd *SCloudprovider) markStartSync(userCred mcclient.TokenCredential, syncRange *SSyncRange) error {
- _, err := db.Update(cprvd, func() error {
- cprvd.SyncStatus = api.CLOUD_PROVIDER_SYNC_STATUS_QUEUED
- return nil
- })
- if err != nil {
- return errors.Wrapf(err, "db.Update")
- }
- cprs := cprvd.GetCloudproviderRegions()
- for i := range cprs {
- if cprs[i].Enabled {
- err := cprs[i].markStartingSync(userCred, syncRange)
- if err != nil {
- return errors.Wrap(err, "cprs[i].markStartingSync")
- }
- }
- }
- return nil
- }
- func (cprvd *SCloudprovider) markSyncing(userCred mcclient.TokenCredential) error {
- _, err := db.Update(cprvd, func() error {
- cprvd.SyncStatus = api.CLOUD_PROVIDER_SYNC_STATUS_SYNCING
- cprvd.LastSync = timeutils.UtcNow()
- cprvd.LastSyncEndAt = time.Time{}
- return nil
- })
- if err != nil {
- log.Errorf("Failed to markSyncing error: %v", err)
- return err
- }
- return nil
- }
- func (cprvd *SCloudprovider) markEndSyncWithLock(ctx context.Context, userCred mcclient.TokenCredential, deepSync bool) error {
- err := func() error {
- lockman.LockObject(ctx, cprvd)
- defer lockman.ReleaseObject(ctx, cprvd)
- if cprvd.SyncStatus == api.CLOUD_PROVIDER_SYNC_STATUS_IDLE {
- return nil
- }
- if cprvd.GetSyncStatus2() != api.CLOUD_PROVIDER_SYNC_STATUS_IDLE {
- return nil
- }
- err := cprvd.markEndSync(userCred)
- if err != nil {
- return err
- }
- return nil
- }()
- if err != nil {
- return err
- }
- account, err := cprvd.GetCloudaccount()
- if err != nil {
- return errors.Wrapf(err, "GetCloudaccount")
- }
- return account.MarkEndSyncWithLock(ctx, userCred, deepSync)
- }
- func (cprvd *SCloudprovider) markEndSync(userCred mcclient.TokenCredential) error {
- _, err := db.Update(cprvd, func() error {
- cprvd.SyncStatus = api.CLOUD_PROVIDER_SYNC_STATUS_IDLE
- cprvd.LastSyncEndAt = timeutils.UtcNow()
- return nil
- })
- if err != nil {
- return errors.Wrapf(err, "markEndSync")
- }
- return nil
- }
- func (cprvd *SCloudprovider) cancelStartingSync(userCred mcclient.TokenCredential) error {
- if cprvd.SyncStatus == api.CLOUD_PROVIDER_SYNC_STATUS_QUEUING {
- cprs := cprvd.GetCloudproviderRegions()
- for i := range cprs {
- err := cprs[i].cancelStartingSync(userCred)
- if err != nil {
- return errors.Wrap(err, "cprs[i].cancelStartingSync")
- }
- }
- _, err := db.Update(cprvd, func() error {
- cprvd.SyncStatus = api.CLOUD_PROVIDER_SYNC_STATUS_IDLE
- return nil
- })
- if err != nil {
- return errors.Wrap(err, "db.Update")
- }
- }
- return nil
- }
- func (cprvd *SCloudprovider) GetProviderFactory() (cloudprovider.ICloudProviderFactory, error) {
- return cloudprovider.GetProviderFactory(cprvd.Provider)
- }
- func (cprvd *SCloudprovider) GetProvider(ctx context.Context) (cloudprovider.ICloudProvider, error) {
- if !cprvd.GetEnabled() {
- return nil, errors.Wrap(httperrors.ErrInvalidStatus, "Cloud provider is not enabled")
- }
- accessUrl := cprvd.getAccessUrl()
- passwd, err := cprvd.getPassword()
- if err != nil {
- return nil, err
- }
- account, err := cprvd.GetCloudaccount()
- if err != nil {
- return nil, errors.Wrapf(err, "GetCloudaccount")
- }
- return cloudprovider.GetProvider(cloudprovider.ProviderConfig{
- Id: cprvd.Id,
- Name: cprvd.Name,
- Vendor: cprvd.Provider,
- URL: accessUrl,
- Account: cprvd.Account,
- Secret: passwd,
- ProxyFunc: account.proxyFunc(),
- AliyunResourceGroupIds: options.Options.AliyunResourceGroups,
- ReadOnly: account.ReadOnly,
- RegionId: account.regionId(),
- Options: account.Options,
- UpdatePermission: account.UpdatePermission(ctx),
- })
- }
- func (cprvd *SCloudprovider) savePassword(secret string) error {
- sec, err := utils.EncryptAESBase64(cprvd.Id, secret)
- if err != nil {
- return err
- }
- _, err = db.Update(cprvd, func() error {
- cprvd.Secret = sec
- return nil
- })
- return err
- }
- func (cprvd *SCloudprovider) GetCloudaccount() (*SCloudaccount, error) {
- obj, err := CloudaccountManager.FetchById(cprvd.CloudaccountId)
- if err != nil {
- return nil, errors.Wrapf(err, "FetchById(%s)", cprvd.CloudaccountId)
- }
- return obj.(*SCloudaccount), nil
- }
- func (manager *SCloudproviderManager) FetchCloudproviderById(providerId string) *SCloudprovider {
- providerObj, err := manager.FetchById(providerId)
- if err != nil {
- return nil
- }
- return providerObj.(*SCloudprovider)
- }
- func IsProviderAccountEnabled(providerId string) bool {
- if len(providerId) == 0 {
- return true
- }
- return CloudproviderManager.IsProviderAccountEnabled(providerId)
- }
- func (manager *SCloudproviderManager) IsProviderAccountEnabled(providerId string) bool {
- providerObj := manager.FetchCloudproviderById(providerId)
- if providerObj == nil {
- return false
- }
- if !providerObj.GetEnabled() {
- return false
- }
- account, _ := providerObj.GetCloudaccount()
- if account == nil {
- return false
- }
- return account.GetEnabled()
- }
- func (manager *SCloudproviderManager) FetchCloudproviderByIdOrName(ctx context.Context, providerId string) *SCloudprovider {
- providerObj, err := manager.FetchByIdOrName(ctx, nil, providerId)
- if err != nil {
- if err != sql.ErrNoRows {
- log.Errorf("%s", err)
- }
- return nil
- }
- return providerObj.(*SCloudprovider)
- }
- func (cm *SCloudproviderManager) query(manager db.IModelManager, field string, providerIds []string, filter func(*sqlchemy.SQuery) *sqlchemy.SQuery) *sqlchemy.SSubQuery {
- q := manager.Query()
- if filter != nil {
- q = filter(q)
- }
- sq := q.SubQuery()
- key := "manager_id"
- if manager.Keyword() == CloudproviderRegionManager.Keyword() {
- key = "cloudprovider_id"
- }
- return sq.Query(
- sq.Field(key),
- sqlchemy.COUNT(field),
- ).In(key, providerIds).GroupBy(sq.Field(key)).SubQuery()
- }
- type SCloudproviderUsageCount struct {
- Id string
- api.SCloudproviderUsage
- }
- func (cm *SCloudproviderManager) TotalResourceCount(providerIds []string) (map[string]api.SCloudproviderUsage, error) {
- ret := map[string]api.SCloudproviderUsage{}
- guestSQ := cm.query(GuestManager, "guest_cnt", providerIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- hosts := HostManager.Query().SubQuery()
- sq := q.SubQuery()
- return sq.Query(
- sq.Field("id").Label("guest_id"),
- sq.Field("host_id").Label("host_id"),
- hosts.Field("manager_id").Label("manager_id"),
- ).LeftJoin(hosts, sqlchemy.Equals(sq.Field("host_id"), hosts.Field("id")))
- })
- hostSQ := cm.query(HostManager, "host_cnt", providerIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- return q.IsFalse("is_emulated")
- })
- vpcSQ := cm.query(VpcManager, "vpc_cnt", providerIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- return q.IsFalse("is_emulated")
- })
- storageSQ := cm.query(StorageManager, "storage_cnt", providerIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- return q.IsFalse("is_emulated")
- })
- storagecacheSQ := cm.query(StoragecacheManager, "storage_cache_cnt", providerIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- return q.IsFalse("is_emulated")
- })
- redisSQ := cm.query(ElasticcacheManager, "elasticcache_cnt", providerIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- vpcs := VpcManager.Query().SubQuery()
- sq := q.SubQuery()
- return sq.Query(
- sq.Field("id").Label("redis_id"),
- sq.Field("vpc_id").Label("vpc_id"),
- vpcs.Field("manager_id").Label("manager_id"),
- ).LeftJoin(vpcs, sqlchemy.Equals(sq.Field("vpc_id"), vpcs.Field("id")))
- })
- eipSQ := cm.query(ElasticipManager, "eip_cnt", providerIds, nil)
- snapshotSQ := cm.query(SnapshotManager, "snapshot_cnt", providerIds, nil)
- lbSQ := cm.query(LoadbalancerManager, "loadbalancer_cnt", providerIds, nil)
- rdsSQ := cm.query(DBInstanceManager, "dbinstance_cnt", providerIds, nil)
- projectSQ := cm.query(ExternalProjectManager, "project_cnt", providerIds, nil)
- sregionSQ := cm.query(CloudproviderRegionManager, "sync_region_cnt", providerIds, nil)
- providers := cm.Query().SubQuery()
- providerQ := providers.Query(
- sqlchemy.SUM("guest_count", guestSQ.Field("guest_cnt")),
- sqlchemy.SUM("host_count", hostSQ.Field("host_cnt")),
- sqlchemy.SUM("vpc_count", vpcSQ.Field("vpc_cnt")),
- sqlchemy.SUM("storage_count", storageSQ.Field("storage_cnt")),
- sqlchemy.SUM("storage_cache_count", storagecacheSQ.Field("storage_cache_cnt")),
- sqlchemy.SUM("eip_count", eipSQ.Field("eip_cnt")),
- sqlchemy.SUM("snapshot_count", snapshotSQ.Field("snapshot_cnt")),
- sqlchemy.SUM("loadbalancer_count", lbSQ.Field("loadbalancer_cnt")),
- sqlchemy.SUM("dbinstance_count", rdsSQ.Field("dbinstance_cnt")),
- sqlchemy.SUM("elasticcache_count", redisSQ.Field("elasticcache_cnt")),
- sqlchemy.SUM("project_count", projectSQ.Field("project_cnt")),
- sqlchemy.SUM("sync_region_count", sregionSQ.Field("sync_region_cnt")),
- )
- providerQ.AppendField(providerQ.Field("id"))
- providerQ = providerQ.LeftJoin(guestSQ, sqlchemy.Equals(providerQ.Field("id"), guestSQ.Field("manager_id")))
- providerQ = providerQ.LeftJoin(hostSQ, sqlchemy.Equals(providerQ.Field("id"), hostSQ.Field("manager_id")))
- providerQ = providerQ.LeftJoin(vpcSQ, sqlchemy.Equals(providerQ.Field("id"), vpcSQ.Field("manager_id")))
- providerQ = providerQ.LeftJoin(storageSQ, sqlchemy.Equals(providerQ.Field("id"), storageSQ.Field("manager_id")))
- providerQ = providerQ.LeftJoin(storagecacheSQ, sqlchemy.Equals(providerQ.Field("id"), storagecacheSQ.Field("manager_id")))
- providerQ = providerQ.LeftJoin(eipSQ, sqlchemy.Equals(providerQ.Field("id"), eipSQ.Field("manager_id")))
- providerQ = providerQ.LeftJoin(snapshotSQ, sqlchemy.Equals(providerQ.Field("id"), snapshotSQ.Field("manager_id")))
- providerQ = providerQ.LeftJoin(lbSQ, sqlchemy.Equals(providerQ.Field("id"), lbSQ.Field("manager_id")))
- providerQ = providerQ.LeftJoin(rdsSQ, sqlchemy.Equals(providerQ.Field("id"), rdsSQ.Field("manager_id")))
- providerQ = providerQ.LeftJoin(redisSQ, sqlchemy.Equals(providerQ.Field("id"), redisSQ.Field("manager_id")))
- providerQ = providerQ.LeftJoin(projectSQ, sqlchemy.Equals(providerQ.Field("id"), projectSQ.Field("manager_id")))
- providerQ = providerQ.LeftJoin(sregionSQ, sqlchemy.Equals(providerQ.Field("id"), sregionSQ.Field("cloudprovider_id")))
- providerQ = providerQ.Filter(sqlchemy.In(providerQ.Field("id"), providerIds)).GroupBy(providerQ.Field("id"))
- counts := []SCloudproviderUsageCount{}
- err := providerQ.All(&counts)
- if err != nil {
- return nil, errors.Wrapf(err, "providerQ.All")
- }
- for i := range counts {
- ret[counts[i].Id] = counts[i].SCloudproviderUsage
- }
- return ret, nil
- }
- func (cprvd *SCloudprovider) getProject(ctx context.Context) *db.STenant {
- proj, _ := db.TenantCacheManager.FetchTenantById(ctx, cprvd.ProjectId)
- return proj
- }
- func (manager *SCloudproviderManager) FetchCustomizeColumns(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- objs []interface{},
- fields stringutils2.SSortedStrings,
- isList bool,
- ) []api.CloudproviderDetails {
- rows := make([]api.CloudproviderDetails, len(objs))
- stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
- projRows := manager.SProjectizedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
- pmRows := manager.SProjectMappingResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
- accountIds := make([]string, len(objs))
- providerIds := make([]string, len(objs))
- for i := range rows {
- provider := objs[i].(*SCloudprovider)
- accountIds[i] = provider.CloudaccountId
- providerIds[i] = provider.Id
- rows[i] = api.CloudproviderDetails{
- EnabledStatusStandaloneResourceDetails: stdRows[i],
- ProjectizedResourceInfo: projRows[i],
- ProjectMappingResourceInfo: pmRows[i],
- LastSyncCost: provider.GetLastSyncCost(),
- }
- }
- q := CloudproviderRegionManager.Query()
- q = q.In("cloudprovider_id", providerIds)
- q = q.NotEquals("sync_status", api.CLOUD_PROVIDER_SYNC_STATUS_IDLE)
- cprs := []SCloudproviderregion{}
- err := q.All(&cprs)
- if err != nil {
- return rows
- }
- cprsMap := map[string]int{}
- for i := range cprs {
- _, ok := cprsMap[cprs[i].CloudproviderId]
- if !ok {
- cprsMap[cprs[i].CloudproviderId] = 0
- }
- cprsMap[cprs[i].CloudproviderId] += 1
- }
- accounts := make(map[string]SCloudaccount)
- err = db.FetchStandaloneObjectsByIds(CloudaccountManager, accountIds, &accounts)
- if err != nil {
- log.Errorf("FetchStandaloneObjectsByIds (%s) fail %s",
- CloudaccountManager.KeywordPlural(), err)
- return rows
- }
- proxySettingIds := make([]string, len(accounts))
- for i := range accounts {
- proxySettingId := accounts[i].ProxySettingId
- if !utils.IsInStringArray(proxySettingId, proxySettingIds) {
- proxySettingIds = append(proxySettingIds, proxySettingId)
- }
- }
- proxySettings := make(map[string]proxy.SProxySetting)
- err = db.FetchStandaloneObjectsByIds(proxy.ProxySettingManager, proxySettingIds, &proxySettings)
- if err != nil {
- log.Errorf("FetchStandaloneObjectsByIds (%s) fail %s",
- proxy.ProxySettingManager.KeywordPlural(), err)
- return rows
- }
- usages, err := manager.TotalResourceCount(providerIds)
- if err != nil {
- return rows
- }
- capabilities, err := CloudproviderCapabilityManager.getProvidersCapabilities(providerIds)
- if err != nil {
- return rows
- }
- for i := range rows {
- if account, ok := accounts[accountIds[i]]; ok {
- rows[i].Cloudaccount = account.Name
- rows[i].ReadOnly = account.ReadOnly
- rows[i].Brand = account.Brand
- ps := &rows[i].ProxySetting
- if proxySetting, ok := proxySettings[account.ProxySettingId]; ok {
- ps.Id = proxySetting.Id
- ps.Name = proxySetting.Name
- ps.HTTPProxy = proxySetting.HTTPProxy
- ps.HTTPSProxy = proxySetting.HTTPSProxy
- ps.NoProxy = proxySetting.NoProxy
- }
- }
- rows[i].SyncStatus2 = api.CLOUD_PROVIDER_SYNC_STATUS_IDLE
- if _, ok := cprsMap[providerIds[i]]; ok {
- rows[i].SyncStatus2 = api.CLOUD_PROVIDER_SYNC_STATUS_SYNCING
- }
- if usage, ok := usages[providerIds[i]]; ok {
- rows[i].SCloudproviderUsage = usage
- }
- if capas, ok := capabilities[providerIds[i]]; ok {
- rows[i].Capabilities = capas
- }
- }
- return rows
- }
- func (manager *SCloudproviderManager) initializeDefaultTenantId() error {
- // init accountid
- q := manager.Query().IsNullOrEmpty("tenant_id")
- providers := make([]SCloudprovider, 0)
- err := db.FetchModelObjects(manager, q, &providers)
- if err != nil {
- return errors.Wrap(err, "fetch empty defaullt tenant_id fail")
- }
- for i := range providers {
- provider := providers[i]
- domainId := provider.DomainId
- if len(domainId) == 0 {
- account, err := provider.GetCloudaccount()
- if err != nil {
- log.Errorf("GetCloudaccount fail %s", err)
- continue
- }
- domainId = account.DomainId
- }
- // auto fix accounts without default project
- defaultTenant, err := db.TenantCacheManager.FindFirstProjectOfDomain(context.Background(), domainId)
- if err != nil {
- return errors.Wrapf(err, "FindFirstProjectOfDomain(%s)", provider.DomainId)
- }
- _, err = db.Update(&provider, func() error {
- provider.ProjectId = defaultTenant.Id
- provider.DomainId = defaultTenant.DomainId
- return nil
- })
- if err != nil {
- return errors.Wrap(err, "db.Update for account")
- }
- }
- return nil
- }
- func (manager *SCloudproviderManager) InitializeData() error {
- err := manager.initializeDefaultTenantId()
- if err != nil {
- log.Errorf("initializeDefaultTenantId %s", err)
- }
- return nil
- }
- // 云订阅列表
- func (manager *SCloudproviderManager) ListItemFilter(
- ctx context.Context,
- q *sqlchemy.SQuery,
- userCred mcclient.TokenCredential,
- query api.CloudproviderListInput,
- ) (*sqlchemy.SQuery, error) {
- accountArr := query.CloudaccountId
- if len(accountArr) > 0 {
- cpq := CloudaccountManager.Query().SubQuery()
- subcpq := cpq.Query(cpq.Field("id")).Filter(sqlchemy.OR(
- sqlchemy.In(cpq.Field("id"), stringutils2.RemoveUtf8Strings(accountArr)),
- sqlchemy.In(cpq.Field("name"), accountArr),
- )).SubQuery()
- q = q.In("cloudaccount_id", subcpq)
- }
- var zone *SZone
- var region *SCloudregion
- if len(query.ZoneId) > 0 {
- zoneObj, err := validators.ValidateModel(ctx, userCred, ZoneManager, &query.ZoneId)
- if err != nil {
- return nil, err
- }
- zone = zoneObj.(*SZone)
- region, err = zone.GetRegion()
- if err != nil {
- return nil, err
- }
- vpcs := VpcManager.Query("manager_id").Equals("cloudregion_id", region.Id).Distinct()
- if !utils.IsInStringArray(region.Provider, api.REGIONAL_NETWORK_PROVIDERS) {
- wires := WireManager.Query().Equals("zone_id", query.ZoneId).SubQuery()
- vpcs = vpcs.Join(wires, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id")))
- }
- wireManager := WireManager.Query("manager_id").Equals("zone_id", query.ZoneId).Distinct().SubQuery()
- q = q.Filter(
- sqlchemy.OR(
- sqlchemy.In(q.Field("id"), vpcs.SubQuery()),
- sqlchemy.In(q.Field("id"), wireManager), //vmware
- ),
- )
- } else if len(query.CloudregionId) > 0 {
- regionObj, err := CloudregionManager.FetchByIdOrName(ctx, userCred, query.CloudregionId)
- if err != nil {
- if err == sql.ErrNoRows {
- return nil, httperrors.NewResourceNotFoundError2("cloudregion", query.CloudregionId)
- }
- return nil, httperrors.NewGeneralError(err)
- }
- region = regionObj.(*SCloudregion)
- pr := CloudproviderRegionManager.Query().SubQuery()
- sq := pr.Query(pr.Field("cloudprovider_id")).Equals("cloudregion_id", region.Id).Distinct()
- q = q.In("id", sq)
- }
- if query.Usable != nil && *query.Usable {
- providers := usableCloudProviders().SubQuery()
- networks := NetworkManager.Query().SubQuery()
- wires := WireManager.Query().SubQuery()
- vpcs := VpcManager.Query().SubQuery()
- providerRegions := CloudproviderRegionManager.Query().SubQuery()
- sq := providers.Query(sqlchemy.DISTINCT("id", providers.Field("id")))
- sq = sq.Join(providerRegions, sqlchemy.Equals(providers.Field("id"), providerRegions.Field("cloudprovider_id")))
- sq = sq.Join(vpcs, sqlchemy.Equals(providerRegions.Field("cloudregion_id"), vpcs.Field("cloudregion_id")))
- sq = sq.Join(wires, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id")))
- sq = sq.Join(networks, sqlchemy.Equals(wires.Field("id"), networks.Field("wire_id")))
- sq = sq.Filter(sqlchemy.Equals(vpcs.Field("status"), api.VPC_STATUS_AVAILABLE))
- sq = sq.Filter(sqlchemy.Equals(networks.Field("status"), api.NETWORK_STATUS_AVAILABLE))
- sq = sq.Filter(sqlchemy.OR(
- sqlchemy.IsNullOrEmpty(vpcs.Field("manager_id")),
- sqlchemy.Equals(vpcs.Field("manager_id"), providers.Field("id")),
- ))
- if zone != nil {
- zoneFilter := sqlchemy.OR(sqlchemy.Equals(wires.Field("zone_id"), zone.GetId()), sqlchemy.IsNullOrEmpty(wires.Field("zone_id")))
- sq = sq.Filter(zoneFilter)
- } else if region != nil {
- sq = sq.Filter(sqlchemy.Equals(vpcs.Field("cloudregion_id"), region.GetId()))
- }
- q = q.Filter(sqlchemy.In(q.Field("id"), sq.SubQuery()))
- }
- q, err := manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemFilter")
- }
- q, err = manager.SProjectizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ProjectizedResourceListInput)
- if err != nil {
- return nil, errors.Wrapf(err, "SProjectizedResourceBaseManager.ListItemFilter")
- }
- q, err = manager.SSyncableBaseResourceManager.ListItemFilter(ctx, q, userCred, query.SyncableBaseResourceListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SSyncableBaseResourceManager.ListItemFilter")
- }
- q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
- }
- managerStrs := query.CloudproviderId
- conditions := []sqlchemy.ICondition{}
- for _, managerStr := range managerStrs {
- if len(managerStr) == 0 {
- continue
- }
- providerObj, err := manager.FetchByIdOrName(ctx, userCred, managerStr)
- if err != nil {
- if err == sql.ErrNoRows {
- return nil, httperrors.NewResourceNotFoundError2(CloudproviderManager.Keyword(), managerStr)
- } else {
- return nil, httperrors.NewGeneralError(err)
- }
- }
- conditions = append(conditions, sqlchemy.Equals(q.Field("id"), providerObj.GetId()))
- }
- if len(conditions) > 0 {
- q = q.Filter(sqlchemy.OR(conditions...))
- }
- cloudEnvStr := query.CloudEnv
- if cloudEnvStr == api.CLOUD_ENV_PUBLIC_CLOUD {
- cloudaccounts := CloudaccountManager.Query().SubQuery()
- q = q.Join(cloudaccounts, sqlchemy.Equals(cloudaccounts.Field("id"), q.Field("cloudaccount_id")))
- q = q.Filter(sqlchemy.IsTrue(cloudaccounts.Field("is_public_cloud")))
- q = q.Filter(sqlchemy.IsFalse(cloudaccounts.Field("is_on_premise")))
- }
- if cloudEnvStr == api.CLOUD_ENV_PRIVATE_CLOUD {
- cloudaccounts := CloudaccountManager.Query().SubQuery()
- q = q.Join(cloudaccounts, sqlchemy.Equals(cloudaccounts.Field("id"), q.Field("cloudaccount_id")))
- q = q.Filter(sqlchemy.IsFalse(cloudaccounts.Field("is_public_cloud")))
- q = q.Filter(sqlchemy.IsFalse(cloudaccounts.Field("is_on_premise")))
- }
- if cloudEnvStr == api.CLOUD_ENV_ON_PREMISE {
- cloudaccounts := CloudaccountManager.Query().SubQuery()
- q = q.Join(cloudaccounts, sqlchemy.Equals(cloudaccounts.Field("id"), q.Field("cloudaccount_id")))
- q = q.Filter(sqlchemy.IsFalse(cloudaccounts.Field("is_public_cloud")))
- q = q.Filter(sqlchemy.IsTrue(cloudaccounts.Field("is_on_premise")))
- }
- capabilities := query.Capability
- if len(capabilities) > 0 {
- subq := CloudproviderCapabilityManager.Query("cloudprovider_id").In("capability", capabilities).Distinct().SubQuery()
- q = q.In("id", subq)
- }
- if len(query.HealthStatus) > 0 {
- q = q.In("health_status", query.HealthStatus)
- }
- if len(query.Providers) > 0 {
- subq := CloudaccountManager.Query("id").In("provider", query.Providers).SubQuery()
- q = q.In("cloudaccount_id", subq)
- }
- if len(query.Brands) > 0 {
- subq := CloudaccountManager.Query("id").In("brand", query.Brands).SubQuery()
- q = q.In("cloudaccount_id", subq)
- }
- if len(query.HostSchedtagId) > 0 {
- schedTagObj, err := SchedtagManager.FetchByIdOrName(ctx, userCred, query.HostSchedtagId)
- if err != nil {
- if errors.Cause(err) == sql.ErrNoRows {
- return nil, errors.Wrapf(httperrors.ErrResourceNotFound, "%s %s", SchedtagManager.Keyword(), query.HostSchedtagId)
- } else {
- return nil, errors.Wrap(err, "SchedtagManager.FetchByIdOrName")
- }
- }
- subq := HostManager.Query("manager_id")
- hostschedtags := HostschedtagManager.Query().Equals("schedtag_id", schedTagObj.GetId()).SubQuery()
- subq = subq.Join(hostschedtags, sqlchemy.Equals(hostschedtags.Field("host_id"), subq.Field("id")))
- log.Debugf("%s", subq.String())
- q = q.In("id", subq.SubQuery())
- }
- if query.ReadOnly != nil {
- sq := CloudaccountManager.Query("id").Equals("read_only", *query.ReadOnly).SubQuery()
- q = q.In("cloudaccount_id", sq)
- }
- return q, nil
- }
- func (manager *SCloudproviderManager) OrderByExtraFields(
- ctx context.Context,
- q *sqlchemy.SQuery,
- userCred mcclient.TokenCredential,
- query api.CloudproviderListInput,
- ) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields")
- }
- return q, nil
- }
- func (manager *SCloudproviderManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
- var err error
- if field == "manager" {
- q = q.AppendField(q.Field("name").Label("manager")).Distinct()
- return q, nil
- }
- if field == "account" {
- accounts := CloudaccountManager.Query("name", "id").SubQuery()
- q.AppendField(accounts.Field("name", field)).Distinct()
- q = q.Join(accounts, sqlchemy.Equals(q.Field("cloudaccount_id"), accounts.Field("id")))
- return q, nil
- }
- q, err = manager.SProjectizedResourceBaseManager.QueryDistinctExtraField(q, field)
- if err == nil {
- return q, nil
- }
- q, err = manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
- if err == nil {
- return q, nil
- }
- return q, httperrors.ErrNotFound
- }
- func (provider *SCloudprovider) markProviderDisconnected(ctx context.Context, userCred mcclient.TokenCredential, reason string) error {
- _, err := db.UpdateWithLock(ctx, provider, func() error {
- provider.HealthStatus = api.CLOUD_PROVIDER_HEALTH_UNKNOWN
- return nil
- })
- if err != nil {
- return err
- }
- if provider.Status != api.CLOUD_PROVIDER_DISCONNECTED {
- provider.SetStatus(ctx, userCred, api.CLOUD_PROVIDER_DISCONNECTED, reason)
- return provider.ClearSchedDescCache()
- }
- return nil
- }
- func (cprvd *SCloudprovider) updateName(ctx context.Context, userCred mcclient.TokenCredential, name, desc string) error {
- if cprvd.Name != name || cprvd.Description != desc {
- diff, err := db.Update(cprvd, func() error {
- cprvd.Name = name
- if len(cprvd.Description) == 0 {
- cprvd.Description = desc
- }
- return nil
- })
- if err != nil {
- return errors.Wrapf(err, "db.Update")
- }
- db.OpsLog.LogEvent(cprvd, db.ACT_UPDATE, diff, userCred)
- }
- return nil
- }
- func (provider *SCloudprovider) markProviderConnected(ctx context.Context, userCred mcclient.TokenCredential, healthStatus string) error {
- if healthStatus != provider.HealthStatus {
- diff, err := db.Update(provider, func() error {
- provider.HealthStatus = healthStatus
- return nil
- })
- if err != nil {
- return err
- }
- db.OpsLog.LogEvent(provider, db.ACT_UPDATE, diff, userCred)
- }
- if provider.Status != api.CLOUD_PROVIDER_CONNECTED {
- provider.SetStatus(ctx, userCred, api.CLOUD_PROVIDER_CONNECTED, "")
- return provider.ClearSchedDescCache()
- }
- return nil
- }
- func (provider *SCloudprovider) prepareCloudproviderRegions(ctx context.Context, userCred mcclient.TokenCredential) ([]SCloudproviderregion, error) {
- driver, err := provider.GetProvider(ctx)
- if err != nil {
- return nil, errors.Wrap(err, "provider.GetProvider")
- }
- err = CloudproviderCapabilityManager.setCapabilities(ctx, userCred, provider.Id, driver.GetCapabilities())
- if err != nil {
- return nil, errors.Wrap(err, "CloudproviderCapabilityManager.setCapabilities")
- }
- if driver.GetFactory().IsOnPremise() {
- cpr, err := CloudproviderRegionManager.FetchByIdsOrCreate(provider.Id, api.DEFAULT_REGION_ID)
- if err != nil {
- return nil, errors.Wrapf(err, "FetchByIdsOrCreate")
- }
- cpr.setCapabilities(ctx, userCred, driver.GetCapabilities())
- return []SCloudproviderregion{*cpr}, nil
- }
- iregions, err := driver.GetIRegions()
- if err != nil {
- return nil, errors.Wrapf(err, "GetIRegions")
- }
- externalIdPrefix := driver.GetCloudRegionExternalIdPrefix()
- _, _, cprs, result := CloudregionManager.SyncRegions(ctx, userCred, provider, externalIdPrefix, iregions)
- if result.IsError() {
- log.Errorf("syncRegion fail %s", result.Result())
- }
- return cprs, nil
- }
- func (provider *SCloudprovider) GetCloudproviderRegions() []SCloudproviderregion {
- q := CloudproviderRegionManager.Query()
- q = q.Equals("cloudprovider_id", provider.Id)
- // q = q.IsTrue("enabled")
- // q = q.Equals("sync_status", api.CLOUD_PROVIDER_SYNC_STATUS_IDLE)
- return CloudproviderRegionManager.fetchRecordsByQuery(q)
- }
- func (provider *SCloudprovider) GetRegions() ([]SCloudregion, error) {
- q := CloudregionManager.Query()
- crcp := CloudproviderRegionManager.Query().SubQuery()
- q = q.Join(crcp, sqlchemy.Equals(q.Field("id"), crcp.Field("cloudregion_id"))).Filter(sqlchemy.Equals(crcp.Field("cloudprovider_id"), provider.Id))
- ret := []SCloudregion{}
- return ret, db.FetchModelObjects(CloudregionManager, q, &ret)
- }
- func (provider *SCloudprovider) GetUsableRegions() ([]SCloudregion, error) {
- q := CloudregionManager.Query()
- crcp := CloudproviderRegionManager.Query().SubQuery()
- q = q.Join(crcp, sqlchemy.Equals(q.Field("id"), crcp.Field("cloudregion_id"))).Filter(
- sqlchemy.AND(
- sqlchemy.Equals(crcp.Field("cloudprovider_id"), provider.Id),
- sqlchemy.IsTrue(crcp.Field("enabled")),
- ),
- )
- ret := []SCloudregion{}
- err := db.FetchModelObjects(CloudregionManager, q, &ret)
- if err != nil {
- return nil, err
- }
- return ret, nil
- }
- func (provider *SCloudprovider) resetAutoSync() {
- cprs := provider.GetCloudproviderRegions()
- for i := range cprs {
- cprs[i].resetAutoSync()
- }
- }
- func (provider *SCloudprovider) syncCloudproviderRegions(ctx context.Context, userCred mcclient.TokenCredential, syncRange SSyncRange, wg *sync.WaitGroup) {
- provider.markSyncing(userCred)
- cprs := provider.GetCloudproviderRegions()
- regionIds, _ := syncRange.GetRegionIds()
- syncCnt := 0
- for i := range cprs {
- if cprs[i].Enabled && cprs[i].CanSync() && (len(regionIds) == 0 || utils.IsInStringArray(cprs[i].CloudregionId, regionIds)) {
- syncCnt += 1
- if wg != nil {
- wg.Add(1)
- }
- cprs[i].submitSyncTask(ctx, userCred, syncRange)
- if wg != nil {
- wg.Done()
- }
- }
- }
- if syncCnt == 0 {
- err := provider.markEndSyncWithLock(ctx, userCred, false)
- if err != nil {
- log.Errorf("markEndSyncWithLock for %s error: %v", provider.Name, err)
- }
- }
- }
- func (provider *SCloudprovider) SyncCallSyncCloudproviderRegions(ctx context.Context, userCred mcclient.TokenCredential, syncRange SSyncRange) {
- var wg sync.WaitGroup
- provider.syncCloudproviderRegions(ctx, userCred, syncRange, &wg)
- wg.Wait()
- }
- func (cprvd *SCloudprovider) IsAvailable() bool {
- if !cprvd.GetEnabled() {
- return false
- }
- if !utils.IsInStringArray(cprvd.Status, api.CLOUD_PROVIDER_VALID_STATUS) {
- return false
- }
- if !utils.IsInStringArray(cprvd.HealthStatus, api.CLOUD_PROVIDER_VALID_HEALTH_STATUS) {
- return false
- }
- return true
- }
- func (cprvd *SCloudprovider) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
- // override
- log.Infof("cloud provider delete do nothing")
- return nil
- }
- func (cprvd *SCloudprovider) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
- regions, err := cprvd.GetRegions()
- if err != nil {
- return errors.Wrapf(err, "GetRegions")
- }
- for i := range regions {
- err = regions[i].purgeAll(ctx, cprvd.Id)
- if err != nil {
- return err
- }
- }
- return cprvd.purge(ctx, userCred)
- }
- func (cprvd *SCloudprovider) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
- return cprvd.StartCloudproviderDeleteTask(ctx, userCred, "")
- }
- func (cprvd *SCloudprovider) StartCloudproviderDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
- params := jsonutils.NewDict()
- task, err := taskman.TaskManager.NewTask(ctx, "CloudProviderDeleteTask", cprvd, userCred, params, parentTaskId, "", nil)
- if err != nil {
- return errors.Wrapf(err, "NewTask")
- }
- cprvd.SetStatus(ctx, userCred, api.CLOUD_PROVIDER_START_DELETE, "StartCloudproviderDeleteTask")
- return task.ScheduleRun(nil)
- }
- func (cprvd *SCloudprovider) GetRegionDriver() (IRegionDriver, error) {
- driver := GetRegionDriver(cprvd.Provider)
- if driver == nil {
- return nil, fmt.Errorf("failed to found region driver for %s", cprvd.Provider)
- }
- return driver, nil
- }
- func (cprvd *SCloudprovider) ClearSchedDescCache() error {
- hosts := make([]SHost, 0)
- q := HostManager.Query().Equals("manager_id", cprvd.Id)
- err := db.FetchModelObjects(HostManager, q, &hosts)
- if err != nil {
- return err
- }
- for i := range hosts {
- err := hosts[i].ClearSchedDescCache()
- if err != nil {
- log.Errorf("host CleanHostSchedCache error: %v", err)
- return err
- }
- }
- return nil
- }
- func (cprvd *SCloudprovider) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) (jsonutils.JSONObject, error) {
- if strings.Index(cprvd.Status, "delet") >= 0 {
- return nil, httperrors.NewInvalidStatusError("Cannot enable deleting account")
- }
- _, err := cprvd.SEnabledStatusStandaloneResourceBase.PerformEnable(ctx, userCred, query, input)
- if err != nil {
- return nil, err
- }
- account, err := cprvd.GetCloudaccount()
- if err != nil {
- return nil, err
- }
- if !account.GetEnabled() {
- return account.enableAccountOnly(ctx, userCred, nil, input)
- }
- return nil, nil
- }
- func (cprvd *SCloudprovider) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) (jsonutils.JSONObject, error) {
- _, err := cprvd.SEnabledStatusStandaloneResourceBase.PerformDisable(ctx, userCred, query, input)
- if err != nil {
- return nil, err
- }
- account, err := cprvd.GetCloudaccount()
- if err != nil {
- return nil, err
- }
- allDisable := true
- providers := account.GetCloudproviders()
- for i := range providers {
- if providers[i].GetEnabled() {
- allDisable = false
- break
- }
- }
- if allDisable && account.GetEnabled() {
- return account.PerformDisable(ctx, userCred, nil, input)
- }
- return nil, nil
- }
- func (manager *SCloudproviderManager) filterByDomainId(q *sqlchemy.SQuery, domainId string) *sqlchemy.SQuery {
- subq := db.SharedResourceManager.Query("resource_id")
- subq = subq.Equals("resource_type", CloudaccountManager.Keyword())
- subq = subq.Equals("target_project_id", domainId)
- subq = subq.Equals("target_type", db.SharedTargetDomain)
- cloudaccounts := CloudaccountManager.Query().SubQuery()
- q = q.Join(cloudaccounts, sqlchemy.Equals(
- q.Field("cloudaccount_id"),
- cloudaccounts.Field("id"),
- ))
- q = q.Filter(sqlchemy.OR(
- sqlchemy.AND(
- sqlchemy.Equals(q.Field("domain_id"), domainId),
- sqlchemy.Equals(cloudaccounts.Field("share_mode"), api.CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN),
- ),
- sqlchemy.AND(
- sqlchemy.Equals(cloudaccounts.Field("share_mode"), api.CLOUD_ACCOUNT_SHARE_MODE_SYSTEM),
- sqlchemy.OR(
- sqlchemy.AND(
- sqlchemy.Equals(cloudaccounts.Field("public_scope"), rbacscope.ScopeNone),
- sqlchemy.Equals(cloudaccounts.Field("domain_id"), domainId),
- ),
- sqlchemy.AND(
- sqlchemy.Equals(cloudaccounts.Field("public_scope"), rbacscope.ScopeDomain),
- sqlchemy.OR(
- sqlchemy.Equals(cloudaccounts.Field("domain_id"), domainId),
- sqlchemy.In(cloudaccounts.Field("id"), subq.SubQuery()),
- ),
- ),
- sqlchemy.Equals(cloudaccounts.Field("public_scope"), rbacscope.ScopeSystem),
- ),
- ),
- sqlchemy.AND(
- sqlchemy.Equals(cloudaccounts.Field("domain_id"), domainId),
- sqlchemy.Equals(cloudaccounts.Field("share_mode"), api.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN),
- ),
- ))
- return q
- }
- func (manager *SCloudproviderManager) FilterByOwner(ctx context.Context, q *sqlchemy.SQuery, man db.FilterByOwnerProvider, userCred mcclient.TokenCredential, owner mcclient.IIdentityProvider, scope rbacscope.TRbacScope) *sqlchemy.SQuery {
- if owner != nil {
- switch scope {
- case rbacscope.ScopeProject, rbacscope.ScopeDomain:
- if len(owner.GetProjectDomainId()) > 0 {
- q = manager.filterByDomainId(q, owner.GetProjectDomainId())
- }
- }
- }
- return q
- }
- func (cprvd *SCloudprovider) GetSyncStatus2() string {
- q := CloudproviderRegionManager.Query()
- q = q.Equals("cloudprovider_id", cprvd.Id)
- q = q.NotEquals("sync_status", api.CLOUD_PROVIDER_SYNC_STATUS_IDLE)
- cnt, err := q.CountWithError()
- if err != nil {
- return api.CLOUD_PROVIDER_SYNC_STATUS_ERROR
- }
- if cnt > 0 {
- return api.CLOUD_PROVIDER_SYNC_STATUS_SYNCING
- } else {
- return api.CLOUD_PROVIDER_SYNC_STATUS_IDLE
- }
- }
- func (manager *SCloudproviderManager) fetchRecordsByQuery(q *sqlchemy.SQuery) []SCloudprovider {
- recs := make([]SCloudprovider, 0)
- err := db.FetchModelObjects(manager, q, &recs)
- if err != nil {
- return nil
- }
- return recs
- }
- func (manager *SCloudproviderManager) initAllRecords() {
- recs := manager.fetchRecordsByQuery(manager.Query())
- for i := range recs {
- db.Update(&recs[i], func() error {
- recs[i].SyncStatus = api.CLOUD_PROVIDER_SYNC_STATUS_IDLE
- return nil
- })
- }
- }
- func (provider *SCloudprovider) GetDetailsClirc(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- accessUrl := provider.getAccessUrl()
- passwd, err := provider.getPassword()
- if err != nil {
- return nil, err
- }
- account, err := provider.GetCloudaccount()
- if err != nil {
- return nil, err
- }
- info := cloudprovider.SProviderInfo{
- Name: provider.Name,
- Url: accessUrl,
- Account: provider.Account,
- Secret: passwd,
- Options: account.Options,
- }
- regions, err := provider.GetRegions()
- if err != nil {
- return nil, errors.Wrapf(err, "GetRegions")
- }
- if len(regions) > 0 {
- info.Region = fetchExternalId(regions[0].ExternalId)
- }
- rc, err := cloudprovider.GetClientRC(provider.Provider, info)
- if err != nil {
- return nil, err
- }
- return jsonutils.Marshal(rc), nil
- }
- func (manager *SCloudproviderManager) ResourceScope() rbacscope.TRbacScope {
- return rbacscope.ScopeDomain
- }
- func (provider *SCloudprovider) GetDetailsStorageClasses(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- input api.CloudproviderGetStorageClassInput,
- ) (api.CloudproviderGetStorageClassOutput, error) {
- output := api.CloudproviderGetStorageClassOutput{}
- driver, err := provider.GetProvider(ctx)
- if err != nil {
- return output, httperrors.NewInternalServerError("fail to get provider driver %s", err)
- }
- if len(input.CloudregionId) > 0 {
- _, input.CloudregionResourceInput, err = ValidateCloudregionResourceInput(ctx, userCred, input.CloudregionResourceInput)
- if err != nil {
- return output, errors.Wrap(err, "ValidateCloudregionResourceInput")
- }
- }
- sc := driver.GetStorageClasses(input.CloudregionId)
- if sc == nil {
- return output, httperrors.NewInternalServerError("storage classes not supported")
- }
- output.StorageClasses = sc
- return output, nil
- }
- func (provider *SCloudprovider) GetDetailsCannedAcls(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- input api.CloudproviderGetCannedAclInput,
- ) (api.CloudproviderGetCannedAclOutput, error) {
- output := api.CloudproviderGetCannedAclOutput{}
- driver, err := provider.GetProvider(ctx)
- if err != nil {
- return output, httperrors.NewInternalServerError("fail to get provider driver %s", err)
- }
- if len(input.CloudregionId) > 0 {
- _, input.CloudregionResourceInput, err = ValidateCloudregionResourceInput(ctx, userCred, input.CloudregionResourceInput)
- if err != nil {
- return output, errors.Wrap(err, "ValidateCloudregionResourceInput")
- }
- }
- output.BucketCannedAcls = driver.GetBucketCannedAcls(input.CloudregionId)
- output.ObjectCannedAcls = driver.GetObjectCannedAcls(input.CloudregionId)
- return output, nil
- }
- func (provider *SCloudprovider) getAccountShareInfo() apis.SAccountShareInfo {
- account, _ := provider.GetCloudaccount()
- if account != nil {
- return account.getAccountShareInfo()
- }
- return apis.SAccountShareInfo{}
- }
- func (provider *SCloudprovider) IsSharable(reqUsrId mcclient.IIdentityProvider) bool {
- account, _ := provider.GetCloudaccount()
- if account != nil {
- if account.ShareMode == api.CLOUD_ACCOUNT_SHARE_MODE_SYSTEM {
- return account.IsSharable(reqUsrId)
- }
- }
- return false
- }
- func (provider *SCloudprovider) GetDetailsChangeOwnerCandidateDomains(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (apis.ChangeOwnerCandidateDomainsOutput, error) {
- return db.IOwnerResourceBaseModelGetChangeOwnerCandidateDomains(provider)
- }
- func (provider *SCloudprovider) GetChangeOwnerCandidateDomainIds() []string {
- account, _ := provider.GetCloudaccount()
- if account == nil {
- return []string{}
- }
- if account.ShareMode == api.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN {
- return []string{account.DomainId}
- }
- // if account's public_scope=domain and share_mode=provider_domain, only allow to share to specific domains
- if account.PublicScope == string(rbacscope.ScopeDomain) {
- sharedDomains := account.GetSharedDomains()
- return append(sharedDomains, account.DomainId)
- }
- return []string{}
- }
- func (cprvd *SCloudprovider) GetExternalProjectsByProjectIdOrName(projectId, name string) ([]SExternalProject, error) {
- projects := []SExternalProject{}
- q := ExternalProjectManager.Query().Equals("manager_id", cprvd.Id)
- q = q.Filter(
- sqlchemy.OR(
- sqlchemy.Equals(q.Field("name"), name),
- sqlchemy.Equals(q.Field("tenant_id"), projectId),
- ),
- ).Desc("priority")
- err := db.FetchModelObjects(ExternalProjectManager, q, &projects)
- if err != nil {
- return nil, errors.Wrap(err, "db.FetchModelObjects")
- }
- return projects, nil
- }
- // 若本地项目映射了多个云上项目,则在根据优先级找优先级最大的云上项目
- // 若本地项目没有映射云上任何项目,则在云上新建一个同名项目
- // 若本地项目a映射云上项目b,但b项目不可用,则看云上是否有a项目,有则直接使用,若没有则在云上创建a-1, a-2类似项目
- func (cprvd *SCloudprovider) SyncProject(ctx context.Context, userCred mcclient.TokenCredential, id string) (string, error) {
- lockman.LockRawObject(ctx, ExternalProjectManager.Keyword(), cprvd.Id)
- defer lockman.ReleaseRawObject(ctx, ExternalProjectManager.Keyword(), cprvd.Id)
- provider, err := cprvd.GetProvider(ctx)
- if err != nil {
- return "", errors.Wrap(err, "GetProvider")
- }
- project, err := db.TenantCacheManager.FetchTenantById(ctx, id)
- if err != nil {
- return "", errors.Wrapf(err, "FetchTenantById(%s)", id)
- }
- projects, err := cprvd.GetExternalProjectsByProjectIdOrName(id, project.Name)
- if err != nil {
- return "", errors.Wrapf(err, "GetExternalProjectsByProjectIdOrName(%s,%s)", id, project.Name)
- }
- extProj := GetAvailableExternalProject(project, projects)
- if extProj != nil {
- idx := strings.Index(extProj.ExternalId, "/")
- if idx > -1 {
- return extProj.ExternalId[idx+1:], nil
- }
- return extProj.ExternalId, nil
- }
- retry := 1
- if len(projects) > 0 {
- retry = 10
- }
- var iProject cloudprovider.ICloudProject = nil
- projectName := project.Name
- for i := 0; i < retry; i++ {
- iProject, err = provider.CreateIProject(projectName)
- if err == nil {
- break
- }
- projectName = fmt.Sprintf("%s-%d", project.Name, i)
- }
- if err != nil {
- if errors.Cause(err) != cloudprovider.ErrNotImplemented && errors.Cause(err) != cloudprovider.ErrNotSupported {
- logclient.AddSimpleActionLog(cprvd, logclient.ACT_CREATE, err, userCred, false)
- }
- return "", errors.Wrapf(err, "CreateIProject(%s)", projectName)
- }
- extProj, err = cprvd.newFromCloudProject(ctx, userCred, project, iProject)
- if err != nil {
- return "", errors.Wrap(err, "newFromCloudProject")
- }
- db.Update(extProj, func() error {
- extProj.ManagerId = cprvd.Id
- return nil
- })
- idx := strings.Index(extProj.ExternalId, "/")
- if idx > -1 {
- return extProj.ExternalId[idx+1:], nil
- }
- return extProj.ExternalId, nil
- }
- func (cprvd *SCloudprovider) GetSchedtags() []SSchedtag {
- return GetSchedtags(CloudproviderschedtagManager, cprvd.Id)
- }
- func (cprvd *SCloudprovider) GetDynamicConditionInput() *jsonutils.JSONDict {
- return jsonutils.Marshal(cprvd).(*jsonutils.JSONDict)
- }
- func (cprvd *SCloudprovider) PerformSetSchedtag(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- return PerformSetResourceSchedtag(cprvd, ctx, userCred, query, data)
- }
- func (cprvd *SCloudprovider) GetSchedtagJointManager() ISchedtagJointManager {
- return CloudproviderschedtagManager
- }
- func (cprvd *SCloudprovider) GetInterVpcNetworks() ([]SInterVpcNetwork, error) {
- networks := []SInterVpcNetwork{}
- q := InterVpcNetworkManager.Query().Equals("manager_id", cprvd.Id)
- err := db.FetchModelObjects(InterVpcNetworkManager, q, &networks)
- if err != nil {
- return nil, errors.Wrapf(err, "db.FetchModelObjects")
- }
- return networks, nil
- }
- func (cprvd *SCloudprovider) SyncInterVpcNetwork(ctx context.Context, userCred mcclient.TokenCredential, interVpcNetworks []cloudprovider.ICloudInterVpcNetwork, xor bool) ([]SInterVpcNetwork, []cloudprovider.ICloudInterVpcNetwork, compare.SyncResult) {
- lockman.LockRawObject(ctx, cprvd.Keyword(), fmt.Sprintf("%s-interVpcNetwork", cprvd.Id))
- defer lockman.ReleaseRawObject(ctx, cprvd.Keyword(), fmt.Sprintf("%s-interVpcNetwork", cprvd.Id))
- result := compare.SyncResult{}
- localNetworks := []SInterVpcNetwork{}
- remoteNetworks := []cloudprovider.ICloudInterVpcNetwork{}
- dbNetworks, err := cprvd.GetInterVpcNetworks()
- if err != nil {
- result.Error(errors.Wrapf(err, "GetInterVpcNetworks"))
- return nil, nil, result
- }
- removed := make([]SInterVpcNetwork, 0)
- commondb := make([]SInterVpcNetwork, 0)
- commonext := make([]cloudprovider.ICloudInterVpcNetwork, 0)
- added := make([]cloudprovider.ICloudInterVpcNetwork, 0)
- err = compare.CompareSets(dbNetworks, interVpcNetworks, &removed, &commondb, &commonext, &added)
- if err != nil {
- result.Error(err)
- return nil, nil, result
- }
- for i := 0; i < len(removed); i += 1 {
- err = removed[i].syncRemove(ctx, userCred)
- if err != nil {
- result.DeleteError(err)
- continue
- }
- result.Delete()
- }
- for i := 0; i < len(commondb); i += 1 {
- if !xor {
- err = commondb[i].SyncWithCloudInterVpcNetwork(ctx, userCred, commonext[i])
- if err != nil {
- result.UpdateError(errors.Wrapf(err, "SyncWithCloudInterVpcNetwork"))
- continue
- }
- }
- localNetworks = append(localNetworks, commondb[i])
- remoteNetworks = append(remoteNetworks, commonext[i])
- result.Update()
- }
- for i := 0; i < len(added); i += 1 {
- network, err := InterVpcNetworkManager.newFromCloudInterVpcNetwork(ctx, userCred, added[i], cprvd)
- if err != nil {
- result.AddError(err)
- continue
- }
- localNetworks = append(localNetworks, *network)
- remoteNetworks = append(remoteNetworks, added[i])
- result.Add()
- }
- return localNetworks, remoteNetworks, result
- }
- func (manager *SCloudproviderManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, keys stringutils2.SSortedStrings) (*sqlchemy.SQuery, error) {
- q, err := manager.SEnabledStatusStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
- if err != nil {
- return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemExportKeys")
- }
- q, err = manager.SProjectizedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
- if err != nil {
- return nil, errors.Wrapf(err, "SProjectizedResourceBaseManager.ListItemExportKeys")
- }
- q, err = manager.SProjectMappingResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
- if err != nil {
- return nil, errors.Wrapf(err, "SProjectMappingResourceBaseManager.ListItemExportKeys")
- }
- return q, nil
- }
- // 绑定同步策略
- func (cprvd *SCloudprovider) PerformProjectMapping(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudaccountProjectMappingInput) (jsonutils.JSONObject, error) {
- if len(input.ProjectMappingId) > 0 {
- _, err := validators.ValidateModel(ctx, userCred, ProjectMappingManager, &input.ProjectMappingId)
- if err != nil {
- return nil, err
- }
- if len(cprvd.ProjectMappingId) > 0 && cprvd.ProjectMappingId != input.ProjectMappingId {
- return nil, httperrors.NewInputParameterError("cloudprovider %s has aleady bind project mapping %s", cprvd.Name, cprvd.ProjectMappingId)
- }
- }
- _, err := db.Update(cprvd, func() error {
- cprvd.ProjectMappingId = input.ProjectMappingId
- if input.EnableProjectSync != nil {
- cprvd.EnableProjectSync = tristate.NewFromBool(*input.EnableProjectSync)
- }
- if input.EnableResourceSync != nil {
- cprvd.EnableResourceSync = tristate.NewFromBool(*input.EnableResourceSync)
- }
- return nil
- })
- if err != nil {
- return nil, err
- }
- return nil, refreshPmCaches()
- }
- func (cprvd *SCloudprovider) PerformSetSyncing(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudproviderSync) (jsonutils.JSONObject, error) {
- regionIds := []string{}
- for i := range input.CloudregionIds {
- _, err := validators.ValidateModel(ctx, userCred, CloudregionManager, &input.CloudregionIds[i])
- if err != nil {
- return nil, err
- }
- regionIds = append(regionIds, input.CloudregionIds[i])
- }
- if len(regionIds) == 0 {
- return nil, nil
- }
- q := CloudproviderRegionManager.Query().Equals("cloudprovider_id", cprvd.Id).In("cloudregion_id", regionIds)
- cpcds := []SCloudproviderregion{}
- err := db.FetchModelObjects(CloudproviderRegionManager, q, &cpcds)
- if err != nil {
- return nil, err
- }
- for i := range cpcds {
- _, err := db.Update(&cpcds[i], func() error {
- cpcds[i].Enabled = input.Enabled
- return nil
- })
- if err != nil {
- return nil, errors.Wrapf(err, "db.Update")
- }
- }
- return nil, nil
- }
- func (cprvd *SCloudprovider) SyncError(result compare.SyncResult, iNotes interface{}, userCred mcclient.TokenCredential) {
- if result.IsGenerateError() {
- account := &SCloudaccount{}
- account.Id = cprvd.CloudaccountId
- account.Name = cprvd.Account
- if len(account.Name) == 0 {
- account.Name = cprvd.Name
- }
- account.SetModelManager(CloudaccountManager, account)
- logclient.AddSimpleActionLog(account, logclient.ACT_CLOUD_SYNC, iNotes, userCred, false)
- }
- }
- func (cprvd *SCloudaccount) SyncError(result compare.SyncResult, iNotes interface{}, userCred mcclient.TokenCredential) {
- if result.IsError() {
- logclient.AddSimpleActionLog(cprvd, logclient.ACT_CLOUD_SYNC, iNotes, userCred, false)
- }
- }
|