Skip to content

Commit 45cbcb7

Browse files
feat: Add NAPI wrapper for create_deployment #4
feat: Add NAPI wrapper for create_deployment
2 parents 5d89edb + d1fcb92 commit 45cbcb7

File tree

7 files changed

+469
-12
lines changed

7 files changed

+469
-12
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ crate-type = ["cdylib"]
1010

1111
[dependencies]
1212
anyhow = "1.0.99"
13-
atlas-local = { git = "https://github.com/mongodb/atlas-local-lib.git", rev = "36f56065e891bbe045beeb46489dd7d4142dbd41" }
13+
atlas-local = { git = "https://github.com/mongodb/atlas-local-lib.git", rev = "323a879b8385e8e572f8545e3273fafa5698f8c6" }
1414
bollard = "0.19.2"
1515
napi = { version = "3.0.0", features = ["async", "anyhow"] }
1616
napi-derive = "3.0.0"
17+
semver = "1.0.26"
1718

1819
[build-dependencies]
1920
napi-build = "2"

__test__/index.spec.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,30 @@ test('smoke test', async (t) => {
2020
return
2121
}
2222

23-
// TODO: Implement once createDeployment is added
24-
// let deploymentName = "test_deployment"
25-
// await client.createDeployment(...)
23+
// Skip test after client creation on Windows
24+
// Note all Windows return win32 including 64 bit
25+
if (process.platform === 'win32') {
26+
t.pass('Skipping end-to-end test on Windows')
27+
return
28+
}
29+
30+
// Count initial deployments
31+
let start_deployments_count = (await client.listDeployments()).length
32+
33+
// Create deployment
34+
let createDeploymentOptions = {
35+
name: "test_deployment",
36+
}
37+
await client.createDeployment(createDeploymentOptions)
2638

27-
// List deployments
28-
// We don't care about the number, we're just testing that the method doesn't fail
29-
await client.listDeployments()
39+
// Count deployments after creation
40+
let after_create_deployment_count = (await client.listDeployments()).length
41+
t.assert(after_create_deployment_count - start_deployments_count === 1)
3042

31-
// TODO: Uncommment when createDeployment is added
32-
// await client.deleteDeployment(deploymentName)
43+
// Delete deployment
44+
await client.deleteDeployment(createDeploymentOptions.name)
3345

34-
t.pass()
46+
// Count deployments after deletion
47+
let after_delete_deployment_count = (await client.listDeployments()).length
48+
t.assert(start_deployments_count === after_delete_deployment_count)
3549
})

index.d.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/* eslint-disable */
33
export declare class Client {
44
static connect(): Client
5+
createDeployment(createDeplomentOptions: CreateDeploymentOptions): Promise<void>
56
listDeployments(): Promise<Array<Deployment>>
67
deleteDeployment(deploymentName: string): Promise<void>
78
}
@@ -12,6 +13,24 @@ export declare const enum BindingType {
1213
Specific = 'Specific'
1314
}
1415

16+
export interface CreateDeploymentOptions {
17+
name?: string
18+
image?: string
19+
mongodbVersion?: string
20+
creationSource?: CreationSource
21+
localSeedLocation?: string
22+
mongodbInitdbDatabase?: string
23+
mongodbInitdbRootPasswordFile?: string
24+
mongodbInitdbRootPassword?: string
25+
mongodbInitdbRootUsernameFile?: string
26+
mongodbInitdbRootUsername?: string
27+
mongotLogFile?: string
28+
runnerLogFile?: string
29+
doNotTrack?: boolean
30+
telemetryBaseUrl?: string
31+
mongodbPortBinding?: MongoDBPortBinding
32+
}
33+
1534
export interface CreationSource {
1635
type: CreationSourceType
1736
source: string
@@ -20,7 +39,7 @@ export interface CreationSource {
2039
export declare const enum CreationSourceType {
2140
AtlasCLI = 'AtlasCLI',
2241
Container = 'Container',
23-
MCP = 'MCP',
42+
MCPServer = 'MCPServer',
2443
Other = 'Other'
2544
}
2645

src/lib.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,19 @@ impl Client {
2727
})
2828
}
2929

