diff --git a/Gopkg.lock b/Gopkg.lock index 96cd3e974c..d6a871cc07 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -246,11 +246,12 @@ revision = "3a7818a07cfc862267a0b03635075a444c92dcda" [[projects]] - digest = "1:df12b635fdefd90b1d139a70c45716896552051589b004021c745dcbaf0dad96" + branch = "master" + digest = "1:33e4f758f5c56c37064d7f11c8014e81faa7bcf47295bbda5158f7101f0b1d55" name = "github.com/gophercloud/utils" packages = ["openstack/clientconfig"] pruneopts = "NUT" - revision = "34f5991525d116b3832e0d9409492274f1c06bda" + revision = "3b35bcb43167f6d8080fa824c480f04b60311b51" [[projects]] branch = "master" diff --git a/Gopkg.toml b/Gopkg.toml index ec8c913372..8ace70325f 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -79,7 +79,7 @@ ignored = [ [[constraint]] name = "github.com/gophercloud/utils" - revision = "34f5991525d116b3832e0d9409492274f1c06bda" + branch = "master" [[constraint]] branch = "master" diff --git a/vendor/github.com/gophercloud/utils/openstack/clientconfig/requests.go b/vendor/github.com/gophercloud/utils/openstack/clientconfig/requests.go index 4b38c7a815..007939013b 100644 --- a/vendor/github.com/gophercloud/utils/openstack/clientconfig/requests.go +++ b/vendor/github.com/gophercloud/utils/openstack/clientconfig/requests.go @@ -9,7 +9,7 @@ import ( "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack" - "gopkg.in/yaml.v2" + yaml "gopkg.in/yaml.v2" ) // AuthType respresents a valid method of authentication. @@ -30,6 +30,9 @@ const ( AuthV3Password AuthType = "v3password" // AuthV3Token defines version 3 of the token AuthV3Token AuthType = "v3token" + + // AuthV3ApplicationCredential defines version 3 of the application credential + AuthV3ApplicationCredential AuthType = "v3applicationcredential" ) // ClientOpts represents options to customize the way a client is @@ -333,6 +336,8 @@ func determineIdentityAPI(cloud *Cloud, opts *ClientOpts) string { identityAPI = "3" case AuthV3Token: identityAPI = "3" + case AuthV3ApplicationCredential: + identityAPI = "3" } } @@ -517,41 +522,65 @@ func v3auth(cloud *Cloud, opts *ClientOpts) (*gophercloud.AuthOptions, error) { } } + if cloud.AuthInfo.ApplicationCredentialID == "" { + if v := os.Getenv(envPrefix + "APPLICATION_CREDENTIAL_ID"); v != "" { + cloud.AuthInfo.ApplicationCredentialID = v + } + } + + if cloud.AuthInfo.ApplicationCredentialName == "" { + if v := os.Getenv(envPrefix + "APPLICATION_CREDENTIAL_NAME"); v != "" { + cloud.AuthInfo.ApplicationCredentialName = v + } + } + + if cloud.AuthInfo.ApplicationCredentialSecret == "" { + if v := os.Getenv(envPrefix + "APPLICATION_CREDENTIAL_SECRET"); v != "" { + cloud.AuthInfo.ApplicationCredentialSecret = v + } + } + // Build a scope and try to do it correctly. // https://github.com/openstack/os-client-config/blob/master/os_client_config/config.py#L595 scope := new(gophercloud.AuthScope) - if !isProjectScoped(cloud.AuthInfo) { - if cloud.AuthInfo.DomainID != "" { - scope.DomainID = cloud.AuthInfo.DomainID - } else if cloud.AuthInfo.DomainName != "" { - scope.DomainName = cloud.AuthInfo.DomainName - } - } else { - // If Domain* is set, but UserDomain* or ProjectDomain* aren't, - // then use Domain* as the default setting. - cloud = setDomainIfNeeded(cloud) - - if cloud.AuthInfo.ProjectID != "" { - scope.ProjectID = cloud.AuthInfo.ProjectID + // Application credentials don't support scope + if !isApplicationCredential(cloud.AuthInfo) { + if !isProjectScoped(cloud.AuthInfo) { + if cloud.AuthInfo.DomainID != "" { + scope.DomainID = cloud.AuthInfo.DomainID + } else if cloud.AuthInfo.DomainName != "" { + scope.DomainName = cloud.AuthInfo.DomainName + } } else { - scope.ProjectName = cloud.AuthInfo.ProjectName - scope.DomainID = cloud.AuthInfo.ProjectDomainID - scope.DomainName = cloud.AuthInfo.ProjectDomainName + // If Domain* is set, but UserDomain* or ProjectDomain* aren't, + // then use Domain* as the default setting. + cloud = setDomainIfNeeded(cloud) + + if cloud.AuthInfo.ProjectID != "" { + scope.ProjectID = cloud.AuthInfo.ProjectID + } else { + scope.ProjectName = cloud.AuthInfo.ProjectName + scope.DomainID = cloud.AuthInfo.ProjectDomainID + scope.DomainName = cloud.AuthInfo.ProjectDomainName + } } } ao := &gophercloud.AuthOptions{ - Scope: scope, - IdentityEndpoint: cloud.AuthInfo.AuthURL, - TokenID: cloud.AuthInfo.Token, - Username: cloud.AuthInfo.Username, - UserID: cloud.AuthInfo.UserID, - Password: cloud.AuthInfo.Password, - TenantID: cloud.AuthInfo.ProjectID, - TenantName: cloud.AuthInfo.ProjectName, - DomainID: cloud.AuthInfo.UserDomainID, - DomainName: cloud.AuthInfo.UserDomainName, + Scope: scope, + IdentityEndpoint: cloud.AuthInfo.AuthURL, + TokenID: cloud.AuthInfo.Token, + Username: cloud.AuthInfo.Username, + UserID: cloud.AuthInfo.UserID, + Password: cloud.AuthInfo.Password, + TenantID: cloud.AuthInfo.ProjectID, + TenantName: cloud.AuthInfo.ProjectName, + DomainID: cloud.AuthInfo.UserDomainID, + DomainName: cloud.AuthInfo.UserDomainName, + ApplicationCredentialID: cloud.AuthInfo.ApplicationCredentialID, + ApplicationCredentialName: cloud.AuthInfo.ApplicationCredentialName, + ApplicationCredentialSecret: cloud.AuthInfo.ApplicationCredentialSecret, } // If an auth_type of "token" was specified, then make sure @@ -761,3 +790,11 @@ func setDomainIfNeeded(cloud *Cloud) *Cloud { return cloud } + +// isApplicationCredential determines if an application credential is used to auth. +func isApplicationCredential(authInfo *AuthInfo) bool { + if authInfo.ApplicationCredentialID == "" && authInfo.ApplicationCredentialName == "" && authInfo.ApplicationCredentialSecret == "" { + return false + } + return true +} diff --git a/vendor/github.com/gophercloud/utils/openstack/clientconfig/results.go b/vendor/github.com/gophercloud/utils/openstack/clientconfig/results.go index b49367c3c2..292ff5dc48 100644 --- a/vendor/github.com/gophercloud/utils/openstack/clientconfig/results.go +++ b/vendor/github.com/gophercloud/utils/openstack/clientconfig/results.go @@ -4,109 +4,118 @@ package clientconfig // The format of the clouds-public.yml is documented at // https://docs.openstack.org/python-openstackclient/latest/configuration/ type PublicClouds struct { - Clouds map[string]Cloud `yaml:"public-clouds"` + Clouds map[string]Cloud `yaml:"public-clouds" json:"public-clouds"` } // Clouds represents a collection of Cloud entries in a clouds.yaml file. // The format of clouds.yaml is documented at // https://docs.openstack.org/os-client-config/latest/user/configuration.html. type Clouds struct { - Clouds map[string]Cloud `yaml:"clouds"` + Clouds map[string]Cloud `yaml:"clouds" json:"clouds"` } // Cloud represents an entry in a clouds.yaml/public-clouds.yaml/secure.yaml file. type Cloud struct { - Cloud string `yaml:"cloud"` - Profile string `yaml:"profile"` - AuthInfo *AuthInfo `yaml:"auth"` - AuthType AuthType `yaml:"auth_type"` - RegionName string `yaml:"region_name"` - Regions []interface{} `yaml:"regions"` + Cloud string `yaml:"cloud" json:"cloud"` + Profile string `yaml:"profile" json:"profile"` + AuthInfo *AuthInfo `yaml:"auth" json:"auth"` + AuthType AuthType `yaml:"auth_type" json:"auth_type"` + RegionName string `yaml:"region_name" json:"region_name"` + Regions []interface{} `yaml:"regions" json:"regions"` // API Version overrides. - IdentityAPIVersion string `yaml:"identity_api_version"` - VolumeAPIVersion string `yaml:"volume_api_version"` + IdentityAPIVersion string `yaml:"identity_api_version" json:"identity_api_version"` + VolumeAPIVersion string `yaml:"volume_api_version" json:"volume_api_version"` // Verify whether or not SSL API requests should be verified. - Verify *bool `yaml:"verify"` + Verify *bool `yaml:"verify" json:"verify"` // CACertFile a path to a CA Cert bundle that can be used as part of // verifying SSL API requests. - CACertFile string `yaml:"cacert"` + CACertFile string `yaml:"cacert" json:"cacert"` // ClientCertFile a path to a client certificate to use as part of the SSL // transaction. - ClientCertFile string `yaml:"cert"` + ClientCertFile string `yaml:"cert" json:"cert"` // ClientKeyFile a path to a client key to use as part of the SSL // transaction. - ClientKeyFile string `yaml:"key"` + ClientKeyFile string `yaml:"key" json:"key"` } // AuthInfo represents the auth section of a cloud entry or // auth options entered explicitly in ClientOpts. type AuthInfo struct { // AuthURL is the keystone/identity endpoint URL. - AuthURL string `yaml:"auth_url"` + AuthURL string `yaml:"auth_url" json:"auth_url"` // Token is a pre-generated authentication token. - Token string `yaml:"token"` + Token string `yaml:"token" json:"token"` // Username is the username of the user. - Username string `yaml:"username"` + Username string `yaml:"username" json:"username"` // UserID is the unique ID of a user. - UserID string `yaml:"user_id"` + UserID string `yaml:"user_id" json:"user_id"` // Password is the password of the user. - Password string `yaml:"password"` + Password string `yaml:"password" json:"password"` + + // Application Credential ID to login with. + ApplicationCredentialID string `yaml:"application_credential_id" json:"application_credential_id"` + + // Application Credential name to login with. + ApplicationCredentialName string `yaml:"application_credential_name" json:"application_credential_name"` + + // Application Credential secret to login with. + ApplicationCredentialSecret string `yaml:"application_credential_secret" json:"application_credential_secret"` // ProjectName is the common/human-readable name of a project. // Users can be scoped to a project. // ProjectName on its own is not enough to ensure a unique scope. It must // also be combined with either a ProjectDomainName or ProjectDomainID. // ProjectName cannot be combined with ProjectID in a scope. - ProjectName string `yaml:"project_name"` + ProjectName string `yaml:"project_name" json:"project_name"` // ProjectID is the unique ID of a project. // It can be used to scope a user to a specific project. - ProjectID string `yaml:"project_id"` + ProjectID string `yaml:"project_id" json:"project_id"` // UserDomainName is the name of the domain where a user resides. // It is used to identify the source domain of a user. - UserDomainName string `yaml:"user_domain_name"` + UserDomainName string `yaml:"user_domain_name" json:"user_domain_name"` // UserDomainID is the unique ID of the domain where a user resides. // It is used to identify the source domain of a user. - UserDomainID string `yaml:"user_domain_id"` + UserDomainID string `yaml:"user_domain_id" json:"user_domain_id"` // ProjectDomainName is the name of the domain where a project resides. // It is used to identify the source domain of a project. // ProjectDomainName can be used in addition to a ProjectName when scoping // a user to a specific project. - ProjectDomainName string `yaml:"project_domain_name"` + ProjectDomainName string `yaml:"project_domain_name" json:"project_domain_name"` // ProjectDomainID is the name of the domain where a project resides. // It is used to identify the source domain of a project. // ProjectDomainID can be used in addition to a ProjectName when scoping // a user to a specific project. - ProjectDomainID string `yaml:"project_domain_id"` + ProjectDomainID string `yaml:"project_domain_id" json:"project_domain_id"` // DomainName is the name of a domain which can be used to identify the // source domain of either a user or a project. // If UserDomainName and ProjectDomainName are not specified, then DomainName // is used as a default choice. // It can also be used be used to specify a domain-only scope. - DomainName string `yaml:"domain_name"` + DomainName string `yaml:"domain_name" json:"domain_name"` // DomainID is the unique ID of a domain which can be used to identify the // source domain of eitehr a user or a project. // If UserDomainID and ProjectDomainID are not specified, then DomainID is // used as a default choice. // It can also be used be used to specify a domain-only scope. - DomainID string `yaml:"domain_id"` + DomainID string `yaml:"domain_id" json:"domain_id"` // DefaultDomain is the domain ID to fall back on if no other domain has // been specified and a domain is required for scope. - DefaultDomain string `yaml:"default_domain"` + DefaultDomain string `yaml:"default_domain" json:"default_domain"` }