@gcnv/gcnv-mcp-server 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/GEMINI.md +253 -0
- package/LICENSE +201 -0
- package/README.md +493 -0
- package/build/index.js +185 -0
- package/build/logger.js +19 -0
- package/build/registry/register-tools.js +110 -0
- package/build/registry/tool-registry.js +39 -0
- package/build/tools/active-directory-tools.js +132 -0
- package/build/tools/backup-policy-tools.js +140 -0
- package/build/tools/backup-tools.js +206 -0
- package/build/tools/backup-vault-tools.js +197 -0
- package/build/tools/handlers/active-directory-handler.js +327 -0
- package/build/tools/handlers/backup-handler.js +534 -0
- package/build/tools/handlers/backup-policy-handler.js +275 -0
- package/build/tools/handlers/backup-vault-handler.js +374 -0
- package/build/tools/handlers/host-group-handler.js +413 -0
- package/build/tools/handlers/kms-config-handler.js +321 -0
- package/build/tools/handlers/operation-handler.js +254 -0
- package/build/tools/handlers/quota-rule-handler.js +411 -0
- package/build/tools/handlers/replication-handler.js +504 -0
- package/build/tools/handlers/snapshot-handler.js +320 -0
- package/build/tools/handlers/storage-pool-handler.js +534 -0
- package/build/tools/handlers/volume-handler.js +562 -0
- package/build/tools/host-group-tools.js +134 -0
- package/build/tools/kms-config-tools.js +156 -0
- package/build/tools/operation-tools.js +64 -0
- package/build/tools/quota-rule-tools.js +166 -0
- package/build/tools/replication-tools.js +227 -0
- package/build/tools/snapshot-tools.js +124 -0
- package/build/tools/storage-pool-tools.js +271 -0
- package/build/tools/volume-tools.js +479 -0
- package/build/types/tool.js +1 -0
- package/build/utils/netapp-client-factory.js +64 -0
- package/gemini-extension.json +12 -0
- package/package.json +73 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import { NetAppClientFactory } from '../../utils/netapp-client-factory.js';
|
|
2
|
+
import { logger } from '../../logger.js';
|
|
3
|
+
const log = logger.child({ module: 'snapshot-handler' });
|
|
4
|
+
// Helper to format snapshot data for responses
|
|
5
|
+
function formatSnapshotData(snapshot) {
|
|
6
|
+
const result = {};
|
|
7
|
+
if (!snapshot)
|
|
8
|
+
return result;
|
|
9
|
+
if (snapshot.name) {
|
|
10
|
+
// Extract snapshotId from name (last part after last slash)
|
|
11
|
+
const nameParts = snapshot.name.split('/');
|
|
12
|
+
result.name = snapshot.name;
|
|
13
|
+
result.snapshotId = nameParts[nameParts.length - 1];
|
|
14
|
+
// Extract volumeId from name
|
|
15
|
+
const volumeMatch = snapshot.name.match(/\/volumes\/([^/]+)\/snapshots\//);
|
|
16
|
+
if (volumeMatch && volumeMatch[1]) {
|
|
17
|
+
result.volumeId = volumeMatch[1];
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// Copy basic properties
|
|
21
|
+
if (snapshot.state)
|
|
22
|
+
result.state = snapshot.state;
|
|
23
|
+
// Format timestamps if they exist
|
|
24
|
+
if (snapshot.createTime) {
|
|
25
|
+
result.createTime = new Date(snapshot.createTime.seconds * 1000);
|
|
26
|
+
}
|
|
27
|
+
// Copy optional properties
|
|
28
|
+
if (snapshot.description)
|
|
29
|
+
result.description = snapshot.description;
|
|
30
|
+
if (snapshot.labels)
|
|
31
|
+
result.labels = snapshot.labels;
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
// Create Snapshot Handler
|
|
35
|
+
export const createSnapshotHandler = async (args) => {
|
|
36
|
+
try {
|
|
37
|
+
const { projectId, location, volumeId, snapshotId, description, labels } = args;
|
|
38
|
+
// Create a new NetApp client using the factory
|
|
39
|
+
const netAppClient = NetAppClientFactory.createClient();
|
|
40
|
+
// Format the parent path for the snapshot
|
|
41
|
+
const parent = `projects/${projectId}/locations/${location}/volumes/${volumeId}`;
|
|
42
|
+
// Create the snapshot request
|
|
43
|
+
const request = {
|
|
44
|
+
parent,
|
|
45
|
+
snapshotId,
|
|
46
|
+
snapshot: {
|
|
47
|
+
description,
|
|
48
|
+
labels,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
log.info({ request }, 'Create Snapshot request');
|
|
52
|
+
// Call the API to create a snapshot
|
|
53
|
+
const [operation] = await netAppClient.createSnapshot(request);
|
|
54
|
+
log.info({ operation }, 'Create Snapshot operation');
|
|
55
|
+
return {
|
|
56
|
+
content: [
|
|
57
|
+
{
|
|
58
|
+
type: 'text',
|
|
59
|
+
text: JSON.stringify({
|
|
60
|
+
name: `projects/${projectId}/locations/${location}/volumes/${volumeId}/snapshots/${snapshotId}`,
|
|
61
|
+
operation: operation,
|
|
62
|
+
}, null, 2),
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
structuredContent: {
|
|
66
|
+
name: `projects/${projectId}/locations/${location}/volumes/${volumeId}/snapshots/${snapshotId}`,
|
|
67
|
+
operationId: operation.name || '',
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
log.error({ err: error }, 'Error creating snapshot');
|
|
73
|
+
return {
|
|
74
|
+
isError: true,
|
|
75
|
+
content: [
|
|
76
|
+
{
|
|
77
|
+
type: 'text',
|
|
78
|
+
text: `Error creating snapshot: ${error.message || 'Unknown error'}`,
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
// Delete Snapshot Handler
|
|
85
|
+
export const deleteSnapshotHandler = async (args) => {
|
|
86
|
+
try {
|
|
87
|
+
const { projectId, location, volumeId, snapshotId } = args;
|
|
88
|
+
// Create a new NetApp client using the factory
|
|
89
|
+
const netAppClient = NetAppClientFactory.createClient();
|
|
90
|
+
// Format the name for the snapshot
|
|
91
|
+
const name = `projects/${projectId}/locations/${location}/volumes/${volumeId}/snapshots/${snapshotId}`;
|
|
92
|
+
// Call the API to delete the snapshot
|
|
93
|
+
const request = { name };
|
|
94
|
+
log.info({ request }, 'Delete Snapshot request');
|
|
95
|
+
const [operation] = await netAppClient.deleteSnapshot(request);
|
|
96
|
+
log.info({ operation }, 'Delete Snapshot operation');
|
|
97
|
+
return {
|
|
98
|
+
content: [
|
|
99
|
+
{
|
|
100
|
+
type: 'text',
|
|
101
|
+
text: `Snapshot '${snapshotId}' deletion operation started.`,
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
structuredContent: {
|
|
105
|
+
success: true,
|
|
106
|
+
operationId: operation.name || '',
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
log.error({ err: error }, 'Error deleting snapshot');
|
|
112
|
+
return {
|
|
113
|
+
isError: true,
|
|
114
|
+
content: [
|
|
115
|
+
{
|
|
116
|
+
type: 'text',
|
|
117
|
+
text: `Error deleting snapshot: ${error.message || 'Unknown error'}`,
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
structuredContent: {
|
|
121
|
+
success: false,
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
// Get Snapshot Handler
|
|
127
|
+
export const getSnapshotHandler = async (args) => {
|
|
128
|
+
try {
|
|
129
|
+
const { projectId, location, volumeId, snapshotId } = args;
|
|
130
|
+
// Create a new NetApp client using the factory
|
|
131
|
+
const netAppClient = NetAppClientFactory.createClient();
|
|
132
|
+
// Format the name for the snapshot
|
|
133
|
+
const name = `projects/${projectId}/locations/${location}/volumes/${volumeId}/snapshots/${snapshotId}`;
|
|
134
|
+
// Call the API to get the snapshot
|
|
135
|
+
log.info({ name }, 'Get Snapshot request');
|
|
136
|
+
const [snapshot] = await netAppClient.getSnapshot({ name });
|
|
137
|
+
log.info({ snapshot }, 'Get Snapshot response');
|
|
138
|
+
// Format the snapshot data
|
|
139
|
+
const formattedSnapshot = formatSnapshotData(snapshot);
|
|
140
|
+
return {
|
|
141
|
+
content: [
|
|
142
|
+
{
|
|
143
|
+
type: 'text',
|
|
144
|
+
text: JSON.stringify(formattedSnapshot, null, 2),
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
structuredContent: formattedSnapshot,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
log.error({ err: error }, 'Error getting snapshot');
|
|
152
|
+
return {
|
|
153
|
+
isError: true,
|
|
154
|
+
content: [
|
|
155
|
+
{
|
|
156
|
+
type: 'text',
|
|
157
|
+
text: `Error getting snapshot: ${error.message || 'Unknown error'}`,
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
// List Snapshots Handler
|
|
164
|
+
export const listSnapshotsHandler = async (args) => {
|
|
165
|
+
try {
|
|
166
|
+
const { projectId, location, volumeId, filter, pageSize, pageToken } = args;
|
|
167
|
+
// Create a new NetApp client using the factory
|
|
168
|
+
const netAppClient = NetAppClientFactory.createClient();
|
|
169
|
+
// Format the parent path
|
|
170
|
+
const parent = `projects/${projectId}/locations/${location}/volumes/${volumeId}`;
|
|
171
|
+
// Create the request object
|
|
172
|
+
const request = { parent };
|
|
173
|
+
if (filter)
|
|
174
|
+
request.filter = filter;
|
|
175
|
+
if (pageSize)
|
|
176
|
+
request.pageSize = pageSize;
|
|
177
|
+
if (pageToken)
|
|
178
|
+
request.pageToken = pageToken;
|
|
179
|
+
// Call the API to list snapshots
|
|
180
|
+
log.info({ request }, 'List Snapshots request');
|
|
181
|
+
const [snapshots, , nextPageToken] = await netAppClient.listSnapshots(request);
|
|
182
|
+
log.info({ snapshots, nextPageToken }, 'List Snapshots response');
|
|
183
|
+
const formattedSnapshots = snapshots.map(formatSnapshotData);
|
|
184
|
+
return {
|
|
185
|
+
content: [
|
|
186
|
+
{
|
|
187
|
+
type: 'text',
|
|
188
|
+
text: JSON.stringify({
|
|
189
|
+
snapshots: snapshots,
|
|
190
|
+
nextPageToken: nextPageToken || '',
|
|
191
|
+
}, null, 2),
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
structuredContent: {
|
|
195
|
+
snapshots: formattedSnapshots,
|
|
196
|
+
nextPageToken: nextPageToken || '',
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
log.error({ err: error }, 'Error listing snapshots');
|
|
202
|
+
return {
|
|
203
|
+
isError: true,
|
|
204
|
+
content: [
|
|
205
|
+
{
|
|
206
|
+
type: 'text',
|
|
207
|
+
text: `Error listing snapshots: ${error.message || 'Unknown error'}`,
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
structuredContent: {
|
|
211
|
+
snapshots: [],
|
|
212
|
+
nextPageToken: '',
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
// Revert Volume to Snapshot Handler
|
|
218
|
+
export const revertVolumeToSnapshotHandler = async (args) => {
|
|
219
|
+
try {
|
|
220
|
+
const { projectId, location, volumeId, snapshotId } = args;
|
|
221
|
+
// Create a new NetApp client using the factory
|
|
222
|
+
const netAppClient = NetAppClientFactory.createClient();
|
|
223
|
+
// Format the name for the snapshot
|
|
224
|
+
const snapshot = `projects/${projectId}/locations/${location}/volumes/${volumeId}/snapshots/${snapshotId}`;
|
|
225
|
+
const volume = `projects/${projectId}/locations/${location}/volumes/${volumeId}`;
|
|
226
|
+
// Call the API to revert to snapshot
|
|
227
|
+
const request = {
|
|
228
|
+
name: volume,
|
|
229
|
+
snapshot,
|
|
230
|
+
};
|
|
231
|
+
log.info({ request }, 'Revert to Snapshot request');
|
|
232
|
+
const [operation] = await netAppClient.revertVolume(request);
|
|
233
|
+
log.info({ operation }, 'Revert to Snapshot operation');
|
|
234
|
+
return {
|
|
235
|
+
content: [
|
|
236
|
+
{
|
|
237
|
+
type: 'text',
|
|
238
|
+
text: `Volume '${volumeId}' revert to snapshot '${snapshotId}' operation started.`,
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
structuredContent: {
|
|
242
|
+
success: true,
|
|
243
|
+
operationId: operation.name || '',
|
|
244
|
+
},
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
log.error({ err: error }, 'Error reverting to snapshot');
|
|
249
|
+
return {
|
|
250
|
+
isError: true,
|
|
251
|
+
content: [
|
|
252
|
+
{
|
|
253
|
+
type: 'text',
|
|
254
|
+
text: `Error reverting to snapshot: ${error.message || 'Unknown error'}`,
|
|
255
|
+
},
|
|
256
|
+
],
|
|
257
|
+
structuredContent: {
|
|
258
|
+
success: false,
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
// Update Snapshot Handler
|
|
264
|
+
export const updateSnapshotHandler = async (args) => {
|
|
265
|
+
try {
|
|
266
|
+
const { projectId, location, volumeId, snapshotId, description, labels } = args;
|
|
267
|
+
// Create a new NetApp client using the factory
|
|
268
|
+
const netAppClient = NetAppClientFactory.createClient();
|
|
269
|
+
// Format the name for the snapshot
|
|
270
|
+
const name = `projects/${projectId}/locations/${location}/volumes/${volumeId}/snapshots/${snapshotId}`;
|
|
271
|
+
// Prepare the update mask based on provided fields
|
|
272
|
+
const updateMask = [];
|
|
273
|
+
const snapshot = { name };
|
|
274
|
+
if (description !== undefined) {
|
|
275
|
+
snapshot.description = description;
|
|
276
|
+
updateMask.push('description');
|
|
277
|
+
}
|
|
278
|
+
if (labels !== undefined) {
|
|
279
|
+
snapshot.labels = labels;
|
|
280
|
+
updateMask.push('labels');
|
|
281
|
+
}
|
|
282
|
+
// Call the API to update the snapshot
|
|
283
|
+
const request = {
|
|
284
|
+
snapshot,
|
|
285
|
+
updateMask: {
|
|
286
|
+
paths: updateMask,
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
log.info({ request }, 'Update Snapshot request');
|
|
290
|
+
const [operation] = await netAppClient.updateSnapshot(request);
|
|
291
|
+
log.info({ operation }, 'Update Snapshot operation');
|
|
292
|
+
return {
|
|
293
|
+
content: [
|
|
294
|
+
{
|
|
295
|
+
type: 'text',
|
|
296
|
+
text: JSON.stringify({
|
|
297
|
+
message: `Snapshot '${snapshotId}' update operation started`,
|
|
298
|
+
operation: operation,
|
|
299
|
+
}, null, 2),
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
structuredContent: {
|
|
303
|
+
name: name,
|
|
304
|
+
operationId: operation.name || '',
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
log.error({ err: error }, 'Error updating snapshot');
|
|
310
|
+
return {
|
|
311
|
+
isError: true,
|
|
312
|
+
content: [
|
|
313
|
+
{
|
|
314
|
+
type: 'text',
|
|
315
|
+
text: `Error updating snapshot: ${error.message || 'Unknown error'}`,
|
|
316
|
+
},
|
|
317
|
+
],
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
};
|