~derek-name/openvista-gtm-integration/bug818588-ovbackup_nice

« back to all changes in this revision

Viewing changes to scripts/usr/sbin/ovinstancerepl

  • Committer: Derek Veit
  • Date: 2011-08-22 19:04:10 UTC
  • mfrom: (131.2.576 replication)
  • Revision ID: derek.veit@medsphere.com-20110822190410-w4sepab2fxrs3u0p
Merge replication branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/bin/bash
 
2
 
 
3
# Script to configure an OpenVista instance for replication
 
4
#
 
5
# Copyright (C) 2010 Medsphere Systems Corporation
 
6
#
 
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.
 
10
#
 
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
 
14
# for more details.
 
15
#
 
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>.
 
18
#
 
19
# You can contact Medsphere Systems Corporation headquarters at 1917 Palomar
 
20
# Oaks Way, Suite 200, Carlsbad, CA 92008 or at legal@medsphere.com.
 
21
 
 
22
 
 
23
# common functions
 
24
. /usr/lib/openvista/functions
 
25
 
 
26
log_command_usage "$@"
 
27
 
 
28
this_script=ovinstancerepl
 
29
 
 
30
root=$(get_ov_root)
 
31
 
 
32
version()
 
33
{
 
34
    # Display version information.
 
35
    log_func "$@"
 
36
    cat <<EOF
 
37
ovinstancerepl 0.9
 
38
Copyright (C) 2010 Medsphere Systems Corporation
 
39
 
 
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.
 
42
EOF
 
43
}
 
44
 
 
45
usage()
 
46
{
 
47
    # Display usage information.
 
48
    log_func "$@"
 
49
    cat <<EOF
 
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
 
56
   or  ovinstancerepl -h
 
57
   or  ovinstancerepl -V
 
58
Configure an OpenVista instance for replication.
 
59
 
 
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
 
67
                         has been stopped
 
68
  resync                resync a secondary instance with its primary
 
69
  INSTANCE_NAME         name of the OpenVista instance, e.g. 'open' or 'dev'
 
70
 
 
71
  Options:
 
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
 
83
                         secondary.
 
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.
 
102
EOF
 
103
}
 
104
 
 
105
main_()
 
106
{
 
107
    log_func "$@"
 
108
    parse_arguments "$@"
 
109
    verify_user_is_root
 
110
 
 
111
    case $action in
 
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"
 
120
            exit_command $?
 
121
            ;;
 
122
        "status")
 
123
            show_status $scripted_flag "$instance"
 
124
            exit_command $?
 
125
            ;;
 
126
        "list")
 
127
            list_configuration $scripted_flag "$instance"
 
128
            exit_command $?
 
129
            ;;
 
130
        "test")
 
131
            if test_replication "$instance"; then
 
132
                exit_command 0
 
133
            else
 
134
                exit_command $? ""
 
135
            fi
 
136
            ;;
 
137
        "stop" | "start")
 
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"
 
143
            exit_command $?
 
144
            ;;
 
145
        "resync")
 
146
            resync
 
147
            exit_command $?
 
148
            ;;
 
149
    esac
 
150
}
 
151
 
 
152
parse_arguments()
 
153
{
 
154
    # Parse the command line options and arguments.
 
155
    log_func "$@"
 
156
 
 
157
    # The following variables are set globally for use by main_().
 
158
    unset action
 
159
    unset primary_ip
 
160
    unset secondary_ip
 
161
    unset backup_file
 
162
    unset instsecondary
 
163
    unset keys_directory
 
164
    unset mupip_port
 
165
    unset rsync_port
 
166
    unset scripted_flag
 
167
    unset other_instance
 
168
 
 
169
    # parse the options
 
170
    local old_OPTSTRING=$OPTSTRING
 
171
    local old_OPTIND=$OPTIND
 
172
    unset OPTSTRING
 
173
    unset OPTIND
 
174
    while getopts "hVa:b:f:i:m:r:sw:" option; do
 
175
        case $option in
 
176
            h)  usage
 
177
                exit_command 0
 
178
                ;;
 
179
            V)  version
 
180
                exit_command 0
 
181
                ;;
 
182
            a)  primary_ip=$OPTARG
 
183
                ;;
 
184
            b)  secondary_ip=$OPTARG
 
185
                ;;
 
186
            f)  backup_file=$OPTARG
 
187
                ;;
 
188
            i)  instsecondary=$OPTARG
 
189
                ;;
 
190
            k)  keys_directory=$OPTARG
 
191
                ;;
 
192
            m)  mupip_port=$OPTARG
 
193
                ;;
 
194
            r)  rsync_port=$OPTARG
 
195
                ;;
 
196
            s)  scripted_flag="-s"
 
197
                ;;
 
198
            w)  other_instance=$OPTARG
 
199
                ;;
 
200
        esac
 
201
    done
 
202
    shift $(expr $OPTIND - 1)
 
203
    OPTSTRING=$old_OPTSTRING
 
204
    OPTIND=$old_OPTIND
 
205
 
 
206
    action="$1"
 
207
    shift
 
208
    case $action in
 
209
        "primary" | "secondary")
 
210
            replication_mode=$action
 
211
 
 
212
            instance=$1
 
213
            : ${other_instance:=$instance}
 
214
 
 
215
            # check that the necessary arguments were provided
 
216
            [[ "$instance" ]] \
 
217
              || exit_command 2 "The $action action requires an OpenVista" \
 
218
                                "instance name"
 
219
            is_openvista_instance "$instance" \
 
220
              || exit_command 2 "Not an OpenVista instance: $instance"
 
221
 
 
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"
 
226
 
 
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"
 
235
 
 
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
 
240
                    exit_command 2 \
 
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"
 
244
                fi
 
245
            else
 
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" \
 
249
                  || exit_command 2 \
 
250
                       "Not a valid OpenVista instance name: $other_instance"
 
251
            fi
 
252
 
 
253
            if [[ "$backup_file" ]] && [[ "$action" != "secondary" ]]; then
 
254
                exit_command 2 "The -f option is only applicable for secondary"
 
255
            fi
 
256
 
 
257
            [[ "$scripted_flag" ]] && exit_for_bad_option "-s" "$action"
 
258
            ;;
 
259
 
 
260
        "status" | "list")
 
261
            instance=$1
 
262
 
 
263
            [[ "$instance" ]] \
 
264
              || exit_command 2 "The $action action requires an OpenVista" \
 
265
                                "instance name"
 
266
            is_openvista_instance "$instance" \
 
267
              || exit_command 2 "Not an OpenVista instance: $instance"
 
268
 
 
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"
 
277
            ;;
 
278
 
 
279
        "test" | "stop" | "start")
 
280
            instance=$1
 
281
 
 
282
            [[ "$instance" ]] \
 
283
              || exit_command 2 "The $action action requires an OpenVista" \
 
284
                                "instance name"
 
285
            is_openvista_instance "$instance" \
 
286
              || exit_command 2 "Not an OpenVista instance: $instance"
 
287
 
 
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"
 
297
            ;;
 
298
 
 
299
        "resync")
 
300
            instance=$1
 
301
 
 
302
            [[ "$instance" ]] \
 
303
              || exit_command 2 "The $action action requires an OpenVista" \
 
304
                                "instance name"
 
305
            is_openvista_instance "$instance" \
 
306
              || exit_command 2 "Not an OpenVista instance: $instance"
 
307
 
 
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"
 
316
            ;;
 
317
 
 
318
        *)
 
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"
 
322
            exit_command 2
 
323
            ;;
 
324
    esac
 
325
}
 
326
 
 
327
verify_user_is_root()
 
328
{
 
329
    # check that user is root
 
330
    log_func "$@"
 
331
    arg_count 0 0 "$@" || exit_command 1
 
332
    [[ $(id -u) == 0 ]] || exit_command 4 "Only root may configure replication"
 
333
}
 
334
 
 
335
setup()
 
336
{
 
337
    # set up an OpenVista as a replicating primary or secondary
 
338
    #
 
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.
 
343
    log_func "$@"
 
344
    arg_count 7 10 "$@" || exit_command 1
 
345
 
 
346
    local replication_mode=$1
 
347
    local instance=$2
 
348
    local primary_ip=$3
 
349
    local secondary_ip=$4
 
350
    local mupip_port=$5
 
351
    local rsync_port=$6
 
352
    local other_instance=$7
 
353
    local backup_file=$8
 
354
    local instsecondary=$9
 
355
    local keys_directory=${10}
 
356
 
 
357
    # If the OpenVista instance is already configured for replication and
 
358
    # the replication processes are running, then, for safety, fail.
 
359
 
 
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.
 
364
 
 
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
 
369
    fi
 
370
 
 
371
    local local_ip
 
372
    local remote_ip
 
373
    case $action in
 
374
        primary)
 
375
            local_ip=$primary_ip
 
376
            remote_ip=$secondary_ip
 
377
            ;;
 
378
        secondary)
 
379
            local_ip=$secondary_ip
 
380
            remote_ip=$primary_ip
 
381
            ;;
 
382
    esac
 
383
 
 
384
    # validate the local IP address
 
385
    is_local_ip "$local_ip" \
 
386
      || exit_command 2 \
 
387
           "The host name or IP address provided for the $action instance is" \
 
388
           "not found in the list of local adapters"
 
389
 
 
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
 
395
            log -srcw 80 \
 
396
              "To make a backup of the primary instance, ovinstancerepl will" \
 
397
              "need access to the primary server."
 
398
        else
 
399
            log -srcw 80 \
 
400
              "To get the replication instance name of the remote instance," \
 
401
              "ovinstancerepl will need access to the remote server."
 
402
        fi
 
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" \
 
406
          || { log -srcw 80 \
 
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"; }
 
411
    fi
 
412
 
 
413
    # get the value for instsecondary
 
414
    local gtm_repl_instname=$(ovgetvar "$instance" gtm_repl_instname)
 
415
 
 
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
 
420
            exit_command 2 \
 
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\""
 
425
        fi
 
426
    else
 
427
        if ! instsecondary=$( sshk "$remote_ip" \
 
428
                                ovgetvar "$other_instance" gtm_repl_instname \
 
429
                                2>/dev/null ); then
 
430
            error=$( sshk "$remote_ip" \
 
431
                        ovgetvar "$other_instance" gtm_repl_instname \
 
432
                        2>&1 1>/dev/null )
 
433
            log -srlc \
 
434
              "Could not get value for instsecondary from instance" \
 
435
              "\"$other_instance\" on $remote_ip."
 
436
            log -srcw 80 \
 
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"
 
440
        fi
 
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.
 
446
            log -srl \
 
447
              "The local and remote replication instance names match"
 
448
            log -srcw 80 \
 
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" \
 
453
              "name."
 
454
            local response=$( \
 
455
              ask_user -d "yes" \
 
456
                       "Generate new local repl_instance file for $instance?" \
 
457
                       "yes" "no")
 
458
            if [[ "$response" == "yes" ]]; then
 
459
                if gtm_repl_instname=$(generate_repl_instance "$instance"); then
 
460
                    log -sr "Created replication instance file for $instance"
 
461
                else
 
462
                    exit_command 1 \
 
463
                      "Failed to create replication instance file for $instance"
 
464
                fi
 
465
            else
 
466
                exit_command 1 \
 
467
                  "Set up of replication failed: the replication instance" \
 
468
                  "names of $other_instance on $remote_ip and $instance on" \
 
469
                  "$local_ip match"
 
470
           fi
 
471
        fi
 
472
    fi
 
473
 
 
474
    ov_services stop "$instance" \
 
475
      || exit_command 1 "Failed to stop processes for the instance"
 
476
 
 
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"
 
486
 
 
487
    if [[ "$action" == "secondary" ]] && [[ "$backup_file" != "SKIP" ]]; then
 
488
        load_backup_to_secondary "$instance" "$other_instance" \
 
489
                                 "$remote_ip" "$backup_file"
 
490
    fi
 
491
 
 
492
    [[ "$replication_mode" == "secondary" ]] \
 
493
      && copy_keys_to_secondary "$instance" "$other_instance" \
 
494
                                "$remote_ip" "$keys_directory"
 
495
 
 
496
    case $replication_mode in
 
497
        "primary")
 
498
            ov_services start "$instance" \
 
499
              || exit_command 1 "Failed to start OpenVista services for" \
 
500
                                "primary instance \"$instance\""
 
501
            ;;
 
502
        "secondary")
 
503
            ov_services -dr start "$instance" \
 
504
              || exit_command 1 "Failed to start OpenVista services for" \
 
505
                                "secondary instance \"$instance\""
 
506
            ;;
 
507
        *)
 
508
            exit_command 1 \
 
509
              "replication_mode is not set, so services are not started"
 
510
            ;;
 
511
    esac
 
512
}
 
513
 
 
514
load_backup_to_secondary()
 
515
{
 
516
    # Restore a backup of the primary into the secondary.
 
517
    # instance is the local secondary, other_instance is the remote primary
 
518
    log_func "$@"
 
519
    arg_count 3 4 "$@" || exit_command 1
 
520
    local instance=$1
 
521
    local other_instance=$2
 
522
    local remote_ip=$3
 
523
    local backup_file=$4
 
524
 
 
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") \
 
532
          || exit_command 1 \
 
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
 
537
        else
 
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" \
 
541
                      "to $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"
 
547
        fi
 
548
    fi
 
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"
 
553
}
 
554
 
 
555
copy_keys_to_secondary()
 
556
{
 
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.
 
561
    log_func "$@"
 
562
    arg_count 3 4 "$@" || exit_command 1
 
563
    local instance=$1
 
564
    local other_instance=$2
 
565
    local remote_ip=$3
 
566
    local primary_etc_directory=$4
 
567
 
 
568
    # don't do anything if this is local-to-local replication
 
569
    is_local_ip "$remote_ip" && return
 
570
 
 
571
    local secondary_etc_directory=$root/$instance/etc
 
572
    : ${primary_etc_directory:=$remote_ip:$root/$other_instance/etc}
 
573
 
 
574
    log -srlc \
 
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" \
 
579
        -p \
 
580
        "$primary_etc_directory/$instance-*" \
 
581
        "$secondary_etc_directory/" \
 
582
        || exit_command 1 \
 
583
             "Failed to copy the key files of the OpenVista instance"
 
584
 
 
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()
 
592
        {
 
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"
 
596
        }
 
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
 
602
            log -srlc \
 
603
              "Removed existing SSH keys for the \"$instance\" instance from" \
 
604
              "$auth_file"
 
605
        else
 
606
            exit_command 1 \
 
607
               "Unable to remove existing SSH keys for the \"$instance\"" \
 
608
               "instance from $auth_file"
 
609
        fi
 
610
    fi
 
611
 
 
612
    # add keys to user's authorized_keys file
 
613
    add_instance_to_authorized_keys()
 
614
    {
 
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"
 
625
    }
 
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
 
629
        log -srlc \
 
630
          "Added SSH keys for the \"$instance\" instance to $auth_file"
 
631
    else
 
632
        exit_command 1 \
 
633
          "Unable to add SSH keys for the \"$instance\" instance to $auth_file"
 
634
    fi
 
635
 
 
636
    # set apache_user, apache_conf, docroot
 
637
    set_apache_vars
 
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")
 
642
    local error
 
643
    error=$(htpasswd -b -m "$passwdfile" "$username" "$password" 2>&1) \
 
644
      || exit_command 1 "Unable to update $apache_conf/webdav.htpasswd: $error"
 
645
 
 
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
 
651
        log -srlc \
 
652
          "The SSH host keys of the primary server have been copied to the" \
 
653
          "secondary server"
 
654
    else
 
655
        log -srlc \
 
656
          "Failed to copy the SSH host keys of the primary server to the" \
 
657
          "secondary server"
 
658
        exit_command $? \
 
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"
 
662
    fi
 
663
}
 
664
 
 
665
show_status()
 
