Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions .changes/unreleased/Fixed-20251015-160202.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Fixed
body: Fix service datasource bug caused by system retrieval
time: 2025-10-15T16:02:02.994175-07:00
28 changes: 12 additions & 16 deletions opslevel/datasource_opslevel_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,32 +258,27 @@ func (d *ServiceDataSource) Read(ctx context.Context, req datasource.ReadRequest

stateModel := NewServiceDataSourceModel(ctx, service, planModel.Alias.ValueString())

system, err := service.GetSystem(d.client, nil)
if err != nil {
diags.AddAttributeError(
path.Root("system"),
"OpsLevel Client Error",
fmt.Sprintf("unable to read System for service, got error: %s", err),
)
return
}
if system == nil {
sys := newSystemDataSourceModel(*system)
stateModel.System = &sys
// In the future we can use `service.GetSystem()` to get full data
// but for now, GetSystem is not working in opslevel-go
Copy link
Contributor Author

@derek-etherton-opslevel derek-etherton-opslevel Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apparently opslevel-go's GetSystem tries to retrieve system on Service, but the field is parent 😢

if service.Parent != nil {
aliases := OptionalStringListValue(service.Parent.Aliases)
stateModel.System = &systemDataSourceModel{
Aliases: aliases,
Id: ComputedStringValue(string(service.Parent.Id)),
}
}

// NOTE: service's hydrate does not populate properties
properties, err := service.GetProperties(d.client, nil)
if err != nil {
diags.AddAttributeError(
resp.Diagnostics.AddAttributeError(
Copy link
Contributor Author

@derek-etherton-opslevel derek-etherton-opslevel Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

couple minor changes here with error handling:

  1. making sure diags is always actually recorded (sometimes we'd just overwrite it w/ the next one)
  2. remove early returns when fetching some "extra" data fails. As long as we're recording appropriate errors, letting partial success through should make future bugs less catastrophic

path.Root("properties"),
"OpsLevel Client Error",
fmt.Sprintf("unable to read Properties for service, got error: %s", err),
)
return
}
if properties != nil {
} else if properties != nil {
stateModel.Properties, diags = NewPropertiesAllModel(ctx, properties.Nodes)
resp.Diagnostics.Append(diags...)
}

if service.Repositories == nil {
Expand All @@ -294,6 +289,7 @@ func (d *ServiceDataSource) Read(ctx context.Context, req datasource.ReadRequest
types.StringType,
flattenServiceRepositoriesArray(service.Repositories),
)
resp.Diagnostics.Append(diags...)
}

// Save data into Terraform state
Expand Down
47 changes: 47 additions & 0 deletions tests/remote/datasource_service.tftest.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
variables {
api_token = ""
}

run "datasource_service_reads_fields" {
command = plan

variables {
api_token = var.api_token
name = "Test Service for Data Source"
}

module {
source = "./service"
}

assert {
condition = data.opslevel_service.first_service_by_id.id != null
error_message = "expected id to be set for opslevel_service data source"
}

assert {
condition = data.opslevel_service.first_service_by_id.name != null
error_message = "expected name to be set for opslevel_service data source"
}

assert {
condition = data.opslevel_service.first_service_by_id.description != null
error_message = "expected description to be set for opslevel_service data source"
}

assert {
condition = can(data.opslevel_service.first_service_by_id.owner)
error_message = "expected owner field to be accessible for opslevel_service data source"
}

assert {
condition = data.opslevel_service.last_service.id != null
error_message = "expected id to be set for opslevel_service data source"
}

assert {
condition = data.opslevel_service.last_service.name != null
error_message = "expected name to be set for opslevel_service data source"
}
}

Loading