Skip to content

Commit 2c62840

Browse files
committed
feat: add stream_workspace resource + ds to replace stream_instance
1 parent d692d7c commit 2c62840

9 files changed

+733
-0
lines changed

internal/provider/provider.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import (
4545
"github.com/mongodb/terraform-provider-mongodbatlas/internal/service/streaminstance"
4646
"github.com/mongodb/terraform-provider-mongodbatlas/internal/service/streamprivatelinkendpoint"
4747
"github.com/mongodb/terraform-provider-mongodbatlas/internal/service/streamprocessor"
48+
"github.com/mongodb/terraform-provider-mongodbatlas/internal/service/streamworkspace"
4849
"github.com/mongodb/terraform-provider-mongodbatlas/internal/service/teamprojectassignment"
4950
"github.com/mongodb/terraform-provider-mongodbatlas/version"
5051
)
@@ -271,6 +272,8 @@ func (p *MongodbtlasProvider) DataSources(context.Context) []func() datasource.D
271272
pushbasedlogexport.DataSource,
272273
streaminstance.DataSource,
273274
streaminstance.PluralDataSource,
275+
streamworkspace.DataSource,
276+
streamworkspace.PluralDataSource,
274277
streamconnection.DataSource,
275278
streamconnection.PluralDataSource,
276279
controlplaneipaddresses.DataSource,
@@ -314,6 +317,7 @@ func (p *MongodbtlasProvider) Resources(context.Context) []func() resource.Resou
314317
searchdeployment.Resource,
315318
pushbasedlogexport.Resource,
316319
streaminstance.Resource,
320+
streamworkspace.Resource,
317321
streamconnection.Resource,
318322
streamprocessor.Resource,
319323
encryptionatrestprivateendpoint.Resource,
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package streamworkspace
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-framework/datasource"
7+
"github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion"
8+
"github.com/mongodb/terraform-provider-mongodbatlas/internal/config"
9+
"github.com/mongodb/terraform-provider-mongodbatlas/internal/service/streaminstance"
10+
)
11+
12+
var _ datasource.DataSource = &streamsWorkspaceDS{}
13+
var _ datasource.DataSourceWithConfigure = &streamsWorkspaceDS{}
14+
15+
func DataSource() datasource.DataSource {
16+
return &streamsWorkspaceDS{
17+
DSCommon: config.DSCommon{
18+
DataSourceName: streamsWorkspaceName,
19+
},
20+
}
21+
}
22+
23+
type streamsWorkspaceDS struct {
24+
config.DSCommon
25+
}
26+
27+
func (d *streamsWorkspaceDS) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
28+
resp.Schema = conversion.DataSourceSchemaFromResource(ResourceSchema(ctx), &conversion.DataSourceSchemaRequest{
29+
RequiredFields: []string{"project_id", "workspace_name"},
30+
})
31+
}
32+
33+
func (d *streamsWorkspaceDS) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
34+
var streamsWorkspaceConfig TFStreamsWorkspaceModel
35+
resp.Diagnostics.Append(req.Config.Get(ctx, &streamsWorkspaceConfig)...)
36+
if resp.Diagnostics.HasError() {
37+
return
38+
}
39+
40+
connV2 := d.Client.AtlasV2
41+
projectID := streamsWorkspaceConfig.ProjectID.ValueString()
42+
workspaceName := streamsWorkspaceConfig.WorkspaceName.ValueString()
43+
apiResp, _, err := connV2.StreamsApi.GetStreamWorkspace(ctx, projectID, workspaceName).Execute()
44+
if err != nil {
45+
resp.Diagnostics.AddError("error fetching resource", err.Error())
46+
return
47+
}
48+
49+
newInstanceModel, diags := streaminstance.NewTFStreamInstance(ctx, apiResp)
50+
if diags.HasError() {
51+
resp.Diagnostics.Append(diags...)
52+
return
53+
}
54+
55+
// Convert instance model to workspace model
56+
var newWorkspaceModel TFStreamsWorkspaceModel
57+
newWorkspaceModel.FromInstanceModel(newInstanceModel)
58+
59+
resp.Diagnostics.Append(resp.State.Set(ctx, newWorkspaceModel)...)
60+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package streamworkspace_test
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
8+
"github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/acc"
9+
)
10+
11+
func TestAccStreamsWorkspaceDS_basic(t *testing.T) {
12+
var (
13+
dataSourceName = "data.mongodbatlas_stream_workspace.test"
14+
projectID = acc.ProjectIDExecution(t)
15+
workspaceName = acc.RandomName()
16+
)
17+
18+
resource.ParallelTest(t, resource.TestCase{
19+
PreCheck: func() { acc.PreCheckBasic(t) },
20+
ProtoV6ProviderFactories: acc.TestAccProviderV6Factories,
21+
CheckDestroy: acc.CheckDestroyStreamInstance,
22+
Steps: []resource.TestStep{
23+
{
24+
Config: streamsWorkspaceDataSourceConfig(projectID, workspaceName, region, cloudProvider),
25+
Check: resource.ComposeAggregateTestCheckFunc(
26+
streamsWorkspaceAttributeChecks(dataSourceName, workspaceName, region, cloudProvider),
27+
resource.TestCheckResourceAttr(dataSourceName, "stream_config.tier", "SP30"),
28+
),
29+
},
30+
},
31+
})
32+
}
33+
34+
func streamsWorkspaceDataSourceConfig(projectID, workspaceName, region, cloudProvider string) string {
35+
return fmt.Sprintf(`
36+
%s
37+
38+
data "mongodbatlas_stream_workspace" "test" {
39+
project_id = mongodbatlas_stream_workspace.test.project_id
40+
workspace_name = mongodbatlas_stream_workspace.test.workspace_name
41+
}
42+
`, streamsWorkspaceConfig(projectID, workspaceName, region, cloudProvider))
43+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package streamworkspace
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/hashicorp/terraform-plugin-framework/datasource"
8+
"github.com/hashicorp/terraform-plugin-framework/diag"
9+
"github.com/hashicorp/terraform-plugin-framework/types"
10+
"github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion"
11+
"github.com/mongodb/terraform-provider-mongodbatlas/internal/config"
12+
"github.com/mongodb/terraform-provider-mongodbatlas/internal/service/streaminstance"
13+
"go.mongodb.org/atlas-sdk/v20250312008/admin"
14+
)
15+
16+
var _ datasource.DataSource = &streamsWorkspacesDS{}
17+
var _ datasource.DataSourceWithConfigure = &streamsWorkspacesDS{}
18+
19+
func PluralDataSource() datasource.DataSource {
20+
return &streamsWorkspacesDS{
21+
DSCommon: config.DSCommon{
22+
DataSourceName: fmt.Sprintf("%ss", streamsWorkspaceName),
23+
},
24+
}
25+
}
26+
27+
type streamsWorkspacesDS struct {
28+
config.DSCommon
29+
}
30+
31+
func (d *streamsWorkspacesDS) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
32+
resp.Schema = conversion.PluralDataSourceSchemaFromResource(ResourceSchema(ctx), &conversion.PluralDataSourceSchemaRequest{
33+
RequiredFields: []string{"project_id"},
34+
HasLegacyFields: true,
35+
})
36+
}
37+
38+
func (d *streamsWorkspacesDS) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
39+
var streamsWorkspacesConfig TFStreamsWorkspacesModel
40+
resp.Diagnostics.Append(req.Config.Get(ctx, &streamsWorkspacesConfig)...)
41+
if resp.Diagnostics.HasError() {
42+
return
43+
}
44+
45+
connV2 := d.Client.AtlasV2
46+
projectID := streamsWorkspacesConfig.ProjectID.ValueString()
47+
itemsPerPage := streamsWorkspacesConfig.ItemsPerPage.ValueInt64Pointer()
48+
pageNum := streamsWorkspacesConfig.PageNum.ValueInt64Pointer()
49+
apiResp, _, err := connV2.StreamsApi.ListStreamWorkspacesWithParams(ctx, &admin.ListStreamWorkspacesApiParams{
50+
GroupId: projectID,
51+
ItemsPerPage: conversion.Int64PtrToIntPtr(itemsPerPage),
52+
PageNum: conversion.Int64PtrToIntPtr(pageNum),
53+
}).Execute()
54+
if err != nil {
55+
resp.Diagnostics.AddError("error fetching results", err.Error())
56+
return
57+
}
58+
59+
newStreamsWorkspacesModel, diags := NewTFStreamsWorkspaces(ctx, &streamsWorkspacesConfig, apiResp)
60+
if diags.HasError() {
61+
resp.Diagnostics.Append(diags...)
62+
return
63+
}
64+
resp.Diagnostics.Append(resp.State.Set(ctx, newStreamsWorkspacesModel)...)
65+
}
66+
67+
type TFStreamsWorkspacesModel struct {
68+
ID types.String `tfsdk:"id"`
69+
ProjectID types.String `tfsdk:"project_id"`
70+
Results []TFStreamsWorkspaceModel `tfsdk:"results"`
71+
PageNum types.Int64 `tfsdk:"page_num"`
72+
ItemsPerPage types.Int64 `tfsdk:"items_per_page"`
73+
TotalCount types.Int64 `tfsdk:"total_count"`
74+
}
75+
76+
func NewTFStreamsWorkspaces(ctx context.Context, streamsWorkspacesConfig *TFStreamsWorkspacesModel, apiResp *admin.PaginatedApiStreamsTenant) (*TFStreamsWorkspacesModel, diag.Diagnostics) {
77+
var diags diag.Diagnostics
78+
79+
// Convert the stream instances response to stream instances model first
80+
instancesModel := &streaminstance.TFStreamInstancesModel{
81+
ID: streamsWorkspacesConfig.ID,
82+
ProjectID: streamsWorkspacesConfig.ProjectID,
83+
PageNum: streamsWorkspacesConfig.PageNum,
84+
ItemsPerPage: streamsWorkspacesConfig.ItemsPerPage,
85+
}
86+
87+
newInstancesModel, instanceDiags := streaminstance.NewTFStreamInstances(ctx, instancesModel, apiResp)
88+
if instanceDiags.HasError() {
89+
diags.Append(instanceDiags...)
90+
return nil, diags
91+
}
92+
93+
// Convert each instance result to workspace result
94+
workspaceResults := make([]TFStreamsWorkspaceModel, len(newInstancesModel.Results))
95+
for i := range newInstancesModel.Results {
96+
workspaceResults[i].FromInstanceModel(&newInstancesModel.Results[i])
97+
}
98+
99+
return &TFStreamsWorkspacesModel{
100+
ID: newInstancesModel.ID,
101+
ProjectID: newInstancesModel.ProjectID,
102+
Results: workspaceResults,
103+
PageNum: newInstancesModel.PageNum,
104+
ItemsPerPage: newInstancesModel.ItemsPerPage,
105+
TotalCount: newInstancesModel.TotalCount,
106+
}, diags
107+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package streamworkspace_test
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
8+
"github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/acc"
9+
)
10+
11+
func TestAccStreamsWorkspacesDS_basic(t *testing.T) {
12+
var (
13+
dataSourceName = "data.mongodbatlas_stream_workspaces.test"
14+
projectID = acc.ProjectIDExecution(t)
15+
workspaceName = acc.RandomName()
16+
)
17+
18+
checks := []resource.TestCheckFunc{
19+
resource.TestCheckResourceAttrSet(dataSourceName, "project_id"),
20+
resource.TestCheckResourceAttrSet(dataSourceName, "results.#"),
21+
resource.TestCheckResourceAttrSet(dataSourceName, "results.0.workspace_name"),
22+
resource.TestCheckResourceAttrSet(dataSourceName, "results.0.data_process_region.region"),
23+
resource.TestCheckResourceAttrSet(dataSourceName, "results.0.data_process_region.cloud_provider"),
24+
resource.TestCheckResourceAttrSet(dataSourceName, "results.0.hostnames.#"),
25+
}
26+
27+
resource.ParallelTest(t, resource.TestCase{
28+
PreCheck: func() { acc.PreCheckBasic(t) },
29+
ProtoV6ProviderFactories: acc.TestAccProviderV6Factories,
30+
CheckDestroy: acc.CheckDestroyStreamInstance,
31+
Steps: []resource.TestStep{
32+
{
33+
Config: streamsWorkspacesDataSourceConfig(projectID, workspaceName, region, cloudProvider),
34+
Check: resource.ComposeAggregateTestCheckFunc(checks...),
35+
},
36+
},
37+
})
38+
}
39+
40+
func TestAccStreamsWorkspacesDS_withPageConfig(t *testing.T) {
41+
var (
42+
dataSourceName = "data.mongodbatlas_stream_workspaces.test"
43+
projectID = acc.ProjectIDExecution(t)
44+
workspaceName = acc.RandomName()
45+
pageNumber = 1000 // high page number so no results are returned
46+
)
47+
48+
resource.ParallelTest(t, resource.TestCase{
49+
PreCheck: func() { acc.PreCheckBasic(t) },
50+
ProtoV6ProviderFactories: acc.TestAccProviderV6Factories,
51+
CheckDestroy: acc.CheckDestroyStreamInstance,
52+
Steps: []resource.TestStep{
53+
{
54+
Config: streamsWorkspacesWithPageAttrDataSourceConfig(projectID, workspaceName, region, cloudProvider, pageNumber),
55+
Check: resource.ComposeAggregateTestCheckFunc(
56+
resource.TestCheckResourceAttr(dataSourceName, "results.#", "0"),
57+
),
58+
},
59+
},
60+
})
61+
}
62+
63+
func streamsWorkspacesDataSourceConfig(projectID, workspaceName, region, cloudProvider string) string {
64+
return fmt.Sprintf(`
65+
%s
66+
67+
data "mongodbatlas_stream_workspaces" "test" {
68+
project_id = mongodbatlas_stream_workspace.test.project_id
69+
}
70+
`, streamsWorkspaceConfig(projectID, workspaceName, region, cloudProvider))
71+
}
72+
73+
func streamsWorkspacesWithPageAttrDataSourceConfig(projectID, workspaceName, region, cloudProvider string, pageNum int) string {
74+
return fmt.Sprintf(`
75+
%s
76+
77+
data "mongodbatlas_stream_workspaces" "test" {
78+
project_id = mongodbatlas_stream_workspace.test.project_id
79+
page_num = %d
80+
items_per_page = 1
81+
}
82+
`, streamsWorkspaceConfig(projectID, workspaceName, region, cloudProvider), pageNum)
83+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package streamworkspace
2+
3+
import (
4+
"github.com/mongodb/terraform-provider-mongodbatlas/internal/service/streaminstance"
5+
)
6+
7+
// AsInstanceModel returns a TFStreamInstanceModel with workspace_name mapped to instance_name
8+
// This eliminates the need for conversion functions by reusing the same underlying data
9+
func (m *TFStreamsWorkspaceModel) AsInstanceModel() *streaminstance.TFStreamInstanceModel {
10+
return &streaminstance.TFStreamInstanceModel{
11+
ID: m.ID,
12+
InstanceName: m.WorkspaceName, // Map workspace_name to instance_name
13+
ProjectID: m.ProjectID,
14+
DataProcessRegion: m.DataProcessRegion,
15+
StreamConfig: m.StreamConfig,
16+
Hostnames: m.Hostnames,
17+
}
18+
}
19+
20+
// FromInstanceModel populates this workspace model from a TFStreamInstanceModel
21+
// This eliminates the need for conversion functions by directly updating fields
22+
func (m *TFStreamsWorkspaceModel) FromInstanceModel(instanceModel *streaminstance.TFStreamInstanceModel) {
23+
m.ID = instanceModel.ID
24+
m.WorkspaceName = instanceModel.InstanceName // Map instance_name to workspace_name
25+
m.ProjectID = instanceModel.ProjectID
26+
m.DataProcessRegion = instanceModel.DataProcessRegion
27+
m.StreamConfig = instanceModel.StreamConfig
28+
m.Hostnames = instanceModel.Hostnames
29+
}

0 commit comments

Comments
 (0)