Skip to content

feat: Search Deployment CloudFormation Resource#1520

Closed
sivaram-mongodb wants to merge 1 commit intomasterfrom
CLOUDP-369807-search-deployment
Closed

feat: Search Deployment CloudFormation Resource#1520
sivaram-mongodb wants to merge 1 commit intomasterfrom
CLOUDP-369807-search-deployment

Conversation

@sivaram-mongodb
Copy link
Copy Markdown
Contributor

@sivaram-mongodb sivaram-mongodb commented Dec 31, 2025

Proposed changes

Added new resource Search Deployment:

  • Manages dedicated search nodes for workload isolation in MongoDB Atlas clusters
  • Supports configurable instance sizes and node counts for search workloads
  • Provides isolated search tier for better performance and resource management
  • Implements callback-based asynchronous operations for state management
  • Single deployment per cluster (limited to one spec configuration)

Resource Configuration:

The Search Deployment resource enables you to create and manage dedicated search nodes that provide workload isolation for Atlas Search queries. By deploying search nodes, you can separate search workloads from your database workloads, improving overall cluster performance.

Required Properties:

  • ProjectId: Atlas project identifier (24-hexadecimal characters)
  • ClusterName: Name of the cluster to attach search nodes
  • Specs: Array of search node specifications (currently limited to 1 element)
    • InstanceSize: Hardware specification for search nodes (e.g., S20_HIGHCPU_NVME, S30_HIGHCPU_NVME)
    • NodeCount: Number of search nodes in the deployment

Optional Properties:

  • Profile: AWS Secrets Manager profile for Atlas credentials (default: "default")

Read-Only Properties:

  • Id: Unique 24-hexadecimal identifier for the search deployment
  • StateName: Current operating state (IDLE when ready, DELETED when removed)
  • EncryptionAtRestProvider: Encryption provider for the deployment (AWS, GCP, AZURE, or NONE)

Create-Only Properties:

  • ProjectId, ClusterName, Profile: These cannot be changed after creation

Configuration Examples:

Basic Search Deployment:

{
  "ProjectId": "64d2a9b8f1a2c3e4d5e6f7a8",
  "ClusterName": "my-cluster",
  "Specs": [
    {
      "InstanceSize": "S30_HIGHCPU_NVME",
      "NodeCount": 2
    }
  ]
}

cfn testing:

image

stack testing:

image

Atlas UI - Before Creation

image

Atlas UI - After Creation

image

Jira ticket: CLOUDP-369807

Please include a summary of the fix/feature/change, including any relevant motivation and context.

Link to any related issue(s):

Type of change:

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as
    expected)
  • This change requires a documentation update
  • If changes include removal or addition of 3rd party GitHub actions, I updated our internal document. Reach out to the APIx Integration slack channel to get access to the internal document.

Manual QA performed:

  • cfn invoke for each of CRUDL/cfn test
  • Updated resource in example
  • Published to AWS private registry
  • Used the template in example to create and update a stack in AWS
  • Deleted stack to ensure resources are deleted
  • Created multiple resources in same stack
  • Validated in Atlas UI
  • Included screenshots

Required Checklist:

  • I have signed the MongoDB CLA
  • I have added tests that prove my fix is effective or that my feature works
  • I have checked that this change does not generate any credentials and that they are NOT accidentally logged anywhere.
  • I have added any necessary documentation (if appropriate)
  • I have run make fmt and formatted my code
  • For CFN Resources: I have released by changes in the private registry and proved by change
    works in Atlas

Further comments

@sivaram-mongodb sivaram-mongodb requested a review from a team as a code owner December 31, 2025 06:17
@sivaram-mongodb sivaram-mongodb force-pushed the CLOUDP-369807-search-deployment branch 2 times, most recently from f74ae97 to 487b36b Compare December 31, 2025 06:25
@sivaram-mongodb sivaram-mongodb force-pushed the CLOUDP-369807-search-deployment branch from 487b36b to a37eee4 Compare December 31, 2025 09:50
make build
sam local start-lambda &
cfn test --function-name TestEntrypoint --verbose
cfn test --verbose --enforce-timeout 3600
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[q] why the enforce-timeout?

for i := range respSpecs {
instanceSize := respSpecs[i].InstanceSize
// Follow cluster pattern: directly assign NodeCount from API response
// Reference: mongodbatlas-cloudformation-resources/cfn-resources/cluster/cmd/resource/mappings.go:305,317
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure, I understand how this is different than the previous implementation as that is using respSpecs as well?

also, I think you can remove this comment as the code is quite self-explanatory

}

func Create(req handler.Request, prevModel *Model, currentModel *Model) (handler.ProgressEvent, error) {
var InitEnvWithClient = func(req handler.Request, currentModel *Model, requiredFields []string) (*admin20250312010.APIClient, *handler.ProgressEvent) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we can rename this to InitEnv as this is doing a few things other than initializing the client as well.

createResp, resp, err := connV2.AtlasSearchApi.CreateClusterSearchDeployment(context.Background(), projectID, clusterName, &apiReq).Execute()
if err != nil {
return handleError(resp, err)
notFound := resp != nil && resp.StatusCode == http.StatusNotFound
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is StatusNotFound a valid case for the create API?

alreadyExists := resp != nil && resp.StatusCode == http.StatusConflict &&
strings.Contains(err.Error(), SearchDeploymentAlreadyExistsErrorAPI)

if alreadyExists || notFound {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the intention here is to handle the transition where creation can take some time, can you extract the logic to a callback function similar to cluster here - https://github.com/mongodb/mongodbatlas-cloudformation-resources/blob/master/cfn-resources/cluster/cmd/resource/resource.go#L255

Otherwise it's not very clear what the logic is trying to accomplish

projectID := util.SafeString(currentModel.ProjectId)
clusterName := util.SafeString(currentModel.ClusterName)

// Check if resource exists before updating (required by contract tests)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[q] why is this needed now? How do the existing contract tests running today?

)

func HandleStateTransition(connV2 admin20231115014.APIClient, currentModel *Model, targetState string) handler.ProgressEvent {
func ValidateProgress(connV2 admin20250312010.APIClient, currentModel *Model, isDelete bool) handler.ProgressEvent {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you please explain the changes in this method?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ValidateProgress function follows the flex-cluster pattern :
Uses isDelete bool instead of targetState string — determines target state internally (IdleState for create/update, DeletedState for delete)
Returns handler.ProgressEvent directly (no error return)
Handles nil states safely with a default of DeletedState
For delete operations, returns success without ResourceModel
This aligns with the flex-cluster implementation and is the current pattern for state validation in callback functions.

Id *string `json:",omitempty"`
Specs []ApiSearchDeploymentSpec `json:",omitempty"`
StateName *string `json:",omitempty"`
Profile *string `json:",omitempty"`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you please update the PR description to include only what has been updated? This is an existing resource & I believe only new attributes have been added. The PR description, however, implies that a new resource is being added.


Human-readable label that indicates the current operating condition of this search deployment.

#### EncryptionAtRestProvider
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you also update the example for this resource (under /examples/search-deployment) & ensure that works for the testing screenshots in the PR description?


function usage {
echo "usage:$0 <project_name>"
echo "Creates a new project and an Cluster for testing"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you also please update the test input files to use the new attribute?

clusterName=$(jq -r '.ClusterName' ./inputs/inputs_1_create.json)
projectId=$(jq -r '.ProjectId' ./inputs/inputs_1_create.json)

# TEMPORARY: Skip deletion of test cluster/project (only for today's testing - 2025-12-29)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: would revert this & keep only required changes in the PR to merge

@sivaram-mongodb sivaram-mongodb marked this pull request as draft January 14, 2026 06:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants