@performance-agent/mcp-server 1.0.1 → 1.0.6
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/README.md +400 -25
- package/dist/index.d.ts +14 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +783 -47
- package/dist/index.js.map +1 -1
- package/dist/prompts/jmx_prompt.txt +262 -0
- package/dist/prompts/prompts/jmx_prompt.txt +262 -0
- package/dist/tools/azure-infra/config-parser.d.ts +14 -0
- package/dist/tools/azure-infra/config-parser.d.ts.map +1 -0
- package/dist/tools/azure-infra/config-parser.js +361 -0
- package/dist/tools/azure-infra/config-parser.js.map +1 -0
- package/dist/tools/azure-infra/index.d.ts +52 -0
- package/dist/tools/azure-infra/index.d.ts.map +1 -0
- package/dist/tools/azure-infra/index.js +448 -0
- package/dist/tools/azure-infra/index.js.map +1 -0
- package/dist/tools/azure-infra/terraform-generator.d.ts +19 -0
- package/dist/tools/azure-infra/terraform-generator.d.ts.map +1 -0
- package/dist/tools/azure-infra/terraform-generator.js +458 -0
- package/dist/tools/azure-infra/terraform-generator.js.map +1 -0
- package/dist/tools/azure-infra/types.d.ts +123 -0
- package/dist/tools/azure-infra/types.d.ts.map +1 -0
- package/dist/tools/azure-infra/types.js +95 -0
- package/dist/tools/azure-infra/types.js.map +1 -0
- package/dist/tools/cloud-executor/index.d.ts +78 -0
- package/dist/tools/cloud-executor/index.d.ts.map +1 -0
- package/dist/tools/cloud-executor/index.js +528 -0
- package/dist/tools/cloud-executor/index.js.map +1 -0
- package/dist/tools/cloud-executor/result-analyzer.d.ts +65 -0
- package/dist/tools/cloud-executor/result-analyzer.d.ts.map +1 -0
- package/dist/tools/cloud-executor/result-analyzer.js +367 -0
- package/dist/tools/cloud-executor/result-analyzer.js.map +1 -0
- package/dist/tools/cloud-executor/vm-metrics.d.ts +87 -0
- package/dist/tools/cloud-executor/vm-metrics.d.ts.map +1 -0
- package/dist/tools/cloud-executor/vm-metrics.js +506 -0
- package/dist/tools/cloud-executor/vm-metrics.js.map +1 -0
- package/dist/tools/jmx-generator/index.d.ts +20 -0
- package/dist/tools/jmx-generator/index.d.ts.map +1 -0
- package/dist/tools/jmx-generator/index.js +115 -0
- package/dist/tools/jmx-generator/index.js.map +1 -0
- package/dist/tools/jmx-generator/sanitizer.d.ts +19 -0
- package/dist/tools/jmx-generator/sanitizer.d.ts.map +1 -0
- package/dist/tools/jmx-generator/sanitizer.js +166 -0
- package/dist/tools/jmx-generator/sanitizer.js.map +1 -0
- package/package.json +5 -2
- package/scripts/copy-prompts.js +46 -0
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloud Performance Test Executor
|
|
3
|
+
*
|
|
4
|
+
* This module provides end-to-end automated cloud performance testing:
|
|
5
|
+
* 1. Provision or reuse an Azure VM
|
|
6
|
+
* 2. Install JMeter on the VM
|
|
7
|
+
* 3. Upload the JMX test script
|
|
8
|
+
* 4. Execute the performance test
|
|
9
|
+
* 5. Download and return results
|
|
10
|
+
* 6. Optionally cleanup resources
|
|
11
|
+
*/
|
|
12
|
+
import { execSync } from 'child_process';
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
import { provisionAzureVM } from '../azure-infra/index.js';
|
|
16
|
+
import { PERF_OUTPUT_DIR } from '../azure-infra/terraform-generator.js';
|
|
17
|
+
export { analyzeTestResults } from './result-analyzer.js';
|
|
18
|
+
export { getVMMetrics } from './vm-metrics.js';
|
|
19
|
+
// Configuration
|
|
20
|
+
const DEFAULT_JMETER_VERSION = '5.6.3';
|
|
21
|
+
const DEFAULT_VM_SIZE = 'small';
|
|
22
|
+
const DEFAULT_REGION = 'eastus';
|
|
23
|
+
const SSH_TIMEOUT = 30;
|
|
24
|
+
/**
|
|
25
|
+
* Execute a command and return output
|
|
26
|
+
*/
|
|
27
|
+
function runCommand(command, options = {}) {
|
|
28
|
+
try {
|
|
29
|
+
const result = execSync(command, {
|
|
30
|
+
encoding: 'utf-8',
|
|
31
|
+
timeout: options.timeout || 300000, // 5 minute default timeout
|
|
32
|
+
cwd: options.cwd,
|
|
33
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
34
|
+
});
|
|
35
|
+
return result.trim();
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
throw new Error(`Command failed: ${command}\n${error.message}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Execute SSH command on remote VM
|
|
43
|
+
*/
|
|
44
|
+
function sshCommand(ip, sshKeyPath, command, timeoutSeconds = 300) {
|
|
45
|
+
const sshCmd = `ssh -i "${sshKeyPath}" -o StrictHostKeyChecking=no -o ConnectTimeout=${SSH_TIMEOUT} azureuser@${ip} "${command}"`;
|
|
46
|
+
return runCommand(sshCmd, { timeout: timeoutSeconds * 1000 });
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Copy file to remote VM via SCP
|
|
50
|
+
*/
|
|
51
|
+
function scpToRemote(localPath, remotePath, ip, sshKeyPath) {
|
|
52
|
+
const scpCmd = `scp -i "${sshKeyPath}" -o StrictHostKeyChecking=no -o ConnectTimeout=${SSH_TIMEOUT} "${localPath}" azureuser@${ip}:${remotePath}`;
|
|
53
|
+
runCommand(scpCmd, { timeout: 120000 });
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Copy file from remote VM via SCP
|
|
57
|
+
*/
|
|
58
|
+
function scpFromRemote(remotePath, localPath, ip, sshKeyPath) {
|
|
59
|
+
const scpCmd = `scp -i "${sshKeyPath}" -o StrictHostKeyChecking=no -o ConnectTimeout=${SSH_TIMEOUT} azureuser@${ip}:${remotePath} "${localPath}"`;
|
|
60
|
+
runCommand(scpCmd, { timeout: 300000 });
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Wait for SSH to become available
|
|
64
|
+
*/
|
|
65
|
+
async function waitForSSH(ip, sshKeyPath, maxRetries = 30) {
|
|
66
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
67
|
+
try {
|
|
68
|
+
sshCommand(ip, sshKeyPath, 'echo ready', 10);
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
await new Promise(resolve => setTimeout(resolve, 10000)); // Wait 10 seconds
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Install JMeter on the remote VM
|
|
79
|
+
*/
|
|
80
|
+
async function installJMeter(ip, sshKeyPath, version = DEFAULT_JMETER_VERSION) {
|
|
81
|
+
// Check if JMeter is already installed
|
|
82
|
+
try {
|
|
83
|
+
const checkResult = sshCommand(ip, sshKeyPath, 'which jmeter || ls ~/apache-jmeter-*/bin/jmeter 2>/dev/null', 30);
|
|
84
|
+
if (checkResult && checkResult.includes('jmeter')) {
|
|
85
|
+
console.error('JMeter already installed on VM');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// JMeter not installed, continue with installation
|
|
91
|
+
}
|
|
92
|
+
console.error('Installing Java and JMeter on VM...');
|
|
93
|
+
// Install Java
|
|
94
|
+
sshCommand(ip, sshKeyPath, 'sudo apt-get update && sudo apt-get install -y default-jdk', 300);
|
|
95
|
+
// Download and extract JMeter
|
|
96
|
+
const jmeterUrl = `https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-${version}.tgz`;
|
|
97
|
+
sshCommand(ip, sshKeyPath, `cd ~ && curl -sL "${jmeterUrl}" | tar xz`, 180);
|
|
98
|
+
// Verify installation
|
|
99
|
+
sshCommand(ip, sshKeyPath, `~/apache-jmeter-${version}/bin/jmeter --version`, 30);
|
|
100
|
+
console.error('JMeter installation complete');
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Analyze JMX file to estimate resource requirements
|
|
104
|
+
*/
|
|
105
|
+
function analyzeJMXRequirements(jmxFilePath) {
|
|
106
|
+
const content = fs.readFileSync(jmxFilePath, 'utf-8');
|
|
107
|
+
// Build a map of user-defined variables
|
|
108
|
+
const variableMap = {};
|
|
109
|
+
const varPattern = /<elementProp name="([^"]+)" elementType="Argument">[\s\S]*?<stringProp name="Argument\.value">(\d+)<\/stringProp>/g;
|
|
110
|
+
let varMatch;
|
|
111
|
+
while ((varMatch = varPattern.exec(content)) !== null) {
|
|
112
|
+
variableMap[varMatch[1]] = parseInt(varMatch[2], 10);
|
|
113
|
+
}
|
|
114
|
+
// Extract thread count - handle both hardcoded and variable references
|
|
115
|
+
const threadPattern = /<stringProp name="ThreadGroup\.num_threads">([^<]+)<\/stringProp>/g;
|
|
116
|
+
let totalThreads = 0;
|
|
117
|
+
let threadMatch;
|
|
118
|
+
while ((threadMatch = threadPattern.exec(content)) !== null) {
|
|
119
|
+
const value = threadMatch[1].trim();
|
|
120
|
+
if (value.startsWith('${') && value.endsWith('}')) {
|
|
121
|
+
// Variable reference
|
|
122
|
+
const varName = value.slice(2, -1);
|
|
123
|
+
totalThreads += variableMap[varName] || 1;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
// Hardcoded number
|
|
127
|
+
totalThreads += parseInt(value, 10) || 0;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Extract duration - check both explicit duration and calculate from loops
|
|
131
|
+
let duration = 60; // default
|
|
132
|
+
const durationMatch = content.match(/<stringProp name="ThreadGroup\.duration">(\d+)<\/stringProp>/);
|
|
133
|
+
if (durationMatch) {
|
|
134
|
+
duration = parseInt(durationMatch[1], 10);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
// Calculate from loops and estimated request time
|
|
138
|
+
const loopPattern = /<stringProp name="LoopController\.loops">([^<]+)<\/stringProp>/g;
|
|
139
|
+
let totalLoops = 0;
|
|
140
|
+
let loopCount = 0;
|
|
141
|
+
let loopMatch;
|
|
142
|
+
while ((loopMatch = loopPattern.exec(content)) !== null) {
|
|
143
|
+
const value = loopMatch[1].trim();
|
|
144
|
+
let loops = 1;
|
|
145
|
+
if (value.startsWith('${') && value.endsWith('}')) {
|
|
146
|
+
// Variable reference
|
|
147
|
+
const varName = value.slice(2, -1);
|
|
148
|
+
loops = variableMap[varName] || 1;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
loops = parseInt(value, 10) || 1;
|
|
152
|
+
}
|
|
153
|
+
totalLoops += loops;
|
|
154
|
+
loopCount++;
|
|
155
|
+
}
|
|
156
|
+
if (loopCount > 0) {
|
|
157
|
+
// Count HTTP samplers to estimate requests per loop
|
|
158
|
+
const samplerCount = (content.match(/<HTTPSamplerProxy/g) || []).length;
|
|
159
|
+
const avgLoops = totalLoops / loopCount;
|
|
160
|
+
const estimatedSecondsPerRequest = 2; // Conservative estimate
|
|
161
|
+
duration = avgLoops * samplerCount * estimatedSecondsPerRequest;
|
|
162
|
+
// Ensure minimum realistic duration
|
|
163
|
+
if (duration < 10)
|
|
164
|
+
duration = 10;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Recommend VM size based on thread count
|
|
168
|
+
let recommendedSize = 'small';
|
|
169
|
+
if (totalThreads > 500)
|
|
170
|
+
recommendedSize = 'xlarge';
|
|
171
|
+
else if (totalThreads > 200)
|
|
172
|
+
recommendedSize = 'large';
|
|
173
|
+
else if (totalThreads > 50)
|
|
174
|
+
recommendedSize = 'medium';
|
|
175
|
+
return { recommendedSize, threadCount: totalThreads, duration };
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Parse JTL results file and extract summary
|
|
179
|
+
*/
|
|
180
|
+
function parseJTLResults(jtlPath) {
|
|
181
|
+
if (!fs.existsSync(jtlPath)) {
|
|
182
|
+
return { totalRequests: 0, errorRate: 0, avgResponseTime: 0, summary: 'Results file not found' };
|
|
183
|
+
}
|
|
184
|
+
const content = fs.readFileSync(jtlPath, 'utf-8');
|
|
185
|
+
const lines = content.split('\n').filter(line => line.trim() && !line.startsWith('timeStamp'));
|
|
186
|
+
let totalRequests = 0;
|
|
187
|
+
let errorCount = 0;
|
|
188
|
+
let totalResponseTime = 0;
|
|
189
|
+
lines.forEach(line => {
|
|
190
|
+
const parts = line.split(',');
|
|
191
|
+
if (parts.length >= 4) {
|
|
192
|
+
totalRequests++;
|
|
193
|
+
totalResponseTime += parseInt(parts[1], 10) || 0;
|
|
194
|
+
if (parts[7] === 'false' || parts[3] !== '200') {
|
|
195
|
+
errorCount++;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
const errorRate = totalRequests > 0 ? (errorCount / totalRequests) * 100 : 0;
|
|
200
|
+
const avgResponseTime = totalRequests > 0 ? totalResponseTime / totalRequests : 0;
|
|
201
|
+
const summary = `Total Requests: ${totalRequests}, Error Rate: ${errorRate.toFixed(2)}%, Avg Response Time: ${avgResponseTime.toFixed(2)}ms`;
|
|
202
|
+
return { totalRequests, errorRate, avgResponseTime, summary };
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Main function: Run cloud performance test end-to-end
|
|
206
|
+
*/
|
|
207
|
+
export async function runCloudPerformanceTest(config) {
|
|
208
|
+
const startTime = new Date();
|
|
209
|
+
let vmInfo;
|
|
210
|
+
let sshKeyPath = config.sshKeyPath;
|
|
211
|
+
try {
|
|
212
|
+
// Validate JMX file exists
|
|
213
|
+
if (!fs.existsSync(config.jmxFilePath)) {
|
|
214
|
+
throw new Error(`JMX file not found: ${config.jmxFilePath}`);
|
|
215
|
+
}
|
|
216
|
+
const jmxFileName = path.basename(config.jmxFilePath);
|
|
217
|
+
const analysis = analyzeJMXRequirements(config.jmxFilePath);
|
|
218
|
+
console.error(`JMX Analysis: ${analysis.threadCount} threads, ${analysis.duration}s duration, recommended VM: ${analysis.recommendedSize}`);
|
|
219
|
+
// Step 1: Provision VM or use existing
|
|
220
|
+
let publicIp;
|
|
221
|
+
let vmName;
|
|
222
|
+
let resourceGroup;
|
|
223
|
+
if (config.reuseExistingVM && config.existingVMIp) {
|
|
224
|
+
// Reuse existing VM
|
|
225
|
+
publicIp = config.existingVMIp;
|
|
226
|
+
vmName = config.vmName || 'existing-vm';
|
|
227
|
+
resourceGroup = config.resourceGroup || 'unknown';
|
|
228
|
+
sshKeyPath = config.sshKeyPath;
|
|
229
|
+
if (!sshKeyPath || !fs.existsSync(sshKeyPath)) {
|
|
230
|
+
throw new Error('SSH key path required when reusing existing VM');
|
|
231
|
+
}
|
|
232
|
+
console.error(`Reusing existing VM at ${publicIp}`);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
// Provision new VM
|
|
236
|
+
vmName = config.vmName || `perf-test-vm-${Date.now()}`;
|
|
237
|
+
resourceGroup = config.resourceGroup || `rg-perf-test-${Date.now()}`;
|
|
238
|
+
const vmSize = config.vmSize || analysis.recommendedSize;
|
|
239
|
+
const vmRegion = (config.region || DEFAULT_REGION);
|
|
240
|
+
console.error(`Provisioning new VM: ${vmName} (${vmSize}) in ${vmRegion}`);
|
|
241
|
+
const provisionResult = await provisionAzureVM({
|
|
242
|
+
description: `Create a ${vmSize} Ubuntu VM for JMeter performance testing`,
|
|
243
|
+
config: {
|
|
244
|
+
name: vmName,
|
|
245
|
+
resourceGroup: resourceGroup,
|
|
246
|
+
subscriptionId: config.subscriptionId,
|
|
247
|
+
sizePreset: vmSize,
|
|
248
|
+
os: 'ubuntu-22.04',
|
|
249
|
+
region: vmRegion,
|
|
250
|
+
publicIP: true,
|
|
251
|
+
openPorts: [22],
|
|
252
|
+
},
|
|
253
|
+
method: 'terraform', // Use Terraform for provisioning
|
|
254
|
+
generateTerraform: true,
|
|
255
|
+
});
|
|
256
|
+
if (!provisionResult.success) {
|
|
257
|
+
throw new Error(`VM provisioning failed: ${provisionResult.message || 'Unknown error'}`);
|
|
258
|
+
}
|
|
259
|
+
if (!provisionResult.publicIP) {
|
|
260
|
+
throw new Error('Failed to get VM public IP from provisioning result');
|
|
261
|
+
}
|
|
262
|
+
publicIp = provisionResult.publicIP;
|
|
263
|
+
sshKeyPath = path.join(process.cwd(), PERF_OUTPUT_DIR, 'terraform', vmName, `${vmName}_ssh_key.pem`);
|
|
264
|
+
// Wait for SSH to be available
|
|
265
|
+
console.error('Waiting for VM to become available...');
|
|
266
|
+
if (!sshKeyPath) {
|
|
267
|
+
sshKeyPath = path.join(process.cwd(), PERF_OUTPUT_DIR, 'terraform', vmName, `${vmName}_ssh_key.pem`);
|
|
268
|
+
}
|
|
269
|
+
const sshReady = await waitForSSH(publicIp, sshKeyPath);
|
|
270
|
+
if (!sshReady) {
|
|
271
|
+
throw new Error('VM SSH not available after timeout');
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
vmInfo = { name: vmName, resourceGroup, publicIp, sshKeyPath: sshKeyPath };
|
|
275
|
+
// Step 2: Install JMeter
|
|
276
|
+
await installJMeter(publicIp, sshKeyPath);
|
|
277
|
+
// Step 3: Upload JMX file
|
|
278
|
+
console.error(`Uploading JMX file: ${jmxFileName}`);
|
|
279
|
+
scpToRemote(config.jmxFilePath, `~/${jmxFileName}`, publicIp, sshKeyPath);
|
|
280
|
+
// Step 4: Execute test
|
|
281
|
+
console.error('Executing JMeter test...');
|
|
282
|
+
const jmeterVersion = DEFAULT_JMETER_VERSION;
|
|
283
|
+
const testCommand = `cd ~ && ./apache-jmeter-${jmeterVersion}/bin/jmeter -n -t ${jmxFileName} -l results.jtl -e -o report/ 2>&1`;
|
|
284
|
+
try {
|
|
285
|
+
const testTimeout = (config.testDurationMinutes || 30) * 60 + 120; // Add 2 min buffer
|
|
286
|
+
sshCommand(publicIp, sshKeyPath, testCommand, testTimeout);
|
|
287
|
+
}
|
|
288
|
+
catch (error) {
|
|
289
|
+
// Test might timeout but still produce results
|
|
290
|
+
console.error(`Test execution warning: ${error.message}`);
|
|
291
|
+
}
|
|
292
|
+
// Step 5: Download results
|
|
293
|
+
// Use unified .perf-output folder for all outputs
|
|
294
|
+
const outputPath = config.outputPath || path.join(process.cwd(), PERF_OUTPUT_DIR, 'test-results');
|
|
295
|
+
if (!fs.existsSync(outputPath)) {
|
|
296
|
+
fs.mkdirSync(outputPath, { recursive: true });
|
|
297
|
+
}
|
|
298
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
299
|
+
const resultsDir = path.join(outputPath, `test-${timestamp}`);
|
|
300
|
+
fs.mkdirSync(resultsDir, { recursive: true });
|
|
301
|
+
const localJtlPath = path.join(resultsDir, 'results.jtl');
|
|
302
|
+
console.error('Downloading test results...');
|
|
303
|
+
try {
|
|
304
|
+
scpFromRemote('~/results.jtl', localJtlPath, publicIp, sshKeyPath);
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
console.error('Warning: Could not download results.jtl');
|
|
308
|
+
}
|
|
309
|
+
// Try to download HTML report
|
|
310
|
+
try {
|
|
311
|
+
const reportZipPath = path.join(resultsDir, 'report.tar.gz');
|
|
312
|
+
sshCommand(publicIp, sshKeyPath, 'cd ~ && tar -czf report.tar.gz report/', 60);
|
|
313
|
+
scpFromRemote('~/report.tar.gz', reportZipPath, publicIp, sshKeyPath);
|
|
314
|
+
runCommand(`cd "${resultsDir}" && tar -xzf report.tar.gz`, { timeout: 30000 });
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
console.error('Warning: Could not download HTML report');
|
|
318
|
+
}
|
|
319
|
+
const endTime = new Date();
|
|
320
|
+
const durationSeconds = Math.round((endTime.getTime() - startTime.getTime()) / 1000);
|
|
321
|
+
// Parse results
|
|
322
|
+
const parsedResults = parseJTLResults(localJtlPath);
|
|
323
|
+
// Step 6: Cleanup if requested
|
|
324
|
+
let cleanedUp = false;
|
|
325
|
+
if (config.cleanupAfterTest && !config.reuseExistingVM) {
|
|
326
|
+
console.error('Cleaning up Azure resources with Terraform...');
|
|
327
|
+
try {
|
|
328
|
+
const terraformDir = path.join(process.cwd(), PERF_OUTPUT_DIR, 'terraform', vmName);
|
|
329
|
+
const cleanupResult = await cleanupAzureResources(resourceGroup, terraformDir, true);
|
|
330
|
+
cleanedUp = cleanupResult.success;
|
|
331
|
+
if (!cleanedUp) {
|
|
332
|
+
console.error(`Warning: ${cleanupResult.message}`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
catch {
|
|
336
|
+
console.error('Warning: Could not cleanup resources');
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
success: true,
|
|
341
|
+
vmInfo,
|
|
342
|
+
testExecution: {
|
|
343
|
+
startTime: startTime.toISOString(),
|
|
344
|
+
endTime: endTime.toISOString(),
|
|
345
|
+
durationSeconds,
|
|
346
|
+
},
|
|
347
|
+
results: {
|
|
348
|
+
localPath: resultsDir,
|
|
349
|
+
jtlFile: localJtlPath,
|
|
350
|
+
...parsedResults,
|
|
351
|
+
},
|
|
352
|
+
cleanedUp,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
catch (error) {
|
|
356
|
+
return {
|
|
357
|
+
success: false,
|
|
358
|
+
vmInfo,
|
|
359
|
+
error: error.message,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Get recommended VM configuration based on JMX analysis
|
|
365
|
+
*/
|
|
366
|
+
export function getVMRecommendation(jmxFilePath) {
|
|
367
|
+
const analysis = analyzeJMXRequirements(jmxFilePath);
|
|
368
|
+
const costMap = {
|
|
369
|
+
small: '~$0.02/hour',
|
|
370
|
+
medium: '~$0.10/hour',
|
|
371
|
+
large: '~$0.20/hour',
|
|
372
|
+
xlarge: '~$0.40/hour',
|
|
373
|
+
};
|
|
374
|
+
const descMap = {
|
|
375
|
+
small: '1 vCPU, 2GB RAM - Good for up to 50 concurrent users',
|
|
376
|
+
medium: '2 vCPUs, 8GB RAM - Good for up to 200 concurrent users',
|
|
377
|
+
large: '4 vCPUs, 16GB RAM - Good for up to 500 concurrent users',
|
|
378
|
+
xlarge: '8 vCPUs, 32GB RAM - Good for 500+ concurrent users',
|
|
379
|
+
};
|
|
380
|
+
return {
|
|
381
|
+
...analysis,
|
|
382
|
+
estimatedCost: costMap[analysis.recommendedSize] || '~$0.10/hour',
|
|
383
|
+
description: descMap[analysis.recommendedSize] || 'Standard configuration',
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Cleanup Azure resources - Delete resource group using Terraform destroy (primary) or Azure CLI (fallback)
|
|
388
|
+
*/
|
|
389
|
+
export async function cleanupAzureResources(resourceGroup, terraformDir, force = false) {
|
|
390
|
+
const steps = [];
|
|
391
|
+
const logStep = (message) => {
|
|
392
|
+
console.error(message);
|
|
393
|
+
steps.push(message);
|
|
394
|
+
};
|
|
395
|
+
try {
|
|
396
|
+
// Primary method: Use Terraform destroy if directory exists
|
|
397
|
+
if (terraformDir && fs.existsSync(terraformDir)) {
|
|
398
|
+
logStep(`🔄 Step 1/4: Detected Terraform directory: ${terraformDir}`);
|
|
399
|
+
// Check if terraform state exists
|
|
400
|
+
const tfStatePath = path.join(terraformDir, 'terraform.tfstate');
|
|
401
|
+
const hasTfState = fs.existsSync(tfStatePath);
|
|
402
|
+
if (!hasTfState) {
|
|
403
|
+
logStep('⚠️ No Terraform state found, falling back to Azure CLI');
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
logStep('✅ Step 2/4: Terraform state file found');
|
|
407
|
+
try {
|
|
408
|
+
// Run terraform destroy with real-time output
|
|
409
|
+
const destroyCmd = 'terraform destroy -auto-approve';
|
|
410
|
+
logStep(`🚀 Step 3/4: Executing: ${destroyCmd}`);
|
|
411
|
+
// Always run synchronously for better UX - show progress
|
|
412
|
+
const result = runCommand(`cd "${terraformDir}" && ${destroyCmd}`, { timeout: 600000 });
|
|
413
|
+
logStep('✅ Step 3/4: Terraform destroy completed');
|
|
414
|
+
// Verify deletion by checking if resource group still exists
|
|
415
|
+
logStep('🔍 Step 4/4: Verifying resource deletion...');
|
|
416
|
+
let verificationStatus = 'unknown';
|
|
417
|
+
try {
|
|
418
|
+
const checkCmd = `az group exists --name ${resourceGroup}`;
|
|
419
|
+
const stillExists = runCommand(checkCmd, { timeout: 30000 }).trim().toLowerCase() === 'true';
|
|
420
|
+
if (stillExists) {
|
|
421
|
+
verificationStatus = 'pending';
|
|
422
|
+
logStep('⏳ Resource group still exists (deletion may be propagating)');
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
verificationStatus = 'confirmed';
|
|
426
|
+
logStep('✅ Step 4/4: Resource group deletion CONFIRMED - No longer exists in Azure');
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
catch (verifyError) {
|
|
430
|
+
verificationStatus = 'verification-failed';
|
|
431
|
+
logStep('⚠️ Could not verify deletion status (Azure CLI check failed)');
|
|
432
|
+
}
|
|
433
|
+
logStep('');
|
|
434
|
+
logStep('═══════════════════════════════════════════════════════════');
|
|
435
|
+
logStep('🎉 CLEANUP COMPLETE');
|
|
436
|
+
logStep('═══════════════════════════════════════════════════════════');
|
|
437
|
+
logStep(` Resource Group: ${resourceGroup}`);
|
|
438
|
+
logStep(` Method: Terraform destroy`);
|
|
439
|
+
logStep(` Status: ${verificationStatus === 'confirmed' ? '✅ DELETED' : '⏳ Deletion in progress'}`);
|
|
440
|
+
logStep(` Billing: ${verificationStatus === 'confirmed' ? '💰 STOPPED' : '💰 Will stop shortly'}`);
|
|
441
|
+
logStep('═══════════════════════════════════════════════════════════');
|
|
442
|
+
return {
|
|
443
|
+
success: true,
|
|
444
|
+
message: verificationStatus === 'confirmed'
|
|
445
|
+
? `✅ Resource group '${resourceGroup}' has been successfully destroyed and verified deleted from Azure.`
|
|
446
|
+
: `Resource group '${resourceGroup}' destruction completed. Deletion is propagating through Azure.`,
|
|
447
|
+
method: 'terraform',
|
|
448
|
+
steps,
|
|
449
|
+
verificationStatus,
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
catch (error) {
|
|
453
|
+
logStep(`❌ Terraform destroy failed: ${error.message}`);
|
|
454
|
+
logStep('⚠️ Falling back to Azure CLI...');
|
|
455
|
+
// Fall through to Azure CLI method
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
logStep('ℹ️ No Terraform directory provided or found, using Azure CLI');
|
|
461
|
+
}
|
|
462
|
+
// Fallback: Use Azure CLI to delete resource group
|
|
463
|
+
logStep('🔍 Checking if resource group exists...');
|
|
464
|
+
const checkCmd = `az group exists --name ${resourceGroup}`;
|
|
465
|
+
const exists = runCommand(checkCmd).trim().toLowerCase() === 'true';
|
|
466
|
+
if (!exists) {
|
|
467
|
+
logStep('');
|
|
468
|
+
logStep('═══════════════════════════════════════════════════════════');
|
|
469
|
+
logStep('✅ ALREADY DELETED');
|
|
470
|
+
logStep('═══════════════════════════════════════════════════════════');
|
|
471
|
+
logStep(` Resource Group: ${resourceGroup}`);
|
|
472
|
+
logStep(` Status: Does not exist in Azure`);
|
|
473
|
+
logStep(` Billing: 💰 STOPPED`);
|
|
474
|
+
logStep('═══════════════════════════════════════════════════════════');
|
|
475
|
+
return {
|
|
476
|
+
success: true,
|
|
477
|
+
message: `Resource group '${resourceGroup}' does not exist or has already been deleted. No billing charges.`,
|
|
478
|
+
method: 'already-deleted',
|
|
479
|
+
steps,
|
|
480
|
+
verificationStatus: 'confirmed',
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
// Delete resource group with Azure CLI
|
|
484
|
+
logStep(`🗑️ Deleting resource group with Azure CLI: ${resourceGroup}`);
|
|
485
|
+
const deleteCmd = `az group delete --name ${resourceGroup} --yes`;
|
|
486
|
+
runCommand(deleteCmd, { timeout: 600000 });
|
|
487
|
+
logStep('✅ Azure CLI delete command completed');
|
|
488
|
+
// Verify deletion
|
|
489
|
+
logStep('🔍 Verifying resource deletion...');
|
|
490
|
+
let verificationStatus = 'unknown';
|
|
491
|
+
try {
|
|
492
|
+
const stillExists = runCommand(checkCmd, { timeout: 30000 }).trim().toLowerCase() === 'true';
|
|
493
|
+
verificationStatus = stillExists ? 'pending' : 'confirmed';
|
|
494
|
+
if (!stillExists) {
|
|
495
|
+
logStep('✅ Resource group deletion CONFIRMED');
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
catch (e) {
|
|
499
|
+
verificationStatus = 'verification-failed';
|
|
500
|
+
}
|
|
501
|
+
logStep('');
|
|
502
|
+
logStep('═══════════════════════════════════════════════════════════');
|
|
503
|
+
logStep('🎉 CLEANUP COMPLETE');
|
|
504
|
+
logStep('═══════════════════════════════════════════════════════════');
|
|
505
|
+
logStep(` Resource Group: ${resourceGroup}`);
|
|
506
|
+
logStep(` Method: Azure CLI`);
|
|
507
|
+
logStep(` Status: ${verificationStatus === 'confirmed' ? '✅ DELETED' : '⏳ Deletion in progress'}`);
|
|
508
|
+
logStep(` Billing: 💰 STOPPED`);
|
|
509
|
+
logStep('═══════════════════════════════════════════════════════════');
|
|
510
|
+
return {
|
|
511
|
+
success: true,
|
|
512
|
+
message: `Resource group '${resourceGroup}' deleted successfully using Azure CLI.`,
|
|
513
|
+
method: 'azure-cli',
|
|
514
|
+
steps,
|
|
515
|
+
verificationStatus,
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
catch (error) {
|
|
519
|
+
logStep(`❌ Error: ${error.message}`);
|
|
520
|
+
return {
|
|
521
|
+
success: false,
|
|
522
|
+
message: `Failed to delete resource group: ${error.message}`,
|
|
523
|
+
method: 'failed',
|
|
524
|
+
steps,
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/cloud-executor/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performance Test Result Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Provides detailed analysis of JMeter test results including:
|
|
5
|
+
* - Request statistics (throughput, response times, error rates)
|
|
6
|
+
* - Performance trends over time
|
|
7
|
+
* - Azure VM metrics during test execution (CPU, memory, disk, network)
|
|
8
|
+
*/
|
|
9
|
+
export interface TestResultAnalysis {
|
|
10
|
+
success: boolean;
|
|
11
|
+
resultFile?: string;
|
|
12
|
+
summary: {
|
|
13
|
+
totalRequests: number;
|
|
14
|
+
successfulRequests: number;
|
|
15
|
+
failedRequests: number;
|
|
16
|
+
errorRate: number;
|
|
17
|
+
avgResponseTime: number;
|
|
18
|
+
minResponseTime: number;
|
|
19
|
+
maxResponseTime: number;
|
|
20
|
+
p50ResponseTime: number;
|
|
21
|
+
p90ResponseTime: number;
|
|
22
|
+
p95ResponseTime: number;
|
|
23
|
+
p99ResponseTime: number;
|
|
24
|
+
throughput: number;
|
|
25
|
+
testDurationSeconds: number;
|
|
26
|
+
};
|
|
27
|
+
requestBreakdown?: {
|
|
28
|
+
label: string;
|
|
29
|
+
count: number;
|
|
30
|
+
avgTime: number;
|
|
31
|
+
minTime: number;
|
|
32
|
+
maxTime: number;
|
|
33
|
+
errorCount: number;
|
|
34
|
+
errorRate: number;
|
|
35
|
+
}[];
|
|
36
|
+
vmMetrics?: {
|
|
37
|
+
available: boolean;
|
|
38
|
+
cpuUsage?: {
|
|
39
|
+
avg: number;
|
|
40
|
+
max: number;
|
|
41
|
+
min: number;
|
|
42
|
+
};
|
|
43
|
+
memoryUsage?: {
|
|
44
|
+
avg: number;
|
|
45
|
+
max: number;
|
|
46
|
+
min: number;
|
|
47
|
+
};
|
|
48
|
+
diskIO?: {
|
|
49
|
+
readMBps: number;
|
|
50
|
+
writeMBps: number;
|
|
51
|
+
};
|
|
52
|
+
networkIO?: {
|
|
53
|
+
inboundMBps: number;
|
|
54
|
+
outboundMBps: number;
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
insights: string[];
|
|
58
|
+
recommendations: string[];
|
|
59
|
+
error?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Main function: Analyze performance test results
|
|
63
|
+
*/
|
|
64
|
+
export declare function analyzeTestResults(resultFilePath: string, resourceGroup?: string, vmName?: string, testStartTime?: string, testEndTime?: string): Promise<TestResultAnalysis>;
|
|
65
|
+
//# sourceMappingURL=result-analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-analyzer.d.ts","sourceRoot":"","sources":["../../../src/tools/cloud-executor/result-analyzer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE;QACP,aAAa,EAAE,MAAM,CAAC;QACtB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,cAAc,EAAE,MAAM,CAAC;QACvB,SAAS,EAAE,MAAM,CAAC;QAClB,eAAe,EAAE,MAAM,CAAC;QACxB,eAAe,EAAE,MAAM,CAAC;QACxB,eAAe,EAAE,MAAM,CAAC;QACxB,eAAe,EAAE,MAAM,CAAC;QACxB,eAAe,EAAE,MAAM,CAAC;QACxB,eAAe,EAAE,MAAM,CAAC;QACxB,eAAe,EAAE,MAAM,CAAC;QACxB,UAAU,EAAE,MAAM,CAAC;QACnB,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC;IACF,gBAAgB,CAAC,EAAE;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;KACnB,EAAE,CAAC;IACJ,SAAS,CAAC,EAAE;QACV,SAAS,EAAE,OAAO,CAAC;QACnB,QAAQ,CAAC,EAAE;YACT,GAAG,EAAE,MAAM,CAAC;YACZ,GAAG,EAAE,MAAM,CAAC;YACZ,GAAG,EAAE,MAAM,CAAC;SACb,CAAC;QACF,WAAW,CAAC,EAAE;YACZ,GAAG,EAAE,MAAM,CAAC;YACZ,GAAG,EAAE,MAAM,CAAC;YACZ,GAAG,EAAE,MAAM,CAAC;SACb,CAAC;QACF,MAAM,CAAC,EAAE;YACP,QAAQ,EAAE,MAAM,CAAC;YACjB,SAAS,EAAE,MAAM,CAAC;SACnB,CAAC;QACF,SAAS,CAAC,EAAE;YACV,WAAW,EAAE,MAAM,CAAC;YACpB,YAAY,EAAE,MAAM,CAAC;SACtB,CAAC;KACH,CAAC;IACF,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAmVD;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,cAAc,EAAE,MAAM,EACtB,aAAa,CAAC,EAAE,MAAM,EACtB,MAAM,CAAC,EAAE,MAAM,EACf,aAAa,CAAC,EAAE,MAAM,EACtB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,kBAAkB,CAAC,CA+D7B"}
|