Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- Add support for `timeslice_metric_indicator` in `elasticstack_kibana_slo` ([#1195](https://github.com/elastic/terraform-provider-elasticstack/pull/1195))
- Add `elasticstack_elasticsearch_ingest_processor_reroute` data source ([#678](https://github.com/elastic/terraform-provider-elasticstack/issues/678))
- Add `namespace` attribute to `elasticstack_kibana_synthetics_monitor` resource to support setting data stream namespace independently from `space_id` ([#1164](https://github.com/elastic/terraform-provider-elasticstack/issues/1164))

## [0.11.16] - 2025-07-09

Expand Down
67 changes: 67 additions & 0 deletions internal/kibana/synthetics/acc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"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/hashicorp/terraform-plugin-sdk/v2/terraform"
)

var (
Expand Down Expand Up @@ -53,6 +54,34 @@ resource "elasticstack_kibana_synthetics_monitor" "%s" {
ipv6 = false
}
}
`
httpMonitorConfigWithNamespace = `

resource "elasticstack_kibana_synthetics_monitor" "%s" {
name = "TestHttpMonitorResource - %s"
space_id = "testacc"
namespace = "test-namespace"
schedule = 5
private_locations = [elasticstack_kibana_synthetics_private_location.%s.label]
enabled = true
tags = ["a", "b"]
alert = {
status = {
enabled = true
}
tls = {
enabled = true
}
}
service_name = "test apm service"
timeout = 30
http = {
url = "http://localhost:5601"
mode = "any"
ipv4 = true
ipv6 = false
}
}
`
httpMonitorSslConfig = `

Expand Down Expand Up @@ -842,3 +871,41 @@ resource "elasticstack_kibana_synthetics_private_location" "%s" {

return resourceId, provider + config
}

func TestSyntheticMonitorHTTPResourceWithNamespace(t *testing.T) {

name := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum)
id := "http-monitor-namespace"
httpMonitorId, config := testMonitorConfig(id, httpMonitorConfigWithNamespace, name)

resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ProtoV6ProviderFactories: acctest.Providers,
Steps: []resource.TestStep{
// Create and Read http monitor with explicit namespace
{
SkipFunc: versionutils.CheckIfVersionIsUnsupported(minKibanaVersion),
Config: config,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrSet(httpMonitorId, "id"),
resource.TestCheckResourceAttr(httpMonitorId, "name", "TestHttpMonitorResource - "+name),
resource.TestCheckResourceAttr(httpMonitorId, "space_id", "testacc"),
resource.TestCheckResourceAttr(httpMonitorId, "namespace", "test-namespace"),
resource.TestCheckResourceAttr(httpMonitorId, "schedule", "5"),
resource.TestCheckResourceAttr(httpMonitorId, "enabled", "true"),
resource.TestCheckResourceAttr(httpMonitorId, "http.url", "http://localhost:5601"),
),
},
// Import
{
SkipFunc: versionutils.CheckIfVersionIsUnsupported(minKibanaVersion),
ResourceName: httpMonitorId,
ImportState: true,
ImportStateIdFunc: func(s *terraform.State) (string, error) {
return fmt.Sprintf("%s/%s", "testacc", s.RootModule().Resources[httpMonitorId].Primary.Attributes["id"]), nil
},
ImportStateVerify: true,
},
},
})
}
7 changes: 6 additions & 1 deletion internal/kibana/synthetics/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ func (r *Resource) Create(ctx context.Context, request resource.CreateRequest, r
return
}

namespace := plan.SpaceID.ValueString()
// Use namespace if explicitly set, otherwise fall back to space_id
namespace := plan.Namespace.ValueString()
if namespace == "" || plan.Namespace.IsNull() || plan.Namespace.IsUnknown() {
namespace = plan.SpaceID.ValueString()
}

result, err := kibanaClient.KibanaSynthetics.Monitor.Add(ctx, input.config, input.fields, namespace)
if err != nil {
response.Diagnostics.AddError(fmt.Sprintf("Failed to create Kibana monitor `%s`, namespace %s", input.config.Name, namespace), err.Error())
Expand Down
19 changes: 18 additions & 1 deletion internal/kibana/synthetics/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ type tfModelV0 struct {
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
SpaceID types.String `tfsdk:"space_id"`
Namespace types.String `tfsdk:"namespace"`
Schedule types.Int64 `tfsdk:"schedule"`
Locations []types.String `tfsdk:"locations"`
PrivateLocations []types.String `tfsdk:"private_locations"`
Expand Down Expand Up @@ -151,6 +152,15 @@ func monitorConfigSchema() schema.Schema {
},
Computed: true,
},
"namespace": schema.StringAttribute{
MarkdownDescription: "The data stream namespace. If not specified, defaults to the value of space_id. The namespace must be lowercase and not contain spaces. The namespace must not include any of the following characters: *, \\, /, ?, \", <, >, |, whitespace, ,, #, :, or -.",
Optional: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
stringplanmodifier.RequiresReplace(),
},
Computed: true,
},
"schedule": schema.Int64Attribute{
Optional: true,
MarkdownDescription: "The monitor’s schedule in minutes. Supported values are 1, 3, 5, 10, 15, 30, 60, 120 and 240.",
Expand Down Expand Up @@ -653,6 +663,7 @@ func (v *tfModelV0) toModelV0(ctx context.Context, api *kbapi.SyntheticsMonitor)
ID: types.StringValue(resourceID.String()),
Name: types.StringValue(api.Name),
SpaceID: types.StringValue(api.Namespace),
Namespace: types.StringValue(api.Namespace),
Schedule: types.Int64Value(schedule),
Locations: v.Locations,
PrivateLocations: StringSliceValue(privateLocLabels),
Expand Down Expand Up @@ -873,6 +884,12 @@ func (v *tfModelV0) toSyntheticsMonitorConfig(ctx context.Context) (*kbapi.Synth
return nil, dg
}

// Use namespace if explicitly set, otherwise fall back to space_id
namespace := v.Namespace.ValueString()
if namespace == "" || v.Namespace.IsNull() || v.Namespace.IsUnknown() {
namespace = v.SpaceID.ValueString()
}

return &kbapi.SyntheticsMonitorConfig{
Name: v.Name.ValueString(),
Schedule: kbapi.MonitorSchedule(v.Schedule.ValueInt64()),
Expand All @@ -883,7 +900,7 @@ func (v *tfModelV0) toSyntheticsMonitorConfig(ctx context.Context) (*kbapi.Synth
Alert: toTFAlertConfig(ctx, v.Alert),
APMServiceName: v.APMServiceName.ValueString(),
TimeoutSeconds: int(v.TimeoutSeconds.ValueInt64()),
Namespace: v.SpaceID.ValueString(),
Namespace: namespace,
Params: params,
RetestOnFailure: v.RetestOnFailure.ValueBoolPointer(),
}, diag.Diagnostics{} //dg
Expand Down
15 changes: 15 additions & 0 deletions internal/kibana/synthetics/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ func TestToModelV0(t *testing.T) {
ID: types.StringValue("/"),
Name: types.StringValue(""),
SpaceID: types.StringValue(""),
Namespace: types.StringValue(""),
Schedule: types.Int64Value(0),
APMServiceName: types.StringValue(""),
TimeoutSeconds: types.Int64Value(0),
Expand Down Expand Up @@ -83,6 +84,7 @@ func TestToModelV0(t *testing.T) {
ID: types.StringValue("/"),
Name: types.StringValue(""),
SpaceID: types.StringValue(""),
Namespace: types.StringValue(""),
Schedule: types.Int64Value(0),
APMServiceName: types.StringValue(""),
TimeoutSeconds: types.Int64Value(0),
Expand Down Expand Up @@ -111,6 +113,7 @@ func TestToModelV0(t *testing.T) {
ID: types.StringValue("/"),
Name: types.StringValue(""),
SpaceID: types.StringValue(""),
Namespace: types.StringValue(""),
Schedule: types.Int64Value(0),
APMServiceName: types.StringValue(""),
TimeoutSeconds: types.Int64Value(0),
Expand All @@ -130,6 +133,7 @@ func TestToModelV0(t *testing.T) {
ID: types.StringValue("/"),
Name: types.StringValue(""),
SpaceID: types.StringValue(""),
Namespace: types.StringValue(""),
Schedule: types.Int64Value(0),
APMServiceName: types.StringValue(""),
TimeoutSeconds: types.Int64Value(0),
Expand Down Expand Up @@ -191,6 +195,7 @@ func TestToModelV0(t *testing.T) {
ID: types.StringValue("default/test-id-http"),
Name: types.StringValue("test-name-http"),
SpaceID: types.StringValue("default"),
Namespace: types.StringValue("default"),
Schedule: types.Int64Value(5),
Locations: []types.String{types.StringValue("us_east")},
PrivateLocations: []types.String{types.StringValue("test private location")},
Expand Down Expand Up @@ -261,6 +266,7 @@ func TestToModelV0(t *testing.T) {
ID: types.StringValue("default/test-id-tcp"),
Name: types.StringValue("test-name-tcp"),
SpaceID: types.StringValue("default"),
Namespace: types.StringValue("default"),
Schedule: types.Int64Value(5),
Locations: nil,
PrivateLocations: []types.String{types.StringValue("test private location")},
Expand Down Expand Up @@ -320,6 +326,7 @@ func TestToModelV0(t *testing.T) {
ID: types.StringValue("default/test-id-icmp"),
Name: types.StringValue("test-name-icmp"),
SpaceID: types.StringValue("default"),
Namespace: types.StringValue("default"),
Schedule: types.Int64Value(5),
Locations: nil,
PrivateLocations: []types.String{types.StringValue("test private location")},
Expand Down Expand Up @@ -375,6 +382,7 @@ func TestToModelV0(t *testing.T) {
ID: types.StringValue("default/test-id-browser"),
Name: types.StringValue("test-name-browser"),
SpaceID: types.StringValue("default"),
Namespace: types.StringValue("default"),
Schedule: types.Int64Value(5),
Locations: nil,
PrivateLocations: []types.String{types.StringValue("test private location")},
Expand Down Expand Up @@ -457,6 +465,7 @@ func TestToKibanaAPIRequest(t *testing.T) {
ID: types.StringValue("test-id-http"),
Name: types.StringValue("test-name-http"),
SpaceID: types.StringValue("default"),
Namespace: types.StringValue("default"),
Schedule: types.Int64Value(5),
Locations: []types.String{types.StringValue("us_east")},
PrivateLocations: []types.String{types.StringValue("test private location")},
Expand Down Expand Up @@ -533,6 +542,7 @@ func TestToKibanaAPIRequest(t *testing.T) {
ID: types.StringValue("test-id-tcp"),
Name: types.StringValue("test-name-tcp"),
SpaceID: types.StringValue("default"),
Namespace: types.StringValue("default"),
Schedule: types.Int64Value(5),
Locations: []types.String{types.StringValue("us_east")},
PrivateLocations: nil,
Expand Down Expand Up @@ -597,6 +607,7 @@ func TestToKibanaAPIRequest(t *testing.T) {
ID: types.StringValue("test-id-icmp"),
Name: types.StringValue("test-name-icmp"),
SpaceID: types.StringValue("default"),
Namespace: types.StringValue("default"),
Schedule: types.Int64Value(5),
Locations: []types.String{types.StringValue("us_east")},
PrivateLocations: nil,
Expand Down Expand Up @@ -637,6 +648,7 @@ func TestToKibanaAPIRequest(t *testing.T) {
ID: types.StringValue("test-id-browser"),
Name: types.StringValue("test-name-browser"),
SpaceID: types.StringValue("default"),
Namespace: types.StringValue("default"),
Schedule: types.Int64Value(5),
Locations: []types.String{types.StringValue("us_east")},
PrivateLocations: nil,
Expand Down Expand Up @@ -722,6 +734,7 @@ func TestToModelV0MergeAttributes(t *testing.T) {
ID: types.StringValue("/"),
Name: types.StringValue(""),
SpaceID: types.StringValue(""),
Namespace: types.StringValue(""),
Schedule: types.Int64Value(0),
APMServiceName: types.StringValue(""),
TimeoutSeconds: types.Int64Value(0),
Expand Down Expand Up @@ -767,6 +780,7 @@ func TestToModelV0MergeAttributes(t *testing.T) {
ID: types.StringValue("/"),
Name: types.StringValue(""),
SpaceID: types.StringValue(""),
Namespace: types.StringValue(""),
Schedule: types.Int64Value(0),
APMServiceName: types.StringValue(""),
TimeoutSeconds: types.Int64Value(0),
Expand Down Expand Up @@ -801,6 +815,7 @@ func TestToModelV0MergeAttributes(t *testing.T) {
ID: types.StringValue("/"),
Name: types.StringValue(""),
SpaceID: types.StringValue(""),
Namespace: types.StringValue(""),
Schedule: types.Int64Value(0),
APMServiceName: types.StringValue(""),
TimeoutSeconds: types.Int64Value(0),
Expand Down
7 changes: 6 additions & 1 deletion internal/kibana/synthetics/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@ func (r *Resource) Update(ctx context.Context, request resource.UpdateRequest, r
return
}

namespace := plan.SpaceID.ValueString()
// Use namespace if explicitly set, otherwise fall back to space_id
namespace := plan.Namespace.ValueString()
if namespace == "" || plan.Namespace.IsNull() || plan.Namespace.IsUnknown() {
namespace = plan.SpaceID.ValueString()
}

result, err := kibanaClient.KibanaSynthetics.Monitor.Update(ctx, kbapi.MonitorID(monitorId.ResourceId), input.config, input.fields, namespace)
if err != nil {
response.Diagnostics.AddError(fmt.Sprintf("Failed to update Kibana monitor `%s`, namespace %s", input.config.Name, namespace), err.Error())
Expand Down
Loading