Skip to content
Open
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
5 changes: 5 additions & 0 deletions scripts/accuracy/runAccuracyTests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ export MDB_ACCURACY_RUN_ID=$(npx uuid v4)
# export MDB_AZURE_OPEN_AI_API_KEY=""
# export MDB_AZURE_OPEN_AI_API_URL=""

# For providing Atlas API credentials (required for Atlas tools)
# Set dummy values for testing (allows Atlas tools to be registered for mocking)
export MDB_MCP_API_CLIENT_ID=${MDB_MCP_API_CLIENT_ID:-"test-atlas-client-id"}
export MDB_MCP_API_CLIENT_SECRET=${MDB_MCP_API_CLIENT_SECRET:-"test-atlas-client-secret"}

# For providing a mongodb based storage to store accuracy result
# export MDB_ACCURACY_MDB_URL=""
# export MDB_ACCURACY_MDB_DB=""
Expand Down
4 changes: 4 additions & 0 deletions scripts/filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ function filterOpenapi(openapi: OpenAPIV3_1.Document): OpenAPIV3_1.Document {
"deleteProjectIpAccessList",
"listOrganizationProjects",
"listAlerts",
"listDropIndexes",
"listClusterSuggestedIndexes",
"listSchemaAdvice",
"listSlowQueries",
];

const filteredPaths = {};
Expand Down
48 changes: 48 additions & 0 deletions src/common/atlas/apiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,42 @@ export class ApiClient {
return data;
}

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
async listDropIndexes(options: FetchOptions<operations["listDropIndexes"]>) {
const { data, error, response } = await this.client.GET(
"/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/performanceAdvisor/dropIndexSuggestions",
options
);
if (error) {
throw ApiClientError.fromError(response, error);
}
return data;
}

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
async listSchemaAdvice(options: FetchOptions<operations["listSchemaAdvice"]>) {
const { data, error, response } = await this.client.GET(
"/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/performanceAdvisor/schemaAdvice",
options
);
if (error) {
throw ApiClientError.fromError(response, error);
}
return data;
}

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
async listClusterSuggestedIndexes(options: FetchOptions<operations["listClusterSuggestedIndexes"]>) {
const { data, error, response } = await this.client.GET(
"/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/performanceAdvisor/suggestedIndexes",
options
);
if (error) {
throw ApiClientError.fromError(response, error);
}
return data;
}

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
async listDatabaseUsers(options: FetchOptions<operations["listDatabaseUsers"]>) {
const { data, error, response } = await this.client.GET(
Expand Down Expand Up @@ -508,6 +544,18 @@ export class ApiClient {
return data;
}

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
async listSlowQueries(options: FetchOptions<operations["listSlowQueries"]>) {
const { data, error, response } = await this.client.GET(
"/api/atlas/v2/groups/{groupId}/processes/{processId}/performanceAdvisor/slowQueryLogs",
options
);
if (error) {
throw ApiClientError.fromError(response, error);
}
return data;
}

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
async listOrganizations(options?: FetchOptions<operations["listOrganizations"]>) {
const { data, error, response } = await this.client.GET("/api/atlas/v2/orgs", options);
Expand Down
34 changes: 32 additions & 2 deletions src/common/atlas/cluster.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
import type { ClusterDescription20240805, FlexClusterDescription20241113 } from "./openapi.js";
import type { ApiClient } from "./apiClient.js";
import { LogId } from "../logger.js";
import { ConnectionString } from "mongodb-connection-string-url";

type AtlasProcessId = `${string}:${number}`;

function extractProcessIds(connectionString: string): Array<AtlasProcessId> {
if (!connectionString) {
return [];
}
const connectionStringUrl = new ConnectionString(connectionString);
return connectionStringUrl.hosts as Array<AtlasProcessId>;
}
export interface Cluster {
name?: string;
instanceType: "FREE" | "DEDICATED" | "FLEX";
instanceSize?: string;
state?: "IDLE" | "CREATING" | "UPDATING" | "DELETING" | "REPAIRING";
mongoDBVersion?: string;
connectionString?: string;
processIds?: Array<string>;
}

export function formatFlexCluster(cluster: FlexClusterDescription20241113): Cluster {
const connectionString = cluster.connectionStrings?.standardSrv || cluster.connectionStrings?.standard;
return {
name: cluster.name,
instanceType: "FLEX",
instanceSize: undefined,
state: cluster.stateName,
mongoDBVersion: cluster.mongoDBVersion,
connectionString: cluster.connectionStrings?.standardSrv || cluster.connectionStrings?.standard,
connectionString,
processIds: extractProcessIds(cluster.connectionStrings?.standard ?? ""),
};
}

Expand Down Expand Up @@ -52,14 +65,16 @@ export function formatCluster(cluster: ClusterDescription20240805): Cluster {

const instanceSize = regionConfigs[0]?.instanceSize ?? "UNKNOWN";
const clusterInstanceType = instanceSize === "M0" ? "FREE" : "DEDICATED";
const connectionString = cluster.connectionStrings?.standardSrv || cluster.connectionStrings?.standard;

return {
name: cluster.name,
instanceType: clusterInstanceType,
instanceSize: clusterInstanceType === "DEDICATED" ? instanceSize : undefined,
state: cluster.stateName,
mongoDBVersion: cluster.mongoDBVersion,
connectionString: cluster.connectionStrings?.standardSrv || cluster.connectionStrings?.standard,
connectionString,
processIds: extractProcessIds(cluster.connectionStrings?.standard ?? ""),
};
}

Expand Down Expand Up @@ -96,3 +111,18 @@ export async function inspectCluster(apiClient: ApiClient, projectId: string, cl
}
}
}

export async function getProcessIdsFromCluster(
apiClient: ApiClient,
projectId: string,
clusterName: string
): Promise<Array<string>> {
try {
const cluster = await inspectCluster(apiClient, projectId, clusterName);
return cluster.processIds || [];
} catch (error) {
throw new Error(
`Failed to get processIds from cluster: ${error instanceof Error ? error.message : String(error)}`
);
}
}
Loading
Loading