666
{
 
667
    # Show the status of OpenVista replication for the instance
 
668
 
 
669
    log_func "$@"
 
670
    local scripted=false
 
671
    if [[ "$1" == "-s" ]]; then
 
672
        scripted=true
 
673
        shift
 
674
    fi
 
675
    arg_count 1 1 "$@" || exit_command 1
 
676
    local instance=$1
 
677
 
 
678
    # set instances
 
679
    is_openvista_instance $instance \
 
680
      || exit_command 2 "Not an OpenVista instance: $instance"
 
681
 
 
682
    # collect the data
 
683
    old_IFS=$IFS
 
684
    IFS=$'\n'
 
685
    instance_data=( $(get_status "$instance") )
 
686
    IFS=$old_IFS
 
687
 
 
688
    if $scripted; then
 
689
        printf '%s\n' "${instance_data[@]}"
 
690
    else
 
691
        tabulate_pairs "${instance_data[@]}"
 
692
    fi
 
693
}
 
694
 
 
695
get_status()
 
696
{
 
697
    # Return replication status data for a single OpenVista instance.
 
698
    # This data will be used to create the status table.
 
699
    #
 
700
    # The data being returned is in the format of
 
701
    #   "Label=value"
 
702
    #
 
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.
 
705
    #
 
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
 
708
    # function.
 
709
    local IFS=$' \t\n'
 
710
 
 
711
    log_func "$@"
 
712
    arg_count 1 1 "$@" || exit_command 1
 
713
    local instance=$1
 
714
 
 
715
    # clear and then set values from replication.conf
 
716
    unset replication_mode
 
717
    unset replication_ip
 
718
    unset bind_address
 
719
    unset other_instance
 
720
    unset mupip_port
 
721
    unset instsecondary
 
722
    unset rsync_port
 
723
    set_gtm_env -e "$instance"
 
724
 
 
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
 
729
        "IP address")
 
730
            ip_address=$bind_address
 
731
            host_name=$(echo "$local_names" | awk '{print $2;}')
 
732
            ;;
 
733
        "qualified hostname" | "unqualified hostname")
 
734
            host_name=$bind_address
 
735
            ip_address=${local_names%% *}
 
736
            ;;
 
737
    esac
 
738
    echo "Host name=${host_name:-($HOSTNAME)}"
 
739
    echo "IP address=${ip_address:-($(hostname -i))}"
 
740
    echo "Replicates with=$replication_ip"
 
741
    echo "-=-"
 
742
 
 
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"}
 
747
 
 
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"
 
752
 
 
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"
 
756
 
 
757
    port_status "GT.M port number" "$mupip_port" mupip
 
758
    echo "Replicating with="$(get_gtm_remote_host "$instance")
 
759
 
 
760
    old_IFS=$IFS
 
761
    IFS=$'\n'
 
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]}"
 
770
    IFS=$old_IFS
 
771
 
 
772
    mumps_pids=( $(get_mumps_pids "$instance") )
 
773
    echo "Mumps process count=${#mumps_pids[@]}"
 
774
 
 
775
    echo "-=-"
 
776
 
 
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)"
 
782
}
 
783
 
 
784
get_gtm_remote_host()
 
785
{
 
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.
 
789
 
 
790
    local instance=$1
 
791
    # get OpenVista environment
 
792
    set_gtm_env -v "$instance" || return $?
 
793
 
 
794
    local pid mode
 
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")
 
798
 
 
799
    if [[ "$mode" == "ACTIVE" ]]; then
 
800
        # primary
 
801
        # get the remote host from the mupip command arguments
 
802
        ps --format args= --pid "$pid" \
 
803
          | sed -nr "s/^.* -secondary=([^: ]+).*$/\1/p"
 
804
        return 0
 
805
    else
 
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
 
812
        local port
 
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
 
816
        netstat -antp \
 
817
          | grep :$port \
 
818
          | grep $pid \
 
819
          | sed -nr "s/^tcp.*:$port\s+([^:]+):.*$/\1/p"
 
820
        return 0
 
821
    fi
 
822
}
 
823
 
 
824
get_lsyncd_status()
 
825
{
 
826
    # pid and status of lsyncd daemon (should be on primary)
 
827
    log_func "$@"
 
828
    lsyncd_pid_file="$root/$instance/replication/lsyncd.pid"
 
829
    local value
 
830
 
 
831
    if [[ -f "$lsyncd_pid_file" ]]; then
 
832
        lsyncd_pid=$(< "$lsyncd_pid_file")
 
833
        value=$(check_pid "$lsyncd_pid")
 
834
    fi
 
835
 
 
836
    local running=$(echo "$value" | grep "Running")
 
837
    daemon_status_color "$value" primary "$replication_mode" "$running"
 
838
}
 
839
 
 
840
get_rsyncd_status()
 
841
{
 
842
    # pid and status of rsync daemon (should be on secondary)
 
843
    log_func "$@"
 
844
    rsyncd_pid_file="$root/$instance/replication/rsyncd.pid"
 
845
    local value
 
846
 
 
847
    if [[ -f "$rsyncd_pid_file" ]]; then
 
848
        rsyncd_pid=$(< "$rsyncd_pid_file")
 
849
        value=$(check_pid "$rsyncd_pid")
 
850
    fi
 
851
 
 
852
    local running=$(echo "$value" | grep "Running")
 
853
    daemon_status_color "$value" secondary "$replication_mode" "$running"
 
854
}
 
855
 
 
856
get_last_webdav_file()
 
857
{
 
858
    # filename of the last file added to the WebDAV directory
 
859
    #
 
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.
 
864
    #
 
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.
 
868
    log_func "$@"
 
869
    set_apache_vars
 
870
    local webdav_dir
 
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"
 
875
    fi
 
876
}
 
877
 
 
878
find_last_webdav_file()
 
879
{
 
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.
 
883
    # E.g.,
 
884
    #   find_last_webdav_file /var/www/html/webdav/open
 
885
    log_func "$@"
 
886
 
 
887
    local next_dir
 
888
    local last_file
 
889
 
 
890
    next_dir=$(find "$1" -mindepth 1 -maxdepth 1 -type d ! -empty \
 
891
                 | sort \
 
892
                 | tail -n1) \
 
893
      && [[ "$next_dir" ]] \
 
894
      && last_file=$(find_last_webdav_file "$next_dir") \
 
895
      || last_file=$(find "$1" -mindepth 1 -maxdepth 1 -type f \
 
896
                       | sort \
 
897
                       | tail -n1)
 
898
 
 
899
    [[ "$last_file" ]] && echo "$last_file"
 
900
}
 
901
 
 
902
get_routines_file_count()
 
903
{
 
904
    # number of files in the routines directory of the instance
 
905
    log_func "$@"
 
906
    routines_dir="$root/$instance/routines"
 
907
    find "$routines_dir" -type f | wc -l
 
908
    return 0
 
909
}
 
910
 
 
911
get_gtm_repl_instance_value()
 
912
{
 
913
    # Get a value from the mupip replication instance file report.
 
914
    log_func "$@"
 
915
    arg_count 2 2 "$@" || exit_command 1
 
916
    local instance=$1
 
917
    local label=$2
 
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"
 
922
}
 
923
 
 
924
list_configuration()
 
925
{
 
926
    # Show the replication configuration parameters of the instance.
 
927
 
 
928
    log_func "$@"
 
929
    local scripted=false
 
930
    if [[ "$1" == "-s" ]]; then
 
931
        scripted=true
 
932
        shift
 
933
    fi
 
934
    arg_count 1 1 "$@" || exit_command 1
 
935
    local instance=$1
 
936
 
 
937
    # set instances
 
938
    is_openvista_instance "$instance" \
 
939
      || exit_command 2 "Not an OpenVista instance: $instance"
 
940
 
 
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\""
 
945
 
 
946
    local replication_mode
 
947
    local replication_ip
 
948
    local bind_address
 
949
    local other_instance
 
950
    local mupip_port
 
951
    local instsecondary
 
952
    local rsync_port
 
953
    . "$conf_file"
 
954
 
 
955
    local settings
 
956
    settings=( \
 
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
 
965
        )
 
966
 
 
967
    if $scripted; then
 
968
        printf '%s\n' "${settings[@]}"
 
969
    else
 
970
        tabulate_pairs "${settings[@]}"
 
971
    fi
 
972
}
 
973
 
 
974
test_replication()
 
