oshipka/oshipka.sh

442 lines
13 KiB
Bash
Raw Permalink Normal View History

2020-03-18 12:32:40 +01:00
#!/usr/bin/env bash
if [ -v $OSHIPKA_PATH ]; then
echo "You need to specify OSHIPKA_PATH env variable"
exit 1
fi
echo "oshipka is at: $OSHIPKA_PATH"
#!/usr/bin/env bash
HELP="
2020-06-04 16:40:52 +02:00
Usage $0 [ bootstrap | model | db_migrate | db_upgrade | db_populate | db_recreate | db_purge_recreate | init | worker | web | venv | install | link | cert ]
2020-03-18 12:32:40 +01:00
bootstrap [PROJECT_PATH] Create a new project in PROJECT_PATH
2020-05-02 22:28:37 +02:00
init Install dev env
2020-06-27 20:32:12 +02:00
download_sensitive Download sensitive
2020-05-02 22:28:37 +02:00
2020-06-04 16:40:52 +02:00
model Create or update a model from files in webapp/view_models/*.yaml
db_migrate DB migration
db_upgrade DB upgrade to last migration
db_populate Populate db with data from data_static/ and populate.py
2021-12-22 09:36:42 +01:00
db_recreate Delete the database, recreate to latest migration
db_recreate_populate Same as db_recreate and populate
db_purge_recreate_populate Same as db_recreate_populate but also purge the migrations
2020-06-04 16:40:52 +02:00
2020-06-29 11:00:34 +02:00
translate Translations subcommand
2021-10-24 12:53:09 +02:00
ca Create oshipka certificate authority (Oshipka CA)
cert_dev [DOMAIN] Generate dev certificate signed by Oshipka CA
2020-03-19 14:13:58 +01:00
worker Start worker
web Start webapp
2020-05-02 22:28:37 +02:00
2020-03-26 09:17:17 +01:00
venv Init venv
install Install requirements
2020-04-15 21:13:28 +02:00
link Link dev oshipka
2020-04-15 21:33:31 +02:00
prod Run in prod
2020-06-21 11:17:34 +02:00
prod_install Install in prod
2020-04-15 21:13:28 +02:00
cert [DOMAIN] Install certificate
2020-03-18 12:32:40 +01:00
"
2020-06-29 11:00:34 +02:00
HELP_TRANSLATION="
USAGE ./manage.sh translate [extract|gen {lang}|compile|update]
extract Extract strings in files as defined in translations/babel.cfg
gen {lang} Init translations for {lang}
compile Compile all translations
update Use after a new extract - it may mark strings as fuzzy.
"
command_translate() {
2020-07-08 14:38:55 +02:00
shift
2020-06-29 11:00:34 +02:00
TRANSLATE_COMMAND=$1
shift
2020-07-08 14:38:55 +02:00
source venv/bin/activate
2020-06-29 11:00:34 +02:00
case "$TRANSLATE_COMMAND" in
extract) pybabel extract -F translations/babel.cfg -o translations/messages.pot .
;;
gen) pybabel init -i translations/messages.pot -d translations -l "$@"
;;
compile) pybabel compile -d translations
;;
update) pybabel update -i translations/messages.pot -d translations
;;
*) >&2 echo -e "${HELP_TRANSLATION}"
;;
esac
return $?
}
2021-10-24 12:53:09 +02:00
ca () {
if [ -f ${OSHIPKA_PATH}/ssl/oshipka_ca.pem ]; then
echo "Oshipka CA already exists"
exit 1;
fi
echo "Creating Oshipka CA..."
mkdir -p ${OSHIPKA_PATH}/ssl
cd ${OSHIPKA_PATH}/ssl || exit
openssl genrsa -out oshipka_ca.key 2048
openssl req -x509 -new -nodes -key oshipka_ca.key -sha256 -days 1825 -out oshipka_ca.pem -subj "/C=/ST=/L=/O=Oshipka Web Development CA/OU=/CN=oshipka_web_development_ca"
}
cert_dev () {
shift
DOMAIN=$1
if [ -f webapp/ssl/cert.crt ]; then
echo "Certificate already exists"
exit 1;
elif [ ! -f ${OSHIPKA_PATH}/ssl/oshipka_ca.key ]; then
echo "Oshipka CA not found, generating..."
ca
fi
if [ -z "${DOMAIN}" ]; then
DOMAIN=$(basename `pwd`)
fi
mkdir -p webapp/ssl
echo "Create CSR for ${DOMAIN}"
openssl genrsa -out "webapp/ssl/cert.key" 2048
openssl req -new -key "webapp/ssl/cert.key" -out "webapp/ssl/cert.csr" -subj "/C=/ST=/L=/O=Oshipka Web Development/OU=/CN=${DOMAIN}.localhost"
cat > "webapp/ssl/cert.ext" << EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = ${DOMAIN}.localhost
EOF
echo "Create self-signed certificate"
openssl x509 -req -in "webapp/ssl/cert.csr" -CA ${OSHIPKA_PATH}/ssl/oshipka_ca.pem -CAkey ${OSHIPKA_PATH}/ssl/oshipka_ca.key -CAcreateserial -out "webapp/ssl/cert.crt" -days 825 -sha256 -extfile "webapp/ssl/cert.ext"
rm "webapp/ssl/cert.ext" "webapp/ssl/cert.csr"
}
2020-06-29 11:00:34 +02:00
2020-03-19 14:13:58 +01:00
worker () {
2020-03-25 16:23:24 +01:00
source venv/bin/activate
2020-03-20 12:44:42 +01:00
python worker.py
2020-03-19 14:13:58 +01:00
}
web () {
2020-03-25 16:23:24 +01:00
source venv/bin/activate
2020-03-19 14:13:58 +01:00
python run.py
}
2023-07-21 22:51:22 +02:00
init_apt() {
sudo apt-get update
sudo apt-get install -y build-essential libssl-dev libffi-dev python3-dev
}
2020-03-25 16:23:24 +01:00
init_venv() {
virtualenv -p python3 venv
}
install_reqs() {
source venv/bin/activate
2020-06-21 21:18:50 +02:00
pip3 install --upgrade pip --trusted-host pypi.org --trusted-host files.pythonhosted.org
2020-03-25 16:23:24 +01:00
pip install -r requirements.txt
}
2020-04-15 21:13:28 +02:00
link_dev_oshipka() {
source venv/bin/activate
pip install -e ${OSHIPKA_PATH}
2020-05-02 13:40:29 +02:00
pip install -e ${TWW_PATH}
2020-04-15 21:13:28 +02:00
}
2020-06-27 20:32:12 +02:00
download_sensitive() {
if [ ! -f sensitive.py ]; then
echo "File sensitive.py NOT FOUND"
2020-08-11 14:35:25 +02:00
if [ -f sensitive_dev.py ]; then
echo "Copying sensitive_dev for dev env"
cp sensitive_dev.py sensitive.py
else
exit 1;
fi
2020-06-27 20:32:12 +02:00
fi
}
2020-05-02 22:28:37 +02:00
init() {
2023-07-21 22:51:22 +02:00
init_apt
2020-05-02 22:28:37 +02:00
init_venv
install_reqs
link_dev_oshipka
2020-06-27 20:32:12 +02:00
mkdir -p data
db_upgrade
download_sensitive
db_populate
2020-05-02 22:28:37 +02:00
}
2020-04-15 21:13:28 +02:00
install_cert() {
PROJECT_DOMAIN=$1
sudo apt install certbot
2020-06-21 21:36:31 +02:00
sudo certbot certonly --authenticator standalone --installer nginx --pre-hook "service nginx stop" --post-hook "service nginx start" --redirect --agree-tos --no-eff-email --email danieltcv@gmail.com -d ${PROJECT_DOMAIN} --no-bootstrap
2020-04-15 21:13:28 +02:00
}
2020-03-18 12:32:40 +01:00
bootstrap() {
shift
PROJECT_PATH=$1
if [[ -z "$PROJECT_PATH" ]]; then
read -p "Enter project path: " PROJECT_PATH
fi
if [[ -z "$PROJECT_PATH" ]]; then
echo "ERROR: Specify project path"
exit 1
else
echo "INFO: Project path: $PROJECT_PATH"
PROJECT_PATH=`realpath $PROJECT_PATH`
echo "INFO: Absolute project path: $PROJECT_PATH"
if [[ "$PROJECT_PATH" == $OSHIPKA_PATH* ]]; then
echo "ERROR: Project path can't be inside this directory. Exiting..."
exit 1
fi
if [ -d $PROJECT_PATH ]; then
echo "ERROR: Project path exists. Please remove or specify another. Exiting..."
exit 1
else
echo "INFO: Project path doesn't exist, creating..."
mkdir -p $PROJECT_PATH
fi
fi
PROJECT_NAME=$(basename $PROJECT_PATH)
echo "INFO: Bootstrapping project $PROJECT_NAME..."
mkdir -p ${PROJECT_PATH}
cp -r ${OSHIPKA_PATH}/bootstrap/* ${PROJECT_PATH}/
2020-03-25 16:23:24 +01:00
cp ${OSHIPKA_PATH}/bootstrap/.gitignore ${PROJECT_PATH}/.gitignore
2020-06-04 22:11:57 +02:00
mkdir ${PROJECT_PATH}/data
2020-03-26 09:17:17 +01:00
cd ${PROJECT_PATH}
2021-10-24 12:53:09 +02:00
sed -i "s/PROJECT_NAME.localhost:5000/${PROJECT_NAME}.localhost:5000/" config.py
cert_dev
2020-03-25 16:23:24 +01:00
init_venv
2020-04-15 21:13:28 +02:00
link_dev_oshipka
2020-06-04 15:24:18 +02:00
source venv/bin/activate
2021-05-14 23:37:30 +02:00
model
2020-06-04 15:24:18 +02:00
python manager.py db init
2020-06-04 16:40:52 +02:00
python manager.py db migrate -m "001"
_post_migrate
2020-06-04 15:24:18 +02:00
python manager.py db upgrade
2021-10-25 08:38:17 +02:00
command_translate "" extract
command_translate "" gen en
# TODO: sed acts on a line-by-line
# sed -i 's/msgid "Project"/msgstr ${PROJECT_NAME}/' translations/en/LC_MESSAGES/messages.po
command_translate "" compile
2020-07-08 14:38:55 +02:00
git init .
git add .
git commit -m "Initial commit"
2020-03-18 12:32:40 +01:00
}
2020-04-15 21:33:31 +02:00
run_in_prod() {
shift
PORT=$1
2020-04-15 21:56:06 +02:00
source venv/bin/activate
2020-04-15 21:33:31 +02:00
gunicorn -w 4 -b 0.0.0.0:${PORT} run:app
}
2020-06-21 11:17:34 +02:00
prod_install() {
shift
2020-06-27 20:32:12 +02:00
if [ ! -f ${OSHIPKA_PATH}/provision/auto_dns/sensitive.py ]; then
echo "File ${OSHIPKA_PATH}/provision/auto_dns/sensitive.py NOT FOUND"
exit 1;
fi
sudo apt install -y nginx dnsutils
2020-06-21 11:17:34 +02:00
source venv/bin/activate
PROJECT_NAME=$(basename `pwd`)
2020-06-21 17:45:33 +02:00
echo "1/6 Generating service and config files..."
python "${OSHIPKA_PATH}/provision/prod_mgmt.py"
2020-06-21 11:17:34 +02:00
if [ -f "/etc/systemd/system/${PROJECT_NAME}.service" ]; then
echo "Service gunicorn for ${PROJECT_NAME} service exists."
systemctl status ${PROJECT_NAME}
else
echo "Installing '$PROJECT_NAME' gunicorn service"
sudo cp "${OSHIPKA_PATH}/provision/tmp/${PROJECT_NAME}.service" /etc/systemd/system/
sudo systemctl enable "${PROJECT_NAME}"
sudo systemctl start "${PROJECT_NAME}"
fi
2020-06-21 17:45:33 +02:00
echo "2/6 Installing '$PROJECT_NAME' worker service"
2020-06-21 11:17:34 +02:00
if [ -f "/etc/systemd/system/${PROJECT_NAME}_worker.service" ]; then
echo "Service worker for ${PROJECT_NAME} service exists."
systemctl status "${PROJECT_NAME}_worker"
else
sudo cp "${OSHIPKA_PATH}/provision/tmp/${PROJECT_NAME}_worker.service" /etc/systemd/system/
sudo systemctl enable "${PROJECT_NAME}_worker"
sudo systemctl start "${PROJECT_NAME}_worker"
fi
NGINX_CONFIG_FILE=$(basename `find $OSHIPKA_PATH/provision/tmp -name *.conf`)
DOMAIN=$(basename -s .conf $NGINX_CONFIG_FILE)
2020-06-21 17:45:33 +02:00
echo "3/6 Installing '$DOMAIN' domain..."
python "${OSHIPKA_PATH}/provision/auto_dns/set_domain_ipv4.py" "$DOMAIN"
sudo systemctl start nginx
2020-07-01 10:32:06 +02:00
echo "Enabling firewall rule -> 80/tcp..."
sudo ufw allow proto tcp to any port 80
2020-06-21 17:45:33 +02:00
echo "4/6 Installing '$PROJECT_NAME' insecure nginx config..."
2020-06-21 21:18:50 +02:00
if [ -f "/etc/nginx/sites-available/${DOMAIN}.insecure" ]; then
2020-06-21 17:45:33 +02:00
echo "Insecure Nginx config for ${PROJECT_NAME} available."
2020-06-21 21:18:50 +02:00
if [ -f "/etc/nginx/sites-enabled/${DOMAIN}_insecure" ]; then
2020-06-21 17:45:33 +02:00
echo "Nginx config for ${PROJECT_NAME} enabled."
else
echo "Nginx config for ${PROJECT_NAME} NOT enabled."
fi
else
echo "Installing insecure nginx config for ${PROJECT_NAME} -> enabling + available."
2020-06-21 21:18:50 +02:00
sudo cp "${OSHIPKA_PATH}/provision/tmp/${DOMAIN}.insecure" /etc/nginx/sites-available/
sudo ln -s "/etc/nginx/sites-available/${DOMAIN}.insecure" "/etc/nginx/sites-enabled/${DOMAIN}.insecure"
2020-06-21 17:45:33 +02:00
sudo systemctl reload nginx
fi
2020-06-21 11:17:34 +02:00
2020-06-21 17:45:33 +02:00
echo "5/6 Installing '$PROJECT_NAME' certificate..."
2020-06-21 11:17:34 +02:00
install_cert $DOMAIN
2020-06-21 17:45:33 +02:00
echo "6/6 Installing '$PROJECT_NAME' secure nginx config..."
echo "Enabling firewall rule for 192.168.1.1 -> 443/tcp..."
2020-07-01 10:32:06 +02:00
sudo ufw allow proto tcp to any port 443
2020-06-21 17:45:33 +02:00
echo "Removing '$PROJECT_NAME' insecure nginx config..."
2020-06-21 21:36:31 +02:00
sudo rm "/etc/nginx/sites-available/${DOMAIN}.insecure" "/etc/nginx/sites-enabled/${DOMAIN}.insecure"
2020-06-27 20:55:31 +02:00
# PROBLEM: BIO_new_file("/etc/nginx/dhparam.pem") failed
# SOLUTION: sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048
if [ ! -f "/etc/nginx/dhparam.pem" ]; then
sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048
fi
2020-06-21 11:17:34 +02:00
if [ -f "/etc/nginx/sites-available/${NGINX_CONFIG_FILE}" ]; then
echo "Nginx config for ${PROJECT_NAME} available."
if [ -f "/etc/nginx/sites-enabled/${NGINX_CONFIG_FILE}" ]; then
echo "Nginx config for ${PROJECT_NAME} enabled."
else
echo "Nginx config for ${PROJECT_NAME} NOT enabled."
fi
2020-06-21 17:45:33 +02:00
else
2020-06-21 11:17:34 +02:00
echo "Installing nginx config for ${PROJECT_NAME} -> enabling + available."
2020-06-21 17:45:33 +02:00
sudo cp "${OSHIPKA_PATH}/provision/tmp/${NGINX_CONFIG_FILE}" /etc/nginx/sites-available/
2020-06-21 11:17:34 +02:00
sudo ln -s "/etc/nginx/sites-available/${NGINX_CONFIG_FILE}" "/etc/nginx/sites-enabled/${NGINX_CONFIG_FILE}"
2020-06-21 17:45:33 +02:00
sudo systemctl reload nginx
2020-06-21 11:17:34 +02:00
fi
2020-06-21 21:36:31 +02:00
# PROBLEM : Certificates missing
# SOLUTION: rm /etc/ssl/certs/ca-certificates.crt
# sudo update-ca-certificates in virtual environment.
2020-06-21 11:17:34 +02:00
}
2020-06-03 16:00:51 +02:00
model() {
shift
source venv/bin/activate
2020-06-03 18:11:37 +02:00
python "${OSHIPKA_PATH}/vm_gen/vm_gen.py" "`pwd`"
2020-06-03 16:00:51 +02:00
}
2020-06-04 15:24:18 +02:00
db_migrate() {
shift
source venv/bin/activate
2020-06-22 17:20:13 +02:00
next_id=$(printf "%03d" $(($(ls -la migrations/versions/*.py | wc -l)+1)))
python manager.py db migrate -m "${next_id}"
2020-06-04 15:24:18 +02:00
_post_migrate
}
db_upgrade() {
shift
source venv/bin/activate
2020-07-13 10:38:29 +02:00
mkdir -p data
2020-06-04 15:24:18 +02:00
python manager.py db upgrade
}
2021-12-22 09:36:42 +01:00
db_purge_recreate_populate() {
2020-06-04 16:40:52 +02:00
shift
source venv/bin/activate
2021-05-08 14:14:54 +02:00
rm -rf data/db.sqlite data/search_index migrations/ data/media
2020-06-04 16:40:52 +02:00
python manager.py db init
2021-10-24 12:53:09 +02:00
model
2020-06-04 16:40:52 +02:00
db_migrate
db_upgrade
db_populate
}
db_populate() {
shift
source venv/bin/activate
python init_populate.py
}
db_recreate() {
shift
source venv/bin/activate
rm -rf data/db.sqlite data/search_index
db_upgrade
2021-12-22 09:36:42 +01:00
}
db_recreate_populate() {
shift
db_recreate
2020-06-04 16:40:52 +02:00
db_populate
}
2020-06-04 15:24:18 +02:00
_post_migrate() {
for i in migrations/versions/*.py; do
sed -i "s/sqlalchemy_utils.types.choice.ChoiceType(length=255), /sa.String(), / " "$i";
2020-06-04 16:40:52 +02:00
sed -i "s/oshipka.persistance.LiberalBoolean(), /sa.Boolean(), / " "$i";
2020-06-04 15:24:18 +02:00
done
}
2020-03-18 12:32:40 +01:00
command_main() {
INITIAL_COMMAND=$1
case "$INITIAL_COMMAND" in
bootstrap) bootstrap "$@"
2020-03-19 14:13:58 +01:00
;;
2020-06-03 16:00:51 +02:00
model) model "$@"
;;
2020-06-04 15:24:18 +02:00
db_migrate) db_migrate "$@"
;;
db_upgrade) db_upgrade "$@"
;;
2020-06-04 16:40:52 +02:00
db_populate) db_populate "$@"
;;
db_recreate) db_recreate "$@"
;;
2021-12-22 09:36:42 +01:00
db_recreate_populate) db_recreate_populate "$@"
;;
db_purge_recreate_populate) db_purge_recreate_populate "$@"
2020-06-04 16:40:52 +02:00
;;
2020-06-29 11:00:34 +02:00
translate) command_translate "$@"
;;
2020-05-02 22:28:37 +02:00
init) init "$@"
;;
2020-06-27 20:32:12 +02:00
download_sensitive) download_sensitive "$@"
;;
2020-03-19 14:13:58 +01:00
worker) worker "$@"
;;
2020-03-26 09:17:17 +01:00
web) web "$@"
;;
venv) init_venv "$@"
;;
2021-10-24 12:53:09 +02:00
ca) ca "$@"
;;
cert_dev) cert_dev "$@"
;;
2020-03-26 09:17:17 +01:00
install) install_reqs "$@"
;;
2020-04-15 21:13:28 +02:00
link) link_dev_oshipka "$@"
;;
2020-04-15 21:33:31 +02:00
prod) run_in_prod "$@"
;;
2020-06-21 11:17:34 +02:00
prod_install) prod_install "$@"
;;
2020-06-21 17:45:33 +02:00
cert) shift && install_cert "$@"
2020-03-18 12:32:40 +01:00
;;
*) >&2 echo -e "${HELP}"
return 1
;;
esac
return $?
}
2020-03-26 09:17:17 +01:00
command_main "$@"