Skip to content

Commit b462936

Browse files
authored
Local mailing list db import (boostorg#1844)
1 parent 0c4efe2 commit b462936

File tree

3 files changed

+129
-22
lines changed

3 files changed

+129
-22
lines changed

env.template

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,7 @@ DEBUG_TOOLBAR=True
7474
# for production database dumps on Google Cloud Storage
7575
PROD_DB_DUMP_URL=gs://boostbackups/db1/daily/
7676
PROD_DB_DUMP_FILE_WILDCARD=boost_production.db1*
77+
PROD_LISTS_CORE_DB_DUMP_URL=gs://boostbackups/db1/daily/
78+
PROD_LISTS_CORE_DB_DUMP_FILE_WILDCARD=lists_production_core.db1*
79+
PROD_LISTS_WEB_DB_DUMP_URL=gs://boostbackups/db1/daily/
80+
PROD_LISTS_WEB_DB_DUMP_FILE_WILDCARD=lists_production_web.db1*

scripts/dev-bootstrap-linux.sh

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ prereqsoption="yes"
1515
# docker_mode either "native" or "desktop" (Docker Desktop). Only support "native" currently.
1616
docker_mode="native"
1717
# the 'just' install can't be run as root. Switch to 'standard_user' for that:
18-
standard_user="ubuntu"
18+
standard_user="${SHELL_USER:-ubuntu}"
1919

20-
# On Linux, there are two ways to run Docker. Either the standard native docker installation, or Docker Desktop, which runs inside a virtual machine. The most common installation is standard docker, so that is what is supported by this script currently. In the future, Docker Desktop support could be added. Each method has pros and cons. It's important that the user inside the Django containers is the same as the user on the host machine outside the containers, so that file ownership matches up. Since the user is 'root' inside the containers, it should be 'root' on the host machine. Therefore, any development work should be done as 'root'. That means, run 'sudo su -' before using docker-compose. Docker Desktop would be an alternative to that requirement, and allow running as a regular user account. But with some downside, that it is not a typical linux Docker installation as found on servers.
20+
# On Linux, there are two ways to run Docker. Either the standard native docker installation, or Docker Desktop, which runs inside a virtual machine. The most common installation is standard docker, so that is what is supported by this script currently. In the future, Docker Desktop support could be added. Each method has pros and cons. It's important that the user inside the Django containers is the same as the user on the host machine outside the containers, so that file ownership matches up. Since the user is 'root' inside the containers, it should be 'root' on the host machine. Therefore, any development work should be done as 'root'. That means, run 'sudo su -' before using docker-compose. Docker Desktop would be an alternative to that requirement, and allow running as a regular user account. But with some downside, that it is not a typical linux Docker installation as found on servers.
2121

2222
if [[ ${docker_mode} == "native" ]]; then
2323
repo_path_base="/opt/github"
@@ -27,6 +27,12 @@ if [[ ${docker_mode} == "native" ]]; then
2727
fi
2828
completion_message_1="When doing development work, always switch to the root user, cd to that directory location, and run 'docker compose up -d'. You should be root when running docker compose."
2929
shell_initialization_file=/root/.bashrc
30+
if id "$standard_user" >/dev/null 2>&1; then
31+
true
32+
else
33+
echo "The script needs to be informed about a standard non-root user for certain commands. Those can be discovered by listing 'ls -al /home'. Then please run 'export SHELL_USER=__'. Exiting."
34+
exit 1
35+
fi
3036
fi
3137
if [[ ${docker_mode} == "desktop" ]]; then
3238
repo_path_base="${HOME}/github"
@@ -156,14 +162,22 @@ fi
156162

157163
if [[ "$prereqsoption" == "yes" ]]; then
158164

159-
# sudo apt-get update
165+
sudo apt-get update
166+
167+
if ! cargo --version &> /dev/null
168+
then
169+
echo "Installing cargo"
170+
sudo apt-get install -y cargo
171+
fi
172+
160173
x="\$nrconf{restart} = 'a';"
174+
mkdir -p /etc/needrestart/conf.d
161175
echo "$x" | sudo tee /etc/needrestart/conf.d/90-autorestart.conf 1>/dev/null
162176

163177
if ! command -v makedeb &> /dev/null
164178
then
165179
echo "Installing makdeb"
166-
MAKEDEB_RELEASE=makedeb bash -ci "$(wget -qO - 'https://shlink.makedeb.org/install')"
180+
su - "${standard_user}" -c "export MAKEDEB_RELEASE=makedeb && bash -ci $(wget -qO - 'https://shlink.makedeb.org/install')"
167181
# Or, an alternate method:
168182
# wget -qO - 'https://proget.makedeb.org/debian-feeds/makedeb.pub' | gpg --dearmor | sudo tee /usr/share/keyrings/makedeb-archive-keyring.gpg 1> /dev/null
169183
# echo 'deb [signed-by=/usr/share/keyrings/makedeb-archive-keyring.gpg arch=all] https://proget.makedeb.org/ makedeb main' | sudo tee /etc/apt/sources.list.d/makedeb.list
@@ -176,6 +190,19 @@ if [[ "$prereqsoption" == "yes" ]]; then
176190
sudo apt-get install -y git
177191
fi
178192

193+
if ! command -v psql &> /dev/null
194+
then
195+
apt install -y postgresql-client-16
196+
fi
197+
198+
if ! command -v gcloud &> /dev/null
199+
then
200+
echo "Installing gcloud"
201+
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg
202+
echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
203+
apt-get update && apt-get install -y google-cloud-cli
204+
fi
205+
179206
if ! command -v python3 &> /dev/null
180207
then
181208
echo "Installing python3"

scripts/load_production_data.sh

Lines changed: 94 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,50 @@
11
#!/bin/bash
22
set -eu
3+
4+
# Import Production Data Locally
5+
6+
# Instructions
7+
#
8+
# 1. Install prerequisites (Docker, Just, etc), either manually or using ./scripts/dev-bootstrap-macos.sh
9+
# 2. Run this script with --help to see options. ./scripts/load_production_data.sh --help
10+
#
11+
#
12+
13+
# READ IN COMMAND-LINE OPTIONS
14+
TEMP=$(getopt -o h:: --long help::,lists::,only-lists:: -- "$@")
15+
eval set -- "$TEMP"
16+
17+
# extract options and their arguments into variables.
18+
while true ; do
19+
case "$1" in
20+
-h|--help)
21+
helpmessage="""
22+
usage: load_production_data.sh [-h] [--lists] [--only-lists]
23+
24+
Load production data. By default this will import the main website database.
25+
26+
optional arguments:
27+
-h, --help Show this help message and exit
28+
--lists Import mailing list dbs also.
29+
--only-lists Import mailing list database and not the main web database.
30+
"""
31+
32+
echo ""
33+
echo "$helpmessage" ;
34+
echo ""
35+
exit 0
36+
;;
37+
--lists)
38+
lists_option="yes" ; shift 2 ;;
39+
--only-lists)
40+
lists_option="yes" ; skip_web_option="yes" ; shift 2 ;;
41+
--) shift ; break ;;
42+
*) echo "Internal error!" ; exit 1 ;;
43+
esac
44+
done
45+
346
[ -f ".env" ] || { echo "Error: .env file not found"; exit 1; }
47+
# shellcheck disable=SC1091
448
source .env
549

650
download_media_file() {
@@ -22,7 +66,7 @@ download_media_file() {
2266
return 1;
2367
}
2468

25-
local media_temp_dir=$(mktemp -d)
69+
local -r media_temp_dir=$(mktemp -d)
2670
trap 'rm -rf "$media_temp_dir"' RETURN
2771

2872
echo "Downloading all media files from bucket: $PROD_MEDIA_CONTENT_BUCKET_NAME to: $media_temp_dir"
@@ -53,35 +97,56 @@ download_media_file() {
5397
}
5498

5599
download_latest_db_dump() {
100+
if [ "$1" = "web_db" ]; then
101+
DB_URL="PROD_DB_DUMP_URL"
102+
DB_WILDCARD="PROD_DB_DUMP_FILE_WILDCARD"
103+
DB_NAME=$(grep PGDATABASE .env | cut -d= -f2)
104+
DB_USER=$(grep PGUSER .env | cut -d= -f2)
105+
elif [ "$1" = "lists_core_db" ]; then
106+
DB_URL="PROD_LISTS_CORE_DB_DUMP_URL"
107+
DB_WILDCARD="PROD_LISTS_CORE_DB_DUMP_FILE_WILDCARD"
108+
DB_NAME="lists_production_core"
109+
DB_USER=$(grep PGUSER .env | cut -d= -f2)
110+
elif [ "$1" = "lists_web_db" ]; then
111+
DB_URL="PROD_LISTS_WEB_DB_DUMP_URL"
112+
DB_WILDCARD="PROD_LISTS_WEB_DB_DUMP_FILE_WILDCARD"
113+
DB_NAME="lists_production_web"
114+
DB_USER=$(grep PGUSER .env | cut -d= -f2)
115+
else
116+
echo "Type of db dump not specified. Exiting"
117+
exit 1
118+
fi
119+
56120
# download the latest database dump and restore it to the db
57-
[ -z "$PROD_DB_DUMP_URL" ] && {
58-
echo "Error: PROD_DB_DUMP_URL not set in .env";
121+
[ -z "${!DB_URL}" ] && {
122+
echo "Error: ${!DB_URL} not set in .env";
59123
return 1;
60124
}
61-
[ -z "$PROD_DB_DUMP_FILE_WILDCARD" ] && {
62-
echo "Error: PROD_DB_DUMP_FILE_WILDCARD not set in .env";
125+
[ -z "${!DB_WILDCARD}" ] && {
126+
echo "Error: ${!DB_WILDCARD} not set in .env";
63127
return 1;
64128
}
65129

66-
local db_temp_dir=$(mktemp -d)
130+
local -r db_temp_dir=$(mktemp -d)
131+
echo "db_temp_dir is $db_temp_dir"
67132
trap 'rm -rf "$db_temp_dir"' RETURN
68-
local dump_file_path=""
133+
# not used: local dump_file_path=""
69134

70135
echo "Finding latest database dump..."
71136
# Get a list of all dump files
72-
gcloud storage ls "$PROD_DB_DUMP_URL$PROD_DB_DUMP_FILE_WILDCARD" > "$db_temp_dir/all_files.txt" || {
73-
echo "Failed to list files at $PROD_DB_DUMP_URL";
137+
gcloud storage ls "${!DB_URL}${!DB_WILDCARD}" > "$db_temp_dir/all_files.txt" || {
138+
echo "Failed to list files at ${!DB_URL}";
74139
return 1;
75140
}
76141

77142
[ -s "$db_temp_dir/all_files.txt" ] || {
78-
echo "No files found at $PROD_DB_DUMP_URL";
143+
echo "No files found at ${!DB_URL}";
79144
return 1;
80145
}
81146

82147
grep "\.dump$" "$db_temp_dir/all_files.txt" | sort -r > "$db_temp_dir/dump_files.txt"
83148
[ -s "$db_temp_dir/dump_files.txt" ] || {
84-
echo "No .dump files found at $PROD_DB_DUMP_URL";
149+
echo "No .dump files found at ${!DB_URL}";
85150
return 1;
86151
}
87152

@@ -98,8 +163,6 @@ download_latest_db_dump() {
98163
echo "Successfully downloaded database dump: $DUMP_FILENAME"
99164

100165
echo "Restoring database..."
101-
DB_NAME=$(grep PGDATABASE .env | cut -d= -f2)
102-
DB_USER=$(grep PGUSER .env | cut -d= -f2)
103166
echo "Using database: $DB_NAME and user: $DB_USER"
104167

105168
echo "Stopping all services..."
@@ -117,7 +180,7 @@ download_latest_db_dump() {
117180
docker compose exec db bash -c "psql -U $DB_USER -d template1 -c \"CREATE DATABASE $DB_NAME;\""
118181
echo "Restoring database from dump..."
119182
docker compose cp "$db_temp_dir/$DUMP_FILENAME" "db:/tmp/$DUMP_FILENAME"
120-
docker compose exec db bash -c "pg_restore -U $DB_USER -d $DB_NAME -v --no-owner --no-privileges /tmp/$DUMP_FILENAME" || true
183+
docker compose exec db bash -c "pg_restore -U $DB_USER -d $DB_NAME -v --no-owner --no-privileges /tmp/$DUMP_FILENAME"
121184
# apply any migrations newer than our dumped database
122185
docker compose exec web bash -c "./manage.py migrate"
123186
# update the database to delete all rows from socialaccount_social app, which need to be configured differently locally
@@ -130,10 +193,23 @@ download_latest_db_dump() {
130193
return 0
131194
}
132195

133-
download_latest_db_dump || {
134-
echo "Failed to download and restore latest database dump";
135-
exit 1;
136-
}
196+
if [ "${skip_web_option:-}" != "yes" ]; then
197+
download_latest_db_dump web_db || {
198+
echo "Failed to download and restore latest database dump";
199+
exit 1;
200+
}
201+
fi
202+
203+
if [ "${lists_option:-}" = "yes" ]; then
204+
download_latest_db_dump lists_web_db || {
205+
echo "Failed to download and restore latest lists_web_db dump";
206+
exit 1;
207+
}
208+
download_latest_db_dump lists_core_db || {
209+
echo "Failed to download and restore latest lists_core_db dump";
210+
exit 1;
211+
}
212+
fi
137213

138214
download_media_file || {
139215
echo "Failed to download media files from bucket"

0 commit comments

Comments
 (0)