Skip to content

Commit 96caea4

Browse files
sivaram-mongodbsivaram-mongodbParthasarathyV
authored
feat: update private-endpoint-aws resource (#1539)
Co-authored-by: sivaram-mongodb <sivaram@mongodb.com> Co-authored-by: ParthasarathyV <114770988+ParthasarathyV@users.noreply.github.com>
1 parent 34ad12b commit 96caea4

6 files changed

Lines changed: 164 additions & 33 deletions

File tree

cfn-resources/private-endpoint-aws/cmd/resource/model.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cfn-resources/private-endpoint-aws/cmd/resource/resource.go

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import (
2121
"net/http"
2222
"strings"
2323

24-
admin20231115014 "go.mongodb.org/atlas-sdk/v20231115014/admin"
24+
"go.mongodb.org/atlas-sdk/v20250312012/admin"
2525

2626
"github.com/aws-cloudformation/cloudformation-cli-go-plugin/cfn/handler"
2727
"github.com/aws/aws-sdk-go-v2/aws"
@@ -92,11 +92,13 @@ func Create(req handler.Request, prevModel *Model, currentModel *Model) (handler
9292
*privateEndpoint.ConnectionStatus == Rejected {
9393
return handler.ProgressEvent{
9494
OperationStatus: handler.Failed,
95-
Message: fmt.Sprintf("Connection was Rejected : %s", *privateEndpoint.ErrorMessage),
95+
Message: fmt.Sprintf("Connection was Rejected: %s", *privateEndpoint.ErrorMessage),
9696
ResourceModel: currentModel,
9797
}, nil
9898
}
9999

100+
currentModel.completeByAtlasModel(*privateEndpoint)
101+
100102
return handler.ProgressEvent{
101103
OperationStatus: handler.Success,
102104
Message: "Create Success",
@@ -115,17 +117,17 @@ func Create(req handler.Request, prevModel *Model, currentModel *Model) (handler
115117
}}, nil
116118
}
117119

118-
endpointRequest := admin20231115014.CreateEndpointRequest{
120+
endpointRequest := admin.CreateEndpointRequest{
119121
Id: currentModel.Id,
120122
}
121123

122-
privateEndpointRequest := client.Atlas20231115014.PrivateEndpointServicesApi.CreatePrivateEndpoint(context.Background(), *currentModel.ProjectId,
124+
privateEndpointRequest := client.AtlasSDK.PrivateEndpointServicesApi.CreatePrivateEndpoint(context.Background(), *currentModel.ProjectId,
123125
CloudProvider, *currentModel.EndpointServiceId, &endpointRequest)
124126

125127
_, response, err := privateEndpointRequest.Execute()
126128
defer response.Body.Close()
127129
if err != nil {
128-
if response.StatusCode == http.StatusConflict {
130+
if util.StatusConflict(response) {
129131
return progress_events.GetFailedEventByCode(
130132
fmt.Sprintf("error creating Serverless Private Endpoint %s", err.Error()),
131133
string(types.HandlerErrorCodeAlreadyExists),
@@ -146,8 +148,8 @@ func Create(req handler.Request, prevModel *Model, currentModel *Model) (handler
146148
}}, nil
147149
}
148150

149-
func getPrivateEndpoint(client *util.MongoDBClient, model *Model) (*admin20231115014.PrivateLinkEndpoint, *http.Response, error) {
150-
privateEndpointRequest := client.Atlas20231115014.PrivateEndpointServicesApi.GetPrivateEndpoint(context.Background(), *model.ProjectId,
151+
func getPrivateEndpoint(client *util.MongoDBClient, model *Model) (*admin.PrivateLinkEndpoint, *http.Response, error) {
152+
privateEndpointRequest := client.AtlasSDK.PrivateEndpointServicesApi.GetPrivateEndpoint(context.Background(), *model.ProjectId,
151153
CloudProvider, *model.Id, *model.EndpointServiceId)
152154
privateEndpoint, response, err := privateEndpointRequest.Execute()
153155

@@ -184,9 +186,11 @@ func Read(req handler.Request, prevModel *Model, currentModel *Model) (handler.P
184186
}, nil
185187
}
186188

187-
func (m *Model) completeByAtlasModel(privateEndpoint admin20231115014.PrivateLinkEndpoint) {
188-
m.ErrorMessage = privateEndpoint.ErrorMessage
189+
func (m *Model) completeByAtlasModel(privateEndpoint admin.PrivateLinkEndpoint) {
190+
m.InterfaceEndpointId = privateEndpoint.InterfaceEndpointId
191+
m.DeleteRequested = privateEndpoint.DeleteRequested
189192
m.ConnectionStatus = privateEndpoint.ConnectionStatus
193+
m.ErrorMessage = privateEndpoint.ErrorMessage
190194
}
191195

192196
// Update handles the Update event from the Cloudformation service.
@@ -215,37 +219,39 @@ func Delete(req handler.Request, prevModel *Model, currentModel *Model) (handler
215219
_, response, peError := getPrivateEndpoint(client, currentModel)
216220
defer response.Body.Close()
217221
if peError != nil {
218-
if response.StatusCode == http.StatusNotFound {
222+
if util.StatusNotFound(response) {
219223
return handler.ProgressEvent{
220224
OperationStatus: handler.Success,
221-
Message: "Create Success",
225+
Message: "Delete Success",
222226
}, nil
223227
}
224228
return progress_events.GetFailedEventByResponse("Error validating Private Endpoint deletion progress", response), nil
225229
}
226230

227231
return handler.ProgressEvent{
228232
OperationStatus: handler.InProgress,
229-
Message: "Create in progress",
233+
Message: "Delete in progress",
230234
CallbackDelaySeconds: 20,
231235
CallbackContext: map[string]interface{}{
232236
"state": "deleting",
233237
}}, nil
234238
}
235239

236-
privateEndpointRequest := client.Atlas20231115014.PrivateEndpointServicesApi.DeletePrivateEndpoint(context.Background(), *currentModel.ProjectId,
240+
privateEndpointRequest := client.AtlasSDK.PrivateEndpointServicesApi.DeletePrivateEndpoint(context.Background(), *currentModel.ProjectId,
237241
CloudProvider, *currentModel.Id, *currentModel.EndpointServiceId)
238-
_, response, err := privateEndpointRequest.Execute()
239-
defer response.Body.Close()
242+
response, err := privateEndpointRequest.Execute()
243+
if response != nil && response.Body != nil {
244+
defer response.Body.Close()
245+
}
240246
if err != nil {
241-
return progress_events.GetFailedEventByResponse(fmt.Sprintf("error creating Serverless Private Endpoint %s",
247+
return progress_events.GetFailedEventByResponse(fmt.Sprintf("error deleting Private Endpoint: %s",
242248
err.Error()), response),
243249
nil
244250
}
245251

246252
return handler.ProgressEvent{
247253
OperationStatus: handler.InProgress,
248-
Message: "Create in progress",
254+
Message: "Delete in progress",
249255
CallbackDelaySeconds: 20,
250256
ResourceModel: currentModel,
251257
CallbackContext: map[string]interface{}{

cfn-resources/private-endpoint-aws/docs/README.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ To declare this entity in your AWS CloudFormation template, use the following sy
1717
"<a href="#endpointserviceid" title="EndpointServiceId">EndpointServiceId</a>" : <i>String</i>,
1818
"<a href="#id" title="Id">Id</a>" : <i>String</i>,
1919
"<a href="#enforceconnectionsuccess" title="EnforceConnectionSuccess">EnforceConnectionSuccess</a>" : <i>Boolean</i>,
20-
"<a href="#connectionstatus" title="ConnectionStatus">ConnectionStatus</a>" : <i>String</i>,
21-
"<a href="#errormessage" title="ErrorMessage">ErrorMessage</a>" : <i>String</i>
2220
}
2321
}
2422
</pre>
@@ -33,8 +31,6 @@ Properties:
3331
<a href="#endpointserviceid" title="EndpointServiceId">EndpointServiceId</a>: <i>String</i>
3432
<a href="#id" title="Id">Id</a>: <i>String</i>
3533
<a href="#enforceconnectionsuccess" title="EnforceConnectionSuccess">EnforceConnectionSuccess</a>: <i>Boolean</i>
36-
<a href="#connectionstatus" title="ConnectionStatus">ConnectionStatus</a>: <i>String</i>
37-
<a href="#errormessage" title="ErrorMessage">ErrorMessage</a>: <i>String</i>
3834
</pre>
3935

4036
## Properties
@@ -73,7 +69,7 @@ _Update requires_: [Replacement](https://docs.aws.amazon.com/AWSCloudFormation/l
7369

7470
Unique string that identifies the private endpoint. for AWS is the VPC endpoint ID, example: vpce-xxxxxxxx
7571

76-
_Required_: No
72+
_Required_: Yes
7773

7874
_Type_: String
7975

@@ -89,23 +85,27 @@ _Type_: Boolean
8985

9086
_Update requires_: [No interruption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-no-interrupt)
9187

92-
#### ConnectionStatus
88+
## Return Values
9389

94-
State of the Amazon Web Service PrivateLink connection when MongoDB Cloud received this request.
90+
### Fn::GetAtt
9591

96-
_Required_: No
92+
The `Fn::GetAtt` intrinsic function returns a value for a specified attribute of this type. The following are the available attributes and sample return values.
9793

98-
_Type_: String
94+
For more information about using the `Fn::GetAtt` intrinsic function, see [Fn::GetAtt](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html).
9995

100-
_Update requires_: [No interruption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-no-interrupt)
96+
#### InterfaceEndpointId
10197

102-
#### ErrorMessage
98+
Unique identifier of the AWS VPC interface endpoint (e.g., vpce-0d00c26273372c6ef).
10399

104-
Error message returned when requesting private connection resource. The resource returns null if the request succeeded.
100+
#### DeleteRequested
105101

106-
_Required_: No
102+
Indicates if Atlas received a request to remove the interface endpoint from the private endpoint connection.
107103

108-
_Type_: String
104+
#### ConnectionStatus
109105

110-
_Update requires_: [No interruption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-no-interrupt)
106+
State of the Amazon Web Service PrivateLink connection when MongoDB Cloud received this request.
107+
108+
#### ErrorMessage
109+
110+
Error message returned when requesting private connection resource. The resource returns null if the request succeeded.
111111

cfn-resources/private-endpoint-aws/mongodb-atlas-privateendpointaws.json

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
},
99
"required": [
1010
"ProjectId",
11-
"EndpointServiceId"
11+
"EndpointServiceId",
12+
"Id"
1213
],
1314
"properties": {
1415
"Profile": {
@@ -32,6 +33,14 @@
3233
"description": "If this proper is set to TRUE, the cloud formation resource will return success Only if the private connection is Succeeded",
3334
"type": "boolean"
3435
},
36+
"InterfaceEndpointId": {
37+
"description": "Unique identifier of the AWS VPC interface endpoint (e.g., vpce-0d00c26273372c6ef).",
38+
"type": "string"
39+
},
40+
"DeleteRequested": {
41+
"description": "Indicates if Atlas received a request to remove the interface endpoint from the private endpoint connection.",
42+
"type": "boolean"
43+
},
3544
"ConnectionStatus": {
3645
"description": "State of the Amazon Web Service PrivateLink connection when MongoDB Cloud received this request.",
3746
"type": "string"
@@ -54,6 +63,12 @@
5463
"/properties/Profile",
5564
"/properties/Id"
5665
],
66+
"readOnlyProperties": [
67+
"/properties/InterfaceEndpointId",
68+
"/properties/DeleteRequested",
69+
"/properties/ConnectionStatus",
70+
"/properties/ErrorMessage"
71+
],
5772
"handlers": {
5873
"create": {
5974
"permissions": [
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# How to create a MongoDB::Atlas::PrivateEndpointAWS
2+
3+
## Step 1: Activate the PrivateEndpointAWS resource in CloudFormation
4+
Step a: Create Role using [execution-role.yaml](https://github.com/mongodb/mongodbatlas-cloudformation-resources/blob/master/examples/execution-role.yaml) in CFN resources folder.
5+
6+
Step b: Search for MongoDB::Atlas::PrivateEndpointAWS resource.
7+
8+
(CloudFormation > Public extensions > choose 'Third party' > Search with " Execution name prefix = MongoDB " )
9+
10+
Step c: Select and activate
11+
Enter the RoleArn that is created in step 1.
12+
13+
Your PrivateEndpointAWS Resource is ready to use.
14+
15+
## Step 2: Create template using [private-endpoint-aws.json](private-endpoint-aws.json)
16+
Note: Make sure you are providing appropriate values for:
17+
1. MongoDBAtlasProjectId
18+
2. AtlasPrivateEndpointServiceId (get from: `atlas privateEndpoints aws list --projectId <PROJECT_ID>`)
19+
3. AWSVPCEndpointId (format: vpce-xxxxxxxxx)
20+
4. Profile (optional)
21+
5. EnforceConnectionSuccess (optional)
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
{
2+
"AWSTemplateFormatVersion": "2010-09-09",
3+
"Description": "Test template for MongoDB::Atlas::PrivateEndpointAWS resource. Links an existing AWS VPC Endpoint to an existing Atlas Private Endpoint Service.",
4+
"Parameters": {
5+
"Profile": {
6+
"Type": "String",
7+
"Description": "Atlas Profile name for credential management. See profile-secret.yaml for setup instructions.",
8+
"Default": "default"
9+
},
10+
"MongoDBAtlasProjectId": {
11+
"Type": "String",
12+
"Description": "Unique 24-hexadecimal digit string that identifies your MongoDB Atlas project.",
13+
"AllowedPattern": "^([a-f0-9]{24})$",
14+
"ConstraintDescription": "Must be a valid 24-character hexadecimal MongoDB Atlas project ID."
15+
},
16+
"AtlasPrivateEndpointServiceId": {
17+
"Type": "String",
18+
"Description": "The Atlas Private Endpoint Service ID (24-character hexadecimal). Get this from MongoDB::Atlas::PrivateEndpointService.Id or Atlas CLI.",
19+
"AllowedPattern": "^([a-f0-9]{24})$",
20+
"ConstraintDescription": "Must be a valid 24-character hexadecimal Atlas Private Endpoint Service ID."
21+
},
22+
"AWSVPCEndpointId": {
23+
"Type": "String",
24+
"Description": "The AWS VPC Endpoint ID that you want to link to Atlas (e.g., vpce-0123456789abcdef0).",
25+
"AllowedPattern": "^vpce-[a-z0-9]{8,17}$",
26+
"ConstraintDescription": "Must be a valid AWS VPC Endpoint ID starting with 'vpce-'."
27+
},
28+
"EnforceConnectionSuccess": {
29+
"Type": "String",
30+
"Description": "If true, CloudFormation will fail if the connection is REJECTED. If false, it succeeds even if REJECTED.",
31+
"Default": "true",
32+
"AllowedValues": ["true", "false"]
33+
}
34+
},
35+
"Resources": {
36+
"AtlasPrivateEndpointConnection": {
37+
"Type": "MongoDB::Atlas::PrivateEndpointAWS",
38+
"Properties": {
39+
"ProjectId": {
40+
"Ref": "MongoDBAtlasProjectId"
41+
},
42+
"EndpointServiceId": {
43+
"Ref": "AtlasPrivateEndpointServiceId"
44+
},
45+
"Id": {
46+
"Ref": "AWSVPCEndpointId"
47+
},
48+
"Profile": {
49+
"Ref": "Profile"
50+
},
51+
"EnforceConnectionSuccess": {
52+
"Ref": "EnforceConnectionSuccess"
53+
}
54+
}
55+
}
56+
},
57+
"Outputs": {
58+
"ConnectionStatus": {
59+
"Description": "Status of the AWS PrivateLink connection. Returns one of: NONE, PENDING_ACCEPTANCE, PENDING, AVAILABLE, REJECTED, DELETING.",
60+
"Value": {
61+
"Fn::GetAtt": [
62+
"AtlasPrivateEndpointConnection",
63+
"ConnectionStatus"
64+
]
65+
}
66+
},
67+
"InterfaceEndpointId": {
68+
"Description": "Unique identifier of the interface endpoint.",
69+
"Value": {
70+
"Fn::GetAtt": [
71+
"AtlasPrivateEndpointConnection",
72+
"InterfaceEndpointId"
73+
]
74+
}
75+
},
76+
"DeleteRequested": {
77+
"Description": "Indicates if Atlas received a request to remove the interface endpoint from the private endpoint connection.",
78+
"Value": {
79+
"Fn::GetAtt": [
80+
"AtlasPrivateEndpointConnection",
81+
"DeleteRequested"
82+
]
83+
}
84+
}
85+
}
86+
}
87+

0 commit comments

Comments
 (0)