Apply or unapply a patch to remote Evergreen hosts
[sitka/sitka-tools.git] / patching / patch-eg.sh
1 #!/bin/bash
2 # Author: schan@sitka.bclibraries.ca
3
4 Help() {
5         cat<<____
6
7 DESCRIPTION:
8 Apply or unapply a patch to remote Evergreen hosts
9
10 USAGE:
11 ./patch-eg.sh -p ID [ -b backup_label ] [ -P rule ] [ -y ] [ -R ] [ -h ] host1 host2...
12
13 OPTIONS:
14     -p SHA1 ID of patch to apply (mandatory)
15     -b Backup label of patch
16        Defaults to patch ID
17     -P Patch rule (web, xul, perl) to determine patch directory, user, and strip level
18        Defaults to 'web'
19     -y Yes, apply the patch instead of doing a dry run
20     -R Reverse or undo the patch instead of applying it
21     -h Print this message and exit
22 ____
23 }
24
25 # Parse command line for run-time options
26 while getopts 'p:b:P:yRh' Option; do
27         case $Option in
28         (p) Patch_ID=$OPTARG;;
29         (b) Patch_Backup=$OPTARG;;
30         (P) Patch_Rule=$OPTARG;;
31         (y) Runit='';;
32         (R) Reverse='-R';;
33         (h) Help && exit 0;;
34         esac
35 done
36 shift $(( $OPTIND - 1 ))
37
38 # Calculate default options
39 Remote_Host=${1:?}
40 Patch_ID=${Patch_ID:?}
41 Patch_Backup=${Patch_Backup:-$Patch_ID}
42 Patch_Rule=${Patch_Rule:-web}
43 Runit=${Runit-'--dry-run'}
44 Reverse=${Reverse-''}
45
46 # Define function to echo the intended action for a host
47 Echo_Intention() {
48         [[ $Runit == '--dry-run' ]] && echo -ne '\nDry run: '
49         if [[ $Reverse == '-R' ]]; then echo -n 'Reversing '; else echo -n 'Applying '; fi
50         echo -e "patch $Patch_ID to $1 and backing up as $Patch_Backup"
51 }
52
53 # Associate the patch rule to patch path, strip level, and sudo user
54 # If patch rule is 'perl', the patch path will be dynamically determined from the host
55 declare -A Rule
56 case $Patch_Rule in
57     (web)  Rule=( [path]=/srv/openils/var             [level]=2 [sudo]=opensrf );;
58     (xul)  Rule=( [path]=/srv/openils/var/web/xul     [level]=4 [sudo]=opensrf );;
59     (perl) Rule=( [path]=/usr/local/share/perl/5.14.2 [level]=5 [sudo]=root    );;
60 esac
61
62
63 # Set local environment
64
65 # Domain name of patch host (Evergreen)
66 #declare -r SOURCE="git.evergreen-ils.org/?p=Evergreen.git"
67 # Domain name of patch host (Sitka)
68 declare -r SOURCE="git.sitka.bclibraries.ca/gitweb/?p=sitka/evergreen.git"
69 # Domain name of target hosts
70 declare -r TARGET=sitka.bclibraries.ca
71 # Name of ssh and sudo user
72 declare -r LOGIN=sitkastaff
73
74
75 # Calculate command text strings
76 declare -r SUDO="sudo -p '' -S -u ${Rule[sudo]}"
77 declare -r Patch_URL="http://$SOURCE;a=patch;h=$Patch_ID"
78 declare -r WGET="wget -q -O - '$Patch_URL'"
79 declare -r Backup_Policy="-b -B .patch/$Patch_Backup/ -V simple"
80 declare -r PATCH="patch $Runit $Reverse -r - $Backup_Policy -p${Rule[level]}"
81 declare -r OPENILS_DIR="perl -MOpenILS -e 'print \$INC{qq(OpenILS.pm)}'"
82
83 # Define function to find directory name of the OpenILS Perl module at a host
84 Perl_Dir() { dirname $(ssh "$LOGIN@$1.$TARGET" $OPENILS_DIR); }
85
86 # Define function to patch a directory at a host via ssh sudo
87 Patch_Dir() { ssh "$LOGIN@$1.$TARGET" "$SUDO bash -c \"$WGET | $PATCH -d $2 \""; }
88
89 # Ask the user once for sudo password
90 read -s -p "$LOGIN's sudo password: " Password ; echo
91
92 for Host; do
93         Echo_Intention $Host
94         [[ $Patch_Rule == 'perl' ]] && Rule[path]=$(Perl_Dir $Host)
95         Patch_Dir $Host ${Rule[path]} <<< $Password
96 done