1 | 'use strict'
|
2 |
|
3 | const co = require('co')
|
4 | const cli = require('heroku-cli-util')
|
5 |
|
6 | function * run (context, heroku) {
|
7 | const url = require('url')
|
8 | const util = require('../lib/util')
|
9 | const host = require('../lib/host')
|
10 | const pgbackups = require('../lib/pgbackups')(context, heroku)
|
11 | const fetcher = require('../lib/fetcher')(heroku)
|
12 | const {app, args, flags} = context
|
13 | const interval = Math.max(3, parseInt(flags['wait-interval'])) || 3
|
14 |
|
15 | let resolve = co.wrap(function * (db) {
|
16 | if (db.match(/^postgres:\/\//)) {
|
17 | let uri = url.parse(db)
|
18 | let name = uri.path ? uri.path.slice(1) : ''
|
19 | let hostname = `${uri.host}:${uri.port || 5432}`
|
20 | return {
|
21 | name: name ? `database ${name} on ${hostname}` : `database on ${hostname}`,
|
22 | url: db,
|
23 | confirm: name || uri.host
|
24 | }
|
25 | } else {
|
26 | let attachment = yield fetcher.attachment(app, db)
|
27 | if (!attachment) throw new Error(`${db} not found on ${cli.color.app(app)}`)
|
28 | let [addon, config] = yield [
|
29 | heroku.get(`/addons/${attachment.addon.name}`),
|
30 | heroku.get(`/apps/${attachment.addon.app.name}/config-vars`)
|
31 | ]
|
32 | attachment.addon = addon
|
33 | return {
|
34 | name: attachment.name.replace(/^HEROKU_POSTGRESQL_/, '').replace(/_URL$/, ''),
|
35 | url: config[util.getUrl(addon.config_vars)],
|
36 | attachment,
|
37 | confirm: app
|
38 | }
|
39 | }
|
40 | })
|
41 |
|
42 | let [source, target] = yield [resolve(args.source), resolve(args.target)]
|
43 | if (source.url === target.url) throw new Error('Cannot copy database onto itself')
|
44 |
|
45 | yield cli.confirmApp(target.confirm, flags.confirm, `WARNING: Destructive action
|
46 | This command will remove all data from ${cli.color.yellow(target.name)}
|
47 | Data from ${cli.color.yellow(source.name)} will then be transferred to ${cli.color.yellow(target.name)}`)
|
48 |
|
49 | let copy
|
50 | let attachment
|
51 | yield cli.action(`Starting copy of ${cli.color.yellow(source.name)} to ${cli.color.yellow(target.name)}`, co(function * () {
|
52 | attachment = target.attachment || source.attachment
|
53 | if (!attachment) throw new Error('Heroku PostgreSQL database must be source or target')
|
54 | copy = yield heroku.post(`/client/v11/databases/${attachment.addon.id}/transfers`, {
|
55 | body: {
|
56 | from_name: source.name,
|
57 | from_url: source.url,
|
58 | to_name: target.name,
|
59 | to_url: target.url
|
60 | },
|
61 | host: host(attachment.addon)
|
62 | })
|
63 | }))
|
64 | yield pgbackups.wait('Copying', copy.uuid, interval, flags.verbose, attachment.addon.app.name)
|
65 | }
|
66 |
|
67 | module.exports = {
|
68 | topic: 'pg',
|
69 | command: 'copy',
|
70 | needsApp: true,
|
71 | needsAuth: true,
|
72 | description: 'copy all data from source db to target',
|
73 | help: 'at least one of the databases must be a Heroku PostgreSQL DB',
|
74 | args: [
|
75 | {name: 'source'},
|
76 | {name: 'target'}
|
77 | ],
|
78 | flags: [
|
79 | {name: 'wait-interval', hasValue: true},
|
80 | {name: 'verbose'},
|
81 | {name: 'confirm', hasValue: true}
|
82 | ],
|
83 | run: cli.command({preauth: true}, co.wrap(run))
|
84 | }
|