lib/Utils/LoadtestConfigUtil.js (293 lines of code) (raw):
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LoadtestConfigUtil = void 0;
const util_1 = require("util");
const pathLib = require('path');
const Util = __importStar(require("./CommonUtils"));
const EngineUtil = __importStar(require("./EngineUtil"));
const TestKind_1 = require("../models/TestKind");
const yaml = require('js-yaml');
const fs = __importStar(require("fs"));
const PayloadModels_1 = require("../models/PayloadModels");
const UtilModels_1 = require("../models/UtilModels");
const CoreUtils = __importStar(require("./CoreUtils"));
const GeneralConstants_1 = require("../Constants/GeneralConstants");
const InputConstants = __importStar(require("../Constants/InputConstants"));
const PassFailCriteriaUtil_1 = require("./PassFailCriteriaUtil");
const YamlValidationUtil_1 = require("./YamlValidationUtil");
class LoadtestConfigUtil {
static parseLoadtestConfigFile() {
var _a, _b, _c, _d, _e, _f, _g;
const yamlFilePath = this.validateAndGetYamlFilePath();
const yamlConfig = this.readLoadtestConfigFile(yamlFilePath);
let loadtestConfig = {};
let filePath = pathLib.dirname(yamlFilePath);
loadtestConfig.testId = ((_a = yamlConfig.testId) !== null && _a !== void 0 ? _a : yamlConfig.testName);
loadtestConfig.testId = loadtestConfig.testId.toLowerCase();
loadtestConfig.displayName = (_b = yamlConfig.displayName) !== null && _b !== void 0 ? _b : loadtestConfig.testId;
loadtestConfig.description = yamlConfig.description;
loadtestConfig.engineInstances = (_c = yamlConfig.engineInstances) !== null && _c !== void 0 ? _c : 1;
loadtestConfig.kind = (_d = yamlConfig.testType) !== null && _d !== void 0 ? _d : TestKind_1.TestKind.JMX;
if (yamlConfig.splitAllCSVs != undefined) {
loadtestConfig.splitAllCSVs = yamlConfig.splitAllCSVs;
}
this.parseFileConfiguration(loadtestConfig, yamlConfig, filePath);
this.parseParameters(loadtestConfig, yamlConfig);
if (yamlConfig.failureCriteria != undefined) {
if (Array.isArray(yamlConfig.failureCriteria)) {
loadtestConfig.failureCriteria = (0, PassFailCriteriaUtil_1.getPassFailCriteriaFromString)(yamlConfig.failureCriteria);
}
else {
loadtestConfig.failureCriteria = (0, PassFailCriteriaUtil_1.getPassFailCriteriaFromString)((_e = yamlConfig.failureCriteria.clientMetrics) !== null && _e !== void 0 ? _e : []);
loadtestConfig.serverFailureCriteria = (0, PassFailCriteriaUtil_1.getServerCriteriaFromYaml)((_f = yamlConfig.failureCriteria.serverMetrics) !== null && _f !== void 0 ? _f : []);
}
}
if (yamlConfig.autoStop != undefined) {
loadtestConfig.autoStop = this.getAutoStopCriteria(yamlConfig.autoStop);
}
if (yamlConfig.subnetId != undefined) {
loadtestConfig.subnetId = (yamlConfig.subnetId);
}
if (yamlConfig.publicIPDisabled != undefined) {
loadtestConfig.publicIPDisabled = (yamlConfig.publicIPDisabled);
}
// Setting default values for appComponents and serverMetricsConfig
loadtestConfig.appComponents = {};
loadtestConfig.serverMetricsConfig = {};
loadtestConfig.addDefaultsForAppComponents = {};
if (yamlConfig.appComponents != undefined) {
this.parseAppComponentsAndServerMetricsConfig(loadtestConfig, yamlConfig.appComponents);
}
// Setting default values for reference identities
loadtestConfig.keyVaultReferenceIdentityType = PayloadModels_1.ManagedIdentityTypeForAPI.SystemAssigned;
loadtestConfig.metricsReferenceIdentityType = PayloadModels_1.ManagedIdentityTypeForAPI.SystemAssigned;
loadtestConfig.engineReferenceIdentityType = PayloadModels_1.ManagedIdentityTypeForAPI.None;
if (yamlConfig.keyVaultReferenceIdentity != undefined || yamlConfig.keyVaultReferenceIdentityType != undefined) {
loadtestConfig.keyVaultReferenceIdentityType = yamlConfig.keyVaultReferenceIdentity ? PayloadModels_1.ManagedIdentityTypeForAPI.UserAssigned : PayloadModels_1.ManagedIdentityTypeForAPI.SystemAssigned;
loadtestConfig.keyVaultReferenceIdentity = (_g = yamlConfig.keyVaultReferenceIdentity) !== null && _g !== void 0 ? _g : null;
}
if (yamlConfig.referenceIdentities != undefined) {
this.parseReferenceIdentities(loadtestConfig, yamlConfig.referenceIdentities);
}
if (yamlConfig.regionalLoadTestConfig != undefined) {
loadtestConfig.regionalLoadTestConfig = this.getMultiRegionLoadTestConfig(yamlConfig.regionalLoadTestConfig);
}
return loadtestConfig;
}
static getAutoStopCriteria(autoStopInput) {
let autoStop;
if (autoStopInput == null) {
autoStop = null;
return autoStop;
}
if (typeof autoStopInput == "string") {
if (autoStopInput == GeneralConstants_1.autoStopDisable) {
let data = {
autoStopDisabled: true,
};
autoStop = data;
}
else {
throw new Error("Invalid value, for disabling auto stop use 'autoStop: disable'");
}
}
else {
let data = {
autoStopDisabled: false,
errorRate: autoStopInput.errorPercentage,
errorRateTimeWindowInSeconds: autoStopInput.timeWindow,
maximumVirtualUsersPerEngine: autoStopInput.maximumVirtualUsersPerEngine,
};
autoStop = data;
}
return autoStop;
}
static validateAndGetYamlFilePath() {
var _a;
let yamlFilePath = (_a = CoreUtils.getInput(InputConstants.loadTestConfigFile)) !== null && _a !== void 0 ? _a : '';
if ((0, util_1.isNullOrUndefined)(yamlFilePath) || yamlFilePath == '') {
throw new Error(`The input field "${InputConstants.loadTestConfigFileLabel}" is empty. Provide the path to load test yaml file.`);
}
if (!(pathLib.extname(yamlFilePath) === ".yaml" || pathLib.extname(yamlFilePath) === ".yml")) {
throw new Error("The Load Test configuration file should be of type .yaml or .yml");
}
return yamlFilePath;
}
static readLoadtestConfigFile(yamlFilePath) {
const config = yaml.load(fs.readFileSync(yamlFilePath, 'utf8'));
let configValidation = (0, YamlValidationUtil_1.validateYamlConfig)(config);
if (!configValidation.valid) {
throw new Error(configValidation.error + ` Refer to the load test YAML syntax at https://learn.microsoft.com/azure/load-testing/reference-test-config-yaml`);
}
return config;
}
static parseFileConfiguration(loadtestConfig, yamlConfig, filePath) {
loadtestConfig.testPlan = pathLib.join(filePath, yamlConfig.testPlan);
loadtestConfig.configurationFiles = [];
if (yamlConfig.configurationFiles != undefined) {
var tempconfigFiles = [];
tempconfigFiles = yamlConfig.configurationFiles;
for (let file of tempconfigFiles) {
if (loadtestConfig.kind == TestKind_1.TestKind.URL && !Util.checkFileType(file, 'csv')) {
throw new Error("Only CSV files are allowed as configuration files for a URL-based test.");
}
file = pathLib.join(filePath, file);
loadtestConfig.configurationFiles.push(file);
}
;
}
loadtestConfig.zipArtifacts = [];
if (yamlConfig.zipArtifacts != undefined) {
var tempconfigFiles = [];
tempconfigFiles = yamlConfig.zipArtifacts;
if (loadtestConfig.kind == TestKind_1.TestKind.URL && tempconfigFiles.length > 0) {
throw new Error("Zip artifacts are not supported for the URL-based test.");
}
for (let file of tempconfigFiles) {
file = pathLib.join(filePath, file);
loadtestConfig.zipArtifacts.push(file);
}
;
}
let framework = EngineUtil.getLoadTestFrameworkModelFromKind(loadtestConfig.kind);
if (yamlConfig.properties != undefined && yamlConfig.properties.userPropertyFile != undefined) {
if (loadtestConfig.kind == TestKind_1.TestKind.URL) {
throw new Error("User property file is not supported for the URL-based test.");
}
let propFile = yamlConfig.properties.userPropertyFile;
loadtestConfig.propertyFile = pathLib.join(filePath, propFile);
if (!Util.checkFileTypes(yamlConfig.properties.userPropertyFile, framework.userPropertyFileExtensions)) {
throw new Error(`User property file with extension other than ${framework.ClientResources.userPropertyFileExtensionsFriendly} is not permitted.`);
}
}
}
static parseParameters(loadtestConfig, yamlConfig) {
loadtestConfig.secrets = {};
if (yamlConfig.secrets != undefined) {
for (let secret of yamlConfig.secrets) {
let str = `name : ${secret.name}, value : ${secret.value}`;
if ((0, util_1.isNullOrUndefined)(secret.name)) {
throw new Error(`Invalid secret name at ${str}`);
}
if (!Util.validateUrl(secret.value)) {
throw new Error(`Invalid secret url at ${str}`);
}
loadtestConfig.secrets[secret.name] = { type: 'AKV_SECRET_URI', value: secret.value };
}
}
loadtestConfig.environmentVariables = {};
if (yamlConfig.env != undefined) {
for (let env of yamlConfig.env) {
let str = `name : ${env.name}, value : ${env.value}`;
if ((0, util_1.isNullOrUndefined)(env.name)) {
throw new Error(`Invalid environment name at ${str}`);
}
loadtestConfig.environmentVariables[env.name] = env.value;
}
}
loadtestConfig.certificates = null;
if (yamlConfig.certificates != undefined) {
if (yamlConfig.certificates.length > 1) {
throw new Error(`Only one certificate can be added in the load test configuration.`);
}
if (yamlConfig.certificates.length == 1) {
let certificate = yamlConfig.certificates[0];
let str = `name : ${certificate.name}, value : ${certificate.value}`;
if ((0, util_1.isNullOrUndefined)(certificate.name)) {
throw new Error(`Invalid certificate name at ${str}`);
}
if (!Util.validateUrlcert(certificate.value)) {
throw new Error(`Invalid certificate url at ${str}`);
}
loadtestConfig.certificates = { name: certificate.name, type: 'AKV_CERT_URI', value: certificate.value };
}
}
}
static parseAppComponentsAndServerMetricsConfig(loadtestConfig, appComponents) {
var _a, _b, _c, _d, _e, _f, _g, _h;
for (let value of appComponents) {
let resourceId = value.resourceId.toLowerCase();
loadtestConfig.appComponents[resourceId] = {
resourceName: (value.resourceName || Util.getResourceNameFromResourceId(resourceId)),
kind: (_a = value.kind) !== null && _a !== void 0 ? _a : null,
resourceType: (_b = Util.getResourceTypeFromResourceId(resourceId)) !== null && _b !== void 0 ? _b : '',
resourceId: resourceId,
subscriptionId: (_c = Util.getSubscriptionIdFromResourceId(resourceId)) !== null && _c !== void 0 ? _c : '',
resourceGroup: (_d = Util.getResourceGroupFromResourceId(resourceId)) !== null && _d !== void 0 ? _d : ''
};
let metrics = ((_e = value.metrics) !== null && _e !== void 0 ? _e : []);
if (loadtestConfig.addDefaultsForAppComponents[resourceId] == undefined) {
loadtestConfig.addDefaultsForAppComponents[resourceId] = metrics.length == 0;
}
else {
// when the same resource has metrics at one place, but not at other, we dont need defaults anymore.
loadtestConfig.addDefaultsForAppComponents[resourceId] = loadtestConfig.addDefaultsForAppComponents[resourceId] && metrics.length == 0;
}
for (let serverComponent of metrics) {
let key = (resourceId + '/' + ((_f = serverComponent.namespace) !== null && _f !== void 0 ? _f : Util.getResourceTypeFromResourceId(resourceId)) + '/' + serverComponent.name).toLowerCase();
if (!loadtestConfig.serverMetricsConfig.hasOwnProperty(key) || (0, util_1.isNullOrUndefined)(loadtestConfig.serverMetricsConfig[key])) {
loadtestConfig.serverMetricsConfig[key] = {
name: serverComponent.name,
aggregation: serverComponent.aggregation,
metricNamespace: (_g = serverComponent.namespace) !== null && _g !== void 0 ? _g : Util.getResourceTypeFromResourceId(resourceId),
resourceId: resourceId,
resourceType: (_h = Util.getResourceTypeFromResourceId(resourceId)) !== null && _h !== void 0 ? _h : '',
id: key
};
}
else {
loadtestConfig.serverMetricsConfig[key].aggregation = loadtestConfig.serverMetricsConfig[key].aggregation + "," + serverComponent.aggregation;
}
}
}
}
static parseReferenceIdentities(loadtestConfig, referenceIdentities) {
let segregatedManagedIdentities = Util.validateAndGetSegregatedManagedIdentities(referenceIdentities);
loadtestConfig.keyVaultReferenceIdentity = segregatedManagedIdentities.referenceIdentityValuesUAMIMap[UtilModels_1.ReferenceIdentityKinds.KeyVault].length > 0 ? segregatedManagedIdentities.referenceIdentityValuesUAMIMap[UtilModels_1.ReferenceIdentityKinds.KeyVault][0] : null;
loadtestConfig.keyVaultReferenceIdentityType = segregatedManagedIdentities.referenceIdentityValuesUAMIMap[UtilModels_1.ReferenceIdentityKinds.KeyVault].length > 0 ? PayloadModels_1.ManagedIdentityTypeForAPI.UserAssigned : PayloadModels_1.ManagedIdentityTypeForAPI.SystemAssigned;
loadtestConfig.metricsReferenceIdentity = segregatedManagedIdentities.referenceIdentityValuesUAMIMap[UtilModels_1.ReferenceIdentityKinds.Metrics].length > 0 ? segregatedManagedIdentities.referenceIdentityValuesUAMIMap[UtilModels_1.ReferenceIdentityKinds.Metrics][0] : null;
loadtestConfig.metricsReferenceIdentityType = segregatedManagedIdentities.referenceIdentityValuesUAMIMap[UtilModels_1.ReferenceIdentityKinds.Metrics].length > 0 ? PayloadModels_1.ManagedIdentityTypeForAPI.UserAssigned : PayloadModels_1.ManagedIdentityTypeForAPI.SystemAssigned;
if (segregatedManagedIdentities.referenceIdentiesSystemAssignedCount[UtilModels_1.ReferenceIdentityKinds.Engine] > 0) {
loadtestConfig.engineReferenceIdentityType = PayloadModels_1.ManagedIdentityTypeForAPI.SystemAssigned;
}
else if (segregatedManagedIdentities.referenceIdentityValuesUAMIMap[UtilModels_1.ReferenceIdentityKinds.Engine].length > 0) {
loadtestConfig.engineReferenceIdentityType = PayloadModels_1.ManagedIdentityTypeForAPI.UserAssigned;
loadtestConfig.engineReferenceIdentities = segregatedManagedIdentities.referenceIdentityValuesUAMIMap[UtilModels_1.ReferenceIdentityKinds.Engine];
}
else {
loadtestConfig.engineReferenceIdentityType = PayloadModels_1.ManagedIdentityTypeForAPI.None;
}
}
static getMultiRegionLoadTestConfig(multiRegionalConfig) {
let parsedMultiRegionConfiguration = [];
multiRegionalConfig.forEach(regionConfig => {
let data = {
region: regionConfig.region,
engineInstances: regionConfig.engineInstances,
};
parsedMultiRegionConfiguration.push(data);
});
return parsedMultiRegionConfiguration;
}
}
exports.LoadtestConfigUtil = LoadtestConfigUtil;