-
Notifications
You must be signed in to change notification settings - Fork 178
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: new
mongodbatlas_stream_instance
resource (#1685)
* feat: new mongodbatlas_stream_instance resource implementation * unit testing for sdk to TF model * unit testing for tf to sdk models * include acceptance tests * add test case for potential empty fields * resource documentation * include example section * configure acceptance tests in CI * include missing step for terraform setup * Update website/docs/r/stream_instance.html.markdown Co-authored-by: Andrea Angiolillo <[email protected]> * remove redundant return statement in import function * addressing doc comments --------- Co-authored-by: Andrea Angiolillo <[email protected]>
- Loading branch information
1 parent
a8dfd1b
commit ebe95d4
Showing
12 changed files
with
690 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# MongoDB Atlas Provider - Atlas Stream Instance defined in a Project | ||
|
||
This example shows how to use Atlas Stream Instances in Terraform. It also creates a project, which is a prerequisite. | ||
|
||
You must set the following variables: | ||
|
||
- `public_key`: Atlas public key | ||
- `private_key`: Atlas private key | ||
- `org_id`: Unique 24-hexadecimal digit string that identifies the Organization that must contain the project. | ||
|
||
To learn more, see the [Stream Instance Documentation](https://www.mongodb.com/docs/atlas/atlas-sp/manage-processing-instance/#configure-a-stream-processing-instance). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
resource "mongodbatlas_project" "example" { | ||
name = "project-name" | ||
org_id = var.org_id | ||
} | ||
|
||
resource "mongodbatlas_stream_instance" "example" { | ||
project_id = mongodbatlas_project.example | ||
instance_name = "InstanceName" | ||
data_process_region = { | ||
region = "VIRGINIA_USA" | ||
cloud_provider = "AWS" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
provider "mongodbatlas" { | ||
public_key = var.public_key | ||
private_key = var.private_key | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
variable "public_key" { | ||
description = "Public API key to authenticate to Atlas" | ||
type = string | ||
} | ||
variable "private_key" { | ||
description = "Private API key to authenticate to Atlas" | ||
type = string | ||
} | ||
variable "org_id" { | ||
description = "Unique 24-hexadecimal digit string that identifies your Atlas Organization" | ||
type = string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
terraform { | ||
required_providers { | ||
mongodbatlas = { | ||
source = "mongodb/mongodbatlas" | ||
version = "~> 1.14" | ||
} | ||
} | ||
required_version = ">= 1.0" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package streaminstance | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/diag" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
"github.com/hashicorp/terraform-plugin-framework/types/basetypes" | ||
"go.mongodb.org/atlas-sdk/v20231115002/admin" | ||
) | ||
|
||
func NewStreamInstanceCreateReq(ctx context.Context, plan *TFStreamInstanceRSModel) (*admin.StreamsTenant, diag.Diagnostics) { | ||
dataProcessRegion := &TFInstanceProcessRegionSpecModel{} | ||
if diags := plan.DataProcessRegion.As(ctx, dataProcessRegion, basetypes.ObjectAsOptions{}); diags.HasError() { | ||
return nil, diags | ||
} | ||
return &admin.StreamsTenant{ | ||
GroupId: plan.ProjectID.ValueStringPointer(), | ||
Name: plan.InstanceName.ValueStringPointer(), | ||
DataProcessRegion: &admin.StreamsDataProcessRegion{ | ||
CloudProvider: dataProcessRegion.CloudProvider.ValueString(), | ||
Region: dataProcessRegion.Region.ValueString(), | ||
}, | ||
}, nil | ||
} | ||
|
||
func NewStreamInstanceUpdateReq(ctx context.Context, plan *TFStreamInstanceRSModel) (*admin.StreamsDataProcessRegion, diag.Diagnostics) { | ||
dataProcessRegion := &TFInstanceProcessRegionSpecModel{} | ||
if diags := plan.DataProcessRegion.As(ctx, dataProcessRegion, basetypes.ObjectAsOptions{}); diags.HasError() { | ||
return nil, diags | ||
} | ||
return &admin.StreamsDataProcessRegion{ | ||
CloudProvider: dataProcessRegion.CloudProvider.ValueString(), | ||
Region: dataProcessRegion.Region.ValueString(), | ||
}, nil | ||
} | ||
|
||
func NewTFStreamInstance(ctx context.Context, apiResp *admin.StreamsTenant) (*TFStreamInstanceRSModel, diag.Diagnostics) { | ||
hostnames, diags := types.ListValueFrom(ctx, types.StringType, apiResp.Hostnames) | ||
|
||
var dataProcessRegion = types.ObjectNull(ProcessRegionObjectType.AttrTypes) | ||
if apiResp.DataProcessRegion != nil { | ||
returnedProcessRegion, diagsProcessRegion := types.ObjectValueFrom(ctx, ProcessRegionObjectType.AttrTypes, TFInstanceProcessRegionSpecModel{ | ||
CloudProvider: types.StringValue(apiResp.DataProcessRegion.CloudProvider), | ||
Region: types.StringValue(apiResp.DataProcessRegion.Region), | ||
}) | ||
dataProcessRegion = returnedProcessRegion | ||
diags.Append(diagsProcessRegion...) | ||
} | ||
if diags.HasError() { | ||
return nil, diags | ||
} | ||
|
||
return &TFStreamInstanceRSModel{ | ||
ID: types.StringPointerValue(apiResp.Id), | ||
InstanceName: types.StringPointerValue(apiResp.Name), | ||
ProjectID: types.StringPointerValue(apiResp.GroupId), | ||
DataProcessRegion: dataProcessRegion, | ||
Hostnames: hostnames, | ||
}, nil | ||
} |
174 changes: 174 additions & 0 deletions
174
internal/service/streaminstance/model_stream_instance_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
package streaminstance_test | ||
|
||
import ( | ||
"context" | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
"github.com/mongodb/terraform-provider-mongodbatlas/internal/service/streaminstance" | ||
"go.mongodb.org/atlas-sdk/v20231115002/admin" | ||
) | ||
|
||
type sdkToTFModelTestCase struct { | ||
SDKResp *admin.StreamsTenant | ||
expectedTFModel *streaminstance.TFStreamInstanceRSModel | ||
name string | ||
} | ||
|
||
const ( | ||
dummyProjectID = "111111111111111111111111" | ||
dummyStreamInstanceID = "222222222222222222222222" | ||
cloudProvider = "AWS" | ||
region = "VIRGINIA_USA" | ||
instanceName = "InstanceName" | ||
) | ||
|
||
var hostnames = []string{"atlas-stream.virginia-usa.a.query.mongodb-dev.net"} | ||
|
||
func TestStreamInstanceSDKToTFModel(t *testing.T) { | ||
testCases := []sdkToTFModelTestCase{ | ||
{ | ||
name: "Complete SDK response", | ||
SDKResp: &admin.StreamsTenant{ | ||
Id: admin.PtrString(dummyStreamInstanceID), | ||
DataProcessRegion: &admin.StreamsDataProcessRegion{ | ||
CloudProvider: cloudProvider, | ||
Region: region, | ||
}, | ||
GroupId: admin.PtrString(dummyProjectID), | ||
Hostnames: hostnames, | ||
Name: admin.PtrString(instanceName), | ||
}, | ||
expectedTFModel: &streaminstance.TFStreamInstanceRSModel{ | ||
ID: types.StringValue(dummyStreamInstanceID), | ||
DataProcessRegion: tfRegionObject(t, cloudProvider, region), | ||
ProjectID: types.StringValue(dummyProjectID), | ||
Hostnames: tfHostnamesList(t, hostnames), | ||
InstanceName: types.StringValue(instanceName), | ||
}, | ||
}, | ||
{ | ||
name: "Empty hostnames and dataProcessRegion in response", // should never happen, but verifying it is handled gracefully | ||
SDKResp: &admin.StreamsTenant{ | ||
Id: admin.PtrString(dummyStreamInstanceID), | ||
GroupId: admin.PtrString(dummyProjectID), | ||
Name: admin.PtrString(instanceName), | ||
}, | ||
expectedTFModel: &streaminstance.TFStreamInstanceRSModel{ | ||
ID: types.StringValue(dummyStreamInstanceID), | ||
DataProcessRegion: types.ObjectNull(streaminstance.ProcessRegionObjectType.AttrTypes), | ||
ProjectID: types.StringValue(dummyProjectID), | ||
Hostnames: types.ListNull(types.StringType), | ||
InstanceName: types.StringValue(instanceName), | ||
}, | ||
}, | ||
} | ||
|
||
for _, tc := range testCases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
resultModel, diags := streaminstance.NewTFStreamInstance(context.Background(), tc.SDKResp) | ||
if diags.HasError() { | ||
t.Errorf("unexpected errors found: %s", diags.Errors()[0].Summary()) | ||
} | ||
if !reflect.DeepEqual(resultModel, tc.expectedTFModel) { | ||
t.Errorf("created terraform model did not match expected output") | ||
} | ||
}) | ||
} | ||
} | ||
|
||
type tfToSDKCreateModelTestCase struct { | ||
tfModel *streaminstance.TFStreamInstanceRSModel | ||
expectedSDKReq *admin.StreamsTenant | ||
name string | ||
} | ||
|
||
func TestStreamInstanceTFToSDKCreateModel(t *testing.T) { | ||
testCases := []tfToSDKCreateModelTestCase{ | ||
{ | ||
name: "Complete TF state", | ||
tfModel: &streaminstance.TFStreamInstanceRSModel{ | ||
DataProcessRegion: tfRegionObject(t, cloudProvider, region), | ||
ProjectID: types.StringValue(dummyProjectID), | ||
InstanceName: types.StringValue(instanceName), | ||
}, | ||
expectedSDKReq: &admin.StreamsTenant{ | ||
DataProcessRegion: &admin.StreamsDataProcessRegion{ | ||
CloudProvider: cloudProvider, | ||
Region: region, | ||
}, | ||
GroupId: admin.PtrString(dummyProjectID), | ||
Name: admin.PtrString(instanceName), | ||
}, | ||
}, | ||
} | ||
|
||
for _, tc := range testCases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
apiReqResult, diags := streaminstance.NewStreamInstanceCreateReq(context.Background(), tc.tfModel) | ||
if diags.HasError() { | ||
t.Errorf("unexpected errors found: %s", diags.Errors()[0].Summary()) | ||
} | ||
if !reflect.DeepEqual(apiReqResult, tc.expectedSDKReq) { | ||
t.Errorf("created sdk model did not match expected output") | ||
} | ||
}) | ||
} | ||
} | ||
|
||
type tfToSDKUpdateModelTestCase struct { | ||
tfModel *streaminstance.TFStreamInstanceRSModel | ||
expectedSDKReq *admin.StreamsDataProcessRegion | ||
name string | ||
} | ||
|
||
func TestStreamInstanceTFToSDKUpdateModel(t *testing.T) { | ||
testCases := []tfToSDKUpdateModelTestCase{ | ||
{ | ||
name: "Complete TF state", | ||
tfModel: &streaminstance.TFStreamInstanceRSModel{ | ||
ID: types.StringValue(dummyStreamInstanceID), | ||
DataProcessRegion: tfRegionObject(t, cloudProvider, region), | ||
ProjectID: types.StringValue(dummyProjectID), | ||
Hostnames: tfHostnamesList(t, hostnames), | ||
InstanceName: types.StringValue(instanceName), | ||
}, | ||
expectedSDKReq: &admin.StreamsDataProcessRegion{ | ||
CloudProvider: cloudProvider, | ||
Region: region, | ||
}, | ||
}, | ||
} | ||
|
||
for _, tc := range testCases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
apiReqResult, diags := streaminstance.NewStreamInstanceUpdateReq(context.Background(), tc.tfModel) | ||
if diags.HasError() { | ||
t.Errorf("unexpected errors found: %s", diags.Errors()[0].Summary()) | ||
} | ||
if !reflect.DeepEqual(apiReqResult, tc.expectedSDKReq) { | ||
t.Errorf("created sdk model did not match expected output") | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func tfRegionObject(t *testing.T, cloudProvider, region string) types.Object { | ||
dataProcessRegion, diags := types.ObjectValueFrom(context.Background(), streaminstance.ProcessRegionObjectType.AttrTypes, streaminstance.TFInstanceProcessRegionSpecModel{ | ||
CloudProvider: types.StringValue(cloudProvider), | ||
Region: types.StringValue(region), | ||
}) | ||
if diags.HasError() { | ||
t.Errorf("failed to create terraform data process region model: %s", diags.Errors()[0].Summary()) | ||
} | ||
return dataProcessRegion | ||
} | ||
|
||
func tfHostnamesList(t *testing.T, hostnames []string) types.List { | ||
resultList, diags := types.ListValueFrom(context.Background(), types.StringType, hostnames) | ||
if diags.HasError() { | ||
t.Errorf("failed to create terraform hostnames list: %s", diags.Errors()[0].Summary()) | ||
} | ||
return resultList | ||
} |
Oops, something went wrong.