@gcnv/gcnv-mcp-server 1.0.3
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 +200 -0
- package/LICENSE +201 -0
- package/README.md +374 -0
- package/build/index.js +185 -0
- package/build/logger.js +19 -0
- package/build/registry/register-tools.js +101 -0
- package/build/registry/tool-registry.js +27 -0
- package/build/tools/active-directory-tools.js +124 -0
- package/build/tools/backup-policy-tools.js +140 -0
- package/build/tools/backup-tools.js +178 -0
- package/build/tools/backup-vault-tools.js +147 -0
- package/build/tools/handlers/active-directory-handler.js +321 -0
- package/build/tools/handlers/backup-handler.js +451 -0
- package/build/tools/handlers/backup-policy-handler.js +275 -0
- package/build/tools/handlers/backup-vault-handler.js +370 -0
- package/build/tools/handlers/kms-config-handler.js +327 -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 +346 -0
- package/build/tools/handlers/volume-handler.js +353 -0
- package/build/tools/kms-config-tools.js +162 -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 +215 -0
- package/build/tools/volume-tools.js +216 -0
- package/build/types/tool.js +1 -0
- package/build/utils/netapp-client-factory.js +53 -0
- package/gemini-extension.json +12 -0
- package/package.json +66 -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
|
+
};
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { NetAppClientFactory } from '../../utils/netapp-client-factory.js';
|
|
2
|
+
import { logger } from '../../logger.js';
|
|
3
|
+
const log = logger.child({ module: 'storage-pool-handler' });
|
|
4
|
+
// Create Storage Pool Handler
|
|
5
|
+
export const createStoragePoolHandler = async (args) => {
|
|
6
|
+
try {
|
|
7
|
+
const { projectId, location, storagePoolId, capacityGib, serviceLevel, description, labels, network, activeDirectory, kmsConfig, encryptionType, ldapEnabled, psaRange, globalAccessAllowed, allowAutoTiering, } = args;
|
|
8
|
+
// Create a new NetApp client using the factory
|
|
9
|
+
const netAppClient = NetAppClientFactory.createClient();
|
|
10
|
+
// Format the parent path for the storage pool
|
|
11
|
+
const parent = `projects/${projectId}/locations/${location}`;
|
|
12
|
+
// Build the storage pool payload with provided fields only
|
|
13
|
+
const storagePoolPayload = {
|
|
14
|
+
capacityGib,
|
|
15
|
+
serviceLevel,
|
|
16
|
+
description,
|
|
17
|
+
labels,
|
|
18
|
+
network,
|
|
19
|
+
};
|
|
20
|
+
if (activeDirectory)
|
|
21
|
+
storagePoolPayload.activeDirectory = activeDirectory;
|
|
22
|
+
if (kmsConfig)
|
|
23
|
+
storagePoolPayload.kmsConfig = kmsConfig;
|
|
24
|
+
if (encryptionType)
|
|
25
|
+
storagePoolPayload.encryptionType = encryptionType;
|
|
26
|
+
if (ldapEnabled !== undefined)
|
|
27
|
+
storagePoolPayload.ldapEnabled = ldapEnabled;
|
|
28
|
+
if (psaRange)
|
|
29
|
+
storagePoolPayload.psaRange = psaRange;
|
|
30
|
+
if (globalAccessAllowed !== undefined)
|
|
31
|
+
storagePoolPayload.globalAccessAllowed = globalAccessAllowed;
|
|
32
|
+
if (allowAutoTiering !== undefined)
|
|
33
|
+
storagePoolPayload.allowAutoTiering = allowAutoTiering;
|
|
34
|
+
// Create the storage pool request
|
|
35
|
+
const request = {
|
|
36
|
+
parent,
|
|
37
|
+
storagePoolId,
|
|
38
|
+
storagePool: storagePoolPayload,
|
|
39
|
+
};
|
|
40
|
+
log.info({ request }, 'Create Storage Pool request');
|
|
41
|
+
// Call the API to create a storage pool
|
|
42
|
+
const [operation] = await netAppClient.createStoragePool(request);
|
|
43
|
+
log.info({ operation }, 'Create Storage Pool operation');
|
|
44
|
+
return {
|
|
45
|
+
content: [
|
|
46
|
+
{
|
|
47
|
+
type: 'text',
|
|
48
|
+
text: JSON.stringify({
|
|
49
|
+
name: `projects/${projectId}/locations/${location}/storagePools/${storagePoolId}`,
|
|
50
|
+
operation: operation,
|
|
51
|
+
}, null, 2),
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
structuredContent: {
|
|
55
|
+
name: `projects/${projectId}/locations/${location}/storagePools/${storagePoolId}`,
|
|
56
|
+
operationId: operation.name || '',
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
log.error({ err: error }, 'Error creating storage pool');
|
|
62
|
+
return {
|
|
63
|
+
isError: true,
|
|
64
|
+
content: [
|
|
65
|
+
{
|
|
66
|
+
type: 'text',
|
|
67
|
+
text: `Error creating storage pool: ${error.message || 'Unknown error'}`,
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
// Delete Storage Pool Handler
|
|
74
|
+
export const deleteStoragePoolHandler = async (args) => {
|
|
75
|
+
try {
|
|
76
|
+
const { projectId, location, storagePoolId, force = false } = args;
|
|
77
|
+
// Create a new NetApp client using the factory
|
|
78
|
+
const netAppClient = NetAppClientFactory.createClient();
|
|
79
|
+
// Format the name for the storage pool
|
|
80
|
+
const name = `projects/${projectId}/locations/${location}/storagePools/${storagePoolId}`;
|
|
81
|
+
// Call the API to delete the storage pool
|
|
82
|
+
const request = { name };
|
|
83
|
+
// Only add force if it's true to avoid API errors
|
|
84
|
+
if (force) {
|
|
85
|
+
request.force = force;
|
|
86
|
+
}
|
|
87
|
+
const operation = await netAppClient.deleteStoragePool(request);
|
|
88
|
+
const operationName = operation[0].name || '';
|
|
89
|
+
return {
|
|
90
|
+
content: [
|
|
91
|
+
{
|
|
92
|
+
type: 'text',
|
|
93
|
+
text: JSON.stringify({ success: true, operation: operation }, null, 2),
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
structuredContent: {
|
|
97
|
+
success: true,
|
|
98
|
+
operationId: operationName,
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
log.error({ err: error }, 'Error deleting storage pool');
|
|
104
|
+
return {
|
|
105
|
+
isError: true,
|
|
106
|
+
content: [
|
|
107
|
+
{
|
|
108
|
+
type: 'text',
|
|
109
|
+
text: `Error deleting storage pool: ${error.message || 'Unknown error'}`,
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
// Get Storage Pool Handler
|
|
116
|
+
export const getStoragePoolHandler = async (args) => {
|
|
117
|
+
try {
|
|
118
|
+
const { projectId, location, storagePoolId } = args;
|
|
119
|
+
// Create a new NetApp client using the factory
|
|
120
|
+
const netAppClient = NetAppClientFactory.createClient();
|
|
121
|
+
// Format the name for the storage pool
|
|
122
|
+
const name = `projects/${projectId}/locations/${location}/storagePools/${storagePoolId}`;
|
|
123
|
+
// Call the API to get the storage pool
|
|
124
|
+
const [storagePool] = await netAppClient.getStoragePool({ name });
|
|
125
|
+
log.info({ storagePool }, 'Get Storage Pool response');
|
|
126
|
+
return {
|
|
127
|
+
content: [
|
|
128
|
+
{
|
|
129
|
+
type: 'text',
|
|
130
|
+
text: JSON.stringify(storagePool, null, 2),
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
structuredContent: {
|
|
134
|
+
name: storagePool.name || '',
|
|
135
|
+
storagePoolId: storagePoolId,
|
|
136
|
+
capacityGib: Number(storagePool.capacityGib) || 0,
|
|
137
|
+
volumeCapacityGib: Number(storagePool.volumeCapacityGib) || 0,
|
|
138
|
+
volumecount: storagePool.volumeCount || 0,
|
|
139
|
+
serviceLevel: storagePool.serviceLevel || '',
|
|
140
|
+
state: storagePool.state || 'UNKNOWN',
|
|
141
|
+
createTime: storagePool.createTime && storagePool.createTime.seconds
|
|
142
|
+
? new Date(Number(storagePool.createTime.seconds) * 1000)
|
|
143
|
+
: new Date(),
|
|
144
|
+
description: storagePool.description || '',
|
|
145
|
+
labels: storagePool.labels || {},
|
|
146
|
+
network: storagePool.network,
|
|
147
|
+
activeDirectory: storagePool.activeDirectory,
|
|
148
|
+
kmsConfig: storagePool.kmsConfig,
|
|
149
|
+
encryptionType: storagePool.encryptionType,
|
|
150
|
+
ldapEnabled: storagePool.ldapEnabled ?? false,
|
|
151
|
+
psaRange: storagePool.psaRange,
|
|
152
|
+
globalAccessAllowed: storagePool.globalAccessAllowed ?? false,
|
|
153
|
+
allowAutoTiering: storagePool.allowAutoTiering ?? false,
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
log.error({ err: error }, 'Error getting storage pool');
|
|
159
|
+
return {
|
|
160
|
+
isError: true,
|
|
161
|
+
content: [
|
|
162
|
+
{
|
|
163
|
+
type: 'text',
|
|
164
|
+
text: `Error getting storage pool: ${error.message || 'Unknown error'}`,
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
// List Storage Pools Handler
|
|
171
|
+
export const listStoragePoolsHandler = async (args) => {
|
|
172
|
+
try {
|
|
173
|
+
const { projectId, location, filter, pageSize, pageToken } = args;
|
|
174
|
+
// Create a new NetApp client using the factory
|
|
175
|
+
const netAppClient = NetAppClientFactory.createClient();
|
|
176
|
+
// Format the parent path for listing storage pools
|
|
177
|
+
const parent = `projects/${projectId}/locations/${location}`;
|
|
178
|
+
// Call the API to list storage pools
|
|
179
|
+
const [storagePools, , paginated_response] = await netAppClient.listStoragePools({
|
|
180
|
+
parent,
|
|
181
|
+
pageSize,
|
|
182
|
+
pageToken,
|
|
183
|
+
orderBy: undefined,
|
|
184
|
+
filter,
|
|
185
|
+
});
|
|
186
|
+
log.info({ storagePools, paginated_response }, 'List Storage Pools response');
|
|
187
|
+
// Get the storage pools and next page token
|
|
188
|
+
const nextPageToken = paginated_response ? paginated_response.nextPageToken : undefined;
|
|
189
|
+
// Map the storage pools to the desired format
|
|
190
|
+
const formattedPools = storagePools.map((pool) => {
|
|
191
|
+
// Extract the ID from the name
|
|
192
|
+
const name = pool.name || '';
|
|
193
|
+
const nameParts = name.split('/');
|
|
194
|
+
const extractedId = nameParts[nameParts.length - 1];
|
|
195
|
+
return {
|
|
196
|
+
name: name,
|
|
197
|
+
storagePoolId: extractedId,
|
|
198
|
+
serviceLevel: pool.serviceLevel || '',
|
|
199
|
+
capacityGib: Number(pool.capacityGib) || 0,
|
|
200
|
+
volumeCapacityGib: Number(pool.volumeCapacityGib) || 0,
|
|
201
|
+
volumecount: pool.volumeCount || 0,
|
|
202
|
+
state: pool.state || 'UNKNOWN',
|
|
203
|
+
createTime: pool.createTime && pool.createTime.seconds
|
|
204
|
+
? new Date(Number(pool.createTime.seconds) * 1000)
|
|
205
|
+
: new Date(),
|
|
206
|
+
description: pool.description || '',
|
|
207
|
+
labels: pool.labels || {},
|
|
208
|
+
network: pool.network,
|
|
209
|
+
activeDirectory: pool.activeDirectory,
|
|
210
|
+
kmsConfig: pool.kmsConfig,
|
|
211
|
+
encryptionType: pool.encryptionType,
|
|
212
|
+
ldapEnabled: pool.ldapEnabled ?? false,
|
|
213
|
+
psaRange: pool.psaRange,
|
|
214
|
+
globalAccessAllowed: pool.globalAccessAllowed ?? false,
|
|
215
|
+
allowAutoTiering: pool.allowAutoTiering ?? false,
|
|
216
|
+
};
|
|
217
|
+
});
|
|
218
|
+
return {
|
|
219
|
+
content: [
|
|
220
|
+
{
|
|
221
|
+
type: 'text',
|
|
222
|
+
text: JSON.stringify(storagePools, null, 2),
|
|
223
|
+
},
|
|
224
|
+
],
|
|
225
|
+
structuredContent: {
|
|
226
|
+
storagePools: formattedPools,
|
|
227
|
+
nextPageToken: nextPageToken,
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
log.error({ err: error }, 'Error listing storage pools');
|
|
233
|
+
return {
|
|
234
|
+
isError: true,
|
|
235
|
+
content: [
|
|
236
|
+
{
|
|
237
|
+
type: 'text',
|
|
238
|
+
text: `Error listing storage pools: ${error.message || 'Unknown error'}`,
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
// Update Storage Pool Handler
|
|
245
|
+
export const updateStoragePoolHandler = async (args) => {
|
|
246
|
+
try {
|
|
247
|
+
const { projectId, location, storagePoolId, capacityGib, description, labels } = args;
|
|
248
|
+
// Create a new NetApp client using the factory
|
|
249
|
+
const netAppClient = NetAppClientFactory.createClient();
|
|
250
|
+
// Format the name for the storage pool
|
|
251
|
+
const name = `projects/${projectId}/locations/${location}/storagePools/${storagePoolId}`;
|
|
252
|
+
// Prepare the update mask based on provided fields
|
|
253
|
+
const updateMask = [];
|
|
254
|
+
const storagePool = {};
|
|
255
|
+
if (capacityGib !== undefined) {
|
|
256
|
+
storagePool.capacityGib = capacityGib;
|
|
257
|
+
updateMask.push('capacity_gib');
|
|
258
|
+
}
|
|
259
|
+
if (description !== undefined) {
|
|
260
|
+
storagePool.description = description;
|
|
261
|
+
updateMask.push('description');
|
|
262
|
+
}
|
|
263
|
+
if (labels !== undefined) {
|
|
264
|
+
storagePool.labels = labels;
|
|
265
|
+
updateMask.push('labels');
|
|
266
|
+
}
|
|
267
|
+
// Call the API to update the storage pool
|
|
268
|
+
const [operation] = await netAppClient.updateStoragePool({
|
|
269
|
+
storagePool: {
|
|
270
|
+
name,
|
|
271
|
+
...storagePool,
|
|
272
|
+
},
|
|
273
|
+
updateMask: {
|
|
274
|
+
paths: updateMask,
|
|
275
|
+
},
|
|
276
|
+
});
|
|
277
|
+
log.info({ operation }, 'Update Storage Pool operation');
|
|
278
|
+
return {
|
|
279
|
+
content: [
|
|
280
|
+
{
|
|
281
|
+
type: 'text',
|
|
282
|
+
text: JSON.stringify({ name: `Update ${name}`, operation: operation }, null, 2),
|
|
283
|
+
},
|
|
284
|
+
],
|
|
285
|
+
structuredContent: {
|
|
286
|
+
name: storagePool.name || '',
|
|
287
|
+
operationId: operation.name || '',
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
log.error({ err: error }, 'Error updating storage pool');
|
|
293
|
+
return {
|
|
294
|
+
isError: true,
|
|
295
|
+
content: [
|
|
296
|
+
{
|
|
297
|
+
type: 'text',
|
|
298
|
+
text: `Error updating storage pool: ${error.message || 'Unknown error'}`,
|
|
299
|
+
},
|
|
300
|
+
],
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
// Validate Directory Service Handler
|
|
305
|
+
export const validateDirectoryServiceHandler = async (args) => {
|
|
306
|
+
try {
|
|
307
|
+
const { projectId, location, storagePoolId, directoryServiceType } = args;
|
|
308
|
+
// Create a new NetApp client using the factory
|
|
309
|
+
const netAppClient = NetAppClientFactory.createClient();
|
|
310
|
+
// Format the name for the storage pool
|
|
311
|
+
const name = `projects/${projectId}/locations/${location}/storagePools/${storagePoolId}`;
|
|
312
|
+
// Call the API to validate directory service
|
|
313
|
+
const [operation] = await netAppClient.validateDirectoryService({
|
|
314
|
+
name,
|
|
315
|
+
directoryServiceType,
|
|
316
|
+
});
|
|
317
|
+
log.info({ operation }, 'Validate Directory Service operation');
|
|
318
|
+
return {
|
|
319
|
+
content: [
|
|
320
|
+
{
|
|
321
|
+
type: 'text',
|
|
322
|
+
text: JSON.stringify({
|
|
323
|
+
message: `Directory service validation initiated for storage pool ${storagePoolId}`,
|
|
324
|
+
operation: operation,
|
|
325
|
+
}, null, 2),
|
|
326
|
+
},
|
|
327
|
+
],
|
|
328
|
+
structuredContent: {
|
|
329
|
+
success: true,
|
|
330
|
+
operationId: operation.name || '',
|
|
331
|
+
},
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
log.error({ err: error }, 'Error validating directory service');
|
|
336
|
+
return {
|
|
337
|
+
isError: true,
|
|
338
|
+
content: [
|
|
339
|
+
{
|
|
340
|
+
type: 'text',
|
|
341
|
+
text: `Error validating directory service: ${error.message || 'Unknown error'}`,
|
|
342
|
+
},
|
|
343
|
+
],
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
};
|