Skip to content
This repository was archived by the owner on Jul 6, 2021. It is now read-only.

Commit 1f26ebc

Browse files
committed
feat: additional connection CLI options added (--pg-**, --ssh-**)
1 parent 83d7555 commit 1f26ebc

9 files changed

+298
-80
lines changed

.gitlab-ci.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,12 @@ test-general:
107107
- vacuumdb -U test_user dbname --analyze
108108
- export ARTIFACTS_PATH=$(pwd)/artifacts && echo $ARTIFACTS_PATH
109109
# First run only for K00X reports
110-
- ./checkup collect -h postgres.test1.node -p 5433 --username test_user --project test --dbname dbname -e 1 --file resources/checks/K000_query_analysis.sh > >(tee -a std.log) 2> >(tee -a err.log >&2)
111-
- ./checkup collect -h postgres.test2.node -p 5434 --username test_user --project test --dbname dbname -e 1 --file resources/checks/K000_query_analysis.sh > >(tee -a std.log) 2> >(tee -a err.log >&2)
110+
- ./checkup collect -h postgres.test1.node --pg-port 5433 --username test_user --project test --dbname dbname -e 1 --file resources/checks/K000_query_analysis.sh > >(tee -a std.log) 2> >(tee -a err.log >&2)
111+
- ./checkup collect -h postgres.test2.node --pg-port 5434 --username test_user --project test --dbname dbname -e 1 --file resources/checks/K000_query_analysis.sh > >(tee -a std.log) 2> >(tee -a err.log >&2)
112112
- ./checkup collect -h postgres.test3.node --username test_user --project test --dbname dbname -e 1 --file resources/checks/K000_query_analysis.sh > >(tee -a std.log) 2> >(tee -a err.log >&2)
113113
# Last run of checkup
114-
- ./checkup collect -h postgres.test1.node -p 5433 --username test_user --project test --dbname dbname -e 1 > >(tee -a std.log) 2> >(tee -a err.log >&2)
115-
- ./checkup collect -h postgres.test2.node -p 5434 --username test_user --project test --dbname dbname -e 1 > >(tee -a std.log) 2> >(tee -a err.log >&2)
114+
- ./checkup collect -h postgres.test1.node --pg-port 5433 --username test_user --project test --dbname dbname -e 1 > >(tee -a std.log) 2> >(tee -a err.log >&2)
115+
- ./checkup collect -h postgres.test2.node --pg-port 5434 --username test_user --project test --dbname dbname -e 1 > >(tee -a std.log) 2> >(tee -a err.log >&2)
116116
- ./checkup collect -h postgres.test3.node --username test_user --project test --dbname dbname -e 1 > >(tee -a std.log) 2> >(tee -a err.log >&2)
117117
- ./checkup process --project test
118118
# Check results

README.md

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
### Demo: [an example of postgres-checkup report](https://gitlab.com/postgres-ai/postgres-checkup-tests/tree/master/1.2.2) (based on CI, single node).
1+
### Demo: [an example of postgres-checkup report](https://gitlab.com/postgres-ai/postgres-checkup-tests/tree/master/1.2.2) (based on CI, multi node).
22

33
***Disclaimer: Conclusions, Recommendations – work in progress.**
44
To treat the data correctly, you need deep Postgres knowledge. Each report
@@ -163,9 +163,19 @@ project directory, as epoch of check `1`. Epoch is a numerical (**integer**) sig
163163
For example: in half a year we can switch to "epoch number `2`".
164164

165165
`-h db2.vpn.local` means: try to connect to host via SSH and then use remote `psql` command to perform checks.
166-
167166
If SSH is not available the local 'psql' will be used (non-psql reports will be skipped).
168167

168+
Also, you can define a specific way to connect: SSH or `psql`:
169+
170+
`--ssh-hostname db2.vpn.local` - SSH will be used for the connection. SSH port can be defined as well
171+
with option `--ssh-port`.
172+
173+
`--pg-hostname db2.vpn.local` - `psql` will be used for the connection. The port where PostgreSQL
174+
accepts connections can be defined with the option `--pg-port`.
175+
176+
In case when `--pg-port` or `--ssh-port` are not defined but `--port` is defined, value of `--port` option
177+
will be used instead of `--pg-port` or `--ssh-port` depending on the current connection type.
178+
169179
For comprehensive analysis, it is recommended to run the tool on the master and
170180
all its replicas – postgres-checkup is able to combine all the information from
171181
multiple nodes to a single report.

