Skip to content

Commit 8d08f9d

Browse files
committed
Auto-source toolbelt configs
If `toolbelt.auto` is set to true, /etc/skel/.profile and /root/.profile will be updated to source the /var/vcap/jobs/toolbelt/envrc automatically. The former allows new `bosh ssh` sessions to function and the latter means that you don't lose stuff when you `sudo -i` This commit also introduces a new colorized prompt for toolbelt that provides useful information about what deployment / job / index you are currently logged into, and visually differentiates root from non-root.
1 parent 39243b2 commit 8d08f9d

File tree

9 files changed

+348
-5
lines changed

9 files changed

+348
-5
lines changed

jobs/toolbelt/monit

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
check file toolbelt
2-
path /etc/envrc
3-
start program "/bin/cp /var/vcap/jobs/toolbelt/envrc /etc/envrc"
1+
check process toolbelt
2+
with pidfile /var/vcap/sys/run/toolbelt/toolbelt.pid
3+
start program "/var/vcap/jobs/toolbelt/bin/monit_debugger toolbelt_ctl '/var/vcap/jobs/toolbelt/bin/ctl start'"
4+
stop program "/var/vcap/jobs/toolbelt/bin/monit_debugger toolbelt_ctl '/var/vcap/jobs/toolbelt/bin/ctl stop'"
45
group vcap

jobs/toolbelt/spec

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
name: toolbelt
33
packages: []
44
templates:
5+
bin/ctl: bin/ctl
6+
bin/monit_debugger: bin/monit_debugger
7+
data/properties.sh.erb: data/properties.sh
8+
helpers/ctl_setup.sh: helpers/ctl_setup.sh
9+
helpers/ctl_utils.sh: helpers/ctl_utils.sh
510
envrc: envrc
611

7-
properties: {}
12+
properties:
13+
toolbelt.auto:
14+
description: Automatically configure the environment when you login.
15+
default: true

jobs/toolbelt/templates/bin/ctl

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/bin/bash
2+
3+
set -e # exit immediately if a simple command exits with a non-zero status
4+
set -u # report the usage of uninitialized variables
5+
6+
source /var/vcap/jobs/toolbelt/helpers/ctl_setup.sh 'toolbelt'
7+
export LANG=en_US.UTF-8
8+
9+
setup_sleeper() {
10+
FDIR=$(mktemp -d)
11+
mkfifo $FDIR/fifo
12+
exec 3<> $FDIR/fifo
13+
trap "exec 2<&-; rm -r $FDIR" EXIT
14+
}
15+
16+
checkenv() {
17+
trap "exit 0" INT TERM QUIT
18+
command=". ${JOB_DIR}/envrc"
19+
<% if p('toolbelt.auto') %>
20+
# toolbelt.auto is enabled; adding envrc to .profiles
21+
for profile in /root/.profile /etc/skel/.profile; do
22+
if ! grep -q "^${command}\$" ${profile} >/dev/null 2>&1; then
23+
echo "${command}" >> ${profile}
24+
fi
25+
done
26+
27+
<% else %>
28+
for profile in /root/.profile /etc/skel/.profile; do
29+
# toolbelt.auto is disabled; stripping envrc from .profiles
30+
if grep -q "^${command}\$" ${profile} >/dev/null 2>&1; then
31+
sed -i -e "s@^${command}\$@@" ${profile}
32+
fi
33+
done
34+
<% end %>
35+
36+
# sleep 60
37+
read -t 60 -u 3 var || true
38+
}
39+
40+
case $1 in
41+
42+
start)
43+
pid_guard $PIDFILE $JOB_NAME
44+
echo $$ > $PIDFILE
45+
setup_sleeper
46+
while true; do checkenv; done
47+
;;
48+
49+
stop)
50+
kill_and_wait $PIDFILE
51+
52+
;;
53+
*)
54+
echo "Usage: master_ctl {start|stop}"
55+
56+
;;
57+
58+
esac
59+
exit 0
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/bin/sh
2+
# USAGE monit_debugger <label> command to run
3+
mkdir -p /var/vcap/sys/log/monit
4+
{
5+
echo "MONIT-DEBUG date"
6+
date
7+
echo "MONIT-DEBUG env"
8+
env
9+
echo "MONIT-DEBUG $@"
10+
$2 $3 $4 $5 $6 $7
11+
R=$?
12+
echo "MONIT-DEBUG exit code $R"
13+
} >/var/vcap/sys/log/monit/monit_debugger.$1.log 2>&1
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env bash
2+
3+
# job template binding variables
4+
5+
# job name & index of this VM within cluster
6+
# e.g. JOB_NAME=redis, JOB_INDEX=0
7+
export NAME='<%= name %>'
8+
export JOB_INDEX=<%= index %>
9+
# full job name, like redis/0 or webapp/3
10+
export JOB_FULL="$NAME/$JOB_INDEX"

jobs/toolbelt/templates/envrc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,17 @@ for package in $(find /var/vcap/packages -type l -name 'toolbelt-*'); do
1616
fi
1717
done
1818
done
19+
20+
21+
red=$(tput setaf 1)
22+
green=$(tput setaf 2)
23+
blue=$(tput setaf 4)
24+
cyan=$(tput setaf 6)
25+
rst=$(tput sgr0)
26+
PS1="==[]=[ ${cyan}<%= spec.deployment %>${rst} ${green}<%= spec.job.name %>/<%= spec.index %>${rst} ]=[]=="
27+
if [[ "${UID}" -eq 0 ]]; then
28+
PS1="$PS1\n\\t ${red}\\u${rst} ${blue}\\w\\e \$${rst} "
29+
else
30+
PS1="$PS1\n\\t ${blue}\\u \\w #${rst} "
31+
fi
32+
export PS1="\[${PS1}\]"
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#!/usr/bin/env bash
2+
3+
# Setup env vars and folders for the ctl script
4+
# This helps keep the ctl script as readable
5+
# as possible
6+
7+
# Usage options:
8+
# source /var/vcap/jobs/foobar/helpers/ctl_setup.sh JOB_NAME OUTPUT_LABEL
9+
# source /var/vcap/jobs/foobar/helpers/ctl_setup.sh foobar
10+
# source /var/vcap/jobs/foobar/helpers/ctl_setup.sh foobar foobar
11+
# source /var/vcap/jobs/foobar/helpers/ctl_setup.sh foobar nginx
12+
13+
set -e # exit immediately if a simple command exits with a non-zero status
14+
set -u # report the usage of uninitialized variables
15+
16+
JOB_NAME=$1
17+
output_label=${2:-${JOB_NAME}}
18+
19+
export JOB_DIR=/var/vcap/jobs/$JOB_NAME
20+
chmod 755 $JOB_DIR # to access file via symlink
21+
22+
# Load some bosh deployment properties into env vars
23+
# Try to put all ERb into data/properties.sh.erb
24+
# incl $NAME, $JOB_INDEX, $WEBAPP_DIR
25+
source $JOB_DIR/data/properties.sh
26+
27+
source $JOB_DIR/helpers/ctl_utils.sh
28+
redirect_output ${output_label}
29+
30+
export HOME=${HOME:-/home/vcap}
31+
32+
# Add all packages' /bin & /sbin into $PATH
33+
for package_bin_dir in $(ls -d /var/vcap/packages/*/*bin)
34+
do
35+
export PATH=${package_bin_dir}:$PATH
36+
done
37+
38+
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-''} # default to empty
39+
for package_bin_dir in $(ls -d /var/vcap/packages/*/lib)
40+
do
41+
export LD_LIBRARY_PATH=${package_bin_dir}:$LD_LIBRARY_PATH
42+
done
43+
44+
# Setup log, run and tmp folders
45+
46+
export RUN_DIR=/var/vcap/sys/run/$JOB_NAME
47+
export LOG_DIR=/var/vcap/sys/log/$JOB_NAME
48+
export TMP_DIR=/var/vcap/sys/tmp/$JOB_NAME
49+
export STORE_DIR=/var/vcap/store/$JOB_NAME
50+
for dir in $RUN_DIR $LOG_DIR $TMP_DIR $STORE_DIR
51+
do
52+
mkdir -p ${dir}
53+
chown vcap:vcap ${dir}
54+
chmod 775 ${dir}
55+
done
56+
export TMPDIR=$TMP_DIR
57+
58+
export C_INCLUDE_PATH=/var/vcap/packages/mysqlclient/include/mysql:/var/vcap/packages/sqlite/include:/var/vcap/packages/libpq/include
59+
export LIBRARY_PATH=/var/vcap/packages/mysqlclient/lib/mysql:/var/vcap/packages/sqlite/lib:/var/vcap/packages/libpq/lib
60+
61+
# consistent place for vendoring python libraries within package
62+
if [[ -d ${WEBAPP_DIR:-/xxxx} ]]
63+
then
64+
export PYTHONPATH=$WEBAPP_DIR/vendor/lib/python
65+
fi
66+
67+
if [[ -d /var/vcap/packages/java7 ]]
68+
then
69+
export JAVA_HOME="/var/vcap/packages/java7"
70+
fi
71+
72+
# setup CLASSPATH for all jars/ folders within packages
73+
export CLASSPATH=${CLASSPATH:-''} # default to empty
74+
for java_jar in $(ls -d /var/vcap/packages/*/*/*.jar)
75+
do
76+
export CLASSPATH=${java_jar}:$CLASSPATH
77+
done
78+
79+
PIDFILE=$RUN_DIR/$output_label.pid
80+
81+
echo '$PATH' $PATH
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
# Helper functions used by ctl scripts
2+
3+
# links a job file (probably a config file) into a package
4+
# Example usage:
5+
# link_job_file_to_package config/redis.yml [config/redis.yml]
6+
# link_job_file_to_package config/wp-config.php wp-config.php
7+
link_job_file_to_package() {
8+
source_job_file=$1
9+
target_package_file=${2:-$source_job_file}
10+
full_package_file=$WEBAPP_DIR/${target_package_file}
11+
12+
link_job_file ${source_job_file} ${full_package_file}
13+
}
14+
15+
# links a job file (probably a config file) somewhere
16+
# Example usage:
17+
# link_job_file config/bashrc /home/vcap/.bashrc
18+
link_job_file() {
19+
source_job_file=$1
20+
target_file=$2
21+
full_job_file=$JOB_DIR/${source_job_file}
22+
23+
echo link_job_file ${full_job_file} ${target_file}
24+
if [[ ! -f ${full_job_file} ]]
25+
then
26+
echo "file to link ${full_job_file} does not exist"
27+
else
28+
# Create/recreate the symlink to current job file
29+
# If another process is using the file, it won't be
30+
# deleted, so don't attempt to create the symlink
31+
mkdir -p $(dirname ${target_file})
32+
ln -nfs ${full_job_file} ${target_file}
33+
fi
34+
}
35+
36+
# If loaded within monit ctl scripts then pipe output
37+
# If loaded from 'source ../utils.sh' then normal STDOUT
38+
redirect_output() {
39+
SCRIPT=$1
40+
mkdir -p /var/vcap/sys/log/monit
41+
exec 1>> /var/vcap/sys/log/monit/$SCRIPT.log 2>&1
42+
}
43+
44+
pid_guard() {
45+
pidfile=$1
46+
name=$2
47+
48+
if [ -f "$pidfile" ]; then
49+
pid=$(head -1 "$pidfile")
50+
51+
if [ -n "$pid" ] && [ -e /proc/$pid ]; then
52+
echo "$name is already running, please stop it first"
53+
exit 1
54+
fi
55+
56+
echo "Removing stale pidfile..."
57+
rm $pidfile
58+
fi
59+
}
60+
61+
wait_pid() {
62+
pid=$1
63+
try_kill=$2
64+
timeout=${3:-0}
65+
force=${4:-0}
66+
countdown=$(( $timeout * 10 ))
67+
68+
echo wait_pid $pid $try_kill $timeout $force $countdown
69+
if [ -e /proc/$pid ]; then
70+
if [ "$try_kill" = "1" ]; then
71+
echo "Killing $pidfile: $pid "
72+
kill $pid
73+
fi
74+
while [ -e /proc/$pid ]; do
75+
sleep 0.1
76+
[ "$countdown" != '0' -a $(( $countdown % 10 )) = '0' ] && echo -n .
77+
if [ $timeout -gt 0 ]; then
78+
if [ $countdown -eq 0 ]; then
79+
if [ "$force" = "1" ]; then
80+
echo -ne "\nKill timed out, using kill -9 on $pid... "
81+
kill -9 $pid
82+
sleep 0.5
83+
fi
84+
break
85+
else
86+
countdown=$(( $countdown - 1 ))
87+
fi
88+
fi
89+
done
90+
if [ -e /proc/$pid ]; then
91+
echo "Timed Out"
92+
else
93+
echo "Stopped"
94+
fi
95+
else
96+
echo "Process $pid is not running"
97+
echo "Attempting to kill pid anyway..."
98+
kill $pid
99+
fi
100+
}
101+
102+
wait_pidfile() {
103+
pidfile=$1
104+
try_kill=$2
105+
timeout=${3:-0}
106+
force=${4:-0}
107+
countdown=$(( $timeout * 10 ))
108+
109+
if [ -f "$pidfile" ]; then
110+
pid=$(head -1 "$pidfile")
111+
if [ -z "$pid" ]; then
112+
echo "Unable to get pid from $pidfile"
113+
exit 1
114+
fi
115+
116+
wait_pid $pid $try_kill $timeout $force
117+
118+
rm -f $pidfile
119+
else
120+
echo "Pidfile $pidfile doesn't exist"
121+
fi
122+
}
123+
124+
kill_and_wait() {
125+
pidfile=$1
126+
# Monit default timeout for start/stop is 30s
127+
# Append 'with timeout {n} seconds' to monit start/stop program configs
128+
timeout=${2:-25}
129+
force=${3:-1}
130+
if [[ -f ${pidfile} ]]
131+
then
132+
wait_pidfile $pidfile 1 $timeout $force
133+
else
134+
# TODO assume $1 is something to grep from 'ps ax'
135+
pid="$(ps auwwx | grep "$1" | awk '{print $2}')"
136+
wait_pid $pid 1 $timeout $force
137+
fi
138+
}
139+
140+
check_nfs_mount() {
141+
opts=$1
142+
exports=$2
143+
mount_point=$3
144+
145+
if grep -qs $mount_point /proc/mounts; then
146+
echo "Found NFS mount $mount_point"
147+
else
148+
echo "Mounting NFS..."
149+
mount $opts $exports $mount_point
150+
if [ $? != 0 ]; then
151+
echo "Cannot mount NFS from $exports to $mount_point, exiting..."
152+
exit 1
153+
fi
154+
fi
155+
}

templates/jobs.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,6 @@ jobs:
2121

2222
networks: (( param "please set networks" ))
2323

24-
properties: {}
24+
properties:
25+
toolbelt:
26+
auto: true

0 commit comments

Comments
 (0)