|
|
|
|
@ -7,6 +7,7 @@ package api
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"log"
|
|
|
|
|
"net/http"
|
|
|
|
|
"os"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
@ -44,39 +45,67 @@ func NewClient() (*Client, error) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cl, err := httpclient.New(httpclient.Config{
|
|
|
|
|
hcpClientCfg := httpclient.Config{
|
|
|
|
|
SourceChannel: fmt.Sprintf("packer/%s", version.PackerVersion.FormattedVersion()),
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
}
|
|
|
|
|
if err := hcpClientCfg.Canonicalize(); err != nil {
|
|
|
|
|
return nil, &ClientError{
|
|
|
|
|
StatusCode: InvalidClientConfig,
|
|
|
|
|
Err: err,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cl, err := httpclient.New(hcpClientCfg)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, &ClientError{
|
|
|
|
|
StatusCode: InvalidClientConfig,
|
|
|
|
|
Err: err,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
client := &Client{
|
|
|
|
|
Packer: packerSvc.New(cl, nil),
|
|
|
|
|
Organization: organizationSvc.New(cl, nil),
|
|
|
|
|
Project: projectSvc.New(cl, nil),
|
|
|
|
|
}
|
|
|
|
|
//if both HCP_ORGANIZATION_ID and HCP_PROJECT_ID are set via env variables the hcpConfig may have all we need already.
|
|
|
|
|
if hcpClientCfg.Profile().OrganizationID != "" && hcpClientCfg.Profile().ProjectID != "" {
|
|
|
|
|
client.OrganizationID = hcpClientCfg.Profile().OrganizationID
|
|
|
|
|
client.ProjectID = hcpClientCfg.Profile().ProjectID
|
|
|
|
|
|
|
|
|
|
if err := client.loadOrganizationID(); err != nil {
|
|
|
|
|
return nil, &ClientError{
|
|
|
|
|
StatusCode: InvalidClientConfig,
|
|
|
|
|
Err: err,
|
|
|
|
|
}
|
|
|
|
|
return client, nil
|
|
|
|
|
}
|
|
|
|
|
if err := client.loadProjectID(); err != nil {
|
|
|
|
|
return nil, &ClientError{
|
|
|
|
|
StatusCode: InvalidClientConfig,
|
|
|
|
|
Err: err,
|
|
|
|
|
|
|
|
|
|
if client.OrganizationID == "" {
|
|
|
|
|
err := client.loadOrganizationID()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, &ClientError{
|
|
|
|
|
StatusCode: InvalidClientConfig,
|
|
|
|
|
Err: err,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if client.ProjectID == "" {
|
|
|
|
|
err := client.loadProjectID()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, &ClientError{
|
|
|
|
|
StatusCode: InvalidClientConfig,
|
|
|
|
|
Err: err,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return client, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *Client) loadOrganizationID() error {
|
|
|
|
|
if c.OrganizationID != "" {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if env.HasOrganizationID() {
|
|
|
|
|
c.OrganizationID = os.Getenv(env.HCPOrganizationID)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
// Get the organization ID.
|
|
|
|
|
listOrgParams := organizationSvc.NewOrganizationServiceListParams()
|
|
|
|
|
listOrgResp, err := c.Organization.OrganizationServiceList(listOrgParams, nil)
|
|
|
|
|
@ -92,55 +121,62 @@ func (c *Client) loadOrganizationID() error {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *Client) loadProjectID() error {
|
|
|
|
|
if c.ProjectID != "" {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
if env.HasProjectID() {
|
|
|
|
|
c.ProjectID = os.Getenv(env.HCPProjectID)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
// Get the project using the organization ID.
|
|
|
|
|
listProjParams := projectSvc.NewProjectServiceListParams()
|
|
|
|
|
listProjParams.ScopeID = &c.OrganizationID
|
|
|
|
|
scopeType := string(rmmodels.HashicorpCloudResourcemanagerResourceIDResourceTypeORGANIZATION)
|
|
|
|
|
listProjParams.ScopeType = &scopeType
|
|
|
|
|
listProjResp, err := c.Project.ProjectServiceList(listProjParams, nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("unable to fetch project id: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if env.HasProjectID() {
|
|
|
|
|
proj, err := findProjectByID(os.Getenv(env.HCPProjectID), listProjResp.Payload.Projects)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.ProjectID = proj.ID
|
|
|
|
|
} else {
|
|
|
|
|
if len(listProjResp.Payload.Projects) > 1 {
|
|
|
|
|
log.Printf("[WARNING] Multiple HCP projects found, will pick the oldest one by default\n" +
|
|
|
|
|
"To specify which project to use, set the HCP_PROJECT_ID environment variable to the one you want to use.")
|
|
|
|
|
if err != nil {
|
|
|
|
|
//For permission errors our service principle may not have the perms
|
|
|
|
|
// to see all projects for an Org; this is the case for project-level service principles.
|
|
|
|
|
serviceErr, ok := err.(*projectSvc.ProjectServiceListDefault)
|
|
|
|
|
if !ok {
|
|
|
|
|
return fmt.Errorf("unable to fetch project list: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proj, err := findOldestProject(listProjResp.Payload.Projects)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
if serviceErr.Code() == http.StatusForbidden {
|
|
|
|
|
return fmt.Errorf("unable to fetch project\n\n"+
|
|
|
|
|
"If the provided credentials are tied to a specific project trying setting the %s environment variable to one you want to use.", env.HCPProjectID)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.ProjectID = proj.ID
|
|
|
|
|
if len(listProjResp.Payload.Projects) > 1 {
|
|
|
|
|
log.Printf("[WARNING] Multiple HCP projects found, will pick the oldest one by default\n"+
|
|
|
|
|
"To specify which project to use, set the %s environment variable to the one you want to use.", env.HCPProjectID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proj, err := getOldestProject(listProjResp.Payload.Projects)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
c.ProjectID = proj.ID
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func findOldestProject(projs []*models.HashicorpCloudResourcemanagerProject) (*models.HashicorpCloudResourcemanagerProject, error) {
|
|
|
|
|
if len(projs) == 0 {
|
|
|
|
|
// getOldestProject retrieves the oldest project from a list based on its created_at time.
|
|
|
|
|
func getOldestProject(projects []*models.HashicorpCloudResourcemanagerProject) (*models.HashicorpCloudResourcemanagerProject, error) {
|
|
|
|
|
if len(projects) == 0 {
|
|
|
|
|
return nil, fmt.Errorf("no project found")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proj := projs[0]
|
|
|
|
|
for i := 1; i < len(projs); i++ {
|
|
|
|
|
nxtProj := projs[i]
|
|
|
|
|
|
|
|
|
|
if time.Time(nxtProj.CreatedAt).Before(time.Time(proj.CreatedAt)) {
|
|
|
|
|
proj = nxtProj
|
|
|
|
|
oldestTime := time.Now()
|
|
|
|
|
var oldestProj *models.HashicorpCloudResourcemanagerProject
|
|
|
|
|
for _, proj := range projects {
|
|
|
|
|
projTime := time.Time(proj.CreatedAt)
|
|
|
|
|
if projTime.Before(oldestTime) {
|
|
|
|
|
oldestProj = proj
|
|
|
|
|
oldestTime = projTime
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return proj, nil
|
|
|
|
|
return oldestProj, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func findProjectByID(projID string, projs []*models.HashicorpCloudResourcemanagerProject) (*models.HashicorpCloudResourcemanagerProject, error) {
|
|
|
|
|
|