Skip to content

Instantly share code, notes, and snippets.

@sethetter
Created December 6, 2017 01:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sethetter/00ca4cdf3c5e10a7ed28b95ce462aad9 to your computer and use it in GitHub Desktop.
Save sethetter/00ca4cdf3c5e10a7ed28b95ce462aad9 to your computer and use it in GitHub Desktop.
const url = require('url')
const qs = require('querystring')
const path = require('path')
const fs = require('fs')
const { createServer } = require('http')
const { exec } = require('child_process')
const envFile = fs.readFileSync(path.resolve(__dirname, 'dbctl.env'), { encoding: 'utf8' })
envFile.split('\\n').forEach(pair => {
const [key, val] = pair.split('=')
if (key && val) process.env[key] = val
})
const execCmd = (cmd, env) => new Promise((resolve, reject) => {
exec(cmd, {env: process.env}, (err, stdout, stderr) => {
return err ? reject(err) : resolve([stdout, stderr])
})
})
const bucket = process.env.BACKUPS_BUCKET_URL
const controller = {
dump: (req, res) => {
const timestamp = Date.now()
const filename = timestamp + '.dump.sql'
return execCmd('pg_dump -f /tmp/' + filename)
.then(() => execCmd('aws s3 cp /tmp/' + filename + ' ' + bucket + '/' + filename))
.then(() => execCmd('rm /tmp/' + filename))
.then(() => res.end(bucket + '/' + filename))
.catch(e => errResponse(e, res))
},
pull: (req, res) => {
const timestamp = qs.parse(req.url.query).timestamp
if (!timestamp) throw new Error('No timestamp provided')
const filename = timestamp + '.dump.sql'
return execCmd('aws s3 cp ' + bucket + '/' + filename + ' /tmp/' + filename)
.then(() => {
fs.readFile('/tmp/' + filename, (err, file) => {
if (err) throw err
return execCmd('rm /tmp/' + filename)
.then(() => res.end(file))
})
})
.catch(e => errResponse(e, res))
},
restore: (req, res) => {
const timestamp = qs.parse(req.url.query).timestamp
if (!timestamp) throw new Error('No timestamp provided')
const filename = timestamp + '.dump.sql'
return execCmd('aws s3 cp ' + bucket + '/' + filename + ' /tmp/' + filename)
.then(() => execCmd('psql < /tmp/' + filename))
.then(([stdout]) => {
return execCmd('rm /tmp/' + filename)
.then(() => res.end(stdout))
})
.catch(e => errResponse(e, res))
}
}
const errResponse = (err, res) => {
console.error(err)
res.statusCode = 500
res.end(err.message || 'Server error')
}
createServer((req, res) => {
req.url = url.parse(req.url)
try {
switch (req.url.pathname) {
case '/dump': return controller.dump(req, res)
case '/pull': return controller.pull(req, res)
case '/restore': return controller.restore(req, res)
default: return res.end('Invalid route')
}
} catch(e) {
return errResponse(e, res)
}
}).listen(3333)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment