Skip to content

Commit d17acd2

Browse files
authored
Merge branch 'main' into slo-data-view-id
2 parents 044b7c4 + 6487901 commit d17acd2

File tree

11 files changed

+268
-33
lines changed

11 files changed

+268
-33
lines changed

.buildkite/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
steps:
22
- label: Release
33
agents:
4-
image: "golang:1.25.0@sha256:5502b0e56fca23feba76dbc5387ba59c593c02ccc2f0f7355871ea9a0852cebe"
4+
image: "golang:1.25.1@sha256:bb979b278ffb8d31c8b07336fd187ef8fafc8766ebeaece524304483ea137e96"
55
cpu: "16"
66
memory: "24G"
77
ephemeralStorage: "20G"

.github/workflows/copilot-setup-steps.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424

2525
steps:
2626
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
27-
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
27+
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6
2828
with:
2929
go-version-file: 'go.mod'
3030
cache: true

.github/workflows/test.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
timeout-minutes: 5
2020
steps:
2121
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
22-
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
22+
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6
2323
with:
2424
go-version-file: 'go.mod'
2525
cache: true
@@ -35,7 +35,7 @@ jobs:
3535
runs-on: ubuntu-latest
3636
steps:
3737
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
38-
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
38+
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6
3939
with:
4040
go-version-file: 'go.mod'
4141
cache: true
@@ -130,7 +130,7 @@ jobs:
130130
- '9.0.3'
131131
steps:
132132
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
133-
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
133+
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6
134134
with:
135135
go-version-file: 'go.mod'
136136
cache: true

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- Add support for `inactivity_timeout` in `elasticstack_fleet_agent_policy` ([#641](https://github.com/elastic/terraform-provider-elasticstack/issues/641))
1616
- [Refactor] Regenerate the SLO client using the current OpenAPI spec ([#1303](https://github.com/elastic/terraform-provider-elasticstack/pull/1303))
1717
- Add support for `data_view_id` in the `elasticstack_kibana_slo` resource ([#1305](https://github.com/elastic/terraform-provider-elasticstack/pull/1305))
18+
- Add support for `unenrollment_timeout` in `elasticstack_fleet_agent_policy` ([#1169](https://github.com/elastic/terraform-provider-elasticstack/issues/1169))
1819

1920
## [0.11.17] - 2025-07-21
2021

docs/resources/fleet_agent_policy.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ resource "elasticstack_fleet_agent_policy" "test_policy" {
5959
- `skip_destroy` (Boolean) Set to true if you do not wish the agent policy to be deleted at destroy time, and instead just remove the agent policy from the Terraform state.
6060
- `supports_agentless` (Boolean) Set to true to enable agentless data collection.
6161
- `sys_monitoring` (Boolean) Enable collection of system logs and metrics.
62+
- `unenrollment_timeout` (String) The unenrollment timeout for the agent policy. If an agent is inactive for this period, it will be automatically unenrolled. Supports duration strings (e.g., '30s', '2m', '1h').
6263

6364
### Read-Only
6465

internal/fleet/agent_policy/models.go

Lines changed: 68 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ import (
1717
)
1818

1919
type features struct {
20-
SupportsGlobalDataTags bool
21-
SupportsSupportsAgentless bool
22-
SupportsInactivityTimeout bool
20+
SupportsGlobalDataTags bool
21+
SupportsSupportsAgentless bool
22+
SupportsInactivityTimeout bool
23+
SupportsUnenrollmentTimeout bool
2324
}
2425

2526
type globalDataTagsItemModel struct {
@@ -28,22 +29,23 @@ type globalDataTagsItemModel struct {
2829
}
2930

3031
type agentPolicyModel struct {
31-
ID types.String `tfsdk:"id"`
32-
PolicyID types.String `tfsdk:"policy_id"`
33-
Name types.String `tfsdk:"name"`
34-
Namespace types.String `tfsdk:"namespace"`
35-
Description types.String `tfsdk:"description"`
36-
DataOutputId types.String `tfsdk:"data_output_id"`
37-
MonitoringOutputId types.String `tfsdk:"monitoring_output_id"`
38-
FleetServerHostId types.String `tfsdk:"fleet_server_host_id"`
39-
DownloadSourceId types.String `tfsdk:"download_source_id"`
40-
MonitorLogs types.Bool `tfsdk:"monitor_logs"`
41-
MonitorMetrics types.Bool `tfsdk:"monitor_metrics"`
42-
SysMonitoring types.Bool `tfsdk:"sys_monitoring"`
43-
SkipDestroy types.Bool `tfsdk:"skip_destroy"`
44-
SupportsAgentless types.Bool `tfsdk:"supports_agentless"`
45-
InactivityTimeout customtypes.Duration `tfsdk:"inactivity_timeout"`
46-
GlobalDataTags types.Map `tfsdk:"global_data_tags"` //> globalDataTagsModel
32+
ID types.String `tfsdk:"id"`
33+
PolicyID types.String `tfsdk:"policy_id"`
34+
Name types.String `tfsdk:"name"`
35+
Namespace types.String `tfsdk:"namespace"`
36+
Description types.String `tfsdk:"description"`
37+
DataOutputId types.String `tfsdk:"data_output_id"`
38+
MonitoringOutputId types.String `tfsdk:"monitoring_output_id"`
39+
FleetServerHostId types.String `tfsdk:"fleet_server_host_id"`
40+
DownloadSourceId types.String `tfsdk:"download_source_id"`
41+
MonitorLogs types.Bool `tfsdk:"monitor_logs"`
42+
MonitorMetrics types.Bool `tfsdk:"monitor_metrics"`
43+
SysMonitoring types.Bool `tfsdk:"sys_monitoring"`
44+
SkipDestroy types.Bool `tfsdk:"skip_destroy"`
45+
SupportsAgentless types.Bool `tfsdk:"supports_agentless"`
46+
InactivityTimeout customtypes.Duration `tfsdk:"inactivity_timeout"`
47+
UnenrollmentTimeout customtypes.Duration `tfsdk:"unenrollment_timeout"`
48+
GlobalDataTags types.Map `tfsdk:"global_data_tags"` //> globalDataTagsModel
4749
}
4850

4951
func (model *agentPolicyModel) populateFromAPI(ctx context.Context, data *kbapi.AgentPolicy) diag.Diagnostics {
@@ -79,11 +81,20 @@ func (model *agentPolicyModel) populateFromAPI(ctx context.Context, data *kbapi.
7981
model.SupportsAgentless = types.BoolPointerValue(data.SupportsAgentless)
8082
if data.InactivityTimeout != nil {
8183
// Convert seconds to duration string
82-
d := time.Duration(*data.InactivityTimeout * float32(time.Second)).Truncate(time.Second)
83-
model.InactivityTimeout = customtypes.NewDurationValue(d.String())
84+
seconds := int64(*data.InactivityTimeout)
85+
d := time.Duration(seconds) * time.Second
86+
model.InactivityTimeout = customtypes.NewDurationValue(d.Truncate(time.Second).String())
8487
} else {
8588
model.InactivityTimeout = customtypes.NewDurationNull()
8689
}
90+
if data.UnenrollTimeout != nil {
91+
// Convert seconds to duration string
92+
seconds := int64(*data.UnenrollTimeout)
93+
d := time.Duration(seconds) * time.Second
94+
model.UnenrollmentTimeout = customtypes.NewDurationValue(d.Truncate(time.Second).String())
95+
} else {
96+
model.UnenrollmentTimeout = customtypes.NewDurationNull()
97+
}
8798
if utils.Deref(data.GlobalDataTags) != nil {
8899
diags := diag.Diagnostics{}
89100
var map0 = make(map[string]globalDataTagsItemModel)
@@ -216,6 +227,24 @@ func (model *agentPolicyModel) toAPICreateModel(ctx context.Context, feat featur
216227
body.InactivityTimeout = &seconds
217228
}
218229

230+
if utils.IsKnown(model.UnenrollmentTimeout) {
231+
if !feat.SupportsUnenrollmentTimeout {
232+
return kbapi.PostFleetAgentPoliciesJSONRequestBody{}, diag.Diagnostics{
233+
diag.NewAttributeErrorDiagnostic(
234+
path.Root("unenrollment_timeout"),
235+
"Unsupported Elasticsearch version",
236+
fmt.Sprintf("Unenrollment timeout is only supported in Elastic Stack %s and above", MinVersionUnenrollmentTimeout),
237+
),
238+
}
239+
}
240+
duration, diags := model.UnenrollmentTimeout.Parse()
241+
if diags.HasError() {
242+
return kbapi.PostFleetAgentPoliciesJSONRequestBody{}, diags
243+
}
244+
seconds := float32(duration.Seconds())
245+
body.UnenrollTimeout = &seconds
246+
}
247+
219248
tags, diags := model.convertGlobalDataTags(ctx, feat)
220249
if diags.HasError() {
221250
return kbapi.PostFleetAgentPoliciesJSONRequestBody{}, diags
@@ -276,6 +305,24 @@ func (model *agentPolicyModel) toAPIUpdateModel(ctx context.Context, feat featur
276305
body.InactivityTimeout = &seconds
277306
}
278307

308+
if utils.IsKnown(model.UnenrollmentTimeout) {
309+
if !feat.SupportsUnenrollmentTimeout {
310+
return kbapi.PutFleetAgentPoliciesAgentpolicyidJSONRequestBody{}, diag.Diagnostics{
311+
diag.NewAttributeErrorDiagnostic(
312+
path.Root("unenrollment_timeout"),
313+
"Unsupported Elasticsearch version",
314+
fmt.Sprintf("Unenrollment timeout is only supported in Elastic Stack %s and above", MinVersionUnenrollmentTimeout),
315+
),
316+
}
317+
}
318+
duration, diags := model.UnenrollmentTimeout.Parse()
319+
if diags.HasError() {
320+
return kbapi.PutFleetAgentPoliciesAgentpolicyidJSONRequestBody{}, diags
321+
}
322+
seconds := float32(duration.Seconds())
323+
body.UnenrollTimeout = &seconds
324+
}
325+
279326
tags, diags := model.convertGlobalDataTags(ctx, feat)
280327
if diags.HasError() {
281328
return kbapi.PutFleetAgentPoliciesAgentpolicyidJSONRequestBody{}, diags

internal/fleet/agent_policy/resource.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ var (
1919
)
2020

2121
var (
22-
MinVersionGlobalDataTags = version.Must(version.NewVersion("8.15.0"))
23-
MinSupportsAgentlessVersion = version.Must(version.NewVersion("8.15.0"))
24-
MinVersionInactivityTimeout = version.Must(version.NewVersion("8.7.0"))
22+
MinVersionGlobalDataTags = version.Must(version.NewVersion("8.15.0"))
23+
MinSupportsAgentlessVersion = version.Must(version.NewVersion("8.15.0"))
24+
MinVersionInactivityTimeout = version.Must(version.NewVersion("8.7.0"))
25+
MinVersionUnenrollmentTimeout = version.Must(version.NewVersion("8.15.0"))
2526
)
2627

2728
// NewResource is a helper function to simplify the provider implementation.
@@ -63,9 +64,15 @@ func (r *agentPolicyResource) buildFeatures(ctx context.Context) (features, diag
6364
return features{}, utils.FrameworkDiagsFromSDK(diags)
6465
}
6566

67+
supportsUnenrollmentTimeout, diags := r.client.EnforceMinVersion(ctx, MinVersionUnenrollmentTimeout)
68+
if diags.HasError() {
69+
return features{}, utils.FrameworkDiagsFromSDK(diags)
70+
}
71+
6672
return features{
67-
SupportsGlobalDataTags: supportsGDT,
68-
SupportsSupportsAgentless: supportsSupportsAgentless,
69-
SupportsInactivityTimeout: supportsInactivityTimeout,
73+
SupportsGlobalDataTags: supportsGDT,
74+
SupportsSupportsAgentless: supportsSupportsAgentless,
75+
SupportsInactivityTimeout: supportsInactivityTimeout,
76+
SupportsUnenrollmentTimeout: supportsUnenrollmentTimeout,
7077
}, nil
7178
}

internal/fleet/agent_policy/resource_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,33 @@ func TestAccResourceAgentPolicy(t *testing.T) {
156156
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "inactivity_timeout", "2m"),
157157
),
158158
},
159+
{
160+
SkipFunc: versionutils.CheckIfVersionIsUnsupported(agent_policy.MinVersionUnenrollmentTimeout),
161+
Config: testAccResourceAgentPolicyCreateWithUnenrollmentTimeout(policyName),
162+
Check: resource.ComposeTestCheckFunc(
163+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "name", fmt.Sprintf("Policy %s", policyName)),
164+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "namespace", "default"),
165+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "description", "Test Agent Policy with Unenrollment Timeout"),
166+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "monitor_logs", "true"),
167+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "monitor_metrics", "false"),
168+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "skip_destroy", "false"),
169+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "unenrollment_timeout", "300s"),
170+
),
171+
},
172+
{
173+
SkipFunc: versionutils.CheckIfVersionIsUnsupported(agent_policy.MinVersionUnenrollmentTimeout),
174+
Config: testAccResourceAgentPolicyUpdateWithTimeouts(policyName),
175+
Check: resource.ComposeTestCheckFunc(
176+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "name", fmt.Sprintf("Updated Policy %s", policyName)),
177+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "namespace", "default"),
178+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "description", "Test Agent Policy with Both Timeouts"),
179+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "monitor_logs", "false"),
180+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "monitor_metrics", "true"),
181+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "skip_destroy", "false"),
182+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "inactivity_timeout", "120s"),
183+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "unenrollment_timeout", "900s"),
184+
),
185+
},
159186
{
160187
SkipFunc: versionutils.CheckIfVersionIsUnsupported(agent_policy.MinVersionGlobalDataTags),
161188
Config: testAccResourceAgentPolicyCreateWithGlobalDataTags(policyNameGlobalDataTags, false),
@@ -332,6 +359,30 @@ data "elasticstack_fleet_enrollment_tokens" "test_policy" {
332359
`, fmt.Sprintf("Policy %s", id))
333360
}
334361

362+
func testAccResourceAgentPolicyCreateWithUnenrollmentTimeout(id string) string {
363+
return fmt.Sprintf(`
364+
provider "elasticstack" {
365+
elasticsearch {}
366+
kibana {}
367+
}
368+
369+
resource "elasticstack_fleet_agent_policy" "test_policy" {
370+
name = "%s"
371+
namespace = "default"
372+
description = "Test Agent Policy with Unenrollment Timeout"
373+
monitor_logs = true
374+
monitor_metrics = false
375+
skip_destroy = false
376+
unenrollment_timeout = "300s"
377+
}
378+
379+
data "elasticstack_fleet_enrollment_tokens" "test_policy" {
380+
policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id
381+
}
382+
383+
`, fmt.Sprintf("Policy %s", id))
384+
}
385+
335386
func testAccResourceAgentPolicyCreateWithBadGlobalDataTags(id string, skipDestroy bool) string {
336387
return fmt.Sprintf(`
337388
provider "elasticstack" {
@@ -509,3 +560,28 @@ func checkResourceAgentPolicySkipDestroy(s *terraform.State) error {
509560
}
510561
return nil
511562
}
563+
564+
func testAccResourceAgentPolicyUpdateWithTimeouts(id string) string {
565+
return fmt.Sprintf(`
566+
provider "elasticstack" {
567+
elasticsearch {}
568+
kibana {}
569+
}
570+
571+
resource "elasticstack_fleet_agent_policy" "test_policy" {
572+
name = "%s"
573+
namespace = "default"
574+
description = "Test Agent Policy with Both Timeouts"
575+
monitor_logs = false
576+
monitor_metrics = true
577+
skip_destroy = false
578+
inactivity_timeout = "120s"
579+
unenrollment_timeout = "900s"
580+
}
581+
582+
data "elasticstack_fleet_enrollment_tokens" "test_policy" {
583+
policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id
584+
}
585+
586+
`, fmt.Sprintf("Updated Policy %s", id))
587+
}

internal/fleet/agent_policy/schema.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ func getSchema() schema.Schema {
104104
Optional: true,
105105
CustomType: customtypes.DurationType{},
106106
},
107+
"unenrollment_timeout": schema.StringAttribute{
108+
Description: "The unenrollment timeout for the agent policy. If an agent is inactive for this period, it will be automatically unenrolled. Supports duration strings (e.g., '30s', '2m', '1h').",
109+
Computed: true,
110+
Optional: true,
111+
CustomType: customtypes.DurationType{},
112+
},
107113
"global_data_tags": schema.MapNestedAttribute{
108114
Description: "User-defined data tags to apply to all inputs. Values can be strings (string_value) or numbers (number_value) but not both. Example -- key1 = {string_value = value1}, key2 = {number_value = 42}",
109115
NestedObject: schema.NestedAttributeObject{

0 commit comments

Comments
 (0)