From 5a3b8d5b416a43fa020677ed6ac1b0ec80359642 Mon Sep 17 00:00:00 2001 From: Valentin Lab Date: Wed, 28 Nov 2018 11:35:27 +0100 Subject: [PATCH] new: [postgres,odoo-tecnativa] rewrite to avoid any host direct contact This allows ``compose`` to be run from a docker. --- odoo-tecnativa/actions/load | 37 ++++++++++--- odoo-tecnativa/actions/save | 40 ++++++++++---- postgres/actions/save | 10 +++- postgres/hooks/init | 52 ++++++++---------- .../hooks/postgres_database-relation-joined | 54 ++++++++++++++++--- postgres/lib/common | 31 +++++------ 6 files changed, 153 insertions(+), 71 deletions(-) diff --git a/odoo-tecnativa/actions/load b/odoo-tecnativa/actions/load index 36a9e7fc..87d6094a 100755 --- a/odoo-tecnativa/actions/load +++ b/odoo-tecnativa/actions/load @@ -9,7 +9,6 @@ if [ -z "$SERVICE_DATASTORE" ]; then exit 1 fi -depends curl usage="$exname [-h|--help] SRC_FILE DBNAME" @@ -55,6 +54,13 @@ if ! [ -e "$source" ]; then exit 1 fi +realpath=$(realpath "$source") || exit 1 +dirname="$(dirname "$realpath")" || exit 1 +basename=$(basename "$realpath") || exit 1 +host_path="$(get_host_path "$dirname")" || { + die "Failed to find host path for local directory: $dirname" +} + set -e @@ -78,13 +84,28 @@ fi container="$(echo "$containers" | head -n 1)" ## XXXvlab: taking first ip is probably not a good idea -container_ip="$(get_docker_ips "$container" | head -n 1 | cut -f 2 -d ":")" - -curl -X POST \ - -F "master_pwd=${ADMIN_PASSWORD}" \ - -F "backup_file=@${source}" \ - -F "name=${dbname}" \ - http://${container_ip}:8069/web/database/restore >/dev/null 2>&1 || { +read-0 container_network container_ip < <(get_container_network_ip "$container") + +DEFAULT_CURL_IMAGE=${DEFAULT_CURL_IMAGE:-docker.0k.io/curl} + +debug docker run --network "$container_network" \ + "-v" "$host_path:/tmp/work" \ + "$DEFAULT_CURL_IMAGE" \ + -sS \ + -X POST \ + -F "master_pwd=" \ + -F "backup_file=@/tmp/work/${source}" \ + -F "name=${dbname}" \ + http://${container_ip}:8069/web/database/restore +docker run --network "$container_network" \ + "-v" "$host_path:/tmp/work" \ + "$DEFAULT_CURL_IMAGE" \ + -sS \ + -X POST \ + -F "master_pwd=${ADMIN_PASSWORD}" \ + -F "backup_file=@/tmp/work/${basename}" \ + -F "name=${dbname}" \ + http://${container_ip}:8069/web/database/restore >/dev/null || { die "Querying odoo through curl was unsuccessfull." } diff --git a/odoo-tecnativa/actions/save b/odoo-tecnativa/actions/save index f400c121..bbeb2c5f 100755 --- a/odoo-tecnativa/actions/save +++ b/odoo-tecnativa/actions/save @@ -9,7 +9,6 @@ if [ -z "$SERVICE_DATASTORE" ]; then exit 1 fi -depends curl usage="$exname [-h|--help] [--force|-f] DBNAME DEST_FILENAME" @@ -59,6 +58,12 @@ if [ -e "$output" -a -z "$force" ]; then exit 1 fi +realpath=$(realpath "$output") || exit 1 +dirname="$(dirname "$realpath")" || exit 1 +basename=$(basename "$realpath") || exit 1 +host_path="$(get_host_path "$dirname")" || { + die "Failed to find host path for local directory: $dirname" +} set -e @@ -82,14 +87,31 @@ fi container="$(echo "$containers" | head -n 1)" ## XXXvlab: taking first ip is probably not a good idea -container_ip="$(get_docker_ips "$container" | head -n 1 | cut -f 2 -d ":")" - -curl -X POST \ - -F "master_pwd=${ADMIN_PASSWORD}" \ - -F "name=${dbname}" \ - -F "backup_format=zip" \ - -o "$output" \ - http://${container_ip}:8069/web/database/backup >/dev/null 2>&1 || { +read-0 container_network container_ip < <(get_container_network_ip "$container") + +DEFAULT_CURL_IMAGE=${DEFAULT_CURL_IMAGE:-docker.0k.io/curl} + + +debug docker run --network "$container_network" \ + "-v" "$host_path:/tmp/work" \ + "$DEFAULT_CURL_IMAGE" \ + -X POST \ + -F "master_pwd=" \ + -F "name=${dbname}" \ + -F "backup_format=zip" \ + -o "/tmp/work/$basename" \ + http://${container_ip}:8069/web/database/backup + +docker run --network "$container_network" \ + "-v" "$host_path:/tmp/work" \ + "$DEFAULT_CURL_IMAGE" \ + -sS \ + -X POST \ + -F "master_pwd=${ADMIN_PASSWORD}" \ + -F "name=${dbname}" \ + -F "backup_format=zip" \ + -o "/tmp/work/$basename" \ + http://${container_ip}:8069/web/database/backup || { die "Querying odoo through curl was unsuccessfull." } diff --git a/postgres/actions/save b/postgres/actions/save index d241fb99..b824658e 100755 --- a/postgres/actions/save +++ b/postgres/actions/save @@ -42,6 +42,13 @@ if [ -z "$DEST" ]; then exit 1 fi +realpath=$(realpath "$DEST") || exit 1 +dirname="$(dirname "$realpath")" || exit 1 +basename=$(basename "$realpath") || exit 1 +host_path="$(get_host_path "$dirname")" || { + die "Failed to find host path for local directory: $dirname" +} + if [[ "$dbname" == *"@"* ]]; then IFS="@" read user dbname < <(echo "$dbname") fi @@ -55,7 +62,8 @@ if ! db_has_database "$dbname"; then exit 1 fi -PGM cp "$dbname" "$DEST" || { +db_docker_opts+=("-v" "$host_path:/tmp/work") +PGM cp "$dbname" "/tmp/work/$basename" || { die "pgm command failed !" } info "Saved database '$dbname' into '$DEST'." \ No newline at end of file diff --git a/postgres/hooks/init b/postgres/hooks/init index bc12e68d..60a54467 100755 --- a/postgres/hooks/init +++ b/postgres/hooks/init @@ -11,43 +11,35 @@ ## - SERVICE_CONFIGSTORE Location on host of the CONFIGSTORE of this service - # Please note that postgres detect on its own if its datadir needs to be populated -[ -e ~/.pgpass ] && exit 0 - . lib/common set -e -POSTGRES_ROOT_PASSWORD="$(gen_password)" - -## -## Setting up access from host -## - -ddb < <(echo "ALTER USER postgres WITH ENCRYPTED password '$POSTGRES_ROOT_PASSWORD'") - -sed -ri 's%^host all all 0\.0\.0\.0/0 trust$%host all all 0.0.0.0/0 md5%g' \ - "$SERVICE_DATASTORE/var/lib/postgresql/data/pg_hba.conf" - -docker restart "$container_id" - -## XXXvlab: this won't help support multiple project running on the -## same host -cat < ~/.pgpass +if ! [ -f "$HOST_DB_PASSFILE" ]; then + POSTGRES_ROOT_PASSWORD="$(gen_password)" + ddb < <(echo "ALTER USER postgres WITH ENCRYPTED password '$POSTGRES_ROOT_PASSWORD'") + cat < "$HOST_DB_PASSFILE" *:*:*:postgres:$POSTGRES_ROOT_PASSWORD EOF - -chmod 600 ~/.pgpass - -## -## pgm -## - -echo 'prefix_pg_local_command=" " ## otherwise, will default to sudo -u postgres ' > /root/.pgm.rc - -info "New root password for postgres. " - + chmod 600 "$HOST_DB_PASSFILE" + info "New root password for postgres. " +fi + +if ! egrep "^host all all (0.0.0.0/0|all) md5\$" "$PG_HBA" >/dev/null 2>&1; then + if egrep "^host all all (0.0.0.0/0|all) trust\$" "$PG_HBA" >/dev/null 2>&1; then + sed -ri 's%^host all all (0\.0\.0\.0/0|all) trust$%host all all \1 md5%g' \ + "$PG_HBA" + if is_db_locked; then + ensure_db_docker_running + docker restart "$container_id" + info "Restarted container $container_id" + fi + info "Accepting connection from outside." + else + die "Can't ensure connection from outside. Please update the charm init script." + fi +fi diff --git a/postgres/hooks/postgres_database-relation-joined b/postgres/hooks/postgres_database-relation-joined index a74087cb..ca9c5c11 100755 --- a/postgres/hooks/postgres_database-relation-joined +++ b/postgres/hooks/postgres_database-relation-joined @@ -7,23 +7,51 @@ ## - the target of the link is launched first, and get a chance to ``relation-set`` ## - both side of the scripts get to use ``relation-get``. -## could generate this also if not set -DBNAME=$(relation-get dbname) -[ "$(relation-get password 2>/dev/null)" ] && exit 0 +DBNAME=$(relation-get dbname) || { + DBNAME="$BASE_SERVICE_NAME" + relation-set dbname "$DBNAME" +} + +USER=$(relation-get user) || { + USER="$BASE_SERVICE_NAME" + relation-set user "$USER" +} . lib/common set -e -USER=$(relation-get user) -PASSWORD="$(gen_password)" +## YYY: check that password was not already generated/set for the same user +## use session state storage. + +## is there a previous password set for user $USER ? + +NO_PREVIOUS_PASS= +PREVIOUS_PASSWORD_PATH="$state_tmpdir/$SERVICE_NAME/pwd/$USER" +PREVIOUS_PASSWORD=$(cat "$PREVIOUS_PASSWORD_PATH" 2>/dev/null) || NO_PREVIOUS_PASS=true + +if PASSWORD="$(relation-get password 2>/dev/null)"; then + if [ -z "$NO_PREVIOUS_PASS" -a "$PREVIOUS_PASSWORD" != "$PASSWORD" ]; then + die "Inconsistent password specification for user '$USER' on ${DARKYELLOW}$TARGET_SERVICE_NAME$NORMAL." + fi +else + if [ "$PREVIOUS_PASSWORD" ]; then + PASSWORD="${PREVIOUS_PASSWORD}" + else + PASSWORD="$(gen_password)" + info "Generated a new password for use '$USER'." + fi +fi + + POSTGIS=$(relation-get postgis 2>/dev/null) || true UNACCENT=$(relation-get unaccent 2>/dev/null) || true ensure_db_docker_running +## XXXvlab: should send all these into only one docker... db_has_database "$DBNAME" || UNACCENT="$UNACCENT" POSTGIS="$POSTGIS" db_create "$DBNAME" if ! db_has_user "$USER"; then info "Creating a new user $USER." @@ -32,7 +60,14 @@ else info "Updating password of user $USER." db_change_password "$USER" "$PASSWORD" fi + db_grant_rights "$DBNAME" "$USER" +info "Granted rights on database '$DBNAME' to user '$USER'." + + +## +## PGPASS +## pgpass_line="*:*:*:$USER:$PASSWORD" pgpass_file="$CONFIGSTORE/$BASE_SERVICE_NAME/root/.pgpass" @@ -44,4 +79,11 @@ mkdir -p "$(dirname "$pgpass_file")" echo "$pgpass_line" >> "$pgpass_file" chmod 600 "$pgpass_file" -relation-set password "$PASSWORD" \ No newline at end of file + +## +## Saving password +## + +relation-set password "$PASSWORD" +mkdir -p "$(dirname "$PREVIOUS_PASSWORD_PATH")" +echo "$PASSWORD" > "$PREVIOUS_PASSWORD_PATH" diff --git a/postgres/lib/common b/postgres/lib/common index cfff3b45..b2cac81c 100644 --- a/postgres/lib/common +++ b/postgres/lib/common @@ -2,9 +2,13 @@ include pretty -export DB_NAME="postgres" +export DB_NAME="$SERVICE_NAME" ## general type of database (ie: postgres/mysql...) export DB_DATADIR=/var/lib/postgresql/data -export DB_PASSFILE=/root/.pgpass + +export DATA_DIR=$SERVICE_DATASTORE$DB_DATADIR +export HOST_DB_PASSFILE="$DATA_DIR/pgpass" +export CLIENT_DB_PASSFILE="/root/.pgpass" +export PG_HBA="$DATA_DIR/pg_hba.conf" is_db_locked() { @@ -15,8 +19,12 @@ is_db_locked() { _set_db_params() { local docker_ip="$1" docker_network="$2" - export db_docker_opts="--network $docker_network -e PGHOST=$docker_ip -e PGUSER=postgres" - export db_cmd_opts= + db_docker_opts+=("--network" "$docker_network" + "-e" PGHOST="$docker_ip" + "-e" PGUSER=postgres + "-e" prefix_pg_local_command=' ') + + db_cmd_opts+=() } ddb () { dcmd psql -qAt "$@"; } @@ -85,19 +93,8 @@ db_change_password() { PGM() { ensure_db_docker_running &2 - - docker run -i --rm \ - $db_docker_opts -e prefix_pg_local_command=' ' \ - --entrypoint pgm "$DOCKER_BASE_IMAGE" $db_cmd_opts "$@" - + echo "${db_docker_opts[@]}" + dcmd pgm "$@" } db_grant_rights () {