Skip to content

Commit c9b6a6b

Browse files
authored
fix: add namespace attribute to elasticstack_kibana_synthetics_monitor resource (elastic#1247)
It allows to support setting data stream namespace independently from `space_id`. Fixes elastic#1164. Fixes elastic#1131. Fixes elastic#1083. Based on elastic#1208
1 parent ecc383b commit c9b6a6b

File tree

15 files changed

+121
-234
lines changed

15 files changed

+121
-234
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
- Add `slo_id` validation to `elasticstack_kibana_slo` ([#1221](https://github.com/elastic/terraform-provider-elasticstack/pull/1221))
44
- Add `ignore_missing_component_templates` to `elasticstack_elasticsearch_index_template` ([#1206](https://github.com/elastic/terraform-provider-elasticstack/pull/1206))
55
- Prevent provider panic when a script exists in state, but not in Elasticsearch ([#1218](https://github.com/elastic/terraform-provider-elasticstack/pull/1218))
6+
- 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))
67

78
## [0.11.17] - 2025-07-21
89

docs/resources/kibana_synthetics_monitor.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,13 @@ resource "elasticstack_kibana_synthetics_monitor" "my_monitor" {
7272
- `http` (Attributes) HTTP Monitor specific fields (see [below for nested schema](#nestedatt--http))
7373
- `icmp` (Attributes) ICMP Monitor specific fields (see [below for nested schema](#nestedatt--icmp))
7474
- `locations` (List of String) Where to deploy the monitor. Monitors can be deployed in multiple locations so that you can detect differences in availability and response times across those locations.
75+
- `namespace` (String) The data stream namespace. Note: if you change its value, kibana creates new datastream. A user needs permissions for new/old datastream in update case to be able to see full monitor history. The `namespace` field should be lowercase and not contain spaces. The namespace must not include any of the following characters: *, \, /, ?, ", <, >, |, whitespace, ,, #, :, or -. Default: `default`
7576
- `params` (String) Monitor parameters. Raw JSON object, use `jsonencode` function to represent JSON
7677
- `private_locations` (List of String) These Private Locations refer to locations hosted and managed by you, whereas locations are hosted by Elastic. You can specify a Private Location using the location’s name.
7778
- `retest_on_failure` (Boolean) Enable or disable retesting when a monitor fails. By default, monitors are automatically retested if the monitor goes from "up" to "down". If the result of the retest is also "down", an error will be created, and if configured, an alert sent. Then the monitor will resume running according to the defined schedule. Using retest_on_failure can reduce noise related to transient problems. Default: `true`.
7879
- `schedule` (Number) The monitor’s schedule in minutes. Supported values are 1, 3, 5, 10, 15, 30, 60, 120 and 240.
7980
- `service_name` (String) The APM service name.
80-
- `space_id` (String) The namespace field should be lowercase and not contain spaces. The namespace must not include any of the following characters: *, \, /, ?, ", <, >, |, whitespace, ,, #, :, or -. Default: `default`
81+
- `space_id` (String) Kibana space. The space ID that is part of the Kibana URL when inside the space. Space IDs are limited to lowercase alphanumeric, underscore, and hyphen characters (a-z, 0-9, _, and -). You are cannot change the ID with the update operation.
8182
- `tags` (List of String) An array of tags.
8283
- `tcp` (Attributes) TCP Monitor specific fields (see [below for nested schema](#nestedatt--tcp))
8384
- `timeout` (Number) The monitor timeout in seconds, monitor will fail if it doesn’t complete within this time. Default: `16`

internal/kibana/synthetics/acc_test.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ resource "elasticstack_kibana_synthetics_monitor" "%s" {
3232
resource "elasticstack_kibana_synthetics_monitor" "%s" {
3333
name = "TestHttpMonitorResource - %s"
3434
space_id = "testacc"
35+
namespace = "test_namespace"
3536
schedule = 5
3637
private_locations = [elasticstack_kibana_synthetics_private_location.%s.label]
3738
enabled = true
@@ -164,6 +165,7 @@ resource "elasticstack_kibana_synthetics_monitor" "%s" {
164165
resource "elasticstack_kibana_synthetics_monitor" "%s" {
165166
name = "TestTcpMonitorResource - %s"
166167
space_id = "testacc"
168+
namespace = "testacc_test"
167169
schedule = 5
168170
private_locations = [elasticstack_kibana_synthetics_private_location.%s.label]
169171
enabled = true
@@ -230,6 +232,7 @@ resource "elasticstack_kibana_synthetics_monitor" "%s" {
230232
resource "elasticstack_kibana_synthetics_monitor" "%s" {
231233
name = "TestIcmpMonitorResource - %s"
232234
space_id = "testacc"
235+
namespace = "testacc_namespace"
233236
schedule = 5
234237
private_locations = [elasticstack_kibana_synthetics_private_location.%s.label]
235238
enabled = true
@@ -279,6 +282,7 @@ resource "elasticstack_kibana_synthetics_monitor" "%s" {
279282
resource "elasticstack_kibana_synthetics_monitor" "%s" {
280283
name = "TestBrowserMonitorResource - %s"
281284
space_id = "testacc"
285+
namespace = "testacc_ns"
282286
schedule = 5
283287
private_locations = [elasticstack_kibana_synthetics_private_location.%s.label]
284288
enabled = true
@@ -363,7 +367,8 @@ func TestSyntheticMonitorHTTPResource(t *testing.T) {
363367
Check: resource.ComposeAggregateTestCheckFunc(
364368
resource.TestCheckResourceAttrSet(bmMonitorId, "id"),
365369
resource.TestCheckResourceAttr(bmMonitorId, "name", "TestHttpMonitorResource - "+bmName),
366-
resource.TestCheckResourceAttr(bmMonitorId, "space_id", "default"),
370+
resource.TestCheckResourceAttr(bmMonitorId, "space_id", ""),
371+
resource.TestCheckResourceAttr(bmMonitorId, "namespace", "default"),
367372
resource.TestCheckResourceAttr(bmMonitorId, "alert.status.enabled", "true"),
368373
resource.TestCheckResourceAttr(bmMonitorId, "alert.tls.enabled", "true"),
369374
resource.TestCheckResourceAttr(bmMonitorId, "http.url", "http://localhost:5601"),
@@ -376,7 +381,8 @@ func TestSyntheticMonitorHTTPResource(t *testing.T) {
376381
Check: resource.ComposeAggregateTestCheckFunc(
377382
resource.TestCheckResourceAttrSet(sslHttpMonitorId, "id"),
378383
resource.TestCheckResourceAttr(sslHttpMonitorId, "name", "TestHttpMonitorResource - "+sslName),
379-
resource.TestCheckResourceAttr(sslHttpMonitorId, "space_id", "default"),
384+
resource.TestCheckResourceAttr(sslHttpMonitorId, "space_id", ""),
385+
resource.TestCheckResourceAttr(sslHttpMonitorId, "namespace", "default"),
380386
resource.TestCheckResourceAttr(sslHttpMonitorId, "http.url", "http://localhost:5601"),
381387
resource.TestCheckResourceAttr(sslHttpMonitorId, "http.ssl_verification_mode", "full"),
382388
resource.TestCheckResourceAttr(sslHttpMonitorId, "http.ssl_supported_protocols.#", "1"),
@@ -405,6 +411,7 @@ func TestSyntheticMonitorHTTPResource(t *testing.T) {
405411
resource.TestCheckResourceAttrSet(httpMonitorId, "id"),
406412
resource.TestCheckResourceAttr(httpMonitorId, "name", "TestHttpMonitorResource - "+name),
407413
resource.TestCheckResourceAttr(httpMonitorId, "space_id", "testacc"),
414+
resource.TestCheckResourceAttr(httpMonitorId, "namespace", "test_namespace"),
408415
resource.TestCheckResourceAttr(httpMonitorId, "schedule", "5"),
409416
resource.TestCheckResourceAttr(httpMonitorId, "private_locations.#", "1"),
410417
resource.TestCheckResourceAttrSet(httpMonitorId, "private_locations.0"),
@@ -446,6 +453,7 @@ func TestSyntheticMonitorHTTPResource(t *testing.T) {
446453
resource.TestCheckResourceAttrSet(httpMonitorId, "id"),
447454
resource.TestCheckResourceAttr(httpMonitorId, "name", "TestHttpMonitorResource Updated - "+name),
448455
resource.TestCheckResourceAttr(httpMonitorId, "space_id", "testacc"),
456+
resource.TestCheckResourceAttr(httpMonitorId, "namespace", "test_namespace"),
449457
resource.TestCheckResourceAttr(httpMonitorId, "schedule", "10"),
450458
resource.TestCheckResourceAttr(httpMonitorId, "private_locations.#", "1"),
451459
resource.TestCheckResourceAttrSet(httpMonitorId, "private_locations.0"),
@@ -509,7 +517,8 @@ func TestSyntheticMonitorTCPResource(t *testing.T) {
509517
Check: resource.ComposeAggregateTestCheckFunc(
510518
resource.TestCheckResourceAttrSet(bmMonitorId, "id"),
511519
resource.TestCheckResourceAttr(bmMonitorId, "name", "TestTcpMonitorResource - "+bmName),
512-
resource.TestCheckResourceAttr(bmMonitorId, "space_id", "default"),
520+
resource.TestCheckResourceAttr(bmMonitorId, "space_id", ""),
521+
resource.TestCheckResourceAttr(bmMonitorId, "namespace", "default"),
513522
resource.TestCheckResourceAttr(bmMonitorId, "tcp.host", "http://localhost:5601"),
514523
resource.TestCheckResourceAttr(bmMonitorId, "alert.status.enabled", "true"),
515524
resource.TestCheckResourceAttr(bmMonitorId, "alert.tls.enabled", "true"),
@@ -523,7 +532,8 @@ func TestSyntheticMonitorTCPResource(t *testing.T) {
523532
Check: resource.ComposeAggregateTestCheckFunc(
524533
resource.TestCheckResourceAttrSet(sslTcpMonitorId, "id"),
525534
resource.TestCheckResourceAttr(sslTcpMonitorId, "name", "TestHttpMonitorResource - "+sslName),
526-
resource.TestCheckResourceAttr(sslTcpMonitorId, "space_id", "default"),
535+
resource.TestCheckResourceAttr(sslTcpMonitorId, "space_id", ""),
536+
resource.TestCheckResourceAttr(sslTcpMonitorId, "namespace", "default"),
527537
resource.TestCheckResourceAttr(sslTcpMonitorId, "tcp.host", "http://localhost:5601"),
528538
resource.TestCheckResourceAttr(sslTcpMonitorId, "tcp.ssl_verification_mode", "full"),
529539
resource.TestCheckResourceAttr(sslTcpMonitorId, "tcp.ssl_supported_protocols.#", "1"),
@@ -552,6 +562,7 @@ func TestSyntheticMonitorTCPResource(t *testing.T) {
552562
resource.TestCheckResourceAttrSet(tcpMonitorId, "id"),
553563
resource.TestCheckResourceAttr(tcpMonitorId, "name", "TestTcpMonitorResource - "+name),
554564
resource.TestCheckResourceAttr(tcpMonitorId, "space_id", "testacc"),
565+
resource.TestCheckResourceAttr(tcpMonitorId, "namespace", "testacc_test"),
555566
resource.TestCheckResourceAttr(tcpMonitorId, "schedule", "5"),
556567
resource.TestCheckResourceAttr(tcpMonitorId, "private_locations.#", "1"),
557568
resource.TestCheckResourceAttrSet(tcpMonitorId, "private_locations.0"),
@@ -590,6 +601,7 @@ func TestSyntheticMonitorTCPResource(t *testing.T) {
590601
resource.TestCheckResourceAttrSet(tcpMonitorId, "id"),
591602
resource.TestCheckResourceAttr(tcpMonitorId, "name", "TestTcpMonitorResource Updated - "+name),
592603
resource.TestCheckResourceAttr(tcpMonitorId, "space_id", "testacc"),
604+
resource.TestCheckResourceAttr(tcpMonitorId, "namespace", "testacc_test"),
593605
resource.TestCheckResourceAttr(tcpMonitorId, "schedule", "10"),
594606
resource.TestCheckResourceAttr(tcpMonitorId, "private_locations.#", "1"),
595607
resource.TestCheckResourceAttrSet(tcpMonitorId, "private_locations.0"),
@@ -643,7 +655,8 @@ func TestSyntheticMonitorICMPResource(t *testing.T) {
643655
Check: resource.ComposeAggregateTestCheckFunc(
644656
resource.TestCheckResourceAttrSet(bmMonitorId, "id"),
645657
resource.TestCheckResourceAttr(bmMonitorId, "name", "TestIcmpMonitorResource - "+bmName),
646-
resource.TestCheckResourceAttr(bmMonitorId, "space_id", "default"),
658+
resource.TestCheckResourceAttr(bmMonitorId, "space_id", ""),
659+
resource.TestCheckResourceAttr(bmMonitorId, "namespace", "default"),
647660
resource.TestCheckResourceAttr(bmMonitorId, "icmp.host", "localhost"),
648661
resource.TestCheckResourceAttr(bmMonitorId, "alert.status.enabled", "true"),
649662
resource.TestCheckResourceAttr(bmMonitorId, "alert.tls.enabled", "true"),
@@ -658,6 +671,7 @@ func TestSyntheticMonitorICMPResource(t *testing.T) {
658671
resource.TestCheckResourceAttrSet(icmpMonitorId, "id"),
659672
resource.TestCheckResourceAttr(icmpMonitorId, "name", "TestIcmpMonitorResource - "+name),
660673
resource.TestCheckResourceAttr(icmpMonitorId, "space_id", "testacc"),
674+
resource.TestCheckResourceAttr(icmpMonitorId, "namespace", "testacc_namespace"),
661675
resource.TestCheckResourceAttr(icmpMonitorId, "schedule", "5"),
662676
resource.TestCheckResourceAttr(icmpMonitorId, "private_locations.#", "1"),
663677
resource.TestCheckResourceAttrSet(icmpMonitorId, "private_locations.0"),
@@ -689,6 +703,7 @@ func TestSyntheticMonitorICMPResource(t *testing.T) {
689703
resource.TestCheckResourceAttrSet(icmpMonitorId, "id"),
690704
resource.TestCheckResourceAttr(icmpMonitorId, "name", "TestIcmpMonitorResource Updated - "+name),
691705
resource.TestCheckResourceAttr(icmpMonitorId, "space_id", "testacc"),
706+
resource.TestCheckResourceAttr(icmpMonitorId, "namespace", "testacc_namespace"),
692707
resource.TestCheckResourceAttr(icmpMonitorId, "schedule", "10"),
693708
resource.TestCheckResourceAttr(icmpMonitorId, "private_locations.#", "1"),
694709
resource.TestCheckResourceAttrSet(icmpMonitorId, "private_locations.0"),
@@ -735,7 +750,8 @@ func TestSyntheticMonitorBrowserResource(t *testing.T) {
735750
Check: resource.ComposeAggregateTestCheckFunc(
736751
resource.TestCheckResourceAttrSet(bmMonitorId, "id"),
737752
resource.TestCheckResourceAttr(bmMonitorId, "name", "TestBrowserMonitorResource - "+bmName),
738-
resource.TestCheckResourceAttr(bmMonitorId, "space_id", "default"),
753+
resource.TestCheckResourceAttr(bmMonitorId, "space_id", ""),
754+
resource.TestCheckResourceAttr(bmMonitorId, "namespace", "default"),
739755
resource.TestCheckResourceAttr(bmMonitorId, "browser.inline_script", "step('Go to https://google.com.co', () => page.goto('https://www.google.com'))"),
740756
resource.TestCheckResourceAttr(bmMonitorId, "alert.status.enabled", "true"),
741757
resource.TestCheckResourceAttr(bmMonitorId, "alert.tls.enabled", "true"),
@@ -749,6 +765,7 @@ func TestSyntheticMonitorBrowserResource(t *testing.T) {
749765
resource.TestCheckResourceAttrSet(browserMonitorId, "id"),
750766
resource.TestCheckResourceAttr(browserMonitorId, "name", "TestBrowserMonitorResource - "+name),
751767
resource.TestCheckResourceAttr(browserMonitorId, "space_id", "testacc"),
768+
resource.TestCheckResourceAttr(browserMonitorId, "namespace", "testacc_ns"),
752769
resource.TestCheckResourceAttr(browserMonitorId, "schedule", "5"),
753770
resource.TestCheckResourceAttr(browserMonitorId, "private_locations.#", "1"),
754771
resource.TestCheckResourceAttrSet(browserMonitorId, "private_locations.0"),
@@ -780,6 +797,7 @@ func TestSyntheticMonitorBrowserResource(t *testing.T) {
780797
resource.TestCheckResourceAttrSet(browserMonitorId, "id"),
781798
resource.TestCheckResourceAttr(browserMonitorId, "name", "TestBrowserMonitorResource Updated - "+name),
782799
resource.TestCheckResourceAttr(browserMonitorId, "space_id", "testacc"),
800+
resource.TestCheckResourceAttr(browserMonitorId, "namespace", "testacc_ns"),
783801
resource.TestCheckResourceAttr(browserMonitorId, "schedule", "10"),
784802
resource.TestCheckResourceAttr(browserMonitorId, "private_locations.#", "1"),
785803
resource.TestCheckResourceAttrSet(browserMonitorId, "private_locations.0"),

internal/kibana/synthetics/create.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package synthetics
33
import (
44
"context"
55
"fmt"
6+
67
"github.com/hashicorp/terraform-plugin-framework/resource"
78
)
89

@@ -26,14 +27,14 @@ func (r *Resource) Create(ctx context.Context, request resource.CreateRequest, r
2627
return
2728
}
2829

29-
namespace := plan.SpaceID.ValueString()
30-
result, err := kibanaClient.KibanaSynthetics.Monitor.Add(ctx, input.config, input.fields, namespace)
30+
spaceId := plan.SpaceID.ValueString()
31+
result, err := kibanaClient.KibanaSynthetics.Monitor.Add(ctx, input.config, input.fields, spaceId)
3132
if err != nil {
32-
response.Diagnostics.AddError(fmt.Sprintf("Failed to create Kibana monitor `%s`, namespace %s", input.config.Name, namespace), err.Error())
33+
response.Diagnostics.AddError(fmt.Sprintf("Failed to create Kibana monitor `%s`, space %s", input.config.Name, spaceId), err.Error())
3334
return
3435
}
3536

36-
plan, diags = plan.toModelV0(ctx, result)
37+
plan, diags = plan.toModelV0(ctx, result, spaceId)
3738
response.Diagnostics.Append(diags...)
3839
if response.Diagnostics.HasError() {
3940
return

internal/kibana/synthetics/read.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
78
"github.com/disaster37/go-kibana-rest/v8/kbapi"
89
"github.com/hashicorp/terraform-plugin-framework/resource"
910
)
@@ -28,21 +29,21 @@ func (r *Resource) Read(ctx context.Context, request resource.ReadRequest, respo
2829
return
2930
}
3031

31-
namespace := compositeId.ClusterId
32+
spaceId := compositeId.ClusterId
3233
monitorId := kbapi.MonitorID(compositeId.ResourceId)
33-
result, err := kibanaClient.KibanaSynthetics.Monitor.Get(ctx, monitorId, namespace)
34+
result, err := kibanaClient.KibanaSynthetics.Monitor.Get(ctx, monitorId, spaceId)
3435
if err != nil {
3536
var apiError *kbapi.APIError
3637
if errors.As(err, &apiError) && apiError.Code == 404 {
3738
response.State.RemoveResource(ctx)
3839
return
3940
}
4041

41-
response.Diagnostics.AddError(fmt.Sprintf("Failed to get monitor `%s`, namespace %s", monitorId, namespace), err.Error())
42+
response.Diagnostics.AddError(fmt.Sprintf("Failed to get monitor `%s`, space %s", monitorId, spaceId), err.Error())
4243
return
4344
}
4445

45-
state, diags = state.toModelV0(ctx, result)
46+
state, diags = state.toModelV0(ctx, result, spaceId)
4647
response.Diagnostics.Append(diags...)
4748
if response.Diagnostics.HasError() {
4849
return

0 commit comments

Comments
 (0)