Managing Multiple OpenStack CLI Environments

By Paul Heinlein | Aug 10, 2016 (updated Aug 11, 2016 )

If you’re an OpenStack administrator or power user, there’s a good chance you need to use the OpenStack command-line tools within multiple projects. Here’s a bash script to help you move between projects.

I’ll say it here and then I’ll say it again in the script’s embedded comments: you need to source the following script rather than executing it. Otherwise, you’ll find yourself with an unchanged environment. Assuming you name the script stackenv, usage would look something like this:

# use the source builtin
source stackenv
# or its alias
. stackenv
# use it to set environment for a project
. stackenv set
# or clear that environment
source stackenv clear

I’ll offer only one other comment on the script: it’s specific to bash. I haven’t tested it under other sh-compatible shells, but I doubt it’s 100% functional.

#!/bin/bash
#
# for managing environments for multiple OpenStack projects
#
# this script should be sourced NOT executed since it wants to
# alter the current shell environment. likewise, the "exit" command
# should never appear in this script, lest your current shell
# disappear.
#
# =====================================================================

# space-separated list of your OpenStack projects: required!
PRJS="project-one projectTwo yet-another"
# some openstack info: required!
MY_AUTH_URL="http://openstack.domain.com:5000/v2.0"
MY_REGION_NAME="RegionOne"
# your default username (defaults to your system username)
MY_USERNAME=$(whoami)
# what $PS1 should be when this script resets the environment
MYPS1='[\u@\h \W]\\$ '
# name of this script
ME="stackenv"
# default action is to print the usage screen
VERB=${1:-help}
# placeholder for selection made later
MY_TENANT_NAME=""

# do basic check to see if script is being sourced. WARNING: this
# is a bash-specific test. it's pretty much guaranteed to fail for
# other shells
if test "$0" = "$BASH_SOURCE"; then
  echo "FATAL: $ME should be sourced NOT executed" >&2
  VERB="help"
fi

function listProjects {
  echo ""
  echo "available projects:"
  for P in $PRJS; do
    echo "- $P"
  done
}

function printEnvironment {
  # don't echo the password
  echo "OS_USERNAME=$OS_USERNAME"
  echo "OS_TENANT_NAME=$OS_TENANT_NAME"
  echo "OS_PASSWORD=*********"
  echo "OS_AUTH_URL=$OS_AUTH_URL"
  echo "OS_REGION_NAME=$OS_REGION_NAME"
}

function setEnvironment {
  if test -z "$MY_TENANT_NAME"; then return 1; fi

  unset -v OS_SERVICE_TOKEN  

  # default OpenStack authentication and region variables
  OS_AUTH_URL="$MY_AUTH_URL"
  OS_REGION_NAME="$MY_REGION_NAME"

  # set project name
  OS_TENANT_NAME=$MY_TENANT_NAME

  # set username
  read -p "Username for project $MY_TENANT_NAME? [$MY_USERNAME] "
  case "$REPLY" in
    [A-Za-z]*)
      OS_USERNAME=$REPLY
      ;;
    *)
      OS_USERNAME=$MY_USERNAME
      ;;
  esac

  # set password
  read -s -p "Password for user $OS_USERNAME in project $MY_TENANT_NAME? "
  OS_PASSWORD="$REPLY"
  echo
  return 0
}

function selectProject {
  PS3="Select an OpenStack project: "
  select MY_TENANT_NAME in $PRJS; do
    if [ $MY_TENANT_NAME ]; then
      return
    else
      echo "invalid choice. exiting now"
      MY_TENANT_NAME=""
      break
    fi
  done
}

function usage {
  echo ""
  echo "usage:"
  echo ""
  echo "  . $ME help    -- print this usage menu"
  echo "  . $ME report  -- print current OpenStack env vars"
  echo "  . $ME list    -- list available OpenStack projects"
  echo "  . $ME set     -- set OpenStack env vars to work with a project"
  echo "  . $ME clear   -- clear current OpenStack env vars"
  echo ""
  echo "NOTE: $ME can only alter your working enviroment when it is"
  echo "      sourced NOT run as a script."
  echo ""
}

case "$VERB" in
  clear)
    export PS1="$MYPS1"
    unset -v OS_SERVICE_TOKEN OS_USERNAME OS_PASSWORD
    unset -v OS_AUTH_URL OS_TENANT_NAME OS_REGION_NAME
    echo "OpenStack variables cleared from environment"
    ;;
  help)
    usage
    ;;
  list)
    listProjects
    ;;
  set)
    selectProject
    setEnvironment
    if test $? -eq 0; then
      export PS1="${OS_TENANT_NAME}:${OS_USERNAME}> "
      export OS_USERNAME OS_PASSWORD OS_AUTH_URL
      export OS_TENANT_NAME OS_REGION_NAME
    fi
    ;;
  report)
    printEnvironment
    ;;
  *)
    usage
    ;;
esac

# clean up variables and functions that don't belong in
# working environment
unset -f listProjects selectProject printEnvironment setEnvironment usage
unset -v ME MYPS1 MY_AUTH_URL MY_REGION_NAME
unset -v MY_TENANT_NAME MY_USERNAME PRJS REPLY VERB

# end