diff --git a/devops/common.lib b/devops/common.lib new file mode 100644 index 00000000..89f21e8b --- /dev/null +++ b/devops/common.lib @@ -0,0 +1,33 @@ +#!/bin/bash + +################################# +# Validate that a string has the following characteristics: +# - At least 2 chars +# - No more than 5 chars +# - Has no whitespace +# Globals: +# None +# Arguments: +# initials +################################# +function validateInitials() { + MIN=2 + MAX=5 + + initials=$1 + + if [ -z "$initials" ]; then + printf '%s\n' "Error: initials can't be empty" >&2 + return 1 + elif [[ "${initials}" =~ [^a-zA-Z] ]]; then + printf '%s\n' "Error: initials must only contain letters, a-z" >&2 + return 1 + elif [[ "${#initials}" < $MIN ]]; then + printf '%s\n' "Error: initials must be at least $MIN characters" >&2 + return 1 + elif [[ "${#initials}" > $MAX ]]; then + printf '%s\n' "Error: initials must be no more than $MAX characters" >&2 + return 1 + fi + return 0 +} diff --git a/devops/makeReactBucket/makeReactBucket.bash b/devops/makeReactBucket/makeReactBucket.bash new file mode 100755 index 00000000..b29f5bff --- /dev/null +++ b/devops/makeReactBucket/makeReactBucket.bash @@ -0,0 +1,70 @@ +#!/bin/bash + +SCRIPT_PATH=$(dirname "$0") + +# import validateInitials from common.lib +# shellcheck disable=SC1091 +. "$SCRIPT_PATH/../common.lib" + +RANDOM_STRING=$(cat /dev/urandom | base64 | tr -dc 'a-z0-9' | fold -w 5 | head -n 1) +BUCKET_TEMPLATE="$SCRIPT_PATH/makeReactBucket.yml" +INITIALS_PROMPT="What are your initials? ('q' to quit)" + +initials="$1" +skipPrompt=false + +while :; do + # get and validate user initials if not passed as arg + if [[ -z "$initials" ]]; then + printf "%s\n" "$INITIALS_PROMPT" >&1 + printf "%s" "> " >&1 + while read -r initials && [ "$initials" != "q" ]; do + if validateInitials "$initials"; then + break + fi + printf "%s\n" "$INITIALS_PROMPT" >&1 + printf "%s" "> " >&1 + done + elif validateInitials "$initials"; then + skipPrompt=true + answer=y + else + break + fi + + if [ "$initials" == "q" ]; then + printf '%s\n' "Done" >&1 + break + fi + + formattedInitials="$(echo "${initials}" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')" + todayDate=$(date +'%Y%m%d') + uniqueName=$formattedInitials-$RANDOM_STRING-$todayDate + + bucketName=$uniqueName-bucket + stackName=$uniqueName-stack + + if [ "$skipPrompt" = false ]; then + # show user name of bucket and stack, get confirmation to create resources + printf "%s\n" "Your bucket and stack will be named as follows:" \ + " - bucket: $bucketName" \ + " - stack: $stackName" \ + "Create bucket and stack? (y/n)" >&1 + printf "%s" "> " >&1 + while read -r answer && [ "$answer" != "q" ]; do + if [ "${answer:0:1}" == "y" ] || [ "${answer:0:1}" == "n" ]; then + break + else + printf "%s\n" "Create bucket? (y/n)" >&1 + printf "%s" "> " >&1 + fi + done + fi + + if [ "${answer:0:1}" == "y" ]; then + printf '%s\n' "aws cloudformation deploy --template-file $BUCKET_TEMPLATE --stack-name $stackName --parameter-overrides BucketName=$bucketName" >&1 + aws cloudformation deploy --template-file "$BUCKET_TEMPLATE" --stack-name "$stackName" --parameter-overrides BucketName="$bucketName" + fi + printf '%s\n' "Done" >&1 + break +done diff --git a/devops/makeReactBucket/makeReactBucket.json b/devops/makeReactBucket/makeReactBucket.json deleted file mode 100644 index d7a6c367..00000000 --- a/devops/makeReactBucket/makeReactBucket.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "AWSTemplateFormatVersion": "2010-09-09", - "Parameters": { - "BucketName": { - "Description": "Name of your S3 bucket. Must be unique.", - "Type": "String" - } - }, - "Resources": { - "ReactBucket": { - "Type": "AWS::S3::Bucket", - "Properties": { - "BucketName" : { "Ref": "BucketName" }, - "AccessControl": "PublicRead", - "WebsiteConfiguration": { - "IndexDocument": "index.html", - "ErrorDocument": "index.html" - } - } - }, - "ReactBucketPolicy": { - "Type": "AWS::S3::BucketPolicy", - "Properties": { - "Bucket" : { "Ref": "ReactBucket" }, - "PolicyDocument": { - "Id": "MyPolicy", - "Version": "2012-10-17", - "Statement": { - "Sid": "PublicReadGetObject", - "Effect": "Allow", - "Principal": "*", - "Action": "s3:GetObject", - "Resource": { - "Fn::Join": ["", ["arn:aws:s3:::", {"Ref":"ReactBucket"}, "/*"]] - } - } - } - } - } - }, - "Outputs": { - "WebsiteURL": { - "Value": { - "Fn::GetAtt": [ - "ReactBucket", - "WebsiteURL" - ] - }, - "Description": "URL for website hosted on S3" - }, - "S3BucketSecureURL": { - "Value": { - "Fn::Join": [ - "", - [ - "https://", - { - "Fn::GetAtt": [ - "ReactBucket", - "DomainName" - ] - } - ] - ] - }, - "Description": "Name of S3 bucket to hold website content" - } - } -} \ No newline at end of file diff --git a/devops/makeReactBucket/makeReactBucket.sh b/devops/makeReactBucket/makeReactBucket.sh deleted file mode 100755 index e30cf64b..00000000 --- a/devops/makeReactBucket/makeReactBucket.sh +++ /dev/null @@ -1,64 +0,0 @@ -# !/bin/sh - -MIN=2 -MAX=5 -RANDOM_STRING=$(cat /dev/urandom | base64 | tr -dc 'a-z0-9' | fold -w 5 | head -n 1) -INITIALS_PROMPT="What are your initials? ('q' to quit)" -BUCKET_TEMPLATE="./makeReactBucket.json" - -while : - do - # get and validate user initials - printf "%s\n" "$INITIALS_PROMPT" >&1 - printf "%s" "> " >&1 - while read initials && [ "$initials" != "q" ]; - do - if [ -z "$initials" ]; then - printf '%s\n' "Error: initials can't be empty" >&2 - elif [[ "${initials}" =~ [^a-zA-Z] ]]; then - printf '%s\n' "Error: initials must only contain letters, a-z" >&2 - elif [[ "${#initials}" < $MIN ]]; then - printf '%s\n' "Error: initials must be at least $MIN characters" >&2 - elif [[ "${#initials}" > $MAX ]]; then - printf '%s\n' "Error: initials must be no more than $MAX characters" >&2 - else - break - fi - printf "%s\n" "$INITIALS_PROMPT" >&1 - printf "%s" "> " >&1 - done - - if [ "$initials" == "q" ]; then - printf '%s\n' "Done" >&1 - break - fi - - formattedInitials="$(echo "${initials}" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')" - todayDate=$(date +'%Y%m%d') - uniqueName=$formattedInitials-$RANDOM_STRING-$todayDate - - bucketName=$uniqueName-bucket - stackName=$uniqueName-stack - - # show user name of bucket and stack, get confirmation to create resources - printf "%s\n" "Your bucket and stack will be named as follows:" \ - " - bucket: $bucketName" \ - " - stack: $stackName" \ - "Create bucket and stack? (y/n)" >&1 - printf "%s" "> " >&1 - while read answer && [ "$answer" != "q" ]; - do - if [ "${answer:0:1}" == "y" ]; then - printf '%s\n' "aws cloudformation deploy --template-file ./makeReactBucket.json --stack-name $stackName --parameter-overrides BucketName=$bucketName" >&1 - aws cloudformation deploy --template-file $BUCKET_TEMPLATE --stack-name $stackName --parameter-overrides BucketName=$bucketName - break - elif [ "${answer:0:1}" == "n" ]; then - break - else - printf "%s\n" "Create bucket? (y/n)" >&1 - printf "%s" "> " >&1 - fi - done - printf '%s\n' "Done" >&1 - break - done \ No newline at end of file diff --git a/devops/makeReactBucket/makeReactBucket.yml b/devops/makeReactBucket/makeReactBucket.yml new file mode 100644 index 00000000..f2f7f4c3 --- /dev/null +++ b/devops/makeReactBucket/makeReactBucket.yml @@ -0,0 +1,45 @@ +AWSTemplateFormatVersion: 2010-09-09 +Parameters: + BucketName: + Description: Name of your S3 bucket. Must be unique. + Type: String +Resources: + ReactBucket: + Type: AWS::S3::Bucket + Properties: + BucketName: !Ref BucketName + AccessControl: PublicRead + WebsiteConfiguration: + IndexDocument: index.html + ErrorDocument: index.html + ReactBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref ReactBucket + PolicyDocument: + Id: MyPolicy + Version: 2012-10-17 + Statement: + Sid: PublicReadForGetBucketObjects + Effect: Allow + Principal: '*' + Action: s3:GetObject + Resource: !Join + - '' + - - 'arn:aws:s3:::' + - !Ref ReactBucket + - /* +Outputs: + WebsiteURL: + Value: !GetAtt + - ReactBucket + - WebsiteURL + Description: URL for website hosted on S3 + S3BucketSecureURL: + Value: !Join + - '' + - - 'https://' + - !GetAtt + - ReactBucket + - DomainName + Description: Name of S3 bucket to hold website content