Skip to content

Instantly share code, notes, and snippets.

@chenweienn
Last active January 13, 2023 09:11
Show Gist options
  • Select an option

  • Save chenweienn/f143c34cad6eff691e639571fb5b8b9a to your computer and use it in GitHub Desktop.

Select an option

Save chenweienn/f143c34cad6eff691e639571fb5b8b9a to your computer and use it in GitHub Desktop.
A script to list service instances on TAS foundation.
#!/bin/bash
SCRIPT_NAME=$(basename $0)
usage() {
echo "Usage:"
echo " $SCRIPT_NAME --per-svc|--per-org"
echo ""
echo "Flags:"
echo " --per-svc Print triple (org_name, space_name, service_instance_name) for every service offering."
echo " User-provided service instances are printed as the end."
echo " The triples are ordered alphabetically by org_name and space_name."
echo ""
echo " --per-org Print triple (service_offering_name, service_plan_name, service_instance_name) for every space in every org."
echo " User-provided service instances are printed as the end."
echo " The triples are ordered alphabetically by service_offering_name and service_plan_name."
echo ""
echo "Prereuisites:"
echo " 1. jq"
echo " 2. cf login using admin user"
echo ""
echo "Tips:"
echo " This script polls a few cf APIs to retrieve resources: orgs, spaces, service_offerings, service_plans, service_instances."
echo " They are saved into files ./<resource>.json locally."
echo " You can \"export SKIP_POLL_CF_API=true\" to reuse polled resources from prior script execution."
echo ""
}
# print org-space-service mappings for a service instance
map_org_space_svc() {
SVC_INSTANCE="$1"
SVC_INSTANCE_NAME=$(echo $SVC_INSTANCE | jq '.name' -r)
SVC_INSTANCE_SPACE_GUID=$(echo $SVC_INSTANCE | jq '.relationships.space.data.guid' -r)
SVC_INSTANCE_SPACE=$(cat ./spaces.json | jq --arg GUID $SVC_INSTANCE_SPACE_GUID 'select(.guid==$GUID)' -c)
SVC_INSTANCE_SPACE_NAME=$(echo $SVC_INSTANCE_SPACE | jq '.name' -r)
SVC_INSTANCE_ORG_GUID=$(echo $SVC_INSTANCE_SPACE | jq '.relationships.organization.data.guid' -r)
SVC_INSTANCE_ORG=$(cat ./organizations.json | jq --arg GUID $SVC_INSTANCE_ORG_GUID 'select(.guid==$GUID)' -c)
SVC_INSTANCE_ORG_NAME=$(echo $SVC_INSTANCE_ORG | jq '.name' -r)
echo -e " Org: $SVC_INSTANCE_ORG_NAME \tSpace: $SVC_INSTANCE_SPACE_NAME \tInstance: $SVC_INSTANCE_NAME"
}
map_offering_plan_svc() {
SVC_INSTANCE="$1"
SVC_INSTANCE_NAME=$(echo $SVC_INSTANCE | jq '.name' -r)
SVC_PLAN_GUID=$(echo $SVC_INSTANCE | jq '.relationships.service_plan.data.guid' -r)
SVC_PLAN_NAME=$(cat ./service_plans.json | jq --arg GUID $SVC_PLAN_GUID 'select(.guid==$GUID) | .name' -r)
SVC_OFFERING_GUID=$(cat ./service_plans.json | jq --arg GUID $SVC_PLAN_GUID 'select(.guid==$GUID) | .relationships.service_offering.data.guid' -r)
SVC_OFFERING_NAME=$(cat ./service_offerings.json | jq --arg GUID $SVC_OFFERING_GUID 'select(.guid==$GUID) | .name' -r)
echo -e " Offering: $SVC_OFFERING_NAME \tPlan: $SVC_PLAN_NAME \tInstance: $SVC_INSTANCE_NAME"
}
# print service instances for each service_offerings/service_plans and for user-provided services as well
per_svc() {
# part-1: managed services
cat ./service_offerings.json | \
while read -r SVC_OFF; do
SVC_OFF_NAME=$(echo "$SVC_OFF" | jq -r '.name')
SVC_OFF_GUID=$(echo "$SVC_OFF" | jq -r '.guid')
echo -e "=============== Service Offering: $SVC_OFF_NAME ================\n"
cat ./service_plans.json | jq --arg GUID $SVC_OFF_GUID 'select(.relationships.service_offering.data.guid==$GUID)' -c | \
while read -r SVC_PLAN; do
SVC_PLAN_NAME=$(echo "$SVC_PLAN" | jq -r '.name')
SVC_PLAN_GUID=$(echo "$SVC_PLAN" | jq -r '.guid')
INSTANCE_COUNT=$(cat ./service_instances.json | jq --arg GUID $SVC_PLAN_GUID -s '[ .[] | select(.relationships.service_plan?.data.guid==$GUID) ] | length')
# echo "debug instance count: $INSTANCE_COUNT"
echo -e " -------- Service Plan: $SVC_PLAN_NAME ( #instances: $INSTANCE_COUNT )"
if [ $INSTANCE_COUNT -gt 0 ]; then
echo ""
cat ./service_instances.json | jq --arg GUID $SVC_PLAN_GUID 'select(.relationships.service_plan?.data.guid==$GUID)' -c | \
while read -r SVC_INSTANCE; do
map_org_space_svc "$SVC_INSTANCE"
done | sort -k 2,4 --ignore-case | column -t -s "$(printf '\t')"
echo ""
fi
done
echo ""
done
# part-2: user-provided services
USER_PROVIDED_INSTANCE_COUNT=$(cat ./service_instances.json | jq -s '[ .[] | select(.type=="user-provided") ] | length')
echo -e "=============== User-provided services ( #instances: $USER_PROVIDED_INSTANCE_COUNT ) ============\n"
if [ $USER_PROVIDED_INSTANCE_COUNT -gt 0 ]; then
cat ./service_instances.json | jq 'select(.type=="user-provided")' -c | \
while read -r SVC_INSTANCE; do
map_org_space_svc "$SVC_INSTANCE"
done | sort -k 2,4 --ignore-case | column -t -s "$(printf '\t')"
fi
}
## generating service usage details per organizations/spaces
per_org() {
cat ./organizations.json | jq -c '.' | \
while read -r ORG; do
ORG_NAME=$(echo "$ORG" | jq -r '.name')
ORG_GUID=$(echo "$ORG" | jq -r '.guid')
echo -e "=============== Org: $ORG_NAME ================\n"
cat ./spaces.json | jq --arg GUID $ORG_GUID 'select(.relationships.organization.data.guid==$GUID)' -c | \
while read -r SPACE; do
SPACE_NAME=$(echo "$SPACE" | jq -r '.name')
SPACE_GUID=$(echo "$SPACE" | jq -r '.guid')
SPACE_INSTANCE_COUNT=$(cat ./service_instances.json | jq --arg GUID $SPACE_GUID -s '[ .[] | select(.relationships.space.data.guid==$GUID) ] | length')
echo -e " ------- Space: $SPACE_NAME ( #instances: $SPACE_INSTANCE_COUNT )"
if [ $SPACE_INSTANCE_COUNT -gt 0 ]; then
echo ""
# part-1: managed services
cat ./service_instances.json | jq --arg GUID $SPACE_GUID 'select(.relationships.space.data.guid==$GUID and .type=="managed")' -c | \
while read -r SVC_INSTANCE; do
map_offering_plan_svc "$SVC_INSTANCE"
done | sort -k 2,4 --ignore-case | column -t -s "$(printf '\t')"
echo ""
# part-2: user-provided services
USER_PROVIDED_INSTANCE_COUNT=$(cat ./service_instances.json | jq --arg GUID $SPACE_GUID -s '[ .[] | select(.relationships.space.data.guid==$GUID and .type=="user-provided") ] | length')
if [ $USER_PROVIDED_INSTANCE_COUNT -gt 0 ]; then
echo -e " User provided services:\n"
cat ./service_instances.json | jq --arg GUID $SPACE_GUID 'select(.relationships.space.data.guid==$GUID and .type=="user-provided")' -c | \
while read -r SVC_INSTANCE; do
# user-provided service instances are not associated with any service offering or plan. Just print their names.
SVC_INSTANCE_NAME=$(echo $SVC_INSTANCE | jq '.name' -r)
echo " Instance: $SVC_INSTANCE_NAME"
done | sort -k 2 --ignore-case
echo ""
fi
fi
done
echo ""
done
}
# v2 API allows results-per-page <=100
# https://bosh.io/jobs/cloud_controller_ng?source=github.com/cloudfoundry/capi-release&version=1.143.0#p%3dcc.renderer.max_results_per_page
# v3 API allows per_page <=5000
# https://github.com/cloudfoundry/cloud_controller_ng/blob/main/lib/cloud_controller/paging/pagination_options.rb#L10
poll_cf_resources() {
API_RESOURCES=("organizations" "spaces" "service_offerings" "service_plans" "service_instances")
PER_PAGE_MAX=5000
for RESOURCE in "${API_RESOURCES[@]}"; do
echo "Saving $RESOURCE into ./$RESOURCE.json ..."
# clean old API resources cache files
echo -n "" > ./$RESOURCE.json
TOTAL_PAGES=$(cf curl "/v3/$RESOURCE?per_page=$PER_PAGE_MAX" | jq '.pagination.total_pages' -r)
PAGE=1
while [ $PAGE -le $TOTAL_PAGES ]; do
cf curl "/v3/$RESOURCE?per_page=$PER_PAGE_MAX&page=$PAGE" | jq '.resources[]' -c >> ./$RESOURCE.json
((PAGE++))
done
done
}
main() {
# Check pre-requisites: jq, cf login
if ! (jq --version > /dev/null 2>&1); then
usage
exit
fi
if ! (cf orgs > /dev/null 2>&1); then
usage
exit
fi
# STEP-1: retrieve cf API RESOURCEs = (organizations, spaces, service_offerings, service_plans, service_instances) to ./$RESOURCE.json
# export SKIP_POLL_CF_API=true to reuse polled resources json file from prior execution
if [ "${SKIP_POLL_CF_API:-}" != "true" ]; then
poll_cf_resources
fi
# STEP-2: print service instances details
case $1 in
# grouping output per service offering
--per-svc )
per_svc
;;
# grouping output per org
--per-org )
per_org
;;
* )
usage
;;
esac
echo "Finished"
}
main $@
@chenweienn
Copy link
Author

