-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathwaffles.sh
More file actions
executable file
·229 lines (201 loc) · 6.24 KB
/
waffles.sh
File metadata and controls
executable file
·229 lines (201 loc) · 6.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#!/usr/bin/env bash
# Functions
# help prints a standard help message
function help {
echo
echo "waffles - A simple configuration management and deployment tool."
echo
echo "Options:"
echo " -h: help"
echo " -d: debug"
echo " -n: noop"
echo " -r: role, stored in site/roles"
echo " -t: run in test mode. exit 1 if changes were made"
echo
echo " -c: (push) the number of times to retry connecting. Default: 5"
echo " -k: (push) the ssh key to use. Default: ~/.ssh/id_rsa"
echo " -s: (push) remote server to connect to through SSH"
echo " -u: (push) the remote user to connect as through SSH. Default: root"
echo " -w: (push) the amount of time in seconds to wait between retrying. Default: 5"
echo " -y: (push) whether or not to use sudo remotely. Default: false"
echo " -z: (push) the remote directory to copy Waffles to. Default: /etc/waffles"
echo
echo "Usage:"
echo " waffles.sh -r <role>: apply a role to the local server"
echo " waffles.sh -s www.example.com -u root -r web: apply the web role remotely to www.example.com as root"
echo " waffles.sh -d -r web: apply the web role locally in debug mode"
echo " waffles.sh -n -r web: apply the web role locally in no-op mode"
echo " waffles.sh -t -r web: apply the web role locally in test mode"
echo
exit 1
}
# apply_role_locally applies the role to the local node
function apply_role_locally {
stdlib.include $role_script
# If WAFFLES_TEST is set, exit 1 if any changes where made
if [[ -n $WAFFLES_TEST ]]; then
[[ $stdlib_resource_changes -eq 0 ]] || exit 1
fi
}
# apply_role_remotely applies the role to a remote node
function apply_role_remotely {
if [[ -z $WAFFLES_REMOTE_SSH_KEY ]] || [[ ! -f $WAFFLES_REMOTE_SSH_KEY ]]; then
stdlib.error "SSH key not specified or not found."
exit 1
fi
stdlib.include $role_script
local _include
for i in "${!stdlib_remote_copy[@]}"; do
if [[ $i =~ sh$ ]]; then
_include="$_include --include=$i"
else
_include="$_include --include=$i/**"
fi
done
local _args
local _rsync_quiet="-q"
if [[ -n $WAFFLES_NOOP ]]; then
_args="$_args -n"
fi
if [[ -n $WAFFLES_DEBUG ]]; then
_args="$_args -d"
_rsync_quiet=""
fi
# To deploy to explicit IPv6 addresses, use the bracket form ([fd00:abcd::1]) and let the following code take care of the rest.
local _rsync_server
local _ssh_server
if [[ $server =~ [][] ]]; then
server="${server/[/}"
server="${server/]/}"
_rsync_server="[$WAFFLES_SSH_USER@$server]"
_ssh_server="$WAFFLES_SSH_USER@$server"
else
_rsync_server="$WAFFLES_SSH_USER@$server"
_ssh_server="$WAFFLES_SSH_USER@$server"
fi
# Determine if "sudo" is required
local _remote_rsync_path
local _remote_ssh_command
if [[ -n $WAFFLES_REMOTE_SUDO ]]; then
_remote_rsync_path="sudo rsync"
_remote_ssh_command="sudo bash waffles.sh"
else
_remote_rsync_path="rsync"
_remote_ssh_command="bash waffles.sh"
fi
stdlib.debug "Testing connectivity to $_ssh_server"
_ssh_status=255
_attempt=0
while [[ $_ssh_status -ne 0 && $_attempt -lt $WAFFLES_REMOTE_SSH_ATTEMPTS ]]; do
_attempt=$(( _attempt+1 ))
stdlib.debug "Attempt $_attempt of $WAFFLES_REMOTE_SSH_ATTEMPTS."
stdlib.debug_mute ssh -i $WAFFLES_REMOTE_SSH_KEY $_ssh_server pwd
_ssh_status=$?
if [[ $_ssh_status -ne 0 ]]; then
if [[ $_attempt -lt $WAFFLES_REMOTE_SSH_ATTEMPTS ]]; then
stdlib.debug "Unable to connect. Waiting $WAFFLES_REMOTE_SSH_WAIT seconds."
sleep $WAFFLES_REMOTE_SSH_WAIT
fi
fi
done
if [[ $_ssh_status != 0 ]]; then
stdlib.error "Unable to connect to $_ssh_server. Exiting."
exit 1
fi
stdlib.debug "Copying Waffles to remote server $_rsync_server"
rsync -azv $_rsync_quiet -e "ssh -i $WAFFLES_REMOTE_SSH_KEY" --rsync-path="$_remote_rsync_path" --include='**/' --include='waffles.sh' --include='waffles.conf' --include='lib/**' --include="$WAFFLES_SITE_DIR/roles/${role}.sh" --exclude='*' --prune-empty-dirs $WAFFLES_DIR/ "$_rsync_server:$WAFFLES_REMOTE_DIR"
stdlib.debug "Copying site to remote server $_rsync_server"
rsync -azv $_rsync_quiet -e "ssh -i $WAFFLES_REMOTE_SSH_KEY" --rsync-path="$_remote_rsync_path" --include="**/" $_include --include="roles/${role}.sh" --exclude='*' --prune-empty-dirs $WAFFLES_SITE_DIR/ "$_rsync_server:$WAFFLES_REMOTE_DIR/site/"
ssh -i $WAFFLES_REMOTE_SSH_KEY $_ssh_server "cd $WAFFLES_REMOTE_DIR && $_remote_ssh_command $_args -r $role"
}
# Main Script
# Try to find waffles.conf in either /etc/waffles or ~/.waffles
if [[ -f "/etc/waffles/waffles.conf" ]]; then
source /etc/waffles/waffles.conf
fi
if [[ -f ~/.waffles/waffles.conf ]]; then
source ~/.waffles/waffles.conf
fi
# If CONFIG_FILE or WAFFLES_CONFIG_FILE is set, prefer it
if [[ -n $CONFIG_FILE ]]; then
source "$CONFIG_FILE"
fi
if [[ -n $WAFFLES_CONFIG_FILE ]]; then
source "$WAFFLES_CONFIG_FILE"
fi
# Make sure WAFFLES_SITE_DIR has a value
if [[ -z $WAFFLES_SITE_DIR ]]; then
echo "WAFFLES_SITE_DIR is not set."
exit 1
fi
# Read in the standard library
source "$WAFFLES_DIR/lib/init.sh"
# Parse options
while getopts :c:dhk:nr:s:tu:w:yz: opt; do
case $opt in
c)
WAFFLES_REMOTE_SSH_ATTEMPTS="$OPTARG"
;;
d)
WAFFLES_DEBUG=1
;;
h)
help
exit 1
;;
k)
WAFFLES_REMOTE_SSH_KEY="$OPTARG"
;;
n)
WAFFLES_NOOP=1
;;
r)
role="$OPTARG"
;;
s)
WAFFLES_REMOTE=1
server="$OPTARG"
;;
t)
WAFFLES_TEST=1
;;
u)
WAFFLES_SSH_USER="$OPTARG"
;;
w)
WAFFLES_REMOTE_SSH_WAIT="$OPTARG"
;;
y)
WAFFLES_REMOTE_SUDO="true"
;;
z)
WAFFLES_REMOTE_DIR="$OPTARG"
;;
:)
echo "Option -$OPTARG requires an argument." >&2
help
exit 1;
;;
\?)
echo "Invalid option: -$OPTARG" >&2
help
exit 1
;;
esac
done
if [[ -z $role ]]; then
help
exit 1
fi
# Make sure the role is defined in a script.
role_script="${WAFFLES_SITE_DIR}/roles/${role}.sh"
if [[ ! -f $role_script ]]; then
stdlib.error "File $role_script does not exist for role $role."
exit 1
fi
# Call either the local or remote apply_role function
if [[ -n $server ]]; then
(apply_role_remotely)
else
(apply_role_locally)
fi