Skip to content

Commit eabca1f

Browse files
committed
impl fw resource.agent_policy
1 parent b6434ba commit eabca1f

File tree

15 files changed

+403
-314
lines changed

15 files changed

+403
-314
lines changed

internal/clients/fleet/fleet.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ func GetEnrollmentTokensByPolicy(ctx context.Context, client *Client, policyID s
4949
}
5050

5151
// ReadAgentPolicy reads a specific agent policy from the API.
52-
func ReadAgentPolicy(ctx context.Context, client *Client, id string) (*fleetapi.AgentPolicy, diag.Diagnostics) {
52+
func ReadAgentPolicy(ctx context.Context, client *Client, id string) (*fleetapi.AgentPolicy, fwdiag.Diagnostics) {
5353
resp, err := client.API.AgentPolicyInfoWithResponse(ctx, id)
5454
if err != nil {
55-
return nil, diag.FromErr(err)
55+
return nil, fromErr(err)
5656
}
5757

5858
switch resp.StatusCode() {
@@ -61,7 +61,7 @@ func ReadAgentPolicy(ctx context.Context, client *Client, id string) (*fleetapi.
6161
case http.StatusNotFound:
6262
return nil, nil
6363
default:
64-
return nil, reportUnknownError(resp.StatusCode(), resp.Body)
64+
return nil, reportUnknownErrorFw(resp.StatusCode(), resp.Body)
6565
}
6666
}
6767

@@ -77,41 +77,41 @@ func CreateAgentPolicy(ctx context.Context, client *Client, req fleetapi.AgentPo
7777
return nil
7878
})
7979
if err != nil {
80-
return nil, diag.FromErr(err)
80+
return nil, fromErr(err)
8181
}
8282

8383
switch resp.StatusCode() {
8484
case http.StatusOK:
8585
return resp.JSON200.Item, nil
8686
default:
87-
return nil, reportUnknownError(resp.StatusCode(), resp.Body)
87+
return nil, reportUnknownErrorFw(resp.StatusCode(), resp.Body)
8888
}
8989
}
9090

9191
// UpdateAgentPolicy updates an existing agent policy.
92-
func UpdateAgentPolicy(ctx context.Context, client *Client, id string, req fleetapi.AgentPolicyUpdateRequest) (*fleetapi.AgentPolicy, diag.Diagnostics) {
92+
func UpdateAgentPolicy(ctx context.Context, client *Client, id string, req fleetapi.AgentPolicyUpdateRequest) (*fleetapi.AgentPolicy, fwdiag.Diagnostics) {
9393
resp, err := client.API.UpdateAgentPolicyWithResponse(ctx, id, req)
9494
if err != nil {
95-
return nil, diag.FromErr(err)
95+
return nil, fromErr(err)
9696
}
9797

9898
switch resp.StatusCode() {
9999
case http.StatusOK:
100100
return &resp.JSON200.Item, nil
101101
default:
102-
return nil, reportUnknownError(resp.StatusCode(), resp.Body)
102+
return nil, reportUnknownErrorFw(resp.StatusCode(), resp.Body)
103103
}
104104
}
105105

106106
// DeleteAgentPolicy deletes an existing agent policy
107-
func DeleteAgentPolicy(ctx context.Context, client *Client, id string) diag.Diagnostics {
107+
func DeleteAgentPolicy(ctx context.Context, client *Client, id string) fwdiag.Diagnostics {
108108
body := fleetapi.DeleteAgentPolicyJSONRequestBody{
109109
AgentPolicyId: id,
110110
}
111111

112112
resp, err := client.API.DeleteAgentPolicyWithResponse(ctx, body)
113113
if err != nil {
114-
return diag.FromErr(err)
114+
return fromErr(err)
115115
}
116116

117117
switch resp.StatusCode() {
@@ -120,7 +120,7 @@ func DeleteAgentPolicy(ctx context.Context, client *Client, id string) diag.Diag
120120
case http.StatusNotFound:
121121
return nil
122122
default:
123-
return reportUnknownError(resp.StatusCode(), resp.Body)
123+
return reportUnknownErrorFw(resp.StatusCode(), resp.Body)
124124
}
125125
}
126126

internal/fleet/agent_policy/create.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package agent_policy
2+
3+
import (
4+
"context"
5+
6+
"github.com/elastic/terraform-provider-elasticstack/internal/clients/fleet"
7+
"github.com/hashicorp/terraform-plugin-framework/resource"
8+
)
9+
10+
func (r *agentPolicyResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
11+
var planModel agentPolicyModel
12+
13+
diags := req.Plan.Get(ctx, &planModel)
14+
resp.Diagnostics.Append(diags...)
15+
if resp.Diagnostics.HasError() {
16+
return
17+
}
18+
19+
client, err := r.client.GetFleetClient()
20+
if err != nil {
21+
resp.Diagnostics.AddError(err.Error(), "")
22+
return
23+
}
24+
25+
body := planModel.toAPICreateModel()
26+
policy, diags := fleet.CreateAgentPolicy(ctx, client, body)
27+
resp.Diagnostics.Append(diags...)
28+
if resp.Diagnostics.HasError() {
29+
return
30+
}
31+
32+
planModel.populateFromAPI(policy)
33+
34+
resp.State.Set(ctx, planModel)
35+
resp.Diagnostics.Append(diags...)
36+
}

internal/fleet/agent_policy/delete.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package agent_policy
2+
3+
import (
4+
"context"
5+
6+
"github.com/elastic/terraform-provider-elasticstack/internal/clients/fleet"
7+
"github.com/hashicorp/terraform-plugin-framework/resource"
8+
"github.com/hashicorp/terraform-plugin-log/tflog"
9+
)
10+
11+
func (r *agentPolicyResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
12+
var stateModel agentPolicyModel
13+
14+
diags := req.State.Get(ctx, &stateModel)
15+
resp.Diagnostics.Append(diags...)
16+
if resp.Diagnostics.HasError() {
17+
return
18+
}
19+
20+
client, err := r.client.GetFleetClient()
21+
if err != nil {
22+
resp.Diagnostics.AddError(err.Error(), "")
23+
return
24+
}
25+
26+
policyID := stateModel.PolicyID.ValueString()
27+
skipDestroy := stateModel.SkipDestroy.ValueBool()
28+
if skipDestroy {
29+
tflog.Debug(ctx, "Skipping destroy of Agent Policy", map[string]any{"policy_id": policyID})
30+
return
31+
}
32+
33+
diags = fleet.DeleteAgentPolicy(ctx, client, policyID)
34+
resp.Diagnostics.Append(diags...)
35+
}

internal/fleet/agent_policy/models.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package agent_policy
2+
3+
import (
4+
"slices"
5+
6+
fleetapi "github.com/elastic/terraform-provider-elasticstack/generated/fleet"
7+
"github.com/hashicorp/terraform-plugin-framework/types"
8+
)
9+
10+
type agentPolicyModel struct {
11+
ID types.String `tfsdk:"id"`
12+
PolicyID types.String `tfsdk:"policy_id"`
13+
Name types.String `tfsdk:"name"`
14+
Namespace types.String `tfsdk:"namespace"`
15+
Description types.String `tfsdk:"description"`
16+
DataOutputId types.String `tfsdk:"data_output_id"`
17+
MonitoringOutputId types.String `tfsdk:"monitoring_output_id"`
18+
FleetServerHostId types.String `tfsdk:"fleet_server_host_id"`
19+
DownloadSourceId types.String `tfsdk:"download_source_id"`
20+
MonitorLogs types.Bool `tfsdk:"monitor_logs"`
21+
MonitorMetrics types.Bool `tfsdk:"monitor_metrics"`
22+
SysMonitoring types.Bool `tfsdk:"sys_monitoring"`
23+
SkipDestroy types.Bool `tfsdk:"skip_destroy"`
24+
}
25+
26+
func (model *agentPolicyModel) populateFromAPI(data *fleetapi.AgentPolicy) {
27+
if data == nil {
28+
return
29+
}
30+
31+
model.ID = types.StringValue(data.Id)
32+
model.PolicyID = types.StringValue(data.Id)
33+
model.DataOutputId = types.StringPointerValue(data.DataOutputId)
34+
model.Description = types.StringPointerValue(data.Description)
35+
model.DownloadSourceId = types.StringPointerValue(data.DownloadSourceId)
36+
model.FleetServerHostId = types.StringPointerValue(data.FleetServerHostId)
37+
38+
if data.MonitoringEnabled != nil {
39+
model.MonitorLogs = types.BoolValue(slices.Contains(data.MonitoringEnabled, fleetapi.AgentPolicyMonitoringEnabledLogs))
40+
model.MonitorMetrics = types.BoolValue(slices.Contains(data.MonitoringEnabled, fleetapi.AgentPolicyMonitoringEnabledMetrics))
41+
} else {
42+
model.MonitorLogs = types.BoolNull()
43+
model.MonitorMetrics = types.BoolNull()
44+
}
45+
model.MonitoringOutputId = types.StringPointerValue(data.MonitoringOutputId)
46+
model.Name = types.StringValue(data.Name)
47+
model.Namespace = types.StringValue(data.Namespace)
48+
}
49+
50+
func (model agentPolicyModel) toAPICreateModel() fleetapi.AgentPolicyCreateRequest {
51+
monitoring := make([]fleetapi.AgentPolicyCreateRequestMonitoringEnabled, 0, 2)
52+
if model.MonitorLogs.ValueBool() {
53+
monitoring = append(monitoring, fleetapi.AgentPolicyCreateRequestMonitoringEnabledLogs)
54+
}
55+
if model.MonitorMetrics.ValueBool() {
56+
monitoring = append(monitoring, fleetapi.AgentPolicyCreateRequestMonitoringEnabledMetrics)
57+
}
58+
59+
body := fleetapi.AgentPolicyCreateRequest{
60+
DataOutputId: model.DataOutputId.ValueStringPointer(),
61+
Description: model.Description.ValueStringPointer(),
62+
DownloadSourceId: model.DownloadSourceId.ValueStringPointer(),
63+
FleetServerHostId: model.FleetServerHostId.ValueStringPointer(),
64+
Id: model.PolicyID.ValueStringPointer(),
65+
MonitoringEnabled: monitoring,
66+
MonitoringOutputId: model.MonitoringOutputId.ValueStringPointer(),
67+
Name: model.Name.ValueString(),
68+
Namespace: model.Namespace.ValueString(),
69+
}
70+
71+
return body
72+
}
73+
74+
func (model agentPolicyModel) toAPIUpdateModel() fleetapi.AgentPolicyUpdateRequest {
75+
monitoring := make([]fleetapi.AgentPolicyUpdateRequestMonitoringEnabled, 0, 2)
76+
if model.MonitorLogs.ValueBool() {
77+
monitoring = append(monitoring, fleetapi.Logs)
78+
}
79+
if model.MonitorMetrics.ValueBool() {
80+
monitoring = append(monitoring, fleetapi.Metrics)
81+
}
82+
83+
body := fleetapi.AgentPolicyUpdateRequest{
84+
DataOutputId: model.DataOutputId.ValueStringPointer(),
85+
Description: model.Description.ValueStringPointer(),
86+
DownloadSourceId: model.DownloadSourceId.ValueStringPointer(),
87+
FleetServerHostId: model.FleetServerHostId.ValueStringPointer(),
88+
MonitoringEnabled: monitoring,
89+
MonitoringOutputId: model.MonitoringOutputId.ValueStringPointer(),
90+
Name: model.Name.ValueString(),
91+
Namespace: model.Namespace.ValueString(),
92+
}
93+
94+
return body
95+
}

internal/fleet/agent_policy/read.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package agent_policy
2+
3+
import (
4+
"context"
5+
6+
"github.com/elastic/terraform-provider-elasticstack/internal/clients/fleet"
7+
"github.com/hashicorp/terraform-plugin-framework/resource"
8+
)
9+
10+
func (r *agentPolicyResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
11+
var stateModel agentPolicyModel
12+
13+
diags := req.State.Get(ctx, &stateModel)
14+
resp.Diagnostics.Append(diags...)
15+
if resp.Diagnostics.HasError() {
16+
return
17+
}
18+
19+
client, err := r.client.GetFleetClient()
20+
if err != nil {
21+
resp.Diagnostics.AddError(err.Error(), "")
22+
return
23+
}
24+
25+
policyID := stateModel.PolicyID.ValueString()
26+
policy, diags := fleet.ReadAgentPolicy(ctx, client, policyID)
27+
resp.Diagnostics.Append(diags...)
28+
if resp.Diagnostics.HasError() {
29+
return
30+
}
31+
32+
if policy == nil {
33+
resp.State.RemoveResource(ctx)
34+
return
35+
}
36+
37+
stateModel.populateFromAPI(policy)
38+
39+
resp.State.Set(ctx, stateModel)
40+
resp.Diagnostics.Append(diags...)
41+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package agent_policy
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/elastic/terraform-provider-elasticstack/internal/clients"
8+
"github.com/hashicorp/terraform-plugin-framework/path"
9+
"github.com/hashicorp/terraform-plugin-framework/resource"
10+
)
11+
12+
var (
13+
_ resource.Resource = &agentPolicyResource{}
14+
_ resource.ResourceWithConfigure = &agentPolicyResource{}
15+
_ resource.ResourceWithImportState = &agentPolicyResource{}
16+
)
17+
18+
// NewResource is a helper function to simplify the provider implementation.
19+
func NewResource() resource.Resource {
20+
return &agentPolicyResource{}
21+
}
22+
23+
type agentPolicyResource struct {
24+
client *clients.ApiClient
25+
}
26+
27+
func (r *agentPolicyResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
28+
client, diags := clients.ConvertProviderData(req.ProviderData)
29+
resp.Diagnostics.Append(diags...)
30+
r.client = client
31+
}
32+
33+
func (r *agentPolicyResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
34+
resp.TypeName = fmt.Sprintf("%s_%s", req.ProviderTypeName, "fleet_agent_policy")
35+
}
36+
37+
func (r *agentPolicyResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
38+
resource.ImportStatePassthroughID(ctx, path.Root("policy_id"), req, resp)
39+
}

internal/fleet/agent_policy_resource_test.go renamed to internal/fleet/agent_policy/resource_test.go

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package fleet_test
1+
package agent_policy_test
22

33
import (
44
"context"
@@ -9,6 +9,7 @@ import (
99
"github.com/elastic/terraform-provider-elasticstack/internal/acctest"
1010
"github.com/elastic/terraform-provider-elasticstack/internal/clients"
1111
"github.com/elastic/terraform-provider-elasticstack/internal/clients/fleet"
12+
"github.com/elastic/terraform-provider-elasticstack/internal/utils"
1213
"github.com/elastic/terraform-provider-elasticstack/internal/versionutils"
1314
"github.com/hashicorp/go-version"
1415
sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
@@ -50,6 +51,14 @@ func TestAccResourceAgentPolicy(t *testing.T) {
5051
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "skip_destroy", "false"),
5152
),
5253
},
54+
{
55+
SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionAgentPolicy),
56+
Config: testAccResourceAgentPolicyUpdate(policyName, false),
57+
ResourceName: "elasticstack_fleet_agent_policy.test_policy",
58+
ImportState: true,
59+
ImportStateVerify: true,
60+
ImportStateVerifyIgnore: []string{"skip_destroy"},
61+
},
5362
},
5463
})
5564
}
@@ -138,11 +147,11 @@ func checkResourceAgentPolicyDestroy(s *terraform.State) error {
138147
if err != nil {
139148
return err
140149
}
141-
packagePolicy, diag := fleet.ReadAgentPolicy(context.Background(), fleetClient, rs.Primary.ID)
142-
if diag.HasError() {
143-
return errors.New(diag[0].Summary)
150+
policy, diags := fleet.ReadAgentPolicy(context.Background(), fleetClient, rs.Primary.ID)
151+
if diags.HasError() {
152+
return utils.FwDiagsAsError(diags)
144153
}
145-
if packagePolicy != nil {
154+
if policy != nil {
146155
return fmt.Errorf("agent policy id=%v still exists, but it should have been removed", rs.Primary.ID)
147156
}
148157
}
@@ -164,16 +173,16 @@ func checkResourceAgentPolicySkipDestroy(s *terraform.State) error {
164173
if err != nil {
165174
return err
166175
}
167-
packagePolicy, diag := fleet.ReadAgentPolicy(context.Background(), fleetClient, rs.Primary.ID)
168-
if diag.HasError() {
169-
return errors.New(diag[0].Summary)
176+
policy, diags := fleet.ReadAgentPolicy(context.Background(), fleetClient, rs.Primary.ID)
177+
if diags.HasError() {
178+
return utils.FwDiagsAsError(diags)
170179
}
171-
if packagePolicy == nil {
180+
if policy == nil {
172181
return fmt.Errorf("agent policy id=%v does not exist, but should still exist when skip_destroy is true", rs.Primary.ID)
173182
}
174183

175-
if diag = fleet.DeleteAgentPolicy(context.Background(), fleetClient, rs.Primary.ID); diag.HasError() {
176-
return errors.New(diag[0].Summary)
184+
if diags = fleet.DeleteAgentPolicy(context.Background(), fleetClient, rs.Primary.ID); diags.HasError() {
185+
return errors.New(diags.Errors()[0].Summary())
177186
}
178187
}
179188
return nil

0 commit comments

Comments
 (0)