Add e2e tests
This commit is contained in:
parent
99a355f25d
commit
601fb7dacf
1163 changed files with 289217 additions and 14195 deletions
354
vendor/github.com/gophercloud/gophercloud/auth_options.go
generated
vendored
Normal file
354
vendor/github.com/gophercloud/gophercloud/auth_options.go
generated
vendored
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
package gophercloud
|
||||
|
||||
/*
|
||||
AuthOptions stores information needed to authenticate to an OpenStack Cloud.
|
||||
You can populate one manually, or use a provider's AuthOptionsFromEnv() function
|
||||
to read relevant information from the standard environment variables. Pass one
|
||||
to a provider's AuthenticatedClient function to authenticate and obtain a
|
||||
ProviderClient representing an active session on that provider.
|
||||
|
||||
Its fields are the union of those recognized by each identity implementation and
|
||||
provider.
|
||||
|
||||
An example of manually providing authentication information:
|
||||
|
||||
opts := gophercloud.AuthOptions{
|
||||
IdentityEndpoint: "https://openstack.example.com:5000/v2.0",
|
||||
Username: "{username}",
|
||||
Password: "{password}",
|
||||
TenantID: "{tenant_id}",
|
||||
}
|
||||
|
||||
provider, err := openstack.AuthenticatedClient(opts)
|
||||
|
||||
An example of using AuthOptionsFromEnv(), where the environment variables can
|
||||
be read from a file, such as a standard openrc file:
|
||||
|
||||
opts, err := openstack.AuthOptionsFromEnv()
|
||||
provider, err := openstack.AuthenticatedClient(opts)
|
||||
*/
|
||||
type AuthOptions struct {
|
||||
// IdentityEndpoint specifies the HTTP endpoint that is required to work with
|
||||
// the Identity API of the appropriate version. While it's ultimately needed by
|
||||
// all of the identity services, it will often be populated by a provider-level
|
||||
// function.
|
||||
//
|
||||
// The IdentityEndpoint is typically referred to as the "auth_url" or
|
||||
// "OS_AUTH_URL" in the information provided by the cloud operator.
|
||||
IdentityEndpoint string `json:"-"`
|
||||
|
||||
// Username is required if using Identity V2 API. Consult with your provider's
|
||||
// control panel to discover your account's username. In Identity V3, either
|
||||
// UserID or a combination of Username and DomainID or DomainName are needed.
|
||||
Username string `json:"username,omitempty"`
|
||||
UserID string `json:"-"`
|
||||
|
||||
Password string `json:"password,omitempty"`
|
||||
|
||||
// At most one of DomainID and DomainName must be provided if using Username
|
||||
// with Identity V3. Otherwise, either are optional.
|
||||
DomainID string `json:"-"`
|
||||
DomainName string `json:"name,omitempty"`
|
||||
|
||||
// The TenantID and TenantName fields are optional for the Identity V2 API.
|
||||
// The same fields are known as project_id and project_name in the Identity
|
||||
// V3 API, but are collected as TenantID and TenantName here in both cases.
|
||||
// Some providers allow you to specify a TenantName instead of the TenantId.
|
||||
// Some require both. Your provider's authentication policies will determine
|
||||
// how these fields influence authentication.
|
||||
// If DomainID or DomainName are provided, they will also apply to TenantName.
|
||||
// It is not currently possible to authenticate with Username and a Domain
|
||||
// and scope to a Project in a different Domain by using TenantName. To
|
||||
// accomplish that, the ProjectID will need to be provided as the TenantID
|
||||
// option.
|
||||
TenantID string `json:"tenantId,omitempty"`
|
||||
TenantName string `json:"tenantName,omitempty"`
|
||||
|
||||
// AllowReauth should be set to true if you grant permission for Gophercloud to
|
||||
// cache your credentials in memory, and to allow Gophercloud to attempt to
|
||||
// re-authenticate automatically if/when your token expires. If you set it to
|
||||
// false, it will not cache these settings, but re-authentication will not be
|
||||
// possible. This setting defaults to false.
|
||||
//
|
||||
// NOTE: The reauth function will try to re-authenticate endlessly if left
|
||||
// unchecked. The way to limit the number of attempts is to provide a custom
|
||||
// HTTP client to the provider client and provide a transport that implements
|
||||
// the RoundTripper interface and stores the number of failed retries. For an
|
||||
// example of this, see here:
|
||||
// https://github.com/rackspace/rack/blob/1.0.0/auth/clients.go#L311
|
||||
AllowReauth bool `json:"-"`
|
||||
|
||||
// TokenID allows users to authenticate (possibly as another user) with an
|
||||
// authentication token ID.
|
||||
TokenID string `json:"-"`
|
||||
}
|
||||
|
||||
// ToTokenV2CreateMap allows AuthOptions to satisfy the AuthOptionsBuilder
|
||||
// interface in the v2 tokens package
|
||||
func (opts AuthOptions) ToTokenV2CreateMap() (map[string]interface{}, error) {
|
||||
// Populate the request map.
|
||||
authMap := make(map[string]interface{})
|
||||
|
||||
if opts.Username != "" {
|
||||
if opts.Password != "" {
|
||||
authMap["passwordCredentials"] = map[string]interface{}{
|
||||
"username": opts.Username,
|
||||
"password": opts.Password,
|
||||
}
|
||||
} else {
|
||||
return nil, ErrMissingInput{Argument: "Password"}
|
||||
}
|
||||
} else if opts.TokenID != "" {
|
||||
authMap["token"] = map[string]interface{}{
|
||||
"id": opts.TokenID,
|
||||
}
|
||||
} else {
|
||||
return nil, ErrMissingInput{Argument: "Username"}
|
||||
}
|
||||
|
||||
if opts.TenantID != "" {
|
||||
authMap["tenantId"] = opts.TenantID
|
||||
}
|
||||
if opts.TenantName != "" {
|
||||
authMap["tenantName"] = opts.TenantName
|
||||
}
|
||||
|
||||
return map[string]interface{}{"auth": authMap}, nil
|
||||
}
|
||||
|
||||
func (opts *AuthOptions) ToTokenV3CreateMap(scope map[string]interface{}) (map[string]interface{}, error) {
|
||||
type domainReq struct {
|
||||
ID *string `json:"id,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
type projectReq struct {
|
||||
Domain *domainReq `json:"domain,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
ID *string `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
type userReq struct {
|
||||
ID *string `json:"id,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Password string `json:"password"`
|
||||
Domain *domainReq `json:"domain,omitempty"`
|
||||
}
|
||||
|
||||
type passwordReq struct {
|
||||
User userReq `json:"user"`
|
||||
}
|
||||
|
||||
type tokenReq struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
type identityReq struct {
|
||||
Methods []string `json:"methods"`
|
||||
Password *passwordReq `json:"password,omitempty"`
|
||||
Token *tokenReq `json:"token,omitempty"`
|
||||
}
|
||||
|
||||
type authReq struct {
|
||||
Identity identityReq `json:"identity"`
|
||||
}
|
||||
|
||||
type request struct {
|
||||
Auth authReq `json:"auth"`
|
||||
}
|
||||
|
||||
// Populate the request structure based on the provided arguments. Create and return an error
|
||||
// if insufficient or incompatible information is present.
|
||||
var req request
|
||||
|
||||
if opts.Password == "" {
|
||||
if opts.TokenID != "" {
|
||||
// Because we aren't using password authentication, it's an error to also provide any of the user-based authentication
|
||||
// parameters.
|
||||
if opts.Username != "" {
|
||||
return nil, ErrUsernameWithToken{}
|
||||
}
|
||||
if opts.UserID != "" {
|
||||
return nil, ErrUserIDWithToken{}
|
||||
}
|
||||
if opts.DomainID != "" {
|
||||
return nil, ErrDomainIDWithToken{}
|
||||
}
|
||||
if opts.DomainName != "" {
|
||||
return nil, ErrDomainNameWithToken{}
|
||||
}
|
||||
|
||||
// Configure the request for Token authentication.
|
||||
req.Auth.Identity.Methods = []string{"token"}
|
||||
req.Auth.Identity.Token = &tokenReq{
|
||||
ID: opts.TokenID,
|
||||
}
|
||||
} else {
|
||||
// If no password or token ID are available, authentication can't continue.
|
||||
return nil, ErrMissingPassword{}
|
||||
}
|
||||
} else {
|
||||
// Password authentication.
|
||||
req.Auth.Identity.Methods = []string{"password"}
|
||||
|
||||
// At least one of Username and UserID must be specified.
|
||||
if opts.Username == "" && opts.UserID == "" {
|
||||
return nil, ErrUsernameOrUserID{}
|
||||
}
|
||||
|
||||
if opts.Username != "" {
|
||||
// If Username is provided, UserID may not be provided.
|
||||
if opts.UserID != "" {
|
||||
return nil, ErrUsernameOrUserID{}
|
||||
}
|
||||
|
||||
// Either DomainID or DomainName must also be specified.
|
||||
if opts.DomainID == "" && opts.DomainName == "" {
|
||||
return nil, ErrDomainIDOrDomainName{}
|
||||
}
|
||||
|
||||
if opts.DomainID != "" {
|
||||
if opts.DomainName != "" {
|
||||
return nil, ErrDomainIDOrDomainName{}
|
||||
}
|
||||
|
||||
// Configure the request for Username and Password authentication with a DomainID.
|
||||
req.Auth.Identity.Password = &passwordReq{
|
||||
User: userReq{
|
||||
Name: &opts.Username,
|
||||
Password: opts.Password,
|
||||
Domain: &domainReq{ID: &opts.DomainID},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if opts.DomainName != "" {
|
||||
// Configure the request for Username and Password authentication with a DomainName.
|
||||
req.Auth.Identity.Password = &passwordReq{
|
||||
User: userReq{
|
||||
Name: &opts.Username,
|
||||
Password: opts.Password,
|
||||
Domain: &domainReq{Name: &opts.DomainName},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opts.UserID != "" {
|
||||
// If UserID is specified, neither DomainID nor DomainName may be.
|
||||
if opts.DomainID != "" {
|
||||
return nil, ErrDomainIDWithUserID{}
|
||||
}
|
||||
if opts.DomainName != "" {
|
||||
return nil, ErrDomainNameWithUserID{}
|
||||
}
|
||||
|
||||
// Configure the request for UserID and Password authentication.
|
||||
req.Auth.Identity.Password = &passwordReq{
|
||||
User: userReq{ID: &opts.UserID, Password: opts.Password},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
b, err := BuildRequestBody(req, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(scope) != 0 {
|
||||
b["auth"].(map[string]interface{})["scope"] = scope
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (opts *AuthOptions) ToTokenV3ScopeMap() (map[string]interface{}, error) {
|
||||
|
||||
var scope struct {
|
||||
ProjectID string
|
||||
ProjectName string
|
||||
DomainID string
|
||||
DomainName string
|
||||
}
|
||||
|
||||
if opts.TenantID != "" {
|
||||
scope.ProjectID = opts.TenantID
|
||||
} else {
|
||||
if opts.TenantName != "" {
|
||||
scope.ProjectName = opts.TenantName
|
||||
scope.DomainID = opts.DomainID
|
||||
scope.DomainName = opts.DomainName
|
||||
}
|
||||
}
|
||||
|
||||
if scope.ProjectName != "" {
|
||||
// ProjectName provided: either DomainID or DomainName must also be supplied.
|
||||
// ProjectID may not be supplied.
|
||||
if scope.DomainID == "" && scope.DomainName == "" {
|
||||
return nil, ErrScopeDomainIDOrDomainName{}
|
||||
}
|
||||
if scope.ProjectID != "" {
|
||||
return nil, ErrScopeProjectIDOrProjectName{}
|
||||
}
|
||||
|
||||
if scope.DomainID != "" {
|
||||
// ProjectName + DomainID
|
||||
return map[string]interface{}{
|
||||
"project": map[string]interface{}{
|
||||
"name": &scope.ProjectName,
|
||||
"domain": map[string]interface{}{"id": &scope.DomainID},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
if scope.DomainName != "" {
|
||||
// ProjectName + DomainName
|
||||
return map[string]interface{}{
|
||||
"project": map[string]interface{}{
|
||||
"name": &scope.ProjectName,
|
||||
"domain": map[string]interface{}{"name": &scope.DomainName},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
} else if scope.ProjectID != "" {
|
||||
// ProjectID provided. ProjectName, DomainID, and DomainName may not be provided.
|
||||
if scope.DomainID != "" {
|
||||
return nil, ErrScopeProjectIDAlone{}
|
||||
}
|
||||
if scope.DomainName != "" {
|
||||
return nil, ErrScopeProjectIDAlone{}
|
||||
}
|
||||
|
||||
// ProjectID
|
||||
return map[string]interface{}{
|
||||
"project": map[string]interface{}{
|
||||
"id": &scope.ProjectID,
|
||||
},
|
||||
}, nil
|
||||
} else if scope.DomainID != "" {
|
||||
// DomainID provided. ProjectID, ProjectName, and DomainName may not be provided.
|
||||
if scope.DomainName != "" {
|
||||
return nil, ErrScopeDomainIDOrDomainName{}
|
||||
}
|
||||
|
||||
// DomainID
|
||||
return map[string]interface{}{
|
||||
"domain": map[string]interface{}{
|
||||
"id": &scope.DomainID,
|
||||
},
|
||||
}, nil
|
||||
} else if scope.DomainName != "" {
|
||||
// DomainName
|
||||
return map[string]interface{}{
|
||||
"domain": map[string]interface{}{
|
||||
"name": &scope.DomainName,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (opts AuthOptions) CanReauth() bool {
|
||||
return opts.AllowReauth
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue