Skip to content

Commit ec590e8

Browse files
fmenezesCopilot
andauthored
feat: support flex clusters to atlas tools (#182)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent ca067a1 commit ec590e8

File tree

8 files changed

+533
-92
lines changed

8 files changed

+533
-92
lines changed

scripts/filter.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,13 @@ function filterOpenapi(openapi: OpenAPIV3_1.Document): OpenAPIV3_1.Document {
2525
"createProject",
2626
"deleteProject",
2727
"listClusters",
28+
"listFlexClusters",
2829
"getCluster",
30+
"getFlexCluster",
2931
"createCluster",
32+
"createFlexCluster",
3033
"deleteCluster",
34+
"deleteFlexCluster",
3135
"listClustersForAllProjects",
3236
"createDatabaseUser",
3337
"deleteDatabaseUser",

src/common/atlas/apiClient.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,46 @@ export class ApiClient {
275275
}
276276
}
277277

278+
async listFlexClusters(options: FetchOptions<operations["listFlexClusters"]>) {
279+
const { data, error, response } = await this.client.GET("/api/atlas/v2/groups/{groupId}/flexClusters", options);
280+
if (error) {
281+
throw ApiClientError.fromError(response, error);
282+
}
283+
return data;
284+
}
285+
286+
async createFlexCluster(options: FetchOptions<operations["createFlexCluster"]>) {
287+
const { data, error, response } = await this.client.POST(
288+
"/api/atlas/v2/groups/{groupId}/flexClusters",
289+
options
290+
);
291+
if (error) {
292+
throw ApiClientError.fromError(response, error);
293+
}
294+
return data;
295+
}
296+
297+
async deleteFlexCluster(options: FetchOptions<operations["deleteFlexCluster"]>) {
298+
const { error, response } = await this.client.DELETE(
299+
"/api/atlas/v2/groups/{groupId}/flexClusters/{name}",
300+
options
301+
);
302+
if (error) {
303+
throw ApiClientError.fromError(response, error);
304+
}
305+
}
306+
307+
async getFlexCluster(options: FetchOptions<operations["getFlexCluster"]>) {
308+
const { data, error, response } = await this.client.GET(
309+
"/api/atlas/v2/groups/{groupId}/flexClusters/{name}",
310+
options
311+
);
312+
if (error) {
313+
throw ApiClientError.fromError(response, error);
314+
}
315+
return data;
316+
}
317+
278318
async listOrganizations(options?: FetchOptions<operations["listOrganizations"]>) {
279319
const { data, error, response } = await this.client.GET("/api/atlas/v2/orgs", options);
280320
if (error) {

src/common/atlas/cluster.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { ClusterDescription20240805, FlexClusterDescription20241113 } from "./openapi.js";
2+
import { ApiClient } from "./apiClient.js";
3+
import logger, { LogId } from "../../logger.js";
4+
5+
export interface Cluster {
6+
name?: string;
7+
instanceType: "FREE" | "DEDICATED" | "FLEX";
8+
instanceSize?: string;
9+
state?: "IDLE" | "CREATING" | "UPDATING" | "DELETING" | "REPAIRING";
10+
mongoDBVersion?: string;
11+
connectionString?: string;
12+
}
13+
14+
export function formatFlexCluster(cluster: FlexClusterDescription20241113): Cluster {
15+
return {
16+
name: cluster.name,
17+
instanceType: "FLEX",
18+
instanceSize: undefined,
19+
state: cluster.stateName,
20+
mongoDBVersion: cluster.mongoDBVersion,
21+
connectionString: cluster.connectionStrings?.standardSrv || cluster.connectionStrings?.standard,
22+
};
23+
}
24+
25+
export function formatCluster(cluster: ClusterDescription20240805): Cluster {
26+
const regionConfigs = (cluster.replicationSpecs || [])
27+
.map(
28+
(replicationSpec) =>
29+
(replicationSpec.regionConfigs || []) as {
30+
providerName: string;
31+
electableSpecs?: {
32+
instanceSize: string;
33+
};
34+
readOnlySpecs?: {
35+
instanceSize: string;
36+
};
37+
analyticsSpecs?: {
38+
instanceSize: string;
39+
};
40+
}[]
41+
)
42+
.flat()
43+
.map((regionConfig) => {
44+
return {
45+
providerName: regionConfig.providerName,
46+
instanceSize:
47+
regionConfig.electableSpecs?.instanceSize ||
48+
regionConfig.readOnlySpecs?.instanceSize ||
49+
regionConfig.analyticsSpecs?.instanceSize,
50+
};
51+
});
52+
53+
const instanceSize = (regionConfigs.length <= 0 ? undefined : regionConfigs[0].instanceSize) || "UNKNOWN";
54+
55+
const clusterInstanceType = instanceSize == "M0" ? "FREE" : "DEDICATED";
56+
57+
return {
58+
name: cluster.name,
59+
instanceType: clusterInstanceType,
60+
instanceSize: clusterInstanceType == "DEDICATED" ? instanceSize : undefined,
61+
state: cluster.stateName,
62+
mongoDBVersion: cluster.mongoDBVersion,
63+
connectionString: cluster.connectionStrings?.standardSrv || cluster.connectionStrings?.standard,
64+
};
65+
}
66+
67+
export async function inspectCluster(apiClient: ApiClient, projectId: string, clusterName: string): Promise<Cluster> {
68+
try {
69+
const cluster = await apiClient.getCluster({
70+
params: {
71+
path: {
72+
groupId: projectId,
73+
clusterName,
74+
},
75+
},
76+
});
77+
return formatCluster(cluster);
78+
} catch (error) {
79+
try {
80+
const cluster = await apiClient.getFlexCluster({
81+
params: {
82+
path: {
83+
groupId: projectId,
84+
name: clusterName,
85+
},
86+
},
87+
});
88+
return formatFlexCluster(cluster);
89+
} catch (flexError) {
90+
const err = flexError instanceof Error ? flexError : new Error(String(flexError));
91+
logger.error(LogId.atlasInspectFailure, "inspect-cluster", `error inspecting cluster: ${err.message}`);
92+
throw error;
93+
}
94+
}
95+
}

0 commit comments

Comments
 (0)