Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions docs/resources/fleet_integration_policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ page_title: "elasticstack_fleet_integration_policy Resource - terraform-provider
subcategory: "Fleet"
description: |-
Creates or updates a Fleet Integration Policy.
It is highly recommended that all inputs and streams are provided in the
Terraform plan, even if some are disabled. Otherwise, differences may appear
between what is in the plan versus what is returned by the Fleet API.
The Kibana Fleet UI https://www.elastic.co/guide/en/fleet/current/add-integration-to-policy.html
can be used as a reference for what data needs to be provided. Instead of saving
a new integration configuration, the API request can be previewed, showing what
Expand All @@ -17,10 +14,6 @@ description: |-

Creates or updates a Fleet Integration Policy.

It is highly recommended that all inputs and streams are provided in the
Terraform plan, even if some are disabled. Otherwise, differences may appear
between what is in the plan versus what is returned by the Fleet API.

The [Kibana Fleet UI](https://www.elastic.co/guide/en/fleet/current/add-integration-to-policy.html)
can be used as a reference for what data needs to be provided. Instead of saving
a new integration configuration, the API request can be previewed, showing what
Expand Down Expand Up @@ -124,6 +117,10 @@ Optional:
- `streams` (Attributes Map) Input streams mapped by stream ID. (see [below for nested schema](#nestedatt--inputs--streams))
- `vars` (String, Sensitive) Input-level variables as JSON.

Read-Only:

- `defaults` (Attributes) Input defaults. (see [below for nested schema](#nestedatt--inputs--defaults))

<a id="nestedatt--inputs--streams"></a>
### Nested Schema for `inputs.streams`

Expand All @@ -132,6 +129,23 @@ Optional:
- `enabled` (Boolean) Enable the stream.
- `vars` (String, Sensitive) Stream-level variables as JSON.


<a id="nestedatt--inputs--defaults"></a>
### Nested Schema for `inputs.defaults`

Read-Only:

- `streams` (Attributes Map) Stream-level defaults mapped by stream ID. (see [below for nested schema](#nestedatt--inputs--defaults--streams))
- `vars` (String) Input-level variable defaults as JSON.

<a id="nestedatt--inputs--defaults--streams"></a>
### Nested Schema for `inputs.defaults.streams`

Read-Only:

- `enabled` (Boolean) Default enabled state for the stream.
- `vars` (String) Stream-level variable defaults as JSON.

## Import

Import is supported using the following syntax:
Expand Down
68 changes: 65 additions & 3 deletions internal/fleet/integration_policy/acc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,9 +276,14 @@ func TestAccResourceIntegrationPolicySecrets(t *testing.T) {
"policy_name": config.StringVariable(policyName),
"secret_key": config.StringVariable("updated"),
},
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"vars_json", "space_ids"},
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"vars_json",
"space_ids",
"inputs.aws_logs-aws-cloudwatch.defaults",
"inputs.aws_logs-aws-s3.defaults",
},
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("elasticstack_fleet_integration_policy.test_policy", "vars_json", regexp.MustCompile(`{"access_key_id":{"id":"\S+","isSecretRef":true},"default_region":"us-east-2","endpoint":"endpoint","secret_access_key":{"id":"\S+","isSecretRef":true},"session_token":{"id":"\S+","isSecretRef":true}}`)),
),
Expand Down Expand Up @@ -425,6 +430,63 @@ func TestAccIntegrationPolicyInputs(t *testing.T) {
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "inputs.kafka-kafka/metrics.streams.kafka.partition.enabled", "false"),
),
},
{
ProtoV6ProviderFactories: acctest.Providers,
SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionIntegrationPolicy),
ConfigDirectory: acctest.NamedTestCaseDirectory("update_logfile_tags_only"),
ConfigVariables: config.Variables{
"policy_name": config.StringVariable(policyName),
},
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "name", policyName),
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "description", "Kafka Integration Policy - Logfile with tags only"),
// Check that the kafka-logfile input is enabled with only tags specified
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "inputs.kafka-logfile.enabled", "true"),
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "inputs.kafka-logfile.streams.kafka.log.enabled", "true"),
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "inputs.kafka-logfile.streams.kafka.log.vars", `{"tags":["custom-tag-1","custom-tag-2"]}`),
// Check that the kafka/metrics input remains enabled
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "inputs.kafka-kafka/metrics.enabled", "true"),
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "inputs.kafka-kafka/metrics.vars", `{"hosts":["localhost:9092"],"period":"10s","ssl.certificate_authorities":[]}`),
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "inputs.kafka-kafka/metrics.streams.kafka.broker.enabled", "true"),
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "inputs.kafka-kafka/metrics.streams.kafka.consumergroup.enabled", "true"),
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "inputs.kafka-kafka/metrics.streams.kafka.consumergroup.vars", `{"topics":["don't mention the war, I mentioned it once but I think I got away with it"]}`),
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "inputs.kafka-kafka/metrics.streams.kafka.partition.enabled", "false"),
),
},
{
ProtoV6ProviderFactories: acctest.Providers,
SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionIntegrationPolicy),
ConfigDirectory: acctest.NamedTestCaseDirectory("minimal"),
ConfigVariables: config.Variables{
"policy_name": config.StringVariable(policyName),
},
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "name", policyName),
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "description", "Kafka Integration Policy - Minimal"),
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "integration_name", "kafka"),
// Check specified inputs
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "inputs.kafka-logfile.enabled", "false"),
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "inputs.kafka-kafka/metrics.enabled", "true"),
// Check unspecified, disabled by default input
resource.TestCheckNoResourceAttr("elasticstack_fleet_integration_policy.test_policy", "inputs.kafka-jolokia/metrics"),
),
},
{
ProtoV6ProviderFactories: acctest.Providers,
SkipFunc: versionutils.CheckIfVersionIsUnsupported(minVersionIntegrationPolicy),
ConfigDirectory: acctest.NamedTestCaseDirectory("unset"),
ConfigVariables: config.Variables{
"policy_name": config.StringVariable(policyName),
},
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "name", policyName),
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "description", "Kafka Integration Policy - Minimal"),
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "integration_name", "kafka"),
// Check previously specified inputs
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "inputs.kafka-logfile.enabled", "false"),
resource.TestCheckResourceAttr("elasticstack_fleet_integration_policy.test_policy", "inputs.kafka-kafka/metrics.enabled", "true"),
),
},
},
})
}
Expand Down
8 changes: 7 additions & 1 deletion internal/fleet/integration_policy/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,13 @@ func (r *integrationPolicyResource) Create(ctx context.Context, req resource.Cre
// Remember if the user configured input in the plan
planHadInput := utils.IsKnown(planModel.Inputs) && !planModel.Inputs.IsNull() && len(planModel.Inputs.Elements()) > 0

diags = planModel.populateFromAPI(ctx, policy)
pkg, diags := fleet.GetPackage(ctx, client, policy.Package.Name, policy.Package.Version)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

diags = planModel.populateFromAPI(ctx, pkg, policy)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
Expand Down
74 changes: 74 additions & 0 deletions internal/fleet/integration_policy/input_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package integration_policy

import (
"context"

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)

var (
_ basetypes.ObjectTypable = (*InputType)(nil)
_ basetypes.ObjectValuableWithSemanticEquals = (*InputValue)(nil)
)

// InputType is a custom type for an individual input that supports semantic equality
type InputType struct {
basetypes.ObjectType
}

// String returns a human readable string of the type name.
func (t InputType) String() string {
return "integration_policy.InputType"
}

// ValueType returns the Value type.
func (t InputType) ValueType(ctx context.Context) attr.Value {
return InputValue{
ObjectValue: basetypes.NewObjectUnknown(t.AttributeTypes()),
}
}

// Equal returns true if the given type is equivalent.
func (t InputType) Equal(o attr.Type) bool {
other, ok := o.(InputType)
if !ok {
return false
}
return t.ObjectType.Equal(other.ObjectType)
}

// ValueFromObject returns an ObjectValuable type given a basetypes.ObjectValue.
func (t InputType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) {
return InputValue{
ObjectValue: in,
}, nil
}

// ValueFromTerraform returns a Value given a tftypes.Value.
func (t InputType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) {
attrValue, err := t.ObjectType.ValueFromTerraform(ctx, in)
if err != nil {
return nil, err
}

objectValue, ok := attrValue.(basetypes.ObjectValue)
if !ok {
return nil, err
}

return InputValue{
ObjectValue: objectValue,
}, nil
}

// NewInputType creates a new InputType with the given attribute types
func NewInputType(attrTypes map[string]attr.Type) InputType {
return InputType{
ObjectType: basetypes.ObjectType{
AttrTypes: attrTypes,
},
}
}
Loading