update redis addon to use pipeline+http api
This commit is contained in:
+57
-28
@@ -1,5 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const { pipeline } = require('stream');
|
||||
|
||||
exports = module.exports = {
|
||||
listServices,
|
||||
getServiceStatus,
|
||||
@@ -43,6 +45,7 @@ const addonConfigs = require('./addonconfigs.js'),
|
||||
eventlog = require('./eventlog.js'),
|
||||
fs = require('fs'),
|
||||
hat = require('./hat.js'),
|
||||
http = require('http'),
|
||||
infra = require('./infra_version.js'),
|
||||
mail = require('./mail.js'),
|
||||
once = require('once'),
|
||||
@@ -590,7 +593,12 @@ async function waitForContainer(containerName, tokenEnvName) {
|
||||
const result = await getContainerDetails(containerName, tokenEnvName);
|
||||
|
||||
await promiseRetry({ times: 10, interval: 15000, debug }, async () => {
|
||||
const [networkError, response] = await safe(superagent.get(`https://${result.ip}:3000/healthcheck?access_token=${result.token}`)
|
||||
// temporary workaround till we move all containers to http
|
||||
const url = containerName.includes('redis')
|
||||
? `http://${result.ip}:3000/healthcheck?access_token=${result.token}`
|
||||
: `https://${result.ip}:3000/healthcheck?access_token=${result.token}`;
|
||||
|
||||
const [networkError, response] = await safe(superagent.get(url)
|
||||
.timeout(5000)
|
||||
.disableTLSCerts()
|
||||
.ok(() => true));
|
||||
@@ -1266,6 +1274,51 @@ async function pipeRequestToFile(url, filename) {
|
||||
});
|
||||
}
|
||||
|
||||
async function pipeRequestToFile2(url, filename) {
|
||||
assert.strictEqual(typeof url, 'string');
|
||||
assert.strictEqual(typeof filename, 'string');
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const writeStream = fs.createWriteStream(filename);
|
||||
const request = http.request(url, { method: 'POST' }); // ClientRequest
|
||||
request.setTimeout(60000, () => request.destroy(new Error('Request timedout'))); // connect OR post-connect idle timeout
|
||||
|
||||
request.on('error', (error) => reject(new BoxError(BoxError.NETWORK_ERROR, `Could not pipe ${url} to ${filename}: ${error.message}`))); // network error, dns error
|
||||
request.on('response', (response) => {
|
||||
if (response.statusCode !== 200) return reject(new BoxError(BoxError.ADDONS_ERROR, `Unexpected response code or HTTP error when piping ${url} to ${filename}: status ${response.statusCode}`));
|
||||
|
||||
pipeline(response, writeStream, (error) => {
|
||||
if (error) return reject(new BoxError(BoxError.ADDONS_ERROR, `Error piping ${url} to ${filename}: ${error.message}`));
|
||||
|
||||
if (!response.complete) return reject(new BoxError(BoxError.ADDONS_ERROR, `Response not complete when piping ${url} to ${filename}`));
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
request.end(); // make the request
|
||||
});
|
||||
}
|
||||
|
||||
async function pipeFileToRequest(filename, url) {
|
||||
assert.strictEqual(typeof filename, 'string');
|
||||
assert.strictEqual(typeof url, 'string');
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const readStream = fs.createReadStream(filename);
|
||||
const request = http.request(url, { method: 'POST' }); // ClientRequest
|
||||
request.setTimeout(60000, () => request.destroy(new Error('Request timedout'))); // connect OR post-connect idle timeout
|
||||
request.on('response', (response) => {
|
||||
response.resume(); // drain the response
|
||||
if (response.statusCode !== 200) return reject(new BoxError(BoxError.ADDONS_ERROR, `Unexpected response code or HTTP error when piping ${filename} to ${url}: status ${response.statusCode} complete ${response.complete}`));
|
||||
|
||||
resolve();
|
||||
});
|
||||
|
||||
pipeline(readStream, request, function (error) {
|
||||
if (error) return reject(new BoxError(BoxError.ADDONS_ERROR, `Error piping file ${filename} to request ${url}`));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function backupMySql(app, options) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
@@ -1800,8 +1853,7 @@ async function clearRedis(app, options) {
|
||||
|
||||
const result = await getContainerDetails('redis-' + app.id, 'CLOUDRON_REDIS_TOKEN');
|
||||
|
||||
const [networkError, response] = await safe(superagent.post(`https://${result.ip}:3000/clear?access_token=${result.token}`)
|
||||
.disableTLSCerts()
|
||||
const [networkError, response] = await safe(superagent.post(`http://${result.ip}:3000/clear?access_token=${result.token}`)
|
||||
.ok(() => true));
|
||||
|
||||
if (networkError) throw new BoxError(BoxError.ADDONS_ERROR, `Network error clearing redis: ${networkError.message}`);
|
||||
@@ -1830,9 +1882,7 @@ async function backupRedis(app, options) {
|
||||
debug('Backing up redis');
|
||||
|
||||
const result = await getContainerDetails('redis-' + app.id, 'CLOUDRON_REDIS_TOKEN');
|
||||
|
||||
const url = `https://${result.ip}:3000/backup?access_token=${result.token}`;
|
||||
await pipeRequestToFile(url, dumpPath('redis', app.id));
|
||||
await pipeRequestToFile2(`http://${result.ip}:3000/backup?access_token=${result.token}`, dumpPath('redis', app.id));
|
||||
}
|
||||
|
||||
async function restoreRedis(app, options) {
|
||||
@@ -1842,28 +1892,7 @@ async function restoreRedis(app, options) {
|
||||
debug('Restoring redis');
|
||||
|
||||
const result = await getContainerDetails('redis-' + app.id, 'CLOUDRON_REDIS_TOKEN');
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
reject = once(reject); // protect from multiple returns with streams
|
||||
|
||||
let input;
|
||||
const newDumpLocation = dumpPath('redis', app.id);
|
||||
if (fs.existsSync(newDumpLocation)) {
|
||||
input = fs.createReadStream(newDumpLocation);
|
||||
} else { // old location of dumps
|
||||
input = fs.createReadStream(path.join(paths.APPS_DATA_DIR, app.id, 'redis/dump.rdb'));
|
||||
}
|
||||
input.on('error', (error) => reject(new BoxError(BoxError.FS_ERROR, `Error reading input stream when restoring redis: ${error.message}`)));
|
||||
|
||||
const restoreReq = request.post(`https://${result.ip}:3000/restore?access_token=${result.token}`, { json: true, rejectUnauthorized: false }, function (error, response) {
|
||||
if (error) return reject(new BoxError(BoxError.ADDONS_ERROR, `Error restoring redis: ${error.message}`));
|
||||
if (response.statusCode !== 200) return reject(new BoxError(BoxError.ADDONS_ERROR, `Error restoring redis. Status code: ${response.statusCode} message: ${response.body.message}`));
|
||||
|
||||
resolve();
|
||||
});
|
||||
|
||||
input.pipe(restoreReq);
|
||||
});
|
||||
await pipeFileToRequest(dumpPath('redis', app.id), `http://${result.ip}:3000/restore?access_token=${result.token}`);
|
||||
}
|
||||
|
||||
async function statusTurn() {
|
||||
|
||||
Reference in New Issue
Block a user