diff --git a/cmd/climc/shell/cloudaccounts.go b/cmd/climc/shell/cloudaccounts.go index 78a3cbf568..d4ca3a1afd 100644 --- a/cmd/climc/shell/cloudaccounts.go +++ b/cmd/climc/shell/cloudaccounts.go @@ -68,7 +68,7 @@ func init() { "Aliyun": {"access_key_id", "access_key_secret"}, "Azure": {"directory_id", "client_id", "client_secret", "environment"}, "Qcloud": {"app_id", "secret_id", "secret_key"}, - "OpenStack": {"project_name", "username", "password", "auth_url"}, + "OpenStack": {"project_name", "username", "password", "auth_url", "endpoint_type"}, "Huawei": {"access_key_id", "access_key_secret", "environment"}, "Aws": {"access_key_id", "access_key_secret", "environment"}, } @@ -224,6 +224,7 @@ func init() { ProjectName string `help:"OpenStack project_name"` Username string `help:"OpenStack|VMware username"` Password string `help:"OpenStack|VMware password"` + EndpointType string `help:"OpenStack endpointType"` ClientID string `help:"Azure tenant_id"` ClientSecret string `help:"Azure clinet_secret"` } diff --git a/cmd/openstackcli/main.go b/cmd/openstackcli/main.go index 5af96c0ed3..13f7adc183 100644 --- a/cmd/openstackcli/main.go +++ b/cmd/openstackcli/main.go @@ -13,13 +13,14 @@ import ( ) type BaseOptions struct { - Help bool `help:"Show help"` - AuthURL string `help:"Auth URL" default:"$OPENSTACK_AUTH_URL"` - Username string `help:"Username" default:"$OPENSTACK_USERNAME"` - Password string `help:"Password" default:"$OPENSTACK_PASSWORD"` - Project string `help:"Project" default:"$OPENSTACK_PROJECT"` - RegionID string `help:"RegionId" default:"$OPENSTACK_REGION_ID"` - SUBCOMMAND string `help:"openstackcli subcommand" subcommand:"true"` + Help bool `help:"Show help"` + AuthURL string `help:"Auth URL" default:"$OPENSTACK_AUTH_URL"` + Username string `help:"Username" default:"$OPENSTACK_USERNAME"` + Password string `help:"Password" default:"$OPENSTACK_PASSWORD"` + Project string `help:"Project" default:"$OPENSTACK_PROJECT"` + EndpointType string `help:"Project" default:"$OPENSTACK_ENDPOINT_TYPE|internal"` + RegionID string `help:"RegionId" default:"$OPENSTACK_REGION_ID"` + SUBCOMMAND string `help:"openstackcli subcommand" subcommand:"true"` } func getSubcommandParser() (*structarg.ArgumentParser, error) { @@ -75,7 +76,7 @@ func newClient(options *BaseOptions) (*openstack.SRegion, error) { return nil, fmt.Errorf("Missing Password") } - cli, err := openstack.NewOpenStackClient("", "", options.AuthURL, options.Username, options.Password, options.Project) + cli, err := openstack.NewOpenStackClient("", "", options.AuthURL, options.Username, options.Password, options.Project, options.EndpointType) if err != nil { return nil, err } diff --git a/pkg/util/openstack/openstack.go b/pkg/util/openstack/openstack.go index c5c71f40f1..12b34f7c8c 100644 --- a/pkg/util/openstack/openstack.go +++ b/pkg/util/openstack/openstack.go @@ -30,14 +30,15 @@ type SOpenStackClient struct { username string password string project string + endpointType string client *mcclient.Client tokenCredential mcclient.TokenCredential iregions []cloudprovider.ICloudRegion } -func NewOpenStackClient(providerID string, providerName string, authURL string, username string, password string, project string) (*SOpenStackClient, error) { +func NewOpenStackClient(providerID string, providerName string, authURL string, username string, password string, project string, endpointType string) (*SOpenStackClient, error) { cli := &SOpenStackClient{providerID: providerID, providerName: providerName, - authURL: authURL, username: username, password: password, project: project} + authURL: authURL, username: username, password: password, project: project, endpointType: endpointType} return cli, cli.fetchRegions() } @@ -68,7 +69,7 @@ func (cli *SOpenStackClient) Request(region, service, method string, url string, header.Set("X-Openstack-Nova-API-Version", microversion) } ctx := context.Background() - session := cli.client.NewSession(ctx, region, "", "internal", cli.tokenCredential, "") + session := cli.client.NewSession(ctx, region, "", cli.endpointType, cli.tokenCredential, "") header, resp, err := session.JSONRequest(service, "", httputils.THttpMethod(method), url, header, body) if err != nil && body != nil { uri, _ := session.GetServiceURL(service, "") @@ -83,7 +84,7 @@ func (cli *SOpenStackClient) RawRequest(region, service, method string, url stri header.Set("X-Openstack-Nova-API-Version", microversion) } ctx := context.Background() - session := cli.client.NewSession(ctx, region, "", "internal", cli.tokenCredential, "") + session := cli.client.NewSession(ctx, region, "", cli.endpointType, cli.tokenCredential, "") data := strings.NewReader("") if body != nil { data = strings.NewReader(body.String()) @@ -98,14 +99,14 @@ func (cli *SOpenStackClient) StreamRequest(region, service, method string, url s } header.Set("Content-Type", "application/octet-stream") ctx := context.Background() - session := cli.client.NewSession(ctx, region, "", "internal", cli.tokenCredential, "") + session := cli.client.NewSession(ctx, region, "", cli.endpointType, cli.tokenCredential, "") return session.RawRequest(service, "", httputils.THttpMethod(method), url, header, body) } func (cli *SOpenStackClient) getVersion(region string, service string) (string, string, error) { ctx := context.Background() - session := cli.client.NewSession(ctx, region, "", "internal", cli.tokenCredential, "") - uri, err := session.GetServiceURL(service, "internal") + session := cli.client.NewSession(ctx, region, "", cli.endpointType, cli.tokenCredential, "") + uri, err := session.GetServiceURL(service, cli.endpointType) if err != nil { return "", "", err } diff --git a/pkg/util/openstack/provider/provider.go b/pkg/util/openstack/provider/provider.go index 7541898129..67771e2f51 100644 --- a/pkg/util/openstack/provider/provider.go +++ b/pkg/util/openstack/provider/provider.go @@ -6,6 +6,7 @@ import ( "strings" "yunion.io/x/jsonutils" + "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" @@ -17,6 +18,8 @@ type SOpenStackProviderFactory struct { // providerTable map[string]*SOpenStackProvider } +var EndpointTypes = []string{"admin", "internal", "public"} + func (self *SOpenStackProviderFactory) GetId() string { return openstack.CLOUD_PROVIDER_OPENSTACK } @@ -62,7 +65,15 @@ func (self *SOpenStackProviderFactory) ValidateCreateCloudaccountData(ctx contex if len(authURL) == 0 { return httperrors.NewMissingParameterError("auth_url") } - data.Set("account", jsonutils.NewString(fmt.Sprintf("%s/%s", projectName, username))) + account := fmt.Sprintf("%s/%s", projectName, username) + if endpointType, _ := data.GetString("endpoint_type"); len(endpointType) > 0 { + if !utils.IsInStringArray(endpointType, EndpointTypes) { + return httperrors.NewInputParameterError("Unsupport endpoint_type %s only support %s", endpointType, EndpointTypes) + } + account = fmt.Sprintf("%s/%s", account, endpointType) + } + + data.Set("account", jsonutils.NewString(account)) data.Set("secret", jsonutils.NewString(password)) data.Set("access_url", jsonutils.NewString(authURL)) return nil @@ -75,7 +86,7 @@ func (self *SOpenStackProviderFactory) ValidateUpdateCloudaccountCredential(ctx if len(accountInfo) < 2 { return nil, httperrors.NewMissingParameterError("project_name") } - projectName = accountInfo[1] + projectName = accountInfo[0] } username, _ := data.GetString("username") if len(username) == 0 { @@ -85,8 +96,24 @@ func (self *SOpenStackProviderFactory) ValidateUpdateCloudaccountCredential(ctx if len(password) == 0 { return nil, httperrors.NewMissingParameterError("password") } + + _account := fmt.Sprintf("%s/%s", projectName, username) + endpointType, _ := data.GetString("endpoint_type") + if len(endpointType) == 0 { + if accountInfo := strings.Split(cloudaccount, "/"); len(accountInfo) == 3 { + endpointType = accountInfo[2] + } + } + + if len(endpointType) > 0 { + if !utils.IsInStringArray(endpointType, EndpointTypes) { + return nil, httperrors.NewInputParameterError("Unsupport endpoint_type %s only support %s", endpointType, EndpointTypes) + } + _account = fmt.Sprintf("%s/%s", _account, endpointType) + } + account := &cloudprovider.SCloudaccount{ - Account: fmt.Sprintf("%s/%s", projectName, username), + Account: _account, Secret: password, } return account, nil @@ -97,8 +124,11 @@ func (self *SOpenStackProviderFactory) GetProvider(providerId, providerName, url if len(accountInfo) < 2 { return nil, fmt.Errorf("Missing username or project name %s", account) } - project, username := accountInfo[0], accountInfo[1] - client, err := openstack.NewOpenStackClient(providerId, providerName, url, username, password, project) + project, username, endpointType := accountInfo[0], accountInfo[1], "internal" + if len(accountInfo) == 3 { + endpointType = accountInfo[2] + } + client, err := openstack.NewOpenStackClient(providerId, providerName, url, username, password, project, endpointType) if err != nil { return nil, err }