snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
This commit is contained in:
0
scripts/setup/__init__.py
Normal file
0
scripts/setup/__init__.py
Normal file
2
scripts/setup/apt-repos/ksplice/jammy.list
Normal file
2
scripts/setup/apt-repos/ksplice/jammy.list
Normal file
@@ -0,0 +1,2 @@
|
||||
deb [signed-by=/etc/apt/keyrings/ksplice.asc] http://www.ksplice.com/apt jammy ksplice
|
||||
deb-src [signed-by=/etc/apt/keyrings/ksplice.asc] http://www.ksplice.com/apt jammy ksplice
|
||||
65
scripts/setup/apt-repos/ksplice/ksplice.asc
Normal file
65
scripts/setup/apt-repos/ksplice/ksplice.asc
Normal file
@@ -0,0 +1,65 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQENBEoTaW8BCADXQtpKT5gzOC+/Me50Z07GHfZqkjAThrY+XGhKenklDrZA8nXe
|
||||
FDcmlmMvfeSViP5UH+X7tzjUFT2FcUh65+Onggi/J9nFIDweQXxpzDYyWCK+B0RX
|
||||
InKsq3TfEs5G0yIfYuKi/pgLYkFBls0stWC+1BS+3Lx4uDRTb/44D4LgzHKoAfy1
|
||||
Soho8nDDL1pWEpQAq/5yVSgRc1Vvs1s+CmR8zE5gVi3cfGS0kigdfZJVEdAY/w99
|
||||
t3abgYo1Eq3+Vc1bb+5DiEQZlZsWxWglQlvSyx60U2oxr05Ki+3ZyBomfFCTfL2m
|
||||
fzzJ8cyglzNhFKhyFQIHqzoPR+Sxl8ppcnEJABEBAAG0NktzcGxpY2UgQVBUIFJl
|
||||
cG9zaXRvcnkgU2lnbmluZyBLZXkgPGRldmVsQGtzcGxpY2UuY29tPokBNgQTAQgA
|
||||
IAUCShNpbwIbAwULCQgHAwQVCgkIBRYCAwEAAh4BAheAAAoJEPfKYmW21AOO/pUH
|
||||
/jKDtB3iRU2B4jii71CSFyFaz3BvJvgRMmIf53L85h3sUvqeVJiy8MoreWeoxst9
|
||||
uJBnp8W61QwolCbU6awqdZ2ywRi7JyYNopaEKptxJ3EgBYm+Dq0S7srQK0qCMdRX
|
||||
k7OrhCoJEmev7SazhpdIkMWPtRyksgktBMlwQ5/PyLyW+mP3a8ujYDjMIqzScyDV
|
||||
YBTKK8HtXaLb6Y2Fu4jinAm4YLP3XfnAyNE1Xi9fkzTBWgC4AZ4wctQWxViu6Q91
|
||||
HBB1xBjQYD6aCrPLB8/EtYO6n9UoIov6We8qwDDq7oufEKt8/uLXsomEbaWgOqAv
|
||||
wZzpU6ZHueA8JEmNQYzf6pWZAg0EXKv2DQEQANWkHff3Mp7btrQsBCfiNYNh9fi2
|
||||
0KBhtfWyDI4pyU7ZkzF0sgXZPPUquYuKbRqbqW1NghWk/SFUewfWLLsxpWDUr+9p
|
||||
ghLx2MvdKuaNfvQ/dAoiu7kevyIY4q9fiMwdtRmaCFnJVF2+XZA1z2iH6X6LcLPI
|
||||
KEWU1Xd0aWaxoFFPqjkRy+dlDxxV2xsWdEBikIM7rnA4K6NY1V7YXl4DrHLiZB9U
|
||||
4K4XuNjWxvjNFqdNUTSFnLKKDo55NmO62OvtX6QOtPkrc91efaQ+xVZwR0kk61r6
|
||||
Gon3CcDVqJMk02m9E/p8m2+LDymgmokgPtVQ9N8anfyTqw997gGaoR9FJRs1Pkko
|
||||
IW+Wnhjf2kfOYp9f7yON5nZeAHH9ngaxbqr+0A6SxnyccH9cg9mSvpX61ddk/gPm
|
||||
l40hYvGHNrnzkUOIaLx3Vngogyl6omFS7bi+t72uZifbA4U/oZhl+LUo4wiYCNAL
|
||||
XcGS2kCVKoM3MJB6mg1++gaI7y/Sw7yYfLXp+mn6GTtPiG95JyhhggFpMxx1MSW8
|
||||
+MDmaBdNoEX+q20XUuUV/nU+82QpBWgJHtX36m5kaxZ6r0q/4ZpRgLe4qj3owoI7
|
||||
gbfi5K725ijh5nfKvsayVIzqsHQWLjJ8NP1H2ZLxgem4IqGBDkhQGXrHvaHWzTb6
|
||||
ZqF54fQJkxtX/uETABEBAAG0RE9yYWNsZSBPU1MgZ3JvdXAgKE9wZW4gU291cmNl
|
||||
IFNvZnR3YXJlIGdyb3VwKSA8YnVpbGRAb3NzLm9yYWNsZS5jb20+iQI+BBMBAgAo
|
||||
BQJcq/YNAhsDBQklmAYABgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRCCVi6p
|
||||
rZhto3nfD/4vHhyoqJ+yURoGlbPjKodwC27PbmwJbjBsfhXnoR8pkCH5ZD8nA8XJ
|
||||
tLLCpvOAhSsiXODwIy5ScozkESVSQo8Ngj4KO9S0/QH14VOGqOntY2XLQhBfyoLq
|
||||
n+BMsNe4RsouP4R8u8qKGpwva0khpBaJABp+0bkMUchqdmlWvzx5cnAAwKV7+bb3
|
||||
HsriDRz3n29l0UXuKCAhweVMncZYZsvNFeLR9dVNAkCW1HkbH4WdGdKYCmUvqPVQ
|
||||
bVyB6xmt8lls2yXT7kSrigdQ3exOBqpNhoxZHuMfocUX7l3Tmd2mW0tdsbohrVzV
|
||||
nh76FrZ6EGdx4HFIK3lVPnO2a8kKbhBPj5LwAqx1AunHddZNazkHjUNjLfJAdpDP
|
||||
5KjjZgS28YJ6Y+wJ+SJ3xk0SW2X0ozSIdglsV6G/ZyRl7hFU0QNWC6uWcQQogK+F
|
||||
/BLhvPYhBk9JhAsYuZRjCmmR/ZWOQOFNBQynWKoteyiUKMN9NxmuVRoARc/sDXC4
|
||||
sGUAQcT/Jk5lupyATgBkqRWclia7aWtKQ2GKww5WxWEPILIUTDX58P5Ge9H240c6
|
||||
qB5NX/qQ7Ia76cLx2fArKrTAsnO77wQ116Zy+V32nDHcU9ZMZDgYY0ncxV3B/Cdi
|
||||
SDm8oYNI6Y8O4SefGRo8mtMkgdIld+NKD8zQ+IsZdw4ykZU15ulJArkCDQRcq/YN
|
||||
ARAAodmaW82j7/5qZiH06CeXNJRy2osQ2R7ybtDsddRqQRmBN9FTRqf71OZ+hQLI
|
||||
dLXWrcDSX4WgH8UFPjkHLFR1/znShB3Q8Cmqjk3E2lAKpiA4I6lMdPRKdGH2BAIM
|
||||
aDN9hJmXwwT6LMRTlY6NDnWD/ZqM4NcYhYc/BgTyVnIXu0TtsU0TC97uwitB58BH
|
||||
R4BLPw8wV1DlRL+9hlD6N4tTZ1mp+XYHsCc/sy5elrfUySEHeVph0f69ZpAs9uT9
|
||||
uHty8q2QNsMdjXc1LadOlbJ+N5QIWkMe6nMw2RyVzQh/jhYoDVrSw7t3qYFbJUzQ
|
||||
iCsLGJ5cn8RlUWSFcS6Vwa74vSIeGRH00Dp1Fe8L/AmewIBKPPEWrLOWFN81HVDB
|
||||
Z1kmkLwiX2gfdVytPhO0S8kPG5dMyp4xI581Kx2pqIT27q2BsLXeoFO9uygGD1Gz
|
||||
aFjadGpSE2G8yhFu3VTWpfCGf/2DV/7WLca8QPqPYC5YydT3N6FHfaK4ZCXjySjj
|
||||
bxtEQ/PTwBj76/f+fhT9xuygnMC8KDX5ZhB7bq/SYgki7M6Z4VGZdxpMdRm/Jjpq
|
||||
pK9B46ejSHVyNFkA31PpnyqVhvCHzKEY2V/JtA+aV3+h6IM1WvjexKXpbTZM4sVn
|
||||
fqHZ4am3YspRXP7MVDCsB0W7pSj/WWAZEZvMF7M2BQKRAIsAEQEAAYkCJQQYAQIA
|
||||
DwUCXKv2DQIbDAUJJZgGAAAKCRCCVi6prZhto7gSD/9ZESN0eiy9Ms9uMPCa0fRH
|
||||
dPCKz96oc9Krnsj2MNI69ENaS/j8KJ0G7X4WxMOkiefjCIAgT14xv8vz0JzZjkvL
|
||||
MeXM5EkwSDMSpyMh7CpFwTK8xvJOfHgZziEqIyFFwwtZC5anr8lPT34Heg/NAtce
|
||||
+4C4q7RmMUmXXqht2gvu0BMA4+2qbGTC3bYbWUGQZRUI6IS7CDX70CCIyEMe3oaD
|
||||
zAeMqhCIe/il4YMrFyV19MVMAfTe/H7abBPrVr9GMTViofOaWqZNrz1IM0NK2sbZ
|
||||
WKRIHRh0O6pLMHoUxxRGS0nDDKE4oSMnhzbTBkbnFB+Il85yKPZBg9bm9i1A0Kcp
|
||||
+ymwXsEI/8Zd1gBODJqMLGnimQ2wBmVHIdTHXM8xHUTX6x76XmzXzLRX5v7VgESY
|
||||
CZwQwv1F6/5FvJ35heYn4/2sNOGS89fFX7gdmCXSZe9N3UJRSc2d3jRlLMWjyFOa
|
||||
v/6PZPuJHfBzGejK/93ww5Sq5iwoMt0Gv2eD4K9t//yU0knp1sJABwRe9GfwUqOr
|
||||
6I/6Ec9dc6H8Wsy8EmtsPdXoXrl7K/Isw3vgJrF3YHau7TXIs0YBFmvyI4fdx23h
|
||||
vILSVIDnXI14+ih7od+AIQCwUS+i+KWvuQVuykMas/j3CHR6+1EM+ap+MwuKJpHE
|
||||
5d586NuHxeqt80YNMJDN0Q==
|
||||
=Y2MU
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
2
scripts/setup/apt-repos/ksplice/noble.list
Normal file
2
scripts/setup/apt-repos/ksplice/noble.list
Normal file
@@ -0,0 +1,2 @@
|
||||
deb [signed-by=/etc/apt/keyrings/ksplice.asc] http://www.ksplice.com/apt noble ksplice
|
||||
deb-src [signed-by=/etc/apt/keyrings/ksplice.asc] http://www.ksplice.com/apt noble ksplice
|
||||
1
scripts/setup/apt-repos/teleport/jammy.list
Normal file
1
scripts/setup/apt-repos/teleport/jammy.list
Normal file
@@ -0,0 +1 @@
|
||||
deb [signed-by=/etc/apt/keyrings/teleport-pubkey.asc] https://apt.releases.teleport.dev/ubuntu jammy stable/v17
|
||||
1
scripts/setup/apt-repos/teleport/noble.list
Normal file
1
scripts/setup/apt-repos/teleport/noble.list
Normal file
@@ -0,0 +1 @@
|
||||
deb [signed-by=/etc/apt/keyrings/teleport-pubkey.asc] https://apt.releases.teleport.dev/ubuntu noble stable/v17
|
||||
52
scripts/setup/apt-repos/teleport/teleport-pubkey.asc
Normal file
52
scripts/setup/apt-repos/teleport/teleport-pubkey.asc
Normal file
@@ -0,0 +1,52 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
oq8y1SJMCrfC9Ub5q2/ijiJWUw==
|
||||
=+Ne5
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
BIN
scripts/setup/apt-repos/zulip/apache-arrow-keyring.gpg
Normal file
BIN
scripts/setup/apt-repos/zulip/apache-arrow-keyring.gpg
Normal file
Binary file not shown.
5
scripts/setup/apt-repos/zulip/bookworm.list
Normal file
5
scripts/setup/apt-repos/zulip/bookworm.list
Normal file
@@ -0,0 +1,5 @@
|
||||
deb [signed-by=/etc/apt/keyrings/pgdg.asc] http://apt.postgresql.org/pub/repos/apt/ bookworm-pgdg main
|
||||
deb-src [signed-by=/etc/apt/keyrings/pgdg.asc] http://apt.postgresql.org/pub/repos/apt/ bookworm-pgdg main
|
||||
|
||||
deb http://deb.debian.org/debian bookworm-backports main
|
||||
deb-src http://deb.debian.org/debian bookworm-backports main
|
||||
50
scripts/setup/apt-repos/zulip/custom.sh
Executable file
50
scripts/setup/apt-repos/zulip/custom.sh
Executable file
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
os_info="$(. /etc/os-release && printf '%s\n' "$ID" "$VERSION_ID" "$VERSION_CODENAME")"
|
||||
{
|
||||
read -r os_id
|
||||
read -r os_version_id
|
||||
read -r os_version_codename
|
||||
} <<<"$os_info"
|
||||
|
||||
if [ ! -e /usr/share/doc/groonga-apt-source/copyright ] && [ "$os_id $os_version_id" != "ubuntu 26.04" ]; then
|
||||
pgroonga_apt_sign_key=$(readlink -f "$LIST_PATH/pgroonga-packages.groonga.org.asc")
|
||||
|
||||
remove_pgroonga_apt_tmp_dir() {
|
||||
rm -rf "$pgroonga_apt_tmp_dir"
|
||||
}
|
||||
pgroonga_apt_tmp_dir=$(mktemp --directory)
|
||||
trap remove_pgroonga_apt_tmp_dir EXIT
|
||||
|
||||
{
|
||||
cd "$pgroonga_apt_tmp_dir" || exit 1
|
||||
tmp_gpg_home=.gnupg
|
||||
gpg --homedir="$tmp_gpg_home" --import "$pgroonga_apt_sign_key"
|
||||
# Find fingerprint of the first key.
|
||||
pgroonga_apt_sign_key_fingerprint=$(
|
||||
gpg --homedir="$tmp_gpg_home" --with-colons --list-keys \
|
||||
| grep '^fpr:' \
|
||||
| cut --delimiter=: --fields=10 \
|
||||
| head --lines=1
|
||||
)
|
||||
|
||||
groonga_apt_source_deb="groonga-apt-source-latest-$os_version_codename.deb"
|
||||
groonga_apt_source_deb_sign="$groonga_apt_source_deb.asc.$pgroonga_apt_sign_key_fingerprint"
|
||||
curl -fLO --retry 3 "https://packages.groonga.org/$os_id/$groonga_apt_source_deb"
|
||||
curl -fLO --retry 3 "https://packages.groonga.org/$os_id/$groonga_apt_source_deb_sign"
|
||||
gpg \
|
||||
--homedir="$tmp_gpg_home" \
|
||||
--verify \
|
||||
"$groonga_apt_source_deb_sign" \
|
||||
"$groonga_apt_source_deb"
|
||||
# To suppress the following warning by "apt-get install":
|
||||
# N: Download is performed unsandboxed as root as file
|
||||
# '.../groonga-apt-source-latest-$os_version_codename.deb' couldn't be
|
||||
# accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied)
|
||||
chown _apt .
|
||||
|
||||
apt-get -y install "./$groonga_apt_source_deb"
|
||||
}
|
||||
touch "$STAMP_FILE"
|
||||
fi
|
||||
11
scripts/setup/apt-repos/zulip/jammy.list
Normal file
11
scripts/setup/apt-repos/zulip/jammy.list
Normal file
@@ -0,0 +1,11 @@
|
||||
deb [signed-by=/etc/apt/keyrings/pgdg.asc] http://apt.postgresql.org/pub/repos/apt/ jammy-pgdg main
|
||||
deb-src [signed-by=/etc/apt/keyrings/pgdg.asc] http://apt.postgresql.org/pub/repos/apt/ jammy-pgdg main
|
||||
|
||||
deb [signed-by=/etc/apt/keyrings/pgroonga-ppa.asc] http://ppa.launchpad.net/groonga/ppa/ubuntu jammy main
|
||||
deb-src [signed-by=/etc/apt/keyrings/pgroonga-ppa.asc] http://ppa.launchpad.net/groonga/ppa/ubuntu jammy main
|
||||
|
||||
deb [signed-by=/etc/apt/keyrings/strukturag.asc] https://ppa.launchpadcontent.net/strukturag/libheif/ubuntu/ jammy main
|
||||
deb-src [signed-by=/etc/apt/keyrings/strukturag.asc] https://ppa.launchpadcontent.net/strukturag/libheif/ubuntu/ jammy main
|
||||
|
||||
deb [signed-by=/etc/apt/keyrings/strukturag.asc] https://ppa.launchpadcontent.net/strukturag/libde265/ubuntu/ jammy main
|
||||
deb-src [signed-by=/etc/apt/keyrings/strukturag.asc] https://ppa.launchpadcontent.net/strukturag/libde265/ubuntu/ jammy main
|
||||
12
scripts/setup/apt-repos/zulip/noble.list
Normal file
12
scripts/setup/apt-repos/zulip/noble.list
Normal file
@@ -0,0 +1,12 @@
|
||||
deb [signed-by=/etc/apt/keyrings/pgdg.asc] http://apt.postgresql.org/pub/repos/apt/ noble-pgdg main
|
||||
deb-src [signed-by=/etc/apt/keyrings/pgdg.asc] http://apt.postgresql.org/pub/repos/apt/ noble-pgdg main
|
||||
|
||||
deb [signed-by=/etc/apt/keyrings/pgroonga-ppa.asc] http://ppa.launchpad.net/groonga/ppa/ubuntu noble main
|
||||
deb-src [signed-by=/etc/apt/keyrings/pgroonga-ppa.asc] http://ppa.launchpad.net/groonga/ppa/ubuntu noble main
|
||||
|
||||
deb [signed-by=/etc/apt/keyrings/strukturag.asc] https://ppa.launchpadcontent.net/strukturag/libheif/ubuntu/ noble main
|
||||
deb-src [signed-by=/etc/apt/keyrings/strukturag.asc] https://ppa.launchpadcontent.net/strukturag/libheif/ubuntu/ noble main
|
||||
|
||||
# libde265 in 24.04 is up-to-date, so the PPA doesn't provide 24.04 packages
|
||||
#deb [signed-by=/etc/apt/keyrings/strukturag.asc] https://ppa.launchpadcontent.net/strukturag/libde265/ubuntu/ noble main
|
||||
#deb-src [signed-by=/etc/apt/keyrings/strukturag.asc] https://ppa.launchpadcontent.net/strukturag/libde265/ubuntu/ noble main
|
||||
77
scripts/setup/apt-repos/zulip/pgdg.asc
Normal file
77
scripts/setup/apt-repos/zulip/pgdg.asc
Normal file
@@ -0,0 +1,77 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
=DA1T
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
@@ -0,0 +1,52 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQINBFpuo48BEAC/4UomZcZt2wjDb4WoFGxVxDISaf4k/xliQCz3V11CHN53If3d
|
||||
GsqjOQrJTRpu5euXEoecb0YiiUWI28eD1IajTruunGDjI672/u3+iR6Ga1wk7nia
|
||||
/5tlo4LMYl5va/BQkxVIx95OcoHBh46loVAnbaq+OyfV+r9dILJUf1txAJ65RIGZ
|
||||
SikgkoSCoVnRwNhhLo4ssu65M6o4lRsI6dUP8wpny8dK8EpRlSwrbicrll+lBDxF
|
||||
ZIh1OKll2u5qZ7mtQKOMbCwVhildyHrdUG1PI4ynIIDv9/8r+Wf4weoCqlnsKdKr
|
||||
eHf990yWde0qSMTZnyjJfyY8pKNPkz2cWHKpxiKz6DaDSXJA/soAAmneRh370L0+
|
||||
q9YbUL/TKa3iBmNZOaiJxS+w2pt4n7Z0GPocz56MtGHY0zLplmrm/+z8bBH+Vv1M
|
||||
DQEt1hIE+fdB2tGIDCgjvegEVRckCdWb6ZHeRvcmE7/VKoY0GZZC2088AEyc6Hd9
|
||||
6B0NWEDpooDFTfkaZ5IVc1VW3K7FF6l0Xm+9fLzmL7L8vzAnMZD5xB1AnDw/Woix
|
||||
7Hl7uTdVXBlFWckiuU2N83mtT/IflsK3oBfZ7UVJJWzXiY1iGiEDmAqnENmSiN+D
|
||||
NKGZusJM75rCcUM47XIxC1tV+bYbVf/ToPdmXfn5ElR9nMjl77jY+TEmqQARAQAB
|
||||
tEFHcm9vbmdhIEtleSAoR3Jvb25nYSBPZmZpY2lhbCBTaWduaW5nIEtleSkgPHBh
|
||||
Y2thZ2VzQGdyb29uZ2Eub3JnPokCTgQTAQgAOBYhBCcB8xfPzMuXXK3pwmJM93Q0
|
||||
g5IlBQJabqOPAhsDBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEGJM93Q0g5Il
|
||||
v5IP/0K+YEP051EH82R/9F2Krhc4+cI/ktrrqLk1dvshkpU5m5jc+p8Ynjdc9Orq
|
||||
oEotKUIDCQVtyVdk/bOWd75tgCScclslsXLdpx6hGYA6eRKAV4yPtXQnSd8FutQW
|
||||
iu9poaMPMgODH8bf8PuDGrkLjNhdA0ZuLf1eiabIO94HaF1o1tZ0jVg6UbZ8MwLt
|
||||
LhU9ox81VjEPOssGiR8MCBgHZCxhfe2gSR1mmxDE9d80Kb2DYb4kCke2MjoSku0S
|
||||
h2BtIl/9Gn2VGp5E1klf+VRjoxK6MjvefY7yG5mSWBsE8YmKholzVD4QUSXWY0e3
|
||||
ed8LPt38WXM43eUJt1uD5fd+XoVfTR+ZSaU2P9cEbYb8iec23t2AfXHowhpOcUqy
|
||||
LSnTGPdTeVmZQmp6LSjtIAYwz5Bjdq3kDkPZikYKGYykYuoO4gIuOiBCoWEKUil+
|
||||
bTIG3eU1rfCLjWsWvTJfmsxrB9hX+DjLQUNP7GH/DGAxwt4oSu0hhlGrpAs1ir09
|
||||
KeIQreCyw+yP8t2yFwQ4Lo264Q1euAl29DauB8jfAzS4VVR6U08TpxtzrzTBpKgI
|
||||
0wY+Xg2TgTG1JrdZFAYfgnppkeRfwvppZ51EKgtMtDYsHj07Ds6XcoTrpd9Ttj4k
|
||||
F/Oe8Y8xg7NkRmPF3CXK1HRsdTkfpvR2lUEMKCiMBWmFGWnIuQINBFpuo48BEAC1
|
||||
IHivA5uPRnHpyWUuljjwRQ38TGTNuHeDW0XGychifUSaJMuAkE2ONkGwCeFd2wv6
|
||||
fZA/YVv8OmngwehvBLleDUCS9ANXcuQA9DeH1ZmA032zc3tA8yUq7NXgsIRMWAxo
|
||||
L3Ed+rZa5ivWTL86vOXo9ZkP4PIlD4Dz5KRSOQbYDxypR4Icg5ivyWHBcC5o89Ed
|
||||
XG7Cj1hFzAHREquVKIwR+dcZ1zCsAd2lB8lNoDu4qkMX+adZVzzDl+LLJzLos9wx
|
||||
llJGkIctbICWbc2Il906NTU4o23UipUSfgl5Rv7xWoHsYA1nzGK423Ji0JZSjbfk
|
||||
nNBT1HFKhrVyhcUiNJ8t7VL/nkxfHeZKkmiZOu53xwemm8S45ly6FDMDLZZ8ij8R
|
||||
6SlyRHu/lJUw6PFBk/GSC7HH7QFmT1tli5/BTgl0EHCAxvxv+wHYt++Lv1kKToYu
|
||||
WPOjD52y1edwcdqT/l022AyhXP9sHyjlacSxww1giLDNwy+2GOtwdaUreQd5SVJ7
|
||||
48bh4V7VjRvVCIJGhQs72PI4AFyFQZ1gCXHZK7lAsDg9LV5iuOWD8iu3zS7XuJFn
|
||||
Di8aIe6zQ6qP8FMivaQeRvwnRPCdRvk/noBfuqlDPSBCEfDiVkLfbkdNKIDF3QgF
|
||||
c7ZuGSJl+m6IluUm1hMx587+JnR9FpW0Lc46ypMApQARAQABiQI2BBgBCAAgFiEE
|
||||
JwHzF8/My5dcrenCYkz3dDSDkiUFAlpuo48CGwwACgkQYkz3dDSDkiV7ZA//SLYc
|
||||
hegp0AWszEDvySB6dyn3v/ZZfuIUkknPbaYo2M516TUFb960EMFaKC96FeV6AEyv
|
||||
B+pL9iDsobRqtrMzLfWENibhnY3Dm+THNgPkFg905+ygnMKSHTloi++BFgSl+sjO
|
||||
SRtdN5yNF8tVuRUsgiepQdcQ6AioFHaq4HxMAIJLfJA3qIue4/cGIpbdneflCvOa
|
||||
V6jYDjCsUdLSwh3J4DdVyquIq34wVVZYdtOao7EwKVcy62GHtJxmnv8no5hsAizL
|
||||
t+8nf14jX4zIueoBGLyFP2XoaiUH9NDuApp3oILuQPighu3BFC7bjy3MFIaO7MHb
|
||||
Jvm0wjQADAr4UhXk1ALNWrSDiLMNa0raJzzzr43dCIN6lsmlbNj4CvMYdtWi4ObS
|
||||
F5p9m03oHJhSRhn7+mAJJDwCqrYyf0T1WWR/dz86LkefdHQF/5mVmWEX6OoqcYL+
|
||||
gC4S+dc+5RP2anHYO00pBtrWNjSZ6Fy0TqV4PQbO4BZG+omu2HkiU890NLgW0DKl
|
||||
pEMq49UQfItfJtvCffzpC4kq8obMi4eFFC6puz1DcjSjFd9U2iAUFb7rSrS2fxi1
|
||||
pj3P7QUmt1MuQgRuaE64dcaP92TtCUVFtgmFPoDL00aMJiz9roVOyTgLc90AHq6R
|
||||
6TYbUXXz7NBwM+kX8Uq9KpPXkHnP1D4TgEw7o5A=
|
||||
=7PCC
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
27
scripts/setup/apt-repos/zulip/pgroonga-ppa.asc
Normal file
27
scripts/setup/apt-repos/zulip/pgroonga-ppa.asc
Normal file
@@ -0,0 +1,27 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: SKS 1.1.5
|
||||
Comment: Hostname: keyserver.ubuntu.com
|
||||
|
||||
mQINBFMyaEABEADEeUoP5AmhJZLHujySJaLKd1EXpIxkope3l4f/3tkbPTvV+jkyYvOSX/ii
|
||||
NAHyVGPrg4UjJI+kDLru1glFoabBs+J4xk2Lql9DcHW0x7YPgBXKCuj2sg84Teb0KTnAkAFI
|
||||
gd8w2kzs6l9itQbtCWei0wH+pGpp9YJqEqJhqc3U51LqUoMmYjTd2WTaN+BNVZOE3ws4Pa4+
|
||||
JyikyVOkuj/8q+jRF8LHWmeb76SuycvZMyGjJBnIs65wmmSN6VpeHtQA3NzIAV2FKuirEEuW
|
||||
5j7fD9L8WNTXy++K6NTvcd2InXgEWMG3rSGvfE2CvZSxKc/b9/xVdaG0LDtTTWPTosNdluUA
|
||||
K4M91Rz7UEvC06SWIdxqL8LdLOy/6OYaJxgh1exrEadRPWAKr+Ak7LDMiYPHq80npQzMh8Hn
|
||||
oUbQTaQ7KDFD17BZ7HauXn8rRmG/vpdQvKzswRoc3+mroh5hA6otjKdmOWAaD5AmNNxcvR3O
|
||||
iNjDTnX804pjrjHzmTAAxrPKwPxbPzFUeNB4Dt4BzUdesdbbZYJw5ojcvt9qCfLU0DOZXWk4
|
||||
t1nHvIQvGoG8cE63x1buVHcwFXwxocMUdn4iFam9srBlDx1G8TMlaKITNHvoc//evBU0arz0
|
||||
12UMDb8TXAT5zOW1W6szFSt1ZFn0By9Ab+I69UCIgB2iknMUtwARAQABtBlMYXVuY2hwYWQg
|
||||
UFBBIGZvciBHcm9vbmdhiQI4BBMBAgAiBQJTMmhAAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIe
|
||||
AQIXgAAKCRAzWefOy2ShV5p5EACWQ5QBQV86SAhjJHfRe1MSYVZtrA3v+wwS52V/C9sV9xlc
|
||||
Sn2IGIpUQM2816fVMTM23pvj9lzuP3PpcHl0vc5/gqSliRPAzXawgs8Gl+wB9FcwnKPPQfyR
|
||||
CWflFg5mc37+5wM/fTagL7V5S+mBcDrAyMOr7AFgt03nTCwoSaNHatF+pBZRqpyWByM6sqD+
|
||||
IF2ChI4O3QTI5H6HkbQStEHLGuz8G6UX1MBRZ9LrRl0hUqdc2F/dcogrtV5NWkimXvMcTBYB
|
||||
9dTeuvj7eSma6JemqJAXfCARq54KjYwcZHapzczJe3Kgj1tSqD8O1Z8fsT16P2b0tUnDgNjX
|
||||
PB9UQGsP5NLK+vGnVBg5xJA5GqaN69lsUsvPaFFngmKmykQQNlDk7Q3yrAvMJWwRPQ1c8eMq
|
||||
kkrkKBal8Rq/EJaoaoBG6SFx2cSAD4GMxPEL7G3qJeNJPSLVSOP9j9nGIZ4SETeGIKCNVgVF
|
||||
16iXIxwflvgJP+/1qX3/Qin2YDYCeGvFmJiy5s0VFM1IdK+znrUu0apoCSYVia1D9NJGEdKf
|
||||
l7m/Odtxycq9VP1DKD/k4spWqsdpiBkJMch7XWfa7KF12bwV/tHP4KqJ02/xqhSqk+Ru4A9R
|
||||
LjQFWXs4o/Qwf5qF7FlGhpFridr0xdxtLVmK7bV4Hogldx1bKbkOpCL29BY8GA==
|
||||
=NjhU
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
6
scripts/setup/apt-repos/zulip/resolute.list
Normal file
6
scripts/setup/apt-repos/zulip/resolute.list
Normal file
@@ -0,0 +1,6 @@
|
||||
deb [signed-by=/etc/apt/keyrings/pgdg.asc] http://apt.postgresql.org/pub/repos/apt/ resolute-pgdg main
|
||||
deb-src [signed-by=/etc/apt/keyrings/pgdg.asc] http://apt.postgresql.org/pub/repos/apt/ resolute-pgdg main
|
||||
|
||||
# Not available for Ubuntu 26.04 yet
|
||||
#deb [signed-by=/etc/apt/keyrings/pgroonga-ppa.asc] http://ppa.launchpad.net/groonga/ppa/ubuntu resolute main
|
||||
#deb-src [signed-by=/etc/apt/keyrings/pgroonga-ppa.asc] http://ppa.launchpad.net/groonga/ppa/ubuntu resolute main
|
||||
28
scripts/setup/apt-repos/zulip/strukturag.asc
Normal file
28
scripts/setup/apt-repos/zulip/strukturag.asc
Normal file
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQINBGY0lEwBEAD9qq6oOeRJvCi0fHNqJELvS8ykqfuXxWqn1B9DLt0VuTxgmaxG
|
||||
QNaG0B2pfrhoVDs+9wwfOuW0rtUtjWpccJjZaooTIEFSR4AKZAh3O4gUtvI7y95r
|
||||
q7+wWFct4RjbFyZOpmeinhIgnItTbkVjhjJvvQ66H4gUfNeJOoAE7CYgnMhZ1Sn8
|
||||
E6zxWJVLo0c5hXkkc4x4T1Aq02diO0Zg6T6HesxsCLeb5Sbjrca7ukUBGV3WFKAF
|
||||
QC22r8oCC4LiN5TX1WNQJjDSw0M2AY31AF+ebQvZGa1kcClWjqBCD7717+zbevPe
|
||||
/bx88Yr6eh+xuJ3ZJQ209phdeNq9RRkIDnap7TIVn21VoCQolH+adP9boxgG1iIz
|
||||
0gBx1KXBjRgV9owoYan4Mz9+c+5MMgJ975D+8GoRcNr1oycjOO/VVXw7ST9UiXqo
|
||||
TuOU2c1P8KmM3IUF41Igy5rd7MLy9uizKC/WY/lfLOH8pzT3LoWVmhMDJHooF9fq
|
||||
UC80GRIIaBM3f7sQH873zdqzaRPqtgJDxOAzLoZqUaFwLXuMfvYxhwMLWhe3b6Wp
|
||||
shCe3xifqZIHf9iZkqZ9b2TsstXervs0TlW9Xy8FT8RMuEzsX8DLNsUert+PzWpq
|
||||
C8Qse1AElMgSSxEsucWMbW5cnKj6ViEf10gy5VwlTgEgvt9KpZ2Icm43mwARAQAB
|
||||
tB1MYXVuY2hwYWQgUFBBIGZvciBzdHJ1a3R1ciBBR4kCTgQTAQoAOBYhBEfpK5wT
|
||||
yXuwgfX/wXF9tBYRYATJBQJmNJRMAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheA
|
||||
AAoJEHF9tBYRYATJ/oMQAPVJWmzF+UKwkCA/kFeihXdA6OWl1BttFQpwTAAmxr9u
|
||||
SCg/w1ltIYqTfZcAjMUhY52oDix/NxzZZb/B4dxOkUM4gYmkbzq4wlT0QyrRgjNZ
|
||||
wflwdNjXGI9Ew9ta/3xvNE98LQWyV64t+Q8PihDD7VwOE/c2XVPvXQk8GWmsHJ48
|
||||
nGLaAPzn68kolv3XpkDB+ul07OLC7FXlADxWFOsobwula/zytFK2oyuQ1NiXoJ5I
|
||||
3+IA5sAp7O1mDOZ3m8RROfw56IbwHlNXAP8/REbqWEsXVNkyMf56snpsIr8FPlqY
|
||||
C74QbR/PHcb7vEdeWZgHmuIGNF37QPMx4XUGWjh/9NNi7AHGMa2cRsSF1xm1R99Q
|
||||
Zr1vmRPJM2z54gPq/JwY7WlcL6yEFMBL+WtNuiua5xxZ3rkMs956IuFS55zjrNeO
|
||||
MPmK77tdmFEui0GiTIyAJpoZIwp0AgYBdmP4/2Y6j6LN1sV+VkOzQz2CqDT87yO1
|
||||
BoN65jFuw61H3Y/+OBQMtoxamxs1m/Jjv0sEYf21nKgfukOTLecRWH1tXu0moTAf
|
||||
eEf0MOXzhH1teyfv/21haprwxJn0cG515oHB/JutFNKrXx3qtNH5QjRXIbz9EWAs
|
||||
u1mi4ERxSWAELxiJQWztCOhB5sI8Auq+Kk4uzbCutK6BQrUQORz2FGEJwEXy1f7g
|
||||
=76Dg
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
2
scripts/setup/apt-repos/zulip/trixie.list
Normal file
2
scripts/setup/apt-repos/zulip/trixie.list
Normal file
@@ -0,0 +1,2 @@
|
||||
deb [signed-by=/etc/apt/keyrings/pgdg.asc] http://apt.postgresql.org/pub/repos/apt/ trixie-pgdg main
|
||||
deb-src [signed-by=/etc/apt/keyrings/pgdg.asc] http://apt.postgresql.org/pub/repos/apt/ trixie-pgdg main
|
||||
10
scripts/setup/apt-repos/zulip/zulip.pref
Normal file
10
scripts/setup/apt-repos/zulip/zulip.pref
Normal file
@@ -0,0 +1,10 @@
|
||||
# libarrow1600 is missing on Debian 12
|
||||
Package: libgroonga0
|
||||
Pin: version 14.0.3-1
|
||||
Pin-Priority: 499
|
||||
|
||||
|
||||
# On bookworm, pull libheif1 from backports
|
||||
Package: libheif1
|
||||
Pin: release n=bookworm-backports
|
||||
Pin-Priority: 500
|
||||
72
scripts/setup/compare-settings-to-template
Executable file
72
scripts/setup/compare-settings-to-template
Executable file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import difflib
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
sys.path.append(BASE_DIR)
|
||||
from scripts.lib.setup_path import setup_path
|
||||
|
||||
setup_path()
|
||||
|
||||
|
||||
current_path = "/etc/zulip/settings.py"
|
||||
if len(sys.argv) >= 2:
|
||||
current_path = sys.argv[1]
|
||||
|
||||
print(f"Reading current configuration from {current_path}...")
|
||||
with open(current_path) as f:
|
||||
current_contents = f.read()
|
||||
|
||||
import requests
|
||||
|
||||
print("Fetching old versions of setting templates from Github...")
|
||||
templ = {}
|
||||
url: str | None = "https://api.github.com/repos/zulip/zulip/tags?per_page=100"
|
||||
|
||||
while url is not None:
|
||||
resp = requests.get(url)
|
||||
if resp.status_code != 200:
|
||||
print(resp.content)
|
||||
sys.exit(1)
|
||||
|
||||
url = resp.links.get("next", {}).get("url")
|
||||
for tag in [t["name"] for t in resp.json()]:
|
||||
if not re.match(r"^\d+\.\d+(\.\d+)?$", tag):
|
||||
continue
|
||||
|
||||
filename = "zproject/prod_settings_template.py"
|
||||
if [int(x) for x in tag.split(".")] < [1, 4]:
|
||||
filename = "zproject/local_settings_template.py"
|
||||
|
||||
print(f" - {tag}")
|
||||
resp = requests.get(
|
||||
f"https://raw.githubusercontent.com/zulip/zulip/{tag}/{filename}",
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
templ[tag] = resp.content.decode()
|
||||
else:
|
||||
print("Failure: ")
|
||||
print(resp)
|
||||
|
||||
print("Computing minimal difference...")
|
||||
sequence_matchers = {}
|
||||
for version, contents in templ.items():
|
||||
sm = difflib.SequenceMatcher(None, current_contents, contents)
|
||||
sequence_matchers[version] = sm
|
||||
|
||||
likely = sorted(sequence_matchers.keys(), key=lambda v: sequence_matchers[v].ratio(), reverse=True)
|
||||
print(f"Most likely version: {likely[0]}")
|
||||
|
||||
|
||||
diff = difflib.unified_diff(
|
||||
templ[likely[0]].splitlines(keepends=True),
|
||||
current_contents.splitlines(keepends=True),
|
||||
fromfile=f"zulip-server-{version}/zproject/prod_settings_template.py",
|
||||
tofile=current_path,
|
||||
)
|
||||
|
||||
print()
|
||||
print("".join(diff), end="")
|
||||
30
scripts/setup/configure-rabbitmq
Executable file
30
scripts/setup/configure-rabbitmq
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Delete the "guest" default user and replace it with a Zulip user
|
||||
# with a real password
|
||||
set -eu
|
||||
|
||||
# If the RabbitMQ distribution cookie is insecure, reset it and
|
||||
# restart RabbitMQ.
|
||||
"$(dirname "$0")/generate-rabbitmq-cookie"
|
||||
|
||||
RABBITMQ_USERNAME=$("$(dirname "$0")/../get-django-setting" RABBITMQ_USERNAME)
|
||||
RABBITMQ_PASSWORD=$("$(dirname "$0")/../get-django-setting" RABBITMQ_PASSWORD)
|
||||
RABBITMQ_VHOST=$("$(dirname "$0")/../get-django-setting" RABBITMQ_VHOST)
|
||||
|
||||
tries=0
|
||||
while ((tries < 30)) && ! rabbitmqctl ping -q 2>/dev/null; do
|
||||
((tries++)) || echo "Waiting for RabbitMQ to start up..."
|
||||
sleep 1
|
||||
done
|
||||
rabbitmqctl await_startup
|
||||
|
||||
rabbitmqctl delete_user "$RABBITMQ_USERNAME" || true
|
||||
rabbitmqctl delete_user zulip || true
|
||||
rabbitmqctl delete_user guest || true
|
||||
rabbitmqctl add_user "$RABBITMQ_USERNAME" "$RABBITMQ_PASSWORD"
|
||||
rabbitmqctl set_user_tags "$RABBITMQ_USERNAME" administrator
|
||||
if ! rabbitmqctl list_vhosts --no-table-headers --quiet | grep -qx "$RABBITMQ_VHOST"; then
|
||||
rabbitmqctl add_vhost "$RABBITMQ_VHOST"
|
||||
fi
|
||||
rabbitmqctl set_permissions -p "$RABBITMQ_VHOST" "$RABBITMQ_USERNAME" '.*' '.*' '.*'
|
||||
61
scripts/setup/create-database
Executable file
61
scripts/setup/create-database
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "Error: This script must be run as root" >&2
|
||||
exit 1
|
||||
fi
|
||||
set -x
|
||||
|
||||
# What user should we use for connecting to the database
|
||||
POSTGRES_USER="${POSTGRES_USER:-postgres}"
|
||||
|
||||
# What database name and username to use when connecting to the database
|
||||
DATABASE_NAME=$(crudini --get /etc/zulip/zulip.conf postgresql database_name 2>/dev/null || echo zulip)
|
||||
DATABASE_USER=$(crudini --get /etc/zulip/zulip.conf postgresql database_user 2>/dev/null || echo zulip)
|
||||
|
||||
if [ "$(su "$POSTGRES_USER" -c "cd / && psql -v ON_ERROR_STOP=1 -Atc \"SELECT 1 FROM pg_database WHERE datname='$DATABASE_NAME';\"")" = "1" ]; then
|
||||
records="$(su "$POSTGRES_USER" -c "cd / && psql -v ON_ERROR_STOP=1 -Atc 'SELECT COUNT(*) FROM $DATABASE_NAME.zerver_message;' $DATABASE_USER" || echo 0)"
|
||||
if [ "$records" -gt 200 ]; then
|
||||
set +x
|
||||
echo "WARNING: This will delete your Zulip database which currently contains $records messages."
|
||||
read -p "Do you want to proceed? [y/N] " -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
exit 1
|
||||
fi
|
||||
set -x
|
||||
fi
|
||||
fi
|
||||
|
||||
# Shut down all services to ensure a quiescent state.
|
||||
if [ -e "/home/zulip/deployments" ]; then
|
||||
su zulip -c "/home/zulip/deployments/current/scripts/stop-server"
|
||||
fi
|
||||
|
||||
# Drop any open connections to any old database.
|
||||
# Send the script via stdin in case the postgres user lacks permission to read it.
|
||||
su -s /usr/bin/env - -- "$POSTGRES_USER" \
|
||||
bash -s - zulip zulip_base <"$(dirname "$0")/terminate-psql-sessions"
|
||||
|
||||
(
|
||||
cd / # Make sure the current working directory is readable by postgres
|
||||
su "$POSTGRES_USER" -c "psql -v ON_ERROR_STOP=1 -v dbname=$DATABASE_NAME -v dbuser=$DATABASE_USER -e"
|
||||
) <"$(dirname "$0")/create-db.sql"
|
||||
|
||||
# Set a postgres password if the postgres username is not "zulip".
|
||||
# When the username is zulip, we rely on running as the zulip system
|
||||
# user for authentication via postgres' peer authentication.
|
||||
if [ "$DATABASE_USER" != "zulip" ]; then
|
||||
PASSWORD=$(crudini --get /etc/zulip/zulip-secrets.conf secrets postgres_password)
|
||||
su "$POSTGRES_USER" -c "psql -v ON_ERROR_STOP=1 -e postgres" <<EOF
|
||||
ALTER ROLE $DATABASE_USER PASSWORD '$PASSWORD';
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Clear memcached to avoid contamination from previous database state
|
||||
if [ -e "/home/zulip/deployments" ]; then
|
||||
/home/zulip/deployments/current/scripts/setup/flush-memcached
|
||||
fi
|
||||
|
||||
echo "Database created"
|
||||
20
scripts/setup/create-db.sql
Normal file
20
scripts/setup/create-db.sql
Normal file
@@ -0,0 +1,20 @@
|
||||
\set dbuser :dbuser
|
||||
SELECT CASE WHEN :'dbuser' = ':dbuser' THEN 'zulip' ELSE :'dbuser' END AS dbuser \gset
|
||||
\set dbname :dbname
|
||||
SELECT CASE WHEN :'dbname' = ':dbname' THEN 'zulip' ELSE :'dbname' END AS dbname \gset
|
||||
|
||||
\connect postgres
|
||||
DROP DATABASE IF EXISTS :"dbname";
|
||||
SELECT format($$BEGIN
|
||||
CREATE USER %I;
|
||||
EXCEPTION WHEN duplicate_object THEN
|
||||
RAISE NOTICE 'user already exists';
|
||||
END$$, :'dbuser') AS code \gset
|
||||
DO :'code';
|
||||
CREATE DATABASE :"dbname"
|
||||
OWNER=:dbuser
|
||||
ENCODING=UTF8
|
||||
LC_COLLATE='C.UTF-8'
|
||||
LC_CTYPE='C.UTF-8'
|
||||
TEMPLATE=template0;
|
||||
\connect :"dbname"
|
||||
2
scripts/setup/create-pgroonga.sql
Normal file
2
scripts/setup/create-pgroonga.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
\connect zulip
|
||||
CREATE EXTENSION pgroonga;
|
||||
28
scripts/setup/flush-memcached
Executable file
28
scripts/setup/flush-memcached
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import sys
|
||||
|
||||
BASE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../..")
|
||||
sys.path.append(BASE_DIR)
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "zproject.settings")
|
||||
|
||||
from scripts.lib.setup_path import setup_path
|
||||
|
||||
setup_path()
|
||||
|
||||
import bmemcached
|
||||
from django.conf import settings
|
||||
|
||||
cache = settings.CACHES["default"]
|
||||
match cache["BACKEND"]:
|
||||
case "django.core.cache.backends.locmem.LocMemCache":
|
||||
pass
|
||||
case "zerver.lib.singleton_bmemcached.SingletonBMemcached":
|
||||
assert isinstance(cache["OPTIONS"], dict)
|
||||
client = bmemcached.Client((cache["LOCATION"],), **cache["OPTIONS"])
|
||||
try:
|
||||
client.flush_all()
|
||||
finally:
|
||||
client.disconnect_all()
|
||||
case _:
|
||||
raise ValueError(f"Unrecognized cache backend {cache['BACKEND']}")
|
||||
27
scripts/setup/generate-rabbitmq-cookie
Executable file
27
scripts/setup/generate-rabbitmq-cookie
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# rabbitmq sets an insecure "magic cookie" which is used for auth;
|
||||
# reset it to be longer.
|
||||
set -eu
|
||||
|
||||
cookiefile=/var/lib/rabbitmq/.erlang.cookie
|
||||
# If the RabbitMQ distribution cookie is insecure, reset it
|
||||
if [ ! -f "$cookiefile" ] || ! size="$(wc -c "$cookiefile")" || [ "${size%% *}" -le 20 ]; then
|
||||
running=0
|
||||
if service rabbitmq-server status >/dev/null; then
|
||||
running=1
|
||||
service rabbitmq-server stop
|
||||
fi
|
||||
|
||||
echo "Setting a more secure RabbitMQ distribution magic cookie"
|
||||
cookie="$(LC_ALL=C tr -dc '[:alnum:]' </dev/urandom | head -c255)"
|
||||
[ "${#cookie}" -eq 255 ] # make sure tr wasn’t OOM-killed
|
||||
tmpfile="$(mktemp "$cookiefile.XXXXXXXXXX")"
|
||||
chown rabbitmq: "$tmpfile"
|
||||
printf '%s' "$cookie" >"$tmpfile"
|
||||
mv "$tmpfile" "$cookiefile"
|
||||
|
||||
if [ "$running" == "1" ]; then
|
||||
service rabbitmq-server start
|
||||
fi
|
||||
fi
|
||||
108
scripts/setup/generate-self-signed-cert
Executable file
108
scripts/setup/generate-self-signed-cert
Executable file
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
usage() {
|
||||
echo "usage: $0 [--force] [--exists-ok] EXTERNAL_HOST" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
args="$(getopt -o '' --long help,force,exists-ok -- "$@")"
|
||||
eval "set -- $args"
|
||||
while true; do
|
||||
case "$1" in
|
||||
--help) usage ;;
|
||||
--force)
|
||||
FORCE=1
|
||||
shift
|
||||
;;
|
||||
--exists-ok)
|
||||
EXISTS_OK=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*) usage ;;
|
||||
esac
|
||||
done
|
||||
EXTERNAL_HOST="$1"
|
||||
|
||||
if [ -z "$EXTERNAL_HOST" ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "error: this script must be run as root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -x
|
||||
|
||||
is_redhat=false
|
||||
if [ -e /etc/redhat-release ]; then
|
||||
is_redhat=true
|
||||
SSLDIR=/etc/pki/tls
|
||||
else
|
||||
SSLDIR=/etc/ssl
|
||||
fi
|
||||
KEYFILE=$SSLDIR/private/zulip.key
|
||||
CERTFILE=$SSLDIR/certs/zulip.combined-chain.crt
|
||||
|
||||
if [ -n "$EXISTS_OK" ] && [ -e "$KEYFILE" ] && [ -e "$CERTFILE" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$FORCE" ] && { [ -e "$KEYFILE" ] || [ -e "$CERTFILE" ]; }; then
|
||||
echo "$0: certificate and/or key already exists; use --force to overwrite." >&2
|
||||
exit 1
|
||||
fi
|
||||
rm -f "$KEYFILE" "$CERTFILE"
|
||||
|
||||
if [[ "$EXTERNAL_HOST" =~ ^(([0-9]+\.){3}[0-9]+)(:[0-9]+)?$ ]]; then
|
||||
subjectAltName="IP:${BASH_REMATCH[1]}" # IPv4 address
|
||||
elif [[ "$EXTERNAL_HOST" =~ ^\[([^][]*)\](:[0-9]+)?$ ]]; then
|
||||
subjectAltName="IP:${BASH_REMATCH[1]}" # IPv6 address
|
||||
elif [[ "$EXTERNAL_HOST" =~ ^([^:]+)(:[0-9]+)?$ ]]; then
|
||||
subjectAltName="DNS:${BASH_REMATCH[1]}"
|
||||
else
|
||||
echo "$0: invalid host $EXTERNAL_HOST" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
config="$(mktemp)" || exit 1
|
||||
trap 'rm -f "$config"' EXIT
|
||||
|
||||
cat >"$config" <<EOF
|
||||
# Based on /usr/share/ssl-cert/ssleay.cnf from Debian's \`ssl-cert\`
|
||||
# package, which is used for the system's snakeoil cert in /etc/ssl/.
|
||||
|
||||
[ req ]
|
||||
default_bits = 2048
|
||||
distinguished_name = req_distinguished_name
|
||||
prompt = no
|
||||
policy = policy_anything
|
||||
req_extensions = v3_req
|
||||
x509_extensions = v3_req
|
||||
|
||||
[ req_distinguished_name ]
|
||||
commonName = $EXTERNAL_HOST
|
||||
|
||||
[ v3_req ]
|
||||
basicConstraints = CA:FALSE
|
||||
subjectAltName = $subjectAltName
|
||||
EOF
|
||||
|
||||
if [ "$is_redhat" = true ]; then
|
||||
yum install -y openssl
|
||||
else
|
||||
apt-get install -y openssl
|
||||
fi
|
||||
|
||||
# Based on /usr/sbin/make-ssl-cert from Debian's `ssl-cert` package.
|
||||
openssl req -new -x509 \
|
||||
-config "$config" -days 3650 -nodes -sha256 \
|
||||
-out "$CERTFILE" -keyout "$KEYFILE"
|
||||
|
||||
chmod 644 "$CERTFILE"
|
||||
chmod 640 "$KEYFILE"
|
||||
228
scripts/setup/generate_secrets.py
Executable file
228
scripts/setup/generate_secrets.py
Executable file
@@ -0,0 +1,228 @@
|
||||
#!/usr/bin/env python3
|
||||
# This tools generates /etc/zulip/zulip-secrets.conf
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from contextlib import suppress
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
sys.path.append(BASE_DIR)
|
||||
from scripts.lib.setup_path import setup_path
|
||||
from scripts.lib.zulip_tools import get_config, get_config_file
|
||||
|
||||
setup_path()
|
||||
|
||||
os.environ["DISABLE_MANDATORY_SECRET_CHECK"] = "True"
|
||||
os.environ["DJANGO_SETTINGS_MODULE"] = "zproject.settings"
|
||||
|
||||
import argparse
|
||||
import configparser
|
||||
import uuid
|
||||
|
||||
from nacl.encoding import Base64Encoder
|
||||
from nacl.public import PrivateKey
|
||||
|
||||
os.chdir(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
|
||||
# Standard, 64-bit tokens
|
||||
AUTOGENERATED_SETTINGS = [
|
||||
"avatar_salt",
|
||||
"rabbitmq_password",
|
||||
"shared_secret",
|
||||
]
|
||||
|
||||
|
||||
def random_string(cnt: int) -> str:
|
||||
# We do in-function imports so that we only do the expensive work
|
||||
# of importing cryptography modules when necessary.
|
||||
#
|
||||
# This helps optimize noop provision performance.
|
||||
from django.utils.crypto import get_random_string
|
||||
|
||||
return get_random_string(cnt)
|
||||
|
||||
|
||||
def random_token() -> str:
|
||||
# We do in-function imports so that we only do the expensive work
|
||||
# of importing cryptography modules when necessary.
|
||||
#
|
||||
# This helps optimize noop provision performance.
|
||||
import secrets
|
||||
|
||||
return secrets.token_hex(32)
|
||||
|
||||
|
||||
def generate_django_secretkey() -> str:
|
||||
"""Secret key generation taken from Django's startproject.py"""
|
||||
|
||||
# We do in-function imports so that we only do the expensive work
|
||||
# of importing cryptography modules when necessary.
|
||||
#
|
||||
# This helps optimize noop provision performance.
|
||||
from django.utils.crypto import get_random_string
|
||||
|
||||
chars = "abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)"
|
||||
return get_random_string(50, chars)
|
||||
|
||||
|
||||
def get_old_conf(output_filename: str) -> dict[str, str]:
|
||||
if not os.path.exists(output_filename) or os.path.getsize(output_filename) == 0:
|
||||
return {}
|
||||
|
||||
secrets_file = configparser.RawConfigParser()
|
||||
secrets_file.read(output_filename)
|
||||
|
||||
return dict(secrets_file.items("secrets"))
|
||||
|
||||
|
||||
def generate_secrets(development: bool = False) -> None:
|
||||
if development:
|
||||
OUTPUT_SETTINGS_FILENAME = "zproject/dev-secrets.conf"
|
||||
else:
|
||||
OUTPUT_SETTINGS_FILENAME = "/etc/zulip/zulip-secrets.conf"
|
||||
current_conf = get_old_conf(OUTPUT_SETTINGS_FILENAME)
|
||||
|
||||
lines: list[str] = []
|
||||
if len(current_conf) == 0:
|
||||
lines = ["[secrets]\n"]
|
||||
|
||||
def need_secret(name: str) -> bool:
|
||||
return name not in current_conf
|
||||
|
||||
def add_secret(name: str, value: str) -> None:
|
||||
lines.append(f"{name} = {value}\n")
|
||||
current_conf[name] = value
|
||||
|
||||
for name in AUTOGENERATED_SETTINGS:
|
||||
if need_secret(name):
|
||||
add_secret(name, random_token())
|
||||
|
||||
# These secrets are exclusive to a Zulip development environment.
|
||||
# We use PostgreSQL peer authentication by default in production,
|
||||
# and initial_password_salt is used to generate passwords for the
|
||||
# test/development database users. See `manage.py
|
||||
# print_initial_password`.
|
||||
if development and need_secret("initial_password_salt"):
|
||||
add_secret("initial_password_salt", random_token())
|
||||
if development and need_secret("local_database_password"):
|
||||
add_secret("local_database_password", random_token())
|
||||
|
||||
# We only need a secret if the database username does not match
|
||||
# the OS username, as identd auth works in that case.
|
||||
if get_config(
|
||||
get_config_file(), "postgresql", "database_user", "zulip"
|
||||
) != "zulip" and need_secret("postgres_password"):
|
||||
add_secret("postgres_password", random_token())
|
||||
|
||||
# The core Django SECRET_KEY setting, used by Django internally to
|
||||
# secure sessions. If this gets changed, all users will be logged out.
|
||||
if need_secret("secret_key"):
|
||||
secret_key = generate_django_secretkey()
|
||||
add_secret("secret_key", secret_key)
|
||||
# To prevent Django ImproperlyConfigured error
|
||||
from zproject import settings
|
||||
|
||||
settings.SECRET_KEY = secret_key
|
||||
|
||||
# Secret key for the Camo HTTPS proxy.
|
||||
if need_secret("camo_key"):
|
||||
add_secret("camo_key", random_string(64))
|
||||
|
||||
# We enable Altcha in development
|
||||
if development and need_secret("altcha_hmac"):
|
||||
add_secret("altcha_hmac", random_token())
|
||||
|
||||
if not development:
|
||||
# The memcached_password and redis_password secrets are only
|
||||
# required/relevant in production.
|
||||
|
||||
# Password for authentication to memcached.
|
||||
if need_secret("memcached_password"):
|
||||
# We defer importing settings unless we need it, because
|
||||
# importing settings is expensive (mostly because of
|
||||
# django-auth-ldap) and we want the noop case to be fast.
|
||||
from zproject import settings
|
||||
|
||||
if settings.MEMCACHED_LOCATION == "127.0.0.1:11211":
|
||||
add_secret("memcached_password", random_token())
|
||||
|
||||
# Password for authentication to Redis.
|
||||
if need_secret("redis_password"):
|
||||
# We defer importing settings unless we need it, because
|
||||
# importing settings is expensive (mostly because of
|
||||
# django-auth-ldap) and we want the noop case to be fast.
|
||||
from zproject import settings
|
||||
|
||||
if settings.REDIS_HOST == "127.0.0.1":
|
||||
# To prevent Puppet from restarting Redis, which would lose
|
||||
# data because we configured Redis to disable persistence, set
|
||||
# the Redis password on the running server and edit the config
|
||||
# file directly.
|
||||
|
||||
import redis
|
||||
|
||||
from zerver.lib.redis_utils import get_redis_client
|
||||
|
||||
redis_password = random_token()
|
||||
|
||||
for filename in ["/etc/redis/zuli-redis.conf", "/etc/redis/zulip-redis.conf"]:
|
||||
if os.path.exists(filename):
|
||||
with open(filename, "a") as f:
|
||||
f.write(
|
||||
"# Set a Redis password based on zulip-secrets.conf\n"
|
||||
f"requirepass '{redis_password}'\n",
|
||||
)
|
||||
break
|
||||
|
||||
with suppress(redis.exceptions.ConnectionError):
|
||||
get_redis_client().config_set("requirepass", redis_password)
|
||||
|
||||
add_secret("redis_password", redis_password)
|
||||
|
||||
# Random id and secret used to identify this installation when
|
||||
# accessing the Zulip mobile push notifications service.
|
||||
# * zulip_org_key is generated using os.urandom().
|
||||
# * zulip_org_id only needs to be unique, so we use a UUID.
|
||||
if need_secret("zulip_org_key"):
|
||||
add_secret("zulip_org_key", random_string(64))
|
||||
if need_secret("zulip_org_id"):
|
||||
add_secret("zulip_org_id", str(uuid.uuid4()))
|
||||
|
||||
if development and need_secret("push_registration_encryption_keys"):
|
||||
# 'settings.ZILENCER_ENABLED' would be a better check than
|
||||
# 'development' for whether we need push bouncer secrets,
|
||||
# but we're trying to avoid importing settings.
|
||||
private_key = PrivateKey.generate()
|
||||
private_key_str = Base64Encoder.encode(bytes(private_key)).decode("utf-8")
|
||||
public_key_str = Base64Encoder.encode(bytes(private_key.public_key)).decode("utf-8")
|
||||
add_secret(
|
||||
"push_registration_encryption_keys", json.dumps({public_key_str: private_key_str})
|
||||
)
|
||||
|
||||
if len(lines) == 0:
|
||||
print("generate_secrets: No new secrets to generate.")
|
||||
return
|
||||
|
||||
with open(OUTPUT_SETTINGS_FILENAME, "a") as f:
|
||||
# Write a newline at the start, in case there was no newline at
|
||||
# the end of the file due to human editing.
|
||||
f.write("\n" + "".join(lines))
|
||||
|
||||
print(f"Generated new secrets in {OUTPUT_SETTINGS_FILENAME}.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
group = parser.add_mutually_exclusive_group(required=True)
|
||||
group.add_argument(
|
||||
"--development", action="store_true", help="For setting up the developer env for zulip"
|
||||
)
|
||||
group.add_argument(
|
||||
"--production",
|
||||
action="store_false",
|
||||
dest="development",
|
||||
help="For setting up the production env for zulip",
|
||||
)
|
||||
results = parser.parse_args()
|
||||
|
||||
generate_secrets(results.development)
|
||||
60
scripts/setup/initialize-database
Executable file
60
scripts/setup/initialize-database
Executable file
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
usage() {
|
||||
echo "usage: initialize-database [--quiet]" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
args="$(getopt -o '' --long help,quiet -- "$@")"
|
||||
eval "set -- $args"
|
||||
while true; do
|
||||
case "$1" in
|
||||
--help) usage ;;
|
||||
--quiet)
|
||||
QUIET=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*) usage ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$#" -gt 0 ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
set -x
|
||||
|
||||
# Change to root directory of the checkout that we're running from
|
||||
THIS_DIR="$(dirname "$(readlink -f "$0")")"
|
||||
cd "$THIS_DIR/../.."
|
||||
|
||||
./manage.py migrate --noinput
|
||||
./manage.py createcachetable third_party_api_results
|
||||
|
||||
# Check if the supervisor socket exists. If not, it could be:
|
||||
#
|
||||
# A) A normal installation went bad (supervisor hasn't started)
|
||||
# B) We are in a Docker container and don't have supervisor running
|
||||
#
|
||||
# In either case, it doesn't make sense to restart supervisor jobs
|
||||
if [ -e "/var/run/supervisor.sock" ]; then
|
||||
./scripts/restart-server
|
||||
fi
|
||||
|
||||
set +x
|
||||
if [ -z "$QUIET" ]; then
|
||||
echo "Congratulations! You have successfully configured your Zulip database."
|
||||
echo "If you haven't already, you should configure email in /etc/zulip/settings.py."
|
||||
echo
|
||||
echo "Next, run as the zulip user (use 'su zulip' if needed):"
|
||||
echo
|
||||
echo " /home/zulip/deployments/current/manage.py generate_realm_creation_link"
|
||||
echo
|
||||
echo "This generates a secure, single-use link that you can use to set up "
|
||||
echo "a Zulip organization from the convenience of your web browser."
|
||||
fi
|
||||
27
scripts/setup/install
Executable file
27
scripts/setup/install
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Thin wrapper around the actual install script (scripts/lib/install).
|
||||
# The purpose of this wrapper is to log the full install script output
|
||||
# to /var/log/zulip/install.log for easy debugging.
|
||||
|
||||
set -e
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "Error: The installation script must be run as root." >&2
|
||||
exit 1
|
||||
fi
|
||||
umask 022
|
||||
mkdir -p /var/log/zulip
|
||||
|
||||
"$(dirname "$(dirname "$0")")/lib/install" "$@" 2>&1 | tee -a /var/log/zulip/install.log
|
||||
failed=${PIPESTATUS[0]}
|
||||
|
||||
if [ "$failed" -ne 0 ]; then
|
||||
echo -e '\033[0;31m'
|
||||
echo "Zulip installation failed (exit code $failed)!"
|
||||
echo
|
||||
echo -n "The install process is designed to be idempotent, so you can retry "
|
||||
echo -n "after resolving whatever issue caused the failure (there should be a traceback above). "
|
||||
echo -n "A log of this installation is available in /var/log/zulip/install.log"
|
||||
echo -e '\033[0m'
|
||||
exit "$failed"
|
||||
fi
|
||||
25
scripts/setup/pgroonga-config
Executable file
25
scripts/setup/pgroonga-config
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eux
|
||||
|
||||
dbversion=$(crudini --get /etc/zulip/zulip.conf postgresql version)
|
||||
dbname=$(crudini --get /etc/zulip/zulip.conf postgresql database_name 2>/dev/null || echo zulip)
|
||||
|
||||
if ! su postgres -c "psql -At -c 'SELECT datname FROM pg_database WHERE NOT datistemplate'" | grep -Fx "$dbname"; then
|
||||
echo "No database to install into!"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
sharedir="${1:-/usr/share/postgresql/$dbversion}"
|
||||
applied_file="$sharedir/pgroonga_setup.sql.applied"
|
||||
|
||||
installed_version=$(dpkg-query --show --showformat='${Version}' "postgresql-$dbversion-pgdg-pgroonga")
|
||||
|
||||
if [ ! -f "$applied_file" ]; then
|
||||
sql="CREATE EXTENSION PGROONGA"
|
||||
else
|
||||
sql="ALTER EXTENSION pgroonga UPDATE"
|
||||
fi
|
||||
|
||||
echo "$sql" | su postgres -c "psql -v ON_ERROR_STOP=1 $dbname"
|
||||
|
||||
echo "$installed_version" >"$applied_file"
|
||||
139
scripts/setup/reindex-textual-data
Executable file
139
scripts/setup/reindex-textual-data
Executable file
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), "../.."))
|
||||
from scripts.lib.setup_path import setup_path
|
||||
|
||||
setup_path()
|
||||
|
||||
import psycopg2
|
||||
import psycopg2.extensions
|
||||
from psycopg2.sql import SQL, Identifier
|
||||
|
||||
from scripts.lib.zulip_tools import su_to_zulip
|
||||
|
||||
su_to_zulip()
|
||||
os.environ["DJANGO_SETTINGS_MODULE"] = "zproject.settings"
|
||||
from django.conf import settings
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Reindex all text indexes, for glibc upgrades. This will take a write lock on every table, unless --concurrently is passed."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--concurrently", action="store_true", help="reindex concurrently, on Pg ≥ 11; takes longer"
|
||||
)
|
||||
parser.add_argument("--force", action="store_true", help="run the reindexing")
|
||||
options = parser.parse_args()
|
||||
|
||||
logging.Formatter.converter = time.gmtime
|
||||
logging.basicConfig(format="%(asctime)s %(levelname)s: %(message)s")
|
||||
logger = logging.getLogger("reindex-textual-data")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
pg_args = {}
|
||||
pg_args["host"] = settings.DATABASES["default"]["HOST"]
|
||||
pg_args["port"] = settings.DATABASES["default"].get("PORT")
|
||||
pg_args["password"] = settings.DATABASES["default"].get("PASSWORD")
|
||||
pg_args["user"] = settings.DATABASES["default"]["USER"]
|
||||
pg_args["dbname"] = settings.DATABASES["default"]["NAME"]
|
||||
pg_args["sslmode"] = settings.DATABASES["default"]["OPTIONS"].get("sslmode")
|
||||
pg_args["connect_timeout"] = "600"
|
||||
|
||||
# connection_factory=None lets mypy understand the return type
|
||||
conn = psycopg2.connect(connection_factory=None, **pg_args)
|
||||
conn.autocommit = True
|
||||
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT
|
||||
irel.relname AS index_name,
|
||||
trel.relname AS table_name,
|
||||
pg_size_pretty(pg_table_size(i.indrelid)) AS size
|
||||
FROM
|
||||
pg_index AS i
|
||||
JOIN pg_class AS trel ON trel.oid = i.indrelid
|
||||
JOIN pg_namespace AS tnsp ON trel.relnamespace = tnsp.oid
|
||||
JOIN pg_class AS irel ON irel.oid = i.indexrelid
|
||||
JOIN pg_attribute AS a ON a.attrelid = i.indexrelid
|
||||
WHERE tnsp.nspname = 'zulip'
|
||||
AND a.attcollation != 0
|
||||
GROUP BY 1, 2, i.indrelid
|
||||
ORDER BY pg_table_size(i.indrelid) ASC
|
||||
"""
|
||||
)
|
||||
reindex_targets = cursor.fetchall()
|
||||
|
||||
if not options.force:
|
||||
print("Would reindex the following indexes:")
|
||||
for index, _, _ in reindex_targets:
|
||||
print(f" {index}")
|
||||
print(
|
||||
"""
|
||||
|
||||
Re-run with --force to reindex these. Without --concurrently, these
|
||||
index rebuilds will TAKE A WRITE LOCK on their respective tables,
|
||||
which means that production traffic will be affected.
|
||||
|
||||
On PostgreSQL 11 and above, you can pass --concurrently, which will do
|
||||
the index rebuilds without taking such a lock. We recommend only using
|
||||
--concurrently if the Zulip server will be serving traffic while
|
||||
running this tool, because concurrent reindexing takes longer to
|
||||
complete even if the server is not running.
|
||||
"""
|
||||
)
|
||||
sys.exit(0)
|
||||
|
||||
had_failures = False
|
||||
for index_name, table_name, index_size in reindex_targets:
|
||||
if options.concurrently:
|
||||
command = SQL("REINDEX INDEX CONCURRENTLY {}").format(Identifier(index_name))
|
||||
else:
|
||||
command = SQL("REINDEX INDEX {}").format(Identifier(index_name))
|
||||
|
||||
logger.info("%s -- on %s, %s", command, table_name, index_size)
|
||||
try:
|
||||
cursor.execute(command)
|
||||
except psycopg2.OperationalError as e:
|
||||
logger.warning("Failed to reindex %s: %s", index_name, e)
|
||||
had_failures = True
|
||||
|
||||
if not had_failures:
|
||||
sys.exit(0)
|
||||
|
||||
print(
|
||||
"""
|
||||
=========================> REINDEXING FAILED <=========================
|
||||
|
||||
Reindexing failed on one or more indexes; this is generally caused
|
||||
by duplicate rows that had been incorrectly inserted because of
|
||||
corrupted database indexes. This happens, for example, when glibc was
|
||||
upgraded to 2.28 or higher, which has a different ordering of text
|
||||
("collation") than earlier versions. Because of the new ordering,
|
||||
entries in the indexes are not found (because they exist in a
|
||||
different place), which results in duplicates being created in the
|
||||
database for columns which should be unique.
|
||||
|
||||
There is no generalized tool to fix these duplicate rows, but in most cases
|
||||
the database can be repaired with some manual work. We are using
|
||||
this chat.zulip.org for support around such repairs:
|
||||
|
||||
https://chat.zulip.org/#narrow/channel/31-production-help/topic/database.20corruption
|
||||
|
||||
This tool has regenerated all database indexes that do not have duplicate rows.
|
||||
Once you have manually repaired duplicate rows, you can rerun this command
|
||||
to regenerate the rest.
|
||||
|
||||
It is reasonable to run your Zulip server to avoid downtime while you
|
||||
plan the manual repair work. Additional duplicate rows may be created
|
||||
for any corrupted index that has not yet been regenerated. But any new
|
||||
duplicate rows will be similar to existing duplicate rows that you
|
||||
already need to manually repair.
|
||||
"""
|
||||
)
|
||||
sys.exit(1)
|
||||
187
scripts/setup/restore-backup
Executable file
187
scripts/setup/restore-backup
Executable file
@@ -0,0 +1,187 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from typing import IO
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
sys.path.append(BASE_DIR)
|
||||
from scripts.lib.zulip_tools import assert_running_as_root, get_postgres_pwent, run, su_to_zulip
|
||||
|
||||
POSTGRES_PWENT = get_postgres_pwent()
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("tarball", help="Filename of input tarball")
|
||||
parser.add_argument(
|
||||
"--keep-settings", help="Do not overwrite local /etc/zulip/settings.py", action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--keep-zulipconf", help="Do not overwrite local /etc/zulip/zulip.conf", action="store_true"
|
||||
)
|
||||
|
||||
|
||||
def restore_backup(tarball_file: IO[bytes], keep_settings: bool, keep_zulipconf: bool) -> None:
|
||||
assert_running_as_root()
|
||||
su_to_zulip(save_suid=True)
|
||||
|
||||
from scripts.lib.setup_path import setup_path
|
||||
|
||||
setup_path()
|
||||
|
||||
# First, we unpack the /etc/zulip configuration, so we know how
|
||||
# this server is supposed to be configured (and can import
|
||||
# /etc/zulip/settings.py via `from django.conf import settings`,
|
||||
# next). Ignore errors if zulip-backup/settings is not present
|
||||
# (E.g. because this is a development backup).
|
||||
tarball_file.seek(0, 0)
|
||||
excludes = []
|
||||
if keep_settings:
|
||||
excludes += ["--exclude=settings.py"]
|
||||
if keep_zulipconf:
|
||||
excludes += ["--exclude=zulip.conf"]
|
||||
run(
|
||||
[
|
||||
"tar",
|
||||
"--directory=/etc/zulip",
|
||||
"--keep-directory-symlink",
|
||||
*excludes,
|
||||
"--strip-components=2",
|
||||
"-xz",
|
||||
"zulip-backup/settings",
|
||||
],
|
||||
stdin=tarball_file,
|
||||
)
|
||||
|
||||
os.environ["DJANGO_SETTINGS_MODULE"] = "zproject.settings"
|
||||
from django.conf import settings
|
||||
|
||||
paths = [
|
||||
# zproject will only be present for development environment backups.
|
||||
("zproject", os.path.join(settings.DEPLOY_ROOT, "zproject")),
|
||||
]
|
||||
if settings.LOCAL_UPLOADS_DIR is not None:
|
||||
# We only need to restore LOCAL_UPLOADS_DIR if the system is
|
||||
# configured to locally host uploads.
|
||||
paths.append(("uploads", os.path.join(settings.DEPLOY_ROOT, settings.LOCAL_UPLOADS_DIR)))
|
||||
|
||||
with tempfile.TemporaryDirectory(prefix="zulip-restore-backup-") as tmp:
|
||||
uid = os.getuid()
|
||||
gid = os.getgid()
|
||||
os.setresuid(0, 0, 0)
|
||||
for name, path in paths:
|
||||
os.makedirs(path, exist_ok=True)
|
||||
os.chown(path, uid, gid)
|
||||
os.setresuid(uid, uid, 0)
|
||||
|
||||
assert not any("|" in name or "|" in path for name, path in paths)
|
||||
transform_args = [
|
||||
r"--transform=s|^zulip-backup/{}(/.*)?$|{}\1|x".format(
|
||||
re.escape(name),
|
||||
path.replace("\\", r"\\"),
|
||||
)
|
||||
for name, path in paths
|
||||
]
|
||||
|
||||
os.mkdir(os.path.join(tmp, "zulip-backup"))
|
||||
tarball_file.seek(0, 0)
|
||||
run(
|
||||
["tar", "-C", tmp, "--keep-directory-symlink", *transform_args, "-xPz"],
|
||||
stdin=tarball_file,
|
||||
)
|
||||
|
||||
# Now, extract the database backup, destroy the old
|
||||
# database, and create a new, empty database.
|
||||
db = settings.DATABASES["default"]
|
||||
assert isinstance(db["NAME"], str)
|
||||
db_dir = os.path.join(tmp, "zulip-backup", "database")
|
||||
os.setresuid(0, 0, 0)
|
||||
run(["chown", "-R", POSTGRES_PWENT.pw_name, "--", tmp])
|
||||
# Open the terminate-psql-sessions script while still running
|
||||
# as root, since the postgres user may lack permission to read
|
||||
# it -- e.g. because /home/zulip is not world-readable, which
|
||||
# is the default for home directories on Debian 13 and Ubuntu
|
||||
# 21.04 and newer.
|
||||
terminate_psql_sessions_fd = os.open(
|
||||
os.path.join(settings.DEPLOY_ROOT, "scripts", "setup", "terminate-psql-sessions"),
|
||||
os.O_RDONLY,
|
||||
)
|
||||
os.setresuid(POSTGRES_PWENT.pw_uid, POSTGRES_PWENT.pw_uid, 0)
|
||||
|
||||
postgresql_env = dict(os.environ)
|
||||
if db["HOST"] not in ["", "localhost"]:
|
||||
postgresql_env["PGHOST"] = db["HOST"]
|
||||
if "PORT" in db:
|
||||
postgresql_env["PGPORT"] = str(db["PORT"])
|
||||
postgresql_env["PGUSER"] = db["USER"]
|
||||
if "PASSWORD" in db:
|
||||
postgresql_env["PGPASSWORD"] = db["PASSWORD"]
|
||||
|
||||
run(
|
||||
["bash", "-s", "-", db["NAME"]],
|
||||
stdin=terminate_psql_sessions_fd,
|
||||
env=postgresql_env,
|
||||
)
|
||||
os.close(terminate_psql_sessions_fd)
|
||||
run(["dropdb", "--if-exists", "--", db["NAME"]], cwd="/", env=postgresql_env)
|
||||
run(
|
||||
["createdb", "--owner=zulip", "--template=template0", "--", db["NAME"]],
|
||||
cwd="/",
|
||||
env=postgresql_env,
|
||||
)
|
||||
os.setresuid(0, 0, 0)
|
||||
|
||||
if settings.PRODUCTION:
|
||||
# In case we are restoring a backup from an older Zulip
|
||||
# version, there may be new secrets to generate.
|
||||
run(
|
||||
[
|
||||
os.path.join(settings.DEPLOY_ROOT, "scripts", "setup", "generate_secrets.py"),
|
||||
"--production",
|
||||
]
|
||||
)
|
||||
|
||||
# If there is a local RabbitMQ, we need to reconfigure it
|
||||
# to ensure the RabbitMQ password matches the value in the
|
||||
# restored zulip-secrets.conf. We need to be careful to
|
||||
# only do this if RabbitMQ is configured to run locally on
|
||||
# the system.
|
||||
rabbitmq_host = subprocess.check_output(
|
||||
[
|
||||
os.path.join(settings.DEPLOY_ROOT, "scripts", "get-django-setting"),
|
||||
"RABBITMQ_HOST",
|
||||
],
|
||||
text=True,
|
||||
).strip()
|
||||
if rabbitmq_host in ["127.0.0.1", "::1", "localhost", "localhost6"]:
|
||||
run([os.path.join(settings.DEPLOY_ROOT, "scripts", "setup", "configure-rabbitmq")])
|
||||
|
||||
# In production, we also need to do a `zulip-puppet-apply`
|
||||
# in order to apply any configuration from
|
||||
# /etc/zulip/zulip.conf to this system, since it was
|
||||
# originally installed without the restored copy of that
|
||||
# file.
|
||||
run([os.path.join(settings.DEPLOY_ROOT, "scripts", "zulip-puppet-apply"), "-f"])
|
||||
|
||||
# Now, restore the database backup using pg_restore. This
|
||||
# needs to run after zulip-puppet-apply to ensure full-text
|
||||
# search extensions are available and installed.
|
||||
os.setresuid(POSTGRES_PWENT.pw_uid, POSTGRES_PWENT.pw_uid, 0)
|
||||
run(["pg_restore", "--dbname=" + db["NAME"], "--", db_dir], cwd="/", env=postgresql_env)
|
||||
os.setresuid(0, 0, 0)
|
||||
run(["chown", "-R", str(uid), "--", tmp])
|
||||
os.setresuid(uid, uid, 0)
|
||||
|
||||
if settings.PRODUCTION:
|
||||
run([os.path.join(settings.DEPLOY_ROOT, "scripts", "restart-server")])
|
||||
|
||||
run([os.path.join(settings.DEPLOY_ROOT, "scripts", "setup", "flush-memcached")])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(args.tarball, "rb") as tarball_file:
|
||||
restore_backup(tarball_file, args.keep_settings, args.keep_zulipconf)
|
||||
112
scripts/setup/setup-certbot
Executable file
112
scripts/setup/setup-certbot
Executable file
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
usage() {
|
||||
cat <<EOF >&2
|
||||
Usage: $0 --email=admin@example.com [--method={webroot|standalone}] \
|
||||
hostname.example.com [another.example.com]
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "Error: This script must be run as root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
method=webroot
|
||||
args="$(getopt -o '' --long help,email:,method:,agree-tos -n "$0" -- "$@")"
|
||||
eval "set -- $args"
|
||||
agree_tos=()
|
||||
while true; do
|
||||
case "$1" in
|
||||
--email)
|
||||
EMAIL="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
--method)
|
||||
method="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
--agree-tos)
|
||||
agree_tos=(--agree-tos)
|
||||
shift
|
||||
;;
|
||||
--help)
|
||||
show_help=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Parse the remaining arguments as Subject Alternative Names to pass to certbot
|
||||
HOSTNAMES=()
|
||||
for arg; do
|
||||
HOSTNAMES+=(-d "$arg")
|
||||
done
|
||||
DOMAIN=$1
|
||||
|
||||
if [ -n "$show_help" ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
if [ -z "$DOMAIN" ] || [ -z "$EMAIL" ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
case "$method" in
|
||||
standalone)
|
||||
method_args=(--standalone --no-directory-hooks)
|
||||
;;
|
||||
webroot)
|
||||
method_args=(--webroot '--webroot-path=/var/lib/zulip/certbot-webroot/')
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
|
||||
# If we aren't being run interactively, default to keeping the
|
||||
# existing certificate (rather than burning through a renewal)
|
||||
# If run interactively, certbot will prompt.
|
||||
default_keep=()
|
||||
if [ ! -t 0 ]; then
|
||||
default_keep=(--keep-until-expiring)
|
||||
fi
|
||||
|
||||
# We need to know _which_ domain is Zulip's, in the symlink deploy
|
||||
# hook, so we pass this down
|
||||
export ZULIP_DOMAIN="$DOMAIN"
|
||||
|
||||
# Certbot does not run deploy hooks on new certificates
|
||||
# (certbot/certbot#9978) so we will need to fake it if so
|
||||
if [ -d "/etc/letsencrypt/live/$DOMAIN/" ]; then
|
||||
needs_hooks=0
|
||||
else
|
||||
needs_hooks=1
|
||||
fi
|
||||
|
||||
certbot certonly "${method_args[@]}" \
|
||||
"${HOSTNAMES[@]}" -m "$EMAIL" \
|
||||
"${agree_tos[@]}" \
|
||||
"${default_keep[@]}" \
|
||||
--no-eff-email
|
||||
|
||||
# "certbot certonly" before version 3.2.0 does not run deploy hooks,
|
||||
# so we fake running them.
|
||||
if [ "$needs_hooks" = "1" ]; then
|
||||
export RENEWED_DOMAINS="$*"
|
||||
if [ "$method" == "webroot" ]; then
|
||||
for deploy_hook in /etc/letsencrypt/renewal-hooks/deploy/*; do
|
||||
"$deploy_hook"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
echo "Certbot SSL certificate configuration succeeded."
|
||||
32
scripts/setup/sha256-file-to
Executable file
32
scripts/setup/sha256-file-to
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ "$#" -ne 3 ]; then
|
||||
echo "Usage:"
|
||||
echo " sha256-file-to SHA256 http://FETCH/FROM DST"
|
||||
echo
|
||||
echo "SHA256 is the sha256sum of the file fetched; the file is"
|
||||
echo "placed in DST."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
SHA256="$1"
|
||||
URL="$2"
|
||||
DST="$3"
|
||||
|
||||
# Work in a tmpdir which we clean up at the end
|
||||
tmpdir="$(mktemp -d)"
|
||||
trap 'rm -r "$tmpdir"' EXIT
|
||||
cd "$tmpdir"
|
||||
|
||||
# Fetch to a predictable name, not whatever curl guesses from the URL
|
||||
LOCALFILE="output"
|
||||
curl -fL --retry 3 -o "$LOCALFILE" "$URL"
|
||||
|
||||
# Check the hash against what was passed in
|
||||
echo "$SHA256 $LOCALFILE" >"$LOCALFILE.sha256"
|
||||
sha256sum -c "$LOCALFILE.sha256"
|
||||
|
||||
mv "$LOCALFILE" "$DST"
|
||||
56
scripts/setup/sha256-tarball-to
Executable file
56
scripts/setup/sha256-tarball-to
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ "$#" -lt 4 ]; then
|
||||
echo "Usage:"
|
||||
echo " sha256-tarball-to SHA256 http://FETCH/FROM.tar.gz SRC1 DST1 [SRC2 DST2 [...]]"
|
||||
echo
|
||||
echo "SHA256 is the sha256sum of the tarball fetched; each SRC (which may be a"
|
||||
echo "directory) is expected to be a relative path into the unpacked tarball,"
|
||||
echo "and each DST is the absolute path it should be moved to."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
SHA256="$1"
|
||||
URL="$2"
|
||||
shift
|
||||
shift
|
||||
|
||||
# Work in a tmpdir which we clean up at the end
|
||||
tmpdir="$(mktemp -d)"
|
||||
trap 'rm -r "$tmpdir"' EXIT
|
||||
cd "$tmpdir"
|
||||
|
||||
# We support both .tar.gz and .zip files
|
||||
if [[ "$URL" == *.tar.gz ]] || [[ "$URL" == *.tgz ]]; then
|
||||
extension="tar.gz"
|
||||
elif [[ "$URL" == *.zip ]]; then
|
||||
extension="zip"
|
||||
else
|
||||
echo "Can't determine archive type from URL: $URL"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Fetch to a predictable name, not whatever curl guesses from the URL
|
||||
LOCALFILE="archive.$extension"
|
||||
curl -fL --retry 3 -o "$LOCALFILE" "$URL"
|
||||
|
||||
# Check the hash against what was passed in
|
||||
echo "$SHA256 $LOCALFILE" >"$LOCALFILE.sha256"
|
||||
sha256sum -c "$LOCALFILE.sha256"
|
||||
|
||||
if [[ "$extension" == "tar.gz" ]]; then
|
||||
tar xzf "$LOCALFILE"
|
||||
else
|
||||
unzip "$LOCALFILE"
|
||||
fi
|
||||
|
||||
# Take the rest of the arguments two-at-a-time, as source and
|
||||
# destination to move out of the unpacked tarball.
|
||||
while [ "$#" -gt 0 ]; do
|
||||
mv "$1" "$2"
|
||||
shift
|
||||
shift
|
||||
done
|
||||
17
scripts/setup/terminate-psql-sessions
Executable file
17
scripts/setup/terminate-psql-sessions
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
cd /
|
||||
|
||||
tables="$(printf "'%s'," "${@//\'/\'\'}")"
|
||||
tables="${tables%,}"
|
||||
|
||||
psql postgres -v ON_ERROR_STOP=1 <<EOF
|
||||
SELECT pg_terminate_backend(s.pid)
|
||||
FROM pg_stat_activity s, pg_roles r
|
||||
WHERE
|
||||
s.datname IN ($tables)
|
||||
AND r.rolname = CURRENT_USER
|
||||
AND (s.usename = r.rolname OR r.rolsuper = 't')
|
||||
AND s.pid <> pg_backend_pid();
|
||||
EOF
|
||||
149
scripts/setup/upgrade-postgresql
Executable file
149
scripts/setup/upgrade-postgresql
Executable file
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "Error: This script must be run as root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Force a known locale; some OS X terminals set an invalid LC_CTYPE
|
||||
# which crashes pg_upgradecluster
|
||||
export LC_ALL=C.UTF-8
|
||||
export LANG=C.UTF-8
|
||||
export LANGUAGE=C.UTF-8
|
||||
|
||||
LATEST_SUPPORTED_VERSION=18
|
||||
UPGRADE_TO=${1:-$LATEST_SUPPORTED_VERSION}
|
||||
UPGRADE_FROM=$(crudini --get /etc/zulip/zulip.conf postgresql version)
|
||||
ZULIP_PATH="$(dirname "$0")/../.."
|
||||
|
||||
if [ "$UPGRADE_TO" = "$UPGRADE_FROM" ]; then
|
||||
echo "Already running PostgreSQL $UPGRADE_TO!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$UPGRADE_TO" -lt "$UPGRADE_FROM" ]]; then
|
||||
echo "Refusing to downgrade PostgreSQL $UPGRADE_FROM to $UPGRADE_TO!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$UPGRADE_TO" -gt "$LATEST_SUPPORTED_VERSION" ]]; then
|
||||
echo "This version of Zulip does not support PostgreSQL $UPGRADE_TO."
|
||||
echo "You may need to upgrade Zulip before you can upgrade to PostgreSQL $UPGRADE_TO."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify that the version in /etc/zulip/zulip.conf is the version that
|
||||
# Django actually stores its data in. We can only do that if the
|
||||
# database server is on the same host as the application server.
|
||||
if [ -d /home/zulip/deployments/current ]; then
|
||||
DATA_IS_IN=$(
|
||||
su -s /usr/bin/env -- zulip \
|
||||
DJANGO_SETTINGS_MODULE=zproject.settings \
|
||||
uv run --directory=/home/zulip/deployments/current --no-sync \
|
||||
python -c 'from django.db import connection; print(connection.cursor().connection.server_version // 10000)'
|
||||
)
|
||||
|
||||
if [ "$UPGRADE_FROM" != "$DATA_IS_IN" ]; then
|
||||
cat <<EOF
|
||||
|
||||
/etc/zulip/zulip.conf claims that Zulip is running PostgreSQL
|
||||
$UPGRADE_FROM, but the server is connected to a PostgreSQL running
|
||||
version $DATA_IS_IN. Check the output from pg_lsclusters to verify
|
||||
which clusters are running, and update /etc/zulip/zulip.conf to match.
|
||||
|
||||
In general, this results from manually upgrading PostgreSQL; you
|
||||
should use this tool for all PostgreSQL upgrades.
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
set -x
|
||||
|
||||
"$ZULIP_PATH"/scripts/lib/setup-apt-repo
|
||||
apt-get install -y "postgresql-$UPGRADE_TO" "postgresql-client-$UPGRADE_TO"
|
||||
drop_main_cluster="$(
|
||||
pg_lsclusters --json \
|
||||
| jq --arg pg_version "$UPGRADE_TO" -r \
|
||||
'.[] | select((.version|tostring == $ARGS.named.pg_version) and (.cluster == "main")) | .cluster'
|
||||
)"
|
||||
if [ -n "$drop_main_cluster" ]; then
|
||||
pg_dropcluster "$UPGRADE_TO" main --stop
|
||||
fi
|
||||
|
||||
(
|
||||
# Two-stage application of Puppet; we apply the bare-bones
|
||||
# PostgreSQL configuration first, so that FTS will be configured
|
||||
# prior to the pg_upgradecluster.
|
||||
TEMP_CONF_DIR=$(mktemp -d)
|
||||
cp /etc/zulip/zulip.conf "$TEMP_CONF_DIR"
|
||||
ZULIP_CONF="${TEMP_CONF_DIR}/zulip.conf"
|
||||
crudini --set "$ZULIP_CONF" postgresql version "$UPGRADE_TO"
|
||||
|
||||
if [ -f "/usr/share/postgresql/$UPGRADE_FROM/pgroonga_setup.sql.applied" ]; then
|
||||
# This file is intentionally blank, to trigger always running
|
||||
# `ALTER EXTENSION pgroonga UPDATE` and not `CREATE EXTENSION pgroonga`.
|
||||
touch "/usr/share/postgresql/$UPGRADE_TO/pgroonga_setup.sql.applied"
|
||||
fi
|
||||
|
||||
"$ZULIP_PATH"/scripts/zulip-puppet-apply -f --config "$ZULIP_CONF" --tags postgresql_upgrade
|
||||
rm -rf "$TEMP_CONF_DIR"
|
||||
)
|
||||
|
||||
# Capture the output so we know where the path to the post-upgrade scripts is
|
||||
UPGRADE_LOG=$(mktemp "/var/log/zulip/upgrade-postgresql-$UPGRADE_FROM-$UPGRADE_TO.XXXXXXXXX.log")
|
||||
pg_upgradecluster -v "$UPGRADE_TO" "$UPGRADE_FROM" main --method=upgrade --link --no-start | tee "$UPGRADE_LOG"
|
||||
SCRIPTS_PATH=$(grep -o "/var/log/postgresql/pg_upgradecluster-$UPGRADE_FROM-$UPGRADE_TO-main.*" "$UPGRADE_LOG" || true)
|
||||
|
||||
# If the upgrade completed successfully, lock in the new version in
|
||||
# our configuration immediately
|
||||
crudini --set /etc/zulip/zulip.conf postgresql version "$UPGRADE_TO"
|
||||
|
||||
# Make sure the new PostgreSQL is running
|
||||
pg_ctlcluster "$UPGRADE_TO" main start
|
||||
|
||||
# Update the statistics
|
||||
su postgres -c "/usr/lib/postgresql/$UPGRADE_TO/bin/vacuumdb --all --analyze-only --jobs 10"
|
||||
|
||||
# Update extensions
|
||||
if [ -n "$SCRIPTS_PATH" ] && [ -f "$SCRIPTS_PATH/update_extensions.sql" ]; then
|
||||
su postgres -c "psql --file $SCRIPTS_PATH/update_extensions.sql"
|
||||
rm "$SCRIPTS_PATH/update_extensions.sql"
|
||||
fi
|
||||
|
||||
# Start the database up cleanly
|
||||
"$ZULIP_PATH"/scripts/zulip-puppet-apply -f
|
||||
|
||||
# Drop the old data, binaries, and scripts
|
||||
pg_dropcluster "$UPGRADE_FROM" main
|
||||
apt remove -y "postgresql-$UPGRADE_FROM"
|
||||
if [ -n "$SCRIPTS_PATH" ] && [ -f "$SCRIPTS_PATH/delete_old_cluster.sh" ]; then
|
||||
su postgres -c "$SCRIPTS_PATH/delete_old_cluster.sh"
|
||||
rm "$SCRIPTS_PATH/delete_old_cluster.sh"
|
||||
fi
|
||||
|
||||
if [ -n "$SCRIPTS_PATH" ]; then
|
||||
if [ -n "$(ls -A "$SCRIPTS_PATH")" ]; then
|
||||
set +x
|
||||
echo
|
||||
echo
|
||||
echo ">>>>> pg_upgradecluster succeeded, but unexpected post-upgrade scripts"
|
||||
echo " were found:"
|
||||
ls -A1 "$SCRIPTS_PATH"
|
||||
else
|
||||
rmdir "$SCRIPTS_PATH"
|
||||
fi
|
||||
else
|
||||
set +x
|
||||
echo
|
||||
echo
|
||||
echo ">>>>> pg_upgradecluster succeeded, but post-upgrade scripts path could not"
|
||||
echo " be parsed out! Please read the pg_upgradecluster output to understand"
|
||||
echo " the current status of your cluster:"
|
||||
echo " $UPGRADE_LOG"
|
||||
echo " and report this bug with the PostgreSQL $UPGRADE_FROM -> $UPGRADE_TO upgrade to:"
|
||||
echo " https://github.com/zulip/zulip/issues"
|
||||
echo
|
||||
echo
|
||||
fi
|
||||
Reference in New Issue
Block a user