| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077 |
- // 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"
- "gopkg.in/fatih/set.v0"
- "yunion.io/x/cloudmux/pkg/apis/cloudid"
- "yunion.io/x/cloudmux/pkg/cloudprovider"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/util/compare"
- "yunion.io/x/pkg/util/httputils"
- "yunion.io/x/sqlchemy"
- "yunion.io/x/onecloud/pkg/apis"
- api "yunion.io/x/onecloud/pkg/apis/cloudid"
- "yunion.io/x/onecloud/pkg/cloudcommon/db"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
- "yunion.io/x/onecloud/pkg/cloudcommon/validators"
- "yunion.io/x/onecloud/pkg/cloudid/options"
- "yunion.io/x/onecloud/pkg/httperrors"
- "yunion.io/x/onecloud/pkg/mcclient"
- "yunion.io/x/onecloud/pkg/util/stringutils2"
- )
- type SCloudgroupManager struct {
- db.SStatusInfrasResourceBaseManager
- SCloudaccountResourceBaseManager
- SCloudproviderResourceBaseManager
- }
- var CloudgroupManager *SCloudgroupManager
- func init() {
- CloudgroupManager = &SCloudgroupManager{
- SStatusInfrasResourceBaseManager: db.NewStatusInfrasResourceBaseManager(
- SCloudgroup{},
- "cloudgroups_tbl",
- "cloudgroup",
- "cloudgroups",
- ),
- }
- CloudgroupManager.SetVirtualObject(CloudgroupManager)
- }
- type SCloudgroup struct {
- db.SStatusInfrasResourceBase
- db.SExternalizedResourceBase
- SCloudaccountResourceBase
- SCloudproviderResourceBase
- }
- // 权限组列表
- func (manager *SCloudgroupManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.CloudgroupListInput) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SStatusInfrasResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusInfrasResourceBaseListInput)
- if err != nil {
- return nil, err
- }
- q, err = manager.SCloudaccountResourceBaseManager.ListItemFilter(ctx, q, userCred, query.CloudaccountResourceListInput)
- if err != nil {
- return nil, err
- }
- q, err = manager.SCloudproviderResourceBaseManager.ListItemFilter(ctx, q, userCred, query.CloudproviderResourceListInput)
- if err != nil {
- return nil, err
- }
- if len(query.ClouduserId) > 0 {
- _, err = ClouduserManager.FetchById(query.ClouduserId)
- if err != nil {
- if errors.Cause(err) == sql.ErrNoRows {
- return nil, httperrors.NewResourceNotFoundError2("clouduser", query.ClouduserId)
- }
- return q, httperrors.NewGeneralError(errors.Wrap(err, "ClouduserManager.FetchById"))
- }
- sq := CloudgroupUserManager.Query("cloudgroup_id").Equals("clouduser_id", query.ClouduserId)
- q = q.In("id", sq.SubQuery())
- }
- if len(query.CloudpolicyId) > 0 {
- _, err = CloudpolicyManager.FetchById(query.CloudpolicyId)
- if err != nil {
- if errors.Cause(err) == sql.ErrNoRows {
- return nil, httperrors.NewResourceNotFoundError2("cloudpolicy", query.CloudpolicyId)
- }
- return q, httperrors.NewGeneralError(errors.Wrap(err, "CloudpolicyManager.FetchById"))
- }
- sq := CloudgroupPolicyManager.Query("cloudgroup_id").Equals("cloudpolicy_id", query.CloudpolicyId)
- q = q.In("id", sq.SubQuery())
- }
- return q, nil
- }
- func (self *SCloudgroup) StartDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
- task, err := taskman.TaskManager.NewTask(ctx, "CloudgroupDeleteTask", self, userCred, nil, parentTaskId, "", nil)
- if err != nil {
- return errors.Wrap(err, "NewTask")
- }
- self.SetStatus(ctx, userCred, apis.STATUS_DELETING, "")
- return task.ScheduleRun(nil)
- }
- func (self *SCloudgroup) StartSyncstatusTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
- task, err := taskman.TaskManager.NewTask(ctx, "CloudgroupSyncstatusTask", self, userCred, nil, parentTaskId, "", nil)
- if err != nil {
- return errors.Wrap(err, "NewTask")
- }
- self.SetStatus(ctx, userCred, apis.STATUS_SYNC_STATUS, "")
- return task.ScheduleRun(nil)
- }
- func (manager *SCloudgroupManager) FetchUniqValues(ctx context.Context, data jsonutils.JSONObject) jsonutils.JSONObject {
- accountId, _ := data.GetString("cloudaccount_id")
- managerId, _ := data.GetString("manager_id")
- return jsonutils.Marshal(map[string]string{"cloudaccount_id": accountId, "manager_id": managerId})
- }
- func (manager *SCloudgroupManager) FilterByUniqValues(q *sqlchemy.SQuery, values jsonutils.JSONObject) *sqlchemy.SQuery {
- accountId, _ := values.GetString("cloudaccount_id")
- if len(accountId) > 0 {
- q = q.Equals("cloudaccount_id", accountId)
- }
- providerId, _ := values.GetString("manager_id")
- if len(providerId) > 0 {
- q = q.Equals("manager_id", providerId)
- }
- return q
- }
- // 更新权限组
- func (self *SCloudgroup) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudgroupUpdateInput) (api.CloudgroupUpdateInput, error) {
- return input, nil
- }
- // 获取权限组详情
- func (manager *SCloudgroupManager) FetchCustomizeColumns(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- objs []interface{},
- fields stringutils2.SSortedStrings,
- isList bool,
- ) []api.CloudgroupDetails {
- rows := make([]api.CloudgroupDetails, len(objs))
- statusRows := manager.SStatusInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
- acRows := manager.SCloudaccountResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
- mRows := manager.SCloudproviderResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
- groupIds := make([]string, len(objs))
- for i := range rows {
- rows[i] = api.CloudgroupDetails{
- StatusInfrasResourceBaseDetails: statusRows[i],
- CloudaccountResourceDetails: acRows[i],
- CloudproviderResourceDetails: mRows[i],
- Cloudpolicies: []api.SCloudIdBaseResource{},
- }
- group := objs[i].(*SCloudgroup)
- groupIds[i] = group.Id
- }
- userSQ := ClouduserManager.Query().SubQuery()
- ugQ := CloudgroupUserManager.Query().SubQuery()
- q := userSQ.Query(
- userSQ.Field("id"),
- userSQ.Field("name"),
- ugQ.Field("cloudgroup_id"),
- ).
- Join(ugQ, sqlchemy.Equals(ugQ.Field("clouduser_id"), userSQ.Field("id"))).
- Filter(sqlchemy.In(ugQ.Field("cloudgroup_id"), groupIds))
- userInfo := []struct {
- Id string
- Name string
- CloudgroupId string
- }{}
- err := q.All(&userInfo)
- if err != nil {
- log.Errorf("query group user info error: %v", err)
- return rows
- }
- users := map[string][]api.SCloudIdBaseResource{}
- for _, user := range userInfo {
- _, ok := users[user.CloudgroupId]
- if !ok {
- users[user.CloudgroupId] = []api.SCloudIdBaseResource{}
- }
- users[user.CloudgroupId] = append(users[user.CloudgroupId], api.SCloudIdBaseResource{
- Id: user.Id,
- Name: user.Name,
- })
- }
- policySQ := CloudpolicyManager.Query().SubQuery()
- pgQ := CloudgroupPolicyManager.Query().SubQuery()
- q = policySQ.Query(
- policySQ.Field("id"),
- policySQ.Field("name"),
- pgQ.Field("cloudgroup_id"),
- ).
- Join(pgQ, sqlchemy.Equals(pgQ.Field("cloudpolicy_id"), policySQ.Field("id"))).
- Filter(sqlchemy.In(pgQ.Field("cloudgroup_id"), groupIds))
- policyInfo := []struct {
- Id string
- Name string
- CloudgroupId string
- }{}
- err = q.All(&policyInfo)
- if err != nil {
- log.Errorf("query group policy info error: %v", err)
- return rows
- }
- policies := map[string][]api.SCloudIdBaseResource{}
- for _, policy := range policyInfo {
- _, ok := policies[policy.CloudgroupId]
- if !ok {
- policies[policy.CloudgroupId] = []api.SCloudIdBaseResource{}
- }
- policies[policy.CloudgroupId] = append(policies[policy.CloudgroupId], api.SCloudIdBaseResource{
- Id: policy.Id,
- Name: policy.Name,
- })
- }
- for i := range rows {
- rows[i].Cloudusers, _ = users[groupIds[i]]
- rows[i].ClouduserCount = len(rows[i].Cloudusers)
- rows[i].Cloudpolicies, _ = policies[groupIds[i]]
- rows[i].CloudpolicyCount = len(rows[i].Cloudpolicies)
- }
- return rows
- }
- func (manager *SCloudgroupManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
- switch field {
- case "manager":
- managerQuery := CloudproviderManager.Query("name", "id").SubQuery()
- q.AppendField(managerQuery.Field("name", field)).Distinct()
- q = q.Join(managerQuery, sqlchemy.Equals(q.Field("manager_id"), managerQuery.Field("id")))
- return q, nil
- case "account":
- accountQuery := CloudaccountManager.Query("name", "id").SubQuery()
- providers := CloudproviderManager.Query("id", "cloudaccount_id").SubQuery()
- q.AppendField(accountQuery.Field("name", field)).Distinct()
- q = q.Join(providers, sqlchemy.Equals(q.Field("manager_id"), providers.Field("id")))
- q = q.Join(accountQuery, sqlchemy.Equals(providers.Field("cloudaccount_id"), accountQuery.Field("id")))
- return q, nil
- case "provider", "brand":
- accountQuery := CloudaccountManager.Query(field, "id").Distinct().SubQuery()
- providers := CloudproviderManager.Query("id", "cloudaccount_id").SubQuery()
- q.AppendField(accountQuery.Field(field)).Distinct()
- q = q.Join(providers, sqlchemy.Equals(q.Field("manager_id"), providers.Field("id")))
- q = q.Join(accountQuery, sqlchemy.Equals(providers.Field("cloudaccount_id"), accountQuery.Field("id")))
- return q, nil
- }
- return q, httperrors.ErrNotFound
- }
- // 创建权限组
- func (manager *SCloudgroupManager) ValidateCreateData(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- ownerId mcclient.IIdentityProvider,
- query jsonutils.JSONObject,
- input *api.CloudgroupCreateInput,
- ) (*api.CloudgroupCreateInput, error) {
- if len(input.ManagerId) == 0 {
- return nil, httperrors.NewMissingParameterError("manager_id")
- }
- providerObj, err := validators.ValidateModel(ctx, userCred, CloudproviderManager, &input.ManagerId)
- if err != nil {
- return nil, err
- }
- provider := providerObj.(*SCloudprovider)
- input.CloudaccountId = provider.CloudaccountId
- driver, err := provider.GetDriver()
- if err != nil {
- return nil, err
- }
- input, err = driver.ValidateCreateCloudgroup(ctx, userCred, provider, input)
- if err != nil {
- return nil, err
- }
- input.Status = apis.STATUS_CREATING
- return input, nil
- }
- func (self *SCloudgroup) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
- input := api.CloudgroupCreateInput{}
- data.Unmarshal(&input)
- for _, policyId := range input.CloudpolicyIds {
- self.attachPolicy(policyId)
- }
- self.StartCreateTask(ctx, userCred, "")
- }
- func (self *SCloudgroup) StartCreateTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
- params := jsonutils.NewDict()
- task, err := taskman.TaskManager.NewTask(ctx, "CloudgroupCreateTask", self, userCred, params, parentTaskId, "", nil)
- if err != nil {
- return errors.Wrapf(err, "NewTask")
- }
- return task.ScheduleRun(nil)
- }
- // 删除权限组
- func (self *SCloudgroup) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
- params := jsonutils.NewDict()
- return self.StartCloudgroupDeleteTask(ctx, userCred, params, "")
- }
- func (self *SCloudgroup) StartCloudgroupDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error {
- task, err := taskman.TaskManager.NewTask(ctx, "CloudgroupDeleteTask", self, userCred, data, parentTaskId, "", nil)
- if err != nil {
- return errors.Wrap(err, "NewTask")
- }
- self.SetStatus(ctx, userCred, apis.STATUS_DELETING, "")
- return task.ScheduleRun(nil)
- }
- func (self *SCloudgroup) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
- return nil
- }
- func (self *SCloudgroup) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
- return self.purge(ctx)
- }
- func (self *SCloudgroup) GetSamlusers() ([]SSamluser, error) {
- q := SamluserManager.Query().Equals("cloudgroup_id", self.Id)
- users := []SSamluser{}
- err := db.FetchModelObjects(SamluserManager, q, &users)
- if err != nil {
- return nil, errors.Wrapf(err, "db.FetchModelObjects")
- }
- return users, nil
- }
- func (self *SCloudgroup) GetCloudpolicyQuery() *sqlchemy.SQuery {
- sq := CloudgroupPolicyManager.Query("cloudpolicy_id").Equals("cloudgroup_id", self.Id).SubQuery()
- return CloudpolicyManager.Query().In("id", sq)
- }
- func (self *SCloudgroup) GetCloudpolicyCount() (int, error) {
- return self.GetCloudpolicyQuery().CountWithError()
- }
- func (self *SCloudgroup) GetCloudpolicies() ([]SCloudpolicy, error) {
- policies := []SCloudpolicy{}
- q := self.GetCloudpolicyQuery()
- err := db.FetchModelObjects(CloudpolicyManager, q, &policies)
- if err != nil {
- return nil, errors.Wrap(err, "db.FetchModelObjects")
- }
- return policies, nil
- }
- func (self *SCloudgroup) GetCloudpolicy(policyId string) (*SCloudpolicy, error) {
- policies := []SCloudpolicy{}
- q := self.GetCloudpolicyQuery().Equals("id", policyId)
- err := db.FetchModelObjects(CloudpolicyManager, q, &policies)
- if err != nil {
- return nil, errors.Wrap(err, "db.FetchModelObjects")
- }
- if len(policies) > 1 {
- return nil, sqlchemy.ErrDuplicateEntry
- }
- if len(policies) == 0 {
- return nil, sql.ErrNoRows
- }
- return &policies[0], nil
- }
- func (self *SCloudgroup) detachPolicy(policyId string) error {
- policies := []SCloudgroupPolicy{}
- q := CloudgroupPolicyManager.Query().Equals("cloudgroup_id", self.Id).Equals("cloudpolicy_id", policyId)
- err := db.FetchModelObjects(CloudgroupPolicyManager, q, &policies)
- if err != nil {
- return errors.Wrap(err, "db.FetchModelObjects")
- }
- for i := range policies {
- err = policies[i].Delete(context.Background(), nil)
- if err != nil {
- return errors.Wrap(err, "Delete")
- }
- }
- return nil
- }
- func (self *SCloudgroup) GetClouduserQuery() *sqlchemy.SQuery {
- sq := CloudgroupUserManager.Query("clouduser_id").Equals("cloudgroup_id", self.Id).SubQuery()
- return ClouduserManager.Query().In("id", sq)
- }
- func (self *SCloudgroup) GetClouduserCount() (int, error) {
- return self.GetClouduserQuery().CountWithError()
- }
- func (self *SCloudgroup) GetClouduser(userId string) (*SClouduser, error) {
- users := []SClouduser{}
- q := self.GetClouduserQuery().Equals("id", userId)
- err := db.FetchModelObjects(ClouduserManager, q, &users)
- if err != nil {
- return nil, errors.Wrap(err, "db.FetchModelObjects")
- }
- if len(users) > 1 {
- return nil, sqlchemy.ErrDuplicateEntry
- }
- if len(users) == 0 {
- return nil, sql.ErrNoRows
- }
- return &users[0], nil
- }
- func (self *SCloudgroup) GetCloudusers() ([]SClouduser, error) {
- users := []SClouduser{}
- q := self.GetClouduserQuery()
- err := db.FetchModelObjects(ClouduserManager, q, &users)
- if err != nil {
- return nil, errors.Wrap(err, "db.FetchModelObjects")
- }
- return users, nil
- }
- func (self *SCloudgroup) removeUser(userId string) error {
- users := []SCloudgroupUser{}
- q := CloudgroupUserManager.Query().Equals("cloudgroup_id", self.Id).Equals("clouduser_id", userId)
- err := db.FetchModelObjects(CloudgroupUserManager, q, &users)
- if err != nil {
- return errors.Wrap(err, "db.FetchModelObjects")
- }
- for i := range users {
- err = users[i].Delete(context.Background(), nil)
- if err != nil {
- return errors.Wrap(err, "Delete")
- }
- }
- return nil
- }
- // 向权限组加入用户
- // 权限组状态必须为: available
- func (self *SCloudgroup) PerformAddUser(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudgroupAddUserInput) (jsonutils.JSONObject, error) {
- if self.Status != apis.STATUS_AVAILABLE {
- return nil, httperrors.NewInvalidStatusError("Can not remove user in status %s", self.Status)
- }
- userObj, err := validators.ValidateModel(ctx, userCred, ClouduserManager, &input.ClouduserId)
- if err != nil {
- return nil, err
- }
- user := userObj.(*SClouduser)
- if user.ManagerId != self.ManagerId || user.CloudaccountId != self.CloudaccountId {
- return nil, httperrors.NewConflictError("Users and user groups do not belong to the same account")
- }
- _, err = self.GetClouduser(input.ClouduserId)
- if err == nil || errors.Cause(err) == sqlchemy.ErrDuplicateEntry {
- return nil, httperrors.NewDuplicateResourceError("user %s has aleady in this group", input.ClouduserId)
- }
- add := []api.GroupUser{
- {
- Name: user.Name,
- ExternalId: user.ExternalId,
- },
- }
- return nil, self.StartSetUsersTask(ctx, userCred, add, nil, "")
- }
- func (self *SCloudgroup) StartSetUsersTask(ctx context.Context, userCred mcclient.TokenCredential, add, del []api.GroupUser, parentTaskId string) error {
- params := jsonutils.NewDict()
- if len(add) > 0 {
- params.Set("add", jsonutils.Marshal(add))
- }
- if len(del) > 0 {
- params.Set("del", jsonutils.Marshal(del))
- }
- task, err := taskman.TaskManager.NewTask(ctx, "CloudgroupSetUsersTask", self, userCred, params, parentTaskId, "", nil)
- if err != nil {
- return errors.Wrap(err, "NewTask")
- }
- self.SetStatus(ctx, userCred, apis.STATUS_SYNC_STATUS, "")
- return task.ScheduleRun(nil)
- }
- func (self *SCloudgroup) StartCloudgroupSyncstatusTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
- task, err := taskman.TaskManager.NewTask(ctx, "CloudgroupSyncstatusTask", self, userCred, nil, parentTaskId, "", nil)
- if err != nil {
- return errors.Wrap(err, "NewTask")
- }
- self.SetStatus(ctx, userCred, apis.STATUS_SYNC_STATUS, "")
- return task.ScheduleRun(nil)
- }
- // 恢复权限组状态
- func (self *SCloudgroup) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudgroupSyncstatusInput) (jsonutils.JSONObject, error) {
- return nil, self.StartCloudgroupSyncstatusTask(ctx, userCred, "")
- }
- // 从权限组移除用户
- // 权限组状态必须为: available
- func (self *SCloudgroup) PerformRemoveUser(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudgroupRemoveUserInput) (jsonutils.JSONObject, error) {
- if self.Status != apis.STATUS_AVAILABLE {
- return nil, httperrors.NewInvalidStatusError("Can not remove user in status %s", self.Status)
- }
- userObj, err := validators.ValidateModel(ctx, userCred, ClouduserManager, &input.ClouduserId)
- if err != nil {
- return nil, err
- }
- user := userObj.(*SClouduser)
- _, err = self.GetClouduser(input.ClouduserId)
- if err != nil {
- if errors.Cause(err) == sql.ErrNoRows {
- return nil, nil
- }
- return nil, httperrors.NewGeneralError(err)
- }
- del := []api.GroupUser{
- {
- Name: user.Name,
- ExternalId: user.ExternalId,
- },
- }
- return nil, self.StartSetUsersTask(ctx, userCred, nil, del, "")
- }
- func (self *SCloudgroup) addUser(userId string) error {
- gu := &SCloudgroupUser{}
- gu.SetModelManager(CloudgroupUserManager, gu)
- gu.ClouduserId = userId
- gu.CloudgroupId = self.Id
- return CloudgroupUserManager.TableSpec().Insert(context.Background(), gu)
- }
- // 设置权限组用户(全量覆盖)
- // 权限组状态必须为: available
- func (self *SCloudgroup) PerformSetUsers(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudgroupSetUsersInput) (jsonutils.JSONObject, error) {
- if self.Status != apis.STATUS_AVAILABLE {
- return nil, httperrors.NewInvalidStatusError("Can not set users in status %s", self.Status)
- }
- users, err := self.GetCloudusers()
- if err != nil {
- return nil, httperrors.NewGeneralError(err)
- }
- userMap := map[string]*SClouduser{}
- local := set.New(set.ThreadSafe)
- for i := range users {
- local.Add(users[i].Id)
- userMap[users[i].Id] = &users[i]
- }
- newU := set.New(set.ThreadSafe)
- for i := range input.ClouduserIds {
- _user, err := validators.ValidateModel(ctx, userCred, ClouduserManager, &input.ClouduserIds[i])
- if err != nil {
- return nil, err
- }
- user := _user.(*SClouduser)
- if user.ManagerId != self.ManagerId || user.CloudaccountId != self.CloudaccountId {
- return nil, httperrors.NewConflictError("Users and user groups do not belong to the same account")
- }
- newU.Add(user.Id)
- userMap[user.Id] = user
- }
- del, add := []api.GroupUser{}, []api.GroupUser{}
- for _, id := range set.Difference(local, newU).List() {
- user := userMap[id.(string)]
- del = append(del, api.GroupUser{
- Name: user.Name,
- ExternalId: user.ExternalId,
- })
- }
- for _, id := range set.Difference(newU, local).List() {
- user := userMap[id.(string)]
- add = append(add, api.GroupUser{
- Name: user.Name,
- ExternalId: user.ExternalId,
- })
- }
- return nil, self.StartSetUsersTask(ctx, userCred, add, del, "")
- }
- // 设置权限组添权限(全量覆盖)
- // 权限组状态必须为: available
- func (self *SCloudgroup) PerformSetPolicies(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudgroupSetPoliciesInput) (jsonutils.JSONObject, error) {
- if self.Status != apis.STATUS_AVAILABLE {
- return nil, httperrors.NewInvalidStatusError("Can not set policies in status %s", self.Status)
- }
- policies, err := self.GetCloudpolicies()
- if err != nil {
- return nil, httperrors.NewGeneralError(err)
- }
- policyMap := map[string]*SCloudpolicy{}
- local := set.New(set.ThreadSafe)
- for i := range policies {
- local.Add(policies[i].Id)
- policyMap[policies[i].Id] = &policies[i]
- }
- newP := set.New(set.ThreadSafe)
- for i := range input.CloudpolicyIds {
- policObj, err := validators.ValidateModel(ctx, userCred, CloudpolicyManager, &input.CloudpolicyIds[i])
- if err != nil {
- return nil, err
- }
- policy := policObj.(*SCloudpolicy)
- if (policy.ManagerId != self.ManagerId && len(self.ManagerId) > 0) || policy.CloudaccountId != self.CloudaccountId {
- return nil, httperrors.NewConflictError("Policies and groups do not belong to the same account")
- }
- newP.Add(policy.Id)
- policyMap[policy.Id] = policy
- }
- del, add := []api.SPolicy{}, []api.SPolicy{}
- for _, id := range set.Difference(local, newP).List() {
- policy := policyMap[id.(string)]
- del = append(del, api.SPolicy{
- Name: policy.Name,
- ExternalId: policy.ExternalId,
- PolicyType: policy.PolicyType,
- })
- }
- for _, id := range set.Difference(newP, local).List() {
- policy := policyMap[id.(string)]
- add = append(add, api.SPolicy{
- Name: policy.Name,
- ExternalId: policy.ExternalId,
- PolicyType: policy.PolicyType,
- })
- }
- return nil, self.StartSetPoliciesTask(ctx, userCred, add, del, "")
- }
- func (self *SCloudgroup) StartSetPoliciesTask(ctx context.Context, userCred mcclient.TokenCredential, add, del []api.SPolicy, parentTaskId string) error {
- params := jsonutils.NewDict()
- if len(add) > 0 {
- params.Set("add", jsonutils.Marshal(add))
- }
- if len(del) > 0 {
- params.Set("del", jsonutils.Marshal(del))
- }
- task, err := taskman.TaskManager.NewTask(ctx, "CloudgroupSetPoliciesTask", self, userCred, params, parentTaskId, "", nil)
- if err != nil {
- return errors.Wrap(err, "NewTask")
- }
- self.SetStatus(ctx, userCred, apis.STATUS_SYNC_STATUS, "")
- return task.ScheduleRun(nil)
- }
- // 向权限组添加权限
- // 权限组状态必须为: available
- func (self *SCloudgroup) PerformAttachPolicy(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudgroupAttachPolicyInput) (jsonutils.JSONObject, error) {
- if self.Status != apis.STATUS_AVAILABLE {
- return nil, httperrors.NewInvalidStatusError("Can not attach policy in status %s", self.Status)
- }
- policyObj, err := validators.ValidateModel(ctx, userCred, CloudpolicyManager, &input.CloudpolicyId)
- if err != nil {
- return nil, err
- }
- policy := policyObj.(*SCloudpolicy)
- if policy.ManagerId != self.ManagerId || policy.CloudaccountId != self.CloudaccountId {
- return nil, httperrors.NewConflictError("policy and groups do not belong to the same account")
- }
- _, err = self.GetCloudpolicy(input.CloudpolicyId)
- if err == nil || errors.Cause(err) == sqlchemy.ErrDuplicateEntry {
- return nil, httperrors.NewDuplicateResourceError("policy %s has aleady in this group", input.CloudpolicyId)
- }
- add := []api.SPolicy{
- {
- Name: policy.Name,
- ExternalId: policy.ExternalId,
- PolicyType: policy.PolicyType,
- },
- }
- return nil, self.StartSetPoliciesTask(ctx, userCred, add, nil, "")
- }
- // 从权限组移除权限
- // 权限组状态必须为: available
- func (self *SCloudgroup) PerformDetachPolicy(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudgroupDetachPolicyInput) (jsonutils.JSONObject, error) {
- if self.Status != apis.STATUS_AVAILABLE {
- return nil, httperrors.NewInvalidStatusError("Can not detach policy in status %s", self.Status)
- }
- policObj, err := validators.ValidateModel(ctx, userCred, CloudpolicyManager, &input.CloudpolicyId)
- if err != nil {
- return nil, err
- }
- policy := policObj.(*SCloudpolicy)
- _, err = self.GetCloudpolicy(input.CloudpolicyId)
- if err != nil && errors.Cause(err) == sql.ErrNoRows {
- return nil, nil
- }
- del := []api.SPolicy{
- {
- Name: policy.Name,
- ExternalId: policy.ExternalId,
- PolicyType: policy.PolicyType,
- },
- }
- return nil, self.StartSetPoliciesTask(ctx, userCred, nil, del, "")
- }
- func (self *SCloudgroup) attachPolicy(policyId string) error {
- gp := &SCloudgroupPolicy{}
- gp.SetModelManager(CloudgroupPolicyManager, gp)
- gp.CloudpolicyId = policyId
- gp.CloudgroupId = self.Id
- return CloudgroupPolicyManager.TableSpec().Insert(context.Background(), gp)
- }
- func (self *SCloudaccount) SyncCloudgroups(ctx context.Context, userCred mcclient.TokenCredential, iGroups []cloudprovider.ICloudgroup, managerId string) ([]SCloudgroup, []cloudprovider.ICloudgroup, compare.SyncResult) {
- lockman.LockRawObject(ctx, CloudgroupManager.Keyword(), fmt.Sprintf("%s-%s", self.Id, managerId))
- defer lockman.ReleaseRawObject(ctx, CloudgroupManager.Keyword(), fmt.Sprintf("%s-%s", self.Id, managerId))
- result := compare.SyncResult{}
- dbGroups, err := self.GetCloudgroups(managerId)
- if err != nil {
- result.Error(errors.Wrap(err, "GetCloudgroups"))
- return nil, nil, result
- }
- localGroups := []SCloudgroup{}
- remoteGroups := []cloudprovider.ICloudgroup{}
- removed := make([]SCloudgroup, 0)
- commondb := make([]SCloudgroup, 0)
- commonext := make([]cloudprovider.ICloudgroup, 0)
- added := make([]cloudprovider.ICloudgroup, 0)
- err = compare.CompareSets(dbGroups, iGroups, &removed, &commondb, &commonext, &added)
- if err != nil {
- result.Error(errors.Wrap(err, "compare.CompareSets"))
- return nil, nil, result
- }
- for i := 0; i < len(removed); i++ {
- err = removed[i].RealDelete(ctx, userCred)
- if err != nil {
- result.DeleteError(err)
- continue
- }
- result.Delete()
- }
- for i := 0; i < len(commondb); i++ {
- err = commondb[i].SyncWithCloudgroup(ctx, userCred, commonext[i])
- if err != nil {
- result.UpdateError(err)
- continue
- }
- localGroups = append(localGroups, commondb[i])
- remoteGroups = append(remoteGroups, commonext[i])
- result.Update()
- }
- for i := 0; i < len(added); i++ {
- group, err := self.newCloudgroup(ctx, userCred, added[i], managerId)
- if err != nil {
- result.AddError(err)
- continue
- }
- localGroups = append(localGroups, *group)
- remoteGroups = append(remoteGroups, added[i])
- result.Add()
- }
- return localGroups, remoteGroups, result
- }
- func (group *SCloudgroup) GetCloudprovider() (*SCloudprovider, error) {
- provider, err := CloudproviderManager.FetchById(group.ManagerId)
- if err != nil {
- return nil, err
- }
- return provider.(*SCloudprovider), nil
- }
- func (self *SCloudgroup) GetProvider() (cloudprovider.ICloudProvider, error) {
- if len(self.ManagerId) > 0 {
- provider, err := self.GetCloudprovider()
- if err != nil {
- return nil, err
- }
- return provider.GetProvider()
- }
- if len(self.CloudaccountId) > 0 {
- account, err := self.GetCloudaccount()
- if err != nil {
- if err != nil {
- return nil, err
- }
- }
- return account.GetProvider()
- }
- return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty account info")
- }
- func (group *SCloudgroup) GetICloudgroup() (cloudprovider.ICloudgroup, error) {
- if len(group.ExternalId) == 0 {
- return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty external id")
- }
- provider, err := group.GetProvider()
- if err != nil {
- return nil, err
- }
- groups, err := provider.GetICloudgroups()
- if err != nil {
- return nil, err
- }
- for i := range groups {
- if groups[i].GetGlobalId() == group.ExternalId {
- return groups[i], nil
- }
- }
- return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%v", group.ExternalId)
- }
- func (group *SCloudgroup) SyncWithCloudgroup(ctx context.Context, userCred mcclient.TokenCredential, iGroup cloudprovider.ICloudgroup) error {
- _, err := db.Update(group, func() error {
- group.Name = iGroup.GetName()
- group.Status = apis.STATUS_AVAILABLE
- return nil
- })
- return err
- }
- func (self *SCloudaccount) newCloudgroup(ctx context.Context, userCred mcclient.TokenCredential, iGroup cloudprovider.ICloudgroup, managerId string) (*SCloudgroup, error) {
- group := &SCloudgroup{}
- group.SetModelManager(CloudgroupManager, group)
- group.Name = iGroup.GetName()
- group.ExternalId = iGroup.GetGlobalId()
- group.Status = apis.STATUS_AVAILABLE
- group.CloudaccountId = self.Id
- group.ManagerId = managerId
- group.DomainId = self.DomainId
- err := CloudgroupManager.TableSpec().Insert(ctx, group)
- if err != nil {
- return nil, errors.Wrap(err, "Insert")
- }
- return group, nil
- }
- func (self *SCloudgroup) SyncCloudusers(ctx context.Context, userCred mcclient.TokenCredential, iGroup cloudprovider.ICloudgroup) {
- iUsers, err := iGroup.GetICloudusers()
- if err == nil {
- result := self.SyncUsers(ctx, userCred, iUsers)
- log.Debugf("sync cloudusers for group %s result: %s", self.Name, result.Result())
- }
- }
- func (self *SCloudgroup) SyncUsers(ctx context.Context, userCred mcclient.TokenCredential, iUsers []cloudprovider.IClouduser) compare.SyncResult {
- lockman.LockRawObject(ctx, ClouduserManager.Keyword(), self.Id)
- defer lockman.ReleaseRawObject(ctx, ClouduserManager.Keyword(), self.Id)
- result := compare.SyncResult{}
- dbUsers, err := self.GetCloudusers()
- if err != nil {
- result.Error(errors.Wrap(err, "GetCloudusers"))
- return result
- }
- removed := make([]SClouduser, 0)
- commondb := make([]SClouduser, 0)
- commonext := make([]cloudprovider.IClouduser, 0)
- added := make([]cloudprovider.IClouduser, 0)
- err = compare.CompareSets(dbUsers, iUsers, &removed, &commondb, &commonext, &added)
- if err != nil {
- result.Error(errors.Wrap(err, "compare.CompareSets"))
- return result
- }
- for i := 0; i < len(removed); i++ {
- self.removeUser(removed[i].Id)
- if err != nil {
- result.DeleteError(err)
- continue
- }
- result.Delete()
- }
- result.UpdateCnt = len(commondb)
- for i := 0; i < len(added); i++ {
- user, err := db.FetchByExternalIdAndManagerId(ClouduserManager, added[i].GetGlobalId(), func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- if len(self.ManagerId) > 0 {
- return q.Equals("manager_id", self.ManagerId)
- }
- return q.Equals("cloudaccount_id", self.CloudaccountId)
- })
- if err != nil {
- result.AddError(errors.Wrapf(err, "Fetch %s", added[i].GetGlobalId()))
- continue
- }
- err = self.addUser(user.GetId())
- if err != nil {
- result.AddError(err)
- continue
- }
- result.Add()
- }
- return result
- }
- func (self *SCloudgroup) SyncCloudpolicies(ctx context.Context, userCred mcclient.TokenCredential, iGroup cloudprovider.ICloudgroup) {
- iPolicies, err := iGroup.GetICloudpolicies()
- if err == nil {
- result := self.SyncPolicies(ctx, userCred, iPolicies)
- log.Infof("SyncCloudpolicies for group %s(%s) result: %s", self.Name, self.Id, result.Result())
- }
- }
- func (self *SCloudgroup) SyncPolicies(ctx context.Context, userCred mcclient.TokenCredential, iPolicies []cloudprovider.ICloudpolicy) compare.SyncResult {
- result := compare.SyncResult{}
- dbPolicies, err := self.GetCloudpolicies()
- if err != nil {
- result.Error(errors.Wrapf(err, "GetCloudpolicies"))
- return result
- }
- removed := make([]SCloudpolicy, 0)
- commondb := make([]SCloudpolicy, 0)
- commonext := make([]cloudprovider.ICloudpolicy, 0)
- added := make([]cloudprovider.ICloudpolicy, 0)
- err = compare.CompareSets(dbPolicies, iPolicies, &removed, &commondb, &commonext, &added)
- if err != nil {
- result.Error(errors.Wrap(err, "compare.CompareSets"))
- return result
- }
- for i := 0; i < len(removed); i++ {
- err := self.detachPolicy(removed[i].Id)
- if err != nil {
- result.DeleteError(err)
- continue
- }
- result.Delete()
- }
- result.UpdateCnt = len(commondb)
- for i := 0; i < len(added); i++ {
- policy, err := db.FetchByExternalIdAndManagerId(CloudpolicyManager, added[i].GetGlobalId(), func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- if len(self.ManagerId) > 0 {
- return q.Equals("manager_id", self.ManagerId)
- }
- return q.Equals("cloudaccount_id", self.CloudaccountId)
- })
- if err != nil {
- result.AddError(errors.Wrapf(err, "add %s(%s)", added[i].GetName(), added[i].GetGlobalId()))
- continue
- }
- err = self.attachPolicy(policy.GetId())
- if err != nil {
- result.AddError(err)
- continue
- }
- result.Add()
- }
- return result
- }
- func (self *SCloudgroup) GetSamlProvider() (*SSAMLProvider, error) {
- q := SAMLProviderManager.Query().Equals("status", apis.STATUS_AVAILABLE).
- Equals("entity_id", options.Options.ApiServer).
- Equals("cloudaccount_id", self.CloudaccountId).
- IsNotEmpty("external_id")
- if len(self.ManagerId) > 0 {
- q = q.Equals("manager_id", self.ManagerId)
- }
- ret := &SSAMLProvider{}
- ret.SetModelManager(SAMLProviderManager, ret)
- err := q.First(ret)
- if err != nil {
- return nil, err
- }
- return ret, nil
- }
- func (self *SCloudgroup) GetCloudroles() ([]SCloudrole, error) {
- sq := SamluserManager.Query("cloudrole_id").Equals("cloudgroup_id", self.Id).SubQuery()
- q := CloudroleManager.Query().Equals("cloudgroup_id", self.Id).IsNotEmpty("external_id").In("id", sq)
- ret := []SCloudrole{}
- err := db.FetchModelObjects(CloudroleManager, q, &ret)
- if err != nil {
- return nil, err
- }
- return ret, nil
- }
- func (self *SCloudgroup) GetDetailsSaml(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*api.GetCloudaccountSamlOutput, error) {
- output := &api.GetCloudaccountSamlOutput{}
- account, err := self.GetCloudaccount()
- if err != nil {
- return nil, err
- }
- if account.SAMLAuth.IsFalse() {
- return output, httperrors.NewNotSupportedError("account %s not enable saml auth", account.Name)
- }
- provider, err := account.GetProvider()
- if err != nil {
- return output, errors.Wrap(err, "GetProviderFactory")
- }
- samlProvider, err := self.GetSamlProvider()
- if err != nil {
- if errors.Cause(err) == sql.ErrNoRows {
- return nil, httperrors.NewResourceNotReadyError("no available saml provider")
- }
- return nil, errors.Wrapf(err, "GetSamlProvider")
- }
- output.EntityId = provider.GetSamlEntityId()
- if len(output.EntityId) == 0 {
- return output, errors.Wrap(httperrors.ErrNotSupported, "SAML login not supported")
- }
- id := self.CloudaccountId
- if len(self.ManagerId) > 0 {
- id = self.ManagerId
- }
- output.RedirectLoginUrl = httputils.JoinPath(options.Options.ApiServer, cloudid.SAML_IDP_PREFIX, "redirect/login", id)
- output.RedirectLogoutUrl = httputils.JoinPath(options.Options.ApiServer, cloudid.SAML_IDP_PREFIX, "redirect/logout", id)
- output.MetadataUrl = httputils.JoinPath(options.Options.ApiServer, cloudid.SAML_IDP_PREFIX, "metadata", id)
- output.InitLoginUrl = samlProvider.AuthUrl
- return output, nil
- }
|