975
{
 
976
    # Write a value to the primary and read it on the secondary.
 
977
    log_func "$@"
 
978
    arg_count 1 1 "$@" || exit_command 1
 
979
    local instance=$1
 
980
 
 
981
    read_configuration "$instance" \
 
982
      || { log -srl $ov_error
 
983
           return 1; }
 
984
 
 
985
    local primary_ip
 
986
    local secondary_ip
 
987
    local primary_instance
 
988
    local secondary_instance
 
989
    case $replication_mode in
 
990
        "primary")
 
991
            primary_ip=$bind_address
 
992
            secondary_ip=$replication_ip
 
993
            primary_instance=$instance
 
994
            secondary_instance=$other_instance
 
995
            ;;
 
996
        "secondary")
 
997
            primary_ip=$replication_ip
 
998
            secondary_ip=$bind_address
 
999
            primary_instance=$other_instance
 
1000
            secondary_instance=$instance
 
1001
            ;;
 
1002
        "")
 
1003
            log -sr "Instance \"$instance\" is not configured for replication"
 
1004
            return 0
 
1005
            ;;
 
1006
        *)
 
1007
            log -src \
 
1008
              "For instance \"$instance\": replication mode is set to a value" \
 
1009
              "other than 'primary' or 'secondary': '$replication_mode'"
 
1010
            return 1
 
1011
            ;;
 
1012
    esac
 
1013
 
 
1014
    local x variable_value description
 
1015
    for x in \
 
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"
 
1020
    do
 
1021
        variable_value="${x%, *}"
 
1022
        description="${x##*, }"
 
1023
        [[ "$variable_value" ]] \
 
1024
          || { log -sr "For instance \"$instance\": failed to get $description"
 
1025
               return 1; }
 
1026
    done
 
1027
 
 
1028
    typeset -i retval=0
 
1029
 
 
1030
    log -src "Testing replication of instance \"$instance\"" \
 
1031
             "from $primary_ip to $secondary_ip:"
 
1032
 
 
1033
    test_gtm_replication \
 
1034
      || retval+=8
 
1035
 
 
1036
    routines_directory=$root/$instance/routines
 
1037
    test_file_replication "$routines_directory/MSCOVREPLTESTFILE.XXXXXXXX" \
 
1038
      || retval+=16
 
1039
 
 
1040
    set_apache_vars
 
1041
    webdav_directory=$docroot/webdav/$instance
 
1042
    test_file_replication "$webdav_directory/mscovrepltestfile.XXXXXXXX" \
 
1043
      || retval+=32
 
1044
 
 
1045
    return $retval
 
1046
}
 
1047
 
 
1048
test_gtm_replication()
 
1049
{
 
1050
    # Test replication of GT.M globals.
 
1051
    # This is a subroutine of test_replication() and assumes its variables.
 
1052
    log_func "$@"
 
1053
    arg_count 0 0 "$@" || exit_command 1
 
1054
 
 
1055
    local test_value=$(date --rfc-3339=ns)
 
1056
 
 
1057
    local global_name=MSCOVREPLTESTVAL
 
1058
 
 
1059
    local remote_call=$(cat <<EOF
 
1060
. /usr/lib/openvista/functions
 
1061
run_mumps_cmd "$primary_instance" 'S ^$global_name="$test_value"'
 
1062
EOF
 
1063
)
 
1064
    sshk -d "$primary_ip" "$remote_call" \
 
1065
      || { log -srl "    Failed writing the test value to the primary"
 
1066
           return 1; }
 
1067
 
 
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'
 
1073
EOF
 
1074
)
 
1075
    sshk -d "$secondary_ip" "$remote_call" \
 
1076
      1>/dev/null 2>&1 \
 
1077
      || { log -srl "    Failed to run a mumps command on the secondary"
 
1078
           return 1; }
 
1079
 
 
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'
 
1088
EOF
 
1089
)
 
1090
    local replication_successful=false
 
1091
    for (( i=0; i!=$allowed_delay; i++ )); do
 
1092
        sleep 1
 
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
 
1098
            break
 
1099
        fi
 
1100
        # count out the seconds
 
1101
        log -srn "$(( i+1 )) "
 
1102
    done
 
1103
 
 
1104
    local remote_call=$(cat <<EOF
 
1105
. /usr/lib/openvista/functions
 
1106
run_mumps_cmd "$primary_instance" 'K ^$global_name'
 
1107
EOF
 
1108
)
 
1109
    sshk -d "$primary_ip" "$remote_call"
 
1110
 
 
1111
    if $replication_successful; then
 
1112
        color_text green "successful" >&2
 
1113
        return 0
 
1114
    else
 
1115
        color_text red "failed" >&2
 
1116
        return 1
 
1117
    fi
 
1118
}
 
1119
 
 
1120
test_file_replication()
 
1121
{
 
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.
 
1124
    log_func "$@"
 
1125
    arg_count 1 1 "$@" || exit_command 1
 
1126
    local filename=$1
 
1127
 
 
1128
    filename=$(mktemp "$filename")
 
1129
 
 
1130
    local test_value=$(date --rfc-3339=ns)
 
1131
 
 
1132
    local remote_call=$(cat <<EOF
 
1133
echo "$test_value" >$filename
 
1134
EOF
 
1135
)
 
1136
    sshk -d $primary_ip "$remote_call"
 
1137
 
 
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
 
1145
        sleep 1
 
1146
        # read on the secondary
 
1147
        secondary_value=$(sshk "$secondary_ip" cat "$filename" \
 
1148
                            2>/dev/null)
 
1149
        if [[ "$secondary_value" == "$test_value" ]]; then
 
1150
            replication_successful=true
 
1151
            break
 
1152
        fi
 
1153
        # count out the seconds
 
1154
        log -srn "$(( i+1 )) "
 
1155
    done
 
1156
 
 
1157
    sshk "$primary_ip" rm -f "$filename"
 
1158
    sshk "$secondary_ip" rm -f "$filename"
 
1159
 
 
1160
    if $replication_successful; then
 
1161
        color_text green "successful" >&2
 
1162
        return 0
 
1163
    else
 
1164
        color_text red "failed" >&2
 
1165
        return 1
 
1166
    fi
 
1167
}
 
1168
 
 
1169
read_configuration()
 
1170
{
 
1171
    # Set replication variables from replication.conf.
 
1172
    # Unlike set_gtm_env(), this returns an error if there is no such file.
 
1173
    log_func "$@"
 
1174
    arg_count 1 1 "$@" || exit_command 1
 
1175
    local instance=$1
 
1176
 
 
1177
    unset replication_mode
 
1178
    unset replication_ip
 
1179
    unset bind_address
 
1180
    unset other_instance
 
1181
    unset mupip_port
 
1182
    unset instsecondary
 
1183
    unset rsync_port
 
1184
 
 
1185
    local conf_file=$root/$instance/etc/replication.conf
 
1186
    [[ -r "$conf_file" ]] \
 
1187
      || { ov_error="Could not read $conf_file"
 
1188
           return 1; }
 
1189
    . "$conf_file" \
 
1190
      || { ov_error="Could not source $conf_file"
 
1191
           return 1; }
 
1192
}
 
1193
 
 
1194
check_pid()
 
1195
{
 
1196
    # Output the pid and the status of its process
 
1197
    log_func "$@"
 
1198
    arg_count 1 1 "$@" || exit_command 1
 
1199
    local pid=$1
 
1200
    if is_number "$pid"; then
 
1201
        echo -n "PID $pid, "
 
1202
        if ps --pid "$pid" > /dev/null; then
 
1203
            echo "Running"
 
1204
        else
 
1205
            echo "Not running"
 
1206
        fi
 
1207
    fi
 
1208
}
 
1209
 
 
1210
resync()
 
1211
{
 
1212
    # Get a secondary instance back in sync with its primary instance.
 
1213
    log_func "$@"
 
1214
    arg_count 0 0 "$@" || exit_command 1
 
1215
 
 
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"
 
1222
 
 
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"
 
1236
 
 
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"
 
1244
    fi
 
1245
 
 
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"
 
1252
}
 
1253
 
 
1254
main_ "$@"