Skip to content

HCP Waypoint agent actions support #1304

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/1304.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:feature
Add support for agent actions in HCP Waypoint
```
20 changes: 18 additions & 2 deletions docs/data-sources/waypoint_action.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

<!-- schema generated by tfplugindocs -->
Expand All @@ -29,10 +27,28 @@ The Waypoint Action data source retrieves information on a given Action.
<a id="nestedatt--request"></a>
### 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))

<a id="nestedatt--request--agent"></a>
### 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.


<a id="nestedatt--request--custom"></a>
### Nested Schema for `request.custom`

Expand Down
23 changes: 23 additions & 0 deletions docs/data-sources/waypoint_agent_group.md
Original file line number Diff line number Diff line change
@@ -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 generated by tfplugindocs -->
## 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.
17 changes: 15 additions & 2 deletions docs/resources/waypoint_action.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

<!-- schema generated by tfplugindocs -->
Expand All @@ -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))

<a id="nestedatt--request--agent"></a>
### 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.


<a id="nestedatt--request--custom"></a>
### Nested Schema for `request.custom`

Expand Down
23 changes: 23 additions & 0 deletions docs/resources/waypoint_agent_group.md
Original file line number Diff line number Diff line change
@@ -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 generated by tfplugindocs -->
## 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.
15 changes: 15 additions & 0 deletions internal/clients/waypoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
2 changes: 2 additions & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
54 changes: 32 additions & 22 deletions internal/provider/waypoint/data_source_waypoint_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
},
},
},
},
},
Expand All @@ -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)...)

Expand Down Expand Up @@ -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)...)
}
46 changes: 44 additions & 2 deletions internal/provider/waypoint/data_source_waypoint_action_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -51,10 +50,53 @@ func TestAcc_Waypoint_Action_DataSource_basic(t *testing.T) {
})
}

func TestAcc_Waypoint_Action_DataSource_Agent(t *testing.T) {

// 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) },
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_agent" {
name = hcp_waypoint_action.test_agent.name
}`, testAgentAction(actionName))
}
Loading
Loading