Skip to content

Instantly share code, notes, and snippets.

@wheresjames
Last active October 28, 2020 15:47
Show Gist options
  • Save wheresjames/4eb2b6e7ee9080fb701623421b939be8 to your computer and use it in GitHub Desktop.
Save wheresjames/4eb2b6e7ee9080fb701623421b939be8 to your computer and use it in GitHub Desktop.

GCloud site publishing script

#!/bin/bash
#--------------------------------------------------------------------
# Created by Robert Umbehant
#--------------------------------------------------------------------
#
# https://cloud.google.com/appengine/docs/standard/python/getting-started/hosting-a-static-website
#
#--------------------------------------------------------------------
#
# List users
# $ gcloud.sh login-list
#
# Create new login credentials
# $ gcloud.sh login
#
# Switch to another existing user
# $ gcloud.sh login-switch <username>
#
# Revoke user credentials
# $ gcloud.sh revoke <username>
#
# Set project (converts website.com to project name website-com)
# $ gcloud.sh setproject <website.com>
#
# Compress / Publish
# $ gcloud.sh compress-publish <website.com> /var/www/html/website
#
# Create load balancer
# $ gcloud.sh ip-ssl-loadbalancer-create-list example.com
#
#--------------------------------------------------------------------
# Usage
USAGE="USAGE: gcloud.sh <cmd>"
#--------------------------------------------------------------------
# Functions
#--------------------------------------------------------------------
isCmd()
{
# - separator
FOUND=$(echo "\-$COMMANDLIST-" | grep -o "\-${1}-")
if [[ ! -z $FOUND ]]; then return 0; fi
# , separator
FOUND=$(echo ",$COMMANDLIST," | grep -o ",${1},")
if [[ ! -z $FOUND ]]; then return 0; fi
return -1
}
findInStr()
{
FIND_LIST=$1
FIND_EXISTS=$(echo $FIND_LIST | grep -o $2)
if [[ ! -z $FIND_EXISTS ]]; then return 0; fi
return -1
}
findIn()
{
findInStr "$($1)" $2
return $?
}
showWarning()
{
if [[ 0 -lt ${#@} ]]; then
echo -e "[\e[1;33mWARNING\e[1;0m] \e[1;33m${@}\e[1;0m"
fi
}
exitWithError()
{
if [[ 0 -lt ${#@} ]]; then
echo
echo "--------------------------------------------------------------------"
echo -e "[\e[1;31mERROR\e[1;0m] \e[1;31m${@}\e[1;0m"
echo "--------------------------------------------------------------------"
echo
fi
exit -1
}
exitOnError()
{
if [[ 0 -eq $? ]]; then return 0; fi
exitWithError $@
}
warnOnError()
{
if [[ 0 -eq $? ]]; then return 0; fi
showWarning $@
}
isOnline()
{
wget -q --tries=1 --timeout=8 --spider http://google.com
return $?
}
# Download specified file
# @param $1 - File name
# @param $2 - URL Link
# @returns Path to tool
downloadTool()
{
# Tool path
if [ ! -d "$TOOLPATH" ]; then
mkdir -p "$TOOLPATH"
exitOnError "Failed to create path : $TOOLPATH"
fi
# Final tool path
TOOLDNL="${TOOLPATH}/${1}"
# Download the tool if we don't have it
if [ ! -f $TOOLDNL ]; then
echo "Downloading $1..."
echo
curl -L $2 -o $TOOLDNL
exitOnError "CURL failed to download $1"
if [ ! -f $TOOLDNL ]; then
exitWithError "Failed to download $1"
fi
fi
}
# @param $1 - Tool file name
# @param $2 - grep pattern to find exec in zip
# @param $3 - URL to zip file
downloadToolCompressed()
{
TOOLEXEC="${TOOLPATH}/$1"
# Already exists?
if [ -f "${TOOLEXEC}" ]; then return 0; fi
TOOLEXT="${3##*.}"
# Remove existing
TMPZIP="${TOOLPATH}/tmp.${TOOLEXT}"
if [ -f "$TMPZIP" ]; then
rm "$TMPZIP"
fi
# Download the archive
downloadTool "tmp.${TOOLEXT}" $3
if [ ! -f "$TMPZIP" ]; then
exitWithError "Failed to download tool $1"
fi
# Lose old path
TMPZIPPATH="${TOOLPATH}/tmp-${TOOLEXT}"
if [ -d "$TMPZIPPATH" ]; then
rm -Rf "$TMPZIPPATH"
fi
# Create path to extract files
mkdir -p "$TMPZIPPATH"
exitOnError "Failed to create path : $TMPZIPPATH"
case ${TOOLEXT,,} in
"zip")
unzip "$TMPZIP" -d "$TMPZIPPATH"
;;
*)
exitWithError "Unknown archive type : ${TOOLEXT,,}"
;;
esac
# Find the file
TOOLFIND=$(find $TMPZIPPATH | grep -E $2 | head -1)
if [ -z $TOOLFIND ] || [ ! -f $TOOLFIND ]; then
exitWithError "Failed to find in archive : $2 -> $1"
fi
# Copy the exe we found
mv "$TOOLFIND" "$TOOLEXEC"
# Cleanup
rm "$TMPZIP"
rm -Rf "$TMPZIPPATH"
}
# Download compression tools
initCompress()
{
JAVA=$(which java)
if [ -z "$JAVA" ] || [ ! -f "$JAVA" ]; then
exitOnError "Java not installed"
fi
# Closer compiler
downloadToolCompressed "cc.jar" "closure-compiler" "https://dl.google.com/closure-compiler/compiler-latest.zip"
CCEXEC=$TOOLEXEC
# HTML Minifier
MINEXEC=$(which html-minifier)
if [ -z "$MINEXEC" ] || [ ! -f "$MINEXEC" ]; then
npm install html-minifier -g
exitOnError "Failed to install html-minifier"
fi
MINEXEC=$(which html-minifier)
if [ -z "$MINEXEC" ] || [ ! -f "$MINEXEC" ]; then
exitOnError "Failed to install html-minifier"
fi
downloadTool "yui.jar" "https://github.com/yui/yuicompressor/releases/download/v2.4.8/yuicompressor-2.4.8.jar"
YUIEXEC=$TOOLDNL
if [ -z "$TOOLDNL" ] || [ ! -f "$TOOLDNL" ]; then
exitOnError "Failed to install html-minifier"
fi
echo
echo "--------------------------------------------------------------------"
echo "- JAVA : $JAVA"
echo "- CLOSURE COMPILER : $CCEXEC"
echo "- HTML MINIFIER : $MINEXEC"
echo "- CSS MINIFIER : $YUIEXEC"
echo "--------------------------------------------------------------------"
echo
}
# Compresses a web site
# @param $1 - Input directory
# @param $2 - Output directory
compressWeb()
{
echo "- Compressing : $1"
if [[ $1 =~ ".." ]]; then
exitOnError "Invalid directory : $1"
fi
if [ ! -d "$1" ]; then
exitOnError "Directory doesn't exist : $1"
fi
if [ ! -d "$2" ]; then
mkdir -p $2
exitOnError "Failed to create directory : $2"
fi
FILES=$1/*
for SRC in $FILES
do
FNAME=`basename $SRC`
TGT=$2/$FNAME
if [ -d $SRC ]; then
compressWeb $SRC $TGT
# Is the directory empty?
elif [[ $SRC =~ "*" ]]; then
echo "Empty directory : $SRC -> $TGT"
# Is it already minimized?
elif [[ $SRC =~ ".min." ]]; then
echo "Copy Minimized File : $SRC -> $TGT"
cp "$SRC" "$TGT"
exitOnError "(d) Failed to copy $SRC -> $TGT"
# Process this file
else
EXT="${FNAME##*.}"
echo "$EXT : $SRC -> $TGT"
case ${EXT,,} in
"js")
$JAVA -jar $CCEXEC --js_output_file "$TGT" --js "$SRC"
if [[ 0 -ne $? ]]; then
echo "!!! Failed to build $SRC"
cp "$SRC" "$TGT"
exitOnError "(a) Failed to copy $SRC -> $TGT"
fi
;;
"css")
$JAVA -jar $YUIEXEC -o "$TGT" "$SRC"
if [[ 0 -ne $? ]]; then
echo "!!! Failed to build $SRC"
cp "$SRC" "$TGT"
exitOnError "(b) Failed to copy $SRC -> $TGT"
fi
;;
"htm" | "html")
$MINEXEC --collapse-whitespace -o "$TGT" "$SRC"
if [[ 0 -ne $? ]]; then
echo "!!! Failed to build $SRC"
cp "$SRC" "$TGT"
exitOnError "(c) Failed to copy $SRC -> $TGT"
fi
;;
*)
cp "$SRC" "$TGT"
exitOnError "(d) Failed to copy $SRC -> $TGT"
;;
esac
fi
done
return 1
}
#--------------------------------------------------------------------
# Command line
#--------------------------------------------------------------------
SCRIPT_NAME=$(basename $0)
SCRIPT_PATH=$(dirname "$(readlink -f "$0")")
WORKING_PATH=$(pwd)
COMMANDLIST=$1
if [ -z $COMMANDLIST ]; then
echo $USAGE
exit 0
fi
#--------------------------------------------------------------------
# Config
#--------------------------------------------------------------------
GCLOUD="gcloud"
GSUTIL="gsutil"
# Tools
TOOLPATH="${SCRIPT_PATH}/tools"
# gcloud compute regions list
REGIONOPT='--global'
#REGION="--region us-east1"
#REGION="--region europe-north1"
# Network
NETWORKOPT=""
echo "------------------------- Configuration ----------------------------"
echo "- COMMANDS : $COMMANDLIST"
echo "- SCRIPT : $SCRIPT_NAME"
echo "- SCRIPT PATH : $SCRIPT_PATH"
echo "- WORKING PATH : $WORKING_PATH"
echo "- GCLOUD EXE : $GCLOUD"
echo "- GSUTIL EXE : $GSUTIL"
echo "- REGION : $REGIONOPT"
echo "- NETWORK : $NETWORKOPT"
echo "--------------------------------------------------------------------"
echo
$GCLOUD config list
echo
echo "--------------------------------------------------------------------"
echo
if ! isOnline; then
showWarning "You do not appear to be online"
fi
# Init gcloud
if isCmd "init"; then
echo "Initialize..."
$GCLOUD init
exit 0
fi
# Configure
if isCmd "config"; then
echo "Projects..."
$GCLOUD projects list
echo
echo "Configuration..."
$GCLOUD config list
echo
exit 0
fi
# Login
if isCmd "login"; then
if isCmd "list"; then
echo "Accounts..."
$GCLOUD auth list
elif isCmd "switch"; then
USERNAME="$2"
if [ -z $USERNAME ]; then
echo "$USAGE <username>"
echo
exitWithError "Username not specified"
fi
echo "Switch to : "
$GCLOUD config set account $USERNAME
elif isCmd "revoke"; then
USERNAME="$2"
if [ -z $USERNAME ]; then
echo "$USAGE <username>"
echo
exitWithError "Username not specified"
fi
echo "Revoke user credentials : "
$GCLOUD config revoke $USERNAME
else
echo "Login..."
$GCLOUD auth login
fi
exit 0
fi
#--------------------------------------------------------------------
# Website / project must be specified after this point
#--------------------------------------------------------------------
USAGE="$USAGE <website.com>"
WEBSITE=$2
if [ -z $WEBSITE ]; then
echo "$USAGE"
echo
exitWithError "Website / project not specified"
fi
PROJECT="${WEBSITE//./-}"
BUCKET="gs://www.${WEBSITE}"
if [ "$PROJECT" = "$WEBSITE" ]; then
exitWithError "Invalid website : $WEBSITE"
fi
echo "--------------------------------------------------------------------"
echo "- PROJECT : $PROJECT"
echo "- WEBSITE : $WEBSITE"
echo "- BUCKET : $BUCKET"
echo "--------------------------------------------------------------------"
# Set the active project
if isCmd "setproject"; then
$GCLOUD config set project ${PROJECT}
fi
# Make sure the project specified is the active project
ACTIVEPROJECT=$($GCLOUD config get-value project)
if ! findInStr $ACTIVEPROJECT "$PROJECT"; then
echo
echo "Active project: $ACTIVEPROJECT"
exitWithError "Project you specified ($PROJECT) is not active"
fi
#--------------------------------------------------------------------
# Static IP
if isCmd "ip"; then
if isCmd "create"; then
if ! findIn "gcloud compute addresses list" "${PROJECT}-ip"; then
echo "--- CREATE STATIC IP ADDRESS ---"
$GCLOUD compute addresses create ${PROJECT}-ip $REGIONOPT
exitOnError "Failed to create static IP address"
fi
fi
if isCmd "delete"; then
if findIn "gcloud compute addresses list" "${PROJECT}-ip"; then
echo "--- DELETE STATIC IP ADDRESS ---"
$GCLOUD compute addresses delete ${PROJECT}-ip
fi
fi
if isCmd "list"; then
echo "--- STATIC IP ADDRESSES ---"
$GCLOUD compute addresses list
echo
fi
fi
# See if we have an external ip
EXTERNALIP=$(gcloud compute addresses list | grep -Eo ${PROJECT}-ip.*$ | grep -Eo '([0-9]{1,3}\.?){4}')
if [ ! -z $EXTERNALIP ]; then
echo
echo "EXTERNAL IP : ${EXTERNALIP}"
echo
fi
#--------------------------------------------------------------------
# SSL
if isCmd "ssl"; then
if isCmd "create"; then
if ! findIn "$GCLOUD compute ssl-certificates list" "${PROJECT}-cert"; then
echo "--- Create SSL Certificate ---"
$GCLOUD beta compute ssl-certificates create ${PROJECT}-cert \
$REGIONOPT \
--domains ${WEBSITE},www.${WEBSITE}
exitOnError "Failed to create SSL Certificate"
fi
fi
if isCmd "delete"; then
if findIn "$GCLOUD compute ssl-certificates list" "${PROJECT}-cert"; then
echo "--- Delete SSL Certificate ---"
$GCLOUD beta compute ssl-certificates delete ${PROJECT}-cert
fi
fi
if isCmd "list"; then
echo "--- SSL Certificates ---"
$GCLOUD compute ssl-certificates list
echo
fi
fi
#--------------------------------------------------------------------
# Load balancer
if isCmd "loadbalancer"; then
if isCmd "delete"; then
#------------------------------------------------------------
# HTTP
# Delete firewall rule to let in traffic
if findIn "gcloud compute firewall-rules list" "${PROJECT}-http-fw"; then
echo "Deleting firewall rule ${PROJECT}-http-fw"
$GCLOUD compute firewall-rules delete ${PROJECT}-http-fw -q
fi
# Delete forwarding rule
if findIn "$GCLOUD compute forwarding-rules list" "${PROJECT}-http-fr"; then
echo "Deleting forwarding rule ${PROJECT}-http-fr"
$GCLOUD compute forwarding-rules delete ${PROJECT}-http-fr $REGIONOPT -q
fi
# Delete http proxy
if findIn "$GCLOUD compute target-http-proxies list" "${PROJECT}-http-proxy"; then
echo "Deleting HTTP Proxy ${PROJECT}-http-proxy"
$GCLOUD compute target-http-proxies delete ${PROJECT}-http-proxy -q
fi
#------------------------------------------------------------
# HTTPS
# Delete firewall rule to let in traffic
if findIn "gcloud compute firewall-rules list" "${PROJECT}-https-fw"; then
echo "Deleting firewall rule ${PROJECT}-https-fw"
$GCLOUD compute firewall-rules delete ${PROJECT}-https-fw -q
fi
# Delete forwarding rule
if findIn "$GCLOUD compute forwarding-rules list" "${PROJECT}-https-fr"; then
echo "Deleting forwarding rule ${PROJECT}-https-fr"
$GCLOUD compute forwarding-rules delete ${PROJECT}-https-fr $REGIONOPT -q
fi
# Delete https proxy
if findIn "$GCLOUD compute target-https-proxies list" "${PROJECT}-https-proxy"; then
echo "Deleting HTTPS Proxy ${PROJECT}-https-proxy"
$GCLOUD compute target-https-proxies delete ${PROJECT}-https-proxy -q
fi
#------------------------------------------------------------
# Delete url map
if findIn "$GCLOUD compute url-maps list" "${PROJECT}-map"; then
echo "Deleting URL Map ${PROJECT}-map"
$GCLOUD compute url-maps delete ${PROJECT}-map -q
fi
# Delete backend bucket
if findIn "$GCLOUD compute backend-buckets list" "${PROJECT}-bucket"; then
echo "Deleting bucket ${PROJECT}-bucket"
$GCLOUD compute backend-buckets delete ${PROJECT}-bucket -q
fi
fi
if isCmd "create"; then
# Create backend bucket
if ! findIn "$GCLOUD compute backend-buckets list" "${PROJECT}-bucket"; then
echo "Creating bucket ${PROJECT}-bucket"
$GCLOUD compute backend-buckets create ${PROJECT}-bucket \
--gcs-bucket-name "www.${WEBSITE}" \
--enable-cdn
exitOnError "Failed to create backend bucket"
fi
# Create url map
if ! findIn "$GCLOUD compute url-maps list" "${PROJECT}-map"; then
echo "Creating URL Map ${PROJECT}-map"
$GCLOUD compute url-maps create ${PROJECT}-map \
$REGIONOPT \
--default-backend-bucket ${PROJECT}-bucket
exitOnError "Failed to create URL map"
fi
#------------------------------------------------------------
# HTTPS
# Create https proxy
if ! findIn "$GCLOUD compute target-https-proxies list" "${PROJECT}-https-proxy"; then
echo "Creating HTTPS Proxy ${PROJECT}-https-proxy"
$GCLOUD compute target-https-proxies create ${PROJECT}-https-proxy \
--ssl-certificates ${PROJECT}-cert \
--url-map ${PROJECT}-map
exitOnError "Failed to create HTTPS Proxy"
fi
# Create forwarding rule
if ! findIn "$GCLOUD compute forwarding-rules list" "${PROJECT}-https-fr"; then
echo "Creating forwarding rule ${PROJECT}-https-fr"
$GCLOUD compute forwarding-rules create ${PROJECT}-https-fr \
$REGIONOPT \
--address $EXTERNALIP\
--target-https-proxy ${PROJECT}-https-proxy \
--ports 443
exitOnError "Failed to create forwarding rule"
fi
# Create firewall rule to let in traffic
if ! findIn "$GCLOUD compute firewall-rules list" "${PROJECT}-https-fw"; then
echo "Creating firewall rule ${PROJECT}-https-fw"
$GCLOUD compute firewall-rules create ${PROJECT}-https-fw \
--allow=udp:443,tcp:443
exitOnError "Failed to create firewall rule"
fi
#------------------------------------------------------------
# HTTP
# Create http proxy
if ! findIn "$GCLOUD compute target-http-proxies list" "${PROJECT}-http-proxy"; then
echo "Creating HTTP Proxy ${PROJECT}-http-proxy"
$GCLOUD compute target-http-proxies create ${PROJECT}-http-proxy \
--url-map ${PROJECT}-map
exitOnError "Failed to create HTTP Proxy"
fi
# Create forwarding rule
if ! findIn "$GCLOUD compute forwarding-rules list" "${PROJECT}-http-fr"; then
echo "Creating forwarding rule ${PROJECT}-http-fr"
$GCLOUD compute forwarding-rules create ${PROJECT}-http-fr \
$REGIONOPT \
--address $EXTERNALIP\
--target-http-proxy ${PROJECT}-http-proxy \
--ports 80
exitOnError "Failed to create forwarding rule"
fi
# Create firewall rule to let in traffic
if ! findIn "$GCLOUD compute firewall-rules list" "${PROJECT}-http-fw"; then
echo "Creating firewall rule ${PROJECT}-http-fw"
$GCLOUD compute firewall-rules create ${PROJECT}-http-fw \
--allow=udp:80,tcp:80
exitOnError "Failed to create firewall rule"
fi
fi
if isCmd "list"; then
echo "--- Backend buckets ---"
$GCLOUD compute backend-buckets list
echo
echo "--- URL Maps ---"
$GCLOUD compute url-maps list
echo
echo "--- HTTPS Proxies ---"
$GCLOUD compute target-https-proxies list
echo
echo "--- HTTP Proxies ---"
$GCLOUD compute target-http-proxies list
echo
echo "--- Forwarding Rules ---"
$GCLOUD compute forwarding-rules list
echo
echo "--- Firewall Rules ---"
$GCLOUD compute firewall-rules list
echo
fi
exit 0
fi
#--------------------------------------------------------------------
# Compress / Publish website
if isCmd "compress"; then
echo "Compress files..."
SRCDIR=$3
if [ -z $SRCDIR ]; then
echo "$USAGE <source-directory>"
exitWithError "Source directory not specified"
fi
if [ ! -d $SRCDIR ]; then
echo "$USAGE <source-directory>"
exitWithError "Source directory not valid : $SRCDIR"
fi
CMPDIR="$SRCDIR.min"
if [ -d $CMPDIR ]; then
rm -Rf "$CMPDIR"
#exitWithError "Compressed directory already exists : $CMPDIR"
fi
# Get tools
initCompress
# Compress the web files
compressWeb "$SRCDIR" "$CMPDIR"
if [ ! -d "$CMPDIR" ]; then
exitWithError "Failed to compress $SRCDIR -> $CMPDIR"
fi
# Repoint to the compressed directory
SRCDIR=$CMPDIR
fi
if isCmd "publish"; then
echo "Publish files..."
# Set project
$GCLOUD config set project ${PROJECT}
# Ensure project bucket exists
if ! findIn "${GSUTIL} ls" "${BUCKET}"; then
echo "Creating project bucket..."
# Create bucket
$GSUTIL mb "${BUCKET}"
# Set public read access
$GSUTIL defacl set public-read "${BUCKET}"
# Set default pages
$GSUTIL web set -m "index.html" -e "404.html" "${BUCKET}"
echo "Create a DNS Record : www.${WEBSITE} CNAME c.storage.googleapis.com"
fi
# List buckets
echo "--- Buckets ---"
$GSUTIL ls
# If source not already specified (could be compressed)
if [ -z $SRCDIR ]; then
SRCDIR=$3
if [ -z $SRCDIR ]; then
echo "$USAGE <source-directory>"
exitWithError "Source directory not specified"
fi
fi
if [ ! -d $SRCDIR ]; then
echo "$USAGE <source-directory>"
exitWithError "Source directory not valid : $SRCDIR"
fi
# Sync files
$GSUTIL -m rsync -r "$SRCDIR" "${BUCKET}"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment