Skip to content

Instantly share code, notes, and snippets.

@nilium
Last active March 18, 2019 16:57
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 nilium/c00db2305c54d6493e6683ea7b2f20d2 to your computer and use it in GitHub Desktop.
Save nilium/c00db2305c54d6493e6683ea7b2f20d2 to your computer and use it in GitHub Desktop.
Ansible dynamic inventory script to pull GCE hosts
#!/usr/bin/env bash
set -e
usage() {
echo 'Usage: gce-inventory [--help|--list|--host HOSTNAME]' 1>&2
}
LIST_MODE=true
LOOKUP_HOST=
case "$1" in
--list) :;;
--host)
LIST_MODE=false
LOOKUP_HOST="$2"
;;
-h|--help)
usage
exit 2
;;
?*)
echo "Unrecognized argument: $1"
exit 1
;;
'') :;;
esac
# Drop all arguments
set --
lower() {
echo "$@" | tr '[:upper:]' '[:lower:]'
}
tobool() {
case "$(lower "$1")" in
true|t|1|yes|y) echo true;;
false|f|0|no|n) echo false;;
*) echo "${2:-false}";;
esac
}
: "${PROJECT_ID:=$(gcloud config get-value core/project)}"
SELECT_INTERNAL_IP="$(tobool "$SELECT_INTERNAL_IP" false)"
: "${INVENTORY_CONFIG:=gce-inventory.conf}"
[ -r "$INVENTORY_CONFIG" ] && . "$INVENTORY_CONFIG"
if [ "$LIST_MODE" = true ]; then
if [ -n "$FILTER" ]; then
set -- "$@" --filter="$FILTER"
fi
gcloud --project="$PROJECT_ID" compute instances list --format=json "$@"
else
LOOKUP_HOST="name='${LOOKUP_HOST}'"
if [ -n "FILTER" ]; then
set -- "$@" --filter="(${FILTER}) AND (${LOOKUP_HOST})"
else
set -- "$@" --filter="$LOOKUP_HOST" "$@"
fi
gcloud --project="$PROJECT_ID" compute instances list --format=json "$@"
fi |
jq -c \
--argjson internalIPs "$SELECT_INTERNAL_IP" \
--argjson listMode "$LIST_MODE" \
--arg projectID "$PROJECT_ID" \
'
select(. != []) |
# Simplify zone, extract region for only hosts with network interfaces
map(
select(.status == "RUNNING") |
select((.networkInterfaces // []) != []) |
select(
if $internalIPs then
try (.networkInterfaces[0].networkIP != "") catch false
else
try (.networkInterfaces[0].accessConfigs[0].natIP != "") catch false
end
) |
.__orig = . |
.machineType |= (split("/") | last) |
.zone |= (split("/") | last) |
.region = (.zone | split("-")[:-1] | join("-")) |
.network = (.networkInterfaces[0].network | split("/") | last) |
.subnetwork = (.networkInterfaces[0].subnetwork | split("/") | last) |
.externalIP = ((.networkInterfaces[0].accessConfigs[0].natIP) // null) |
.internalIP = ((.networkInterfaces[0].networkIP) // null) |
.tags |= (.items // [])
) |
. as $hosts |
# Host vars
($hosts | map(
{
(.name): {
ansible_host: (if $internalIPs then .internalIP else .externalIP end),
gce_id: (try .id),
gce_name: (try .name),
gce_status: (try .status),
gce_machine_type: (try .machineType),
gce_description: (try .description),
gce_zone: (try .zone),
gce_region: (try .region),
gce_tags: (try .tags),
gce_network: (try .network),
gce_subnetwork: (try .subnetwork),
gce_public_ip: (try .externalIP),
gce_private_ip: (try .internalIP),
gce_service_account: (try (.serviceAccounts[0].email)),
gce_metadata: (.metadata.items // [] | from_entries),
gce_instance: .__orig
}
}
) | add) as $hostvars |
if $listMode then (
# Network tags
($hosts | map(try (.tags[])) | flatten | sort | unique |
map(
. as $tag |
{ "tag_\(.)": { hosts: ($hosts | map(select(.tags | contains([$tag])).name)) } }
) | add
) as $tagged |
# Zonal groups
($hosts | group_by(.zone) | map(
{ (first.zone): { hosts: map(.name) } }
) | add) as $zonal |
# Regional groups
($hosts | group_by(.region) | map(
{ (first.region): { hosts: map(.name) } }
) | add) as $regional |
($regional + $zonal + $tagged) as $grouped |
(($grouped | map(.hosts[]) | sort | unique) as $groupedHostnames |
$hosts | map(.name | select(. as $name | $groupedHostnames | contains([$name]) | not))) as $ungrouped |
$grouped + {
($projectID): { hosts: ($hosts | map(.name)), children: ($grouped | keys) },
ungrouped: { hosts: $ungrouped },
all: { children: [($grouped | keys[]), "ungrouped"] },
_meta: { hostvars: $hostvars }
}
) else (
$hostvars[]
) end
'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment