|
|
@ -75,3 +75,179 @@ get_running_container_for_service() { |
|
|
|
|
|
|
|
echo "${containers[0]}" |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
odoo:save() { |
|
|
|
local ADMIN_PASSWORD container_ip container_network_ip container_network cmd dbname="$1" |
|
|
|
|
|
|
|
ADMIN_PASSWORD=$(odoo:get-admin-password) || { |
|
|
|
err "Couldn't retrieve admin password for $SERVICE_NAME." |
|
|
|
return 1 |
|
|
|
} |
|
|
|
|
|
|
|
container_network_ip=$(get_healthy_container_ip_for_service "$SERVICE_NAME" 8069 4) || { |
|
|
|
err "Please ensure that $DARKYELLOW$SERVICE_NAME$NORMAL is running before using '$exname'." |
|
|
|
return 1 |
|
|
|
} |
|
|
|
|
|
|
|
container_ip=${container_network_ip##*:} |
|
|
|
container_network=${container_network_ip%%:*} |
|
|
|
|
|
|
|
DEFAULT_CURL_IMAGE=${DEFAULT_CURL_IMAGE:-docker.0k.io/curl} |
|
|
|
|
|
|
|
|
|
|
|
check_output() { |
|
|
|
local chars |
|
|
|
read -n 2 -r chars |
|
|
|
if [ "$chars" != "PK" ]; then |
|
|
|
out=$(cat) |
|
|
|
errmsg=$(echo "$out" | grep "alert-danger") |
|
|
|
errmsg=${errmsg#*>} |
|
|
|
errmsg=${errmsg%%<*} |
|
|
|
if [ -n "$errmsg" ]; then |
|
|
|
errmsg=$(echo "$errmsg" | recode html..utf8) |
|
|
|
die "$errmsg" |
|
|
|
fi |
|
|
|
err "Unexpected output not matching ZIP signature. Dump probably failed." |
|
|
|
return 1 |
|
|
|
fi |
|
|
|
{ |
|
|
|
echo -n "$chars" |
|
|
|
cat |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
cmd=( |
|
|
|
docker run --rm --network "$container_network" |
|
|
|
"$DEFAULT_CURL_IMAGE" |
|
|
|
-sS |
|
|
|
-X POST |
|
|
|
-F "master_pwd=${ADMIN_PASSWORD}" |
|
|
|
-F "name=${dbname}" |
|
|
|
-F "backup_format=zip" |
|
|
|
http://${container_ip}:8069/web/database/backup |
|
|
|
) |
|
|
|
|
|
|
|
## XXXvlab: contains password, left only for advanced debug |
|
|
|
#debug "${cmd[@]}" |
|
|
|
|
|
|
|
set -o pipefail |
|
|
|
"${cmd[@]}" | check_output && |
|
|
|
info "Requested odoo '$dbname' dump and outputted result to stdout." |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
odoo:version() { |
|
|
|
local odoo_version container |
|
|
|
container="$(get_running_container_for_service "$SERVICE_NAME")" || { |
|
|
|
err "Couldn't find running container for service ${DARKYELLOW}$SERVICE_NAME${NORMAL}." |
|
|
|
return 1 |
|
|
|
} |
|
|
|
|
|
|
|
odoo_version=$(docker exec "$container" python -c 'import odoo.release; print(odoo.release.version)') || { |
|
|
|
err "Failed to get odoo version from ${DARKYELLOW}$SERVICE_NAME${NORMAL}." |
|
|
|
return 1 |
|
|
|
} |
|
|
|
echo "$odoo_version" |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
odoo:load() { |
|
|
|
local ADMIN_PASSWORD container_ip container_network_ip container_network cmd \ |
|
|
|
dbname="$1" neutralize="$2" DEFAULT_CURL_IMAGE RESTORE_TMPDIR |
|
|
|
|
|
|
|
curl_opts=() |
|
|
|
|
|
|
|
ADMIN_PASSWORD=$(odoo:get-admin-password) || { |
|
|
|
err "Couldn't retrieve admin password for ${DARKYELLOW}$SERVICE_NAME${NORMAL}." |
|
|
|
return 1 |
|
|
|
} |
|
|
|
|
|
|
|
odoo_version=$(odoo:version) || return 1 |
|
|
|
if version:lt "$odoo_version" "16.0" && [ -n "$neutralize" ]; then |
|
|
|
err "Option \`\`--neutralize\`\` (or \`\`-n\`\`)" \ |
|
|
|
"is only available for odoo ${WHITE}16.0${NORMAL}+." |
|
|
|
echo " Service ${DARKYELLOW}$SERVICE_NAME${NORMAL} is running odoo ${WHITE}$odoo_version${NORMAL}" >&2 |
|
|
|
return 1 |
|
|
|
fi |
|
|
|
|
|
|
|
if [ -n "$neutralize" ]; then |
|
|
|
curl_opts+=(-F "neutralize_database=true") |
|
|
|
fi |
|
|
|
|
|
|
|
container_network_ip=$(get_healthy_container_ip_for_service "$SERVICE_NAME" 8069 4) || { |
|
|
|
err "Please ensure that $DARKYELLOW$service$NORMAL is running before using '$exname'." |
|
|
|
return 1 |
|
|
|
} |
|
|
|
|
|
|
|
container_ip=${container_network_ip##*:} |
|
|
|
container_network=${container_network_ip%%:*} |
|
|
|
|
|
|
|
|
|
|
|
DEFAULT_CURL_IMAGE=${DEFAULT_CURL_IMAGE:-docker.0k.io/curl} |
|
|
|
|
|
|
|
check_input() { |
|
|
|
local chars |
|
|
|
read -n 2 -r chars |
|
|
|
if [ "$chars" != "PK" ]; then |
|
|
|
err "Unexpected input not matching ZIP signature. Invalid dump." |
|
|
|
echo " First chars: '$chars'" |
|
|
|
return 1 |
|
|
|
fi |
|
|
|
{ |
|
|
|
printf "%s" "$chars" |
|
|
|
cat |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
## Beware that we are not on the host, so we need to create the |
|
|
|
## fifo in a place we can share with the curl container. |
|
|
|
export TMPDIR=/var/cache/compose |
|
|
|
settmpdir RESTORE_TMPDIR |
|
|
|
|
|
|
|
mkfifo "$RESTORE_TMPDIR/fifo" |
|
|
|
|
|
|
|
## Using fifo because if using ``@-`` curl will load all the database |
|
|
|
## in memory before sending it, which is NOT desirable as the size of |
|
|
|
## the database can be greater than available memory. Using fifo, we |
|
|
|
## force the data to be streamed. |
|
|
|
cmd=( |
|
|
|
docker run -i --rm --network "$container_network" |
|
|
|
-v "$RESTORE_TMPDIR/fifo:/tmp/restore/fifo" |
|
|
|
"$DEFAULT_CURL_IMAGE" |
|
|
|
-sS |
|
|
|
-X POST |
|
|
|
-F "master_pwd=${ADMIN_PASSWORD}" |
|
|
|
-F "name=${dbname}" |
|
|
|
"${curl_opts[@]}" |
|
|
|
-F "backup_file=@/tmp/restore/fifo" |
|
|
|
http://${container_ip}:8069/web/database/restore |
|
|
|
) |
|
|
|
|
|
|
|
## XXXvlab: contains password, left only for advanced debug |
|
|
|
#echo "COMMAND: ${cmd[@]}" >&2 |
|
|
|
|
|
|
|
"${cmd[@]}" > "$RESTORE_TMPDIR/out" & |
|
|
|
pid=$! |
|
|
|
check_input > "$RESTORE_TMPDIR/fifo" |
|
|
|
wait "$pid" || { |
|
|
|
die "Posting to odoo restore API through curl was unsuccessfull." |
|
|
|
} |
|
|
|
|
|
|
|
out=$(cat "$RESTORE_TMPDIR/out") |
|
|
|
|
|
|
|
if [[ "$out" == *"<html>"* ]]; then |
|
|
|
errmsg=$(echo "$out" | grep "alert-danger") |
|
|
|
errmsg=${errmsg#*>} |
|
|
|
errmsg=${errmsg%%<*} |
|
|
|
if [ "$errmsg" ]; then |
|
|
|
errmsg=$(echo "$errmsg" | recode html..utf8) |
|
|
|
die "$errmsg" |
|
|
|
fi |
|
|
|
die "Unexpected output. Restore probably failed." |
|
|
|
fi >&2 |
|
|
|
|
|
|
|
info "Restored stdin dump to odoo '$dbname'." |
|
|
|
|
|
|
|
} |