diff --git a/internal/openstack/client.go b/internal/openstack/client.go index 1541385..29784f7 100644 --- a/internal/openstack/client.go +++ b/internal/openstack/client.go @@ -22,6 +22,7 @@ import ( "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack" + "github.com/gophercloud/gophercloud/openstack/identity/v3/projects" "github.com/gophercloud/utils/openstack/clientconfig" netutil "k8s.io/apimachinery/pkg/util/net" @@ -144,10 +145,18 @@ func NewClient(cfg *AuthOpts) (*OpenStackClient, error) { return nil, err } + projectID := cfg.ProjectID + if projectID == "" { + projectID, err = getProjectID(provider, cfg) + if err != nil { + return nil, err + } + } + return &OpenStackClient{ provider: provider, region: cfg.Region, - projectID: cfg.ProjectID, + projectID: projectID, }, nil } @@ -156,3 +165,31 @@ func (client *OpenStackClient) NewNetworkV2() (*gophercloud.ServiceClient, error Region: client.region, }) } + +// Use the project name and project domain ID from the auth options to get the project ID. +func getProjectID(provider *gophercloud.ProviderClient, cfg *AuthOpts) (string, error) { + identityClient, err := openstack.NewIdentityV3(provider, gophercloud.EndpointOpts{Region: cfg.Region}) + if err != nil { + return "", err + } + + projectPage, err := projects.List( + identityClient, + projects.ListOpts{DomainID: cfg.ProjectDomainID, Name: cfg.ProjectName}, + ).AllPages() + if err != nil { + return "", err + } + + projectList, err := projects.ExtractProjects(projectPage) + if err != nil { + return "", err + } + + // Project names are unique within their domain, so there should never be more than one result. + if len(projectList) < 1 { + return "", fmt.Errorf("no project named %s in domain %s", cfg.ProjectName, cfg.DomainID) + } + + return projectList[0].ID, nil +}