3
# Script to configure an OpenVista instance for replication
5
# Copyright (C) 2010 Medsphere Systems Corporation
7
# This program is free software; you can redistribute it and/or modify it
8
# solely under the terms of the GNU Affero General Public License version 3
9
# as published by the Free Software Foundation.
11
# This program is distributed in the hope that it will be useful, but WITHOUT
12
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
16
# You should have received a copy of the GNU Affero General Public License
17
# along with this program. If not, see <http://www.gnu.org/licenses>.
19
# You can contact Medsphere Systems Corporation headquarters at 1917 Palomar
20
# Oaks Way, Suite 200, Carlsbad, CA 92008 or at legal@medsphere.com.
24
. /usr/lib/openvista/functions
26
log_command_usage "$@"
28
this_script=ovinstancerepl
34
# Display version information.
38
Copyright (C) 2010 Medsphere Systems Corporation
40
ovinstancerepl is powered by Medsphere and part of a suite of open source
41
utilities licensed under the AGPL, available at http://medsphere.org.
47
# Display usage information.
50
Usage: ovinstancerepl -a PRIMARY_IP -b SECONDARY_IP -m MUPIP_PORT -r RSYNC_PORT
51
[-w OTHER_INSTANCE] [-f BACKUP_FILE] [-i INSTSECONDARY]
52
[-k KEYS_DIRECTORY] primary|secondary INSTANCE_NAME
53
or ovinstancerepl [-s] status|list INSTANCE_NAME
54
or ovinstancerepl test|stop|start INSTANCE_NAME
55
or ovinstancerepl [-f BACKUP_FILE] resync INSTANCE_NAME
58
Configure an OpenVista instance for replication.
60
primary set up the instance for replication as the primary
61
secondary set up the instance for replication as the secondary
62
status show local replication status of the instance
63
list show the configuration parameters of the instance
64
test test replication with the remote instance
65
stop|start run on the secondary to disable or enable replication
66
'start' requires that replication has been set up but
68
resync resync a secondary instance with its primary
69
INSTANCE_NAME name of the OpenVista instance, e.g. 'open' or 'dev'
72
-h display this help text and exit
73
-V display version information and exit
74
-a PRIMARY_IP IP address or host name of the primary server
75
-b SECONDARY_IP IP address or host name of the secondary server
76
-f BACKUP_FILE for secondary, full path to a backup file of the primary
77
instance (generated by ovbackup). Without this option,
78
ovinstancerepl will automatically generate and retrieve
79
a new backup of the remote primary. To skip using a
80
backup altogether, use -f "SKIP". Skipping the backup
81
is not recommended if the primary instance contains a
82
large amount of data that is not already on the
84
-i INSTSECONDARY the GT.M replication instance name of the remote
85
instance. ovinstancerepl will normally retrieve this
86
automatically, but this option can be used if the
87
remote server is not currently available
88
-k KEYS_DIRECTORY for secondary, the directory from which to copy SSH keys
89
and the WebDAV password file. ovinstancerepl will
90
normally retrieve these from the etc subdirectory of
91
the remote instance automatically, but this option can
92
be used if the remote server is not currently available
93
-m MUPIP_PORT port number for use by the GT.M replication daemons
94
-r RSYNC_PORT port number for use by the file replication daemons
95
-s format the output for scripted use
96
-w OTHER_INSTANCE the name of the OpenVista instance being replicated to
97
or from. The default is for the primary and secondary
98
instances to have the same name. However, if both
99
instances are on the same server, the primary instance
100
and the secondary instance must each have a different
101
name, so this option must be used.
112
"primary" | "secondary")
113
# Quoting assures that missing values will not shift the positions.
114
# All of the arguments are reuired except for backup_file.
115
setup "$action" "$instance" \
116
"$primary_ip" "$secondary_ip" \
117
"$mupip_port" "$rsync_port" \
118
"$other_instance" "$backup_file" \
119
"$instsecondary" "$keys_directory"
123
show_status $scripted_flag "$instance"
127
list_configuration $scripted_flag "$instance"
131
if test_replication "$instance"; then
138
read_configuration "$instance" \
139
|| exit_command 1 "$ov_error"
140
[[ "$replication_mode" == "secondary" ]] \
141
|| exit_command 2 "'$action' can only be run on a secondary"
142
ov_services -r "$action" "$instance"
154
# Parse the command line options and arguments.
157
# The following variables are set globally for use by main_().
170
local old_OPTSTRING=$OPTSTRING
171
local old_OPTIND=$OPTIND
174
while getopts "hVa:b:f:i:m:r:sw:" option; do
182
a) primary_ip=$OPTARG
184
b) secondary_ip=$OPTARG
186
f) backup_file=$OPTARG
188
i) instsecondary=$OPTARG
190
k) keys_directory=$OPTARG
192
m) mupip_port=$OPTARG
194
r) rsync_port=$OPTARG
196
s) scripted_flag="-s"
198
w) other_instance=$OPTARG
202
shift $(expr $OPTIND - 1)
203
OPTSTRING=$old_OPTSTRING
209
"primary" | "secondary")
210
replication_mode=$action
213
: ${other_instance:=$instance}
215
# check that the necessary arguments were provided
217
|| exit_command 2 "The $action action requires an OpenVista" \
219
is_openvista_instance "$instance" \
220
|| exit_command 2 "Not an OpenVista instance: $instance"
222
[[ "$primary_ip" ]] \
223
|| exit_command 2 "The $action action requires the -a option"
224
[[ "$secondary_ip" ]] \
225
|| exit_command 2 "The $action action requires the -b option"
227
[[ "$mupip_port" ]] \
228
|| exit_command 2 "The $action action requires the -m option"
229
[[ "$mupip_port" =~ ^[0-9]+$ ]] \
230
|| exit_command 2 "The MUPIP_PORT argument must be a number"
231
[[ "$rsync_port" ]] \
232
|| exit_command 2 "The $action action requires the -r option"
233
[[ "$rsync_port" =~ ^[0-9]+$ ]] \
234
|| exit_command 2 "The RSYNC_PORT argument must be a number"
236
if [[ "$other_instance" == "$instance" ]]; then
237
if [[ "$primary_ip" == "$secondary_ip" ]] \
238
|| (is_local_ip "$primary_ip" \
239
&& is_local_ip "$secondary_ip"); then
241
"If the secondary is on the same server as the primary," \
242
"you must use the -w option to specify a different" \
243
"instance name for the secondary"
246
# Since other_instance may be on a remote server that we
247
# currently cannot access, just check the name itself.
248
is_valid_ov_name "$other_instance" \
250
"Not a valid OpenVista instance name: $other_instance"
253
if [[ "$backup_file" ]] && [[ "$action" != "secondary" ]]; then
254
exit_command 2 "The -f option is only applicable for secondary"
257
[[ "$scripted_flag" ]] && exit_for_bad_option "-s" "$action"
264
|| exit_command 2 "The $action action requires an OpenVista" \
266
is_openvista_instance "$instance" \
267
|| exit_command 2 "Not an OpenVista instance: $instance"
269
[[ "$primary_ip" ]] && exit_for_bad_option "-a" "$action"
270
[[ "$secondary_ip" ]] && exit_for_bad_option "-b" "$action"
271
[[ "$backup_file" ]] && exit_for_bad_option "-f" "$action"
272
[[ "$instsecondary" ]] && exit_for_bad_option "-i" "$action"
273
[[ "$keys_directory" ]] && exit_for_bad_option "-k" "$action"
274
[[ "$mupip_port" ]] && exit_for_bad_option "-m" "$action"
275
[[ "$rsync_port" ]] && exit_for_bad_option "-r" "$action"
276
[[ "$other_instance" ]] && exit_for_bad_option "-w" "$action"
279
"test" | "stop" | "start")
283
|| exit_command 2 "The $action action requires an OpenVista" \
285
is_openvista_instance "$instance" \
286
|| exit_command 2 "Not an OpenVista instance: $instance"
288
[[ "$primary_ip" ]] && exit_for_bad_option "-a" "$action"
289
[[ "$secondary_ip" ]] && exit_for_bad_option "-b" "$action"
290
[[ "$mupip_port" ]] && exit_for_bad_option "-m" "$action"
291
[[ "$rsync_port" ]] && exit_for_bad_option "-r" "$action"
292
[[ "$other_instance" ]] && exit_for_bad_option "-w" "$action"
293
[[ "$backup_file" ]] && exit_for_bad_option "-f" "$action"
294
[[ "$instsecondary" ]] && exit_for_bad_option "-i" "$action"
295
[[ "$keys_directory" ]] && exit_for_bad_option "-k" "$action"
296
[[ "$scripted_flag" ]] && exit_for_bad_option "-s" "$action"
303
|| exit_command 2 "The $action action requires an OpenVista" \
305
is_openvista_instance "$instance" \
306
|| exit_command 2 "Not an OpenVista instance: $instance"
308
[[ "$primary_ip" ]] && exit_for_bad_option "-a" "$action"
309
[[ "$secondary_ip" ]] && exit_for_bad_option "-b" "$action"
310
[[ "$instsecondary" ]] && exit_for_bad_option "-i" "$action"
311
[[ "$keys_directory" ]] && exit_for_bad_option "-k" "$action"
312
[[ "$mupip_port" ]] && exit_for_bad_option "-m" "$action"
313
[[ "$rsync_port" ]] && exit_for_bad_option "-r" "$action"
314
[[ "$other_instance" ]] && exit_for_bad_option "-w" "$action"
315
[[ "$scripted_flag" ]] && exit_for_bad_option "-s" "$action"
319
log -srcw 80 "$this_script: first argument must be primary," \
320
"secondary, status, stop, start, test, or resync"
321
log -sr -v ERROR "Try '$this_script -h' for more information"
327
verify_user_is_root()
329
# check that user is root
331
arg_count 0 0 "$@" || exit_command 1
332
[[ $(id -u) == 0 ]] || exit_command 4 "Only root may configure replication"
337
# set up an OpenVista as a replicating primary or secondary
339
# The basic sequence is to stop all OpenVista services, write the
340
# configuration file, and then restart the services.
341
# For a secondary, there is an additional step of retrieving and restoring
342
# a backup from the primary prior to restarting services.
344
arg_count 7 10 "$@" || exit_command 1
346
local replication_mode=$1
349
local secondary_ip=$4
352
local other_instance=$7
354
local instsecondary=$9
355
local keys_directory=${10}
357
# If the OpenVista instance is already configured for replication and
358
# the replication processes are running, then, for safety, fail.
360
# ovinstancerepl retrieves from the remote server the remote instance's
361
# replication instance name and, for a secondary, a backup of the primary.
362
# So unless these have been provided by the -f and -i option arguments,
363
# access to the remote server needs to be established.
365
# check if we will need to retrieve a backup
366
local need_to_get_a_backup=false
367
if [[ "$action" == "secondary" ]] && ! [[ "$backup_file" ]]; then
368
need_to_get_a_backup=true
376
remote_ip=$secondary_ip
379
local_ip=$secondary_ip
380
remote_ip=$primary_ip
384
# validate the local IP address
385
is_local_ip "$local_ip" \
387
"The host name or IP address provided for the $action instance is" \
388
"not found in the list of local adapters"
390
# if we will need remote access, make sure we have it
391
if ($need_to_get_a_backup || ! [[ "$instsecondary" ]]) \
392
&& ! is_local_ip "$remote_ip" \
393
&& ! /usr/sbin/ovsshkey -qt "$remote_ip"; then
394
if $need_to_get_a_backup; then
396
"To make a backup of the primary instance, ovinstancerepl will" \
397
"need access to the primary server."
400
"To get the replication instance name of the remote instance," \
401
"ovinstancerepl will need access to the remote server."
403
local password_prompt="Enter the root password for the primary server"
404
# set up key-authorized SSH access
405
/usr/sbin/ovsshkey -qp "$password_prompt" "$remote_ip" \
407
"If you need to set up replication for an instance and the" \
408
"remote server is not available, you must use the -i option" \
409
"and, if setting up a secondary, the -f option."
410
exit_command 1 "Failed to prepare SSH access to remote server"; }
413
# get the value for instsecondary
414
local gtm_repl_instname=$(ovgetvar "$instance" gtm_repl_instname)
416
if [[ "$instsecondary" ]]; then
417
# instsecondary was specified on the command line
418
# check if it matches the local instance
419
if [[ "$instsecondary" == "$gtm_repl_instname" ]]; then
421
"The value specified for instsecondary should be the" \
422
"replication instance name of the remote instance, but it" \
423
"matches the replication instance name of the local instance:" \
424
"\"$gtm_repl_instname\""
427
if ! instsecondary=$( sshk "$remote_ip" \
428
ovgetvar "$other_instance" gtm_repl_instname \
430
error=$( sshk "$remote_ip" \
431
ovgetvar "$other_instance" gtm_repl_instname \
434
"Could not get value for instsecondary from instance" \
435
"\"$other_instance\" on $remote_ip."
437
"If the remote instance is not available you may use the -i" \
438
"option to specify instsecondary manually."
439
exit_command 1 "Error on the remote server was: $error"
441
# instsecondary was found on the other instance
442
# check if it matches the local instance
443
if [[ "$instsecondary" == "$gtm_repl_instname" ]]; then
444
# Most likely, the secondary instance, which may be local or remote,
445
# was made from a copy of the primary.
447
"The local and remote replication instance names match"
449
"This is likely if the secondary instance was created as a file" \
450
"copy of the primary instance or vice versa. To set up" \
451
"replication, one of the instances will need to have its" \
452
"repl_instance file regenerated with a new replication instance" \
456
"Generate new local repl_instance file for $instance?" \
458
if [[ "$response" == "yes" ]]; then
459
if gtm_repl_instname=$(generate_repl_instance "$instance"); then
460
log -sr "Created replication instance file for $instance"
463
"Failed to create replication instance file for $instance"
467
"Set up of replication failed: the replication instance" \
468
"names of $other_instance on $remote_ip and $instance on" \
474
ov_services stop "$instance" \
475
|| exit_command 1 "Failed to stop processes for the instance"
477
/usr/sbin/ovgenconfig "$instance" replication.conf \
478
"REPLICATION_MODE=$action" \
479
"REPLICATION_IP=$remote_ip" \
480
"BIND_ADDRESS=$local_ip" \
481
"OTHER_INSTANCE=$other_instance" \
482
"MUPIP_PORT=$mupip_port" \
483
"INSTSECONDARY=$instsecondary" \
484
"RSYNC_PORT=$rsync_port" \
485
|| exit_command 1 "Failed to generate replication.conf"
487
if [[ "$action" == "secondary" ]] && [[ "$backup_file" != "SKIP" ]]; then
488
load_backup_to_secondary "$instance" "$other_instance" \
489
"$remote_ip" "$backup_file"
492
[[ "$replication_mode" == "secondary" ]] \
493
&& copy_keys_to_secondary "$instance" "$other_instance" \
494
"$remote_ip" "$keys_directory"
496
case $replication_mode in
498
ov_services start "$instance" \
499
|| exit_command 1 "Failed to start OpenVista services for" \
500
"primary instance \"$instance\""
503
ov_services -dr start "$instance" \
504
|| exit_command 1 "Failed to start OpenVista services for" \
505
"secondary instance \"$instance\""
509
"replication_mode is not set, so services are not started"
514
load_backup_to_secondary()
516
# Restore a backup of the primary into the secondary.
517
# instance is the local secondary, other_instance is the remote primary
519
arg_count 3 4 "$@" || exit_command 1
521
local other_instance=$2
525
# get a backup of the primary if a backup file wasn't specified
526
if ! [[ "$backup_file" ]]; then
527
log -srlc "Creating a backup of the primary to be" \
528
"restored to this secondary"
529
local remote_backup_file
530
remote_backup_file=$(sshk "$remote_ip" \
531
ovbackup -qo "$other_instance") \
533
"Failed to create backup of primary instance" \
534
"$other_instance on $remote_ip"
535
if is_local_ip $remote_ip; then
536
backup_file=$remote_backup_file
538
local backup_name=$(basename "$remote_backup_file")
539
backup_file="$root/$instance/backups/$backup_name"
540
log -srlc "Copying $remote_ip:$remote_backup_file" \
542
KEY_NAME=$(/usr/sbin/ovsshkey -n)
543
scp -o PreferredAuthentications=publickey \
544
-i "/root/.ssh/$KEY_NAME" \
545
--preserve=timestamp \
546
"$remote_ip:$remote_backup_file" "$backup_file"
549
# restore the backup of the primary to this secondary
550
/usr/sbin/ovrestore -qy "$backup_file" "$instance" \
551
|| exit_command 1 "Failed to restore the backup of the" \
552
"primary to the secondary"
555
copy_keys_to_secondary()
557
# Copy the SSH keys and WebDAV password from the primary instance to the
558
# secondary instance.
559
# Also, make the secondary's host keys match the primary server's host keys.
560
# This is only called on a secondary instance.
562
arg_count 3 4 "$@" || exit_command 1
564
local other_instance=$2
566
local primary_etc_directory=$4
568
# don't do anything if this is local-to-local replication
569
is_local_ip "$remote_ip" && return
571
local secondary_etc_directory=$root/$instance/etc
572
: ${primary_etc_directory:=$remote_ip:$root/$other_instance/etc}
575
"Copying keys from $primary_etc_directory to $secondary_etc_directory"
576
KEY_NAME=$(/usr/sbin/ovsshkey -n)
577
scp -o PreferredAuthentications=publickey \
578
-i "/root/.ssh/$KEY_NAME" \
580
"$primary_etc_directory/$instance-*" \
581
"$secondary_etc_directory/" \
583
"Failed to copy the key files of the OpenVista instance"
585
# remove from the user's authorized_keys file any previous keys for instance
586
local user=$(get_ov_user)
587
local home=$(getent passwd "$user" | awk -F : '{ print $6 }')
588
local auth_file=$home/.ssh/authorized_keys
589
if [[ -e "$auth_file" ]] \
590
&& grep " $instance$" "$auth_file" >/dev/null; then
591
remove_instance_from_authorized_keys()
593
temp_auth_file=$(mktemp "${auth_file}_temp.XXXXXXXX")
594
grep -v " $instance$" "$auth_file" > "$temp_auth_file"
595
mv "$temp_auth_file" "$auth_file"
597
# Exporting names explicitly within a subshell rather than using the -m
598
# option of `su` to avoid any accidental mixing of environments.
599
if ( export -f remove_instance_from_authorized_keys
600
export instance auth_file
601
su -c remove_instance_from_authorized_keys "$user" ); then
603
"Removed existing SSH keys for the \"$instance\" instance from" \
607
"Unable to remove existing SSH keys for the \"$instance\"" \
608
"instance from $auth_file"
612
# add keys to user's authorized_keys file
613
add_instance_to_authorized_keys()
615
no_fwd_opts="no-port-forwarding,no-X11-forwarding,no-agent-forwarding"
616
tied_options="$no_fwd_opts,command=\"/usr/bin/ovtied -- $instance\" "
617
ovcc_options="$no_fwd_opts,command=\"/usr/bin/ovcc -- $instance\" "
618
tied_key_file="$secondary_etc_directory/$instance-tied_rsa_key.pub"
619
ovcc_key_file="$secondary_etc_directory/$instance-ovcc_rsa_key.pub"
620
mkdir -m 700 -p "$home/.ssh" \
621
&& printf "$tied_options" >> "$auth_file" \
622
&& cat "$tied_key_file" >> "$auth_file" \
623
&& printf "$ovcc_options" >> "$auth_file" \
624
&& cat "$ovcc_key_file" >> "$auth_file"
626
if ( export -f add_instance_to_authorized_keys
627
export instance secondary_etc_directory home auth_file
628
su -c add_instance_to_authorized_keys "$user" ); then
630
"Added SSH keys for the \"$instance\" instance to $auth_file"
633
"Unable to add SSH keys for the \"$instance\" instance to $auth_file"
636
# set apache_user, apache_conf, docroot
638
# add password to $apache_conf/webdav.htpasswd
639
local passwdfile=$apache_conf/webdav.htpasswd
640
local username=$instance
641
local password=$(< "$secondary_etc_directory/$instance-webdav_password")
643
error=$(htpasswd -b -m "$passwdfile" "$username" "$password" 2>&1) \
644
|| exit_command 1 "Unable to update $apache_conf/webdav.htpasswd: $error"
646
# copy the primary server's host keys over the local host keys, and add
647
# the public key of the primary server's RSA host key to its known hosts
648
# The instance name is only provided for ovsshkey to verify that the local
649
# host is the secondary server.
650
if /usr/sbin/ovsshkey -qs "$instance" "$primary_ip"; then
652
"The SSH host keys of the primary server have been copied to the" \
656
"Failed to copy the SSH host keys of the primary server to the" \
659
"The SSH host keys of the primary server will need to be copied" \
660
"to the secondary server. Otherwise, after a switchover, SSH" \
661
"clients will not recognize the new primary"
667
# Show the status of OpenVista replication for the instance
671
if [[ "$1" == "-s" ]]; then
675
arg_count 1 1 "$@" || exit_command 1
679
is_openvista_instance $instance \
680
|| exit_command 2 "Not an OpenVista instance: $instance"
685
instance_data=( $(get_status "$instance") )
689
printf '%s\n' "${instance_data[@]}"
691
tabulate_pairs "${instance_data[@]}"
697
# Return replication status data for a single OpenVista instance.
698
# This data will be used to create the status table.
700
# The data being returned is in the format of
703
# Since some of the values contain spaces, IFS must be set to newline before
704
# assigning the output to a variable using command substitution.
706
# Since this function will be called with IFS set to newline, set IFS
707
# locally to its normal value to avoid any unusual behavior within the
712
arg_count 1 1 "$@" || exit_command 1
715
# clear and then set values from replication.conf
716
unset replication_mode
723
set_gtm_env -e "$instance"
725
echo "Replication mode=$replication_mode"
726
echo "Instance name=$instance"
727
local local_names=$(getent hosts "$bind_address")
728
case $(get_address_type "$bind_address") in
730
ip_address=$bind_address
731
host_name=$(echo "$local_names" | awk '{print $2;}')
733
"qualified hostname" | "unqualified hostname")
734
host_name=$bind_address
735
ip_address=${local_names%% *}
738
echo "Host name=${host_name:-($HOSTNAME)}"
739
echo "IP address=${ip_address:-($(hostname -i))}"
740
echo "Replicates with=$replication_ip"
743
gtm_repl_instname=$(ovgetvar "$instance" gtm_repl_instname) \
744
|| exit_command 1 "Failed to get gtm_repl_instname"
745
echo -n "Repl. instance name="$(color_text bold "$gtm_repl_instname")
746
echo ${instsecondary:+" -> $instsecondary"}
748
label="HDR Instance File Create Time"
749
instance_file_date=$(get_gtm_repl_instance_value "$instance" "$label") \
750
|| exit_command 1 "Failed to get instance file date"
751
echo "Instance file date=$instance_file_date"
753
gtm_version=$(run_mumps_cmd "$instance" 'W $ZVERSION') \
754
|| exit_command 1 "Failed to get GT.M version"
755
echo "GT.M version=$gtm_version"
757
port_status "GT.M port number" "$mupip_port" mupip
758
echo "Replicating with="$(get_gtm_remote_host "$instance")
762
mupip_processes=( $(mupip_checkhealth "$instance" "$replication_mode") )
763
echo "GT.M source server=${mupip_processes[0]}"
764
echo "GT.M receiver server=${mupip_processes[1]}"
765
echo "GT.M update process=${mupip_processes[2]}"
766
mupip_backlog=( $(mupip_showbacklog "$instance") )
767
echo "Last written JNL SEQNO=${mupip_backlog[0]}"
768
echo "Last sent JNL SEQNO=${mupip_backlog[1]}"
769
echo "GT.M repl. backlog=${mupip_backlog[2]}"
772
mumps_pids=( $(get_mumps_pids "$instance") )
773
echo "Mumps process count=${#mumps_pids[@]}"
777
port_status "rsync port number" "$rsync_port"
778
echo "lsyncd daemon=$(get_lsyncd_status)"
779
echo "rsyncd daemon=$(get_rsyncd_status)"
780
echo "Routines file count=$(get_routines_file_count)"
781
echo "Last WebDAV file=$(get_last_webdav_file)"
784
get_gtm_remote_host()
786
# Get the host name or IP address of the remote server for the instance.
787
# This retrieves the value actually in use, not just the value from the
788
# configuration file, which could have changed since replication started.
791
# get OpenVista environment
792
set_gtm_env -v "$instance" || return $?
795
read_vars pid mode < \
796
<(mupip replic -source -checkhealth 2>&1 1>/dev/null \
797
| sed -nr "s/^PID ([0-9]+).+(ACTIVE|PASSIVE) mode$/\1\n\2/p")
799
if [[ "$mode" == "ACTIVE" ]]; then
801
# get the remote host from the mupip command arguments
802
ps --format args= --pid "$pid" \
803
| sed -nr "s/^.* -secondary=([^: ]+).*$/\1/p"
806
# secondary or nothing
807
# get the mupip receiver PID
808
pid=$(mupip replic -receiver -checkhealth 2>&1 1>/dev/null \
809
| sed -nr "s/^PID ([0-9]+) Receiver server is alive$/\1/p")
810
[[ "$pid" ]] || return 1
811
# get the port number from the mupip receiver command arguments
813
port=$(ps --format args= --pid "$pid" \
814
| sed -nr "s/^.* -listenport=([0-9]+).*$/\1/p")
815
# get the remote host from the port connection
819
| sed -nr "s/^tcp.*:$port\s+([^:]+):.*$/\1/p"
826
# pid and status of lsyncd daemon (should be on primary)
828
lsyncd_pid_file="$root/$instance/replication/lsyncd.pid"
831
if [[ -f "$lsyncd_pid_file" ]]; then
832
lsyncd_pid=$(< "$lsyncd_pid_file")
833
value=$(check_pid "$lsyncd_pid")
836
local running=$(echo "$value" | grep "Running")
837
daemon_status_color "$value" primary "$replication_mode" "$running"
842
# pid and status of rsync daemon (should be on secondary)
844
rsyncd_pid_file="$root/$instance/replication/rsyncd.pid"
847
if [[ -f "$rsyncd_pid_file" ]]; then
848
rsyncd_pid=$(< "$rsyncd_pid_file")
849
value=$(check_pid "$rsyncd_pid")
852
local running=$(echo "$value" | grep "Running")
853
daemon_status_color "$value" secondary "$replication_mode" "$running"
856
get_last_webdav_file()
858
# filename of the last file added to the WebDAV directory
860
# Giving a count of the files would be helpful for comparing primary
861
# and secondary, but it would take too long for the number of files
862
# typically in this directory. So we use the most recently added
863
# file for comparison instead.
865
# The files in the WebDAV directory are named and filed in a
866
# chronologically alphabetical order such that the newest file
867
# can be found without examining every file.
871
webdav_dir="$docroot/webdav/$instance"
872
local last_webdav_file
873
if last_webdav_file=$(find_last_webdav_file "$webdav_dir"); then
874
basename "$last_webdav_file"
878
find_last_webdav_file()
880
# Find the last file added to the WebDAV folder.
881
# This function calls itself recursively, assuming an alphabetically
882
# incremented and nested file structure.
884
# find_last_webdav_file /var/www/html/webdav/open
890
next_dir=$(find "$1" -mindepth 1 -maxdepth 1 -type d ! -empty \
893
&& [[ "$next_dir" ]] \
894
&& last_file=$(find_last_webdav_file "$next_dir") \
895
|| last_file=$(find "$1" -mindepth 1 -maxdepth 1 -type f \
899
[[ "$last_file" ]] && echo "$last_file"
902
get_routines_file_count()
904
# number of files in the routines directory of the instance
906
routines_dir="$root/$instance/routines"
907
find "$routines_dir" -type f | wc -l
911
get_gtm_repl_instance_value()
913
# Get a value from the mupip replication instance file report.
915
arg_count 2 2 "$@" || exit_command 1
918
set_gtm_env -e "$instance"
919
local report=$(mupip replic -edit -show \
920
"$root/$instance/replication/repl_instance" 2>&1)
921
echo "$report" | sed -nr "s/^${label}[ \t]+(.*)[ \t]*$/\1/p"
926
# Show the replication configuration parameters of the instance.
930
if [[ "$1" == "-s" ]]; then
934
arg_count 1 1 "$@" || exit_command 1
938
is_openvista_instance "$instance" \
939
|| exit_command 2 "Not an OpenVista instance: $instance"
941
local root=$(get_ov_root)
942
local conf_file=$root/$instance/etc/replication.conf
943
[[ -r "$conf_file" ]] || exit_command 1 \
944
"Could not read configuration file \"$conf_file\""
946
local replication_mode
957
"Instance name="$instance
958
"Replication mode="$replication_mode
959
"Replication IP="$replication_ip
960
"Local IP="$bind_address
961
"Remote instance="$other_instance
962
"GT.M port="$mupip_port
963
"Instsecondary="$instsecondary
964
"Rsync port="$rsync_port
968
printf '%s\n' "${settings[@]}"
970
tabulate_pairs "${settings[@]}"
976
# Write a value to the primary and read it on the secondary.
978
arg_count 1 1 "$@" || exit_command 1
981
read_configuration "$instance" \
982
|| { log -srl $ov_error
987
local primary_instance
988
local secondary_instance
989
case $replication_mode in
991
primary_ip=$bind_address
992
secondary_ip=$replication_ip
993
primary_instance=$instance
994
secondary_instance=$other_instance
997
primary_ip=$replication_ip
998
secondary_ip=$bind_address
999
primary_instance=$other_instance
1000
secondary_instance=$instance
1003
log -sr "Instance \"$instance\" is not configured for replication"
1008
"For instance \"$instance\": replication mode is set to a value" \
1009
"other than 'primary' or 'secondary': '$replication_mode'"
1014
local x variable_value description
1016
"$primary_ip, the IP address of the primary server" \
1017
"$secondary_ip, the IP address of the secondary server" \
1018
"$primary_instance, the name of the primary instance" \
1019
"$secondary_instance, the name of the secondary instance"
1021
variable_value="${x%, *}"
1022
description="${x##*, }"
1023
[[ "$variable_value" ]] \
1024
|| { log -sr "For instance \"$instance\": failed to get $description"
1030
log -src "Testing replication of instance \"$instance\"" \
1031
"from $primary_ip to $secondary_ip:"
1033
test_gtm_replication \
1036
routines_directory=$root/$instance/routines
1037
test_file_replication "$routines_directory/MSCOVREPLTESTFILE.XXXXXXXX" \
1041
webdav_directory=$docroot/webdav/$instance
1042
test_file_replication "$webdav_directory/mscovrepltestfile.XXXXXXXX" \
1048
test_gtm_replication()
1050
# Test replication of GT.M globals.
1051
# This is a subroutine of test_replication() and assumes its variables.
1053
arg_count 0 0 "$@" || exit_command 1
1055
local test_value=$(date --rfc-3339=ns)
1057
local global_name=MSCOVREPLTESTVAL
1059
local remote_call=$(cat <<EOF
1060
. /usr/lib/openvista/functions
1061
run_mumps_cmd "$primary_instance" 'S ^$global_name="$test_value"'
1064
sshk -d "$primary_ip" "$remote_call" \
1065
|| { log -srl " Failed writing the test value to the primary"
1068
# Before we start waiting for a successful result of a mumps command, test
1069
# that we can at least run a mumps command on the secondary.
1070
local remote_call=$(cat <<EOF
1071
. /usr/lib/openvista/functions
1072
run_mumps_cmd "$secondary_instance" 'W $ZVERSION'
1075
sshk -d "$secondary_ip" "$remote_call" \
1077
|| { log -srl " Failed to run a mumps command on the secondary"
1080
# seconds to wait for replication to occur
1081
local allowed_delay=10
1082
log -srn " GT.M global variable ^$global_name: "
1083
# check each second for a matching value on the secondary
1084
local secondary_value
1085
local remote_call=$(cat <<EOF
1086
. /usr/lib/openvista/functions
1087
run_mumps_cmd "$secondary_instance" 'W ^$global_name'
1090
local replication_successful=false
1091
for (( i=0; i!=$allowed_delay; i++ )); do
1093
# read on the secondary
1094
secondary_value=$(sshk -d "$secondary_ip" "$remote_call" \
1095
2>/dev/null | head -n1)
1096
if [[ "$secondary_value" == "$test_value" ]]; then
1097
replication_successful=true
1100
# count out the seconds
1101
log -srn "$(( i+1 )) "
1104
local remote_call=$(cat <<EOF
1105
. /usr/lib/openvista/functions
1106
run_mumps_cmd "$primary_instance" 'K ^$global_name'
1109
sshk -d "$primary_ip" "$remote_call"
1111
if $replication_successful; then
1112
color_text green "successful" >&2
1115
color_text red "failed" >&2
1120
test_file_replication()
1122
# Write a test file on the primary and read it on the secondary.
1123
# This is a subroutine of test_replication() and assumes its variables.
1125
arg_count 1 1 "$@" || exit_command 1
1128
filename=$(mktemp "$filename")
1130
local test_value=$(date --rfc-3339=ns)
1132
local remote_call=$(cat <<EOF
1133
echo "$test_value" >$filename
1136
sshk -d $primary_ip "$remote_call"
1138
# seconds to wait for replication to occur
1139
local allowed_delay=10
1140
log -srn " $filename: "
1141
# check each second for a matching value on the secondary
1142
local secondary_value
1143
local replication_successful=false
1144
for (( i=0; i!=$allowed_delay; i++ )); do
1146
# read on the secondary
1147
secondary_value=$(sshk "$secondary_ip" cat "$filename" \
1149
if [[ "$secondary_value" == "$test_value" ]]; then
1150
replication_successful=true
1153
# count out the seconds
1154
log -srn "$(( i+1 )) "
1157
sshk "$primary_ip" rm -f "$filename"
1158
sshk "$secondary_ip" rm -f "$filename"
1160
if $replication_successful; then
1161
color_text green "successful" >&2
1164
color_text red "failed" >&2
1169
read_configuration()
1171
# Set replication variables from replication.conf.
1172
# Unlike set_gtm_env(), this returns an error if there is no such file.
1174
arg_count 1 1 "$@" || exit_command 1
1177
unset replication_mode
1178
unset replication_ip
1180
unset other_instance
1185
local conf_file=$root/$instance/etc/replication.conf
1186
[[ -r "$conf_file" ]] \
1187
|| { ov_error="Could not read $conf_file"
1190
|| { ov_error="Could not source $conf_file"
1196
# Output the pid and the status of its process
1198
arg_count 1 1 "$@" || exit_command 1
1200
if is_number "$pid"; then
1201
echo -n "PID $pid, "
1202
if ps --pid "$pid" > /dev/null; then
1212
# Get a secondary instance back in sync with its primary instance.
1214
arg_count 0 0 "$@" || exit_command 1
1216
# verify instance is secondary
1217
read_configuration "$instance" \
1218
|| exit_command $? $ov_error
1219
[[ "$replication_mode" == "secondary" ]] \
1220
|| exit_command 1 "The resync action can only be performed on" \
1221
"an instance configured as a secondary"
1223
# check that the instance is already fully configured
1224
[[ "$replication_ip" ]] \
1225
|| exit_command 1 "replication_ip is not configured for $instance"
1226
[[ "$bind_address" ]] \
1227
|| exit_command 1 "bind_address is not configured for $instance"
1228
[[ "$other_instance" ]] \
1229
|| exit_command 1 "other_instance is not configured for $instance"
1230
[[ "$mupip_port" ]] \
1231
|| exit_command 1 "mupip_port is not configured for $instance"
1232
[[ "$instsecondary" ]] \
1233
|| exit_command 1 "instsecondary is not configured for $instance"
1234
[[ "$rsync_port" ]] \
1235
|| exit_command 1 "rsync_port is not configured for $instance"
1237
# make sure we can access the primary to get a backup
1238
if ! [[ "$backup_file" ]] && ! is_local_ip "$replication_ip"; then
1239
password_prompt="ovinstancerepl will need access to "
1240
password_prompt+="$replication_ip to make and retrieve a "
1241
password_prompt+="backup of the primary"
1242
/usr/sbin/ovsshkey -p "$password_prompt" "$replication_ip" \
1243
|| exit_command 1 "Failed to set up access to primary server"
1246
ov_services stop "$instance"
1247
# The value of backup_file can be blank here.
1248
load_backup_to_secondary "$instance" "$other_instance" \
1249
"$replication_ip" "$backup_file"
1250
ov_services -h "$replication_ip" -r start "$other_instance"
1251
ov_services -dr start "$instance"