diff --git a/cmd/ctyuncli/main.go b/cmd/ctyuncli/main.go index 6eacacb43a..e4c355fefa 100644 --- a/cmd/ctyuncli/main.go +++ b/cmd/ctyuncli/main.go @@ -31,6 +31,8 @@ import ( ) type BaseOptions struct { + cloudprovider.SCtyunExtraOptions + Help bool `help:"Show help" default:"false"` Debug bool `help:"Show debug" default:"false"` AccessKey string `help:"Access key" default:"$CTYUN_ACCESS_KEY"` @@ -101,7 +103,7 @@ func newClient(options *BaseOptions) (*ctyun.SRegion, error) { cli, err := ctyun.NewSCtyunClient( ctyun.NewSCtyunClientConfig( - options.AccessKey, options.Secret, + options.AccessKey, options.Secret, &options.SCtyunExtraOptions, ).Debug(options.Debug). CloudproviderConfig( cloudprovider.ProviderConfig{ diff --git a/pkg/cloudprovider/cloudprovider.go b/pkg/cloudprovider/cloudprovider.go index 16a61863d9..2692eb82cb 100644 --- a/pkg/cloudprovider/cloudprovider.go +++ b/pkg/cloudprovider/cloudprovider.go @@ -99,6 +99,9 @@ type SCloudaccountCredential struct { // Huawei Cloud Stack Online *SHCSOEndpoints + + // ctyun crm account extra info + *SCtyunExtraOptions } type SCloudaccount struct { @@ -176,6 +179,7 @@ type SProviderInfo struct { Url string Account string Secret string + Options *jsonutils.JSONDict } type ICloudProviderFactory interface { @@ -400,7 +404,7 @@ func GetProvider(cfg ProviderConfig) (ICloudProvider, error) { return driver.GetProvider(cfg) } -func GetClientRC(name, accessUrl, account, secret, provider string) (map[string]string, error) { +func GetClientRC(name, accessUrl, account, secret, provider string, options *jsonutils.JSONDict) (map[string]string, error) { driver, err := GetProviderFactory(provider) if err != nil { return nil, errors.Wrap(err, "GetProviderFactory") @@ -410,6 +414,7 @@ func GetClientRC(name, accessUrl, account, secret, provider string) (map[string] Url: accessUrl, Account: account, Secret: secret, + Options: options, } return driver.GetClientRC(info) } diff --git a/pkg/cloudprovider/endpoints.go b/pkg/cloudprovider/endpoints.go index 3c76f960bc..b7459e2171 100644 --- a/pkg/cloudprovider/endpoints.go +++ b/pkg/cloudprovider/endpoints.go @@ -47,7 +47,7 @@ type SHCSOEndpoints struct { // 华为私有云Endpoint域名 // example: hcso.com.cn // required:true - EndpointDomain string `default:"$HUAWEI_ENDPOINT_DOMAIN" metavar:"HUAWEI_ENDPOINT_DOMAIN"` + EndpointDomain string `default:"$HUAWEI_ENDPOINT_DOMAIN" metavar:"$HUAWEI_ENDPOINT_DOMAIN"` // 可用区ID // example: cn-north-2 diff --git a/pkg/cloudprovider/extra.go b/pkg/cloudprovider/extra.go index 8c3142584c..c57db8ad20 100644 --- a/pkg/cloudprovider/extra.go +++ b/pkg/cloudprovider/extra.go @@ -17,3 +17,10 @@ package cloudprovider type SAWSExtraOptions struct { AWSAssumeRoleName string `json:"aws_assume_role_name"` } + +type SCtyunExtraOptions struct { + // customInfo type=1 + CrmBizId string `help:"ctyun crm user biz id. eg. ACMB1000000000123456 " json:"crm_biz_id" default:"$CTYUN_CRM_BIZ_ID"` + // customInfo type=2 + // OptionsAccountId string `help:"ctyun account id." json:"options_account_id"` +} diff --git a/pkg/compute/models/cloudaccounts.go b/pkg/compute/models/cloudaccounts.go index e24c9437d8..c06eead815 100644 --- a/pkg/compute/models/cloudaccounts.go +++ b/pkg/compute/models/cloudaccounts.go @@ -448,6 +448,10 @@ func (manager *SCloudaccountManager) validateCreateData( endpointOptions = jsonutils.Marshal(input.SCloudaccountCredential.SHCSOEndpoints) } + if input.SCloudaccountCredential.SCtyunExtraOptions != nil { + endpointOptions = jsonutils.Marshal(input.SCloudaccountCredential.SCtyunExtraOptions) + } + if endpointOptions != nil { if input.Options == nil { input.Options = jsonutils.NewDict() diff --git a/pkg/compute/models/cloudproviders.go b/pkg/compute/models/cloudproviders.go index 35a9965a89..f75d162584 100644 --- a/pkg/compute/models/cloudproviders.go +++ b/pkg/compute/models/cloudproviders.go @@ -1675,7 +1675,14 @@ func (provider *SCloudprovider) GetDetailsClirc(ctx context.Context, userCred mc if err != nil { return nil, err } - rc, err := cloudprovider.GetClientRC(provider.Name, accessUrl, provider.Account, passwd, provider.Provider) + + account := provider.GetCloudaccount() + var options *jsonutils.JSONDict + if account != nil { + options = account.Options + } + + rc, err := cloudprovider.GetClientRC(provider.Name, accessUrl, provider.Account, passwd, provider.Provider, options) if err != nil { return nil, err } diff --git a/pkg/mcclient/options/cloudaccounts.go b/pkg/mcclient/options/cloudaccounts.go index 0f5fbf9bfc..f13adf71b1 100644 --- a/pkg/mcclient/options/cloudaccounts.go +++ b/pkg/mcclient/options/cloudaccounts.go @@ -348,6 +348,8 @@ func (opts *SXskyCloudAccountCreateOptions) Params() (jsonutils.JSONObject, erro type SCtyunCloudAccountCreateOptions struct { SCloudAccountCreateBaseOptions SAccessKeyCredentialWithEnvironment + + cloudprovider.SCtyunExtraOptions } func (opts *SCtyunCloudAccountCreateOptions) Params() (jsonutils.JSONObject, error) { @@ -848,10 +850,21 @@ func (opts *SS3CloudAccountUpdateOptions) Params() (jsonutils.JSONObject, error) type SCtyunCloudAccountUpdateOptions struct { SCloudAccountUpdateBaseOptions + + cloudprovider.SCtyunExtraOptions } func (opts *SCtyunCloudAccountUpdateOptions) Params() (jsonutils.JSONObject, error) { - return jsonutils.Marshal(opts), nil + params := jsonutils.Marshal(opts).(*jsonutils.JSONDict) + options := jsonutils.NewDict() + if len(opts.SCtyunExtraOptions.CrmBizId) > 0 { + options.Add(jsonutils.NewString(opts.SCtyunExtraOptions.CrmBizId), "crm_biz_id") + } + if options.Size() > 0 { + params.Add(options, "options") + } + + return params, nil } type SJDcloudCloudAccountUpdateOptions struct { diff --git a/pkg/multicloud/ctyun/ctyun.go b/pkg/multicloud/ctyun/ctyun.go index c9690d9206..b9bb00d5eb 100644 --- a/pkg/multicloud/ctyun/ctyun.go +++ b/pkg/multicloud/ctyun/ctyun.go @@ -46,7 +46,8 @@ const ( ) type CtyunClientConfig struct { - cpcfg cloudprovider.ProviderConfig + cpcfg cloudprovider.ProviderConfig + options *cloudprovider.SCtyunExtraOptions projectId string accessKey string @@ -55,10 +56,11 @@ type CtyunClientConfig struct { debug bool } -func NewSCtyunClientConfig(accessKey, accessSecret string) *CtyunClientConfig { +func NewSCtyunClientConfig(accessKey, accessSecret string, options *cloudprovider.SCtyunExtraOptions) *CtyunClientConfig { cfg := &CtyunClientConfig{ accessKey: accessKey, accessSecret: accessSecret, + options: options, } return cfg } @@ -165,6 +167,32 @@ func (client *SCtyunClient) DoPost(apiName string, params map[string]jsonutils.J return formRequest(client, httputils.POST, apiName, nil, params) } +func getCustiomInfo(t string, crmBizId string, accountId string) jsonutils.JSONObject { + if len(t) == 0 { + return nil + } + + customeInfo := jsonutils.NewDict() + //customeInfo.Set("name", jsonutils.NewString("")) + //customeInfo.Set("email", jsonutils.NewString("")) + //customeInfo.Set("phone", jsonutils.NewString("")) + indentity := jsonutils.NewDict() + if len(crmBizId) > 0 { + indentity.Set("crmBizId", jsonutils.NewString(crmBizId)) + } + + if len(accountId) > 0 { + indentity.Set("accountId", jsonutils.NewString(accountId)) + } + + if len(t) > 0 { + customeInfo.Set("type", jsonutils.NewString(t)) + customeInfo.Set("identity", indentity) + } + + return customeInfo +} + func formRequest(client *SCtyunClient, method httputils.THttpMethod, apiName string, queries map[string]string, params map[string]jsonutils.JSONObject) (jsonutils.JSONObject, error) { header := http.Header{} // signer @@ -199,6 +227,11 @@ func formRequest(client *SCtyunClient, method httputils.THttpMethod, apiName str header.Set("hmac", hsum) // 平台类型,整数类型,取值范围:2或3,传2表示2.0自营资源,传3表示3.0合营资源,该参数不需要加密。 header.Set("platform", "3") + // crm账号需要设置customInfo。目前发现只有VPC列表查询需要用到这个参数,其他的接口还没有发现此要求。为了简便对于crm 统一设置此项 + if client.options != nil && len(client.options.CrmBizId) > 0 { + customInfo := getCustiomInfo("1", client.options.CrmBizId, "") + header.Set("customInfo", customInfo.String()) + } } var reqbody string diff --git a/pkg/multicloud/ctyun/project.go b/pkg/multicloud/ctyun/project.go index 5e981642b4..70768deb2d 100644 --- a/pkg/multicloud/ctyun/project.go +++ b/pkg/multicloud/ctyun/project.go @@ -45,7 +45,7 @@ func (self *SProject) GetHealthStatus() string { func (self *SCtyunClient) FetchProjects() ([]SProject, error) { client, err := NewSCtyunClient( NewSCtyunClientConfig( - self.accessKey, self.accessSecret, + self.accessKey, self.accessSecret, self.options, ).Debug(self.debug), ) if err != nil { diff --git a/pkg/multicloud/ctyun/provider/provider.go b/pkg/multicloud/ctyun/provider/provider.go index 872e944d58..c1620441a0 100644 --- a/pkg/multicloud/ctyun/provider/provider.go +++ b/pkg/multicloud/ctyun/provider/provider.go @@ -19,6 +19,7 @@ import ( "strings" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" @@ -85,9 +86,17 @@ func (self *SCtyunProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) account = segs[0] } + options := cloudprovider.SCtyunExtraOptions{} + if cfg.Options != nil { + err := cfg.Options.Unmarshal(&options) + if err != nil { + log.Debugf("cfg.Options.Unmarshal %s", err) + } + } + client, err := ctyun.NewSCtyunClient( ctyun.NewSCtyunClientConfig( - account, cfg.Secret, + account, cfg.Secret, &options, ).ProjectId(projectId).CloudproviderConfig(cfg), ) if err != nil { @@ -100,12 +109,25 @@ func (self *SCtyunProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) } func (self *SCtyunProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - return map[string]string{ + ret := map[string]string{ "CTYUN_ACCESS_URL": info.Url, "CTYUN_ACCESS_KEY": info.Account, "CTYUN_SECRET": info.Secret, "CTYUN_REGION": ctyun.CTYUN_DEFAULT_REGION, - }, nil + } + + options := cloudprovider.SCtyunExtraOptions{} + if info.Options != nil { + err := info.Options.Unmarshal(&options) + if err != nil { + log.Debugf("info.Options.Unmarshal %s", err) + } + } + if len(options.CrmBizId) > 0 { + ret["CTYUN_CRM_BIZ_ID"] = options.CrmBizId + } + + return ret, nil } func init() { diff --git a/pkg/multicloud/ctyun/region.go b/pkg/multicloud/ctyun/region.go index b1ed647bcf..d2faa38573 100644 --- a/pkg/multicloud/ctyun/region.go +++ b/pkg/multicloud/ctyun/region.go @@ -48,7 +48,7 @@ type SRegion struct { } func (self *SRegion) fetchIVpcs() error { - vpcs, err := self.GetVpcs("", "", "") + vpcs, err := self.GetVpcs() if err != nil { return errors.Wrap(err, "SRegion.fetchIVpcs") } @@ -83,17 +83,12 @@ func (self *SRegion) fetchInfrastructure() error { return nil } -func (self *SRegion) GetVpcs(t string, crmBizId string, accountId string) ([]SVpc, error) { +func (self *SRegion) GetVpcs() ([]SVpc, error) { vpcs := make([]SVpc, 0) params := map[string]string{ "regionId": self.GetId(), } - customInfo := self.getCustiomInfo(t, crmBizId, accountId) - if customInfo != nil { - params["customInfo"] = customInfo.String() - } - resp, err := self.client.DoGet("/apiproxy/v3/getVpcs", params) if err != nil { return nil, err diff --git a/pkg/multicloud/ctyun/shell/vpc.go b/pkg/multicloud/ctyun/shell/vpc.go index 0b527efe3e..fa308bd820 100644 --- a/pkg/multicloud/ctyun/shell/vpc.go +++ b/pkg/multicloud/ctyun/shell/vpc.go @@ -21,12 +21,9 @@ import ( func init() { type VpcListOptions struct { - Type string `json:"type"` - CrmBizId string `json:"crm_biz_id"` - AccountId string `json:"account_id"` } shellutils.R(&VpcListOptions{}, "vpc-list", "List vpcs", func(cli *ctyun.SRegion, args *VpcListOptions) error { - vpcs, e := cli.GetVpcs(args.Type, args.CrmBizId, args.AccountId) + vpcs, e := cli.GetVpcs() if e != nil { return e }