checkup

+184-60
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ ALL_ARGS="$@"
1919
OPTIONS_ERROR_EXIT="false"
2020
DEFAULT_LIST_LIMIT=50
2121
DEFAULT_CONNECTION_TIMEOUT=10
22+
DEFAULT_PG_PORT=5432
23+
DEFAULT_SSH_PORT=22
2224
LARGE_DB_ITEMS_COUNT=100000
2325
AVAILABLE_MODES=("collect" "process" "upload" "help" "run")
2426

@@ -377,6 +379,58 @@ validate_arg_type() {
377379
fi
378380
}
379381

382+
#######################################
383+
# Generate psql command
384+
# Globals:
385+
# PSQL_CONN_OPTIONS, HOST, OPTIONS_ERROR_EXIT
386+
# USERNAME, PGPASSWORD, DBNAME, STIMEOUT
387+
# Arguments:
388+
# None
389+
# Returns:
390+
# None
391+
#######################################
392+
generate_psql_cmd() {
393+
local pg_port=$DEFAULT_PG_PORT
394+
if [[ "$PGPORT" != "None" ]]; then
395+
pg_port=$PGPORT
396+
fi
397+
398+
# custom UNIX domain socket directory for PostgreSQL
399+
local psql_unix_socket_option=""
400+
if [[ "${PGSOCKET}" != "None" ]]; then
401+
psql_unix_socket_option=" --host '${PGSOCKET}' "
402+
fi
403+
404+
# custom psql binary path support
405+
local psql_bin="psql"
406+
if [[ "${PSQLBINARY}" != "None" ]]; then
407+
psql_bin="${PSQLBINARY}"
408+
fi
409+
410+
# generate or not PGPASSWORD string (for substitution)
411+
if [[ ! -z ${PGPASSWORD+x} ]]; then
412+
local pgpas_subst="PGPASSWORD=\"${PGPASSWORD}\" " # whitespace in the end of the string
413+
else
414+
local pgpas_subst=""
415+
fi
416+
417+
# use default Postgres username or not
418+
local user_substr=""
419+
if [[ ! -z ${USERNAME+x} ]]; then
420+
user_substr=" -U \"${USERNAME}\" "
421+
fi
422+
423+
# Construct _PSQL macro for usage inside the check scripts
424+
export PSQL_CONN_OPTIONS="--port=${pg_port} --dbname=${DBNAME} ${user_substr} ${psql_unix_socket_option}"
425+
psql_command="${pgpas_subst}${psql_bin} -1 -X -At -q -v ON_ERROR_STOP=1 -P pager=off ${PSQL_CONN_OPTIONS}"
426+
export _PSQL_NO_TIMEOUT="PGAPPNAME=checkup ${psql_command}"
427+
export _PSQL="PGAPPNAME=checkup PGOPTIONS=\"-c statement_timeout=${STIMEOUT}s\" ${psql_command}"
428+
429+
dbg ""
430+
dbg "PSQL_CONN_OPTIONS: $PSQL_CONN_OPTIONS"
431+
dbg ""
432+
}
433+
380434
#######################################
381435
# Validate arguments and and save input variables
382436
# Globals:
@@ -410,18 +464,20 @@ validate_args() {
410464
done
411465

412466
# fill default (not given) psql connection related variables
413-
[[ "${PGPORT}" = "None" ]] && export PGPORT=5432
414467
[[ "${DBNAME}" = "None" ]] && export DBNAME=postgres
415468
[[ "${STIMEOUT}" = "None" ]] && export STIMEOUT=30 # statement timeout
416469
[[ "${USERNAME}" = "None" ]] && export USERNAME=""
417470
[[ "${LISTLIMIT}" = "None" ]] && export LISTLIMIT=${DEFAULT_LIST_LIMIT}
418471
[[ "${CONNTIMEOUT}" = "None" ]] && export CONNTIMEOUT=${DEFAULT_CONNECTION_TIMEOUT} # connection timeout
472+
419473
if [[ "${MODE}" = "None" ]]; then
420474
export MODE="run"
421475
ARG_VALUE[0]="run"
422476
ARG_IS_GIVEN[0]="true"
423477
fi
424478

479+
generate_psql_cmd
480+
425481
if ([[ "$HTML" == "true" ]] || [[ "$PDF" == "true" ]]); then
426482
PANDOC=$(which pandoc || echo -n "0");
427483
if [[ "$PANDOC" == "0" ]]; then
@@ -448,41 +504,6 @@ validate_args() {
448504
fi
449505
fi
450506

451-
# custom UNIX domain socket directory for PostgreSQL
452-
local psql_unix_socket_option=""
453-
if [[ "${PGSOCKET}" != "None" ]]; then
454-
psql_unix_socket_option=" --host '${PGSOCKET}' "
455-
fi
456-
457-
# custom psql binary path support
458-
local psql_bin="psql"
459-
if [[ "${PSQLBINARY}" != "None" ]]; then
460-
psql_bin="${PSQLBINARY}"
461-
fi
462-
463-
# generate or not PGPASSWORD string (for substitution)
464-
if [[ ! -z ${PGPASSWORD+x} ]]; then
465-
local pgpas_subst="PGPASSWORD=\"${PGPASSWORD}\" " # whitespace in the end of the string
466-
else
467-
local pgpas_subst=""
468-
fi
469-
470-
# use default Postgres username or not
471-
local user_substr=""
472-
if [[ ! -z ${USERNAME+x} ]]; then
473-
user_substr=" -U \"${USERNAME}\" "
474-
fi
475-
476-
# Construct _PSQL macro for usage inside the check scripts
477-
export PSQL_CONN_OPTIONS="--port=${PGPORT} --dbname=${DBNAME} ${user_substr} ${psql_unix_socket_option}"
478-
psql_command="${pgpas_subst}${psql_bin} -1 -X -At -q -v ON_ERROR_STOP=1 -P pager=off ${PSQL_CONN_OPTIONS}"
479-
export _PSQL_NO_TIMEOUT="PGAPPNAME=checkup ${psql_command}"
480-
export _PSQL="PGAPPNAME=checkup PGOPTIONS=\"-c statement_timeout=${STIMEOUT}s\" ${psql_command}"
481-
482-
dbg ""
483-
dbg "PSQL_CONN_OPTIONS: $PSQL_CONN_OPTIONS"
484-
dbg ""
485-
486507
# error if mandatory options are not set (print as a stack)
487508
local buf=""
488509
for i in $(seq 0 ${CLI_ARGS_POSSIBLE}); do
@@ -496,6 +517,34 @@ validate_args() {
496517
fi
497518
fi
498519
done
520+
if [[ "$HOST" == "None" ]] && [[ "$SSHHOST" == "None" ]] &&
521+
[[ "$PGHOST" == "None" ]] && ([[ "$MODE" == "collect" ]] || [[ "$MODE" == "run" ]]) ; then
522+
buf="$buf
523+
at least one of options '--hostname', '--ssh-hostname' or '--pg-hostname' must be set"
524+
# mandatory option '--hostname' is not set"
525+
need_fail_exit=true
526+
OPTIONS_ERROR_EXIT=true
527+
fi
528+
529+
local hosts=0
530+
[[ "$SSHHOST" != "None" ]] && hosts=$((hosts + 1))
531+
[[ "$PGHOST" != "None" ]] && hosts=$((hosts + 1))
532+
[[ "$HOST" != "None" ]] && hosts=$((hosts + 1))
533+
534+
if [[ $hosts -gt 1 ]]; then
535+
buf="$buf
536+
only one of options '--hostname', '--ssh-hostname' or '--pg-hostname' may be used"
537+
need_fail_exit=true
538+
OPTIONS_ERROR_EXIT=true
539+
fi
540+
541+
if [[ "$SSHPORT" != "None" ]] && ([[ "$PGHOST" != "None" ]] || [[ "$HOST" != "None" ]]) ; then
542+
buf="$buf
543+
'--ssh-port' may be used only with '--ssh-hostname'"
544+
need_fail_exit=true
545+
OPTIONS_ERROR_EXIT=true
546+
fi
547+
499548
if [[ "$need_fail_exit" = "true" ]]; then
500549
usage "$buf" "1"
501550
fi
@@ -700,7 +749,7 @@ is_in_recovery() {
700749
dbg "host $HOST is 'standby'"
701750
return 0
702751
else
703-
msg "ERROR: Cannot connect to the host: ${HOST}."
752+
msg "ERROR: Cannot connect to the host: ${HOST}"
704753
exit 1
705754
fi
706755
return 13
@@ -938,6 +987,73 @@ glue_md_reports() {
938987
fi
939988
}
940989

990+
#######################################
991+
# Configure SSH connection
992+
# Globals:
993+
# CHECK_HOST_CMD, SSH_SUPPORT, SSHPORT, PORT
994+
# Arguments:
995+
# (text) host name
996+
# Returns:
997+
# Integer
998+
#######################################
999+
configure_ssh_connection() {
1000+
hostname=$1
1001+
1002+
if [[ "$SSHPORT" == "None" ]]; then
1003+
if [[ "$PORT" != "None" ]]; then
1004+
SSHPORT=$PORT
1005+
else
1006+
SSHPORT=$DEFAULT_SSH_PORT
1007+
fi
1008+
fi
1009+
1010+
if native_hostname=$(ssh -p ${SSHPORT} -o ConnectTimeout=10 ${hostname} "hostname" 2>/dev/null); then
1011+
# ssh to remote host and use local psql (default)
1012+
export CHECK_HOST_CMD="ssh ${hostname}"
1013+
export SSH_SUPPORT="true"
1014+
return 0
1015+
else
1016+
return 1
1017+
fi
1018+
}
1019+
1020+
#######################################
1021+
# Configure psql connection
1022+
# Globals:
1023+
# CHECK_HOST_CMD, SSH_SUPPORT, PGPORT, PORT
1024+
# Arguments:
1025+
# (text) host name
1026+
# Returns:
1027+
# Integer
1028+
#######################################
1029+
configure_psql_connection() {
1030+
hostname=$1
1031+
1032+
if [[ "$PGPORT" == "None" ]]; then
1033+
if [[ "$PORT" != "None" ]]; then
1034+
PGPORT=$PORT
1035+
else
1036+
PGPORT=$DEFAULT_PG_PORT
1037+
fi
1038+
generate_psql_cmd
1039+
fi
1040+
1041+
export CHECK_HOST_CMD="bash -e -u -o pipefail -c"
1042+
1043+
# use local psql and connect to remote postgres without ssh
1044+
local re="127\.0"
1045+
if [[ "${hostname}" =~ $re || "${hostname}" = "localhost" ]]; then
1046+
# keep _PSQL and _PSQL_NO_TIMEOUT as is, use UNIX domain socket for psql
1047+
true
1048+
else
1049+
# use TCP for psql
1050+
export _PSQL="PGCONNECT_TIMEOUT=${CONNTIMEOUT} ${_PSQL} -h ${hostname}"
1051+
export _PSQL_NO_TIMEOUT="${_PSQL_NO_TIMEOUT} -h ${hostname}"
1052+
fi
1053+
1054+
export SSH_SUPPORT="false"
1055+
}
1056+
9411057
#######################################
9421058
# Check rights, set global variables, etc.
9431059
# Globals:
@@ -949,31 +1065,34 @@ glue_md_reports() {
9491065
# Integer
9501066
#######################################
9511067
host_pre_start_checks() {
952-
# choise host connection command
953-
# while checking ssh support
954-
if native_hostname=$(ssh $HOST "hostname" 2>/dev/null); then
955-
# ssh to remote host and use local psql (default)
956-
export CHECK_HOST_CMD="ssh ${HOST}"
957-
export SSH_SUPPORT="true"
1068+
if [[ "$SSHHOST" != "None" ]]; then
1069+
# ssh mode
1070+
if configure_ssh_connection $SSHHOST; then
1071+
msg "Connection type (specified): SSH ($SSHHOST:$SSHPORT)"
1072+
export HOST=$SSHHOST
1073+
else
1074+
msg "Connection type (specified): SSH ($SSHHOST:$SSHPORT)"
1075+
msg "ERROR: Cannot connect to the host: ${SSHHOST}:${SSHPORT} via SSH"
1076+
exit 1
1077+
fi
1078+
elif [[ "$PGHOST" != "None" ]]; then
1079+
# psql mode
1080+
if configure_psql_connection $PGHOST; then
1081+
msg "Сonnection type (specified): PostgreSQL ($PGHOST:$PGPORT)"
1082+
export HOST=$PGHOST
1083+
fi
9581084
else
959-
# swap ssh with bash
960-
export CHECK_HOST_CMD="bash -e -u -o pipefail -c"
961-
962-
# use local psql and connect to remote postgres without ssh
963-
local re="127\.0"
964-
if [[ "${HOST}" =~ $re || "${HOST}" = "localhost" ]]; then
965-
# keep _PSQL and _PSQL_NO_TIMEOUT as is, use UNIX domain socket for psql
966-
true
1085+
# auto detect connection command
1086+
if configure_ssh_connection $HOST; then
1087+
msg "Connection type (auto-detected): SSH ($HOST:$SSHPORT)"
9671088
else
968-
# use TCP for psql
969-
export _PSQL="PGCONNECT_TIMEOUT=${CONNTIMEOUT} ${_PSQL} -h ${HOST}"
970-
export _PSQL_NO_TIMEOUT="${_PSQL_NO_TIMEOUT} -h ${HOST}"
1089+
msg "Cannot connect to the host: ${HOST}:${SSHPORT} via SSH"
1090+
configure_psql_connection $HOST;
1091+
msg "Connection type (auto-detected): PostgreSQL ($HOST:$PGPORT)"
9711092
fi
972-
973-
export SSH_SUPPORT="false"
1093+
export HOST
9741094
fi
9751095

976-
export HOST
9771096
dbg "CHECK_HOST_CMD: '${CHECK_HOST_CMD}'"
9781097
dbg "HOST: '${HOST}'"
9791098
dbg "_PSQL: '${_PSQL}'"
@@ -1132,8 +1251,6 @@ run_checks() {
11321251
test -d "${PROJECT_DIR}" || mkdir -p "${PROJECT_DIR}"
11331252

11341253
# perform all checks from './resources/checks/' directory
1135-
msg
1136-
msg "########## Perform checks for host '${HOST}':"
11371254
if is_in_recovery; then
11381255
ROLE="standby"
11391256
else
@@ -1151,6 +1268,8 @@ run_checks() {
11511268
export IS_LARGE_DB=0
11521269
fi
11531270

1271+
msg
1272+
msg "########## Perform checks for host '${HOST}':"
11541273
local output
11551274
for CURRENT_CHECK_FNAME in "${SCRIPT_DIR}"/resources/checks/*_*.sh; do
11561275
[[ -e "${CURRENT_CHECK_FNAME}" ]] || continue
@@ -1332,8 +1451,13 @@ run_upload() {
13321451

13331452
######### COMMANDS WRAPPERS ###########
13341453
ssh() {
1454+
local ssh_port=$DEFAULT_SSH_PORT
1455+
if [[ "$SSHPORT" != "None" ]]; then
1456+
ssh_port=$SSHPORT
1457+
fi
1458+
13351459
local ssh_timeout_options="-o ConnectTimeout=${CONNTIMEOUT} -o ServerAliveInterval=6 -o ServerAliveCountMax=5"
1336-
local ssh_options="-o StrictHostKeyChecking=no -o Compression=no -o BatchMode=yes ${ssh_timeout_options}"
1460+
local ssh_options="-p ${ssh_port} -o StrictHostKeyChecking=no -o Compression=no -o BatchMode=yes ${ssh_timeout_options}"
13371461

13381462
local ssh_master_socket='/tmp/ssh_pg_check_%h_%p_%r'
13391463
local ssh_master_options="-o ControlMaster=auto -o ControlPersist=yes"

0 commit comments

Comments
 (0)