Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat 46 email sendgrid refactor #47

Merged
merged 33 commits into from Feb 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
f5105d3
fix 44
Dec 16, 2021
a6718a8
cleanup
florentinvintila Dec 17, 2021
0dc30d4
cleanup
florentinvintila Dec 17, 2021
4fdd8a6
removed selfsign certificate check
florentinvintila Dec 17, 2021
406f1a1
changes done as per feedback
florentinvintila Jan 19, 2022
43a3a8b
small fix
florentinvintila Jan 19, 2022
a35aef7
workaround fix for node 14, < 15
florentinvintila Jan 20, 2022
adb3101
added libs folder to dockerfile
florentinvintila Jan 20, 2022
eacfd40
small fix
florentinvintila Jan 20, 2022
69fe5e3
fix for headers
florentinvintila Jan 20, 2022
1541197
added logs + small refactoring
florentinvintila Jan 21, 2022
4856aed
new logs
florentinvintila Jan 21, 2022
b8abbee
fix + docker local
florentinvintila Jan 21, 2022
8885f7d
reject all other than 2xx
florentinvintila Jan 21, 2022
054290d
forgot to push
florentinvintila Jan 21, 2022
fa5fc05
regex fail
florentinvintila Jan 21, 2022
6be4532
added input validations
florentinvintila Jan 25, 2022
7f34435
fix typo + package update
florentinvintila Jan 26, 2022
58394a6
force defaults for inputs
florentinvintila Jan 26, 2022
1e598aa
started refactoring
florentinvintila Jan 27, 2022
2fd247d
#46 finished changes for sendEmailWithSendgrid
florentinvintila Jan 31, 2022
60b0624
refactor
florentinvintila Feb 3, 2022
c59567f
#46 fixed package-lock
florentinvintila Feb 3, 2022
381e23e
Merge pull request #45 from boomerang-io/fix-44-http-retry
morarucostel Feb 3, 2022
f590451
49-fix-http-task-headers-split
florentinvintila Feb 17, 2022
1005fd6
#46 changes as per request
florentinvintila Feb 17, 2022
978edf5
Merge pull request #50 from boomerang-io/49-fix-http-task-headers-split
morarucostel Feb 17, 2022
c04ebca
started refactoring
florentinvintila Jan 27, 2022
38a18e4
#46 finished changes for sendEmailWithSendgrid
florentinvintila Jan 31, 2022
424bfe8
merge 1
florentinvintila Feb 17, 2022
e76ab88
#46 fixed package-lock
florentinvintila Feb 17, 2022
c0fcd96
#46 changes as per request
florentinvintila Feb 17, 2022
168a30d
Merge branch 'feat-46-email-sendgrid-refactor' of https://github.com/…
florentinvintila Feb 17, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions Dockerfile
Expand Up @@ -9,6 +9,7 @@ RUN apk add --no-cache bash sed grep curl coreutils nodejs npm
WORKDIR /cli
ADD ./package.json ./package-lock.json ./
ADD ./commands ./commands
ADD ./libs ./libs
RUN npm install --production

ENTRYPOINT [ "npm", "start" ]
12 changes: 12 additions & 0 deletions README.md
Expand Up @@ -46,6 +46,18 @@ Under the `props` folder, you can set input variables:

These files are designed to replicate the properties that would be mounted in confimaps by the controller service.

### Development guide

#### **Utilities file / functions** [libs/utilities.js](./libs/utilities.js)

**_Descriptions_**: This file contains utility functions that are to be used/reused in other tasks to offer the developer a faster way to check for missing parameters, display missing parameters, unset parameters, removal of specific properties from objects, etc.
**_Functions_**

- _checkIfEmpty_: Check if param is set or not, in case of mandatory inputs;
- _unsetField_: Removes every property from object, with the name 'fieldName';
- _checkParameters_: Validates all attributes of the supplied object. Returns true if all parameters are valid;
- _checkForJson_: Try to check if valid JSON and convert it to JS Object.

## Packaging

### Automatic
Expand Down
127 changes: 86 additions & 41 deletions commands/http.js
@@ -1,8 +1,9 @@
const { log, utils } = require("@boomerang-io/worker-core");
const HttpsProxyAgent = require("https-proxy-agent");
const https = require("https");
const Url = require("url");
const URL = require("url");
const fs = require("fs");
const HTTPRetryRequest = require("../libs/HTTPRetryRequest");

module.exports = {
/**
Expand All @@ -12,15 +13,52 @@ module.exports = {
* headers [Text Area - new line delimitered list?]
* content type [Select - Options: any, text, xml, json, html]
* body [Text Area - optional depending on method]
* @param {string} errorcodes Represents a list of HTTP Status Codes, used either for error or success checks
* @param {string} isErrorCodes Represents if the `errorcodes` param is used as failure (true) or success (false)
* @param {int} httperrorretry Represents the number of retries that will be perfomed until success is obtained or the number of retries is achived
* @param {int} httpRetryDelay Represents the number of miliseconds that will delay the next retry
* Allow untrusted SSL certs [Boolean Toggle]
*/

execute() {
log.debug("Started HTTP Call Plugin");

//Destructure and get properties ready.
const taskProps = utils.resolveInputParameters();
const { url, method, header, contentType, body, allowUntrustedCerts, outputFilePath } = taskProps;

const { url, method, header, contentType, body, allowUntrustedCerts, outputFilePath, errorcodes = "", isErrorCodes = "failure", httperrorretry = 0, httpRetryDelay = 200 } = taskProps;

// Input force defaults
let newisErrorCodes = "failure";
let newhttperrorretry = 0;
let newhttpRetryDelay = 200;
// Input not "empty", set value
if (typeof isErrorCodes === "string" && isErrorCodes !== '""' && isErrorCodes !== '" "' && isErrorCodes !== "") {
newisErrorCodes = isErrorCodes.trim().toLowerCase(); // Input normalization
}
if (httperrorretry !== '""' && httperrorretry !== '" "' && httperrorretry !== "") {
newhttperrorretry = parseInt(httperrorretry, 10);
if (isNaN(newhttperrorretry)) {
log.err("Invalid input for: httperrorretry");
process.exit(1);
}
if (newhttperrorretry < 0 || newhttperrorretry > 10) {
log.err("Invalid input for: httperrorretry [0,10]");
process.exit(1);
}
}
if (httpRetryDelay !== '""' && httpRetryDelay !== '" "' && httpRetryDelay !== "") {
newhttpRetryDelay = parseInt(httpRetryDelay, 10);
// parse test
if (isNaN(newhttpRetryDelay)) {
log.err("Invalid input for: httpRetryDelay");
process.exit(1);
}
// bounds exceeded
if (newhttpRetryDelay < 100 || newhttpRetryDelay > 30000) {
log.err("Invalid input for: httpRetryDelay [100,30000]");
process.exit(1);
}
}

/**
* turn header into object based upon new line delimeters
Expand All @@ -31,9 +69,18 @@ module.exports = {
let headerSplitArr = header.split("\n");
log.debug(headerSplitArr);
headerSplitArr.forEach(line => {
let key = line.substring(0, line.indexOf(":"));
let value = line.substring(line.indexOf(":") + 1).trim();
headerObject[key] = value;
let arrHearder = line.split(":");
if (arrHearder && arrHearder.length) {
let key = arrHearder
.shift()
.trim()
.replace(/("|')/g, ""); //take first string, the header
let value = arrHearder
.join(":")
.trim()
.replace(/("|')/g, ""); //rejoin all strings
headerObject[key] = value;
}
});
}

Expand All @@ -56,7 +103,7 @@ module.exports = {
} else {
log.debug("NO_PROXY list detected", process.env.NO_PROXY);
const noProxyList = process.env.NO_PROXY.split(",");
let urltoUrl = new Url.URL(url);
let urltoUrl = new URL(url);
let urlHost = urltoUrl.host.split(":")[0];
log.debug("urlHost:", urlHost);
const skipProxy = noProxyList.some(domain => {
Expand All @@ -81,65 +128,63 @@ module.exports = {
allowUntrustedFlag = true;
}

const opts = Url.parse(url);
const reqURL = new URL.URL(url);
let opts = {};
opts.rejectUnauthorized = !allowUntrustedFlag;
opts.agent = agent;
opts.method = method;
opts.headers = {
...headerObject
};

log.sys("Commencing to execute HTTP call with", opts);
log.sys("Commencing to execute HTTP call with", reqURL, JSON.stringify(opts));

const req = https.request(opts, res => {
log.debug(`statusCode: ${res.statusCode}`);
utils.setOutputParameter("statusCode", JSON.stringify(res.statusCode));
let output = "";

res.on("data", d => {
output += d;
});
let config = {
ERROR_CODES: errorcodes,
MAX_RETRIES: newhttperrorretry,
DELAY: newhttpRetryDelay,
IS_ERROR: newisErrorCodes === "failure"
};
if (body && body !== "" && body !== '""' && body !== '" "') {
log.debug("writing request body");
config.body = body;
}

res.on("end", () => {
new HTTPRetryRequest(config, reqURL, opts)
.then(res => {
log.debug(`statusCode: ${res.statusCode}`);
utils.setOutputParameter("statusCode", JSON.stringify(res.statusCode));
try {
log.debug(`output: ${output}`);
log.debug(`output: ${res.body.toString()}`);
//make sure non-empty output is a valid JSON,
//if not throw exception
if (!(output === null || output.match(/^ *$/) !== null)) {
JSON.parse(output);
if (!(res.body === null || res.body.toString().match(/^ *$/) !== null)) {
JSON.parse(res.body.toString());
}
log.sys("Response Received:", res.body.toString());
} catch (e) {
log.err(e);
process.exit(1);
}
log.sys("Response Received:", output);
if (outputFilePath && outputFilePath.length && outputFilePath !== '""' && outputFilePath !== '" "') {
fs.writeFileSync(outputFilePath, output, err => {
if (err) {
log.err(err);
throw err;
}
log.debug("The task output parameter successfully saved to provided file path.");
//https://nodejs.org/docs/latest-v14.x/api/fs.html#fs_fs_writefilesync_file_data_options
fs.writeFileSync(outputFilePath, res.body, {
encoding: "utf8",
mode: 666,
flag: "w"
});
log.debug("The task output parameter successfully saved to provided file path.");
} else {
utils.setOutputParameter("response", output);
utils.setOutputParameter("response", res.body.toString());
log.debug("The task output parameter successfully saved to standard response file.");
}
log.good("Response successfully received!");
})
.catch(err => {
log.err("HTTP Promise error:", err);
process.exit(1);
});
});

req.on("error", err => {
log.err(err);
process.exit(1);
});

if (body && body !== "" && body !== '""' && body !== '" "') {
log.debug("writing request body");
req.write(body);
}

req.end();
log.debug("Finished HTTP Call File Plugin");
}
};