diff --git a/cmd/account-server/service/account-set/root-account/check.go b/cmd/account-server/service/account-set/root-account/check.go index 0bf98b33b0..426f3e378c 100644 --- a/cmd/account-server/service/account-set/root-account/check.go +++ b/cmd/account-server/service/account-set/root-account/check.go @@ -21,11 +21,18 @@ package rootaccount import ( "fmt" + "strings" + accountset "hcm/pkg/api/account-server/account-set" + "hcm/pkg/api/cloud-server/account" "hcm/pkg/api/core" + "hcm/pkg/api/core/cloud" "hcm/pkg/client" "hcm/pkg/criteria/enumor" + "hcm/pkg/criteria/errf" "hcm/pkg/dal/dao/tools" + "hcm/pkg/iam/meta" + "hcm/pkg/logs" "hcm/pkg/rest" ) @@ -54,3 +61,127 @@ func CheckDuplicateRootAccount(cts *rest.Contexts, client *client.ClientSet, ven return nil } + +// GetAccountBySecret 根据秘钥获取账号信息 +func (s *service) GetAccountBySecret(cts *rest.Contexts) (interface{}, error) { + vendor := enumor.Vendor(cts.Request.PathParameter("vendor")) + if err := vendor.Validate(); err != nil { + return nil, errf.NewFromErr(errf.InvalidParameter, err) + } + + // 校验用户有一级账号管理权限 + if err := s.checkPermission(cts, meta.RootAccount, meta.Find); err != nil { + return nil, err + } + + switch vendor { + case enumor.HuaWei: + return s.getHuaWeiAccountInfo(cts) + case enumor.Aws: + return s.getAwsAccountInfo(cts) + case enumor.Azure: + return s.getAzureAccountInfo(cts) + case enumor.Gcp: + return s.getGcpAccountInfo(cts) + default: + return nil, fmt.Errorf("unsupported vendor: %s", vendor) + } +} + +func (s *service) getHuaWeiAccountInfo(cts *rest.Contexts) (*cloud.HuaWeiInfoBySecret, error) { + req := new(accountset.HuaWeiAccountInfoBySecretReq) + if err := cts.DecodeInto(req); err != nil { + return nil, errf.NewFromErr(errf.DecodeRequestFailed, err) + } + if err := req.Validate(); err != nil { + return nil, errf.NewFromErr(errf.InvalidParameter, err) + } + + info, err := s.client.HCService().HuaWei.Account.GetBySecret(cts.Kit.Ctx, cts.Kit.Header(), req.HuaWeiSecret) + if err != nil { + logs.Errorf("fail to get account info, err: %v, rid: %s", err, cts.Kit.Rid) + return nil, err + } + + return info, nil +} + +func (s *service) getAwsAccountInfo(cts *rest.Contexts) (*cloud.AwsInfoBySecret, error) { + req := new(accountset.AwsAccountInfoBySecretReq) + if err := cts.DecodeInto(req); err != nil { + return nil, errf.NewFromErr(errf.DecodeRequestFailed, err) + } + if err := req.Validate(); err != nil { + return nil, errf.NewFromErr(errf.InvalidParameter, err) + } + + info, err := s.client.HCService().Aws.Account.GetBySecret(cts.Kit.Ctx, cts.Kit.Header(), req.AwsSecret) + if err != nil { + logs.Errorf("fail to get account info, err: %v, rid: %s", err, cts.Kit.Rid) + return nil, err + } + + return info, nil +} + +func (s *service) getGcpAccountInfo(cts *rest.Contexts) ([]cloud.CloudProjectInfo, error) { + req := new(accountset.GcpAccountInfoBySecretReq) + if err := cts.DecodeInto(req); err != nil { + return nil, errf.NewFromErr(errf.DecodeRequestFailed, err) + } + if err := req.Validate(); err != nil { + return nil, errf.NewFromErr(errf.InvalidParameter, err) + } + + info, err := s.client.HCService().Gcp.Account.GetBySecret(cts.Kit.Ctx, cts.Kit.Header(), req.GcpSecret) + if err != nil { + logs.Errorf("fail to get account info, err: %v, rid: %s", err, cts.Kit.Rid) + return nil, err + } + + return info.CloudProjectInfos, nil +} + +func (s *service) getAzureAccountInfo(cts *rest.Contexts) (*account.AzureAccountInfoBySecretResp, error) { + req := new(accountset.AzureAccountInfoBySecretReq) + if err := cts.DecodeInto(req); err != nil { + return nil, errf.NewFromErr(errf.DecodeRequestFailed, err) + } + if err := req.Validate(); err != nil { + return nil, errf.NewFromErr(errf.InvalidParameter, err) + } + + info, err := s.client.HCService().Azure.Account.GetBySecret(cts.Kit.Ctx, cts.Kit.Header(), req.AzureSecret) + if err != nil { + logs.Errorf("[getAzureAccountInfo] fail to get account info, err: %v, rid: %s", err, cts.Kit.Rid) + return nil, err + } + + // TODO 将来需要考虑多订阅的问题 + // 校验订阅数量,要求订阅数量刚好一个 + if len(info.SubscriptionInfos) > 1 { + subs := make([]string, len(info.SubscriptionInfos)) + for i, sub := range info.SubscriptionInfos { + subs[i] = "(" + sub.CloudSubscriptionID + ")" + sub.CloudSubscriptionName + } + return nil, fmt.Errorf("more than one subscription found: " + strings.Join(subs, ",")) + } + subscription := info.SubscriptionInfos[0] + result := &account.AzureAccountInfoBySecretResp{ + CloudSubscriptionID: subscription.CloudSubscriptionID, + CloudSubscriptionName: subscription.CloudSubscriptionName, + } + // 补全ApplicationName + for _, one := range info.ApplicationInfos { + if one.CloudApplicationID == req.CloudApplicationID { + result.CloudApplicationName = one.CloudApplicationName + break + } + } + // 没有拿到应用id的情况 + if len(result.CloudApplicationName) == 0 { + return nil, fmt.Errorf("failed to get application name") + } + + return result, nil +} diff --git a/cmd/account-server/service/account-set/root-account/service.go b/cmd/account-server/service/account-set/root-account/service.go index b56c62935c..f6f1b0dc6b 100644 --- a/cmd/account-server/service/account-set/root-account/service.go +++ b/cmd/account-server/service/account-set/root-account/service.go @@ -48,6 +48,9 @@ func InitService(c *capability.Capability) { h.Add("UpdateRootAccount", http.MethodPatch, "/root_accounts/{account_id}", svc.Update) h.Add("AddRootAccount", http.MethodPost, "/root_accounts/add", svc.Add) + h.Add("GetAccountBySecret", http.MethodPost, "/vendors/{vendor}/root_accounts/secret", + svc.GetAccountBySecret) + h.Load(c.WebService) } diff --git a/docs/api-docs/web-server/docs/resource/account/get_account_by_secret.md b/docs/api-docs/web-server/docs/resource/account/get_account_by_secret.md index aef574c8a8..54f9ee7c66 100644 --- a/docs/api-docs/web-server/docs/resource/account/get_account_by_secret.md +++ b/docs/api-docs/web-server/docs/resource/account/get_account_by_secret.md @@ -154,11 +154,11 @@ POST /api/v1/account/vendors/{vendor}/root_accounts/secret ### azure 响应参数说明 -| 参数名称 | 参数类型 | 描述 | -|---------|----------|--------------------------------| -| code | int32 | 状态码 | -| message | string | 请求信息 | -| data | []object | 响应数据,一个对象数组,包含多个subscription信息 | +| 参数名称 | 参数类型 | 描述 | +|---------|--------|------| +| code | int32 | 状态码 | +| message | string | 请求信息 | +| data | object | 响应数据 | #### data[azure] diff --git a/pkg/api/account-server/account-set/root_account.go b/pkg/api/account-server/account-set/root_account.go index 6105743b08..37876bb74f 100644 --- a/pkg/api/account-server/account-set/root_account.go +++ b/pkg/api/account-server/account-set/root_account.go @@ -23,6 +23,7 @@ package accountset import ( "encoding/json" + "hcm/pkg/api/core/cloud" "hcm/pkg/criteria/enumor" "hcm/pkg/criteria/validator" ) @@ -174,3 +175,55 @@ func (req *KaopuRootAccountExtensionUpdateReq) Validate() error { return nil } + +// GcpAccountInfoBySecretReq ... +type GcpAccountInfoBySecretReq struct { + *cloud.GcpSecret `json:",inline" validate:"required"` +} + +// Validate ... +func (req *GcpAccountInfoBySecretReq) Validate() error { + if err := req.GcpSecret.Validate(); err != nil { + return err + } + return validator.Validate.Struct(req) +} + +// AwsAccountInfoBySecretReq ... +type AwsAccountInfoBySecretReq struct { + *cloud.AwsSecret `json:",inline" validate:"required"` +} + +// Validate ... +func (req *AwsAccountInfoBySecretReq) Validate() error { + if err := req.AwsSecret.Validate(); err != nil { + return err + } + return validator.Validate.Struct(req) +} + +// HuaWeiAccountInfoBySecretReq ... +type HuaWeiAccountInfoBySecretReq struct { + *cloud.HuaWeiSecret `json:",inline" validate:"required"` +} + +// Validate ... +func (req *HuaWeiAccountInfoBySecretReq) Validate() error { + if err := req.HuaWeiSecret.Validate(); err != nil { + return err + } + return validator.Validate.Struct(req) +} + +// AzureAccountInfoBySecretReq ... +type AzureAccountInfoBySecretReq struct { + *cloud.AzureSecret `json:",inline" validate:"required"` +} + +// Validate ... +func (req *AzureAccountInfoBySecretReq) Validate() error { + if err := req.AzureSecret.Validate(); err != nil { + return err + } + return validator.Validate.Struct(req) +}