#!/bin/bash
#
# For a more fool-proof gce-xfstests setup,,,
#

XFSTESTS_FLAVOR=gce
if test -n "$GCE_XFSTESTS_DIR"
then
    DIR="$GCE_XFSTESTS_DIR"
else
    DIR="$(dirname "$(dirname "$0")")"
fi
if test ! -f "$DIR/util/get-config"
then
    echo "$(basename "$0"): couldn't find $DIR/util/get-config"
    exit 1
fi

. "$DIR/util/get-config"

function gce_gen_cert() {
    # Making an SSL cert for a project, storing it in GCS bucket.

    if [ -z "$REGEN_CERT" ] && \
      gsutil -q stat gs://$GS_BUCKET/gce-xfstests-cert.pem && \
      gsutil -q stat gs://$GS_BUCKET/gce-xfstests-server.pem && \
      gsutil -q stat gs://$GS_BUCKET/gce-xfstests-key.pem
    then
        return 0
    fi

    # generate self-signed cert.

    tmpdir=$(mktemp -d)
    openssl req -x509 -newkey rsa:4096 -keyout "$tmpdir/gce-xfstests-key.pem" \
	    -nodes -out "$tmpdir/gce-xfstests-cert.pem" -days 365 \
	    -subj "/CN=*.$GCE_PROJECT.gce-xfstests"

    cat "$tmpdir/gce-xfstests-key.pem" "$tmpdir/gce-xfstests-cert.pem" \
	> "$tmpdir/gce-xfstests-server.pem"

    gsutil -m cp "$tmpdir/*" gs://$GS_BUCKET/
    rm -rf "$tmpdir"
}

function gce_gen_ltm_pass() {
    if gsutil -q stat gs://$GS_BUCKET/ltm-pass &>/dev/null
    then
	return 0
    fi
    if ! type -P pwgen > /dev/null; then
	echo 1>&2 "Please install pwgen, or upload a password to ltm-pass"
	exit 1
    fi
    pwgen -n -s 15 1 | gsutil cp - gs://$GS_BUCKET/ltm-pass
}

if ! type gcloud >& /dev/null ; then
   echo "You apparently do not have the Google Cloud SDK installed"
   echo "Please visit https://cloud.google.com/sdk/docs/quickstart-linux"
   echo "and follow the instructions there"
   exit 1
fi

if test -z "$GS_BUCKET" -o -z "$GCE_PROJECT" -o -z "$GCE_ZONE" \
	-o -z "$GCE_KERNEL"
then
    echo -e "Please make sure the following configuration variables are set in"
    echo -e "~/.config/gce-xfstests or one of the other config files:"
    echo -e "\tGS_BUCKET, GCE_PROJECT, GCE_ZONE, GCE_KERNEL\n"
    echo -e "There are also more optional variables that can be set."
    echo -e "Check Documentation/gce-xfstests.md for all options."
    exit 1
fi

orig_account=$(run_gcloud auth list --filter status=ACTIVE --format="value(account)")

: ${GCE_CONFIGURATION:=gce-xfstests}
if ! gcloud config configurations activate "${GCE_CONFIGURATION}" >& /dev/null ; then
    gcloud config configurations create --activate "${GCE_CONFIGURATION}"
fi
account=$(gcloud auth list --filter status=ACTIVE --format="value(account)")

if test -z "$account" ; then
    if test -n "$orig_account"; then
	gcloud config set account "$orig_account"
    else
	echo "No GCE credentials available.  Please follow the"
	echo "instructions to obtain the Google Cloud credentials"
	echo "you wish to use for gce-xfstests"
	gcloud config set core/project "$GCE_PROJECT"
	if ! gcloud auth login --brief ; then
	    echo "Failed to get GCE credentials"
	    exit 1
	fi
    fi
fi

gcloud config set core/project "$GCE_PROJECT"
gcloud config set compute/zone "$GCE_ZONE"

gcloud services enable compute.googleapis.com
gcloud services enable iam.googleapis.com
gcloud services enable cloudbuild.googleapis.com
gcloud services enable run.googleapis.com
gcloud services enable file.googleapis.com

run_gcloud compute project-info add-metadata \
	--metadata=enable-guest-attributes=TRUE

function SetupRole () {
    local role="$1"

    if ! run_gcloud iam roles describe "for$role" >& /dev/null ; then
	run_gcloud iam roles create "for$role"
    else
	run_gcloud iam roles undelete "for$role" >& /dev/null
    fi

    if ! run_gcloud iam roles update "for$role" --file "$DIR/roles-$role.yaml" \
	 --quiet >& /dev/null ; then
	echo "Failed to update role for$role!"
	# Re-run to get error message
	run_gcloud iam roles update "for$role" --file "$DIR/roles-$role.yaml" \
		   --quiet
	exit 1
    fi
}

function SetupServiceAccount () {
    local srv_acct="$1"
    local role="$2"
    local name="$3"
    local desc="$4"

    case "$role" in
	*/*)	;;
	*)	role="projects/$GCE_PROJECT/roles/$role" ;;
    esac

    if ! run_gcloud iam service-accounts describe "$srv_acct" >& /dev/null ; then
	run_gcloud iam service-accounts create "$name" \
		   --description "$desc Service Account" \
		   --display-name "$name"
	if ! run_gcloud projects add-iam-policy-binding "$GCE_PROJECT" \
	     --member "serviceAccount:$srv_acct" \
	     --role "$role" \
	     --verbosity none >& /dev/null ; then
	    echo "Failed to add iam policy binding for role $role"
	    # Re-run to get error message
	    run_gcloud projects add-iam-policy-binding "$GCE_PROJECT" \
		       --member "serviceAccount:$srv_acct" \
		       --role "$role"
	    exit 1
	fi
    fi

    # when uniform bucket-level access is enabled, acl does not work
    if gsutil acl get gs://$GS_BUCKET &> /dev/null -eq 0; then
	    # set via acl
	    gsutil acl ch -u "${srv_acct}:W" gs://$GS_BUCKET
    else
	    # set via iams
	    if ! gsutil iam ch "serviceAccount:${srv_acct}:legacyBucketWriter" \
		    gs://$GS_BUCKET &> /dev/null; then
		echo "Error setting up gs://$GS_BUCKET write permissions for ${srv_acct}"
	    fi
    fi
}

function SetupServiceAccountCloudBuild () {
    local GCE_PROJECT_NUMBER=`gcloud projects describe $GCE_PROJECT | grep projectNumber | cut -d ":" -f2 | xargs`
    local ac_cloudbuild="serviceAccount:${GCE_PROJECT_NUMBER}@cloudbuild.gserviceaccount.com"

    if ! run_gcloud projects add-iam-policy-binding $GCE_PROJECT \
	 --member="$ac_cloudbuild" --role roles/run.viewer >& /dev/null ; then
	# Re-run to get error message
	run_gcloud projects add-iam-policy-binding $GCE_PROJECT \
		   --member="$ac_cloudbuild" --role roles/run.viewer
	exit 1
    fi
}

get_cache_dir
rm -f "$GCE_CACHE_DIR/service-accounts-opts.$GCE_PROJECT"

SetupRole TestVM
SetupRole LTMKCS
SetupRole ImgCreate
SetupRole Dashboard

SetupServiceAccount "$SERVICE_ACCOUNT_VM" "forTestVM" "test-vm" "Test VM"
SetupServiceAccount "$SERVICE_ACCOUNT_LTM" "forLTMKCS" "ltm-kcs" "LTM/KCS"
SetupServiceAccount "$SERVICE_ACCOUNT_IMG" "forImgCreate" "img-create" \
		    "Image Creation"
SetupServiceAccount "$SERVICE_ACCOUNT_DASH" "forDashboard" "dashboard" \
		    "GCE xfstests dashboard"
SetupServiceAccountCloudBuild

if ! run_gcloud_prj projects describe "$GCE_PROJECT" > /dev/null ; then
    echo -e "Invalid GCE project: $GCE_PROJECT\n"
    bad_config=yes
fi

if ! gsutil ls -b "gs://$GS_BUCKET" > /dev/null ; then
    echo -e "Invalid Cloud Storage Bucket: $GS_BUCKET\n"
    bad_config=yes
fi

if ! gcloud compute zones describe "$GCE_ZONE" > /dev/null ; then
    echo -e "Invalid GCE zone: $GCE_ZONE\n"
    bad_config=yes
fi

if test -n "$GCE_MIN_SCR_SIZE" && \
    ( [[ ! "$GCE_MIN_SCR_SIZE" =~ ^[0-9]*$ ]] || \
    (( GCE_MIN_SCR_SIZE > 250 )) ); then
    echo -e "Invalid minimum scratch size: $GCE_MIN_SCR_SIZE\n"
    echo -e "Must be a number between 0 and 250 inclusive"
    bad_config=yes
fi

if test -n "$GCE_IMAGE_PROJECT" ; then
    project="$GCE_IMAGE_PROJECT"
else
    project=xfstests-cloud
fi

if ! run_gcloud_prj compute images describe-from-family --project $project \
     xfstests > /dev/null ; then
    if test -n "$GCE_IMAGE_PROJECT" ; then
	echo "Bad image project: $GCE_IMAGE_PROJECT"
    else
	echo "You need to add yourself to the gce-xfstests Googlegroup"
	echo -e "Please visit:\n"
	echo -e '\thttps://groups.google.com/forum/#!forum/gce-xfstests\n'
    fi
    bad_config=1
fi

if test -n "$bad_config"; then
    exit 1
fi

if test -n "$GCE_REPORT_EMAIL" ; then
    if test -z "$GCE_SG_API" ; then
	echo "Missing Sendgrid API key; you need to set GCE_SG_API"
    fi
    if test -n "$GCE_REPORT_SENDER" ; then
	addr="$GCE_REPORT_SENDER"
    else
	addr="$GCE_REPORT_EMAIL"
    fi
    addr=$(echo $addr | sed -e 's/.*@//')
    spf=$(dig -t txt +short "$addr" | grep v=spf1)
    if test -n "$spf" && ! echo "$spf" | grep -q "include:sendgrid.net" ; then
	echo "Warning: the spf record for the domain $addr does not"
	echo "mention sendgrid.net:"
	echo -e "\n\t$spf\n"
	echo -e "If you can not change the SPF record for $addr,"
	echo -e "you should consider configuring a different sender"
	echo -e "via the GCE_REPORT_SENDER configuration variable.\n"
	echo -e "If you can change the SPF record, please add"
	echo -e "'include:sendgrid.net' before the 'all' mechanism"
	echo -e "in the spf record for $addr.  Otherwise, mail sent to"
	echo -e "'$GCE_REPORT_EMAIL' from '$GCE_REPORT_SENDER' may be"
	echo -e "rejected as spam.\n"
    fi
fi

for rule in "${GCE_FIREWALL_RULES[@]}"; do
    rule_name=$(echo $rule | cut -d' ' -f1)
    if test -z "$(run_gcloud compute firewall-rules list $rule_name | sed -e 1d)"
    then
	echo "Creating $rule_name firewall rule..."
	run_gcloud compute firewall-rules create $rule
    fi
done
unset rule rule_name

if [ "$1" == "--regenerate-ssl-cert" ]
then
  echo "Regenerating certificate."
  REGEN_OPTS="--force-regen"
fi

$DIR/util/gce-setup-cert $REGEN_OPTS
gce_gen_ltm_pass

exit 0
