Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ crate-type = ["cdylib"]

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

[build-dependencies]
napi-build = "2"
Expand Down
32 changes: 23 additions & 9 deletions __test__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,30 @@ test('smoke test', async (t) => {
return
}

// TODO: Implement once createDeployment is added
// let deploymentName = "test_deployment"
// await client.createDeployment(...)
// Skip test after client creation on Windows
// Note all Windows return win32 including 64 bit
if (process.platform === 'win32') {
t.pass('Skipping end-to-end test on Windows')
return
}

// Count initial deployments
let start_deployments_count = (await client.listDeployments()).length

// Create deployment
let createDeploymentOptions = {
name: "test_deployment",
}
await client.createDeployment(createDeploymentOptions)

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

// TODO: Uncommment when createDeployment is added
// await client.deleteDeployment(deploymentName)
// Delete deployment
await client.deleteDeployment(createDeploymentOptions.name)

t.pass()
// Count deployments after deletion
let after_delete_deployment_count = (await client.listDeployments()).length
t.assert(start_deployments_count === after_delete_deployment_count)
})
21 changes: 20 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/* eslint-disable */
export declare class Client {
static connect(): Client
createDeployment(createDeplomentOptions: CreateDeploymentOptions): Promise<void>
listDeployments(): Promise<Array<Deployment>>
deleteDeployment(deploymentName: string): Promise<void>
}
Expand All @@ -12,6 +13,24 @@ export declare const enum BindingType {
Specific = 'Specific'
}

export interface CreateDeploymentOptions {
name?: string
image?: string
mongodbVersion?: string
creationSource?: CreationSource
localSeedLocation?: string
mongodbInitdbDatabase?: string
mongodbInitdbRootPasswordFile?: string
mongodbInitdbRootPassword?: string
mongodbInitdbRootUsernameFile?: string
mongodbInitdbRootUsername?: string
mongotLogFile?: string
runnerLogFile?: string
doNotTrack?: boolean
telemetryBaseUrl?: string
mongodbPortBinding?: MongoDBPortBinding
}

export interface CreationSource {
type: CreationSourceType
source: string
Expand All @@ -20,7 +39,7 @@ export interface CreationSource {
export declare const enum CreationSourceType {
AtlasCLI = 'AtlasCLI',
Container = 'Container',
MCP = 'MCP',
MCPServer = 'MCPServer',
Other = 'Other'
}

Expand Down
13 changes: 13 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@ impl Client {
})
}

#[napi]
pub async fn create_deployment(
&self,
create_deploment_options: crate::models::create_deployment::CreateDeploymentOptions,
) -> Result<()> {
let options: atlas_local::models::CreateDeploymentOptions = create_deploment_options.into();
self
.client
.create_deployment(&options)
.await
.context("create deployment")
}

#[napi]
pub async fn list_deployments(&self) -> Result<Vec<Deployment>> {
self
Expand Down
160 changes: 160 additions & 0 deletions src/models/create_deployment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
use crate::models::list_deployments::{CreationSource, MongoDBPortBinding};
use napi_derive::napi;
use semver::Version;

#[napi(object)]
pub struct CreateDeploymentOptions {
// Identifiers
pub name: Option<String>,

// Image details
pub image: Option<String>,
pub mongodb_version: Option<String>,

// Creation source
pub creation_source: Option<CreationSource>,

// Initial database configuration
pub local_seed_location: Option<String>,
pub mongodb_initdb_database: Option<String>,
pub mongodb_initdb_root_password_file: Option<String>,
pub mongodb_initdb_root_password: Option<String>,
pub mongodb_initdb_root_username_file: Option<String>,
pub mongodb_initdb_root_username: Option<String>,

// Logging
pub mongot_log_file: Option<String>,
pub runner_log_file: Option<String>,

// Telemetry
pub do_not_track: Option<bool>,
pub telemetry_base_url: Option<String>,

// Port configuration
pub mongodb_port_binding: Option<MongoDBPortBinding>,
}

impl From<CreateDeploymentOptions> for atlas_local::models::CreateDeploymentOptions {
fn from(source: CreateDeploymentOptions) -> Self {
let version: Option<Version> = match source.mongodb_version.as_deref() {
Some("latest") => None,
None => None,
Some(ver_string) => {
// If malformed Version if given, it will panic here
Some(Version::parse(ver_string).expect("Parse version string"))
}
};

Self {
name: source.name,
image: source.image,
mongodb_version: version,
creation_source: source
.creation_source
.map(atlas_local::models::CreationSource::from),
local_seed_location: source.local_seed_location,
mongodb_initdb_database: source.mongodb_initdb_database,
mongodb_initdb_root_password_file: source.mongodb_initdb_root_password_file,
mongodb_initdb_root_password: source.mongodb_initdb_root_password,
mongodb_initdb_root_username_file: source.mongodb_initdb_root_username_file,
mongodb_initdb_root_username: source.mongodb_initdb_root_username,
mongot_log_file: source.mongot_log_file,
runner_log_file: source.runner_log_file,
do_not_track: source.do_not_track,
telemetry_base_url: source.telemetry_base_url,
mongodb_port_binding: source
.mongodb_port_binding
.map(atlas_local::models::MongoDBPortBinding::from),
}
}
}

#[cfg(test)]
mod tests {
use crate::models::list_deployments::{BindingType, CreationSourceType};

use super::*;

#[test]
fn test_lib_create_deployment_options_from_create_deployment_options() {
let create_deployment_options = CreateDeploymentOptions {
name: Some("test_deployment".to_string()),
image: Some("mongodb/mongodb-atlas-local".to_string()),
mongodb_version: Some("8.0.0".to_string()),
creation_source: Some(CreationSource {
source_type: CreationSourceType::MCPServer,
source: "MCPSERVER".to_string(),
}),
local_seed_location: Some("/host/seed-data".to_string()),
mongodb_initdb_database: Some("testdb".to_string()),
mongodb_initdb_root_password_file: Some("/run/secrets/password".to_string()),
mongodb_initdb_root_password: Some("password123".to_string()),
mongodb_initdb_root_username_file: Some("/run/secrets/username".to_string()),
mongodb_initdb_root_username: Some("admin".to_string()),
mongot_log_file: Some("/tmp/mongot.log".to_string()),
runner_log_file: Some("/tmp/runner.log".to_string()),
do_not_track: Some(false),
telemetry_base_url: Some("https://telemetry.example.com".to_string()),
mongodb_port_binding: Some(MongoDBPortBinding {
binding_type: BindingType::Loopback,
ip: "127.0.0.1".to_string(),
port: 27017,
}),
};
let lib_create_deployment_options: atlas_local::models::CreateDeploymentOptions =
create_deployment_options.into();
assert_eq!(
lib_create_deployment_options.name,
Some("test_deployment".to_string())
);
assert_eq!(
lib_create_deployment_options.image,
Some("mongodb/mongodb-atlas-local".to_string())
);
assert_eq!(
lib_create_deployment_options.mongodb_version,
Some(Version::new(8, 0, 0))
);
assert_eq!(
lib_create_deployment_options.creation_source,
Some(atlas_local::models::CreationSource::MCPServer)
);
assert_eq!(
lib_create_deployment_options.local_seed_location,
Some("/host/seed-data".to_string())
);
assert_eq!(
lib_create_deployment_options.mongodb_initdb_database,
Some("testdb".to_string())
);
assert_eq!(
lib_create_deployment_options.mongodb_initdb_root_password_file,
Some("/run/secrets/password".to_string())
);
assert_eq!(
lib_create_deployment_options.mongodb_initdb_root_password,
Some("password123".to_string())
);
assert_eq!(
lib_create_deployment_options.mongodb_initdb_root_username_file,
Some("/run/secrets/username".to_string())
);
assert_eq!(
lib_create_deployment_options.mongodb_initdb_root_username,
Some("admin".to_string())
);
assert_eq!(
lib_create_deployment_options.mongot_log_file,
Some("/tmp/mongot.log".to_string())
);
assert_eq!(
lib_create_deployment_options.runner_log_file,
Some("/tmp/runner.log".to_string())
);
assert_eq!(lib_create_deployment_options.do_not_track, Some(false));
assert_eq!(
lib_create_deployment_options.telemetry_base_url,
Some("https://telemetry.example.com".to_string())
);
}
}
Loading
Loading