Skip to content

Instantly share code, notes, and snippets.

@blurayne
Last active February 13, 2019 20:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save blurayne/001fb1b9f00f644047a2c10eb84e5e02 to your computer and use it in GitHub Desktop.
Save blurayne/001fb1b9f00f644047a2c10eb84e5e02 to your computer and use it in GitHub Desktop.
SSH to EC2 using peco and awless
#!/bin/bash
###
# SSH to AWS EC2 instances using peco and awless
#
# - Generate a cache of AWS instances
# - Open peco to select one or more server and either open ssh or tmux-css
# - Does not use `awless ssh` since prefererence on ‘security by obscurity’
#
# Dependencies
#
# https://github.com/peikk0/tmux-cssh
# https://github.com/peco/peco
# https://github.com/wallix/awless
#
# Part of bash-raclette
# Strict bash scripting
set -euo pipefail -o errtrace
# Using XDG standards ;)
CACHE_PATH="${CACHE_PATH:-$HOME/.cache/rc}"
if [[ -z "${AWS_PROFILES:-}" ]]; then
echo "$(basename $0): No AWS_PROFILES defined"
exit 1
fi
IFS=' ' read -r -a awsProfiles <<< "$AWS_PROFILES"
# hide up cmd output
on_exit_hide_cmd() {
echo -e "\r\e[K\r\e[1A"
}
# output to stdin after run and press return
runcmd (){
echo "$@" | perl -e 'ioctl STDOUT, 0x5412, $_ for split //, <>' ;
trap on_exit_hide_cmd EXIT
}
# output to stdin after run
writecmd (){
echo "$@" | perl -e 'ioctl STDOUT, 0x5412, $_ for split //, do{ chomp($_ = <>); $_ }' ;
trap on_exit_hide_cmd EXIT
}
cachefile_valid() {
local ftime=$(stat -c %Y $1 2>/dev/null)
if [[ -z "$ftime" ]]; then
return 1
fi
# better of with printf here yet trying to be nice to osx's bash3
local now=$(date +%s)
if [[ $(( ${ftime} + 3600 + 24 )) -gt ${now} ]]; then
return 0;
else
return 1
fi
}
update_aws_instance_cache() {
local cmd=()
local cacheFile
local sync=0
if [[ ! -d "$CACHE_PATH" ]]; then
mkdir -p "$CACHE_PATH"
fi
for profile in ${awsProfiles[@]}; do
cacheFile="$CACHE_PATH/aws-$profile-instances.list"
if ! cachefile_valid $CACHE_PATH/aws-$profile-instances.list 1; then
cmd=(
awless -p "$profile" list instances \
--columns id,name,state,keypair,privateip,publicip,tags \
--format=csv --sort name --no-headers '|' xargs -I {} echo $profile,{}
)
( eval ${cmd[@]} > "$cacheFile.new" && mv "$cacheFile.new" "$cacheFile" ) &
if [[ -e "$cacheFile" ]]; then
# if file is old we background process and continue
disown
else
echo "awless: generating cache for $profile"
sync=1
fi
fi
if [[ "$sync" -eq 1 ]]; then
for job in $(jobs -p); do wait $job || ( echo "failure..." && exit 1 ); done
fi
done
}
list_aws_instances() {
for profile in ${awsProfiles[@]}; do
cat "$CACHE_PATH/aws-$profile-instances.list"
done
}
format_aws_instance_csv() {
printf "%s\n" "$@" | sed ':a;N;$!ba;s/\n/\n\n---\n/g' | tr ',' '\n'
}
main() {
update_aws_instance_cache
IFS=$'\n' instances=($(list_aws_instances | peco --initial-filter Fuzzy --prompt "aws-instance>"))
if [[ -z "${instances[*]}" ]]; then
return
fi
format_aws_instance_csv "${instances[@]}"
local cmd="ssh"
echo "${#instances[@]}"
if [[ "${#instances[@]}" -gt 1 ]]; then
cmd="tmux-cssh"
fi
cmd="${cmd} ${@} $(printf "%s\n" "${instances[@]}" | cut -d ',' -f 6 | tr '\n' ' ')"
echo
echo ---
writecmd "${cmd}"
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment