Skip to content
Open
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
5 changes: 5 additions & 0 deletions examples/data-sources/stackit_telemetrylink/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
data "stackit_telemetrylink" "link" {
resource_type = "project"
resource_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
region = "eu01"
}
24 changes: 24 additions & 0 deletions examples/resources/stackit_telemetrylink/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
resource "stackit_telemetrylink" "link" {
resource_type = "project"
resource_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
region = "eu01"
display_name = "telemetrylink-example"
access_token = "eyJxxx"
telemetry_router_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

resource "stackit_telemetrylink" "link2" {
resource_type = "project"
resource_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
region = "eu01"
display_name = "telemetrylink-example"
description = "telemetrylink description"
access_token = "eyJxxx"
telemetry_router_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

# Only use the import statement, if you want to import an existing TelemetryLink
import {
to = stackit_telemetrylink.import-example
id = "${var.resource_type},${var.resource_id},${var.region}"
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ require (
github.com/stackitcloud/stackit-sdk-go/services/sfs v0.10.0
github.com/stackitcloud/stackit-sdk-go/services/ske v1.14.0
github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex v1.10.0
github.com/stackitcloud/stackit-sdk-go/services/telemetrylink v0.1.1
github.com/teambition/rrule-go v1.8.2
golang.org/x/mod v0.35.0
)
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,8 @@ github.com/stackitcloud/stackit-sdk-go/services/ske v1.14.0 h1:Zy3yxmHzW+ydu1nae
github.com/stackitcloud/stackit-sdk-go/services/ske v1.14.0/go.mod h1:TbqmZhLMofmfl+HhVl6oHYcI3zvXTm1vRjN3A/fOkM4=
github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex v1.10.0 h1:angvO3z0TGqZtdwTDsG/tgTw9hxB76A6leUsiUXQtME=
github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex v1.10.0/go.mod h1:AiUoMAqQcOlMgDtkVJlqI7P/VGD5xjN3dYjERGnwN/M=
github.com/stackitcloud/stackit-sdk-go/services/telemetrylink v0.1.1 h1:+YxN37hx3bj55c/CloXOoQTYLzwLp1Cf0NvkLemZECE=
github.com/stackitcloud/stackit-sdk-go/services/telemetrylink v0.1.1/go.mod h1:hgw8janWmDfP2bnuZensxqcAePr49BX5ug8Rq85o+h8=
github.com/stbenjam/no-sprintf-host-port v0.3.1 h1:AyX7+dxI4IdLBPtDbsGAyqiTSLpCP9hWRrXQDU4Cm/g=
github.com/stbenjam/no-sprintf-host-port v0.3.1/go.mod h1:ODbZesTCHMVKthBHskvUUexdcNHAQRXk9NpSsL8p/HQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand Down
1 change: 1 addition & 0 deletions stackit/internal/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ type ProviderData struct {
ServiceEnablementCustomEndpoint string
SfsCustomEndpoint string
ServiceAccountCustomEndpoint string
TelemetryLinkCustomEndpoint string
EnableBetaResources bool
Experiments []string

Expand Down
212 changes: 212 additions & 0 deletions stackit/internal/services/telemetrylink/link/datasource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
package link

import (
"context"
"errors"
"fmt"
"net/http"

"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"

telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1betaapi"

"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/telemetrylink/utils"
tfutils "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
)

var (
_ datasource.DataSource = &telemetryLinkLinkDataSource{}
)

func NewTelemetryLinkLinkDataSource() datasource.DataSource {
return &telemetryLinkLinkDataSource{}
}

type DataSourceModel struct {
ID types.String `tfsdk:"id"` // Required by Terraform
LinkID types.String `tfsdk:"link_id"`
Region types.String `tfsdk:"region"`
ResourceType types.String `tfsdk:"resource_type"`
ResourceID types.String `tfsdk:"resource_id"`
DisplayName types.String `tfsdk:"display_name"`
Description types.String `tfsdk:"description"`
TelemetryRouterID types.String `tfsdk:"telemetry_router_id"`
CreateTime types.String `tfsdk:"create_time"`
Status types.String `tfsdk:"status"`
}

type telemetryLinkLinkDataSource struct {
client *telemetrylink.APIClient
providerData core.ProviderData
}

func (d *telemetryLinkLinkDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_telemetrylink"
}

func (d *telemetryLinkLinkDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
providerData, ok := conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics)
if !ok {
return
}
d.providerData = providerData

apiClient := utils.ConfigureClient(ctx, &providerData, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
d.client = apiClient
tflog.Info(ctx, "TelemetryLink client configured")
}

func (d *telemetryLinkLinkDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: fmt.Sprintf("TelemetryLink data source schema. %s", core.DatasourceRegionFallbackDocstring),
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Description: schemaDescriptions["id"],
Computed: true,
},
"link_id": schema.StringAttribute{
Description: schemaDescriptions["instance_id"],
Computed: true,
Validators: []validator.String{
validate.UUID(),
validate.NoSeparator(),
},
},
"resource_type": schema.StringAttribute{
Description: schemaDescriptions["resource_type"],
Required: true,
Validators: []validator.String{
stringvalidator.OneOf(resourceTypes...),
validate.NoSeparator(),
},
},
"resource_id": schema.StringAttribute{
Comment thread
ozanichkovsky marked this conversation as resolved.
Description: schemaDescriptions["resource_id"],
Required: true,
Validators: []validator.String{
validate.UUID(),
validate.NoSeparator(),
},
},
"region": schema.StringAttribute{
Description: schemaDescriptions["region"],
// the region cannot be found, so it has to be passed
Optional: true,
},
"display_name": schema.StringAttribute{
Description: schemaDescriptions["display_name"],
Computed: true,
Validators: []validator.String{stringvalidator.LengthAtLeast(1)},
},
"description": schema.StringAttribute{
Description: schemaDescriptions["description"],
Computed: true,
},
"telemetry_router_id": schema.StringAttribute{
Description: schemaDescriptions["telemetry_router_id"],
Computed: true,
},
"create_time": schema.StringAttribute{
Description: schemaDescriptions["create_time"],
Computed: true,
},
"status": schema.StringAttribute{
Description: schemaDescriptions["status"],
Computed: true,
},
},
}
}

func (d *telemetryLinkLinkDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform
var model DataSourceModel
diags := req.Config.Get(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

ctx = core.InitProviderContext(ctx)

resourceType := model.ResourceType.ValueString()
resourceID := model.ResourceID.ValueString()
region := d.providerData.GetRegionWithOverride(model.Region)

ctx = tflog.SetField(ctx, "resource_type", resourceType)
ctx = tflog.SetField(ctx, "resource_id", resourceID)
ctx = tflog.SetField(ctx, "region", region)

var response *telemetrylink.TelemetryLinkResponse
var err error
switch resourceType {
case resourceTypeOrganization:
response, err = d.client.DefaultAPI.GetOrganizationTelemetryLink(ctx, resourceID, region).Execute()
case resourceTypeFolder:
response, err = d.client.DefaultAPI.GetFolderTelemetryLink(ctx, resourceID, region).Execute()
case resourceTypeProject:
response, err = d.client.DefaultAPI.GetProjectTelemetryLink(ctx, resourceID, region).Execute()
}
if err != nil {
var oapiErr *oapierror.GenericOpenAPIError
ok := errors.As(err, &oapiErr)
if ok && oapiErr.StatusCode == http.StatusNotFound {
resp.State.RemoveResource(ctx)
return
}
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading TelemetryLink", fmt.Sprintf("Calling API: %v", err))
return
}
ctx = core.LogResponse(ctx)

err = mapDataSourceFields(ctx, response, &model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading TelemetryLink", fmt.Sprintf("Processing response: %v", err))
return
}
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
tflog.Info(ctx, "TelemetryLink read", map[string]interface{}{
"resource_type": resourceType,
"resource_id": resourceID,
})
}

func mapDataSourceFields(_ context.Context, link *telemetrylink.TelemetryLinkResponse, model *DataSourceModel) error {
if link == nil {
return fmt.Errorf("link is nil")
}
if model == nil {
return fmt.Errorf("model is nil")
}
var linkID string
if model.LinkID.ValueString() != "" {
linkID = model.LinkID.ValueString()
} else {
linkID = link.Id
}

model.ID = tfutils.BuildInternalTerraformId(model.ResourceType.ValueString(), model.ResourceID.ValueString(), model.Region.ValueString())
model.LinkID = types.StringValue(linkID)
model.DisplayName = types.StringValue(link.DisplayName)
model.Description = types.StringPointerValue(link.Description)
model.TelemetryRouterID = types.StringValue(link.TelemetryRouterId)
model.CreateTime = types.StringValue(link.CreateTime.String())
model.Status = types.StringValue(link.Status)

return nil
}
85 changes: 85 additions & 0 deletions stackit/internal/services/telemetrylink/link/datasource_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package link

import (
"context"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-framework/types"
telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1betaapi"
)

func fixtureDataSourceModel(mods ...func(model *DataSourceModel)) *DataSourceModel {
model := &DataSourceModel{
ID: types.StringValue("rtp,rid,reg"),
LinkID: types.StringValue("lid"),
Region: types.StringValue("reg"),
ResourceType: types.StringValue("rtp"),
ResourceID: types.StringValue("rid"),
DisplayName: types.StringValue("name"),
Description: types.String{},
TelemetryRouterID: types.StringValue("tlmrid"),
CreateTime: types.StringValue(testTime.String()),
Status: types.StringValue("active"),
}
for _, mod := range mods {
mod(model)
}
return model
}

func TestMapDataSourceFields(t *testing.T) {
tests := []struct {
description string
input *telemetrylink.TelemetryLinkResponse
expected *DataSourceModel
wantErr bool
}{
{
description: "min values",
input: fixtureLink(),
expected: fixtureDataSourceModel(),
},
{
description: "max values",
input: fixtureLink(func(link *telemetrylink.TelemetryLinkResponse) {
link.Description = new("description")
link.DisplayName = "display-name"
link.AccessToken = new("access-token")
link.TelemetryRouterId = "tlmr-id"
}),
expected: fixtureDataSourceModel(func(model *DataSourceModel) {
model.Description = types.StringValue("description")
model.DisplayName = types.StringValue("display-name")
model.TelemetryRouterID = types.StringValue("tlmr-id")
}),
},
{
description: "nil input",
wantErr: true,
expected: fixtureDataSourceModel(),
},
}
for _, tt := range tests {
t.Run(tt.description, func(t *testing.T) {
state := &DataSourceModel{
ResourceType: tt.expected.ResourceType,
ResourceID: tt.expected.ResourceID,
Region: tt.expected.Region,
}
err := mapDataSourceFields(context.Background(), tt.input, state)
if tt.wantErr && err == nil {
t.Fatalf("Should have failed")
}
if !tt.wantErr && err != nil {
t.Fatalf("Should not have failed: %v", err)
}
if !tt.wantErr {
diff := cmp.Diff(state, tt.expected)
if diff != "" {
t.Fatalf("Data does not match: %s", diff)
}
}
})
}
}
Loading