Skip to content

Commit 668e370

Browse files
Copilottobio
andcommitted
Add required_versions attribute to fleet_agent_policy resource
Co-authored-by: tobio <[email protected]>
1 parent fcc606e commit 668e370

File tree

6 files changed

+770
-18
lines changed

6 files changed

+770
-18
lines changed

internal/fleet/agent_policy/acc_test.go

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,3 +799,177 @@ resource "elasticstack_fleet_agent_policy" "test_policy" {
799799
}
800800
`, id)
801801
}
802+
803+
func TestAccResourceAgentPolicyWithRequiredVersions(t *testing.T) {
804+
policyName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum)
805+
806+
resource.Test(t, resource.TestCase{
807+
PreCheck: func() { acctest.PreCheck(t) },
808+
CheckDestroy: checkResourceAgentPolicyDestroy,
809+
ProtoV6ProviderFactories: acctest.Providers,
810+
Steps: []resource.TestStep{
811+
{
812+
SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionAgentPolicy),
813+
Config: testAccResourceAgentPolicyCreateWithRequiredVersions(policyName),
814+
Check: resource.ComposeTestCheckFunc(
815+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "name", fmt.Sprintf("Policy %s", policyName)),
816+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "namespace", "default"),
817+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "required_versions.#", "1"),
818+
resource.TestCheckTypeSetElemNestedAttrs("elasticstack_fleet_agent_policy.test_policy", "required_versions.*", map[string]string{
819+
"version": "8.15.0",
820+
"percentage": "100",
821+
}),
822+
),
823+
},
824+
{
825+
SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionAgentPolicy),
826+
Config: testAccResourceAgentPolicyUpdateRequiredVersionsPercentage(policyName),
827+
Check: resource.ComposeTestCheckFunc(
828+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "name", fmt.Sprintf("Policy %s", policyName)),
829+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "namespace", "default"),
830+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "required_versions.#", "1"),
831+
resource.TestCheckTypeSetElemNestedAttrs("elasticstack_fleet_agent_policy.test_policy", "required_versions.*", map[string]string{
832+
"version": "8.15.0",
833+
"percentage": "50",
834+
}),
835+
),
836+
},
837+
{
838+
SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionAgentPolicy),
839+
Config: testAccResourceAgentPolicyAddRequiredVersion(policyName),
840+
Check: resource.ComposeTestCheckFunc(
841+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "name", fmt.Sprintf("Policy %s", policyName)),
842+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "namespace", "default"),
843+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "required_versions.#", "2"),
844+
resource.TestCheckTypeSetElemNestedAttrs("elasticstack_fleet_agent_policy.test_policy", "required_versions.*", map[string]string{
845+
"version": "8.15.0",
846+
"percentage": "50",
847+
}),
848+
resource.TestCheckTypeSetElemNestedAttrs("elasticstack_fleet_agent_policy.test_policy", "required_versions.*", map[string]string{
849+
"version": "8.16.0",
850+
"percentage": "50",
851+
}),
852+
),
853+
},
854+
{
855+
SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionAgentPolicy),
856+
Config: testAccResourceAgentPolicyRemoveRequiredVersions(policyName),
857+
Check: resource.ComposeTestCheckFunc(
858+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "name", fmt.Sprintf("Policy %s", policyName)),
859+
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "namespace", "default"),
860+
resource.TestCheckNoResourceAttr("elasticstack_fleet_agent_policy.test_policy", "required_versions"),
861+
),
862+
},
863+
},
864+
})
865+
}
866+
867+
func testAccResourceAgentPolicyCreateWithRequiredVersions(id string) string {
868+
return fmt.Sprintf(`
869+
provider "elasticstack" {
870+
elasticsearch {}
871+
kibana {}
872+
}
873+
874+
resource "elasticstack_fleet_agent_policy" "test_policy" {
875+
name = "%s"
876+
namespace = "default"
877+
description = "Test Agent Policy with Required Versions"
878+
monitor_logs = true
879+
monitor_metrics = false
880+
skip_destroy = false
881+
required_versions = [
882+
{
883+
version = "8.15.0"
884+
percentage = 100
885+
}
886+
]
887+
}
888+
889+
data "elasticstack_fleet_enrollment_tokens" "test_policy" {
890+
policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id
891+
}
892+
`, fmt.Sprintf("Policy %s", id))
893+
}
894+
895+
func testAccResourceAgentPolicyUpdateRequiredVersionsPercentage(id string) string {
896+
return fmt.Sprintf(`
897+
provider "elasticstack" {
898+
elasticsearch {}
899+
kibana {}
900+
}
901+
902+
resource "elasticstack_fleet_agent_policy" "test_policy" {
903+
name = "%s"
904+
namespace = "default"
905+
description = "Test Agent Policy with Required Versions - Updated Percentage"
906+
monitor_logs = true
907+
monitor_metrics = false
908+
skip_destroy = false
909+
required_versions = [
910+
{
911+
version = "8.15.0"
912+
percentage = 50
913+
}
914+
]
915+
}
916+
917+
data "elasticstack_fleet_enrollment_tokens" "test_policy" {
918+
policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id
919+
}
920+
`, fmt.Sprintf("Policy %s", id))
921+
}
922+
923+
func testAccResourceAgentPolicyAddRequiredVersion(id string) string {
924+
return fmt.Sprintf(`
925+
provider "elasticstack" {
926+
elasticsearch {}
927+
kibana {}
928+
}
929+
930+
resource "elasticstack_fleet_agent_policy" "test_policy" {
931+
name = "%s"
932+
namespace = "default"
933+
description = "Test Agent Policy with Multiple Required Versions"
934+
monitor_logs = true
935+
monitor_metrics = false
936+
skip_destroy = false
937+
required_versions = [
938+
{
939+
version = "8.15.0"
940+
percentage = 50
941+
},
942+
{
943+
version = "8.16.0"
944+
percentage = 50
945+
}
946+
]
947+
}
948+
949+
data "elasticstack_fleet_enrollment_tokens" "test_policy" {
950+
policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id
951+
}
952+
`, fmt.Sprintf("Policy %s", id))
953+
}
954+
955+
func testAccResourceAgentPolicyRemoveRequiredVersions(id string) string {
956+
return fmt.Sprintf(`
957+
provider "elasticstack" {
958+
elasticsearch {}
959+
kibana {}
960+
}
961+
962+
resource "elasticstack_fleet_agent_policy" "test_policy" {
963+
name = "%s"
964+
namespace = "default"
965+
description = "Test Agent Policy without Required Versions"
966+
monitor_logs = true
967+
monitor_metrics = false
968+
skip_destroy = false
969+
}
970+
971+
data "elasticstack_fleet_enrollment_tokens" "test_policy" {
972+
policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id
973+
}
974+
`, fmt.Sprintf("Policy %s", id))
975+
}

internal/fleet/agent_policy/models.go

Lines changed: 121 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,25 @@ type globalDataTagsItemModel struct {
3030
}
3131

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

5354
func (model *agentPolicyModel) populateFromAPI(ctx context.Context, data *kbapi.AgentPolicy) diag.Diagnostics {
@@ -134,6 +135,37 @@ func (model *agentPolicyModel) populateFromAPI(ctx context.Context, data *kbapi.
134135
model.SpaceIds = types.SetNull(types.StringType)
135136
}
136137

138+
// Handle required_versions
139+
if data.RequiredVersions != nil && len(*data.RequiredVersions) > 0 {
140+
elemType := getRequiredVersionsElementType()
141+
elements := make([]attr.Value, 0, len(*data.RequiredVersions))
142+
143+
for _, rv := range *data.RequiredVersions {
144+
objValue, d := types.ObjectValue(
145+
map[string]attr.Type{
146+
"version": types.StringType,
147+
"percentage": types.Int32Type,
148+
},
149+
map[string]attr.Value{
150+
"version": types.StringValue(rv.Version),
151+
"percentage": types.Int32Value(int32(rv.Percentage)),
152+
},
153+
)
154+
if d.HasError() {
155+
return d
156+
}
157+
elements = append(elements, objValue)
158+
}
159+
160+
reqVersions, d := NewRequiredVersionsValue(elemType, elements)
161+
if d.HasError() {
162+
return d
163+
}
164+
model.RequiredVersions = reqVersions
165+
} else {
166+
model.RequiredVersions = NewRequiredVersionsValueNull(getRequiredVersionsElementType())
167+
}
168+
137169
return nil
138170
}
139171

@@ -186,6 +218,63 @@ func (model *agentPolicyModel) convertGlobalDataTags(ctx context.Context, feat f
186218
return &itemsList, diags
187219
}
188220

221+
// convertRequiredVersions converts the required versions from terraform model to API model
222+
func (model *agentPolicyModel) convertRequiredVersions(ctx context.Context) (*[]struct {
223+
Percentage float32 `json:"percentage"`
224+
Version string `json:"version"`
225+
}, diag.Diagnostics) {
226+
var diags diag.Diagnostics
227+
228+
if model.RequiredVersions.IsNull() || model.RequiredVersions.IsUnknown() {
229+
return nil, diags
230+
}
231+
232+
elements := model.RequiredVersions.Elements()
233+
if len(elements) == 0 {
234+
return nil, diags
235+
}
236+
237+
result := make([]struct {
238+
Percentage float32 `json:"percentage"`
239+
Version string `json:"version"`
240+
}, 0, len(elements))
241+
242+
for _, elem := range elements {
243+
obj, ok := elem.(types.Object)
244+
if !ok {
245+
diags.AddError("required_versions conversion error", fmt.Sprintf("Expected ObjectValue, got %T", elem))
246+
continue
247+
}
248+
249+
attrs := obj.Attributes()
250+
versionAttr := attrs["version"].(types.String)
251+
percentageAttr := attrs["percentage"].(types.Int32)
252+
253+
if versionAttr.IsNull() || versionAttr.IsUnknown() {
254+
diags.AddError("required_versions validation error", "version cannot be null or unknown")
255+
continue
256+
}
257+
if percentageAttr.IsNull() || percentageAttr.IsUnknown() {
258+
diags.AddError("required_versions validation error", "percentage cannot be null or unknown")
259+
continue
260+
}
261+
262+
result = append(result, struct {
263+
Percentage float32 `json:"percentage"`
264+
Version string `json:"version"`
265+
}{
266+
Percentage: float32(percentageAttr.ValueInt32()),
267+
Version: versionAttr.ValueString(),
268+
})
269+
}
270+
271+
if diags.HasError() {
272+
return nil, diags
273+
}
274+
275+
return &result, diags
276+
}
277+
189278
func (model *agentPolicyModel) toAPICreateModel(ctx context.Context, feat features) (kbapi.PostFleetAgentPoliciesJSONRequestBody, diag.Diagnostics) {
190279
monitoring := make([]kbapi.PostFleetAgentPoliciesJSONBodyMonitoringEnabled, 0, 2)
191280

@@ -282,6 +371,13 @@ func (model *agentPolicyModel) toAPICreateModel(ctx context.Context, feat featur
282371
body.SpaceIds = &spaceIds
283372
}
284373

374+
// Handle required_versions
375+
requiredVersions, d := model.convertRequiredVersions(ctx)
376+
if d.HasError() {
377+
return kbapi.PostFleetAgentPoliciesJSONRequestBody{}, d
378+
}
379+
body.RequiredVersions = requiredVersions
380+
285381
return body, nil
286382
}
287383

@@ -379,5 +475,12 @@ func (model *agentPolicyModel) toAPIUpdateModel(ctx context.Context, feat featur
379475
body.SpaceIds = &spaceIds
380476
}
381477

478+
// Handle required_versions
479+
requiredVersions, d := model.convertRequiredVersions(ctx)
480+
if d.HasError() {
481+
return kbapi.PutFleetAgentPoliciesAgentpolicyidJSONRequestBody{}, d
482+
}
483+
body.RequiredVersions = requiredVersions
484+
382485
return body, nil
383486
}

0 commit comments

Comments
 (0)