Rebrand: Sentry -> Cairn OBS

Full rebrand across cosmetic branding, code identifiers, and
infrastructure/data-plane naming, using the supplied Cairn OBS logo
package. Cosmetic: favicon/logo swap (also closes a stale license-audit
finding -- the old favicon was SvelteKit's unreplaced scaffold logo),
new centered welcome landing page, larger/legible sidebar logo, page
titles, CLAUDE.md/README/docs prose.

Code identifiers: Go module path github.com/sentry/sentry ->
github.com/cairnobs/cairnobs across all 13 modules and ~91 files (protoc
regenerated); Rust crates sentry-agent/sentry-parser/sentry-search ->
cairnobs-*; CLI sentryctl -> cairnobsctl; Terraform provider fully
renamed (sentry_dashboard etc. -> cairnobs_dashboard, provider type,
env vars); every session/auth cookie name; agent config paths and
Windows service identity.

Deliberately preserved: the gRPC wire protocol's protobuf packages
(sentry.logs.v1, sentry.agent.v1) and their Go import directory
(proto/sentry/...) -- renaming the wire-level package would break every
currently-deployed agent binary (confirmed two real hosts, including
mail.inbuxa.com, are actively streaming through this exact contract)
until rebuilt and redeployed in lockstep with an ingest cutover. Only
the Go module path wrapping the generated code changes.

Infrastructure: every docker-compose container name (root and three
component-level compose files); the Helm chart (directory, Chart.yaml,
named-template helpers, all templates, values.yaml image repos);
Kubernetes Operator (CRD group sentry.io -> cairnobs.io, both CRD YAML
files, Go identifiers, RBAC markers); the coupled enterprise/tenantcrd
package. Caught and fixed real path-coupling bugs along the way: the
Helm chart's search/ingest volume mounts and the dev-only-credential
detection constant vs. docker-compose.yml's literal values had to move
together or a security warning would have silently stopped firing.

Data plane: Postgres database sentry_metadata -> cairnobs_metadata and
role sentry -> cairnobs; ClickHouse database sentry -> cairnobs; Kafka
topic sentry.logs.raw -> cairnobs.logs.raw and its consumer groups.
Source-level defaults, docker-compose.yml, and every migrate.sh/
provision script default updated together; already-applied migration
files left untouched per this repo's immutable-migration convention.

Verified at every layer: all 13 Go modules build/vet/test clean, both
Rust workspaces (agent, search) build/clippy/test clean, npm run check/
build clean, docker compose config validates on all four compose files.
Live-verified against a real docker stack multiple times through this
work, including a final fresh-volume run confirming the actual renamed
Postgres database/role, ClickHouse database, and Kafka topic all work
end to end with a real login and query, zero console errors.
This commit is contained in:
2026-08-21 20:53:32 -07:00
parent 9e21ea17bb
commit 13cf9a30cb
291 changed files with 1565 additions and 1441 deletions
@@ -31,7 +31,7 @@ func (d *alertRuleDataSource) Metadata(_ context.Context, req datasource.Metadat
func (d *alertRuleDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Looks up an existing Sentry alert rule by ID. See the sentry_alert_rule resource for how one is created/managed.",
Description: "Looks up an existing Cairn OBS alert rule by ID. See the cairnobs_alert_rule resource for how one is created/managed.",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Required: true,
@@ -15,12 +15,12 @@ func TestAccAlertRuleDataSource_basic(t *testing.T) {
Steps: []resource.TestStep{
{
Config: `
provider "sentry" {
provider "cairnobs" {
endpoint = "http://localhost:8080"
alerting_endpoint = "http://localhost:8081"
}
resource "sentry_alert_rule" "test" {
resource "cairnobs_alert_rule" "test" {
name = "Data Source Test Rule"
query = "status>=500 | stats count"
condition_type = "threshold"
@@ -30,14 +30,14 @@ resource "sentry_alert_rule" "test" {
notification_target_id = "placeholder-target-id"
}
data "sentry_alert_rule" "test" {
id = sentry_alert_rule.test.id
data "cairnobs_alert_rule" "test" {
id = cairnobs_alert_rule.test.id
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair("data.sentry_alert_rule.test", "name", "sentry_alert_rule.test", "name"),
resource.TestCheckResourceAttrPair("data.sentry_alert_rule.test", "query", "sentry_alert_rule.test", "query"),
resource.TestCheckResourceAttrPair("data.sentry_alert_rule.test", "threshold_value", "sentry_alert_rule.test", "threshold_value"),
resource.TestCheckResourceAttrPair("data.cairnobs_alert_rule.test", "name", "cairnobs_alert_rule.test", "name"),
resource.TestCheckResourceAttrPair("data.cairnobs_alert_rule.test", "query", "cairnobs_alert_rule.test", "query"),
resource.TestCheckResourceAttrPair("data.cairnobs_alert_rule.test", "threshold_value", "cairnobs_alert_rule.test", "threshold_value"),
),
},
},
@@ -28,7 +28,7 @@ func newAlertRuleResource() resource.Resource {
return &alertRuleResource{}
}
// alertRuleResource implements sentry_alert_rule against
// alertRuleResource implements cairnobs_alert_rule against
// alerting/internal/httpapi's POST/GET/DELETE /rules[/{id}] endpoints.
//
// Deliberately create/destroy only, every attribute RequiresReplace:
@@ -70,7 +70,7 @@ func (r *alertRuleResource) Metadata(_ context.Context, req resource.MetadataReq
func (r *alertRuleResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
replace := []planmodifier.String{stringplanmodifier.RequiresReplace()}
resp.Schema = schema.Schema{
Description: "A Sentry alert rule. Create/destroy only -- alerting has no update endpoint for " +
Description: "A Cairn OBS alert rule. Create/destroy only -- alerting has no update endpoint for " +
"rules today (see this resource's Go doc comment), so every attribute below forces a " +
"destroy-and-recreate on change, never an in-place update.",
Attributes: map[string]schema.Attribute{
@@ -141,7 +141,7 @@ func (r *alertRuleResource) Schema(_ context.Context, _ resource.SchemaRequest,
"notification_target_id": schema.StringAttribute{
Required: true,
PlanModifiers: replace,
Description: "ID of a sentry_notification_target-managed (or manually created) notification target. The API rejects an empty string. No sentry_notification_target resource exists yet -- see the provider README -- so this has to be a target created some other way (sentryctl, curl, or the web UI) for now.",
Description: "ID of a cairnobs_notification_target-managed (or manually created) notification target. The API rejects an empty string. No cairnobs_notification_target resource exists yet -- see the provider README -- so this has to be a target created some other way (cairnobsctl, curl, or the web UI) for now.",
},
"enabled": schema.BoolAttribute{
Optional: true,
@@ -9,7 +9,7 @@ import (
// Same skip-gated-not-faked posture as TestAccDashboardResource_basic --
// see that test's doc comment. notification_target_id below is a
// placeholder: no sentry_notification_target resource exists yet (see
// placeholder: no cairnobs_notification_target resource exists yet (see
// the provider README), so a real run of this test would need a
// pre-existing target id supplied some other way; not a blocker for
// what this test actually proves, since it has never run against a
@@ -20,12 +20,12 @@ func TestAccAlertRuleResource_basic(t *testing.T) {
Steps: []resource.TestStep{
{
Config: `
provider "sentry" {
provider "cairnobs" {
endpoint = "http://localhost:8080"
alerting_endpoint = "http://localhost:8081"
}
resource "sentry_alert_rule" "test" {
resource "cairnobs_alert_rule" "test" {
name = "Acceptance Test Rule"
query = "status>=500 | stats count"
condition_type = "threshold"
@@ -36,18 +36,18 @@ resource "sentry_alert_rule" "test" {
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("sentry_alert_rule.test", "name", "Acceptance Test Rule"),
resource.TestCheckResourceAttr("sentry_alert_rule.test", "comparator", "gt"),
resource.TestCheckResourceAttr("sentry_alert_rule.test", "threshold_value", "5"),
resource.TestCheckResourceAttrSet("sentry_alert_rule.test", "id"),
resource.TestCheckResourceAttrSet("sentry_alert_rule.test", "tenant_id"),
resource.TestCheckResourceAttr("cairnobs_alert_rule.test", "name", "Acceptance Test Rule"),
resource.TestCheckResourceAttr("cairnobs_alert_rule.test", "comparator", "gt"),
resource.TestCheckResourceAttr("cairnobs_alert_rule.test", "threshold_value", "5"),
resource.TestCheckResourceAttrSet("cairnobs_alert_rule.test", "id"),
resource.TestCheckResourceAttrSet("cairnobs_alert_rule.test", "tenant_id"),
// Left unset in config -- must come back as the
// server's own default (true), same "API default,
// not a duplicated Terraform-side one" reasoning
// sentry_dashboard's default_earliest/default_latest
// cairnobs_dashboard's default_earliest/default_latest
// use.
resource.TestCheckResourceAttr("sentry_alert_rule.test", "enabled", "true"),
resource.TestCheckResourceAttr("sentry_alert_rule.test", "for_minutes", "0"),
resource.TestCheckResourceAttr("cairnobs_alert_rule.test", "enabled", "true"),
resource.TestCheckResourceAttr("cairnobs_alert_rule.test", "for_minutes", "0"),
),
},
{
@@ -57,12 +57,12 @@ resource "sentry_alert_rule" "test" {
// and changing one (here, the threshold) must plan a
// destroy-then-create, never an in-place update.
Config: `
provider "sentry" {
provider "cairnobs" {
endpoint = "http://localhost:8080"
alerting_endpoint = "http://localhost:8081"
}
resource "sentry_alert_rule" "test" {
resource "cairnobs_alert_rule" "test" {
name = "Acceptance Test Rule"
query = "status>=500 | stats count"
condition_type = "threshold"
@@ -74,13 +74,13 @@ resource "sentry_alert_rule" "test" {
`,
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectResourceAction("sentry_alert_rule.test", plancheck.ResourceActionDestroyBeforeCreate),
plancheck.ExpectResourceAction("cairnobs_alert_rule.test", plancheck.ResourceActionDestroyBeforeCreate),
},
},
Check: resource.TestCheckResourceAttr("sentry_alert_rule.test", "threshold_value", "10"),
Check: resource.TestCheckResourceAttr("cairnobs_alert_rule.test", "threshold_value", "10"),
},
{
ResourceName: "sentry_alert_rule.test",
ResourceName: "cairnobs_alert_rule.test",
ImportState: true,
ImportStateVerify: true,
},
+3 -3
View File
@@ -14,10 +14,10 @@ import (
// client is a thin HTTP client against api/dashboards.Handler's REST
// endpoints -- deliberately hand-rolled, not generated from an OpenAPI
// spec (none exists in this repo yet), the same "boring, well-
// understood" posture cli/cmd/sentryctl's own httpclient.go already
// understood" posture cli/cmd/cairnobsctl's own httpclient.go already
// takes against the same API. Kept separate from that package (not
// reused directly) since this one needs typed request/response
// marshaling for Terraform's plan/state model, where sentryctl only
// marshaling for Terraform's plan/state model, where cairnobsctl only
// ever needs to pretty-print whatever JSON comes back.
type client struct {
baseURL string
@@ -40,7 +40,7 @@ type apiError struct {
}
func (e *apiError) Error() string {
return fmt.Sprintf("sentry api: request failed with status %d: %s", e.StatusCode, e.Message)
return fmt.Sprintf("cairnobs api: request failed with status %d: %s", e.StatusCode, e.Message)
}
func isNotFound(err error) bool {
+1 -1
View File
@@ -11,7 +11,7 @@ import (
// TestCreateDashboardSendsExpectedRequest is the same "real
// httptest.Server, real HTTP round trip" pattern
// cli/cmd/sentryctl's own tests use against the same api/dashboards
// cli/cmd/cairnobsctl's own tests use against the same api/dashboards
// endpoints -- this client has no fake/mock mode, so its tests exercise
// real request construction and real response parsing throughout.
func TestCreateDashboardSendsExpectedRequest(t *testing.T) {
@@ -34,7 +34,7 @@ func (d *dashboardDataSource) Metadata(_ context.Context, req datasource.Metadat
func (d *dashboardDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Looks up an existing Sentry dashboard by ID. See the sentry_dashboard resource for how one is created/managed.",
Description: "Looks up an existing Cairn OBS dashboard by ID. See the cairnobs_dashboard resource for how one is created/managed.",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Required: true,
@@ -14,23 +14,23 @@ func TestAccDashboardDataSource_basic(t *testing.T) {
Steps: []resource.TestStep{
{
Config: `
provider "sentry" {
provider "cairnobs" {
endpoint = "http://localhost:8080"
}
resource "sentry_dashboard" "test" {
resource "cairnobs_dashboard" "test" {
name = "Data Source Test Dashboard"
description = "created by TestAccDashboardDataSource_basic"
}
data "sentry_dashboard" "test" {
id = sentry_dashboard.test.id
data "cairnobs_dashboard" "test" {
id = cairnobs_dashboard.test.id
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair("data.sentry_dashboard.test", "name", "sentry_dashboard.test", "name"),
resource.TestCheckResourceAttrPair("data.sentry_dashboard.test", "tenant_id", "sentry_dashboard.test", "tenant_id"),
resource.TestCheckResourceAttrPair("data.sentry_dashboard.test", "default_earliest", "sentry_dashboard.test", "default_earliest"),
resource.TestCheckResourceAttrPair("data.cairnobs_dashboard.test", "name", "cairnobs_dashboard.test", "name"),
resource.TestCheckResourceAttrPair("data.cairnobs_dashboard.test", "tenant_id", "cairnobs_dashboard.test", "tenant_id"),
resource.TestCheckResourceAttrPair("data.cairnobs_dashboard.test", "default_earliest", "cairnobs_dashboard.test", "default_earliest"),
),
},
},
@@ -32,11 +32,11 @@ func (d *dashboardPanelDataSource) Metadata(_ context.Context, req datasource.Me
func (d *dashboardPanelDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Looks up an existing Sentry dashboard panel by (dashboard_id, id). See the sentry_dashboard_panel resource for how one is created/managed.",
Description: "Looks up an existing Cairn OBS dashboard panel by (dashboard_id, id). See the cairnobs_dashboard_panel resource for how one is created/managed.",
Attributes: map[string]schema.Attribute{
"dashboard_id": schema.StringAttribute{
Required: true,
Description: "ID of the parent sentry_dashboard.",
Description: "ID of the parent cairnobs_dashboard.",
},
"id": schema.StringAttribute{
Required: true,
@@ -14,30 +14,30 @@ func TestAccDashboardPanelDataSource_basic(t *testing.T) {
Steps: []resource.TestStep{
{
Config: `
provider "sentry" {
provider "cairnobs" {
endpoint = "http://localhost:8080"
}
resource "sentry_dashboard" "test" {
resource "cairnobs_dashboard" "test" {
name = "Panel Data Source Test Dashboard"
}
resource "sentry_dashboard_panel" "test" {
dashboard_id = sentry_dashboard.test.id
resource "cairnobs_dashboard_panel" "test" {
dashboard_id = cairnobs_dashboard.test.id
title = "Errors over time"
query = "status>=500 | timechart count"
viz_type = "line"
}
data "sentry_dashboard_panel" "test" {
dashboard_id = sentry_dashboard.test.id
id = sentry_dashboard_panel.test.id
data "cairnobs_dashboard_panel" "test" {
dashboard_id = cairnobs_dashboard.test.id
id = cairnobs_dashboard_panel.test.id
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair("data.sentry_dashboard_panel.test", "title", "sentry_dashboard_panel.test", "title"),
resource.TestCheckResourceAttrPair("data.sentry_dashboard_panel.test", "query", "sentry_dashboard_panel.test", "query"),
resource.TestCheckResourceAttrPair("data.sentry_dashboard_panel.test", "viz_type", "sentry_dashboard_panel.test", "viz_type"),
resource.TestCheckResourceAttrPair("data.cairnobs_dashboard_panel.test", "title", "cairnobs_dashboard_panel.test", "title"),
resource.TestCheckResourceAttrPair("data.cairnobs_dashboard_panel.test", "query", "cairnobs_dashboard_panel.test", "query"),
resource.TestCheckResourceAttrPair("data.cairnobs_dashboard_panel.test", "viz_type", "cairnobs_dashboard_panel.test", "viz_type"),
),
},
},
@@ -26,10 +26,10 @@ func newDashboardPanelResource() resource.Resource {
return &dashboardPanelResource{}
}
// dashboardPanelResource implements sentry_dashboard_panel against
// dashboardPanelResource implements cairnobs_dashboard_panel against
// api/dashboards.Handler's POST/PUT/DELETE
// /dashboards/{id}/panels[/{panelId}] endpoints -- a genuinely separate
// resource from sentry_dashboard (own id, own lifecycle, own endpoints),
// resource from cairnobs_dashboard (own id, own lifecycle, own endpoints),
// not a nested block on the dashboard resource. That split matches the
// API's own shape (a panel is created/updated/deleted independently of
// its parent dashboard, never by rewriting the dashboard's whole panel
@@ -38,7 +38,7 @@ func newDashboardPanelResource() resource.Resource {
// panel to be rewritten on any single panel's change, hiding
// fine-grained diffs a separate resource shows naturally.
//
// Unlike sentry_alert_rule/sentry_notification_target, this resource
// Unlike cairnobs_alert_rule/cairnobs_notification_target, this resource
// supports a real in-place Update -- api/dashboards.Handler actually has
// a PUT /dashboards/{id}/panels/{panelId}. Only dashboard_id forces a
// replace: UpdatePanel's SQL matches WHERE id = $panelID AND
@@ -76,7 +76,7 @@ func (r *dashboardPanelResource) Metadata(_ context.Context, req resource.Metada
func (r *dashboardPanelResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "A panel on a Sentry dashboard, managed independently of the sentry_dashboard it belongs to.",
Description: "A panel on a Cairn OBS dashboard, managed independently of the cairnobs_dashboard it belongs to.",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
@@ -86,7 +86,7 @@ func (r *dashboardPanelResource) Schema(_ context.Context, _ resource.SchemaRequ
"dashboard_id": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
Description: "ID of the sentry_dashboard this panel belongs to. Forces replacement on change -- there is no API operation to move a panel between dashboards, see this resource's Go doc comment.",
Description: "ID of the cairnobs_dashboard this panel belongs to. Forces replacement on change -- there is no API operation to move a panel between dashboards, see this resource's Go doc comment.",
},
"title": schema.StringAttribute{
Optional: true,
@@ -101,7 +101,7 @@ func (r *dashboardPanelResource) Schema(_ context.Context, _ resource.SchemaRequ
Optional: true,
Computed: true,
Default: stringdefault.StaticString(""),
Description: `"" (auto-detect) or "spl" -- never "sql", the API rejects that for panels specifically (unlike sentry_alert_rule's query_language, which accepts it).`,
Description: `"" (auto-detect) or "spl" -- never "sql", the API rejects that for panels specifically (unlike cairnobs_alert_rule's query_language, which accepts it).`,
},
"viz_type": schema.StringAttribute{
Required: true,
@@ -16,66 +16,66 @@ func TestAccDashboardPanelResource_basic(t *testing.T) {
Steps: []resource.TestStep{
{
Config: `
provider "sentry" {
provider "cairnobs" {
endpoint = "http://localhost:8080"
}
resource "sentry_dashboard" "test" {
resource "cairnobs_dashboard" "test" {
name = "Panel Acceptance Test Dashboard"
}
resource "sentry_dashboard_panel" "test" {
dashboard_id = sentry_dashboard.test.id
resource "cairnobs_dashboard_panel" "test" {
dashboard_id = cairnobs_dashboard.test.id
title = "Errors over time"
query = "status>=500 | timechart count"
viz_type = "line"
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair("sentry_dashboard_panel.test", "dashboard_id", "sentry_dashboard.test", "id"),
resource.TestCheckResourceAttr("sentry_dashboard_panel.test", "title", "Errors over time"),
resource.TestCheckResourceAttr("sentry_dashboard_panel.test", "viz_type", "line"),
resource.TestCheckResourceAttrSet("sentry_dashboard_panel.test", "id"),
resource.TestCheckResourceAttrPair("cairnobs_dashboard_panel.test", "dashboard_id", "cairnobs_dashboard.test", "id"),
resource.TestCheckResourceAttr("cairnobs_dashboard_panel.test", "title", "Errors over time"),
resource.TestCheckResourceAttr("cairnobs_dashboard_panel.test", "viz_type", "line"),
resource.TestCheckResourceAttrSet("cairnobs_dashboard_panel.test", "id"),
// Left unset in config -- must come back as the
// API's own default ("{}"), same "API default, not
// a duplicated Terraform-side one" reasoning
// sentry_dashboard's default_earliest/default_latest
// cairnobs_dashboard's default_earliest/default_latest
// use.
resource.TestCheckResourceAttr("sentry_dashboard_panel.test", "viz_config", "{}"),
resource.TestCheckResourceAttr("cairnobs_dashboard_panel.test", "viz_config", "{}"),
),
},
{
// Update: unlike sentry_alert_rule/sentry_notification_target,
// Update: unlike cairnobs_alert_rule/cairnobs_notification_target,
// this really is an in-place update -- api/dashboards.Handler
// has a real PUT for panels.
Config: `
provider "sentry" {
provider "cairnobs" {
endpoint = "http://localhost:8080"
}
resource "sentry_dashboard" "test" {
resource "cairnobs_dashboard" "test" {
name = "Panel Acceptance Test Dashboard"
}
resource "sentry_dashboard_panel" "test" {
dashboard_id = sentry_dashboard.test.id
resource "cairnobs_dashboard_panel" "test" {
dashboard_id = cairnobs_dashboard.test.id
title = "Errors over time (renamed)"
query = "status>=500 | timechart count"
viz_type = "line"
}
`,
Check: resource.TestCheckResourceAttr("sentry_dashboard_panel.test", "title", "Errors over time (renamed)"),
Check: resource.TestCheckResourceAttr("cairnobs_dashboard_panel.test", "title", "Errors over time (renamed)"),
},
{
// "dashboard_id/panel_id" -- see ImportState's doc
// comment on splitImportID for why a bare panel ID
// isn't enough.
ResourceName: "sentry_dashboard_panel.test",
ResourceName: "cairnobs_dashboard_panel.test",
ImportState: true,
ImportStateIdFunc: func(s *tfstate.State) (string, error) {
rs, ok := s.RootModule().Resources["sentry_dashboard_panel.test"]
rs, ok := s.RootModule().Resources["cairnobs_dashboard_panel.test"]
if !ok {
return "", fmt.Errorf("sentry_dashboard_panel.test not found in state")
return "", fmt.Errorf("cairnobs_dashboard_panel.test not found in state")
}
return rs.Primary.Attributes["dashboard_id"] + "/" + rs.Primary.Attributes["id"], nil
},
@@ -23,9 +23,9 @@ func newDashboardResource() resource.Resource {
return &dashboardResource{}
}
// dashboardResource implements sentry_dashboard against
// dashboardResource implements cairnobs_dashboard against
// api/dashboards.Handler's POST/GET/PUT/DELETE /dashboards[/{id}]
// endpoints -- the exact same JSON contract cli/cmd/sentryctl's
// endpoints -- the exact same JSON contract cli/cmd/cairnobsctl's
// "dashboards apply" and web's Export JSON button already use (see
// cli/README.md's "one JSON contract, multiple callers" framing; this
// is that third caller). Panels are a separate CRUD surface
@@ -54,7 +54,7 @@ func (r *dashboardResource) Metadata(_ context.Context, req resource.MetadataReq
func (r *dashboardResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "A Sentry dashboard. Panels aren't managed by this resource yet -- see the provider README.",
Description: "A Cairn OBS dashboard. Panels aren't managed by this resource yet -- see the provider README.",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
@@ -167,7 +167,7 @@ func (r *dashboardResource) Read(ctx context.Context, req resource.ReadRequest,
out, err := r.client.getDashboard(ctx, state.ID.ValueString())
if err != nil {
if isNotFound(err) {
// Deleted out-of-band (e.g. via web or sentryctl) --
// Deleted out-of-band (e.g. via web or cairnobsctl) --
// dropping it from state lets the next plan offer to
// recreate it, the standard Terraform convention, rather
// than failing every subsequent plan/apply until someone
@@ -13,7 +13,7 @@ import (
// runner -- HashiCorp's standard pattern, one factory reused by every
// acceptance test in this package.
var testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
"sentry": providerserver.NewProtocol6WithError(New("test")()),
"cairnobs": providerserver.NewProtocol6WithError(New("test")()),
}
// The acceptance test below is gated the same way every other live-
@@ -32,49 +32,49 @@ func TestAccDashboardResource_basic(t *testing.T) {
Steps: []resource.TestStep{
{
Config: `
provider "sentry" {
provider "cairnobs" {
endpoint = "http://localhost:8080"
}
resource "sentry_dashboard" "test" {
resource "cairnobs_dashboard" "test" {
name = "Acceptance Test Dashboard"
description = "created by TestAccDashboardResource_basic"
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("sentry_dashboard.test", "name", "Acceptance Test Dashboard"),
resource.TestCheckResourceAttr("sentry_dashboard.test", "description", "created by TestAccDashboardResource_basic"),
resource.TestCheckResourceAttrSet("sentry_dashboard.test", "id"),
resource.TestCheckResourceAttrSet("sentry_dashboard.test", "tenant_id"),
resource.TestCheckResourceAttr("cairnobs_dashboard.test", "name", "Acceptance Test Dashboard"),
resource.TestCheckResourceAttr("cairnobs_dashboard.test", "description", "created by TestAccDashboardResource_basic"),
resource.TestCheckResourceAttrSet("cairnobs_dashboard.test", "id"),
resource.TestCheckResourceAttrSet("cairnobs_dashboard.test", "tenant_id"),
// Left unset in config -- must come back as the
// server's own defaults (store.go: "-1h"/"now"), not
// an empty string, proving the Optional+Computed
// schema round-trips the server's default rather
// than fighting it with a Terraform-side one.
resource.TestCheckResourceAttr("sentry_dashboard.test", "default_earliest", "-1h"),
resource.TestCheckResourceAttr("sentry_dashboard.test", "default_latest", "now"),
resource.TestCheckResourceAttr("cairnobs_dashboard.test", "default_earliest", "-1h"),
resource.TestCheckResourceAttr("cairnobs_dashboard.test", "default_latest", "now"),
),
},
{
// Update: name change should apply in place, not
// replace (no RequiresReplace plan modifier on name).
Config: `
provider "sentry" {
provider "cairnobs" {
endpoint = "http://localhost:8080"
}
resource "sentry_dashboard" "test" {
resource "cairnobs_dashboard" "test" {
name = "Renamed Dashboard"
description = "created by TestAccDashboardResource_basic"
}
`,
Check: resource.TestCheckResourceAttr("sentry_dashboard.test", "name", "Renamed Dashboard"),
Check: resource.TestCheckResourceAttr("cairnobs_dashboard.test", "name", "Renamed Dashboard"),
},
{
// Import: re-reads by ID alone and must match what's in
// state, proving Read()'s server round trip agrees with
// what Create()/Update() last wrote.
ResourceName: "sentry_dashboard.test",
ResourceName: "cairnobs_dashboard.test",
ImportState: true,
ImportStateVerify: true,
},
@@ -31,7 +31,7 @@ func (d *notificationTargetDataSource) Metadata(_ context.Context, req datasourc
func (d *notificationTargetDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Looks up an existing Sentry notification target by ID. See the sentry_notification_target resource for how one is created/managed.",
Description: "Looks up an existing Cairn OBS notification target by ID. See the cairnobs_notification_target resource for how one is created/managed.",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Required: true,
@@ -49,7 +49,7 @@ func (d *notificationTargetDataSource) Schema(_ context.Context, _ datasource.Sc
Computed: true,
Sensitive: true,
Description: "alerting's own GET /targets/{id} returns this unredacted (see the " +
"sentry_notification_target resource's schema doc comment) -- Sensitive here for the " +
"cairnobs_notification_target resource's schema doc comment) -- Sensitive here for the " +
"same reason, and the same state-file caveat applies.",
},
"created_by": schema.StringAttribute{Computed: true},
@@ -15,29 +15,29 @@ func TestAccNotificationTargetDataSource_basic(t *testing.T) {
Steps: []resource.TestStep{
{
Config: `
provider "sentry" {
provider "cairnobs" {
endpoint = "http://localhost:8080"
alerting_endpoint = "http://localhost:8081"
}
resource "sentry_notification_target" "test" {
resource "cairnobs_notification_target" "test" {
name = "Data Source Test Target"
kind = "webhook"
webhook_url = "https://example.com/hook"
secret = "test-secret"
}
data "sentry_notification_target" "test" {
id = sentry_notification_target.test.id
data "cairnobs_notification_target" "test" {
id = cairnobs_notification_target.test.id
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair("data.sentry_notification_target.test", "name", "sentry_notification_target.test", "name"),
resource.TestCheckResourceAttrPair("data.sentry_notification_target.test", "webhook_url", "sentry_notification_target.test", "webhook_url"),
resource.TestCheckResourceAttrPair("data.cairnobs_notification_target.test", "name", "cairnobs_notification_target.test", "name"),
resource.TestCheckResourceAttrPair("data.cairnobs_notification_target.test", "webhook_url", "cairnobs_notification_target.test", "webhook_url"),
// Real, not papered over -- secret round-trips
// unredacted (see the resource test's equivalent
// comment).
resource.TestCheckResourceAttrPair("data.sentry_notification_target.test", "secret", "sentry_notification_target.test", "secret"),
resource.TestCheckResourceAttrPair("data.cairnobs_notification_target.test", "secret", "cairnobs_notification_target.test", "secret"),
),
},
},
@@ -23,7 +23,7 @@ func newNotificationTargetResource() resource.Resource {
return &notificationTargetResource{}
}
// notificationTargetResource implements sentry_notification_target
// notificationTargetResource implements cairnobs_notification_target
// against alerting/internal/httpapi's POST/GET/DELETE
// /targets[/{id}] endpoints.
//
@@ -54,14 +54,14 @@ func (r *notificationTargetResource) Metadata(_ context.Context, req resource.Me
func (r *notificationTargetResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
replace := []planmodifier.String{stringplanmodifier.RequiresReplace()}
resp.Schema = schema.Schema{
Description: "A Sentry alert notification target. Create/destroy only -- alerting has no update " +
Description: "A Cairn OBS alert notification target. Create/destroy only -- alerting has no update " +
"endpoint for targets today (see this resource's Go doc comment), so every attribute below " +
"forces a destroy-and-recreate on change, never an in-place update.",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()},
Description: "Server-generated target ID -- reference this from a sentry_alert_rule's notification_target_id.",
Description: "Server-generated target ID -- reference this from a cairnobs_alert_rule's notification_target_id.",
},
"tenant_id": schema.StringAttribute{
Computed: true,
@@ -15,12 +15,12 @@ func TestAccNotificationTargetResource_basic(t *testing.T) {
Steps: []resource.TestStep{
{
Config: `
provider "sentry" {
provider "cairnobs" {
endpoint = "http://localhost:8080"
alerting_endpoint = "http://localhost:8081"
}
resource "sentry_notification_target" "test" {
resource "cairnobs_notification_target" "test" {
name = "Acceptance Test Target"
kind = "webhook"
webhook_url = "https://example.com/hook"
@@ -28,11 +28,11 @@ resource "sentry_notification_target" "test" {
}
`,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("sentry_notification_target.test", "name", "Acceptance Test Target"),
resource.TestCheckResourceAttr("sentry_notification_target.test", "kind", "webhook"),
resource.TestCheckResourceAttr("sentry_notification_target.test", "secret", "test-secret"),
resource.TestCheckResourceAttrSet("sentry_notification_target.test", "id"),
resource.TestCheckResourceAttrSet("sentry_notification_target.test", "tenant_id"),
resource.TestCheckResourceAttr("cairnobs_notification_target.test", "name", "Acceptance Test Target"),
resource.TestCheckResourceAttr("cairnobs_notification_target.test", "kind", "webhook"),
resource.TestCheckResourceAttr("cairnobs_notification_target.test", "secret", "test-secret"),
resource.TestCheckResourceAttrSet("cairnobs_notification_target.test", "id"),
resource.TestCheckResourceAttrSet("cairnobs_notification_target.test", "tenant_id"),
),
},
{
@@ -40,12 +40,12 @@ resource "sentry_notification_target" "test" {
// TestAccAlertRuleResource_basic's second step --
// notifystore.Store has no Update either.
Config: `
provider "sentry" {
provider "cairnobs" {
endpoint = "http://localhost:8080"
alerting_endpoint = "http://localhost:8081"
}
resource "sentry_notification_target" "test" {
resource "cairnobs_notification_target" "test" {
name = "Renamed Target"
kind = "webhook"
webhook_url = "https://example.com/hook"
@@ -54,10 +54,10 @@ resource "sentry_notification_target" "test" {
`,
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectResourceAction("sentry_notification_target.test", plancheck.ResourceActionDestroyBeforeCreate),
plancheck.ExpectResourceAction("cairnobs_notification_target.test", plancheck.ResourceActionDestroyBeforeCreate),
},
},
Check: resource.TestCheckResourceAttr("sentry_notification_target.test", "name", "Renamed Target"),
Check: resource.TestCheckResourceAttr("cairnobs_notification_target.test", "name", "Renamed Target"),
},
{
// No ImportStateVerifyIgnore for "secret" -- GET
@@ -65,7 +65,7 @@ resource "sentry_notification_target" "test" {
// doc comment and TestGetNotificationTargetReturnsSecretUnredacted),
// so import-time equality is a real, meaningful
// assertion here, not one this test has to paper over.
ResourceName: "sentry_notification_target.test",
ResourceName: "cairnobs_notification_target.test",
ImportState: true,
ImportStateVerify: true,
},
+25 -25
View File
@@ -1,4 +1,4 @@
// Package provider is Sentry's Terraform provider implementation,
// Package provider is Cairn OBS's Terraform provider implementation,
// built on HashiCorp's terraform-plugin-framework (not the legacy
// SDKv2 -- the framework is the actively-developed, currently-
// recommended library for a provider started from scratch, matching
@@ -17,22 +17,22 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types"
)
var _ provider.Provider = &sentryProvider{}
var _ provider.Provider = &cairnobsProvider{}
// New matches providerserver.Serve's expected constructor shape --
// version is threaded through from main.go's -ldflags-injected build
// version.
func New(version string) func() provider.Provider {
return func() provider.Provider {
return &sentryProvider{version: version}
return &cairnobsProvider{version: version}
}
}
type sentryProvider struct {
type cairnobsProvider struct {
version string
}
type sentryProviderModel struct {
type cairnobsProviderModel struct {
Endpoint types.String `tfsdk:"endpoint"`
AlertingEndpoint types.String `tfsdk:"alerting_endpoint"`
Token types.String `tfsdk:"token"`
@@ -42,7 +42,7 @@ type sentryProviderModel struct {
// req.ProviderData -- two separate clients, not one, because `alerting`
// is a genuinely separate service with its own base URL (its own
// REST API, its own port, sometimes its own deployment) -- same split
// web/src/lib/api.ts's apiBase/alertingBase and cli/cmd/sentryctl's
// web/src/lib/api.ts's apiBase/alertingBase and cli/cmd/cairnobsctl's
// --api/--alerting-api already draw, not something invented for this
// provider.
type providerData struct {
@@ -50,36 +50,36 @@ type providerData struct {
alerting *client
}
func (p *sentryProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "sentry"
func (p *cairnobsProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "cairnobs"
resp.Version = p.version
}
func (p *sentryProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
func (p *cairnobsProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Manages Sentry log-aggregation-platform resources. Dashboards, alert rules, and notification targets for now -- tenant/RBAC resources are real, disclosed future work, not built in this pass; see the provider README.",
Description: "Manages Cairn OBS log-aggregation-platform resources. Dashboards, alert rules, and notification targets for now -- tenant/RBAC resources are real, disclosed future work, not built in this pass; see the provider README.",
Attributes: map[string]schema.Attribute{
"endpoint": schema.StringAttribute{
Optional: true,
Description: "Base URL of the api service, e.g. \"http://localhost:8080\". Defaults to " +
"$SENTRY_API_ENDPOINT, or \"http://localhost:8080\" if that's unset too -- same " +
"default sentryctl's --api/$SENTRYCTL_API_URL uses (cli/cmd/sentryctl/main.go).",
"$CAIRNOBS_API_ENDPOINT, or \"http://localhost:8080\" if that's unset too -- same " +
"default cairnobsctl's --api/$CAIRNOBSCTL_API_URL uses (cli/cmd/cairnobsctl/main.go).",
},
"alerting_endpoint": schema.StringAttribute{
Optional: true,
Description: "Base URL of the alerting service, e.g. \"http://localhost:8081\" -- a " +
"separate service from api, not a path under endpoint above (see " +
"/docs/phase-3-alerting-design.md's component boundary). Defaults to " +
"$SENTRY_ALERTING_API_ENDPOINT, or \"http://localhost:8081\" if that's unset too -- " +
"same default sentryctl's --alerting-api/$SENTRYCTL_ALERTING_API_URL uses.",
"$CAIRNOBS_ALERTING_API_ENDPOINT, or \"http://localhost:8081\" if that's unset too -- " +
"same default cairnobsctl's --alerting-api/$CAIRNOBSCTL_ALERTING_API_URL uses.",
},
"token": schema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "Bearer credential sent as \"Authorization: Bearer <token>\" on every request " +
"-- required once a deployment configures enterprise-auth (see " +
"/docs/phase-4-rbac-design.md), same as sentryctl's $SENTRYCTL_TOKEN. Defaults to " +
"$SENTRY_API_TOKEN if unset. Set via a variable or environment, never a literal in a " +
"/docs/phase-4-rbac-design.md), same as cairnobsctl's $CAIRNOBSCTL_TOKEN. Defaults to " +
"$CAIRNOBS_API_TOKEN if unset. Set via a variable or environment, never a literal in a " +
".tf file committed to version control.",
},
},
@@ -87,11 +87,11 @@ func (p *sentryProvider) Schema(_ context.Context, _ provider.SchemaRequest, res
}
// Configure resolves endpoint/token the same precedence order
// sentryctl's resolveAPIURL/resolveToken use (explicit config value,
// cairnobsctl's resolveAPIURL/resolveToken use (explicit config value,
// then an environment variable, then a hardcoded default) so behavior
// stays predictable across both of this project's Sentry API clients.
func (p *sentryProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
var config sentryProviderModel
// stays predictable across both of this project's Cairn OBS API clients.
func (p *cairnobsProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
var config cairnobsProviderModel
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
@@ -99,7 +99,7 @@ func (p *sentryProvider) Configure(ctx context.Context, req provider.ConfigureRe
endpoint := config.Endpoint.ValueString()
if endpoint == "" {
endpoint = os.Getenv("SENTRY_API_ENDPOINT")
endpoint = os.Getenv("CAIRNOBS_API_ENDPOINT")
}
if endpoint == "" {
endpoint = "http://localhost:8080"
@@ -107,7 +107,7 @@ func (p *sentryProvider) Configure(ctx context.Context, req provider.ConfigureRe
alertingEndpoint := config.AlertingEndpoint.ValueString()
if alertingEndpoint == "" {
alertingEndpoint = os.Getenv("SENTRY_ALERTING_API_ENDPOINT")
alertingEndpoint = os.Getenv("CAIRNOBS_ALERTING_API_ENDPOINT")
}
if alertingEndpoint == "" {
alertingEndpoint = "http://localhost:8081"
@@ -115,7 +115,7 @@ func (p *sentryProvider) Configure(ctx context.Context, req provider.ConfigureRe
token := config.Token.ValueString()
if token == "" {
token = os.Getenv("SENTRY_API_TOKEN")
token = os.Getenv("CAIRNOBS_API_TOKEN")
}
data := &providerData{
@@ -126,7 +126,7 @@ func (p *sentryProvider) Configure(ctx context.Context, req provider.ConfigureRe
resp.ResourceData = data
}
func (p *sentryProvider) Resources(_ context.Context) []func() resource.Resource {
func (p *cairnobsProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
newDashboardResource,
newDashboardPanelResource,
@@ -135,7 +135,7 @@ func (p *sentryProvider) Resources(_ context.Context) []func() resource.Resource
}
}
func (p *sentryProvider) DataSources(_ context.Context) []func() datasource.DataSource {
func (p *cairnobsProvider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
newDashboardDataSource,
newDashboardPanelDataSource,
+29 -29
View File
@@ -40,14 +40,14 @@ func TestDashboardResourceSchemaValid(t *testing.T) {
newDashboardResource().Schema(ctx, req, resp)
if resp.Diagnostics.HasError() {
t.Fatalf("sentry_dashboard schema has errors: %v", resp.Diagnostics)
t.Fatalf("cairnobs_dashboard schema has errors: %v", resp.Diagnostics)
}
for _, attr := range []string{
"id", "tenant_id", "name", "description",
"default_earliest", "default_latest", "created_by", "created_at", "updated_at",
} {
if _, ok := resp.Schema.Attributes[attr]; !ok {
t.Errorf("sentry_dashboard schema missing expected attribute %q", attr)
t.Errorf("cairnobs_dashboard schema missing expected attribute %q", attr)
}
}
if !resp.Schema.Attributes["name"].IsRequired() {
@@ -60,9 +60,9 @@ func TestDashboardResourceSchemaValid(t *testing.T) {
func TestDashboardResourceMetadataSetsTypeName(t *testing.T) {
resp := &resource.MetadataResponse{}
newDashboardResource().Metadata(context.Background(), resource.MetadataRequest{ProviderTypeName: "sentry"}, resp)
if resp.TypeName != "sentry_dashboard" {
t.Fatalf("TypeName = %q, want sentry_dashboard", resp.TypeName)
newDashboardResource().Metadata(context.Background(), resource.MetadataRequest{ProviderTypeName: "cairnobs"}, resp)
if resp.TypeName != "cairnobs_dashboard" {
t.Fatalf("TypeName = %q, want cairnobs_dashboard", resp.TypeName)
}
}
@@ -74,7 +74,7 @@ func TestDashboardPanelResourceSchemaValid(t *testing.T) {
newDashboardPanelResource().Schema(ctx, req, resp)
if resp.Diagnostics.HasError() {
t.Fatalf("sentry_dashboard_panel schema has errors: %v", resp.Diagnostics)
t.Fatalf("cairnobs_dashboard_panel schema has errors: %v", resp.Diagnostics)
}
for _, attr := range []string{
"id", "dashboard_id", "title", "query", "query_language", "viz_type", "viz_config",
@@ -82,7 +82,7 @@ func TestDashboardPanelResourceSchemaValid(t *testing.T) {
"earliest_override", "latest_override", "sort_order", "created_at", "updated_at",
} {
if _, ok := resp.Schema.Attributes[attr]; !ok {
t.Errorf("sentry_dashboard_panel schema missing expected attribute %q", attr)
t.Errorf("cairnobs_dashboard_panel schema missing expected attribute %q", attr)
}
}
if !resp.Schema.Attributes["query"].IsRequired() {
@@ -98,9 +98,9 @@ func TestDashboardPanelResourceSchemaValid(t *testing.T) {
func TestDashboardPanelResourceMetadataSetsTypeName(t *testing.T) {
resp := &resource.MetadataResponse{}
newDashboardPanelResource().Metadata(context.Background(), resource.MetadataRequest{ProviderTypeName: "sentry"}, resp)
if resp.TypeName != "sentry_dashboard_panel" {
t.Fatalf("TypeName = %q, want sentry_dashboard_panel", resp.TypeName)
newDashboardPanelResource().Metadata(context.Background(), resource.MetadataRequest{ProviderTypeName: "cairnobs"}, resp)
if resp.TypeName != "cairnobs_dashboard_panel" {
t.Fatalf("TypeName = %q, want cairnobs_dashboard_panel", resp.TypeName)
}
}
@@ -112,7 +112,7 @@ func TestAlertRuleResourceSchemaValid(t *testing.T) {
newAlertRuleResource().Schema(ctx, req, resp)
if resp.Diagnostics.HasError() {
t.Fatalf("sentry_alert_rule schema has errors: %v", resp.Diagnostics)
t.Fatalf("cairnobs_alert_rule schema has errors: %v", resp.Diagnostics)
}
for _, attr := range []string{
"id", "tenant_id", "name", "description", "query", "query_language",
@@ -120,7 +120,7 @@ func TestAlertRuleResourceSchemaValid(t *testing.T) {
"for_minutes", "renotify_interval_minutes", "notification_target_id", "enabled", "created_by",
} {
if _, ok := resp.Schema.Attributes[attr]; !ok {
t.Errorf("sentry_alert_rule schema missing expected attribute %q", attr)
t.Errorf("cairnobs_alert_rule schema missing expected attribute %q", attr)
}
}
if !resp.Schema.Attributes["name"].IsRequired() {
@@ -133,9 +133,9 @@ func TestAlertRuleResourceSchemaValid(t *testing.T) {
func TestAlertRuleResourceMetadataSetsTypeName(t *testing.T) {
resp := &resource.MetadataResponse{}
newAlertRuleResource().Metadata(context.Background(), resource.MetadataRequest{ProviderTypeName: "sentry"}, resp)
if resp.TypeName != "sentry_alert_rule" {
t.Fatalf("TypeName = %q, want sentry_alert_rule", resp.TypeName)
newAlertRuleResource().Metadata(context.Background(), resource.MetadataRequest{ProviderTypeName: "cairnobs"}, resp)
if resp.TypeName != "cairnobs_alert_rule" {
t.Fatalf("TypeName = %q, want cairnobs_alert_rule", resp.TypeName)
}
}
@@ -147,14 +147,14 @@ func TestNotificationTargetResourceSchemaValid(t *testing.T) {
newNotificationTargetResource().Schema(ctx, req, resp)
if resp.Diagnostics.HasError() {
t.Fatalf("sentry_notification_target schema has errors: %v", resp.Diagnostics)
t.Fatalf("cairnobs_notification_target schema has errors: %v", resp.Diagnostics)
}
for _, attr := range []string{
"id", "tenant_id", "name", "kind", "webhook_url",
"payload_template", "headers", "secret", "created_by",
} {
if _, ok := resp.Schema.Attributes[attr]; !ok {
t.Errorf("sentry_notification_target schema missing expected attribute %q", attr)
t.Errorf("cairnobs_notification_target schema missing expected attribute %q", attr)
}
}
if !resp.Schema.Attributes["name"].IsRequired() {
@@ -167,9 +167,9 @@ func TestNotificationTargetResourceSchemaValid(t *testing.T) {
func TestNotificationTargetResourceMetadataSetsTypeName(t *testing.T) {
resp := &resource.MetadataResponse{}
newNotificationTargetResource().Metadata(context.Background(), resource.MetadataRequest{ProviderTypeName: "sentry"}, resp)
if resp.TypeName != "sentry_notification_target" {
t.Fatalf("TypeName = %q, want sentry_notification_target", resp.TypeName)
newNotificationTargetResource().Metadata(context.Background(), resource.MetadataRequest{ProviderTypeName: "cairnobs"}, resp)
if resp.TypeName != "cairnobs_notification_target" {
t.Fatalf("TypeName = %q, want cairnobs_notification_target", resp.TypeName)
}
}
@@ -181,7 +181,7 @@ func TestDashboardDataSourceSchemaValid(t *testing.T) {
newDashboardDataSource().Schema(ctx, req, resp)
if resp.Diagnostics.HasError() {
t.Fatalf("sentry_dashboard data source schema has errors: %v", resp.Diagnostics)
t.Fatalf("cairnobs_dashboard data source schema has errors: %v", resp.Diagnostics)
}
if !resp.Schema.Attributes["id"].IsRequired() {
t.Error(`"id" must be Required -- a data source needs it to know what to look up`)
@@ -199,7 +199,7 @@ func TestDashboardPanelDataSourceSchemaValid(t *testing.T) {
newDashboardPanelDataSource().Schema(ctx, req, resp)
if resp.Diagnostics.HasError() {
t.Fatalf("sentry_dashboard_panel data source schema has errors: %v", resp.Diagnostics)
t.Fatalf("cairnobs_dashboard_panel data source schema has errors: %v", resp.Diagnostics)
}
if !resp.Schema.Attributes["dashboard_id"].IsRequired() {
t.Error(`"dashboard_id" must be Required`)
@@ -220,7 +220,7 @@ func TestAlertRuleDataSourceSchemaValid(t *testing.T) {
newAlertRuleDataSource().Schema(ctx, req, resp)
if resp.Diagnostics.HasError() {
t.Fatalf("sentry_alert_rule data source schema has errors: %v", resp.Diagnostics)
t.Fatalf("cairnobs_alert_rule data source schema has errors: %v", resp.Diagnostics)
}
if !resp.Schema.Attributes["id"].IsRequired() {
t.Error(`"id" must be Required`)
@@ -238,7 +238,7 @@ func TestNotificationTargetDataSourceSchemaValid(t *testing.T) {
newNotificationTargetDataSource().Schema(ctx, req, resp)
if resp.Diagnostics.HasError() {
t.Fatalf("sentry_notification_target data source schema has errors: %v", resp.Diagnostics)
t.Fatalf("cairnobs_notification_target data source schema has errors: %v", resp.Diagnostics)
}
if !resp.Schema.Attributes["id"].IsRequired() {
t.Error(`"id" must be Required`)
@@ -253,14 +253,14 @@ func TestDataSourcesMetadataSetTypeNames(t *testing.T) {
newDS func() datasource.DataSource
wantType string
}{
{newDashboardDataSource, "sentry_dashboard"},
{newDashboardPanelDataSource, "sentry_dashboard_panel"},
{newAlertRuleDataSource, "sentry_alert_rule"},
{newNotificationTargetDataSource, "sentry_notification_target"},
{newDashboardDataSource, "cairnobs_dashboard"},
{newDashboardPanelDataSource, "cairnobs_dashboard_panel"},
{newAlertRuleDataSource, "cairnobs_alert_rule"},
{newNotificationTargetDataSource, "cairnobs_notification_target"},
}
for _, c := range cases {
resp := &datasource.MetadataResponse{}
c.newDS().Metadata(context.Background(), datasource.MetadataRequest{ProviderTypeName: "sentry"}, resp)
c.newDS().Metadata(context.Background(), datasource.MetadataRequest{ProviderTypeName: "cairnobs"}, resp)
if resp.TypeName != c.wantType {
t.Errorf("TypeName = %q, want %q", resp.TypeName, c.wantType)
}