Skip to content

Instantly share code, notes, and snippets.

@dev-head
Created April 14, 2020 06:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dev-head/9a9828dee90adeae5f2106d09d861427 to your computer and use it in GitHub Desktop.
Save dev-head/9a9828dee90adeae5f2106d09d861427 to your computer and use it in GitHub Desktop.
Search EC2 User Data

Search EC2 User Data

Description

Used to find instances that contain user data which matches the provided grep_pattern.

Purpose

This was created because I needed an easy way to search all hosts for specific user data.

Usage

Basic Example

./search-userdata.sh "this is passed to grep"

Search for user data that executes a composer install.

./search-userdata.sh "-E (composer[[:space:]](.*)?install)"

Modify Behavior of script

Script has variables that can be hard coded to modify the behavior

ONLY_INSTANCE_IDS=""            # Add instance ids to check only those; spaced.
MAX_ITEMS=""                    # Set max number of items, helpful for testing.
DEBUG=false                     # each api call and function has debugging output.
OUTPUT_NONMATCHES=false         # True will output if an instance-id has a match or not.
OUTPUT_MATCHEDCONTENT=false     # True will output user data for matched instances.
OUTPUT_NONMATCHEDCONTENT=false  # True will output user data for non matched instances.

Dependencies

  • jq used to parse api results cleanly

TODO

  • Support Options to configure aws cli for region,profile
  • Support options that are manually set as hard coded variables.
#!/usr/bin/env bash
#
# @dependencies
# [jq](https://stedolan.github.io/jq/manual/) used to parse api results cleanly
#
#---{Global Variables}---------------------------------------------------------#
SVC=$0
NAME='search-userdata'
LOG_PREFIX="[${NAME}]"
GREP_PATTERN="${1}"
# manually set behavior Variables.
ONLY_INSTANCE_IDS="" # Add instance ids to check only those; spaced.
MAX_ITEMS="" # Set max number of items, helpful for testing.
DEBUG=false # each api call and function has debugging output.
OUTPUT_NONMATCHES=false # True will output if an instance-id has a match or not.
OUTPUT_MATCHEDCONTENT=false # True will output user data for matched instances.
OUTPUT_NONMATCHEDCONTENT=false # True will output user data for non matched instances.
read -r -d '' USAGE_MESSAGE <<- EOM
---{cloudint-search}------------------------------------------------------------
Used to find instances that contain user
data which matches the provided grep_pattern.
Usage: ${SVC} grep_pattern
Example: ${SVC} "-E (composer[[:space:]](.*)?install)"
--------------------------------------------------------------------------------
EOM
#---{helper functions}---------------------------------------------------------#
usage() { echo "${USAGE_MESSAGE}" 1>&2; exit 0; }
log() { NOW=$(date +"%F %H:%M:%S %z"); (>&2 echo "${LOG_PREFIX}::[${NOW}]::[$@]"); }
debug() { if ${DEBUG}; then log "DEBUG: $@" ; fi }
error() { log "ERROR: $@" ; usage; exit 1 ; }
#---{script functions}---------------------------------------------------------#
getClient(){ echo "aws"; }
runClientCommand(){
local CMD="$(getClient) $@";
debug $CMD;
${CMD}
}
getInstanceUserData(){
local instance_id="${1}"
debug "(getInstanceUserData(${instance_id})"
if [ -z "${instance_id}" ]; then error "invalid instance id provided (${instance_id})"; fi
local data_raw=$(runClientCommand ec2 describe-instance-attribute --attribute userData --instance-id ${instance_id} --output text --query "UserData.Value")
if [ "${data_raw}" == "None" ]; then data_raw=""; fi # hack; `None` is a bad/sad response from the SDK.
local data_base64=$(echo ${data_raw} | base64 --decode)
local data_gzip=$(echo ${data_raw} | base64 --decode | gzip -d 2>/dev/null )
echo "${data_gzip:-$data_base64}"
}
instanceDataHasMatch(){
local instance_id=${1}
local grep_pattern=${2}
if [ -z "${instance_id}" ]; then error "missing instance id (${instance_id})"; fi
if [ -z "${grep_pattern}" ]; then error "missing grep pattern (${grep_pattern})"; fi
debug "(instanceDataHasMatch(${instance_id}, ${grep_pattern})"
data=$(getInstanceUserData ${instance_id})
matches=$(echo "${data}" | grep ${grep_pattern})
if [ ! -z "${matches}" ]; then
debug "match found (${instance_id})"
if ${OUTPUT_MATCHEDCONTENT}; then log "${instance_id} data: (${matches})"; fi
return 0
else
debug "match NOT found (${instance_id})"
if ${OUTPUT_NONMATCHEDCONTENT}; then log "${instance_id} data: (${data})"; fi
return 1
fi
}
execute(){
local grep_pattern="${1}"
debug "(execute(${grep_pattern})"
if [ -z "${grep_pattern}" ]; then error "invalid argument GREP_PATTERN (${grep_pattern})"; fi
if [ ! -z "${TEST_INSTANCE_IDS}" ]; then
local instances=$(runClientCommand ec2 describe-instances --instance-ids "${ONLY_INSTANCE_IDS}" --max-items "${MAX_ITEMS}" --filters "Name=instance-state-name,Values=running" --query "Reservations[].Instances[].InstanceId" | jq -r '.[]')
else
local instances=$(runClientCommand ec2 describe-instances --instance-ids "${ONLY_INSTANCE_IDS}" --filters "Name=instance-state-name,Values=running" --query "Reservations[].Instances[].InstanceId" | jq -r '.[]')
fi
for instance_id in ${instances}; do
if instanceDataHasMatch "${instance_id}" "${grep_pattern}"; then
log "${instance_id} has match"
else
if ${OUTPUT_NONMATCHES}; then log "${instance_id} has no match"; fi
fi
done
}
#---{run time}-----------------------------------------------------------#
execute "${GREP_PATTERN}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment