Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 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 = "testnamespace"
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", "testnamespace"),
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,
},
},
})
}
1 change: 1 addition & 0 deletions internal/kibana/synthetics/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func (r *Resource) Create(ctx context.Context, request resource.CreateRequest, r
}

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
8 changes: 4 additions & 4 deletions internal/kibana/synthetics/parameter/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func Test_roundtrip(t *testing.T) {
{
name: "only required fields",
id: "id-1",
namespaces: []string{"ns-1"},
namespaces: []string{"ns1"},
request: kboapi.SyntheticsParameterRequest{
Key: "key-1",
Value: "value-1",
Expand All @@ -39,7 +39,7 @@ func Test_roundtrip(t *testing.T) {
{
name: "only description",
id: "id-3",
namespaces: []string{"ns-3"},
namespaces: []string{"ns3"},
request: kboapi.SyntheticsParameterRequest{
Key: "key-3",
Value: "value-3",
Expand All @@ -49,7 +49,7 @@ func Test_roundtrip(t *testing.T) {
{
name: "only tags",
id: "id-4",
namespaces: []string{"ns-4"},
namespaces: []string{"ns4"},
request: kboapi.SyntheticsParameterRequest{
Key: "key-4",
Value: "value-4",
Expand All @@ -59,7 +59,7 @@ func Test_roundtrip(t *testing.T) {
{
name: "all namespaces",
id: "id-5",
namespaces: []string{"ns-5"},
namespaces: []string{"ns5"},
request: kboapi.SyntheticsParameterRequest{
Key: "key-5",
Value: "value-5",
Expand Down
26 changes: 25 additions & 1 deletion internal/kibana/synthetics/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"regexp"
"strconv"

"github.com/disaster37/go-kibana-rest/v8/kbapi"
Expand Down Expand Up @@ -99,6 +100,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 +153,21 @@ 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(),
},
Validators: []validator.String{
stringvalidator.RegexMatches(
regexp.MustCompile(`^[^*\\/?\"<>|\s,#:-]*$`),
"namespace must not contain any of the following characters: *, \\, /, ?, \", <, >, |, whitespace, ,, #, :, or -",
),
},
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 +670,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 +891,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 +907,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
1 change: 1 addition & 0 deletions internal/kibana/synthetics/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func (r *Resource) Update(ctx context.Context, request resource.UpdateRequest, r
}

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