Skip to content
Open
Show file tree
Hide file tree
Changes from 5 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