Skip to content
Closed
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- Add support for data_stream `lifecycle` template settings ([#724](https://github.com/elastic/terraform-provider-elasticstack/pull/724))
- Fix a provider panic when `elasticstack_kibana_action_connector` reads a non-existant connector ([#729](https://github.com/elastic/terraform-provider-elasticstack/pull/729))
- Add support for `remote_indicies` to `elasticstack_elasticsearch_security_role` & `elasticstack_kibana_security_role` (#723)[https://github.com/elastic/terraform-provider-elasticstack/pull/723]
- Added support for global data tags in agent policy creation and update. Upgraded the generated Fleet API to version 8.15.0. (#730)[https://github.com/elastic/terraform-provider-elasticstack/pull/730]

## [0.11.6] - 2024-08-20

Expand Down
1 change: 1 addition & 0 deletions docs/resources/fleet_agent_policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ resource "elasticstack_fleet_agent_policy" "test_policy" {
- `description` (String) The description of the agent policy.
- `download_source_id` (String) The identifier for the Elastic Agent binary download server.
- `fleet_server_host_id` (String) The identifier for the Fleet server host.
- `global_data_tags` (Map of String) User-defined data tags that are added to all inputs.
- `monitor_logs` (Boolean) Enable collection of agent logs.
- `monitor_metrics` (Boolean) Enable collection of agent metrics.
- `monitoring_output_id` (String) The identifier for monitoring output.
Expand Down
4 changes: 2 additions & 2 deletions generated/alerting/api_alerting_mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion generated/connectors/connectors.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

611 changes: 522 additions & 89 deletions generated/fleet/fleet.gen.go

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions generated/fleet/getschema.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ func transformOutputTypeRequired(schema *Schema) {
"schemas.output_update_request_elasticsearch.required",
"schemas.output_update_request_kafka.required",
"schemas.output_update_request_logstash.required",
"schemas.output_create_request_remote_elasticsearch.required",
}

for _, v := range path {
Expand Down
111 changes: 111 additions & 0 deletions internal/fleet/agent_policy_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

import (
"context"
"fmt"

fleetapi "github.com/elastic/terraform-provider-elasticstack/generated/fleet"
"github.com/elastic/terraform-provider-elasticstack/internal/clients"
"github.com/elastic/terraform-provider-elasticstack/internal/clients/fleet"
"github.com/hashicorp/go-version"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand All @@ -15,6 +18,8 @@
monitorMetrics = "metrics"
)

var minVersionGlobalDataTags = version.Must(version.NewVersion("8.15.0"))

func ResourceAgentPolicy() *schema.Resource {
agentPolicySchema := map[string]*schema.Schema{
"policy_id": {
Expand Down Expand Up @@ -79,6 +84,14 @@
Type: schema.TypeBool,
Optional: true,
},
"global_data_tags": {
Description: "User-defined data tags that are added to all inputs.",
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
}

return &schema.Resource{
Expand All @@ -103,6 +116,16 @@
return diags
}

apiClient, diags := clients.NewApiClientFromSDKResource(d, meta)
if diags.HasError() {
return diags
}

serverVersion, diags := apiClient.ServerVersion(ctx)
if diags.HasError() {
return diags
}

if id := d.Get("policy_id").(string); id != "" {
d.SetId(id)
}
Expand Down Expand Up @@ -140,6 +163,29 @@
}
req.MonitoringEnabled = &monitoringValues

if tags, ok := d.GetOk("global_data_tags"); ok {
tagMap := tags.(map[string]interface{})

if len(tagMap) > 0 && serverVersion.LessThan(minVersionGlobalDataTags) {
return diag.FromErr(fmt.Errorf("'global_data_tags' is supported only for Elasticsearch v%s and above", minVersionGlobalDataTags.String()))
}

gdt := []map[string]fleetapi.AgentPolicyCreateRequest_GlobalDataTags_AdditionalProperties{}
for key, value := range tagMap {
name := fleetapi.AgentPolicyCreateRequest_GlobalDataTags_AdditionalProperties{}
name.FromAgentPolicyCreateRequestGlobalDataTags0(key)

Check failure on line 176 in internal/fleet/agent_policy_resource.go

View workflow job for this annotation

GitHub Actions / Lint

Error return value of `name.FromAgentPolicyCreateRequestGlobalDataTags0` is not checked (errcheck)

val := fleetapi.AgentPolicyCreateRequest_GlobalDataTags_AdditionalProperties{}
val.FromAgentPolicyCreateRequestGlobalDataTags0(value.(string))

Check failure on line 179 in internal/fleet/agent_policy_resource.go

View workflow job for this annotation

GitHub Actions / Lint

Error return value of `val.FromAgentPolicyCreateRequestGlobalDataTags0` is not checked (errcheck)

gdt = append(gdt, map[string]fleetapi.AgentPolicyCreateRequest_GlobalDataTags_AdditionalProperties{
"name": name,
"value": val,
})
}
req.GlobalDataTags = &gdt
}

policy, diags := fleet.CreateAgentPolicy(ctx, fleetClient, req)
if diags.HasError() {
return diags
Expand All @@ -159,6 +205,16 @@
return diags
}

apiClient, diags := clients.NewApiClientFromSDKResource(d, meta)
if diags.HasError() {
return diags
}

serverVersion, diags := apiClient.ServerVersion(ctx)
if diags.HasError() {
return diags
}

req := fleetapi.AgentPolicyUpdateRequest{
Name: d.Get("name").(string),
Namespace: d.Get("namespace").(string),
Expand Down Expand Up @@ -189,6 +245,36 @@
}
req.MonitoringEnabled = &monitoringValues

if tags, ok := d.GetOk("global_data_tags"); ok {
tagMap := tags.(map[string]interface{})

if len(tagMap) > 0 && serverVersion.LessThan(minVersionGlobalDataTags) {
return diag.FromErr(fmt.Errorf("'global_data_tags' is supported only for Elasticsearch v%s and above", minVersionGlobalDataTags.String()))
}

globalDataTags := []map[string]fleetapi.AgentPolicyUpdateRequest_GlobalDataTags_AdditionalProperties{}
for key, val := range tagMap {
var name, value fleetapi.AgentPolicyUpdateRequest_GlobalDataTags_AdditionalProperties
err := name.FromAgentPolicyUpdateRequestGlobalDataTags0(key)
if err != nil {
return diag.FromErr(err)
}

err = value.FromAgentPolicyUpdateRequestGlobalDataTags0(val.(string))
if err != nil {
return diag.FromErr(err)
}

globalDataTags = append(globalDataTags, map[string]fleetapi.AgentPolicyUpdateRequest_GlobalDataTags_AdditionalProperties{
"name": name,
"value": value,
})
}
req.GlobalDataTags = &globalDataTags
} else {
req.GlobalDataTags = &[]map[string]fleetapi.AgentPolicyUpdateRequest_GlobalDataTags_AdditionalProperties{} // Ensure it's an empty array
}

_, diags = fleet.UpdateAgentPolicy(ctx, fleetClient, d.Id(), req)
if diags.HasError() {
return diags
Expand Down Expand Up @@ -264,6 +350,31 @@
}
}

if agentPolicy.GlobalDataTags != nil {

globalDataTags := make(map[string]string, len(*agentPolicy.GlobalDataTags))
for _, tag := range *agentPolicy.GlobalDataTags {
name, err := tag["name"].AsAgentPolicyGlobalDataTags0()
if err != nil {
return diag.FromErr(err)
}

value, err := tag["value"].AsAgentPolicyGlobalDataTags0()
if err != nil {
return diag.FromErr(err)
}
globalDataTags[name] = value
}

if err := d.Set("global_data_tags", globalDataTags); err != nil {
return diag.FromErr(err)
}
} else {
if err := d.Set("global_data_tags", nil); err != nil {
return diag.FromErr(err)
}
}

return nil
}

Expand Down
123 changes: 123 additions & 0 deletions internal/fleet/agent_policy_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ import (
)

var minVersionAgentPolicy = version.Must(version.NewVersion("8.6.0"))
var minVersionGlobalDataTags = version.Must(version.NewVersion("8.15.0"))

func TestAccResourceAgentPolicy(t *testing.T) {
policyName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum)
policyNameGlobalDataTags := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum)

resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
Expand Down Expand Up @@ -50,6 +52,51 @@ func TestAccResourceAgentPolicy(t *testing.T) {
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "skip_destroy", "false"),
),
},
{
SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionGlobalDataTags),
Config: testAccResourceAgentPolicyCreateWithGlobalDataTags(policyNameGlobalDataTags, false),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "name", fmt.Sprintf("Policy %s", policyNameGlobalDataTags)),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "namespace", "default"),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "description", "Test Agent Policy"),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "monitor_logs", "true"),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "monitor_metrics", "false"),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "skip_destroy", "false"),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "global_data_tags.tag1", "value1"),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "global_data_tags.tag2", "value2"),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "global_data_tags.tag3", "value3"),
),
},
{
SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionGlobalDataTags),
Config: testAccResourceAgentPolicyUpdateWithGlobalDataTags(policyNameGlobalDataTags, false),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "name", fmt.Sprintf("Updated Policy %s", policyNameGlobalDataTags)),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "namespace", "default"),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "description", "This policy was updated"),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "monitor_logs", "false"),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "monitor_metrics", "true"),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "skip_destroy", "false"),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "global_data_tags.tag1", "value1a"),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "global_data_tags.tag2", "value2b"),
resource.TestCheckNoResourceAttr("elasticstack_fleet_agent_policy.test_policy", "global_data_tags.tag3"),
),
},
{
SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionGlobalDataTags),
Config: testAccResourceAgentPolicyUpdateWithNoGlobalDataTags(policyNameGlobalDataTags, false),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "name", fmt.Sprintf("Updated Policy %s", policyNameGlobalDataTags)),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "namespace", "default"),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "description", "This policy was updated without global data tags"),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "monitor_logs", "false"),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "monitor_metrics", "true"),
resource.TestCheckResourceAttr("elasticstack_fleet_agent_policy.test_policy", "skip_destroy", "false"),
resource.TestCheckNoResourceAttr("elasticstack_fleet_agent_policy.test_policy", "global_data_tags.tag1"),
resource.TestCheckNoResourceAttr("elasticstack_fleet_agent_policy.test_policy", "global_data_tags.tag2"),
resource.TestCheckNoResourceAttr("elasticstack_fleet_agent_policy.test_policy", "global_data_tags.tag3"),
),
},
},
})
}
Expand Down Expand Up @@ -123,6 +170,82 @@ data "elasticstack_fleet_enrollment_tokens" "test_policy" {
`, fmt.Sprintf("Updated Policy %s", id), skipDestroy)
}

func testAccResourceAgentPolicyCreateWithGlobalDataTags(id string, skipDestroy bool) string {
return fmt.Sprintf(`
provider "elasticstack" {
elasticsearch {}
kibana {}
}

resource "elasticstack_fleet_agent_policy" "test_policy" {
name = "%s"
namespace = "default"
description = "Test Agent Policy"
monitor_logs = true
monitor_metrics = false
skip_destroy = %t
global_data_tags = {
tag1 = "value1"
tag2 = "value2"
tag3 = "value3"
}
}

data "elasticstack_fleet_enrollment_tokens" "test_policy" {
policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id
}

`, fmt.Sprintf("Policy %s", id), skipDestroy)
}

func testAccResourceAgentPolicyUpdateWithGlobalDataTags(id string, skipDestroy bool) string {
return fmt.Sprintf(`
provider "elasticstack" {
elasticsearch {}
kibana {}
}

resource "elasticstack_fleet_agent_policy" "test_policy" {
name = "%s"
namespace = "default"
description = "This policy was updated"
monitor_logs = false
monitor_metrics = true
skip_destroy = %t
global_data_tags = {
tag1 = "value1a"
tag2 = "value2b"
}
}

data "elasticstack_fleet_enrollment_tokens" "test_policy" {
policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id
}
`, fmt.Sprintf("Updated Policy %s", id), skipDestroy)
}

func testAccResourceAgentPolicyUpdateWithNoGlobalDataTags(id string, skipDestroy bool) string {
return fmt.Sprintf(`
provider "elasticstack" {
elasticsearch {}
kibana {}
}

resource "elasticstack_fleet_agent_policy" "test_policy" {
name = "%s"
namespace = "default"
description = "This policy was updated without global data tags"
monitor_logs = false
monitor_metrics = true
skip_destroy = %t
}

data "elasticstack_fleet_enrollment_tokens" "test_policy" {
policy_id = elasticstack_fleet_agent_policy.test_policy.policy_id
}
`, fmt.Sprintf("Updated Policy %s", id), skipDestroy)
}

func checkResourceAgentPolicyDestroy(s *terraform.State) error {
client, err := clients.NewAcceptanceTestingClient()
if err != nil {
Expand Down
5 changes: 3 additions & 2 deletions internal/fleet/integration_policy_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

fleetapi "github.com/elastic/terraform-provider-elasticstack/generated/fleet"
"github.com/elastic/terraform-provider-elasticstack/internal/clients/fleet"
"github.com/elastic/terraform-provider-elasticstack/internal/utils"
)

func ResourceIntegrationPolicy() *schema.Resource {
Expand Down Expand Up @@ -135,7 +136,7 @@ func resourceIntegrationPolicyCreate(ctx context.Context, d *schema.ResourceData
}

req := fleetapi.CreatePackagePolicyJSONRequestBody{
PolicyId: d.Get("agent_policy_id").(string),
PolicyId: utils.Pointer(d.Get("agent_policy_id").(string)),
Name: d.Get("name").(string),
}
req.Package.Name = d.Get("integration_name").(string)
Expand Down Expand Up @@ -215,7 +216,7 @@ func resourceIntegrationPolicyUpdate(ctx context.Context, d *schema.ResourceData
}

req := fleetapi.UpdatePackagePolicyJSONRequestBody{
PolicyId: d.Get("agent_policy_id").(string),
PolicyId: utils.Pointer(d.Get("agent_policy_id").(string)),
Name: d.Get("name").(string),
}
req.Package.Name = d.Get("integration_name").(string)
Expand Down
Loading
Loading