Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
551 changes: 34 additions & 517 deletions lib/main.js

Large diffs are not rendered by default.

675 changes: 0 additions & 675 deletions lib/mappers.js

This file was deleted.

462 changes: 462 additions & 0 deletions lib/models/APISupport.js

Large diffs are not rendered by default.

175 changes: 175 additions & 0 deletions lib/models/AuthenticationUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
"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 () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthenticationUtils = void 0;
const util_1 = require("util");
const core = __importStar(require("@actions/core"));
const child_process_1 = require("child_process");
const UtilModels_1 = require("./UtilModels");
const jwt_decode_1 = require("jwt-decode");
class AuthenticationUtils {
constructor() {
this.dataPlanetoken = '';
this.controlPlaneToken = '';
this.subscriptionId = '';
this.env = 'AzureCloud';
this.armTokenScope = 'https://management.core.windows.net';
this.dataPlaneTokenScope = 'https://loadtest.azure-dev.com';
this.armEndpoint = 'https://management.azure.com';
this.resourceId = '';
}
authorize() {
return __awaiter(this, void 0, void 0, function* () {
// NOTE: This will set the subscription id
yield this.getTokenAPI(UtilModels_1.TokenScope.ControlPlane);
const rg = core.getInput('resourceGroup');
const ltres = core.getInput('loadTestResource');
if ((0, util_1.isNullOrUndefined)(rg) || rg == '') {
throw new Error(`The input field "resourceGroup" is empty. Provide an existing resource group name.`);
}
if ((0, util_1.isNullOrUndefined)(ltres) || ltres == '') {
throw new Error(`The input field "loadTestResource" is empty. Provide an existing load test resource name.`);
}
this.resourceId = "/subscriptions/" + this.subscriptionId + "/resourcegroups/" + rg + "/providers/microsoft.loadtestservice/loadtests/" + ltres;
yield this.setEndpointAndScope();
});
}
setEndpointAndScope() {
return __awaiter(this, void 0, void 0, function* () {
try {
const cmdArguments = ["cloud", "show"];
var result = yield this.execAz(cmdArguments);
let env = result ? result.name : null;
this.env = env ? env : this.env;
let endpointUrl = (result && result.endpoints) ? result.endpoints.resourceManager : null;
this.armEndpoint = endpointUrl ? endpointUrl : this.armEndpoint;
if (this.env == 'AzureUSGovernment') {
this.dataPlaneTokenScope = 'https://cnt-prod.loadtesting.azure.us';
this.armTokenScope = 'https://management.usgovcloudapi.net';
}
}
catch (err) {
const message = `An error occurred while getting credentials from ` +
`Azure CLI for setting endPoint and scope: ${err.message}`;
throw new Error(message);
}
});
}
getTokenAPI(scope) {
return __awaiter(this, void 0, void 0, function* () {
let tokenScopeDecoded = scope == UtilModels_1.TokenScope.Dataplane ? this.dataPlaneTokenScope : this.armTokenScope;
try {
const cmdArguments = ["account", "get-access-token", "--resource"];
cmdArguments.push(tokenScopeDecoded);
var result = yield this.execAz(cmdArguments);
let token = result.accessToken;
// NOTE: Setting the subscription id
this.subscriptionId = result.subscription;
scope == UtilModels_1.TokenScope.ControlPlane ? this.controlPlaneToken = token : this.dataPlanetoken = token;
return token;
}
catch (err) {
const message = `An error occurred while getting credentials from ` + `Azure CLI: ${err.message}`;
throw new Error(message);
}
});
}
execAz(cmdArguments) {
return __awaiter(this, void 0, void 0, function* () {
const azCmd = process.platform === "win32" ? "az.cmd" : "az";
return new Promise((resolve, reject) => {
(0, child_process_1.execFile)(azCmd, [...cmdArguments, "--out", "json"], { encoding: "utf8", shell: true }, (error, stdout) => {
if (error) {
return reject(error);
}
try {
return resolve(JSON.parse(stdout));
}
catch (err) {
const msg = `An error occurred while parsing the output "${stdout}", of ` +
`the cmd az "${cmdArguments}": ${err.message}.`;
return reject(new Error(msg));
}
});
});
});
}
isValid(scope) {
let token = scope == UtilModels_1.TokenScope.Dataplane ? this.dataPlanetoken : this.controlPlaneToken;
try {
let header = token && (0, jwt_decode_1.jwtDecode)(token);
const now = Math.floor(Date.now() / 1000);
return (header && (header === null || header === void 0 ? void 0 : header.exp) && header.exp + 2 > now);
}
catch (error) {
console.log("Error in getting the token");
}
}
getDataPlaneHeader(apicallType) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
if (!this.isValid(UtilModels_1.TokenScope.Dataplane)) {
let tokenRes = yield this.getTokenAPI(UtilModels_1.TokenScope.Dataplane);
this.dataPlanetoken = tokenRes;
}
let headers = {
'content-type': (_a = UtilModels_1.ContentTypeMap[apicallType]) !== null && _a !== void 0 ? _a : 'application/json',
'Authorization': 'Bearer ' + this.dataPlanetoken
};
return headers;
});
}
armTokenHeader() {
return __awaiter(this, void 0, void 0, function* () {
// right now only get calls from the GH, so no need of content type for now for the get calls.
var tokenRes = yield this.getTokenAPI(UtilModels_1.TokenScope.ControlPlane);
this.controlPlaneToken = tokenRes;
let headers = {
'Authorization': 'Bearer ' + this.controlPlaneToken,
};
return headers;
});
}
}
exports.AuthenticationUtils = AuthenticationUtils;
95 changes: 95 additions & 0 deletions lib/models/FetchHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"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 () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.httpClientRetries = httpClientRetries;
const util_1 = require("./util");
const UtilModels_1 = require("./UtilModels");
const httpc = __importStar(require("typed-rest-client/HttpClient"));
const FileUtils_1 = require("./FileUtils");
const httpClient = new httpc.HttpClient('MALT-GHACTION');
const core = __importStar(require("@actions/core"));
// (note mohit): shift to the enum later.
function httpClientRetries(urlSuffix_1, header_1, method_1) {
return __awaiter(this, arguments, void 0, function* (urlSuffix, header, method, retries = 1, data, isUploadCall = true, log = true) {
let httpResponse;
try {
let correlationId = `gh-actions-${(0, util_1.getUniqueId)()}`;
header[UtilModels_1.correlationHeader] = correlationId; // even if we put console.debug its printing along with the logs, so lets just go ahead with the differentiation with azdo, so we can search the timeframe for azdo in correlationid and resource filter.
if (method == 'get') {
httpResponse = yield httpClient.get(urlSuffix, header);
}
else if (method == 'del') {
httpResponse = yield httpClient.del(urlSuffix, header);
}
else if (method == 'put' && isUploadCall) {
let fileContent = (0, FileUtils_1.uploadFileData)(data);
httpResponse = yield httpClient.request(method, urlSuffix, fileContent, header);
}
else {
httpResponse = yield httpClient.request(method, urlSuffix, data, header);
}
if (httpResponse.message.statusCode != undefined && httpResponse.message.statusCode >= 300) {
core.debug(`correlation id : ${correlationId}`);
}
if (httpResponse.message.statusCode != undefined && [408, 429, 502, 503, 504].includes(httpResponse.message.statusCode)) {
let err = yield (0, util_1.getResultObj)(httpResponse);
throw { message: (err && err.error && err.error.message) ? err.error.message : (0, util_1.ErrorCorrection)(httpResponse) }; // throwing as message to catch it as err.message
}
return httpResponse;
}
catch (err) {
if (retries) {
let sleeptime = (5 - retries) * 1000 + Math.floor(Math.random() * 5001);
if (log) {
console.log(`Failed to connect to ${urlSuffix} due to ${err.message}, retrying in ${sleeptime / 1000} seconds`);
}
yield (0, util_1.sleep)(sleeptime);
return yield httpClientRetries(urlSuffix, header, method, retries - 1, data);
}
else {
throw new Error(`Operation did not succeed after 3 retries. Pipeline failed with error : ${err.message}`);
}
}
});
}
106 changes: 106 additions & 0 deletions lib/models/FileUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"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 () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.uploadFileToResultsFolder = uploadFileToResultsFolder;
exports.deleteFile = deleteFile;
exports.uploadFileData = uploadFileData;
const path_1 = __importDefault(require("path"));
const UtilModels_1 = require("./UtilModels");
const fs = __importStar(require("fs"));
const stream_1 = require("stream");
function uploadFileToResultsFolder(response_1) {
return __awaiter(this, arguments, void 0, function* (response, fileName = UtilModels_1.resultZipFileName) {
try {
const filePath = path_1.default.join(UtilModels_1.resultFolder, fileName);
const file = fs.createWriteStream(filePath);
return new Promise((resolve, reject) => {
file.on("error", (err) => reject(err));
const stream = response.message.pipe(file);
stream.on("close", () => {
try {
resolve(filePath);
}
catch (err) {
reject(err);
}
});
});
}
catch (err) {
err.message = "Error in fetching the results of the testRun";
throw new Error(err);
}
});
}
function deleteFile(foldername) {
if (fs.existsSync(foldername)) {
fs.readdirSync(foldername).forEach((file, index) => {
const curPath = path_1.default.join(foldername, file);
if (fs.lstatSync(curPath).isDirectory()) {
deleteFile(curPath);
}
else {
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(foldername);
}
}
function uploadFileData(filepath) {
try {
let filedata = fs.readFileSync(filepath);
const readable = new stream_1.Readable();
readable._read = () => { };
readable.push(filedata);
readable.push(null);
return readable;
}
catch (err) {
err.message = "File not found " + filepath;
throw new Error(err.message);
}
}
15 changes: 15 additions & 0 deletions lib/models/PayloadModels.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CertificateMetadata = void 0;
class CertificateMetadata {
}
exports.CertificateMetadata = CertificateMetadata;
;
;
;
;
;
;
;
;
;
Loading
Loading