From 7bc320ee66900b2436258ec13a730aeca85b11fd Mon Sep 17 00:00:00 2001 From: Glenn Sarti Date: Thu, 1 Aug 2024 10:49:28 +0800 Subject: [PATCH] Update Org and Run Tasks for Private Run Tasks This commit updates the Org. entitlements for the new Private Run Tasks feature. This commit also updates the Run Task options struct for CRUD operations to pass through the agent pool relationship --- CHANGELOG.md | 5 +++ organization.go | 1 + run_task.go | 9 ++++ run_task_integration_test.go | 79 +++++++++++++++++++++++++++++++++--- task_result.go | 1 + 5 files changed, 89 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a508b3d1..1cd3ad285 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # UNRELEASED + +## Enhancements + * Adds `AllowMemberTokenManagement` permission to `Team` by @juliannatetreault [#922](https://github.com/hashicorp/go-tfe/pull/922) +* Adds `PrivateRunTasks` field to Entitlements by @glennsarti [#944](https://github.com/hashicorp/go-tfe/pull/944) +* Adds `AgentPool` relationship to options when creating and updating Run Tasks by @glennsarti [#944](https://github.com/hashicorp/go-tfe/pull/944) # v1.61.0 diff --git a/organization.go b/organization.go index 86a97515e..e25fa0cee 100644 --- a/organization.go +++ b/organization.go @@ -164,6 +164,7 @@ type Entitlements struct { GlobalRunTasks bool `jsonapi:"attr,global-run-tasks"` Operations bool `jsonapi:"attr,operations"` PrivateModuleRegistry bool `jsonapi:"attr,private-module-registry"` + PrivateRunTasks bool `jsonapi:"attr,private-run-tasks"` RunTasks bool `jsonapi:"attr,run-tasks"` SSO bool `jsonapi:"attr,sso"` Sentinel bool `jsonapi:"attr,sentinel"` diff --git a/run_task.go b/run_task.go index 3f7edb0a4..22fb79d1a 100644 --- a/run_task.go +++ b/run_task.go @@ -54,6 +54,7 @@ type RunTask struct { Enabled bool `jsonapi:"attr,enabled"` Global *GlobalRunTask `jsonapi:"attr,global-configuration,omitempty"` + AgentPool *AgentPool `jsonapi:"relation,agent-pool"` Organization *Organization `jsonapi:"relation,organization"` WorkspaceRunTasks []*WorkspaceRunTask `jsonapi:"relation,workspace-tasks"` } @@ -130,6 +131,10 @@ type RunTaskCreateOptions struct { // Optional: Whether the task contains global configuration Global *GlobalRunTaskOptions `jsonapi:"attr,global-configuration,omitempty"` + + // Optional: Whether the task will be executed using an Agent Pool + // Requires the PrivateRunTasks entitlement + AgentPool *AgentPool `jsonapi:"relation,agent-pool,omitempty"` } // RunTaskUpdateOptions represents the set of options for updating an organization's run task @@ -160,6 +165,10 @@ type RunTaskUpdateOptions struct { // Optional: Whether the task contains global configuration Global *GlobalRunTaskOptions `jsonapi:"attr,global-configuration,omitempty"` + + // Optional: Whether the task will be executed using an Agent Pool + // Requires the PrivateRunTasks entitlement + AgentPool *AgentPool `jsonapi:"relation,agent-pool,omitempty"` } // Create is used to create a new run task for an organization diff --git a/run_task_integration_test.go b/run_task_integration_test.go index ba1811cfb..26c878e91 100644 --- a/run_task_integration_test.go +++ b/run_task_integration_test.go @@ -13,15 +13,32 @@ import ( "github.com/stretchr/testify/require" ) -func hasGlobalRunTasks(client *Client, organizationName string) (bool, error) { +func getOrgEntitlements(client *Client, organizationName string) (*Entitlements, error) { ctx := context.Background() - if orgEntitlements, err := client.Organizations.ReadEntitlements(ctx, organizationName); err != nil { + orgEntitlements, err := client.Organizations.ReadEntitlements(ctx, organizationName) + if err != nil { + return nil, err + } + if orgEntitlements == nil { + return nil, errors.New("The organization entitlements are empty.") + } + return orgEntitlements, nil +} + +func hasGlobalRunTasks(client *Client, organizationName string) (bool, error) { + oe, err := getOrgEntitlements(client, organizationName) + if err != nil { return false, err - } else if orgEntitlements == nil { - return false, errors.New("The organization entitlements are empty.") - } else { - return orgEntitlements.GlobalRunTasks, nil } + return oe.GlobalRunTasks, nil +} + +func hasPrivateRunTasks(client *Client, organizationName string) (bool, error) { + oe, err := getOrgEntitlements(client, organizationName) + if err != nil { + return false, err + } + return oe.PrivateRunTasks, nil } func TestRunTasksCreate(t *testing.T) { @@ -54,6 +71,33 @@ func TestRunTasksCreate(t *testing.T) { } globalEnforce := Mandatory + t.Run("with an agent pool", func(t *testing.T) { + // We can only test if the org, supports private run tasks. For now this isn't + // a fatal error and we just skip the test. + if v, err := hasPrivateRunTasks(client, orgTest.Name); err != nil { + t.Fatalf("Could not retrieve the entitlements for the test organization.: %s", err) + } else if !v { + t.Skip("The test organization requires the private-run-tasks entitlement but is not entitled.") + return + } + + // Unfortunately when we create a Run Task it automatically verifies that the URL by sending a test payload. But + // this means with an agent pool, we need an agent pool to exist, and an agent created with request forwarding enabled. + // This is too much to create for this one test suite. So instead, we really only need to assert that; when the options include an + // agent pool, then we expect HCP Terraform to process the agent pool. So, if we send it a nonsense agent pool ID, then we + // expect an error to be returned saying that the ID was nonsense. + _, err := client.RunTasks.Create(ctx, orgTest.Name, RunTaskCreateOptions{ + Name: runTaskName, + URL: runTaskServerURL, + Description: &runTaskDescription, + Category: "task", + AgentPool: &AgentPool{ + ID: "apool-this-pool-id-will-never-exist-so-we-expect-http-error-response", + }, + }) + require.ErrorContains(t, err, "The provided agent pool does not exist") + }) + t.Run("add run task to organization", func(t *testing.T) { r, err := client.RunTasks.Create(ctx, orgTest.Name, RunTaskCreateOptions{ Name: runTaskName, @@ -262,6 +306,29 @@ func TestRunTasksUpdate(t *testing.T) { assert.Equal(t, newDescription, r.Description) }) + + t.Run("with an agent pool", func(t *testing.T) { + // We can only test if the org, supports private run tasks. For now this isn't + // a fatal error and we just skip the test. + if v, err := hasPrivateRunTasks(client, orgTest.Name); err != nil { + t.Fatalf("Could not retrieve the entitlements for the test organization.: %s", err) + } else if !v { + t.Skip("The test organization requires the private-run-tasks entitlement but is not entitled.") + return + } + + // Unfortunately when we update a Run Task it automatically verifies that the URL by sending a test payload. But + // this means with an agent pool, we need an agent pool to exist, and an agent created with request forwarding enabled. + // This is too much to create for this one test suite. So instead, we really only need to assert that; when the options include an + // agent pool, then we expect HCP Terraform to process the agent pool. So, if we send it a nonsense agent pool ID, then we + // expect an error to be returned saying that the ID was nonsense. + _, err := client.RunTasks.Update(ctx, runTaskTest.ID, RunTaskUpdateOptions{ + AgentPool: &AgentPool{ + ID: "apool-this-pool-id-will-never-exist-so-we-expect-http-error-response", + }, + }) + require.ErrorContains(t, err, "The provided agent pool does not exist") + }) } func TestRunTasksDelete(t *testing.T) { diff --git a/task_result.go b/task_result.go index f60bacd9b..6cb7d874a 100644 --- a/task_result.go +++ b/task_result.go @@ -66,6 +66,7 @@ type TaskResult struct { TaskURL string `jsonapi:"attr,task-url"` WorkspaceTaskID string `jsonapi:"attr,workspace-task-id"` WorkspaceTaskEnforcementLevel TaskEnforcementLevel `jsonapi:"attr,workspace-task-enforcement-level"` + AgentPoolID *string `jsonapi:"attr,agent-pool-id,omitempty"` // The task stage this result belongs to TaskStage *TaskStage `jsonapi:"relation,task_stage"`