This repository has been archived by the owner on Jan 25, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 190
/
Copy pathrun-nomad
executable file
·410 lines (350 loc) · 10.6 KB
/
run-nomad
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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
#!/bin/bash
# This script is used to configure and run Nomad on an AWS server.
set -e
readonly NOMAD_CONFIG_FILE="default.hcl"
readonly SYSTEMD_CONFIG_PATH="/etc/systemd/system/nomad.service"
readonly EC2_INSTANCE_METADATA_URL="http://169.254.169.254/latest/meta-data"
readonly EC2_INSTANCE_DYNAMIC_DATA_URL="http://169.254.169.254/latest/dynamic"
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SCRIPT_NAME="$(basename "$0")"
function print_usage {
echo
echo "Usage: run-nomad [OPTIONS]"
echo
echo "This script is used to configure and run Nomad on an AWS server."
echo
echo "Options:"
echo
echo -e " --server\t\tIf set, run in server mode. Optional. At least one of --server or --client must be set."
echo -e " --client\t\tIf set, run in client mode. Optional. At least one of --server or --client must be set."
echo -e " --num-servers\t\tThe number of servers to expect in the Nomad cluster. Required if --server is true."
echo -e " --config-dir\t\tThe path to the Nomad config folder. Optional. Default is the absolute path of '../config', relative to this script."
echo -e " --data-dir\t\tThe path to the Nomad data folder. Optional. Default is the absolute path of '../data', relative to this script."
echo -e " --bin-dir\t\tThe path to the folder with Nomad binary. Optional. Default is the absolute path of the parent folder of this script."
echo -e " --systemd-stdout\t\tThe StandardOutput option of the systemd unit. Optional. If not configured, uses systemd's default (journal)."
echo -e " --systemd-stderr\t\tThe StandardError option of the systemd unit. Optional. If not configured, uses systemd's default (inherit)."
echo -e " --user\t\tThe user to run Nomad as. Optional. Default is to use the owner of --config-dir."
echo -e " --use-sudo\t\tIf set, run the Nomad agent with sudo. By default, sudo is only used if --client is set."
echo -e " --environment\t\A single environment variable in the key/value pair form 'KEY=\"val\"' to pass to Nomad as environment variable when starting it up. Repeat this option for additional variables. Optional."
echo -e " --skip-nomad-config\tIf this flag is set, don't generate a Nomad configuration file. Optional. Default is false."
echo
echo "Example:"
echo
echo " run-nomad --server --config-dir /custom/path/to/nomad/config"
}
function log {
local readonly level="$1"
local readonly message="$2"
local readonly timestamp=$(date +"%Y-%m-%d %H:%M:%S")
>&2 echo -e "${timestamp} [${level}] [$SCRIPT_NAME] ${message}"
}
function log_info {
local readonly message="$1"
log "INFO" "$message"
}
function log_warn {
local readonly message="$1"
log "WARN" "$message"
}
function log_error {
local readonly message="$1"
log "ERROR" "$message"
}
# Based on code from: http://stackoverflow.com/a/16623897/483528
function strip_prefix {
local readonly str="$1"
local readonly prefix="$2"
echo "${str#$prefix}"
}
function assert_not_empty {
local readonly arg_name="$1"
local readonly arg_value="$2"
if [[ -z "$arg_value" ]]; then
log_error "The value for '$arg_name' cannot be empty"
print_usage
exit 1
fi
}
function split_by_lines {
local prefix="$1"
shift
for var in "$@"; do
echo "${prefix}${var}"
done
}
function lookup_path_in_instance_metadata {
local readonly path="$1"
curl --silent --location "$EC2_INSTANCE_METADATA_URL/$path/"
}
function lookup_path_in_instance_dynamic_data {
local readonly path="$1"
curl --silent --location "$EC2_INSTANCE_DYNAMIC_DATA_URL/$path/"
}
function get_instance_ip_address {
lookup_path_in_instance_metadata "local-ipv4"
}
function get_instance_id {
lookup_path_in_instance_metadata "instance-id"
}
function get_instance_availability_zone {
lookup_path_in_instance_metadata "placement/availability-zone"
}
function get_instance_region {
lookup_path_in_instance_dynamic_data "instance-identity/document" | jq -r ".region"
}
function assert_is_installed {
local readonly name="$1"
if [[ ! $(command -v ${name}) ]]; then
log_error "The binary '$name' is required by this script but is not installed or in the system's PATH."
exit 1
fi
}
function generate_nomad_config {
local readonly server="$1"
local readonly client="$2"
local readonly num_servers="$3"
local readonly config_dir="$4"
local readonly user="$5"
local readonly config_path="$config_dir/$NOMAD_CONFIG_FILE"
local instance_id=""
local instance_ip_address=""
local instance_region=""
local instance_availability_zone=""
instance_id=$(get_instance_id)
instance_ip_address=$(get_instance_ip_address)
instance_region=$(get_instance_region)
availability_zone=$(get_instance_availability_zone)
local server_config=""
if [[ "$server" == "true" ]]; then
server_config=$(cat <<EOF
server {
enabled = true
bootstrap_expect = $num_servers
}
EOF
)
fi
local client_config=""
if [[ "$client" == "true" ]]; then
client_config=$(cat <<EOF
client {
enabled = true
}
EOF
)
fi
log_info "Creating default Nomad config file in $config_path"
cat > "$config_path" <<EOF
datacenter = "$availability_zone"
name = "$instance_id"
region = "$instance_region"
bind_addr = "0.0.0.0"
advertise {
http = "$instance_ip_address"
rpc = "$instance_ip_address"
serf = "$instance_ip_address"
}
$client_config
$server_config
consul {
address = "127.0.0.1:8500"
}
EOF
chown "$user:$user" "$config_path"
}
function generate_systemd_config {
local readonly systemd_config_path="$1"
local readonly nomad_config_dir="$2"
local readonly nomad_data_dir="$3"
local readonly nomad_bin_dir="$4"
local readonly nomad_sytemd_stdout="$5"
local readonly nomad_sytemd_stderr="$6"
local readonly nomad_user="$7"
local readonly use_sudo="$8"
shift 8
local readonly environment=("$@")
local readonly config_path="$nomad_config_dir/$NOMAD_CONFIG_FILE"
if [[ "$use_sudo" == "true" ]]; then
log_info "The --use-sudo flag is set, so running Nomad as the root user"
nomad_user="root"
fi
log_info "Creating systemd config file to run Nomad in $systemd_config_path"
local readonly unit_config=$(cat <<EOF
[Unit]
Description="HashiCorp Nomad"
Documentation=https://www.nomadproject.io/
Requires=network-online.target
After=network-online.target
ConditionalFileNotEmpty=$config_path
EOF
)
local readonly service_config=$(cat <<EOF
[Service]
User=$nomad_user
Group=$nomad_user
ExecStart=$nomad_bin_dir/nomad agent -config $nomad_config_dir -data-dir $nomad_data_dir
ExecReload=/bin/kill --signal HUP \$MAINPID
KillMode=process
Restart=on-failure
LimitNOFILE=65536
$(split_by_lines "Environment=" "${environment[@]}")
EOF
)
local log_config=""
if [[ ! -z $nomad_sytemd_stdout ]]; then
log_config+="StandardOutput=$nomad_sytemd_stdout\n"
fi
if [[ ! -z $nomad_sytemd_stderr ]]; then
log_config+="StandardError=$nomad_sytemd_stderr\n"
fi
local readonly install_config=$(cat <<EOF
[Install]
WantedBy=multi-user.target
EOF
)
echo -e "$unit_config" > "$systemd_config_path"
echo -e "$service_config" >> "$systemd_config_path"
echo -e "$log_config" >> "$systemd_config_path"
echo -e "$install_config" >> "$systemd_config_path"
}
function start_nomad {
log_info "Reloading systemd config and starting Nomad"
sudo systemctl daemon-reload
sudo systemctl enable nomad.service
sudo systemctl restart nomad.service
}
# Based on: http://unix.stackexchange.com/a/7732/215969
function get_owner_of_path {
local readonly path="$1"
ls -ld "$path" | awk '{print $3}'
}
function run {
local server="false"
local client="false"
local num_servers=""
local config_dir=""
local data_dir=""
local bin_dir=""
local systemd_stdout=""
local systemd_stderr=""
local user=""
local skip_nomad_config="false"
local use_sudo=""
local environment=()
local all_args=()
while [[ $# > 0 ]]; do
local key="$1"
case "$key" in
--server)
server="true"
;;
--client)
client="true"
;;
--num-servers)
num_servers="$2"
shift
;;
--config-dir)
assert_not_empty "$key" "$2"
config_dir="$2"
shift
;;
--data-dir)
assert_not_empty "$key" "$2"
data_dir="$2"
shift
;;
--bin-dir)
assert_not_empty "$key" "$2"
bin_dir="$2"
shift
;;
--systemd-stdout)
assert_not_empty "$key" "$2"
systemd_stdout="$2"
shift
;;
--systemd-stderr)
assert_not_empty "$key" "$2"
systemd_stderr="$2"
shift
;;
--user)
assert_not_empty "$key" "$2"
user="$2"
shift
;;
--cluster-tag-key)
assert_not_empty "$key" "$2"
cluster_tag_key="$2"
shift
;;
--cluster-tag-value)
assert_not_empty "$key" "$2"
cluster_tag_value="$2"
shift
;;
--skip-nomad-config)
skip_nomad_config="true"
;;
--use-sudo)
use_sudo="true"
;;
--environment)
assert_not_empty "$key" "$2"
environment+=("$2")
shift
;;
--help)
print_usage
exit
;;
*)
log_error "Unrecognized argument: $key"
print_usage
exit 1
;;
esac
shift
done
if [[ "$server" == "true" ]]; then
assert_not_empty "--num-servers" "$num_servers"
fi
if [[ "$server" == "false" && "$client" == "false" ]]; then
log_error "At least one of --server or --client must be set"
exit 1
fi
if [[ -z "$use_sudo" ]]; then
if [[ "$client" == "true" ]]; then
use_sudo="true"
else
use_sudo="false"
fi
fi
assert_is_installed "systemctl"
assert_is_installed "aws"
assert_is_installed "curl"
assert_is_installed "jq"
if [[ -z "$config_dir" ]]; then
config_dir=$(cd "$SCRIPT_DIR/../config" && pwd)
fi
if [[ -z "$data_dir" ]]; then
data_dir=$(cd "$SCRIPT_DIR/../data" && pwd)
fi
if [[ -z "$bin_dir" ]]; then
bin_dir=$(cd "$SCRIPT_DIR/../bin" && pwd)
fi
# If $systemd_stdout and/or $systemd_stderr are empty, we leave them empty so that generate_systemd_config will use systemd's defaults (journal and inherit, respectively)
if [[ -z "$user" ]]; then
user=$(get_owner_of_path "$config_dir")
fi
if [[ "$skip_nomad_config" == "true" ]]; then
log_info "The --skip-nomad-config flag is set, so will not generate a default Nomad config file."
else
generate_nomad_config "$server" "$client" "$num_servers" "$config_dir" "$user"
fi
generate_systemd_config "$SYSTEMD_CONFIG_PATH" "$config_dir" "$data_dir" "$bin_dir" "$systemd_stdout" "$systemd_stderr" "$user" "$use_sudo" "${environment[@]}"
start_nomad
}
run "$@"