From 1f2d2948f72f547a6c6cdb22635b052827361456 Mon Sep 17 00:00:00 2001 From: HenryEstberg <11286201+HenryEstberg@users.noreply.github.com> Date: Thu, 29 May 2025 16:15:05 -0700 Subject: [PATCH 1/9] First draft of adding agent flavored action support to the provider --- .../waypoint/data_source_waypoint_action.go | 54 +++++--- .../data_source_waypoint_action_test.go | 30 +++- .../waypoint/resource_waypoint_action.go | 130 ++++++++++++++++++ .../waypoint/resource_waypoint_action_test.go | 32 +++++ 4 files changed, 223 insertions(+), 23 deletions(-) diff --git a/internal/provider/waypoint/data_source_waypoint_action.go b/internal/provider/waypoint/data_source_waypoint_action.go index 27d0383f8..2e11fd707 100644 --- a/internal/provider/waypoint/data_source_waypoint_action.go +++ b/internal/provider/waypoint/data_source_waypoint_action.go @@ -96,6 +96,28 @@ func (d *DataSourceAction) Schema(ctx context.Context, req datasource.SchemaRequ }, }, }, + "agent": schema.SingleNestedAttribute{ + Description: "Agent mode allows users to define the agent to use for the request.", + Optional: true, + Attributes: map[string]schema.Attribute{ + "operation_id": schema.StringAttribute{ + Description: "The identifying name of the operation in the agent config file.", + Required: true, + }, + "body": schema.StringAttribute{ + Description: "Arguments to the operation, specified as JSON.", + Optional: true, + }, + "action_run_id": schema.StringAttribute{ + Description: "An optional action run id. If specified the agent will interact with the actions subsystem.", + Optional: true, + }, + "group": schema.StringAttribute{ + Description: "The name of the group that the operation is in.", + Required: true, + }, + }, + }, }, }, }, @@ -119,7 +141,7 @@ func (d *DataSourceAction) Configure(ctx context.Context, req datasource.Configu } func (d *DataSourceAction) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data ActionResourceModel + var data *ActionResourceModel resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) @@ -159,36 +181,24 @@ func (d *DataSourceAction) Read(ctx context.Context, req datasource.ReadRequest, data.ProjectID = types.StringValue(client.Config.ProjectID) data.Request = &actionRequest{} - headerMap := make(map[string]string) var diags diag.Diagnostics // In the future, expand this to accommodate other types of requests - data.Request.Custom = &customRequest{} - if actionModel.Request.Custom.Method != nil { - data.Request.Custom.Method = types.StringValue(string(*actionModel.Request.Custom.Method)) - } else { - data.Request.Custom.Method = types.StringNull() - } - if actionModel.Request.Custom.Headers != nil { - for _, header := range actionModel.Request.Custom.Headers { - headerMap[header.Key] = header.Value + if actionModel.Request.Custom != nil { + diags = readCustomAction(ctx, data, actionModel) + if diags.HasError() { + resp.Diagnostics.Append(diags...) + return } - if len(headerMap) > 0 { - data.Request.Custom.Headers, diags = types.MapValueFrom(ctx, types.StringType, headerMap) + } else if actionModel.Request.Agent != nil { + diags = readAgentAction(ctx, data, actionModel) + if diags.HasError() { resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } - } else { - data.Request.Custom.Headers = types.MapNull(types.StringType) + return } - } else { - data.Request.Custom.Headers = types.MapNull(types.StringType) } - data.Request.Custom.URL = types.StringValue(actionModel.Request.Custom.URL) - data.Request.Custom.Body = types.StringValue(actionModel.Request.Custom.Body) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } diff --git a/internal/provider/waypoint/data_source_waypoint_action_test.go b/internal/provider/waypoint/data_source_waypoint_action_test.go index 7a5c4a0db..f34aaed44 100644 --- a/internal/provider/waypoint/data_source_waypoint_action_test.go +++ b/internal/provider/waypoint/data_source_waypoint_action_test.go @@ -49,12 +49,40 @@ func TestAcc_Waypoint_Action_DataSource_basic(t *testing.T) { }, }, }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, + CheckDestroy: testAccCheckWaypointActionDestroy(t, &actionModel), + Steps: []resource.TestStep{ + { + // establish the base action config with agent + Config: testAgentAction(actionName), + Check: resource.ComposeTestCheckFunc( + testAccCheckWaypointActionExists(t, resourceName, &actionModel), + ), + }, + { + // add a data source config to read the action config with agent + Config: testDataActionConfigAgent(actionName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "name", actionName), + ), + }, + }, + }) } func testDataActionConfig(actionName string) string { return fmt.Sprintf(`%s - data "hcp_waypoint_action" "test" { name = hcp_waypoint_action.test.name }`, testAction(actionName)) } + +func testDataActionConfigAgent(actionName string) string { + return fmt.Sprintf(`%s +data "hcp_waypoint_action" "test" { + name = hcp_waypoint_action.test.name +}`, testAgentAction(actionName)) +} diff --git a/internal/provider/waypoint/resource_waypoint_action.go b/internal/provider/waypoint/resource_waypoint_action.go index 5d2c2da71..e116e4d30 100644 --- a/internal/provider/waypoint/resource_waypoint_action.go +++ b/internal/provider/waypoint/resource_waypoint_action.go @@ -5,6 +5,7 @@ package waypoint import ( "context" + "encoding/base64" "fmt" sharedmodels "github.com/hashicorp/hcp-sdk-go/clients/cloud-shared/v1/models" @@ -46,6 +47,7 @@ type ActionResourceModel struct { type actionRequest struct { Custom *customRequest `tfsdk:"custom"` + Agent *agentRequest `tfsdk:"agent"` } type customRequest struct { @@ -55,6 +57,13 @@ type customRequest struct { Body types.String `tfsdk:"body"` } +type agentRequest struct { + OperationID types.String `tfsdk:"operation_id"` + Body types.String `tfsdk:"body"` + ActionRunID types.String `tfsdk:"action_run_id"` + Group types.String `tfsdk:"group"` +} + func (r *ActionResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_waypoint_action" } @@ -117,6 +126,28 @@ func (r *ActionResource) Schema(ctx context.Context, req resource.SchemaRequest, }, }, }, + "agent": schema.SingleNestedAttribute{ + Description: "Agent mode allows users to define the agent to use for the request.", + Optional: true, + Attributes: map[string]schema.Attribute{ + "operation_id": schema.StringAttribute{ + Description: "The identifying name of the operation in the agent config file.", + Required: true, + }, + "body": schema.StringAttribute{ + Description: "Arguments to the operation, specified as JSON.", + Optional: true, + }, + "action_run_id": schema.StringAttribute{ + Description: "An optional action run id. If specified the agent will interact with the actions subsystem.", + Optional: true, + }, + "group": schema.StringAttribute{ + Description: "The name of the group that the operation is in.", + Required: true, + }, + }, + }, }, }, }, @@ -171,8 +202,11 @@ func (r *ActionResource) Create(ctx context.Context, req resource.CreateRequest, modelBody.ActionConfig.Description = plan.Description.ValueString() } + // TODO(henry): Error here if multiple request types are set? + var diags diag.Diagnostics + // TODO(henry): The following code is very similar to the Update method, consider refactoring to a common function // This is a proxy for the request type, as Custom.Method is required for Custom requests if !plan.Request.Custom.Method.IsUnknown() && !plan.Request.Custom.Method.IsNull() { modelBody.ActionConfig.Request.Custom = &waypoint_models.HashicorpCloudWaypointV20241122ActionConfigFlavorCustom{} @@ -201,6 +235,29 @@ func (r *ActionResource) Create(ctx context.Context, req resource.CreateRequest, modelBody.ActionConfig.Request.Custom.Body = plan.Request.Custom.Body.ValueString() } + } else if !plan.Request.Agent.OperationID.IsUnknown() && !plan.Request.Agent.OperationID.IsNull() { + modelBody.ActionConfig.Request.Agent = &waypoint_models.HashicorpCloudWaypointV20241122ActionConfigFlavorAgent{} + + modelBody.ActionConfig.Request.Agent.Op.ID = plan.Request.Agent.OperationID.ValueString() + modelBody.ActionConfig.Request.Agent.Op.Group = plan.Request.Agent.Group.ValueString() + + if !plan.Request.Agent.Body.IsUnknown() && !plan.Request.Agent.Body.IsNull() { + // The body is expected to be a base64 encoded string, so we decode it + bodyBytes, err := base64.StdEncoding.DecodeString(plan.Request.Agent.Body.ValueString()) + // If there is an error, we immediately return an error to the user + if err != nil { + resp.Diagnostics.AddError( + "Error decoding Agent Body", + fmt.Sprintf("The Agent Body must be a base64 encoded string, got: %q", plan.Request.Agent.Body.ValueString()), + ) + return + } else { + modelBody.ActionConfig.Request.Agent.Op.Body = bodyBytes + } + } + if !plan.Request.Agent.ActionRunID.IsUnknown() && !plan.Request.Agent.ActionRunID.IsNull() { + modelBody.ActionConfig.Request.Agent.Op.ActionRunID = plan.Request.Agent.ActionRunID.ValueString() + } } params := &waypoint_service.WaypointServiceCreateActionConfigParams{ @@ -247,6 +304,12 @@ func (r *ActionResource) Create(ctx context.Context, req resource.CreateRequest, resp.Diagnostics.Append(diags...) return } + } else if aCfgModel.Request.Agent != nil { + diags = readAgentAction(ctx, plan, aCfgModel) + if diags.HasError() { + resp.Diagnostics.Append(diags...) + return + } } // Write logs using the tflog package @@ -314,6 +377,12 @@ func (r *ActionResource) Read(ctx context.Context, req resource.ReadRequest, res resp.Diagnostics.Append(diags...) return } + } else if actionCfg.Request.Agent != nil { + diags := readAgentAction(ctx, data, actionCfg) + if diags.HasError() { + resp.Diagnostics.Append(diags...) + return + } } resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) @@ -383,6 +452,30 @@ func (r *ActionResource) Update(ctx context.Context, req resource.UpdateRequest, modelBody.ActionConfig.Request.Custom.Body = plan.Request.Custom.Body.ValueString() } + // This is a proxy for the request type, as Agent.OperationID is required for Agent requests + } else if !plan.Request.Agent.OperationID.IsUnknown() && !plan.Request.Agent.OperationID.IsNull() { + modelBody.ActionConfig.Request.Agent = &waypoint_models.HashicorpCloudWaypointV20241122ActionConfigFlavorAgent{} + + modelBody.ActionConfig.Request.Agent.Op.ID = plan.Request.Agent.OperationID.ValueString() + modelBody.ActionConfig.Request.Agent.Op.Group = plan.Request.Agent.Group.ValueString() + + if !plan.Request.Agent.Body.IsUnknown() && !plan.Request.Agent.Body.IsNull() { + // The body is expected to be a base64 encoded string, so we decode it + bodyBytes, err := base64.StdEncoding.DecodeString(plan.Request.Agent.Body.ValueString()) + // If there is an error, we immediately return an error to the user + if err != nil { + resp.Diagnostics.AddError( + "Error decoding Agent Body", + fmt.Sprintf("The Agent Body must be a base64 encoded string, got: %q", plan.Request.Agent.Body.ValueString()), + ) + return + } else { + modelBody.ActionConfig.Request.Agent.Op.Body = bodyBytes + } + } + if !plan.Request.Agent.ActionRunID.IsUnknown() && !plan.Request.Agent.ActionRunID.IsNull() { + modelBody.ActionConfig.Request.Agent.Op.ActionRunID = plan.Request.Agent.ActionRunID.ValueString() + } } params := &waypoint_service.WaypointServiceUpdateActionConfigParams{ @@ -429,6 +522,12 @@ func (r *ActionResource) Update(ctx context.Context, req resource.UpdateRequest, resp.Diagnostics.Append(diags...) return } + } else if aCfgModel.Request.Agent != nil { + diags = readAgentAction(ctx, plan, aCfgModel) + if diags.HasError() { + resp.Diagnostics.Append(diags...) + return + } } // Write logs using the tflog package @@ -521,3 +620,34 @@ func readCustomAction( } return diags } + +func readAgentAction( + ctx context.Context, + data *ActionResourceModel, + actionCfg *waypoint_models.HashicorpCloudWaypointV20241122ActionConfig, +) diag.Diagnostics { + data.Request.Agent = &agentRequest{} + var diags diag.Diagnostics + if actionCfg.Request.Agent.Op.ID != "" { + data.Request.Agent.OperationID = types.StringValue(actionCfg.Request.Agent.Op.ID) + } else { + data.Request.Agent.OperationID = types.StringNull() + } + if actionCfg.Request.Agent.Op.Group != "" { + data.Request.Agent.Group = types.StringValue(actionCfg.Request.Agent.Op.Group) + } else { + data.Request.Agent.Group = types.StringNull() + } + if actionCfg.Request.Agent.Op.Body != nil { + //TODO(henry): Test this + data.Request.Agent.Body = types.StringValue(base64.StdEncoding.EncodeToString(actionCfg.Request.Agent.Op.Body)) + } else { + data.Request.Agent.Body = types.StringNull() + } + if actionCfg.Request.Agent.Op.ActionRunID != "" { + data.Request.Agent.ActionRunID = types.StringValue(actionCfg.Request.Agent.Op.ActionRunID) + } else { + data.Request.Agent.ActionRunID = types.StringNull() + } + return diags +} diff --git a/internal/provider/waypoint/resource_waypoint_action_test.go b/internal/provider/waypoint/resource_waypoint_action_test.go index a030613b9..9bcf0d906 100644 --- a/internal/provider/waypoint/resource_waypoint_action_test.go +++ b/internal/provider/waypoint/resource_waypoint_action_test.go @@ -30,7 +30,9 @@ func TestAcc_Waypoint_Action_basic(t *testing.T) { } var actionCfgModel waypoint.ActionResourceModel resourceName := "hcp_waypoint_action.test" + resourceNameAgent := "hcp_waypoint_action.test_agent" actionName := generateRandomName() + actionAgentName := generateRandomName() resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -47,6 +49,22 @@ func TestAcc_Waypoint_Action_basic(t *testing.T) { }, }, }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, + CheckDestroy: testAccCheckWaypointActionDestroy(t, &actionCfgModel), + Steps: []resource.TestStep{ + { + Config: testAgentAction(actionAgentName), + Check: resource.ComposeTestCheckFunc( + testAccCheckWaypointActionExists(t, resourceNameAgent, &actionCfgModel), + testAccCheckWaypointActionName(t, &actionCfgModel, actionAgentName), + resource.TestCheckResourceAttr(resourceNameAgent, "name", actionAgentName), + ), + }, + }, + }) } // Simple attribute check on the action received from the API @@ -146,3 +164,17 @@ resource "hcp_waypoint_action" "test" { } `, actionName) } + +func testAgentAction(actionName string) string { + return fmt.Sprintf(` +resource "hcp_waypoint_action" "test_agent" { + name = "%s" + description = "Test action" + request = { + agent = { + operation_id = "test-operation-id" + group = "test-group" + } + } +}`, actionName) +} From f428b4912b8b2b294caf485b9f73653886565bd7 Mon Sep 17 00:00:00 2001 From: HenryEstberg <11286201+HenryEstberg@users.noreply.github.com> Date: Fri, 30 May 2025 13:30:11 -0700 Subject: [PATCH 2/9] Updated to fix linting --- internal/provider/waypoint/resource_waypoint_action.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/provider/waypoint/resource_waypoint_action.go b/internal/provider/waypoint/resource_waypoint_action.go index e116e4d30..c1c822447 100644 --- a/internal/provider/waypoint/resource_waypoint_action.go +++ b/internal/provider/waypoint/resource_waypoint_action.go @@ -639,7 +639,7 @@ func readAgentAction( data.Request.Agent.Group = types.StringNull() } if actionCfg.Request.Agent.Op.Body != nil { - //TODO(henry): Test this + // TODO(henry): Test this data.Request.Agent.Body = types.StringValue(base64.StdEncoding.EncodeToString(actionCfg.Request.Agent.Op.Body)) } else { data.Request.Agent.Body = types.StringNull() From 5d393e25c18324bf2692c5d09522be13602d2ed2 Mon Sep 17 00:00:00 2001 From: HenryEstberg <11286201+HenryEstberg@users.noreply.github.com> Date: Tue, 3 Jun 2025 18:01:44 -0700 Subject: [PATCH 3/9] Agent actions testing progress and first draft of action groups resource --- internal/clients/waypoint.go | 15 + .../waypoint/resource_waypoint_action.go | 42 ++- .../waypoint/resource_waypoint_action_test.go | 2 + .../waypoint/resource_waypoint_agent_group.go | 328 ++++++++++++++++++ .../resource_waypoint_agent_group_test.go | 125 +++++++ 5 files changed, 499 insertions(+), 13 deletions(-) create mode 100644 internal/provider/waypoint/resource_waypoint_agent_group.go create mode 100644 internal/provider/waypoint/resource_waypoint_agent_group_test.go diff --git a/internal/clients/waypoint.go b/internal/clients/waypoint.go index b76aa0261..9eca4718a 100644 --- a/internal/clients/waypoint.go +++ b/internal/clients/waypoint.go @@ -28,6 +28,21 @@ func GetAction(ctx context.Context, client *Client, loc *sharedmodels.HashicorpC return getResp.GetPayload().ActionConfig, nil } +// GetAgentGroup will retrieve an Agent Group by name +func GetAgentGroup(ctx context.Context, client *Client, loc *sharedmodels.HashicorpCloudLocationLocation, groupName string) (*waypoint_models.HashicorpCloudWaypointV20241122AgentGroup, error) { + params := &waypoint_service.WaypointServiceGetAgentGroupParams{ + Name: groupName, + NamespaceLocationOrganizationID: loc.OrganizationID, + NamespaceLocationProjectID: loc.ProjectID, + } + + getResp, err := client.Waypoint.WaypointServiceGetAgentGroup(params, nil) + if err != nil { + return nil, err + } + return getResp.GetPayload().Group, nil +} + // GetApplicationTemplateByName will retrieve a template by name func GetApplicationTemplateByName(ctx context.Context, client *Client, loc *sharedmodels.HashicorpCloudLocationLocation, appName string) (*waypoint_models.HashicorpCloudWaypointV20241122ApplicationTemplate, error) { params := &waypoint_service.WaypointServiceGetApplicationTemplate2Params{ diff --git a/internal/provider/waypoint/resource_waypoint_action.go b/internal/provider/waypoint/resource_waypoint_action.go index c1c822447..294dbecdc 100644 --- a/internal/provider/waypoint/resource_waypoint_action.go +++ b/internal/provider/waypoint/resource_waypoint_action.go @@ -11,6 +11,7 @@ import ( sharedmodels "github.com/hashicorp/hcp-sdk-go/clients/cloud-shared/v1/models" "github.com/hashicorp/hcp-sdk-go/clients/cloud-waypoint-service/preview/2024-11-22/client/waypoint_service" waypoint_models "github.com/hashicorp/hcp-sdk-go/clients/cloud-waypoint-service/preview/2024-11-22/models" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" @@ -34,7 +35,7 @@ type ActionResource struct { client *clients.Client } -// ActionModel describes the resource data model. +// ActionResourceModel describes the resource data model. type ActionResourceModel struct { ID types.String `tfsdk:"id"` Name types.String `tfsdk:"name"` @@ -178,7 +179,6 @@ func (r *ActionResource) Create(ctx context.Context, req resource.CreateRequest, // Read Terraform plan data into the model resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) - if resp.Diagnostics.HasError() { return } @@ -208,7 +208,7 @@ func (r *ActionResource) Create(ctx context.Context, req resource.CreateRequest, // TODO(henry): The following code is very similar to the Update method, consider refactoring to a common function // This is a proxy for the request type, as Custom.Method is required for Custom requests - if !plan.Request.Custom.Method.IsUnknown() && !plan.Request.Custom.Method.IsNull() { + if plan.Request.Custom != nil && !plan.Request.Custom.Method.IsUnknown() && !plan.Request.Custom.Method.IsNull() { modelBody.ActionConfig.Request.Custom = &waypoint_models.HashicorpCloudWaypointV20241122ActionConfigFlavorCustom{} method := waypoint_models.HashicorpCloudWaypointV20241122ActionConfigFlavorCustomMethod(plan.Request.Custom.Method.ValueString()) @@ -235,11 +235,16 @@ func (r *ActionResource) Create(ctx context.Context, req resource.CreateRequest, modelBody.ActionConfig.Request.Custom.Body = plan.Request.Custom.Body.ValueString() } - } else if !plan.Request.Agent.OperationID.IsUnknown() && !plan.Request.Agent.OperationID.IsNull() { - modelBody.ActionConfig.Request.Agent = &waypoint_models.HashicorpCloudWaypointV20241122ActionConfigFlavorAgent{} - - modelBody.ActionConfig.Request.Agent.Op.ID = plan.Request.Agent.OperationID.ValueString() - modelBody.ActionConfig.Request.Agent.Op.Group = plan.Request.Agent.Group.ValueString() + } else if plan.Request.Agent != nil && !plan.Request.Agent.OperationID.IsUnknown() && !plan.Request.Agent.OperationID.IsNull() { + modelBody.ActionConfig.Request.Agent = &waypoint_models.HashicorpCloudWaypointV20241122ActionConfigFlavorAgent{ + Op: &waypoint_models.HashicorpCloudWaypointV20241122AgentOperation{}, + } + if !plan.Request.Agent.OperationID.IsUnknown() && !plan.Request.Agent.OperationID.IsNull() { + modelBody.ActionConfig.Request.Agent.Op.ID = plan.Request.Agent.OperationID.ValueString() + } + if !plan.Request.Agent.Group.IsUnknown() && !plan.Request.Agent.Group.IsNull() { + modelBody.ActionConfig.Request.Agent.Op.Group = plan.Request.Agent.Group.ValueString() + } if !plan.Request.Agent.Body.IsUnknown() && !plan.Request.Agent.Body.IsNull() { // The body is expected to be a base64 encoded string, so we decode it @@ -275,7 +280,11 @@ func (r *ActionResource) Create(ctx context.Context, req resource.CreateRequest, var aCfgModel *waypoint_models.HashicorpCloudWaypointV20241122ActionConfig if aCfg.Payload != nil { aCfgModel = aCfg.Payload.ActionConfig + } else { + resp.Diagnostics.AddError("Error creating Action", "The response payload was nil.") + return } + if aCfgModel == nil { resp.Diagnostics.AddError("Unknown error creating Action", "Empty Action returned") return @@ -425,7 +434,7 @@ func (r *ActionResource) Update(ctx context.Context, req resource.UpdateRequest, var diags diag.Diagnostics // This is a proxy for the request type, as Custom.Method is required for Custom requests - if !plan.Request.Custom.Method.IsUnknown() && !plan.Request.Custom.Method.IsNull() { + if plan.Request.Custom != nil && !plan.Request.Custom.Method.IsUnknown() && !plan.Request.Custom.Method.IsNull() { modelBody.ActionConfig.Request.Custom = &waypoint_models.HashicorpCloudWaypointV20241122ActionConfigFlavorCustom{} method := waypoint_models.HashicorpCloudWaypointV20241122ActionConfigFlavorCustomMethod(plan.Request.Custom.Method.ValueString()) @@ -453,11 +462,17 @@ func (r *ActionResource) Update(ctx context.Context, req resource.UpdateRequest, } // This is a proxy for the request type, as Agent.OperationID is required for Agent requests - } else if !plan.Request.Agent.OperationID.IsUnknown() && !plan.Request.Agent.OperationID.IsNull() { - modelBody.ActionConfig.Request.Agent = &waypoint_models.HashicorpCloudWaypointV20241122ActionConfigFlavorAgent{} + } else if plan.Request.Agent != nil && !plan.Request.Agent.OperationID.IsUnknown() && !plan.Request.Agent.OperationID.IsNull() { + modelBody.ActionConfig.Request.Agent = &waypoint_models.HashicorpCloudWaypointV20241122ActionConfigFlavorAgent{ + Op: &waypoint_models.HashicorpCloudWaypointV20241122AgentOperation{}, + } - modelBody.ActionConfig.Request.Agent.Op.ID = plan.Request.Agent.OperationID.ValueString() - modelBody.ActionConfig.Request.Agent.Op.Group = plan.Request.Agent.Group.ValueString() + if !plan.Request.Agent.OperationID.IsUnknown() && !plan.Request.Agent.OperationID.IsNull() { + modelBody.ActionConfig.Request.Agent.Op.ID = plan.Request.Agent.OperationID.ValueString() + } + if !plan.Request.Agent.Group.IsUnknown() && !plan.Request.Agent.Group.IsNull() { + modelBody.ActionConfig.Request.Agent.Op.Group = plan.Request.Agent.Group.ValueString() + } if !plan.Request.Agent.Body.IsUnknown() && !plan.Request.Agent.Body.IsNull() { // The body is expected to be a base64 encoded string, so we decode it @@ -578,6 +593,7 @@ func (r *ActionResource) Delete(ctx context.Context, req resource.DeleteRequest, return } } + func (r *ActionResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) } diff --git a/internal/provider/waypoint/resource_waypoint_action_test.go b/internal/provider/waypoint/resource_waypoint_action_test.go index 9bcf0d906..6eb5f0699 100644 --- a/internal/provider/waypoint/resource_waypoint_action_test.go +++ b/internal/provider/waypoint/resource_waypoint_action_test.go @@ -108,6 +108,8 @@ func testAccCheckWaypointActionExists(t *testing.T, resourceName string, actionC if actionCfgModel != nil { actionCfgModel.Name = types.StringValue(actionCfg.Name) actionCfgModel.ID = types.StringValue(actionCfg.ID) + } else { + return fmt.Errorf("actionCfgModel is nil when it should not be") } return nil diff --git a/internal/provider/waypoint/resource_waypoint_agent_group.go b/internal/provider/waypoint/resource_waypoint_agent_group.go new file mode 100644 index 000000000..29879bbc2 --- /dev/null +++ b/internal/provider/waypoint/resource_waypoint_agent_group.go @@ -0,0 +1,328 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package waypoint + +import ( + "context" + "fmt" + + sharedmodels "github.com/hashicorp/hcp-sdk-go/clients/cloud-shared/v1/models" + "github.com/hashicorp/hcp-sdk-go/clients/cloud-waypoint-service/preview/2024-11-22/client/waypoint_service" + waypoint_models "github.com/hashicorp/hcp-sdk-go/clients/cloud-waypoint-service/preview/2024-11-22/models" + + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-provider-hcp/internal/clients" +) + +// Ensure provider defined types fully satisfy framework interfaces +var _ resource.Resource = &AgentGroupResource{} +var _ resource.ResourceWithImportState = &AgentGroupResource{} + +func NewAgentGroupResource() resource.Resource { + return &AgentGroupResource{} +} + +type AgentGroupResource struct { + client *clients.Client +} + +// AgentGroupResourceModel describes the resource data model +type AgentGroupResourceModel struct { + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + ProjectID types.String `tfsdk:"project_id"` + OrgID types.String `tfsdk:"organization_id"` +} + +func (r *AgentGroupResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_waypoint_agent_group" +} + +func (r *AgentGroupResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + // This description is used by the documentation generator and the language server. + MarkdownDescription: "The Waypoint Agent Group resource manages the lifecycle of an Agent Group.", + + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID for the Agent Group.", + Computed: true, + }, + "name": schema.StringAttribute{ + Description: "The name of the Agent Group.", + Required: true, + }, + "project_id": schema.StringAttribute{ + Description: "The ID of the Waypoint project to which the Agent Group belongs.", + Computed: true, + Optional: true, + }, + "organization_id": schema.StringAttribute{ + Description: "The ID of the Waypoint organization to which the Agent Group belongs.", + Computed: true, + }, + "description": schema.StringAttribute{ + Description: "A description of the Agent Group.", + Optional: true, + }, + }, + } +} + +func (r *AgentGroupResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*clients.Client) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected *http.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.client = client +} + +func (r *AgentGroupResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan *AgentGroupResourceModel + + // Read the Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + projectID := r.client.Config.ProjectID + if !plan.ProjectID.IsUnknown() { + projectID = plan.ProjectID.ValueString() + } + + orgID := r.client.Config.OrganizationID + + modelBody := &waypoint_models.HashicorpCloudWaypointV20241122WaypointServiceCreateAgentGroupBody{ + Group: &waypoint_models.HashicorpCloudWaypointV20241122AgentGroup{}, + } + + modelBody.Group.Name = plan.Name.ValueString() + + if !plan.Description.IsNull() && !plan.Description.IsUnknown() { + modelBody.Group.Description = plan.Description.ValueString() + } + + params := &waypoint_service.WaypointServiceCreateAgentGroupParams{ + NamespaceLocationOrganizationID: orgID, + NamespaceLocationProjectID: projectID, + Body: modelBody, + } + + _, err := r.client.Waypoint.WaypointServiceCreateAgentGroup(params, nil) + if err != nil { + resp.Diagnostics.AddError("Error Creating Waypoint Agent Group", err.Error()) + return + } + + // We do not get the agent group back from the API, so we need to get it in a separate request + getParams := &waypoint_service.WaypointServiceGetAgentGroupParams{ + Name: params.Body.Group.Name, + NamespaceLocationOrganizationID: orgID, + NamespaceLocationProjectID: projectID, + } + + getAgentGroupResp, err := r.client.Waypoint.WaypointServiceGetAgentGroup(getParams, nil) + if err != nil { + resp.Diagnostics.AddError("Error Getting Waypoint Agent Group after creation", err.Error()) + return + } + + var agentGroupModel *waypoint_models.HashicorpCloudWaypointV20241122AgentGroup + if getAgentGroupResp.Payload != nil { + agentGroupModel = getAgentGroupResp.Payload.Group + } else { + resp.Diagnostics.AddError("Error Getting Waypoint Agent Group after creation", "The response payload was nil.") + return + } + + if agentGroupModel == nil { + resp.Diagnostics.AddError("Error Getting Waypoint Agent Group after creation", "The agent group model was nil.") + return + } + + if agentGroupModel.Description != "" { + plan.Description = types.StringValue(agentGroupModel.Description) + } else { + plan.Description = types.StringNull() + } + if agentGroupModel.Name != "" { + plan.Name = types.StringValue(agentGroupModel.Name) + } else { + plan.Name = types.StringNull() + } + + // Write logs using the tflog package + // Documentation: https://terraform.io/plugin/log + tflog.Trace(ctx, "Created Agent group resource") + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) + +} + +func (r *AgentGroupResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data *AgentGroupResourceModel + + // Read the Terraform state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + projectID := r.client.Config.ProjectID + if !data.ProjectID.IsUnknown() { + projectID = data.ProjectID.ValueString() + } + + orgID := r.client.Config.OrganizationID + + client := r.client + + group, err := clients.GetAgentGroup(ctx, client, &sharedmodels.HashicorpCloudLocationLocation{ + OrganizationID: orgID, + ProjectID: projectID, + }, data.Name.ValueString()) + if err != nil { + if clients.IsResponseCodeNotFound(err) { + // If the group does not exist, remove it from state + tflog.Info(ctx, "Waypoint Agent Group not found for organization, removing from state") + resp.State.RemoveResource(ctx) + return + } + resp.Diagnostics.AddError("Error Reading Waypoint Agent Group", err.Error()) + return + } + + if group.Description != "" { + data.Description = types.StringValue(group.Description) + } else { + data.Description = types.StringNull() + } + + if group.Name != "" { + data.Name = types.StringValue(group.Name) + } else { + data.Name = types.StringNull() + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *AgentGroupResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan *AgentGroupResourceModel + + // Read the Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + // get the current state as well, so we know the current name of the + // agent group for reference during the update + var data *AgentGroupResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + projectID := r.client.Config.ProjectID + + if !plan.ProjectID.IsUnknown() { + projectID = plan.ProjectID.ValueString() + } + + orgID := r.client.Config.OrganizationID + + modelBody := &waypoint_models.HashicorpCloudWaypointV20241122WaypointServiceUpdateAgentGroupBody{} + + modelBody.Description = plan.Description.ValueString() + + params := &waypoint_service.WaypointServiceUpdateAgentGroupParams{ + Body: modelBody, + Name: data.Name.ValueString(), + NamespaceLocationOrganizationID: orgID, + NamespaceLocationProjectID: projectID, + } + + agentGroup, err := r.client.Waypoint.WaypointServiceUpdateAgentGroup(params, nil) + if err != nil { + resp.Diagnostics.AddError("Error Updating Waypoint Agent Group", err.Error()) + return + } + + if agentGroup.Payload == nil || agentGroup.Payload.Group == nil { + resp.Diagnostics.AddError("Error Updating Waypoint Agent Group", "The response payload or group was nil.") + return + } + + // Update the plan with the new value + if agentGroup.Payload.Group.Description != "" { + plan.Description = types.StringValue(agentGroup.Payload.Group.Description) + } else { + plan.Description = types.StringNull() + } + + // Write logs using the tflog package + // Documentation: https://terraform.io/plugin/log + tflog.Trace(ctx, "Updated Agent group resource") + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *AgentGroupResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data *AgentGroupResourceModel + + // Read Terraform state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + projectID := r.client.Config.ProjectID + if !data.ProjectID.IsUnknown() { + projectID = data.ProjectID.ValueString() + } + + loc := &sharedmodels.HashicorpCloudLocationLocation{ + OrganizationID: r.client.Config.OrganizationID, + ProjectID: projectID, + } + + params := &waypoint_service.WaypointServiceDeleteAgentGroupParams{ + Name: data.Name.ValueString(), + NamespaceLocationOrganizationID: loc.OrganizationID, + NamespaceLocationProjectID: loc.ProjectID, + } + + _, err := r.client.Waypoint.WaypointServiceDeleteAgentGroup(params, nil) + if err != nil { + if clients.IsResponseCodeNotFound(err) { + // If the group does not exist, just return + tflog.Info(ctx, "Waypoint Agent Group not found for organization, nothing to delete") + return + } + resp.Diagnostics.AddError("Error Deleting Waypoint Agent Group", err.Error()) + return + } +} + +func (r *AgentGroupResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} diff --git a/internal/provider/waypoint/resource_waypoint_agent_group_test.go b/internal/provider/waypoint/resource_waypoint_agent_group_test.go new file mode 100644 index 000000000..1617ebf5b --- /dev/null +++ b/internal/provider/waypoint/resource_waypoint_agent_group_test.go @@ -0,0 +1,125 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package waypoint_test + +import ( + "context" + "fmt" + "testing" + + sharedmodels "github.com/hashicorp/hcp-sdk-go/clients/cloud-shared/v1/models" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-provider-hcp/internal/clients" + "github.com/hashicorp/terraform-provider-hcp/internal/provider/acctest" + "github.com/hashicorp/terraform-provider-hcp/internal/provider/waypoint" +) + +func TestAcc_Waypoint_Agent_Group_basic(t *testing.T) { + t.Parallel() + + var agentGroupModel waypoint.AgentGroupResourceModel + resourceName := "hcp_waypoint_agent_group.test" + agentGroupName := generateRandomName() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, + CheckDestroy: testAccCheckWaypointAgentGroupDestroy(t, &agentGroupModel), + Steps: []resource.TestStep{ + { + Config: testAgentGroup(agentGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckWaypointAgentGroupExists(t, resourceName, &agentGroupModel), + testAccCheckWaypointAgentGroupName(t, &agentGroupModel, agentGroupName), + resource.TestCheckResourceAttr(resourceName, "name", agentGroupName), + ), + }, + }, + }) +} + +func testAccCheckWaypointAgentGroupExists(t *testing.T, resourceName string, agentGroupModel *waypoint.AgentGroupResourceModel) resource.TestCheckFunc { + return func(s *terraform.State) error { + // Find the corresponding state object + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("not found: %s", resourceName) + } + + client := acctest.HCPClients(t) + + // Get the project ID, org ID, and Name from state + projectID := rs.Primary.Attributes["project_id"] + groupName := rs.Primary.Attributes["name"] + orgID := rs.Primary.Attributes["organization_id"] + + loc := &sharedmodels.HashicorpCloudLocationLocation{ + ProjectID: projectID, + OrganizationID: orgID, + } + + // Retrieve the agent group using the client + agentGroup, err := clients.GetAgentGroup(context.Background(), client, loc, groupName) + if err != nil { + return fmt.Errorf("error retrieving agent group %s: %w", groupName, err) + } + + // Verify the agent group exists + if agentGroup == nil { + return fmt.Errorf("agent group %s not found", groupName) + } + + return nil + } +} + +func testAccCheckWaypointAgentGroupName(_ *testing.T, agentGroupModel *waypoint.AgentGroupResourceModel, nameValue string) resource.TestCheckFunc { + return func(s *terraform.State) error { + if agentGroupModel.Name.ValueString() != nameValue { + return fmt.Errorf("expected agent group name to be %s, but got %s", nameValue, agentGroupModel.Name.ValueString()) + } + return nil + } +} + +func testAccCheckWaypointAgentGroupDestroy(t *testing.T, agentGroupModel *waypoint.AgentGroupResourceModel) resource.TestCheckFunc { + return func(s *terraform.State) error { + client := acctest.HCPClients(t) + name := agentGroupModel.Name.ValueString() + projectID := agentGroupModel.ProjectID.ValueString() + orgID := client.Config.OrganizationID + + loc := &sharedmodels.HashicorpCloudLocationLocation{ + OrganizationID: orgID, + ProjectID: projectID, + } + + agentGroupGetResponse, err := clients.GetAgentGroup(context.Background(), client, loc, name) + if err != nil { + // expected + if clients.IsResponseCodeNotFound(err) { + return nil + } + return err + } + + // fall through, we expect a not found above but if we get this far then + // the test should fail + if agentGroupGetResponse != nil { + return fmt.Errorf("expected agent group to be destroyed, but it still exists") + } + + return fmt.Errorf("both agent group and error were nil in destroy check, this should not happen") + } +} + +func testAgentGroup(groupName string) string { + return fmt.Sprintf(` +resource "hcp_waypoint_agent_group" "test" { + name = "%s" + description = "Test Agent Group" +} +`, groupName) +} From 73d81125b38b3fe89dc36c5abda96a28f3e1add7 Mon Sep 17 00:00:00 2001 From: HenryEstberg <11286201+HenryEstberg@users.noreply.github.com> Date: Tue, 3 Jun 2025 18:35:37 -0700 Subject: [PATCH 4/9] Fixed nil detection for agent body --- .../provider/waypoint/resource_waypoint_action.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/internal/provider/waypoint/resource_waypoint_action.go b/internal/provider/waypoint/resource_waypoint_action.go index 294dbecdc..eb1a32d1f 100644 --- a/internal/provider/waypoint/resource_waypoint_action.go +++ b/internal/provider/waypoint/resource_waypoint_action.go @@ -233,7 +233,6 @@ func (r *ActionResource) Create(ctx context.Context, req resource.CreateRequest, } if !plan.Request.Custom.Body.IsUnknown() && !plan.Request.Custom.Body.IsNull() { modelBody.ActionConfig.Request.Custom.Body = plan.Request.Custom.Body.ValueString() - } } else if plan.Request.Agent != nil && !plan.Request.Agent.OperationID.IsUnknown() && !plan.Request.Agent.OperationID.IsNull() { modelBody.ActionConfig.Request.Agent = &waypoint_models.HashicorpCloudWaypointV20241122ActionConfigFlavorAgent{ @@ -256,9 +255,8 @@ func (r *ActionResource) Create(ctx context.Context, req resource.CreateRequest, fmt.Sprintf("The Agent Body must be a base64 encoded string, got: %q", plan.Request.Agent.Body.ValueString()), ) return - } else { - modelBody.ActionConfig.Request.Agent.Op.Body = bodyBytes } + modelBody.ActionConfig.Request.Agent.Op.Body = bodyBytes } if !plan.Request.Agent.ActionRunID.IsUnknown() && !plan.Request.Agent.ActionRunID.IsNull() { modelBody.ActionConfig.Request.Agent.Op.ActionRunID = plan.Request.Agent.ActionRunID.ValueString() @@ -634,6 +632,10 @@ func readCustomAction( } else { data.Request.Custom.Body = types.StringNull() } + + // Ensure Agent is nil if Custom is set + data.Request.Agent = nil + return diags } @@ -654,7 +656,7 @@ func readAgentAction( } else { data.Request.Agent.Group = types.StringNull() } - if actionCfg.Request.Agent.Op.Body != nil { + if actionCfg.Request.Agent.Op.Body.String() != "" { // TODO(henry): Test this data.Request.Agent.Body = types.StringValue(base64.StdEncoding.EncodeToString(actionCfg.Request.Agent.Op.Body)) } else { @@ -665,5 +667,9 @@ func readAgentAction( } else { data.Request.Agent.ActionRunID = types.StringNull() } + + // Ensure Custom is nil if Agent is set + data.Request.Custom = nil + return diags } From 4f20386922501bc2bf2d3d5ee6787c5e91b0819e Mon Sep 17 00:00:00 2001 From: HenryEstberg <11286201+HenryEstberg@users.noreply.github.com> Date: Wed, 4 Jun 2025 17:56:31 -0700 Subject: [PATCH 5/9] Updated tests and added agent group data source --- internal/provider/provider.go | 2 + .../data_source_waypoint_action_test.go | 20 ++- .../data_source_waypoint_agent_group.go | 146 ++++++++++++++++++ .../data_source_waypoint_agent_group_test.go | 50 ++++++ .../waypoint/resource_waypoint_agent_group.go | 42 ++++- .../resource_waypoint_agent_group_test.go | 14 +- 6 files changed, 259 insertions(+), 15 deletions(-) create mode 100644 internal/provider/waypoint/data_source_waypoint_agent_group.go create mode 100644 internal/provider/waypoint/data_source_waypoint_agent_group_test.go diff --git a/internal/provider/provider.go b/internal/provider/provider.go index e5bcbe272..92d14ab7a 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -175,6 +175,7 @@ func (p *ProviderFramework) Resources(ctx context.Context) []func() resource.Res webhook.NewNotificationsWebhookResource, // Waypoint waypoint.NewActionResource, + waypoint.NewAgentGroupResource, waypoint.NewApplicationResource, waypoint.NewTemplateResource, waypoint.NewAddOnResource, @@ -207,6 +208,7 @@ func (p *ProviderFramework) DataSources(ctx context.Context) []func() datasource iam.NewUserPrincipalDataSource, // Waypoint waypoint.NewActionDataSource, + waypoint.NewAgentGroupDataSource, waypoint.NewApplicationDataSource, waypoint.NewTemplateDataSource, waypoint.NewAddOnDataSource, diff --git a/internal/provider/waypoint/data_source_waypoint_action_test.go b/internal/provider/waypoint/data_source_waypoint_action_test.go index f34aaed44..54beed660 100644 --- a/internal/provider/waypoint/data_source_waypoint_action_test.go +++ b/internal/provider/waypoint/data_source_waypoint_action_test.go @@ -49,6 +49,22 @@ func TestAcc_Waypoint_Action_DataSource_basic(t *testing.T) { }, }, }) +} + +func TestAcc_Waypoint_Action_DataSource_Agent(t *testing.T) { + t.Parallel() + + // Skip this test unless the appropriate environment variable is set + // This is to prevent running this test by default + if os.Getenv("HCP_WAYP_ACTION_TEST") == "" { + t.Skipf("Waypoint Action tests skipped unless env '%s' set", + "HCP_WAYP_ACTION_TEST") + return + } + var actionModel waypoint.ActionResourceModel + resourceName := "hcp_waypoint_action.test_agent" + dataSourceName := "data." + resourceName + actionName := generateRandomName() resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -82,7 +98,7 @@ data "hcp_waypoint_action" "test" { func testDataActionConfigAgent(actionName string) string { return fmt.Sprintf(`%s -data "hcp_waypoint_action" "test" { - name = hcp_waypoint_action.test.name +data "hcp_waypoint_action" "test_agent" { + name = hcp_waypoint_action.test_agent.name }`, testAgentAction(actionName)) } diff --git a/internal/provider/waypoint/data_source_waypoint_agent_group.go b/internal/provider/waypoint/data_source_waypoint_agent_group.go new file mode 100644 index 000000000..491f60097 --- /dev/null +++ b/internal/provider/waypoint/data_source_waypoint_agent_group.go @@ -0,0 +1,146 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package waypoint + +import ( + "context" + "fmt" + + sharedmodels "github.com/hashicorp/hcp-sdk-go/clients/cloud-shared/v1/models" + "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-provider-hcp/internal/clients" +) + +var _ datasource.DataSource = &DataSourceAgentGroup{} +var _ datasource.DataSourceWithConfigValidators = &DataSourceAgentGroup{} + +func (d DataSourceAgentGroup) ConfigValidators(ctx context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{ + datasourcevalidator.AtLeastOneOf( + path.MatchRoot("name"), + ), + } +} + +type DataSourceAgentGroup struct { + client *clients.Client +} + +func NewAgentGroupDataSource() datasource.DataSource { + return &DataSourceAgentGroup{} +} + +func (d *DataSourceAgentGroup) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_waypoint_agent_group" +} + +func (d *DataSourceAgentGroup) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + // This description is used by the documentation generator and the language server. + MarkdownDescription: "The Waypoint Agent Group resource manages the lifecycle of an Agent Group.", + + Attributes: map[string]schema.Attribute{ + "name": schema.StringAttribute{ + Description: "The name of the Agent Group.", + Required: true, + }, + "project_id": schema.StringAttribute{ + Description: "The ID of the Waypoint project to which the Agent Group belongs.", + Computed: true, + Optional: true, + }, + "organization_id": schema.StringAttribute{ + Description: "The ID of the Waypoint organization to which the Agent Group belongs.", + Computed: true, + Optional: true, + }, + "description": schema.StringAttribute{ + Description: "A description of the Agent Group.", + Optional: true, + }, + }, + } +} + +func (d *DataSourceAgentGroup) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*clients.Client) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected *clients.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + d.client = client +} + +func (d *DataSourceAgentGroup) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *AgentGroupResourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + client := d.client + if d.client == nil { + resp.Diagnostics.AddError( + "Unconfigured HCP Client", + "Expected configured HCP client. Please report this issue to the provider developers.", + ) + return + } + + projectID := client.Config.ProjectID + if !data.ProjectID.IsUnknown() && !data.ProjectID.IsNull() { + projectID = data.ProjectID.ValueString() + } + + orgID := client.Config.OrganizationID + if !data.OrgID.IsUnknown() && !data.OrgID.IsNull() { + orgID = data.OrgID.ValueString() + } + + group, err := clients.GetAgentGroup(ctx, client, &sharedmodels.HashicorpCloudLocationLocation{ + OrganizationID: orgID, + ProjectID: projectID, + }, data.Name.ValueString()) + if err != nil { + if clients.IsResponseCodeNotFound(err) { + // If the group does not exist, remove it from state + tflog.Info(ctx, "Waypoint Agent Group not found for organization, removing from state") + resp.State.RemoveResource(ctx) + return + } + resp.Diagnostics.AddError("Error Reading Waypoint Agent Group", err.Error()) + return + } + + if group.Description != "" { + data.Description = types.StringValue(group.Description) + } else { + data.Description = types.StringNull() + } + + if group.Name != "" { + data.Name = types.StringValue(group.Name) + } else { + data.Name = types.StringNull() + } + + if data.ProjectID.IsUnknown() { + data.ProjectID = types.StringValue(projectID) + } + if data.OrgID.IsUnknown() { + data.OrgID = types.StringValue(orgID) + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/provider/waypoint/data_source_waypoint_agent_group_test.go b/internal/provider/waypoint/data_source_waypoint_agent_group_test.go new file mode 100644 index 000000000..6ad600b4d --- /dev/null +++ b/internal/provider/waypoint/data_source_waypoint_agent_group_test.go @@ -0,0 +1,50 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package waypoint_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-hcp/internal/provider/acctest" + "github.com/hashicorp/terraform-provider-hcp/internal/provider/waypoint" +) + +func TestAcc_Waypoint_Agent_Group_DataSource_basic(t *testing.T) { + t.Parallel() + var agentGroupModel waypoint.AgentGroupResourceModel + resourceName := "hcp_waypoint_agent_group.test" + dataSourceName := "data." + resourceName + agentGroupName := generateRandomName() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, + CheckDestroy: testAccCheckWaypointAgentGroupDestroy(t, &agentGroupModel), + Steps: []resource.TestStep{ + { + // establish the base agent group + Config: testAgentGroup(agentGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckWaypointAgentGroupExists(t, resourceName, &agentGroupModel), + ), + }, + { + // add a data source config to read the agent group + Config: testDataAgentGroup(agentGroupName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "name", agentGroupName), + ), + }, + }, + }) +} + +func testDataAgentGroup(agentGroupName string) string { + return fmt.Sprintf(`%s +data "hcp_waypoint_agent_group" "test" { + name = hcp_waypoint_agent_group.test.name +}`, testAgentGroup(agentGroupName)) +} diff --git a/internal/provider/waypoint/resource_waypoint_agent_group.go b/internal/provider/waypoint/resource_waypoint_agent_group.go index 29879bbc2..91f97f723 100644 --- a/internal/provider/waypoint/resource_waypoint_agent_group.go +++ b/internal/provider/waypoint/resource_waypoint_agent_group.go @@ -49,10 +49,6 @@ func (r *AgentGroupResource) Schema(ctx context.Context, req resource.SchemaRequ MarkdownDescription: "The Waypoint Agent Group resource manages the lifecycle of an Agent Group.", Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Description: "The ID for the Agent Group.", - Computed: true, - }, "name": schema.StringAttribute{ Description: "The name of the Agent Group.", Required: true, @@ -65,6 +61,7 @@ func (r *AgentGroupResource) Schema(ctx context.Context, req resource.SchemaRequ "organization_id": schema.StringAttribute{ Description: "The ID of the Waypoint organization to which the Agent Group belongs.", Computed: true, + Optional: true, }, "description": schema.StringAttribute{ Description: "A description of the Agent Group.", @@ -103,11 +100,14 @@ func (r *AgentGroupResource) Create(ctx context.Context, req resource.CreateRequ } projectID := r.client.Config.ProjectID - if !plan.ProjectID.IsUnknown() { + if !plan.ProjectID.IsUnknown() && !plan.ProjectID.IsNull() { projectID = plan.ProjectID.ValueString() } orgID := r.client.Config.OrganizationID + if !plan.OrgID.IsUnknown() && !plan.OrgID.IsNull() { + orgID = plan.OrgID.ValueString() + } modelBody := &waypoint_models.HashicorpCloudWaypointV20241122WaypointServiceCreateAgentGroupBody{ Group: &waypoint_models.HashicorpCloudWaypointV20241122AgentGroup{}, @@ -168,6 +168,13 @@ func (r *AgentGroupResource) Create(ctx context.Context, req resource.CreateRequ plan.Name = types.StringNull() } + if plan.ProjectID.IsUnknown() { + plan.ProjectID = types.StringValue(projectID) + } + if plan.OrgID.IsUnknown() { + plan.OrgID = types.StringValue(orgID) + } + // Write logs using the tflog package // Documentation: https://terraform.io/plugin/log tflog.Trace(ctx, "Created Agent group resource") @@ -187,11 +194,14 @@ func (r *AgentGroupResource) Read(ctx context.Context, req resource.ReadRequest, } projectID := r.client.Config.ProjectID - if !data.ProjectID.IsUnknown() { + if !data.ProjectID.IsUnknown() && !data.ProjectID.IsNull() { projectID = data.ProjectID.ValueString() } orgID := r.client.Config.OrganizationID + if !data.OrgID.IsUnknown() && !data.OrgID.IsNull() { + orgID = data.OrgID.ValueString() + } client := r.client @@ -222,6 +232,13 @@ func (r *AgentGroupResource) Read(ctx context.Context, req resource.ReadRequest, data.Name = types.StringNull() } + if data.ProjectID.IsUnknown() { + data.ProjectID = types.StringValue(projectID) + } + if data.OrgID.IsUnknown() { + data.OrgID = types.StringValue(orgID) + } + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -242,12 +259,14 @@ func (r *AgentGroupResource) Update(ctx context.Context, req resource.UpdateRequ resp.Diagnostics.Append(req.State.Get(ctx, &data)...) projectID := r.client.Config.ProjectID - - if !plan.ProjectID.IsUnknown() { + if !plan.ProjectID.IsUnknown() && !plan.ProjectID.IsNull() { projectID = plan.ProjectID.ValueString() } orgID := r.client.Config.OrganizationID + if !plan.OrgID.IsUnknown() && !plan.OrgID.IsNull() { + orgID = plan.OrgID.ValueString() + } modelBody := &waypoint_models.HashicorpCloudWaypointV20241122WaypointServiceUpdateAgentGroupBody{} @@ -278,6 +297,13 @@ func (r *AgentGroupResource) Update(ctx context.Context, req resource.UpdateRequ plan.Description = types.StringNull() } + if plan.ProjectID.IsUnknown() { + plan.ProjectID = types.StringValue(projectID) + } + if plan.OrgID.IsUnknown() { + plan.OrgID = types.StringValue(orgID) + } + // Write logs using the tflog package // Documentation: https://terraform.io/plugin/log tflog.Trace(ctx, "Updated Agent group resource") diff --git a/internal/provider/waypoint/resource_waypoint_agent_group_test.go b/internal/provider/waypoint/resource_waypoint_agent_group_test.go index 1617ebf5b..56a7f8fea 100644 --- a/internal/provider/waypoint/resource_waypoint_agent_group_test.go +++ b/internal/provider/waypoint/resource_waypoint_agent_group_test.go @@ -9,6 +9,7 @@ import ( "testing" sharedmodels "github.com/hashicorp/hcp-sdk-go/clients/cloud-shared/v1/models" + "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-hcp/internal/clients" @@ -63,14 +64,17 @@ func testAccCheckWaypointAgentGroupExists(t *testing.T, resourceName string, age // Retrieve the agent group using the client agentGroup, err := clients.GetAgentGroup(context.Background(), client, loc, groupName) if err != nil { - return fmt.Errorf("error retrieving agent group %s: %w", groupName, err) + return fmt.Errorf("error retrieving agent group %q: %w", groupName, err) } // Verify the agent group exists if agentGroup == nil { - return fmt.Errorf("agent group %s not found", groupName) + return fmt.Errorf("agent group %q not found", groupName) } + agentGroupModel.Name = types.StringValue(agentGroup.Name) + agentGroupModel.Description = types.StringValue(agentGroup.Description) + return nil } } @@ -78,7 +82,7 @@ func testAccCheckWaypointAgentGroupExists(t *testing.T, resourceName string, age func testAccCheckWaypointAgentGroupName(_ *testing.T, agentGroupModel *waypoint.AgentGroupResourceModel, nameValue string) resource.TestCheckFunc { return func(s *terraform.State) error { if agentGroupModel.Name.ValueString() != nameValue { - return fmt.Errorf("expected agent group name to be %s, but got %s", nameValue, agentGroupModel.Name.ValueString()) + return fmt.Errorf("expected agent group name to be %q, but got %q", nameValue, agentGroupModel.Name.ValueString()) } return nil } @@ -118,8 +122,8 @@ func testAccCheckWaypointAgentGroupDestroy(t *testing.T, agentGroupModel *waypoi func testAgentGroup(groupName string) string { return fmt.Sprintf(` resource "hcp_waypoint_agent_group" "test" { - name = "%s" - description = "Test Agent Group" + name = %q + description = "Test Agent Group" } `, groupName) } From dce9aad1be377e57767170bb4c195591ef5d5469 Mon Sep 17 00:00:00 2001 From: HenryEstberg <11286201+HenryEstberg@users.noreply.github.com> Date: Thu, 5 Jun 2025 16:21:31 -0700 Subject: [PATCH 6/9] Added more docs changes --- .../provider/waypoint/resource_waypoint_action.go | 4 ---- templates/data-sources/waypoint_action.md.tmpl | 2 -- templates/data-sources/waypoint_agent_group.md.tmpl | 12 ++++++++++++ templates/resources/waypoint_action.md.tmpl | 2 -- templates/resources/waypoint_agent_group.md.tmpl | 12 ++++++++++++ 5 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 templates/data-sources/waypoint_agent_group.md.tmpl create mode 100644 templates/resources/waypoint_agent_group.md.tmpl diff --git a/internal/provider/waypoint/resource_waypoint_action.go b/internal/provider/waypoint/resource_waypoint_action.go index eb1a32d1f..e5f8311c9 100644 --- a/internal/provider/waypoint/resource_waypoint_action.go +++ b/internal/provider/waypoint/resource_waypoint_action.go @@ -202,11 +202,8 @@ func (r *ActionResource) Create(ctx context.Context, req resource.CreateRequest, modelBody.ActionConfig.Description = plan.Description.ValueString() } - // TODO(henry): Error here if multiple request types are set? - var diags diag.Diagnostics - // TODO(henry): The following code is very similar to the Update method, consider refactoring to a common function // This is a proxy for the request type, as Custom.Method is required for Custom requests if plan.Request.Custom != nil && !plan.Request.Custom.Method.IsUnknown() && !plan.Request.Custom.Method.IsNull() { modelBody.ActionConfig.Request.Custom = &waypoint_models.HashicorpCloudWaypointV20241122ActionConfigFlavorCustom{} @@ -657,7 +654,6 @@ func readAgentAction( data.Request.Agent.Group = types.StringNull() } if actionCfg.Request.Agent.Op.Body.String() != "" { - // TODO(henry): Test this data.Request.Agent.Body = types.StringValue(base64.StdEncoding.EncodeToString(actionCfg.Request.Agent.Op.Body)) } else { data.Request.Agent.Body = types.StringNull() diff --git a/templates/data-sources/waypoint_action.md.tmpl b/templates/data-sources/waypoint_action.md.tmpl index 3fcdb9c86..1536bf63e 100644 --- a/templates/data-sources/waypoint_action.md.tmpl +++ b/templates/data-sources/waypoint_action.md.tmpl @@ -7,8 +7,6 @@ description: |- # {{.Name}} `{{.Type}}` --> **Note:** HCP Waypoint actions is currently in beta. - {{ .Description | trimspace }} {{ .SchemaMarkdown | trimspace }} \ No newline at end of file diff --git a/templates/data-sources/waypoint_agent_group.md.tmpl b/templates/data-sources/waypoint_agent_group.md.tmpl new file mode 100644 index 000000000..1536bf63e --- /dev/null +++ b/templates/data-sources/waypoint_agent_group.md.tmpl @@ -0,0 +1,12 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "HCP Waypoint" +description: |- +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +--- + +# {{.Name}} `{{.Type}}` + +{{ .Description | trimspace }} + +{{ .SchemaMarkdown | trimspace }} \ No newline at end of file diff --git a/templates/resources/waypoint_action.md.tmpl b/templates/resources/waypoint_action.md.tmpl index 3fcdb9c86..1536bf63e 100644 --- a/templates/resources/waypoint_action.md.tmpl +++ b/templates/resources/waypoint_action.md.tmpl @@ -7,8 +7,6 @@ description: |- # {{.Name}} `{{.Type}}` --> **Note:** HCP Waypoint actions is currently in beta. - {{ .Description | trimspace }} {{ .SchemaMarkdown | trimspace }} \ No newline at end of file diff --git a/templates/resources/waypoint_agent_group.md.tmpl b/templates/resources/waypoint_agent_group.md.tmpl new file mode 100644 index 000000000..1536bf63e --- /dev/null +++ b/templates/resources/waypoint_agent_group.md.tmpl @@ -0,0 +1,12 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "HCP Waypoint" +description: |- +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +--- + +# {{.Name}} `{{.Type}}` + +{{ .Description | trimspace }} + +{{ .SchemaMarkdown | trimspace }} \ No newline at end of file From a805d2ea46d42ed90b05987c52b300c4b6aa4d9a Mon Sep 17 00:00:00 2001 From: HenryEstberg <11286201+HenryEstberg@users.noreply.github.com> Date: Thu, 5 Jun 2025 17:05:31 -0700 Subject: [PATCH 7/9] Added changelog --- .changelog/1304.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/1304.txt diff --git a/.changelog/1304.txt b/.changelog/1304.txt new file mode 100644 index 000000000..8c63a7896 --- /dev/null +++ b/.changelog/1304.txt @@ -0,0 +1,3 @@ +```release-note:feature +Add support for agent actions in HCP Waypoint +``` \ No newline at end of file From 56506525ca932fac507131fd70f2d06eb615c43a Mon Sep 17 00:00:00 2001 From: Pier-Luc Caron-St-Pierre Date: Thu, 5 Jun 2025 21:20:50 -0400 Subject: [PATCH 8/9] go generate --- docs/data-sources/waypoint_action.md | 20 ++++++++++++++++++-- docs/data-sources/waypoint_agent_group.md | 23 +++++++++++++++++++++++ docs/resources/waypoint_action.md | 17 +++++++++++++++-- docs/resources/waypoint_agent_group.md | 23 +++++++++++++++++++++++ 4 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 docs/data-sources/waypoint_agent_group.md create mode 100644 docs/resources/waypoint_agent_group.md diff --git a/docs/data-sources/waypoint_action.md b/docs/data-sources/waypoint_action.md index e9323e350..d469a4c95 100644 --- a/docs/data-sources/waypoint_action.md +++ b/docs/data-sources/waypoint_action.md @@ -7,8 +7,6 @@ description: |- # hcp_waypoint_action `Data Source` --> **Note:** HCP Waypoint actions is currently in beta. - The Waypoint Action data source retrieves information on a given Action. @@ -29,10 +27,28 @@ The Waypoint Action data source retrieves information on a given Action. ### Nested Schema for `request` +Optional: + +- `agent` (Attributes) Agent mode allows users to define the agent to use for the request. (see [below for nested schema](#nestedatt--request--agent)) + Read-Only: - `custom` (Attributes) Custom mode allows users to define the HTTP method, the request body, etc. (see [below for nested schema](#nestedatt--request--custom)) + +### Nested Schema for `request.agent` + +Required: + +- `group` (String) The name of the group that the operation is in. +- `operation_id` (String) The identifying name of the operation in the agent config file. + +Optional: + +- `action_run_id` (String) An optional action run id. If specified the agent will interact with the actions subsystem. +- `body` (String) Arguments to the operation, specified as JSON. + + ### Nested Schema for `request.custom` diff --git a/docs/data-sources/waypoint_agent_group.md b/docs/data-sources/waypoint_agent_group.md new file mode 100644 index 000000000..30c229502 --- /dev/null +++ b/docs/data-sources/waypoint_agent_group.md @@ -0,0 +1,23 @@ +--- +page_title: "hcp_waypoint_agent_group Data Source - terraform-provider-hcp" +subcategory: "HCP Waypoint" +description: |- + The Waypoint Agent Group resource manages the lifecycle of an Agent Group. +--- + +# hcp_waypoint_agent_group `Data Source` + +The Waypoint Agent Group resource manages the lifecycle of an Agent Group. + + +## Schema + +### Required + +- `name` (String) The name of the Agent Group. + +### Optional + +- `description` (String) A description of the Agent Group. +- `organization_id` (String) The ID of the Waypoint organization to which the Agent Group belongs. +- `project_id` (String) The ID of the Waypoint project to which the Agent Group belongs. \ No newline at end of file diff --git a/docs/resources/waypoint_action.md b/docs/resources/waypoint_action.md index 3af7859b4..8ae595fc1 100644 --- a/docs/resources/waypoint_action.md +++ b/docs/resources/waypoint_action.md @@ -7,8 +7,6 @@ description: |- # hcp_waypoint_action `Resource` --> **Note:** HCP Waypoint actions is currently in beta. - The Waypoint Action resource manages the lifecycle of an Action. @@ -34,8 +32,23 @@ The Waypoint Action resource manages the lifecycle of an Action. Optional: +- `agent` (Attributes) Agent mode allows users to define the agent to use for the request. (see [below for nested schema](#nestedatt--request--agent)) - `custom` (Attributes) Custom mode allows users to define the HTTP method, the request body, etc. (see [below for nested schema](#nestedatt--request--custom)) + +### Nested Schema for `request.agent` + +Required: + +- `group` (String) The name of the group that the operation is in. +- `operation_id` (String) The identifying name of the operation in the agent config file. + +Optional: + +- `action_run_id` (String) An optional action run id. If specified the agent will interact with the actions subsystem. +- `body` (String) Arguments to the operation, specified as JSON. + + ### Nested Schema for `request.custom` diff --git a/docs/resources/waypoint_agent_group.md b/docs/resources/waypoint_agent_group.md new file mode 100644 index 000000000..7d246dbbf --- /dev/null +++ b/docs/resources/waypoint_agent_group.md @@ -0,0 +1,23 @@ +--- +page_title: "hcp_waypoint_agent_group Resource - terraform-provider-hcp" +subcategory: "HCP Waypoint" +description: |- + The Waypoint Agent Group resource manages the lifecycle of an Agent Group. +--- + +# hcp_waypoint_agent_group `Resource` + +The Waypoint Agent Group resource manages the lifecycle of an Agent Group. + + +## Schema + +### Required + +- `name` (String) The name of the Agent Group. + +### Optional + +- `description` (String) A description of the Agent Group. +- `organization_id` (String) The ID of the Waypoint organization to which the Agent Group belongs. +- `project_id` (String) The ID of the Waypoint project to which the Agent Group belongs. \ No newline at end of file From a33cf66499fb1f6a118e1da0eabec4eb415504cb Mon Sep 17 00:00:00 2001 From: HenryEstberg <11286201+HenryEstberg@users.noreply.github.com> Date: Mon, 9 Jun 2025 16:09:07 -0700 Subject: [PATCH 9/9] Removed some test parallelization to stop race condition --- internal/provider/waypoint/data_source_waypoint_action_test.go | 2 -- internal/provider/waypoint/resource_waypoint_action_test.go | 1 - 2 files changed, 3 deletions(-) diff --git a/internal/provider/waypoint/data_source_waypoint_action_test.go b/internal/provider/waypoint/data_source_waypoint_action_test.go index 54beed660..5fcc9c6e7 100644 --- a/internal/provider/waypoint/data_source_waypoint_action_test.go +++ b/internal/provider/waypoint/data_source_waypoint_action_test.go @@ -14,7 +14,6 @@ import ( ) func TestAcc_Waypoint_Action_DataSource_basic(t *testing.T) { - t.Parallel() // Skip this test unless the appropriate environment variable is set // This is to prevent running this test by default @@ -52,7 +51,6 @@ func TestAcc_Waypoint_Action_DataSource_basic(t *testing.T) { } func TestAcc_Waypoint_Action_DataSource_Agent(t *testing.T) { - t.Parallel() // Skip this test unless the appropriate environment variable is set // This is to prevent running this test by default diff --git a/internal/provider/waypoint/resource_waypoint_action_test.go b/internal/provider/waypoint/resource_waypoint_action_test.go index 6eb5f0699..2138b6790 100644 --- a/internal/provider/waypoint/resource_waypoint_action_test.go +++ b/internal/provider/waypoint/resource_waypoint_action_test.go @@ -19,7 +19,6 @@ import ( ) func TestAcc_Waypoint_Action_basic(t *testing.T) { - t.Parallel() // Skip this test unless the appropriate environment variable is set // This is to prevent running this test by default