30+
#[napi]
31+
pub async fn create_deployment(
32+
&self,
33+
create_deploment_options: crate::models::create_deployment::CreateDeploymentOptions,
34+
) -> Result<()> {
35+
let options: atlas_local::models::CreateDeploymentOptions = create_deploment_options.into();
36+
self
37+
.client
38+
.create_deployment(&options)
39+
.await
40+
.context("create deployment")
41+
}
42+
3043
#[napi]
3144
pub async fn list_deployments(&self) -> Result<Vec<Deployment>> {
3245
self

src/models/create_deployment.rs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
use crate::models::list_deployments::{CreationSource, MongoDBPortBinding};
2+
use napi_derive::napi;
3+
use semver::Version;
4+
5+
#[napi(object)]
6+
pub struct CreateDeploymentOptions {
7+
// Identifiers
8+
pub name: Option<String>,
9+
10+
// Image details
11+
pub image: Option<String>,
12+
pub mongodb_version: Option<String>,
13+
14+
// Creation source
15+
pub creation_source: Option<CreationSource>,
16+
17+
// Initial database configuration
18+
pub local_seed_location: Option<String>,
19+
pub mongodb_initdb_database: Option<String>,
20+
pub mongodb_initdb_root_password_file: Option<String>,
21+
pub mongodb_initdb_root_password: Option<String>,
22+
pub mongodb_initdb_root_username_file: Option<String>,
23+
pub mongodb_initdb_root_username: Option<String>,
24+
25+
// Logging
26+
pub mongot_log_file: Option<String>,
27+
pub runner_log_file: Option<String>,
28+
29+
// Telemetry
30+
pub do_not_track: Option<bool>,
31+
pub telemetry_base_url: Option<String>,
32+
33+
// Port configuration
34+
pub mongodb_port_binding: Option<MongoDBPortBinding>,
35+
}
36+
37+
impl From<CreateDeploymentOptions> for atlas_local::models::CreateDeploymentOptions {
38+
fn from(source: CreateDeploymentOptions) -> Self {
39+
let version: Option<Version> = match source.mongodb_version.as_deref() {
40+
Some("latest") => None,
41+
None => None,
42+
Some(ver_string) => {
43+
// If malformed Version if given, it will panic here
44+
Some(Version::parse(ver_string).expect("Parse version string"))
45+
}
46+
};
47+
48+
Self {
49+
name: source.name,
50+
image: source.image,
51+
mongodb_version: version,
52+
creation_source: source
53+
.creation_source
54+
.map(atlas_local::models::CreationSource::from),
55+
local_seed_location: source.local_seed_location,
56+
mongodb_initdb_database: source.mongodb_initdb_database,
57+
mongodb_initdb_root_password_file: source.mongodb_initdb_root_password_file,
58+
mongodb_initdb_root_password: source.mongodb_initdb_root_password,
59+
mongodb_initdb_root_username_file: source.mongodb_initdb_root_username_file,
60+
mongodb_initdb_root_username: source.mongodb_initdb_root_username,
61+
mongot_log_file: source.mongot_log_file,
62+
runner_log_file: source.runner_log_file,
63+
do_not_track: source.do_not_track,
64+
telemetry_base_url: source.telemetry_base_url,
65+
mongodb_port_binding: source
66+
.mongodb_port_binding
67+
.map(atlas_local::models::MongoDBPortBinding::from),
68+
}
69+
}
70+
}
71+
72+
#[cfg(test)]
73+
mod tests {
74+
use crate::models::list_deployments::{BindingType, CreationSourceType};
75+
76+
use super::*;
77+
78+
#[test]
79+
fn test_lib_create_deployment_options_from_create_deployment_options() {
80+
let create_deployment_options = CreateDeploymentOptions {
81+
name: Some("test_deployment".to_string()),
82+
image: Some("mongodb/mongodb-atlas-local".to_string()),
83+
mongodb_version: Some("8.0.0".to_string()),
84+
creation_source: Some(CreationSource {
85+
source_type: CreationSourceType::MCPServer,
86+
source: "MCPSERVER".to_string(),
87+
}),
88+
local_seed_location: Some("/host/seed-data".to_string()),
89+
mongodb_initdb_database: Some("testdb".to_string()),
90+
mongodb_initdb_root_password_file: Some("/run/secrets/password".to_string()),
91+
mongodb_initdb_root_password: Some("password123".to_string()),
92+
mongodb_initdb_root_username_file: Some("/run/secrets/username".to_string()),
93+
mongodb_initdb_root_username: Some("admin".to_string()),
94+
mongot_log_file: Some("/tmp/mongot.log".to_string()),
95+
runner_log_file: Some("/tmp/runner.log".to_string()),
96+
do_not_track: Some(false),
97+
telemetry_base_url: Some("https://telemetry.example.com".to_string()),
98+
mongodb_port_binding: Some(MongoDBPortBinding {
99+
binding_type: BindingType::Loopback,
100+
ip: "127.0.0.1".to_string(),
101+
port: 27017,
102+
}),
103+
};
104+
let lib_create_deployment_options: atlas_local::models::CreateDeploymentOptions =
105+
create_deployment_options.into();
106+
assert_eq!(
107+
lib_create_deployment_options.name,
108+
Some("test_deployment".to_string())
109+
);
110+
assert_eq!(
111+
lib_create_deployment_options.image,
112+
Some("mongodb/mongodb-atlas-local".to_string())
113+
);
114+
assert_eq!(
115+
lib_create_deployment_options.mongodb_version,
116+
Some(Version::new(8, 0, 0))
117+
);
118+
assert_eq!(
119+
lib_create_deployment_options.creation_source,
120+
Some(atlas_local::models::CreationSource::MCPServer)
121+
);
122+
assert_eq!(
123+
lib_create_deployment_options.local_seed_location,
124+
Some("/host/seed-data".to_string())
125+
);
126+
assert_eq!(
127+
lib_create_deployment_options.mongodb_initdb_database,
128+
Some("testdb".to_string())
129+
);
130+
assert_eq!(
131+
lib_create_deployment_options.mongodb_initdb_root_password_file,
132+
Some("/run/secrets/password".to_string())
133+
);
134+
assert_eq!(
135+
lib_create_deployment_options.mongodb_initdb_root_password,
136+
Some("password123".to_string())
137+
);
138+
assert_eq!(
139+
lib_create_deployment_options.mongodb_initdb_root_username_file,
140+
Some("/run/secrets/username".to_string())
141+
);
142+
assert_eq!(
143+
lib_create_deployment_options.mongodb_initdb_root_username,
144+
Some("admin".to_string())
145+
);
146+
assert_eq!(
147+
lib_create_deployment_options.mongot_log_file,
148+
Some("/tmp/mongot.log".to_string())
149+
);
150+
assert_eq!(
151+
lib_create_deployment_options.runner_log_file,
152+
Some("/tmp/runner.log".to_string())
153+
);
154+
assert_eq!(lib_create_deployment_options.do_not_track, Some(false));
155+
assert_eq!(
156+
lib_create_deployment_options.telemetry_base_url,
157+
Some("https://telemetry.example.com".to_string())
158+
);
159+
}
160+
}

0 commit comments

Comments
 (0)