-
Notifications
You must be signed in to change notification settings - Fork 153
/
copy-db.js
147 lines (121 loc) · 4.19 KB
/
copy-db.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
const fs = require("fs");
const { execSync } = require(`child_process`);
const deleteDatabase = process.argv.includes(`--delete`);
const silent = { stdio: [`ignore`, `ignore`, `ignore`] };
const PROD_APP = `foundation-mozilla-org`;
const STAGE_APP = `foundation-mofostaging-net`;
const APP = process.argv.includes(`--prod`) ? PROD_APP : STAGE_APP;
if (APP === STAGE_APP) {
console.log(
`Running db copy for staging, run with --prod to run for production`
);
}
if (!isLoggedInToHeroku()) {
console.log(
"You are not logged into Heroku. Make sure you have the Heroku CLI installed. Run `heroku login` and try again."
);
process.exit(1);
}
const HEROKU_OUTPUT = run(`heroku config:get DATABASE_URL -a ${APP}`);
const HEROKU_TEXT = HEROKU_OUTPUT.toString().replaceAll(`\n`, ` `);
const URL_START = HEROKU_TEXT.indexOf(`postgres://`);
const DATABASE_URL = HEROKU_TEXT.substring(URL_START).trim();
const ROLE = DATABASE_URL.match(/postgres:\/\/([^:]+):/)[1];
const DUMP_FILE = `${ROLE}.db.archive`;
const DB_FLAGS = `-hpostgres -Ufoundation`;
/**
* Exec a command and return its output as plain string
*/
function run(cmd, ignoreThrows = false, opts = {}) {
try {
return execSync(cmd, opts).toString();
} catch (e) {
if (ignoreThrows) return e.toString();
process.exit(1);
}
}
/**
* Run a command in the postgres docker container
*/
function postgres(cmd, ignoreThrows = false) {
cmd = `docker exec ${IMAGE_NAMES.POSTGRES} ${cmd}`;
return run(cmd, ignoreThrows);
}
function getContainerNames() {
return run(`docker ps`)
.split(`\n`)
.map((v) => v.match(/\s(\S+)$/g))
.filter(Boolean)
.map((v) => v[0].trim())
.reduce((a, v) => {
if (!v) return a;
if (v.includes(`backend`)) a.BACKEND = v;
if (v.includes(`postgres`)) a.POSTGRES = v;
return a;
}, {});
}
function stopContainers() {
const IMAGE_NAMES = getContainerNames();
const backend = IMAGE_NAMES.BACKEND;
if (backend) {
console.log(`Stopping ${backend}`);
run(`docker stop ${backend}`, true, silent);
}
const postgres = IMAGE_NAMES.POSTGRES;
if (postgres) {
console.log(`Stopping ${postgres}`);
run(`docker stop ${postgres}`, true, silent);
}
}
function isLoggedInToHeroku() {
try {
execSync("heroku whoami");
return true;
} catch (error) {
return false;
}
}
// ======================== //
// Our script starts here //
// ======================== //
console.log(`Making sure no docker containers are running...`);
stopContainers();
console.log(`Starting postgres docker image...`);
run(`docker-compose up -d postgres`, true, silent);
console.log(`Starting backend docker image...`);
run(`docker-compose up -d backend`, true, silent);
console.log(`Getting running image names...`);
const IMAGE_NAMES = getContainerNames();
if (!fs.existsSync(DUMP_FILE)) {
console.log(`Downloading ${APP} database (this may take a while)...`);
postgres(`pg_dump -F c ${DATABASE_URL} > ${DUMP_FILE}`);
} else {
console.log(`Found local ${APP} database file, skipping download...`);
}
console.log(`Resetting db...`);
postgres(`dropdb ${DB_FLAGS} --if-exists wagtail --force`);
postgres(`createdb ${DB_FLAGS} wagtail`);
console.log(`Building user roles...`);
[ROLE, `datastudio`, `datagrip-cade`].forEach((role) =>
postgres(`createuser ${DB_FLAGS} -s ${role}`, true)
);
console.log(`Importing database snapshot...`);
run(`docker cp ${DUMP_FILE} ${IMAGE_NAMES.POSTGRES}:/`);
// Based on the Heroku docs for restoring to local database:
// https://devcenter.heroku.com/articles/heroku-postgres-import-export#restore-to-local-database
postgres(`pg_restore ${DB_FLAGS} -dwagtail --no-acl --no-owner ${DUMP_FILE}`);
console.log(`Updating site bindings...`);
run(`inv manage fix_local_site_bindings`, true, silent);
console.log(`Creating admin:admin superuser account...`);
run(`inv createsuperuser`, true, silent);
console.log(`Migrating database to match current branch migrations...`);
run(
`docker exec ${IMAGE_NAMES.BACKEND} ./dockerpythonvenv/bin/python network-api/manage.py migrate`
);
console.log(`Stopping docker images...`);
run(`docker-compose down`, true, silent);
if (deleteDatabase) {
console.log(`Running cleanup`);
fs.unlinkSync(DUMP_FILE);
}
console.log(`All done.`);