Skip to content

Commit 1fd2410

Browse files
synthetic monitoring: add support for browser checks (#1924)
1 parent 01204c5 commit 1fd2410

File tree

6 files changed

+178
-2
lines changed

6 files changed

+178
-2
lines changed

docs/resources/synthetic_monitoring_check.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ resource "grafana_synthetic_monitoring_check" "traceroute" {
438438

439439
Optional:
440440

441+
- `browser` (Block Set, Max: 1) Settings for browser check. See https://grafana.com/docs/grafana-cloud/testing/synthetic-monitoring/create-checks/checks/k6-browser/. (see [below for nested schema](#nestedblock--settings--browser))
441442
- `dns` (Block Set, Max: 1) Settings for DNS check. The target must be a valid hostname (or IP address for `PTR` records). (see [below for nested schema](#nestedblock--settings--dns))
442443
- `grpc` (Block Set, Max: 1) Settings for gRPC Health check. The target must be of the form `<host>:<port>`, where the host portion must be a valid hostname or IP address. (see [below for nested schema](#nestedblock--settings--grpc))
443444
- `http` (Block Set, Max: 1) Settings for HTTP check. The target must be a URL (http or https). (see [below for nested schema](#nestedblock--settings--http))
@@ -447,6 +448,14 @@ Optional:
447448
- `tcp` (Block Set, Max: 1) Settings for TCP check. The target must be of the form `<host>:<port>`, where the host portion must be a valid hostname or IP address. (see [below for nested schema](#nestedblock--settings--tcp))
448449
- `traceroute` (Block Set, Max: 1) Settings for traceroute check. The target must be a valid hostname or IP address (see [below for nested schema](#nestedblock--settings--traceroute))
449450

451+
<a id="nestedblock--settings--browser"></a>
452+
### Nested Schema for `settings.browser`
453+
454+
Required:
455+
456+
- `script` (String)
457+
458+
450459
<a id="nestedblock--settings--dns"></a>
451460
### Nested Schema for `settings.dns`
452461

@@ -884,6 +893,31 @@ resource "grafana_synthetic_monitoring_check" "scripted" {
884893
}
885894
```
886895

896+
### Browser Basic
897+
898+
```terraform
899+
data "grafana_synthetic_monitoring_probes" "main" {}
900+
901+
resource "grafana_synthetic_monitoring_check" "browser" {
902+
job = "Validate login"
903+
target = "https://test.k6.io"
904+
enabled = true
905+
probes = [
906+
data.grafana_synthetic_monitoring_probes.main.probes.Paris,
907+
]
908+
labels = {
909+
environment = "production"
910+
}
911+
settings {
912+
browser {
913+
// `browser_script.js` is a file in the same directory as this file and contains the
914+
// script to be executed.
915+
script = file("${path.module}/browser_script.js")
916+
}
917+
}
918+
}
919+
```
920+
887921
### gRPC Health Check Basic
888922

889923
```terraform
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
data "grafana_synthetic_monitoring_probes" "main" {}
2+
3+
resource "grafana_synthetic_monitoring_check" "browser" {
4+
job = "Validate login"
5+
target = "https://test.k6.io"
6+
enabled = true
7+
probes = [
8+
data.grafana_synthetic_monitoring_probes.main.probes.Paris,
9+
]
10+
labels = {
11+
environment = "production"
12+
}
13+
settings {
14+
browser {
15+
// `browser_script.js` is a file in the same directory as this file and contains the
16+
// script to be executed.
17+
script = file("${path.module}/browser_script.js")
18+
}
19+
}
20+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { browser } from 'k6/browser';
2+
import { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';
3+
4+
export const options = {
5+
scenarios: {
6+
ui: {
7+
executor: 'shared-iterations',
8+
options: {
9+
browser: {
10+
type: 'chromium',
11+
},
12+
},
13+
},
14+
},
15+
thresholds: {
16+
checks: ['rate==1.0'],
17+
},
18+
};
19+
20+
export default async function () {
21+
const context = await browser.newContext();
22+
const page = await context.newPage();
23+
24+
try {
25+
await page.goto("https://test.k6.io/my_messages.php");
26+
27+
await page.locator('input[name="login"]').type("admin");
28+
await page.locator('input[name="password"]').type("123");
29+
30+
await Promise.all([
31+
page.waitForNavigation(),
32+
page.locator('input[type="submit"]').click(),
33+
]);
34+
35+
await check(page.locator("h2"), {
36+
header: async (locator) => (await locator.textContent()) == "Welcome, admin!",
37+
});
38+
} finally {
39+
await page.close();
40+
}
41+
}

internal/resources/syntheticmonitoring/resource_check.go

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@ var (
134134
MaxItems: 1,
135135
Elem: syntheticMonitoringCheckSettingsGRPC,
136136
},
137+
"browser": {
138+
Description: "Settings for browser check. See https://grafana.com/docs/grafana-cloud/testing/synthetic-monitoring/create-checks/checks/k6-browser/.",
139+
Type: schema.TypeSet,
140+
Optional: true,
141+
MaxItems: 1,
142+
Elem: syntheticMonitoringCheckSettingsBrowser,
143+
},
137144
},
138145
}
139146

@@ -147,6 +154,16 @@ var (
147154
},
148155
}
149156

157+
syntheticMonitoringCheckSettingsBrowser = &schema.Resource{
158+
Schema: map[string]*schema.Schema{
159+
"script": {
160+
Type: schema.TypeString,
161+
Optional: false,
162+
Required: true,
163+
},
164+
},
165+
}
166+
150167
syntheticMonitoringCheckSettingsDNS = &schema.Resource{
151168
Schema: map[string]*schema.Schema{
152169
"ip_version": syntheticMonitoringCheckIPVersion,
@@ -737,7 +754,7 @@ multiple checks for a single endpoint to check different capabilities.
737754
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
738755
// Suppress diff if it's a multihttp check with a timeout of 5000 (default timeout for those)
739756
// and it's being changed to 3000 (default timeout set here).
740-
doSuppress := d.Get("settings.0.multihttp.0") != nil || d.Get("settings.0.scripted") != nil
757+
doSuppress := d.Get("settings.0.multihttp.0") != nil || d.Get("settings.0.scripted") != nil || d.Get("settings.0.browser") != nil
741758
if doSuppress &&
742759
old == strconv.Itoa(checkMultiHTTPDefaultTimeout) &&
743760
new == strconv.Itoa(checkDefaultTimeout) {
@@ -837,6 +854,7 @@ func resourceCheckCreate(ctx context.Context, d *schema.ResourceData, c *smapi.C
837854
return resourceCheckRead(ctx, d, c)
838855
}
839856

857+
//nolint:gocyclo
840858
func resourceCheckRead(ctx context.Context, d *schema.ResourceData, c *smapi.Client) diag.Diagnostics {
841859
id, err := resourceCheckID.Single(d.Id())
842860
if err != nil {
@@ -1160,6 +1178,17 @@ func resourceCheckRead(ctx context.Context, d *schema.ResourceData, c *smapi.Cli
11601178
settings.Add(map[string]interface{}{
11611179
"grpc": grpc,
11621180
})
1181+
case chk.Settings.Browser != nil:
1182+
browser := schema.NewSet(
1183+
schema.HashResource(syntheticMonitoringCheckSettingsBrowser),
1184+
[]any{},
1185+
)
1186+
browser.Add(map[string]any{
1187+
"script": string(chk.Settings.Browser.Script),
1188+
})
1189+
settings.Add(map[string]any{
1190+
"browser": browser,
1191+
})
11631192
}
11641193

11651194
d.Set("settings", settings)
@@ -1215,7 +1244,7 @@ func makeCheck(d *schema.ResourceData) (*sm.Check, error) {
12151244
}
12161245

12171246
timeout := int64(d.Get("timeout").(int))
1218-
if timeout == checkDefaultTimeout && (settings.Multihttp != nil || settings.Scripted != nil) {
1247+
if timeout == checkDefaultTimeout && (settings.Multihttp != nil || settings.Scripted != nil || settings.Browser != nil) {
12191248
timeout = checkMultiHTTPDefaultTimeout
12201249
}
12211250

@@ -1601,6 +1630,14 @@ func makeCheckSettings(settings map[string]interface{}) (sm.CheckSettings, error
16011630
}
16021631
}
16031632

1633+
browser := settings["browser"].(*schema.Set).List()
1634+
if len(browser) > 0 {
1635+
s := browser[0].(map[string]interface{})
1636+
cs.Browser = &sm.BrowserSettings{
1637+
Script: []byte(s["script"].(string)),
1638+
}
1639+
}
1640+
16041641
return cs, nil
16051642
}
16061643

internal/resources/syntheticmonitoring/resource_check_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,46 @@ func TestAccResourceCheck_scripted(t *testing.T) {
440440
})
441441
}
442442

443+
func TestAccResourceCheck_browser(t *testing.T) {
444+
testutils.CheckCloudInstanceTestsEnabled(t)
445+
446+
// Find and replace the path.module since it's not available in the test environment
447+
scriptFilepathAbs, err := filepath.Abs("../../../examples/resources/grafana_synthetic_monitoring_check")
448+
require.NoError(t, err)
449+
scriptFileContent, err := os.ReadFile(filepath.Join(scriptFilepathAbs, "browser_script.js"))
450+
require.NoError(t, err)
451+
452+
// Inject random job names to avoid conflicts with other tests
453+
jobName := acctest.RandomWithPrefix("browser")
454+
nameReplaceMap := map[string]string{
455+
`"Validate login"`: strconv.Quote(jobName),
456+
"${path.module}": scriptFilepathAbs,
457+
}
458+
resource.ParallelTest(t, resource.TestCase{
459+
ProtoV5ProviderFactories: testutils.ProtoV5ProviderFactories,
460+
Steps: []resource.TestStep{
461+
{
462+
Config: testutils.TestAccExampleWithReplace(t, "resources/grafana_synthetic_monitoring_check/browser_basic.tf", nameReplaceMap),
463+
Check: resource.ComposeTestCheckFunc(
464+
resource.TestCheckResourceAttrSet("grafana_synthetic_monitoring_check.browser", "id"),
465+
resource.TestCheckResourceAttrSet("grafana_synthetic_monitoring_check.browser", "tenant_id"),
466+
resource.TestCheckResourceAttr("grafana_synthetic_monitoring_check.browser", "job", jobName),
467+
resource.TestCheckResourceAttr("grafana_synthetic_monitoring_check.browser", "target", "https://test.k6.io"),
468+
resource.TestCheckResourceAttr("grafana_synthetic_monitoring_check.browser", "timeout", "5000"), // browser has a default timeout of 5000
469+
resource.TestCheckResourceAttrSet("grafana_synthetic_monitoring_check.browser", "probes.0"),
470+
resource.TestCheckResourceAttr("grafana_synthetic_monitoring_check.browser", "labels.environment", "production"),
471+
resource.TestCheckResourceAttr("grafana_synthetic_monitoring_check.browser", "settings.0.browser.0.script", string(scriptFileContent)),
472+
),
473+
},
474+
{
475+
ImportState: true,
476+
ImportStateVerify: true,
477+
ResourceName: "grafana_synthetic_monitoring_check.browser",
478+
},
479+
},
480+
})
481+
}
482+
443483
func TestAccResourceCheck_grpc(t *testing.T) {
444484
testutils.CheckCloudInstanceTestsEnabled(t)
445485

templates/resources/synthetic_monitoring_check.md.tmpl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ description: |-
6666

6767
{{ tffile "examples/resources/grafana_synthetic_monitoring_check/scripted_basic.tf" }}
6868

69+
### Browser Basic
70+
71+
{{ tffile "examples/resources/grafana_synthetic_monitoring_check/browser_basic.tf" }}
72+
6973
### gRPC Health Check Basic
7074

7175
{{ tffile "examples/resources/grafana_synthetic_monitoring_check/grpc_basic.tf" }}

0 commit comments

Comments
 (0)