Skip to content

Commit c76074c

Browse files
INTMDB-803: [Terraform] Create a new Private Endpoint resource and data sources which supports Federated Database Instance and Online Archive (#1182)
1 parent 7690cb5 commit c76074c

17 files changed

+1039
-129
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Example - Privatelink for Data Federation and Online Archive
2+
3+
Setup private connection to a [Data Federation or Online Archive](https://www.mongodb.com/docs/atlas/data-federation/tutorial/config-private-endpoint/) utilizing [Amazon Virtual Private Cloud (aws vpc)](https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html).
4+
5+
6+
## Dependencies
7+
8+
* Terraform v0.13
9+
* An AWS account - provider.aws: version = "~> 4"
10+
* A MongoDB Atlas account - provider.mongodbatlas: version = "~> 1.10"
11+
12+
## Usage
13+
14+
**1\. Ensure your AWS and MongoDB Atlas credentials are set up.**
15+
16+
This can be done using environment variables:
17+
18+
```bash
19+
export MONGODB_ATLAS_PUBLIC_KEY="xxxx"
20+
export MONGODB_ATLAS_PRIVATE_KEY="xxxx"
21+
```
22+
23+
``` bash
24+
$ export AWS_SECRET_ACCESS_KEY='your secret key'
25+
$ export AWS_ACCESS_KEY_ID='your key id'
26+
```
27+
28+
... or the `~/.aws/credentials` file.
29+
30+
```
31+
$ cat ~/.aws/credentials
32+
[default]
33+
aws_access_key_id = your key id
34+
aws_secret_access_key = your secret key
35+
36+
```
37+
... or follow as in the `variables.tf` file and create **terraform.tfvars** file with all the variable values, ex:
38+
```
39+
access_key = "<AWS_ACCESS_KEY_ID>"
40+
secret_key = "<AWS_SECRET_ACCESS_KEY>"
41+
public_key = "<MONGODB_ATLAS_PUBLIC_KEY>"
42+
private_key = "<MONGODB_ATLAS_PRIVATE_KEY>"
43+
project_id = "<MONGODB_ATLAS_PROJECT_ID>"
44+
```
45+
46+
**2\. Review the Terraform plan.**
47+
48+
Execute the below command and ensure you are happy with the plan.
49+
50+
``` bash
51+
$ terraform plan
52+
```
53+
This project currently performs the below deployments:
54+
55+
- MongoDB Atlas Dedicated Cluster - M10
56+
- AWS Custom VPC, Internet Gateway, Route Tables, Subnets with Public and Private access
57+
- PrivateLink Connection at MongoDB Atlas
58+
- Create VPC Endpoint in AWS
59+
60+
**3\. Configure the security group as required.**
61+
62+
The security group in this configuration allows All Traffic access in Inbound and Outbound Rules.
63+
64+
**4\. Execute the Terraform apply.**
65+
66+
Now execute the plan to provision the AWS and Atlas resources.
67+
68+
``` bash
69+
$ terraform apply
70+
```
71+
72+
**5\. Destroy the resources.**
73+
74+
Once you are finished your testing, ensure you destroy the resources to avoid unnecessary charges.
75+
76+
``` bash
77+
$ terraform destroy
78+
```
79+
80+
**What's the resource dependency chain?**
81+
1. `mongodbatlas_project` must exist for any of the following
82+
2. `aws_vpc_endpoint` is dependent on the `mongodbatlas_privatelink_endpoint`, and its dependencies.
83+
3. `mongodbatlas_privatelink_endpoint_service` is dependent on `aws_vpc_endpoint` and its dependencies.
84+
4. `mongodbatlas_privatelink_endpoint_service_data_federation_online_archive` is dependent on the `mongodbatlas_project` and `aws_vpc_endpoint`
85+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
resource "mongodbatlas_privatelink_endpoint" "pe_east" {
2+
project_id = var.project_id
3+
provider_name = "AWS"
4+
region = "us-east-1"
5+
}
6+
7+
resource "mongodbatlas_privatelink_endpoint_service_data_federation_online_archive" "test" {
8+
project_id = var.project_id
9+
endpoint_id = aws_vpc_endpoint.vpce_east.id
10+
provider_name = "AWS"
11+
comment = "Terraform Acceptance Test"
12+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
resource "aws_vpc_endpoint" "vpce_east" {
2+
vpc_id = aws_vpc.vpc_east.id
3+
service_name = mongodbatlas_privatelink_endpoint.pe_east.endpoint_service_name
4+
vpc_endpoint_type = "Interface"
5+
subnet_ids = [aws_subnet.subnet_east_a.id, aws_subnet.subnet_east_b.id]
6+
security_group_ids = [aws_security_group.sg_east.id]
7+
}
8+
9+
resource "aws_vpc" "vpc_east" {
10+
cidr_block = "10.0.0.0/16"
11+
enable_dns_hostnames = true
12+
enable_dns_support = true
13+
}
14+
15+
resource "aws_internet_gateway" "ig_east" {
16+
vpc_id = aws_vpc.vpc_east.id
17+
}
18+
19+
resource "aws_route" "route_east" {
20+
route_table_id = aws_vpc.vpc_east.main_route_table_id
21+
destination_cidr_block = "0.0.0.0/0"
22+
gateway_id = aws_internet_gateway.ig_east.id
23+
}
24+
25+
resource "aws_subnet" "subnet_east_a" {
26+
vpc_id = aws_vpc.vpc_east.id
27+
cidr_block = "10.0.1.0/24"
28+
map_public_ip_on_launch = true
29+
availability_zone = "us-east-1a"
30+
}
31+
32+
resource "aws_subnet" "subnet_east_b" {
33+
vpc_id = aws_vpc.vpc_east.id
34+
cidr_block = "10.0.2.0/24"
35+
map_public_ip_on_launch = false
36+
availability_zone = "us-east-1b"
37+
}
38+
39+
resource "aws_security_group" "sg_east" {
40+
name_prefix = "default-"
41+
description = "Default security group for all instances in vpc"
42+
vpc_id = aws_vpc.vpc_east.id
43+
ingress {
44+
from_port = 0
45+
to_port = 0
46+
protocol = "tcp"
47+
cidr_blocks = [
48+
"0.0.0.0/0",
49+
]
50+
}
51+
egress {
52+
from_port = 0
53+
to_port = 0
54+
protocol = "-1"
55+
cidr_blocks = ["0.0.0.0/0"]
56+
}
57+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
provider "mongodbatlas" {
2+
public_key = var.public_key
3+
private_key = var.private_key
4+
}
5+
provider "aws" {
6+
access_key = var.access_key
7+
secret_key = var.secret_key
8+
region = "us-east-1"
9+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
variable "public_key" {
2+
description = "The public API key for MongoDB Atlas"
3+
}
4+
variable "private_key" {
5+
description = "The private API key for MongoDB Atlas"
6+
}
7+
variable "access_key" {
8+
description = "The access key for AWS Account"
9+
}
10+
variable "secret_key" {
11+
description = "The secret key for AWS Account"
12+
}
13+
variable "project_id" {
14+
description = "Atlas project ID"
15+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
terraform {
2+
required_providers {
3+
aws = {
4+
source = "hashicorp/aws"
5+
}
6+
mongodbatlas = {
7+
source = "mongodb/mongodbatlas"
8+
}
9+
}
10+
required_version = ">= 0.13"
11+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package mongodbatlas
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
8+
)
9+
10+
func dataSourceMongoDBAtlasPrivatelinkEndpointServiceDataFederationOnlineArchive() *schema.Resource {
11+
return &schema.Resource{
12+
ReadContext: dataSourceMongoDBAtlasPrivatelinkEndpointServiceDataFederationOnlineArchiveRead,
13+
Schema: map[string]*schema.Schema{
14+
"project_id": {
15+
Type: schema.TypeString,
16+
Required: true,
17+
},
18+
"endpoint_id": {
19+
Type: schema.TypeString,
20+
Required: true,
21+
},
22+
"provider_name": {
23+
Type: schema.TypeString,
24+
Computed: true,
25+
},
26+
"comment": {
27+
Type: schema.TypeString,
28+
Computed: true,
29+
},
30+
"type": {
31+
Type: schema.TypeString,
32+
Computed: true,
33+
},
34+
},
35+
}
36+
}
37+
38+
func dataSourceMongoDBAtlasPrivatelinkEndpointServiceDataFederationOnlineArchiveRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
39+
conn := meta.(*MongoDBClient).Atlas
40+
projectID := d.Get("project_id").(string)
41+
endopointID := d.Get("endpoint_id").(string)
42+
43+
privateEndpoint, _, err := conn.DataLakes.GetPrivateLinkEndpoint(context.Background(), projectID, endopointID)
44+
if err != nil {
45+
return diag.Errorf(errorPrivateEndpointServiceDataFederationOnlineArchiveRead, endopointID, projectID, err)
46+
}
47+
48+
if err := d.Set("comment", privateEndpoint.Comment); err != nil {
49+
return diag.Errorf(errorPrivateEndpointServiceDataFederationOnlineArchiveRead, endopointID, projectID, err)
50+
}
51+
52+
if err := d.Set("provider_name", privateEndpoint.Provider); err != nil {
53+
return diag.Errorf(errorPrivateEndpointServiceDataFederationOnlineArchiveRead, endopointID, projectID, err)
54+
}
55+
56+
if err := d.Set("type", privateEndpoint.Type); err != nil {
57+
return diag.Errorf(errorPrivateEndpointServiceDataFederationOnlineArchiveRead, endopointID, projectID, err)
58+
}
59+
60+
d.SetId(encodeStateID(map[string]string{
61+
"project_id": projectID,
62+
"endpoint_id": endopointID,
63+
}))
64+
65+
return nil
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package mongodbatlas
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8+
)
9+
10+
var (
11+
dataSourcePrivatelinkEndpointServiceDataFederetionDataArchive = "data.mongodbatlas_privatelink_endpoint_service_data_federation_online_archive.test"
12+
)
13+
14+
func TestAccDataSourceMongoDBAtlasPrivatelinkEndpointServiceDataFederationOnlineArchive_basic(t *testing.T) {
15+
testCheckPrivateEndpointServiceDataFederationOnlineArchiveRun(t)
16+
resource.Test(t, resource.TestCase{
17+
PreCheck: func() { testAccPreCheck(t) },
18+
ProviderFactories: testAccProviderFactories,
19+
CheckDestroy: testAccCheckMongoDBAtlasPrivateEndpointServiceDataFederationOnlineArchiveDestroy,
20+
Steps: []resource.TestStep{
21+
{
22+
Config: testAccDataSourceMongoDBAtlasPrivateEndpointServiceDataFederationOnlineArchiveConfig(projectID, endpointID),
23+
Check: resource.ComposeTestCheckFunc(
24+
testAccCheckMongoDBAtlasPrivateEndpointServiceDataFederationOnlineArchiveExists(resourceNamePrivatelinkEdnpointServiceDataFederationOnlineArchive),
25+
resource.TestCheckResourceAttr(dataSourcePrivatelinkEndpointServiceDataFederetionDataArchive, "project_id", projectID),
26+
resource.TestCheckResourceAttr(dataSourcePrivatelinkEndpointServiceDataFederetionDataArchive, "endpoint_id", endpointID),
27+
resource.TestCheckResourceAttrSet(dataSourcePrivatelinkEndpointServiceDataFederetionDataArchive, "comment"),
28+
resource.TestCheckResourceAttrSet(dataSourcePrivatelinkEndpointServiceDataFederetionDataArchive, "type"),
29+
resource.TestCheckResourceAttrSet(dataSourcePrivatelinkEndpointServiceDataFederetionDataArchive, "provider_name"),
30+
),
31+
},
32+
},
33+
})
34+
}
35+
36+
func testAccDataSourceMongoDBAtlasPrivateEndpointServiceDataFederationOnlineArchiveConfig(projectID, endpointID string) string {
37+
return fmt.Sprintf(`
38+
resource "mongodbatlas_privatelink_endpoint_service_data_federation_online_archive" "test" {
39+
project_id = %[1]q
40+
endpoint_id = %[2]q
41+
provider_name = "AWS"
42+
comment = "Terraform Acceptance Test"
43+
}
44+
45+
data "mongodbatlas_privatelink_endpoint_service_data_federation_online_archive" "test" {
46+
project_id = mongodbatlas_privatelink_endpoint_service_data_federation_online_archive.test.project_id
47+
endpoint_id = mongodbatlas_privatelink_endpoint_service_data_federation_online_archive.test.endpoint_id
48+
}
49+
`, projectID, endpointID)
50+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package mongodbatlas
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
10+
matlas "go.mongodb.org/atlas/mongodbatlas"
11+
)
12+
13+
const errorPrivateEndpointServiceDataFederationOnlineArchiveList = "error reading Private Endpoings for projectId %s: %s"
14+
15+
func dataSourceMongoDBAtlasPrivatelinkEndpointServiceDataFederationOnlineArchives() *schema.Resource {
16+
return &schema.Resource{
17+
ReadContext: dataSourceMongoDBAtlasPrivatelinkEndpointServiceDataFederationOnlineArchivesRead,
18+
Schema: map[string]*schema.Schema{
19+
"project_id": {
20+
Type: schema.TypeString,
21+
Required: true,
22+
},
23+
"results": {
24+
Type: schema.TypeList,
25+
Computed: true,
26+
Elem: &schema.Resource{
27+
Schema: map[string]*schema.Schema{
28+
"endpoint_id": {
29+
Type: schema.TypeString,
30+
Required: true,
31+
},
32+
"provider_name": {
33+
Type: schema.TypeString,
34+
Computed: true,
35+
},
36+
"comment": {
37+
Type: schema.TypeString,
38+
Computed: true,
39+
},
40+
"type": {
41+
Type: schema.TypeString,
42+
Computed: true,
43+
},
44+
},
45+
},
46+
},
47+
},
48+
}
49+
}
50+
51+
func dataSourceMongoDBAtlasPrivatelinkEndpointServiceDataFederationOnlineArchivesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
52+
conn := meta.(*MongoDBClient).Atlas
53+
projectID := d.Get("project_id").(string)
54+
55+
privateEndpoints, _, err := conn.DataLakes.ListPrivateLinkEndpoint(context.Background(), projectID)
56+
if err != nil {
57+
return diag.Errorf(errorPrivateEndpointServiceDataFederationOnlineArchiveList, projectID, err)
58+
}
59+
60+
if err := d.Set("results", flattenPrivateLinkEndpointDataLakeResponse(privateEndpoints.Results)); err != nil {
61+
return diag.FromErr(fmt.Errorf(errorDataLakeSetting, "results", projectID, err))
62+
}
63+
64+
d.SetId(id.UniqueId())
65+
66+
return nil
67+
}
68+
69+
func flattenPrivateLinkEndpointDataLakeResponse(atlasPrivateLinkEndpointDataLakes []*matlas.PrivateLinkEndpointDataLake) []map[string]interface{} {
70+
if len(atlasPrivateLinkEndpointDataLakes) == 0 {
71+
return []map[string]interface{}{}
72+
}
73+
74+
results := make([]map[string]interface{}, len(atlasPrivateLinkEndpointDataLakes))
75+
76+
for i, atlasPrivateLinkEndpointDataLake := range atlasPrivateLinkEndpointDataLakes {
77+
results[i] = map[string]interface{}{
78+
"endpoint_id": atlasPrivateLinkEndpointDataLake.EndpointID,
79+
"provider_name": atlasPrivateLinkEndpointDataLake.Provider,
80+
"comment": atlasPrivateLinkEndpointDataLake.Comment,
81+
"type": atlasPrivateLinkEndpointDataLake.Type,
82+
}
83+
}
84+
85+
return results
86+
}

0 commit comments

Comments
 (0)