Last active
August 3, 2020 20:07
-
-
Save stevenpetryk/37e5eef94dcf6dfff62bc0059d4f5b98 to your computer and use it in GitHub Desktop.
A bitbar app that starts and stops a DO droplet
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
Host workspace | |
User steven | |
ForwardAgent yes | |
ControlPersist 300 | |
HostName 64.225.89.72 | |
StrictHostKeyChecking no | |
UserKnownHostsFile=/dev/null |
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
#!/usr/bin/env bash | |
set -euo pipefail | |
# README | |
# | |
# This script creates a BitBar application that lets you manage a Droplet | |
# suitable for daily development use. When you're done working, it will power | |
# down, snapshot, and destroy the droplet to save you money. | |
# | |
# When you're ready to work again, it will create a new Droplet from the | |
# snapshot and assign a floating IP to it. | |
# | |
# Credit to @andrewhamon for the idea. I just made it a BitBar application. | |
# See https://github.com/andrewhamon/pcmd | |
################################################################################ | |
# Configuration | |
# —————————————————————————————————————————————————————————————————————————————— | |
# You can duplicate this file and change the $NAME variable to have multiple | |
# workspaces. Make sure you make all $NAMEs unique. Beware DigitalOcean's rate | |
# limits when doing this. | |
################################################################################ | |
# The name given in the Mac menu bar | |
NICKNAME="Workspace" | |
# The DigitalOcean Droplet size, image and region | |
SIZE=s-6vcpu-16gb | |
IMAGE=ubuntu-18-04-x64 | |
REGION=sfo3 | |
# The name given to the actual Droplet and the prefix given to every snapshot. | |
# If you have multiple copies of this script, you should change this to a unique | |
# name in each one. | |
NAME=workspace.$IMAGE | |
# The IP of a floating IP you MUST set up before using this script. It will give | |
# your Droplet a stable IP address to SSH into. It does cost a few dollars a | |
# month when it's not assigned to a Droplet. | |
FLOATING_IP=64.225.89.72 | |
################################################################################ | |
# Code (no need to edit) | |
################################################################################ | |
export PATH="/usr/local/bin:$PATH" | |
if ! command -v jq &> /dev/null; then | |
echo "Ensure jq is installed." | |
exit | |
fi | |
if ! command -v doctl &> /dev/null; then | |
echo "Ensure doctl is installed and authenticated." | |
exit | |
fi | |
log(){ | |
echo $@ >&2 | |
} | |
# Run commands with stdout and stderr redirected to /dev/null | |
shush(){ | |
$@ &>/dev/null | |
} | |
fetch_ssh_keys(){ | |
log "Fetching account SSH keys" | |
# Join ids with a comma, and delete the trailing comma | |
doctl compute ssh-key list --format ID --no-header | tr '\n' ',' | sed 's/,$//' | |
} | |
# Find the most recent snapshot that includes the VPS name as the prefix of the | |
# snapshot name | |
fetch_latest_snapshot(){ | |
local prefix=$1 | |
# log "Checking for existing snapshot" | |
doctl compute snapshot list --format Name,ID --no-header | grep $prefix | sort | tail -1 | awk '{print $NF}' | |
} | |
fetch_running_droplet(){ | |
local prefix=$1 | |
log "Checking for existing droplet" | |
doctl compute droplet list --format Name,ID --no-header | grep $prefix | tail -1 | awk '{print $NF}' | |
} | |
create_and_wait(){ | |
local image=$1 | |
local ssh_keys=$(fetch_ssh_keys) | |
log "Creating instance $NAME" | |
doctl compute droplet create $NAME \ | |
--image $image \ | |
--region $REGION \ | |
--size $SIZE \ | |
--ssh-keys $ssh_keys \ | |
--enable-monitoring \ | |
--enable-private-networking \ | |
--enable-ipv6 \ | |
--format ID,PublicIPv4 \ | |
--no-header \ | |
--wait | |
} | |
assign_floating_ip_and_wait(){ | |
local instance_id=$1 | |
log "Assigning floating IP $FLOATING_IP to $instance_id" | |
doctl compute floating-ip-action assign $FLOATING_IP $instance_id | |
} | |
shutdown_and_wait(){ | |
local instance_id=$1 | |
log "Shutting down" | |
shush doctl compute droplet-action shutdown $instance_id --wait | |
} | |
snapshot_and_wait(){ | |
local old_snapshot_id=$(fetch_latest_snapshot $NAME) | |
local instance_id=$1 | |
local snapshot_name=$NAME.$(date -u +"%Y-%m-%dT%H:%M:%SZ") | |
log "Taking snapshot" | |
shush doctl compute droplet-action snapshot $instance_id --snapshot-name $snapshot_name --wait | |
} | |
delete(){ | |
local instance_id=$1 | |
log "Deleting instance" | |
shush doctl compute droplet delete --force $instance_id | |
} | |
start(){ | |
local latest_snapshot_id=$(fetch_latest_snapshot $NAME) | |
local create_result | |
case $latest_snapshot_id in | |
(*[![:space:]]*) | |
log "Snapshot found: $latest_snapshot_id" | |
create_and_wait $latest_snapshot_id | |
;; | |
(*) | |
log "Snapshot not found" | |
create_and_wait $IMAGE | |
;; | |
esac | |
local instance_id=$(fetch_running_droplet $NAME) | |
assign_floating_ip_and_wait $instance_id | |
} | |
stop(){ | |
local instance_id=$(fetch_running_droplet $NAME) | |
shutdown_and_wait $instance_id | |
snapshot_and_wait $instance_id | |
delete $instance_id | |
} | |
fetch_status() { | |
local prefix=$1 | |
local status=$(doctl compute droplet list --format Name,Status --no-header | grep $prefix | tail -1 | awk '{print $NF}') | |
if [ -z "$status" ]; then | |
echo "🔴" | |
else | |
echo "🟢 $status" | |
fi | |
} | |
if [ $# -eq 0 ]; then | |
status=$(fetch_status $NAME) | |
amount=$(doctl invoice summary preview --format Amount --no-header) | |
echo "$NICKNAME $status" | |
echo "---" | |
echo "Usage: \$$amount" | |
if [ "$status" = "🔴" ]; then | |
echo "Start $NICKNAME | bash='$0 start'" | |
else | |
echo "Stop $NICKNAME | bash='$0 stop'" | |
fi | |
else | |
case $1 in | |
"start") | |
start | |
;; | |
"stop") | |
stop | |
;; | |
"cleanup") | |
cleanup_old_snapshots | |
esac | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment