SUSE Conversations


Using Linux Scripts to Manage VMware Virtual Machines



By: gchilders

March 24, 2009 4:27 pm

Reads:2661

Comments:2

Rating:0

Using Linux Scripts to Manage VMware Virtual Machines
by Gary Childers

Introduction

You cannot work in Information Technology today without hearing about “virtualization”, “virtual machines”, “virtual desktops” and now even “virtual applications”. What’s all the buzz about virtual things?

There seems to be a division in the IT world about virtual machine technology: basically, there are those who understand it, and embrace the technology, and those who don’t quite understand it, and are leery of any computer that they cannot touch. But that’s OK – all of us started out fairly ignorant of the “voodoo” of virtualization; it merely takes some time to get acquainted with it, and then learn to trust its capabilities.

After that, the vast majority of folks never want to go back to a world without virtual computing. It is reported that 99 of the Fortune 100 companies in the United States have embraced virtualization technology to realize lower total costs of ownership, higher returns on investment, and improved service levels to their customers.

What is a virtual machine? It is usually defined as a “software implementation of a computer that executes programs like a real machine”. Essentially, it is a “guest” operating system, which runs in an isolated memory and disk space on a “host” operating system. The guest OS has no “awareness” that it is not running on actual, physical hardware. The memory, CPU, disk and network interface resources that are used are provided by the host machine, and by the special virtualization software (called the “hypervisor”) which is running on the host.

One of the chief benefits of virtualized computing is consolidation: instead of running multiple physical computers, which typically operate at 5% to 10% of capacity, on separate hardware, we can instead run the same multiple operating systems, with all their separate configurations and applications, on a virtual machine host. The various guest operating systems and applications behave exactly as if they were running on physical hardware, even though they share the same actual hardware of the host.

Another chief benefit is resiliency and standardization. The “virtual hardware” of a virtual machine (VM) is the same among all the VMs (assuming they are all using the same virtualization software); therefore it is a simple thing to move or copy the VM from one host to another – whether for the purposes of failover, or for provisioning – no matter what physical hardware, from whatever vendor, is being used for the host machines.

VMware, Inc., founded in 1998, is a recognized leader of virtualization for the x86 platform. Their products include VMware Workstation, used primarily on desktop computers, and VMware Infrastructure (formerly called ESX), as well as a scaled-down free server version called VMware Server.

The Goal

Personally, I have been running virtual machines for many years, using VMware. Originally, I needed to test various operating system configurations, and I found that I could replace a lab of a dozen physical computers with just one instance of VMware Workstation. Then I found that I could also demonstrate various software products to my customers using VMware, and thus have the benefit of a mobile lab, without lugging around several desktop computers.

Today, I regularly run four or five virtual machines every day on my laptop, as well as a dozen so on another VMware Server, to test and develop various software configurations. The VMware software works exceptionally well for me.

Here is a view of the VMware Server 2.0 Web-based administration console:

While the Web-based administration console is excellent, it does rely upon having an HTTPS connection to the server on a specific port, which may be an obstacle if we are connecting to the server through a firewall. Also, what if we are at the server (command-line) console itself, without access to a GUI interface? We still want to be able to manage the VMs from there.

Additionally, I ran into one minor annoyance when running VMs on my laptop computer: at the end of the workday I wanted to quickly pack up and go, but first I had to go into each of the guest operating systems, and shut down each of them separately (to save my current configuration, and avoid any data corruption from a “hard” shutdown), before I could power down the host machine. Couldn’t I find a better way to do this?

Solution Requirements

So I made myself my own customer in this respect, and sought to craft a solution that would allow me to perform some tasks in a more automated fashion for my virtual machines. Fortunately for me, I discovered that the fine folks at VMware developed a utility which allows us to utilize command-line control over the virtual machines running in VMware.

Why “command-line” you ask? Well, while the Web-based VMware GUI (above) is excellent for making the management of virtual machines easier and more intuitive, the point-and-click nature of a graphical interface does not lend itself to automation. It always requires human interaction – eyeballs on the screen, and fingers on the mouse – to accomplish anything.

Command-line instructions can be scripted, and so can be configured to do exactly what we want to do in a very defined manner. This is the solution route I needed. The command-line utility provided by VMware is called vmrun. This utility comes with VMware workstation 6.5 and VMware Server 2.0 (but not with previous versions), and I found the documentation on the VMware Web site. This particular solution I will describe is for the Linux version only.

Now let’s flesh out the requirements which I need my script to accomplish: I want to be able to use easy-to-remember console commands to manage the state of all of the virtual machines running on a particular host. Since my VMware host machines are Linux hosts (what else?), then I need to have a Linux script which will accomplish the following tasks:

  • display the available virtual machines which can be run on the host
  • display the status of virtual machines which are currently running
  • start virtual machines on the host server
  • stop virtual machines on the host server
  • reset (reboot) virtual machines on the host server
  • manage groups of virtual machines together
  • execute commands within the guest operating system of virtual machines

The last requirement is significant, in respect to my need to gracefully shut down any applications running on my guest machines, so as not to lose or corrupt any data. To merely “stop” a virtual machine would be analogous to pressing the power button on a physical computer. This is how you spell “data loss”. So I want to use commands which will shut down applications and the operating system in a safe manner.

Proposed Solution

To accomplish these objectives, I have developed a Linux bash script (named vmutil.sh) for use on Linux computers which have VMware Server 2.0 installed. My Linux operating system of choice is SUSE Enterprise Linux Server 10 (SLES10), or in some cases OpenSUSE 10. I have also successfully tested this solution on CentOS.

The environment-specific variables, which are relative to the specific host machine and to the individual virtual machines which run on the host, are contained in a separate configuration script (named vmutil.conf). This secondary script is called by the primary script (vmutil.sh) to set all the necessary parameters that are particular to the VMware host. This makes the solution highly portable: I can use the same vmutil.sh script on different VMware host machines, only modifying the configuration script for each different environment.

Dependencies

VMware Server and Workstation require user authentication in order to control the virtual machines running on the host. Thus this scripted solution uses a service account (in my implementation, named VMwareService), which should be created on the Linux host, and configured to allow VM management with the least required privileges (i.e., don’t use the root account). The service account needs only to be made an Administrator within the VMware application, and needs no special permissions within the Linux host operating system.

Caveat Implementor

As with any proposed solution, I must not omit my standard “disclaimer”: Please note: command scripting (in general), whether in Linux or any other operating system, can do wonders to automate and schedule repetitive tasks – but we must always be very careful. The wonderful thing about scripted tasks is that they perform commands exactly as we tell them to do, quickly and repeatedly. The terrible thing about scripted tasks is also that they perform commands exactly as we tell them to do (not particularly as we think that we are telling them to do), quickly and repeatedly.

Well-written scripts can do a world of good. Poorly-written (or poorly implemented) scripts can put you into a world of hurt. So always, always (and should I say “always”?) test your scripts (repeatedly) in a test lab (non-production) environment, and then carefully test them again in very limited fashion in a “pilot” environment, before full-scale production use. This is especially true for any script which you have “borrowed” from another environment.

The vmrun Utility

As mentioned, VMware has created the vmrun utility to enable users to control virtual machines from the command line, which is the entire basis of this scripted solution. From the vmrun documentation, we learn that the command syntax is as such:

vmrun -T server -h https://NovellLab:8333/sdk -u VMwareService -p secretpw list

This is the net result which I accomplish in my bash script merely by typing “vmutil status”. Remember, I want to use easy-to-remember commands to manage my virtual machines; so the bash script simply fills in all the necessary information from the configuration script, and thus translates my simple commands into the complex command syntax required by the vmrun utility.

Another example of the vmrun command usage, to start a virtual machine, is:

vmrun -T server -h https://NovellLab:8333/sdk -u VMwareService -p secretpw start "[storage1] SLES10/SLES10.vmx"

Obviously, this also does not fall into the “easy-to-remember” category. I accomplish the same results from my bash script by typing “vmutil start sles10″, since the script fills in all the necessary parameters from the configuration file.

The parameter “-T server” (type) specifies VMware Server 2.0 (rather than VMware Workstation). The parameter for the server (host) URL “-h https://NovellLab:8333/sdk” specifies the means by which we communicate with the VMware server, using secure HTTP on port 8333 (default). The VMware administrator username (“-u”) and password (“-p”) are specified, and the command is “start”. The location to the virtual machine configuration (.vmx) file is in the syntax of “[<storagegroup>] <directory>/<filename>.vmx”. Storage groups are setup within the VMware administrative GUI, and the initial default storage group for VMware Server 2.0 (set during installation) is named “[standard]“.

Script Usage

So now on to the script itself. The general syntax of the vmutil.sh script is:

vmutil.sh [ list | status | start | down | stop | reset ] [ <VM or group name> ]

Remember that my requirements are to: display the available VMs, display the status of VMs, start VMs, stop VMs, reset (reboot) VMs, and execute commands within the guest operating system of VMs. Hence the first “action” parameter for the script can be either list, status, start, stop, and reset. But wait – what about the “down” action? What is that for? I will cover that aspect a little later in this article.

The second script parameter specifies the VM or group of VMs upon which we want to perform this action. These VM names and groups are to be specified in the vmutil.conf file.

In my implementations, I have placed my virtual machines in a separate Linux partition named /home/VM, and configured my storage groups to that location. I then placed the scripts in a subdirectory, /home/VM/scripts, on the Linux servers which have VMware Server 2.0 installed.

Note: If a different directory than /home/VM/scripts is used, then the value for the SCRIPTDIR variable (line 12) will need to be changed in vmutil.sh to reflect the script location.

Some basic error messages are incorporated into the script logic to assist the user with the proper syntax. For example, if the script command is entered with no parameters, it would yield these results:

gchilders@NovellLab:~> vmutil
: Invalid action specified
Usage: vmutil.sh <action> [ <VM or group name> ]
Valid actions: < list | start | status | down | stop | reset >

So this tells us that the valid options for the first script parameter: list, status, start, down, stop and reset, and the second parameter is the VM or group name. If we get the first parameter right, but not the second, we might see these results:

gchilders@NovellLab:~> vmutil start asdfasdf
Error: asdfasdf is not a valid virtual machine or group
Usage: vmutil.sh <action> [ <VM or group name> ]
Valid VM names (in vmutil.conf): VMSLES-1 VMSLES-2 VMSLES-3 VMSLES-4 WIN2003-AD1 WIN2003-AD2 WIN2000PRO

Note: the “list” and “status” actions do not require nor use a second parameter, since their functions are to list all virtual machines (which are configured in vmutil.conf), or to show the status of all virtual machines currently running on the server.

Usage Examples

Here are a few examples of the script usage to accomplish the tasks included in my requirements:

  • To list all virtual machines which are configured to be managed with vmutil.sh script:

    gchilders@NovellLab:~> vmutil list
    Listing available VMs from vmutil.conf ...
    VMSLES-1
    VMSLES-2
    VMSLES-3
    VMSLES-4
    WIN2003-AD1
    WIN2003-AD2
    WIN2000PRO
    
    

We may have other virtual machine files on the server, but the vmutil.sh script will only run against those which are configured in the vmutil.conf configuration script.

  • To display the status of virtual machines which are currently running on the server:

    gchilders@NovellLab:~> vmutil status
    Listing VMs that are currently running ...
    Total running VMs: 0
    
    
  • To start a virtual machine on the server:

    gchilders@NovellLab:~> vmutil start WIN2003-AD1
    Executing vmrun to start VMs ... WIN2003-AD1 (VM7)
     * start WIN2003-AD1 ...
    
    gchilders@NovellLab:~> vmutil status
    Listing VMs that are currently running ...
    Total running VMs: 1
    [standard] WIN2003-AD1/WIN2003R2.vmx
    
    

Note that the subsequent command “vmutil status” shows us that the start command for the VM was effective. Note also that the syntax which the vmrun utility uses to display the currently running VMs is: “[<storagegroup>] <directory>/<filename>.vmx”. It is possible to have multiple VM configuration files with the same name, so long as they are in different directories or different storage groups.

Also be aware that the Linux scripting language treats the “space” character as a delimiter to separate commands or parameters; therefore I would advise to always avoid using spaces in the names of the directories and filenames – it only creates headaches for you later on. If you already have .vmx filenames with spaces, it is a simple matter to rename them (within Linux), and then add them back to VMware using the VMware administration console.

  • To start a group of virtual machines on the server:

    gchilders@NovellLab:~> vmutil start vmgroup1
    Executing vmrun to start VMs ... vmgroup1 (VM1 VM2 VM3 VM4)
     * start VMSLES-1 ...
     * start VMSLES-2 ...
     * start VMSLES-3 ...
     * start VMSLES-4 ...
     
     

The vmutil.sh script here loops through the individual VMs that are listed as part of the specified group in the vmutil.conf file, and executes the specified command on each of them. Here we see that VMGROUP1 (not case-sensitive) contains 4 member VMs, which are started one at a time. A configurable delay (in seconds) is used to pause execution between loops to allow the VM time to start up. The default STARTDELAY is 30 seconds.

Again, an execution of “vmutil status” shows us that the previous command was successful:

gchilders@NovellLab:~> vmutil status
Listing VMs that are currently running ...
Total running VMs: 5
[standard] WIN2003-AD1/WIN2003R2.vmx
[standard] VMSLES-1/SLES10.vmx
[standard] VMSLES-2/SLES10.vmx
[standard] VMSLES-3/VMSLES-3.vmx
[standard] VMSLES-4/VMSLES-4.vmx

  • To stop a virtual machine on the server:

    gchilders@NovellLab:~> vmutil stop win2000pro
    Executing vmrun to stop VMs ... win2000pro (VM7)
     * stop WIN2000PRO ...
     
     

Note: again, the “stop” action in vmrun is analogous to pressing the power button on a physical machine, so it only makes sense to use this for non-ACPI-aware operating systems (such as DOS). For most operating systems, we would want to execute commands from within the guest operating system to safely shut down the VM. This is why I developed the “down” action (soon to be explained).

  • To reset the virtual machine on the server:

    gchilders@NovellLab:~> vmutil reset win2000pro
    Executing vmrun to reset VMs ... win2000pro (VM7)
     * reset WIN2000PRO ...
     
     

Note: just as with the “stop” action, the “reset” action is similar to pressing the “reset” button on a computer (which modern computers don’t have any more, since they can be hard on the operating system) – it merely powers off and then powers on the VM. This really only makes sense for cases when the operating system is completely hung, and won’t respond to user commands. Again, this is why I wanted the “down” command. Finally:

  • To execute commands to gracefully shutdown the operating system:

    gchilders@NovellLab:~> vmutil down win2000pro
    Executing vmrun to down VMs ... win2000pro (VM7)
     * down WIN2000PRO ...
     
     

So what is this mysterious “down” action? If you read the vmrun documentation, you won’t find any mention of this as a valid parameter. What we are actually doing here is using the
vmrun action “runProgramInGuest “, with the guest program specified as one that will gracefully shutdown the guest operating system. The actual vmrun command for the Windows VM in this example would be:

/usr/bin/vmrun -T server -h https://localhost:8333/sdk -u VMwareService -p secretpw -gu administrator -gp windowspw runProgramInGuest "[standard] WIN2000PRO/Win2000Pro.vmx" "c:\util\batch\shutdown10.cmd"

This definitely does not fall into the “easy-to-remember” category, which is why I use the script to translate “vmutil down win2000pro” into the above command. As can see, the command which is executed inside the guest operating system is “c:\util\batch\shutdown10.cmd”. Obviously, this pre-supposes that I have configured such a command file in the guest VM, so that it is available for execution.

So let’s take a look that. The “shutdown10.cmd” is a simple Windows command (batch) file:

:: command file to shutdown Windows
c:\winnt\system32\shutdown /L /T:10 /Y /C

The command parameters, “/L” tell it to shutdown the local machine (the VM, in this case); “T:10″ issues a 10-second delay; “/Y” pre-supplies a “yes” answer to “Are you sure you want to shut down?”; and “/C” closes all running applications without further verification. The shutdown command works with most modern versions of Windows. If you have the console of the virtual machine open, you will see this pop-up message:

Note: the Windows shutdown command can be aborted from within the guest VM console, by entering “shutdown /A” in a command prompt during the timeout period. Also, if other specific commands are required to close applications running inside the particular guest VM, they can be included in the guest shutdown script.

What about Linux guest VMs? What about applications running inside the VMs which need to be gracefully shut down before the operating system is halted? I have a need for those, too.

My Linux guest VMs are running eDirectory and Novell Identity Manager, so I don’t want to risk any database corruption by a sudden power-off of the VM without gracefully closing the applications. So I have scripts to help me manage eDirectory from the command-line console (see Bonding Multiple Network Interfaces on SLES 10″>Non-Root eDirectory Management), and I also have scripts to gracefully stop my Identity Manager drivers (see /communities/conversations/6690/hpproliantsupportpacksles10″>Using Linux Scripts to Manage IDM Drivers). Now all I have to do is call my Linux scripts, which operate inside the guest VM, just as I did with the Windows shutdown script.

Once again, the full vmrun command to accomplish this would look like this:

/usr/bin/vmrun -T server -h https://localhost:8333/sdk -u VMwareService -p secretpw -gu root -gp linuxpw runProgramInGuest "[standard] VMSLES-1/SLES10.vmx" "/opt/novell/eDirectory/scripts/downserver.sh"

And again, not exactly “easy-to-remember”. This is the command which my script reduces down to “vmutil down vmsles-1″. The example shows that the operative guest command is “/opt/novell/eDirectory/scripts/downserver.sh”; so again this pre-supposes that I’ve already created the bash script in the guest VM, and made it to be executable. For my example, the “downserver.sh” script is:

#!/bin/bash
# downserver.sh
# Script to automatically shut down a Linux eDirectory server gracefully
# Author: Gary Childers 2009-01-02      Version 1.1
# Usage: downserver.sh

## Set required parameters
SCRIPTDIR="/opt/novell/eDirectory/scripts"
IDMUTIL="idmutil.sh"
NDSUTIL="edirstop.sh"

echo "This will shut down IDM drivers, eDirectory, and the Linux server"
$SCRIPTDIR/$IDMUTIL stop all
sleep 5
$SCRIPTDIR/$NDSUTIL
sleep 10
shutdown -h now

As you can see, this guest script first runs another guest script, “idmutil.sh” (as explained in /communities/conversations/6690/hpproliantsupportpacksles10″>Using Linux Scripts to Manage IDM Drivers), to stop the IDM drivers, then runs a second script, “edirstop.sh” (which is merely a one-liner, ‘/etc/init.d/ndsd stop’), to shutdown eDirectory. Then the final “shutdown -h now” command is given to shutdown the Linux guest operating system. Scripts which call scripts which call scripts – are you keeping up?

Using Symlinks and Aliases

No doubt you may have noticed that in all my examples above, I have run the command: “vmutil”, rather than the true name of the script, with the full path specified, as (in my case):

“/home/VM/scripts/vmutil.sh”. This is because I first created a symbolic link in /usr/bin (which by default is in the user’s path in most implementations of Linux) to the script file. To create the symlink for the script, we merely have to execute this command:

ln -sf /home/VM/scripts/vmutil.sh /usr/bin/vmutil

For different environments, we would have to adjust the script path according to the specific implementation of VMware Server. Then, evoking “vmutil” from any location will call the script.

Remember, one of the requirements for this solution was to give us easy-to-remember console commands to manage the state of the virtual machines. Thus, to further assist us with a simpler command syntax, I have also created a few aliases which merely call the vmutil.sh script with some pre-supplied parameters:

alias vmlist='vmutil list'
alias vmstatus='vmutil status'
alias vmstart='vmutil start'
alias vmdown='vmutil down'
alias vmstop='vmutil stop'
alias vmreset='vmutil reset'

I simply included these alias commands in my .bashrc file, so they execute each time I log into the (host) Linux console. By doing thus, I can execute “vmlist” to list available virtual machines, or “vmstatus” to list all running virtual machines, as in:

gchilders@NovellLab:~> vmlist
Listing available VMs from vmutil.conf ...
VMSLES-1
VMSLES-2
VMSLES-3
VMSLES-4
WIN2003-AD1
WIN2003-AD2
WIN2000PRO

gchilders@NovellLab:~> vmstatus
Listing VMs that are currently running ...
Total running VMs: 5
[standard] WIN2000PRO/Win2000Pro.vmx
[standard] VMSLES-1/SLES10.vmx
[standard] VMSLES-2/SLES10.vmx
[standard] VMSLES-3/VMSLES-3.vmx
[standard] VMSLES-4/VMSLES-4.vmx

This, of course, equally applies to the aliases “vmstart”, “vmdown”, “vmstop” and “vmreset”.

The Configuration Script

So if you’ve stayed with me this far, then you must be interested. And you may be wondering: “OK, I can see how you get a reduction of your commands using aliases and symlinks, but exactly how did you get from:

vmrun -T server -h https://NovellLab:8333/sdk -u VMwareService -p secretpw start "[storage1] SLES10/SLES10.vmx"

to:

vmutil start SLES10
?

The vmutil.sh script processes all of the provided parameters, but the control is all provided in the configuration script. So let’s look at that one first. Here’s my example script:

#!/bin/bash
# vmutil.conf
# Script to set parameters for vmutil.sh utility
# Author: Gary Childers	2009-03-13	Version 1.8

## Set required parameters
## Note: $SCRIPTDIR variable is set in the vmutil.sh script
HOST="https://localhost"
PORT=8333
STOREGRP1="[standard]"
STOREGRP2="[secondary]"
STORELOC1="/home/VM"
STORELOC2="/home/VM2"
AUTHUSER=VMwareService
AUTHPWD=VMw@r3
VMGROUPS="ALLVMS VMGROUP1 VMGROUP2 VMGROUP3"
ALLVMS="VM1 VM2 VM3 VM4 VM5 VM6 VM7"
VMGROUP1="VM1 VM2 VM3 VM4"
VMGROUP2="VM5 VM6"
VMGROUP3="VM7"
STARTDELAY=30
DOWNDELAY=10
STOPDELAY=5
RESETDELAY=30

## Set virtual machine-specific parameters
VM1_NAM="VMSLES-1"
VM1_VMX="$STOREGRP1 VMSLES-1/SLES10.vmx"
VM1_USR=root
VM1_PWD=linuxpw
VM1_CMD="/opt/novell/eDirectory/scripts/downserver.sh"

VM2_NAM="VMSLES-2"
VM2_VMX="$STOREGRP1 VMSLES-2/SLES10.vmx"
VM2_USR=root
VM2_PWD=linuxpw
VM2_CMD="/opt/novell/eDirectory/scripts/downserver.sh"

VM3_NAM="VMSLES-3"
VM3_VMX="$STOREGRP1 VMSLES-3/VMSLES-3.vmx"
VM3_USR=root
VM3_PWD=linuxpw
VM3_CMD="/opt/novell/eDirectory/scripts/downserver.sh"

VM4_NAM="VMSLES-4"
VM4_VMX="$STOREGRP1 VMSLES-4/VMSLES-4.vmx"
VM4_USR=root
VM4_PWD=linuxpw
VM4_CMD="/opt/novell/eDirectory/scripts/downserver.sh"

VM5_NAM="WIN2003-AD1"
VM5_VMX="$STOREGRP1 WIN2003-AD1/WIN2003R2.vmx"
VM5_USR=administrator
VM5_PWD=windowspw
VM5_CMD="c:\util\batch\shutdown.cmd"

VM6_NAM="WIN2003-AD2"
VM6_VMX="$STOREGRP1 WIN2003-AD2/WIN2003R2.vmx"
VM6_USR=administrator
VM6_PWD=windowspw
VM6_CMD="c:\util\batch\shutdown.cmd"

VM7_NAM="WIN2000PRO"
VM7_VMX="$STOREGRP1 WIN2000PRO/Win2000Pro.vmx"
VM7_USR=administrator
VM7_PWD=windowspw
VM7_CMD="c:\util\batch\shutdown.cmd"

You should be able to recognize where the parameters required for the vmrun utility are specified in the variables which are set in the script. In my example, the user-friendly VM name (“VMx_NAM”) value matches the directory in which the VM files are stored. This is helpful for me in my naming scheme, but I could have just as well called the user-friendly name “Fred” or “Barney”. The main script parses the variable name to determine the parameters (for example, “VM7″ resolves to: “WIN2000PRO”).

Notes on Security

For my configuration testing environment, security of my virtual machines is not an important issue. You might notice that in the example configuration script, I have pre-supplied (fictitious) usernames and passwords for running programs in the guest operating systems. My virtual machines run as “host only”, and thus are automatically protected from the outside world.

For other implementations, this may not be the case. Therefore, I have written the script so that if either the username or password for a particular VM is blank in the configuration script, then the main script will pause and prompt the user for the information. For example:

gchilders@Novell-D630:~> vmutil down Win2000Pro
Enter the Host password for VMwareService:
Executing vmrun to down VMs ... Win2000Pro (VM7)
 * down Win2000Pro ...
Enter the Guest password for Administrator:
gchilders@Novell-D630:~>

The Main Script

And now for the main script itself. Below is the text of the vmutil.sh bash script I developed to accomplish the required tasks which I outlined in my requirements:

#!/bin/bash
# vmutil.sh
# Script to manage VMWare virtual machines using the vmrun utility
# Author: Gary Childers	2009-03-13	Version 1.8
# Usage: vmutil.sh < list | start | status | down | stop | reset > [ < VM or group name > ]

#----------------------------------------------------------------------------#
## Set required parameters
USAGE0="Usage: vmutil.sh <action> [ < VM or group name > ]"
USAGE1="Valid actions: < list | start | status | down | stop | reset >"
SCRIPT=vmutil.sh
SCRIPTDIR=/home/VM/scripts
CONFFILE=vmutil.conf
VMRUN=/usr/bin/vmrun
TYPE=server

## Set VM environment-specific variables from a separate config file
if [ -f $SCRIPTDIR/$CONFFILE ]; then 
  . $SCRIPTDIR/$CONFFILE
else
  echo "Configuration file $SCRIPTDIR/$CONFFILE missing!"
  exit 1
fi

## Ensure that mandatory variables are set in the config file
MANDATORY="HOST PORT STOREGRP1 ALLVMS"
for VAR in $MANDATORY; do
  if  [ "`eval echo '${'$VAR'}'`" = "" ]; then 
    echo "Variable $VAR must have a value in $CONFFILE"
    exit 1
  fi
done

## Set parameters passed from the command line
ACTION=$1
VMLIST=$2

## Set additional required global parameters
ALLVMNAMES=`for VM in $ALLVMS; do eval echo '${'$VM"_NAM"'}'; done`

#----------------------------------------------------------------------------#
## Define functions

function LCASE()
{
  ## Function to translate strings to lowercase
  ## Requires input variable: 1-(string)
  echo $1 | tr [:upper:] [:lower:]
}

function ERROROUT()
{
  ## Function to echo error message(s) and exit script
  ## Requires input variables: 1,2,3-(error messages)
  echo $1
  if [ "$2" != "" ]; then echo $2; fi
  if [ "$3" != "" ]; then echo $3; fi
  exit 1	
}

function VALIDATEVMNAME()
{
  ## Validate VM Group Name
  for VMGROUP in $VMGROUPS; do
    if [ "$(LCASE $1)" = "$(LCASE $VMGROUP)" ]; then
      TARGETVMS=`eval echo '${'$VMGROUP'}'`
      return 1
    fi
  done
  ## Validate VM name
  for VM in $ALLVMS; do
    VMNAME=`eval echo '${'$VM"_NAM"'}'`
    if [ "$(LCASE $1)" = "$(LCASE $VMNAME)" ]; then
      TARGETVMS=$VM
      return 1
    fi
  done
}

function NOBLANK()
{
  ## Echo error and exit if input is blank
  ## Requires input variables: 1-(input variable), 2-(variable description)
  if [ "$1" = "" ]; then
    ERRMSG1="Blank $2 is not allowed"
    ERROROUT "$ERRMSG1"
  fi
}

function CHECKAUTH()
{
  ## Prompt for username and password, if not provided
  ## Requires input variables: 1-[ Host | Guest ], 2-(username_var), 3-(password_var)
  if [ "`eval echo '${'$2'}'`" = "" ]; then
    read -p "Enter the $1 auth user name: " $2
    NOBLANK "`eval echo '${'$2'}'`" username
  fi
  if [ "`eval echo '${'$3'}'`" = "" ]; then
    read -p "Enter the $1 password for `eval echo '${'$2'}'`: " -s $3
    echo ""
    NOBLANK "`eval echo '${'$3'}'`" password
  fi
}

function VMLISTSTATUS()
{
  ## Execute vmrun to list the currently running VMs
  $VMRUN -T $TYPE -h $HOST:$PORT/sdk -u $AUTHUSER -p $AUTHPWD list
}

function CHECKIFRUNNING()
{
  ## Check if the current VM is running
  ## Requires input variables: 1-$VM_VMX
  STOREGRP=`echo "$1" | cut -d" " -f1`
  for LISTVM in $ACTIVEVMS; do
    if [ "$STOREGRP $LISTVM" = "$1" ]; then return 1; fi
  done
}

function VMRUNACTION()
{
  ## Execute the specified action (start, stop) using vmrun
  ## Requires input variables: 1-$ACTION, 2-$VM_VMX
###Debug###
#  echo "$VMRUN -T $TYPE -h $HOST:$PORT/sdk -u $AUTHUSER -p $AUTHPWD $1 \"$2\""
  $VMRUN -T $TYPE -h $HOST:$PORT/sdk -u $AUTHUSER -p $AUTHPWD $1 "$2"
}

function VMGUESTACTION()
{
  ## Execute the specified command in the guest OS using vmrun
  ## Requires input variables: 1-$VM_USR, 2-$VM_PWD, 3-command, 4-$VM_VMX, 5-$VM_CMD
###Debug###
#  echo "$VMRUN -T $TYPE -h $HOST:$PORT/sdk -u $AUTHUSER -p $AUTHPWD -gu $1 -gp $2 $3 \"$4\" \"$5\""
  $VMRUN -T $TYPE -h $HOST:$PORT/sdk -u $AUTHUSER -p $AUTHPWD -gu $1 -gp $2 $3 "$4" "$5"
}

#----------------------------------------------------------------------------#

## Validate the action parameter, perform "list" or "status" actions
case $ACTION in
  list 	)	# List all available VMs configured in the config file
			echo "Listing available VMs from $CONFFILE ..."
			echo "$ALLVMNAMES"
			exit 0								;;
  status 	)	# List the status of running VMs using vmrun utility
			echo "Listing VMs that are currently running ..."
			CHECKAUTH Host AUTHUSER AUTHPWD
			VMLISTSTATUS
			exit 0								;;
  start	)	ACTDESC="Starting"						;;
  down 	)	ACTDESC="Downing"						;;
  stop 	)	ACTDESC="Stopping"						;;
  reset	)	ACTDESC="Resetting"						;;
    *		)	## Echo error message for all invalid actions
			ERRMSG1="$ACTION: Invalid action specified"
			ERROROUT "$ERRMSG1" "$USAGE0" "$USAGE1"			;;
esac

## Validate the specified VM name parameter
case $VMLIST in
  ""		)	ERRMSG1="Error: a valid VM name or VM group must be specified"
			ERROROUT "$ERRMSG1" "$USAGE0"				;;
  *		)	VALIDATEVMNAME $VMLIST
			if [ "$?" != "1" ]; then
			  ERRMSG1="Error: $VMLIST is not a valid virtual machine or group"
			  ERRMSG2="Valid VM names (in $CONFFILE): $ALLVMNAMES"
			  ERROROUT "$ERRMSG1" "$USAGE0" "$ERRMSG2" 
			fi								;;
esac

#----------------------------------------------------------------------------#

## Determine what Virtual Machines are currently running using vmrun
CHECKAUTH Host AUTHUSER AUTHPWD
ACTIVEVMS=`VMLISTSTATUS | grep ".vmx" | cut -d" " -f2`

## Start, down or stop the specified VMs using vmrun utility
echo "Executing vmrun to $ACTION VMs ... $VMLIST ($TARGETVMS)"
# Set the values of the required variables
for VM in $TARGETVMS; do
  VM_NAM=`eval echo '${'$VM"_NAM"'}'`
  VM_VMX=`eval echo '${'$VM"_VMX"'}'`
  VM_USR=`eval echo '${'$VM"_USR"'}'`
  VM_PWD=`eval echo '${'$VM"_PWD"'}'`
  VM_CMD=`eval echo '${'$VM"_CMD"'}'`
  echo " * $ACTION $VM_NAM ..."
  # Perform the action on the specified VMs
  case $ACTION in
    start	)	## Start the specified VMs using vmrun utility
			CHECKIFRUNNING "$VM_VMX"
			if [ $? = 1 ]; then
			  echo "  - $VM_NAM is already running"
			  DELAY=0
			else
			  VMRUNACTION $ACTION "$VM_VMX"
			  DELAY=$STARTDELAY
			fi								;;
    down	)	## Run a script in the guest VM to down the VM
			CHECKIFRUNNING "$VM_VMX"
			if [ $? = 1 ]; then
			  CHECKAUTH Guest VM_USR VM_PWD
			  VMGUESTACTION $VM_USR $VM_PWD runProgramInGuest "$VM_VMX" $VM_CMD
			  DELAY=$DOWNDELAY
			else
			  echo "  - $VM_NAM is not currently running"
			  DELAY=0
			fi								;;
    stop	)	## Stop the specified VMs using vmrun utility
			CHECKIFRUNNING "$VM_VMX"
			if [ $? = 1 ]; then
			  VMRUNACTION $ACTION "$VM_VMX"
			  DELAY=$STOPDELAY
			else
			  echo "  - $VM_NAM is not currently running"
			  DELAY=0
			fi								;;
    reset	)	## Stop the specified VMs using vmrun utility
			CHECKIFRUNNING "$VM_VMX"
			if [ $? = 1 ]; then
			  VMRUNACTION $ACTION "$VM_VMX"
			  DELAY=$RESETDELAY
			else
			  echo "  - $VM_NAM is not currently running"
			  DELAY=0
			fi								;;
  esac
  sleep $DELAY
done

exit 0

##END##

Summary

Just to recap this suggested solution for scripted management of VMware virtual machines on VMware Server for Linux:

  • Deploy the scripts in a subdirectory on the VMware Server (in my example, /home/VM/scripts – this location should also be specified in the SCRIPTDIR variable)
  • Create a service account with appropriate roles to the VMware server (no special Linux privileges are required)
  • Modify the vmutil.conf file to reflect the appropriate virtual machine environment
  • Create appropriate scripts in the guest operating systems, as required
  • Create symlinks and aliases on the VMware host to the script files for ease-of-use

This solution allows VMware administrators to more easily manage VMware virtual machines from the Linux console, and to more easily script both host and guest commands for automated processes, such as data backups. If you should choose to adapt these scripts for your environment, be sure (I say again) to test them thoroughly before deployment on any production servers. Have a virtually grand time!

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.22_1171]
Rating: +1 (from 1 vote)

Tags: ,
Categories: SUSE Linux Enterprise Server, Technical Solutions, Virtualization

Disclaimer: As with everything else at SUSE Conversations, this content is definitely not supported by SUSE (so don't even think of calling Support if you try something and it blows up).  It was contributed by a community member and is published "as is." It seems to have worked for at least one person, and might work for you. But please be sure to test, test, test before you do anything drastic with it.

2 Comments

  1. By:rjani48

    A very good and informative article

  2. By:jingyang

    Looking forwards more informative articles.

Comment

RSS