Example output 1:

$ ./list-svc.sh --per-svc
Saving organizations into ./organizations.json ...
Saving spaces into ./spaces.json ...
Saving service_offerings into ./service_offerings.json ...
Saving service_plans into ./service_plans.json ...
Saving service_instances into ./service_instances.json ...
=============== Service Offering: app-autoscaler ================

       -------- Service Plan: standard  ( #instances: 1 )

                Org: system      Space: system      Instance: user-mongodb-strosales


=============== Service Offering: nfs-legacy ================

       -------- Service Plan: Existing  ( #instances: 0 )

=============== Service Offering: nfs ================

       -------- Service Plan: Existing  ( #instances: 0 )

=============== Service Offering: smb ================

       -------- Service Plan: Existing  ( #instances: 0 )

=============== Service Offering: p-rabbitmq ================

       -------- Service Plan: standard  ( #instances: 0 )

=============== Service Offering: p.rabbitmq ================

       -------- Service Plan: single-node-3.7  ( #instances: 2 )

                Org: asomachud      Space: asomachud      Instance: myrmq
                Org: mkasz          Space: mkasz          Instance: RMQ_Instance


=============== Service Offering: p-cloudcache ================

       -------- Service Plan: extra-small  ( #instances: 2 )

                Org: jw          Space: jw          Instance: test
                Org: system      Space: system      Instance: xman-cloudcache

       -------- Service Plan: dev-plan  ( #instances: 0 )
       -------- Service Plan: small-footprint  ( #instances: 0 )

=============== Service Offering: p.config-server ================

       -------- Service Plan: standard  ( #instances: 7 )

                Org: bs            Space: bs              Instance: cook-key2
                Org: bs            Space: bs              Instance: my-config-server
                Org: bs            Space: bs              Instance: x-config-server
                Org: jw            Space: jw              Instance: test-resync
                Org: mkasz         Space: mkasz           Instance: my-config-service
                Org: neena         Space: neena           Instance: my-config-server
                Org: test-org      Space: test-space      Instance: cook-config-server


=============== Service Offering: p.service-registry ================

       -------- Service Plan: standard  ( #instances: 1 )

                Org: mkasz      Space: mkasz      Instance: myregistry


=============== Service Offering: p.mirror-service ================

       -------- Service Plan: standard  ( #instances: 4 )

                Org: p-spring-cloud-services      Space: 10f75029-9a8f-49b5-b02e-5e97e0c60b2a      Instance: mirror-svc
                Org: p-spring-cloud-services      Space: b1133c69-3837-4b94-b227-1531aa6559e5      Instance: mirror-svc
                Org: p-spring-cloud-services      Space: bd58e3f7-2b12-41b9-879e-ff9b95e2882a      Instance: mirror-svc
                Org: p-spring-cloud-services      Space: fc43f699-4a35-4745-8cd5-fdb4bddece79      Instance: mirror-svc


=============== Service Offering: p.gateway ================

       -------- Service Plan: standard  ( #instances: 0 )

=============== User-provided services ( #instances: 3 ) ============

                Org: system      Space: system      Instance: redis
                Org: system      Space: system      Instance: structured-format-json
                Org: system      Space: system      Instance: user-api-service
Finished

Example output 2:

$ SKIP_POLL_CF_API=true ./list-svc.sh --per-org
=============== Org: system ================

        ------- Space: system  ( #instances: 5 )

                Offering: app-autoscaler      Plan: standard         Instance: user-mongodb-strosales
                Offering: p-cloudcache        Plan: extra-small      Instance: xman-cloudcache

                User provided services:

                     Instance: redis
                     Instance: structured-format-json
                     Instance: user-api-service

        ------- Space: notifications-with-ui  ( #instances: 0 )
        ------- Space: autoscaling  ( #instances: 0 )
        ------- Space: metric-registrar-monitor  ( #instances: 0 )
        ------- Space: nfs  ( #instances: 0 )
        ------- Space: smb  ( #instances: 0 )
        ------- Space: rmq-smoke-tests-1-SPACE-d26748a68b73993e  ( #instances: 0 )
        ------- Space: rmq-smoke-tests-1-SPACE-45d08c7c4677e3e0  ( #instances: 0 )
        ------- Space: rmq-smoke-tests-1-SPACE-2b4ad441432b479b  ( #instances: 0 )
        ------- Space: rmq-smoke-tests-1-SPACE-57ea21df0e9c41ad  ( #instances: 0 )
        ------- Space: iaas-brokers  ( #instances: 0 )
        ------- Space: jw  ( #instances: 0 )

=============== Org: test-org ================

        ------- Space: test-space  ( #instances: 1 )

                Offering: p.config-server      Plan: standard      Instance: cook-config-server


=============== Org: ppickett ================

        ------- Space: services  ( #instances: 0 )

=============== Org: asomachud ================

        ------- Space: asomachud  ( #instances: 1 )

                Offering: p.rabbitmq      Plan: single-node-3.7      Instance: myrmq


=============== Org: p-spring-cloud-services ================

        ------- Space: instances  ( #instances: 0 )
        ------- Space: 47444e81-4c3c-4114-b16a-8d7fa5790aec  ( #instances: 0 )
        ------- Space: fc43f699-4a35-4745-8cd5-fdb4bddece79  ( #instances: 1 )

                Offering: p.mirror-service      Plan: standard      Instance: mirror-svc

        ------- Space: b1133c69-3837-4b94-b227-1531aa6559e5  ( #instances: 1 )

                Offering: p.mirror-service      Plan: standard      Instance: mirror-svc

        ------- Space: bd58e3f7-2b12-41b9-879e-ff9b95e2882a  ( #instances: 1 )

                Offering: p.mirror-service      Plan: standard      Instance: mirror-svc

        ------- Space: 10f75029-9a8f-49b5-b02e-5e97e0c60b2a  ( #instances: 1 )

                Offering: p.mirror-service      Plan: standard      Instance: mirror-svc


=============== Org: p-spring-cloud-gateway-service ================

        ------- Space: instances  ( #instances: 0 )

=============== Org: mkasz ================

        ------- Space: mkasz  ( #instances: 3 )

                Offering: p.config-server         Plan: standard             Instance: my-config-service
                Offering: p.rabbitmq              Plan: single-node-3.7      Instance: RMQ_Instance
                Offering: p.service-registry      Plan: standard             Instance: myregistry


=============== Org: neena ================

        ------- Space: neena  ( #instances: 1 )

                Offering: p.config-server      Plan: standard      Instance: my-config-server


=============== Org: mpitts ================

        ------- Space: apptrace  ( #instances: 0 )

=============== Org: bs ================

        ------- Space: bs  ( #instances: 3 )

                Offering: p.config-server      Plan: standard      Instance: cook-key2
                Offering: p.config-server      Plan: standard      Instance: my-config-server
                Offering: p.config-server      Plan: standard      Instance: x-config-server


=============== Org: jw ================

        ------- Space: jw  ( #instances: 2 )

                Offering: p-cloudcache         Plan: extra-small      Instance: test
                Offering: p.config-server      Plan: standard         Instance: test-resync


=============== Org: rios ================

        ------- Space: heckler  ( #instances: 0 )

Finished

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment