diff --git a/CHANGELOG.md b/CHANGELOG.md index 01b9fadea..f95a29eaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - Add `slo_id` validation to `elasticstack_kibana_slo` ([#1221](https://github.com/elastic/terraform-provider-elasticstack/pull/1221)) - Add `ignore_missing_component_templates` to `elasticstack_elasticsearch_index_template` ([#1206](https://github.com/elastic/terraform-provider-elasticstack/pull/1206)) - Prevent provider panic when a script exists in state, but not in Elasticsearch ([#1218](https://github.com/elastic/terraform-provider-elasticstack/pull/1218)) +- Allow version changes without a destroy/create cycle with `elasticstack_fleet_integration` ([#1255](https://github.com/elastic/terraform-provider-elasticstack/pull/1255)). This fixes an issue where it was impossible to upgrade integrations which are used by an integration policy. - Add `namespace` attribute to `elasticstack_kibana_synthetics_monitor` resource to support setting data stream namespace independently from `space_id` ([#1247](https://github.com/elastic/terraform-provider-elasticstack/pull/1247)) ## [0.11.17] - 2025-07-21 diff --git a/internal/fleet/integration/read.go b/internal/fleet/integration/read.go index f8ebb0434..50fb9fe53 100644 --- a/internal/fleet/integration/read.go +++ b/internal/fleet/integration/read.go @@ -28,7 +28,6 @@ func (r *integrationResource) Read(ctx context.Context, req resource.ReadRequest pkg, diags := fleet.GetPackage(ctx, client, name, version) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { - resp.State.RemoveResource(ctx) return } if pkg.Status != nil && *pkg.Status != "installed" { diff --git a/internal/fleet/integration/resource_test.go b/internal/fleet/integration/resource_test.go index a2d540743..18a505d5a 100644 --- a/internal/fleet/integration/resource_test.go +++ b/internal/fleet/integration/resource_test.go @@ -2,6 +2,7 @@ package integration_test import ( "context" + "fmt" "regexp" "testing" @@ -10,11 +11,15 @@ import ( "github.com/elastic/terraform-provider-elasticstack/internal/clients/fleet" "github.com/elastic/terraform-provider-elasticstack/internal/versionutils" "github.com/hashicorp/go-version" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/stretchr/testify/require" ) -var minVersionIntegration = version.Must(version.NewVersion("8.6.0")) +var ( + minVersionIntegration = version.Must(version.NewVersion("8.6.0")) + minVersionIntegrationPolicy = version.Must(version.NewVersion("8.10.0")) +) func TestAccResourceIntegrationFromSDK(t *testing.T) { resource.Test(t, resource.TestCase{ @@ -72,6 +77,40 @@ func TestAccResourceIntegration(t *testing.T) { }) } +func TestAccResourceIntegrationWithPolicy(t *testing.T) { + policyName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ProtoV6ProviderFactories: acctest.Providers, + Steps: []resource.TestStep{ + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionIntegrationPolicy), + Config: testAccResourceIntegrationWithPolicy(policyName, "1.16.0"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_fleet_integration.test_integration", "name", "tcp"), + resource.TestCheckResourceAttr("elasticstack_fleet_integration.test_integration", "version", "1.16.0"), + ), + }, + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionIntegrationPolicy), + Config: testAccResourceIntegrationWithPolicy(policyName, "1.17.0"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_fleet_integration.test_integration", "name", "tcp"), + resource.TestCheckResourceAttr("elasticstack_fleet_integration.test_integration", "version", "1.17.0"), + ), + }, + { + SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionIntegrationPolicy), + ResourceName: "elasticstack_fleet_integration.test_integration", + Config: testAccResourceIntegrationWithPolicy(policyName, "1.17.0"), + ImportState: true, + ImportStateVerify: true, + ExpectError: regexp.MustCompile("Resource Import Not Implemented"), + }, + }, + }) +} + func TestAccResourceIntegrationDeleted(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -122,6 +161,65 @@ resource "elasticstack_fleet_integration" "test_integration" { } ` +func testAccResourceIntegrationWithPolicy(policyName, version string) string { + return fmt.Sprintf(` +provider "elasticstack" { + elasticsearch {} + kibana {} +} + +resource "elasticstack_fleet_integration" "test_integration" { + name = "tcp" + version = "%s" + force = true + skip_destroy = true +} + +// An agent policy to hold the integration policy. +resource "elasticstack_fleet_agent_policy" "sample" { + name = "%s" + namespace = "default" + description = "A sample agent policy" + monitor_logs = true + monitor_metrics = true + skip_destroy = false +} + +// The associated enrollment token. +data "elasticstack_fleet_enrollment_tokens" "sample" { + policy_id = elasticstack_fleet_agent_policy.sample.policy_id +} + +// The integration policy. +resource "elasticstack_fleet_integration_policy" "sample" { + name = "%s" + namespace = "default" + description = "A sample integration policy" + agent_policy_id = elasticstack_fleet_agent_policy.sample.policy_id + integration_name = elasticstack_fleet_integration.test_integration.name + integration_version = elasticstack_fleet_integration.test_integration.version + + input { + input_id = "tcp-tcp" + streams_json = jsonencode({ + "tcp.generic" : { + "enabled" : true, + "vars" : { + "listen_address" : "localhost", + "listen_port" : 8080, + "data_stream.dataset" : "tcp.generic", + "tags" : [], + "syslog_options" : "field: message\n#format: auto\n#timezone: Local\n", + "ssl" : "#certificate: |\n# -----BEGIN CERTIFICATE-----\n# ...\n# -----END CERTIFICATE-----\n#key: |\n# -----BEGIN PRIVATE KEY-----\n# ...\n# -----END PRIVATE KEY-----\n", + "custom" : "" + } + } + }) + } +} +`, version, policyName, policyName) +} + const testAccResourceIntegrationDeleted = ` provider "elasticstack" { elasticsearch {} diff --git a/internal/fleet/integration/schema.go b/internal/fleet/integration/schema.go index ef87f4a85..17ef3faf8 100644 --- a/internal/fleet/integration/schema.go +++ b/internal/fleet/integration/schema.go @@ -26,9 +26,6 @@ func (r *integrationResource) Schema(ctx context.Context, req resource.SchemaReq "version": schema.StringAttribute{ Description: "The integration package version.", Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, }, "force": schema.BoolAttribute{ Description: "Set to true to force the requested action.",