Last active
July 7, 2021 12:05
-
-
Save folex/d12b49b7ad7b18aae817 to your computer and use it in GitHub Desktop.
Opens ssh connections to aws or digitalocean host which starts with $1. Save as `awslist` or `dolist` for AWS and DO respectively.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
name="" | |
REGION="eu-central-1" | |
LISTONLY=false | |
SHOULDFORWARD=false | |
OSNAME=`uname` | |
TITLE="Name PublicIP PrivateIP InstanceType InstanceId PlacementGroup Purpose" | |
case $(basename $0) in | |
awslist) | |
DIGITALOCEAN=false | |
AWS=true | |
USER=ubuntu | |
;; | |
dolist) | |
DIGITALOCEAN=true | |
AWS=false | |
USER=root | |
;; | |
esac | |
while getopts "n:L:r:f:o:lhpxDAu:" opt; do | |
case $opt in | |
#SSH port forwarding | |
L) | |
SHOULDFORWARD=true | |
if [[ "$OPTARG" =~ .*:.*:.* ]]; then | |
echo "OPTARG is $OPTARG" | |
IFS=\: read -a fields <<<"$OPTARG" | |
STARTPORT="${fields[0]}" | |
FORWARDHOST="${fields[1]}" | |
FORWARDPORT="${fields[2]}" | |
else | |
STARTPORT="$OPTARG" | |
FORWARDPORT="$OPTARG" | |
FORWARDHOST="localhost" | |
fi | |
;; | |
n) MAXCOUNT="$OPTARG" ;; | |
l) LISTONLY=true ;; | |
r) REGION="$OPTARG" ;; | |
h) | |
echo ' USAGE: | |
-nNUMBER number of instances to use | |
-LPORT:HOST:REMOTEPORT ssh style port forwarding (PORT incremented for multiple instances) | |
-l list only | |
-rREGION specify region (AWS only) | |
-h this help | |
-fFILENAME specify file with public ips | |
-oARGS additional ssh args, passed to ssh with -o | |
-p use Purpose tag for instance filtering (AWS only) | |
-x enables regex (AWS only) | |
-D query instances from DigitalOcean (doctl) | |
-A query instances from AWS (awscli) | |
-u SSH user | |
NOTE: | |
Script filename `awslist` will default to `-A -u ubuntu`. | |
Script filename `dolist` will default to `-D -u root`. | |
' | |
exit 0 | |
;; | |
f) SOURCEFILE="$OPTARG" ;; | |
o) SSH_ARGS="$OPTARG" ;; | |
p) FILTER_BY_PURPOSE=true ;; | |
x) REGEX=true ;; | |
D) DIGITALOCEAN=true; AWS=false ;; | |
A) AWS=true; DIGITALOCEAN=false ;; | |
u) USER="$OPTARG" ;; | |
:) echo "Option -$OPTARG requires an argument"; exit 1 ;; | |
esac | |
done | |
shift $(expr $OPTIND - 1 ) | |
name="$1" | |
function fetchAndFilter() { | |
# field we're selecting (filtering) on | |
FIELD="$1" | |
if [ -n "$2" ]; then | |
# query, string we're looking for | |
Q="\"$2\"" | |
# P is the predicate we use for filtering | |
# 'test' is like 'contains' but with regex | |
[ "$REGEX" = "true" ] && P="test" || P="contains" | |
SELECT="select (opt($FIELD) | $P($Q)) |" | |
fi | |
aws ec2 describe-instances --region $REGION | jq -r " | |
def tag(f): .Tags | from_entries | f; | |
def get(f): . | f // empty; | |
def opt(f): . | f | tostring | select (length > 0) // \"-\"; | |
flatten | .[].Instances[] | $SELECT | |
\"\(tag(.Name)) \(get(.PublicIpAddress)) \(.PrivateIpAddress) \(.InstanceType) \(.InstanceId) \(opt(.Placement | .GroupName)) \(tag(.Purpose))\" | |
" | |
} | |
function loadFromAws() { | |
if [[ -z `which aws` ]]; then | |
echo "aws cli tools should be installed! https://aws.amazon.com/cli/" | |
exit 0 | |
fi | |
if [[ "$FILTER_BY_PURPOSE" == "true" ]]; then | |
nodes=$(fetchAndFilter "tag(.Purpose)" "$name") | |
else | |
nodes=$(fetchAndFilter "tag(.Name)" "$name") | |
fi | |
length=$(echo "$nodes" | grep . | wc -l) | |
} | |
function loadFromFile() { | |
length=$(wc -l $SOURCEFILE | awk '{print $1}') | |
nodes=$(cat $SOURCEFILE | awk '{ | |
print $1 "|at|" $1 | |
}') | |
} | |
function loadFromDigitalOcean() { | |
if [[ -z `which doctl` ]]; then | |
echo "doctl should be installed! https://github.com/digitalocean/doctl" | |
exit 0 | |
fi | |
TITLE="Name PublicIPv4 VCPUs ID Region Tags" | |
nodes="$(doctl compute droplet list --format ${TITLE// /,} --no-header)" | |
if [[ -n $name ]]; then | |
nodes=$(echo "$nodes" | grep $name) | |
fi | |
length=$(echo "$nodes" | grep . | wc -l) | |
} | |
if [[ "$DIGITALOCEAN" == true ]]; then | |
loadFromDigitalOcean | |
else | |
if [[ ! -z $SOURCEFILE ]]; then | |
echo "Loading from file" | |
loadFromFile | |
else | |
loadFromAws | |
fi | |
fi | |
# yeah, single brackets, double brackets, I know | |
if [[ $length -gt 0 ]]; then | |
nodes=$(echo "$nodes" | sort) | |
if [[ -n $MAXCOUNT ]]; then | |
nodes=$(echo "$nodes" | head -n $MAXCOUNT) | |
length=$MAXCOUNT | |
fi | |
echo -e $TITLE"\n""$nodes" | column -t | |
if [[ "$LISTONLY" != true ]]; then | |
echo "Creating tmux session for $length nodes" | |
session=$(tmux new -dPs $name 2>/dev/null) | |
if [[ -z "${session// }" ]]; then | |
session=$(tmux new -dP) | |
fi | |
echo "$nodes" | tr "|" " " | \ | |
awk \ | |
-v SESSION=$session \ | |
-v SHOULDFORWARD=$SHOULDFORWARD \ | |
-v STARTPORT=$STARTPORT \ | |
-v FORWARDHOST=$FORWARDHOST \ | |
-v FORWARDPORT=$FORWARDPORT \ | |
-v SSH_ARGS="$SSH_ARGS" \ | |
-v OSNAME=$OSNAME \ | |
-v USER=$USER '{ | |
ip = $2 | |
name = $1 | |
sshcommand="\"ssh -o StrictHostKeyChecking=no " USER "@" ip | |
if (SHOULDFORWARD == "true") { | |
resultport=STARTPORT + NR - 1 | |
sshcommand=sshcommand " -L" resultport ":" FORWARDHOST ":" FORWARDPORT | |
} | |
if (length(SSH_ARGS) > 0) { | |
sshcommand=sshcommand " -o " SSH_ARGS | |
} | |
sshcommand=sshcommand "\"" | |
command="tmux split-window -t " SESSION " -v " sshcommand | |
print(command) | |
system(command) | |
title_command="tmux send-keys -t " SESSION " printf Space \\\"\\\\033]2\\;%s\\\\033\\\\\\\\\\\" Space \\\" " name "\\\" Enter" | |
system(title_command) | |
system("tmux select-layout -t " SESSION " tiled") | |
}' | |
tmux kill-pane -t $session"0.0" | |
tmux select-layout -t $session tiled | |
tmux attach | |
fi | |
else | |
echo "No matches" | |
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ~/.tmux.conf | |
set -g mouse on | |
bind ` setw synchronize-panes |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment