Tip

VMware Consolidated Backup (VCB) script additions

VMware Consolidated Backup (VCB) was one of the most anticipated features of VMware Virtual Infrastructure 3 (VI3). VCB provides image-level backup of virtual machines (VMs) and file-level backups of Windows VMs by hooking into existing backup solutions like Veritas BackupExec.

But the scripts that Veritas BackupExec uses to interact with VCB lack some key functionality. In this article, we'll review some changes you can make to these stock scripts that will render the scripts more flexible and more useful for your backup needs – giving you the ability to have usernames and passwords with spaces in them, to easily select multiple VMs for backup and to prevent a single VM backup failure from ruining the entire backup job.

For many others and myself, VCB was a huge letdown when we finally got our hands on it. VCB was marketed as a one-stop shop for virtual machine backups. But what it turned out to be was a framework that could be utilized by various, existing backup solutions to back up virtual machines.

Although VCB may not be what we were expecting, what it is is not necessarily a bad thing. The VCB framework has two parts -- the backend technology used to directly access virtual machines on a SAN and the scripts used by the existing backup solutions. These scripts could use some improvement.

Because the scripts are written in the ever-so-common and useful language of JavaScript, they are easy to modify. VMware provides a basic script framework,

    Requires Free Membership to View

but it leaves a lot to the specific backup software vendors; hence, one script that I am reviewing is not generic and is only useful with Veritas BackupExec.

The first change allows for spaces in the username and password used to back up VMs. The script is called glue.js and it is located in %ProgramFiles%\VMware\VMware Consolidated Backup Framework\generic. This script is exactly what the name implies -- it contains useful functions that help glue the VCB scripts together.

The modification is around line 39:

<code>

// EDIT - akutz - put quotes around the user name and password
  return "\"" + Util_VcbPath + "\\" + command + "\" -h " + HOST + ":" + 
   PORT + " " + " -u \"" + USERNAME + "\" -p \"" + PASSWORD + "\" "

</code>

As you can see, I have edited the script so that quotes are placed properly around the username and password. This particular section of code returns a string of text that will be executed in a shell, and if the username or password has a space, the command and the script will fail.

In the next change, we will implement the ability to select multiple VMs for backup. The stock Veritas BackupExec scripts do not allow for more than VM to be backed up easily, per the documentation included with the scripts at %ProgramFiles%\VMware\VMware Consolidated Backup Framework\backupexec\README-backupexec.html. What you will end up with is an unreadable command if you try to string more than one VM backup together.

In our next script, veritas.js, I aim to fix that. As you might imagine, this is the script that Veritas designed to be used with BackupExec. This script is located in %ProgramFiles%\VMware\VMware Consolidated Backup Framework\backupexec.

We will be paying attention to a function called GetVMFromArgs. Because I have made so many modifications to this function, I will include it in its entirety.

<code>

/*
 *-----------------------------------------------------------------------------
 *
 * GetVMFromArgs --
 *  Populate virtual machine array with unique virtual machine names
 *  specified on command-line options/arguments.
 *
 * Results:
 *  returns an array of virtual machines populated from command-line
 *  arguments.
 *
 * Side effects:
 *  None.
 *
 *-----------------------------------------------------------------------------
 */
function GetVMFromArgs( args )
{
    // This switch defines the level of debugging information to be outputted
    // to standard out. 0 = none, 1 = information, and 2 = verbose.
 var DEBUG = 1;

 var arr_str_all_vms = new Array();

   var vmArray;
   var index;

 vmArray = new Array();
 
 // The user specified the 'akutz special' -- Back up all of the VMs
    // if the user specified "*-FullVM" or back up all of the VMs that match
    // the given regular expression. The regex must be preceeded by "rx:" and end with
    // "-FullVM".
 if ( ( args( 3 ) == "*-FullVM" ) || ( args( 3 ).match( /rx:(.+)-FullVM/i ) != null ) )
 {
  var oWsh = new ActiveXObject("WScript.Shell");

  // Since the user specified that they want to back up either all of the VMs or 
        // all of the VMs that match the given regular expression. we need to get a list
        // of all available VMs for comparison. To do that we will use the vcbVmName.exe 
        // command, which can list out all of the VMs.
  var strTask_cmd = 
   "\"C:\\Program Files\\VMware\\VMware Consolidated Backup Framework\\vcbVmName.exe\" " + 
   "-h \"" + HOST + ":" + PORT + 
   "\" -u \"" + USERNAME + "\" -p \"" + PASSWORD + 
   "\" -s Any";

        // Execute the vcbVmName command and capture its output.
  var oTask = oWsh.Exec( strTask_cmd );
  while ( oTask.status != 0 ) WScript.Sleep( 100 );
  var strTask_std_out = "";
  strTask_std_out = oTask.StdOut.ReadAll();

  if ( DEBUG >= 2 )
  {
   WScript.Echo( strTask_std_out );
  }

  var rxVM_name = null;

   // Get the names of ALL of the VMs from the output of the vcbVmName command
  if ( args( 3 ) == "*-FullVM" )
  {
   rxVM_name = /name:([^\r]+)\r\n[^\r]*\r\nipaddr:([^\r]*)\r/gi;
  }

  // Get the names of the VMs from the output of the vcbVmName command
  // that match the given regular expression
  else
  {
   var strRx_pattern = args( 3 ).match( /rx:(.+)-FullVM/i )[ 1 ];
   var strVm_name_pattern = "name:(" + 
    strRx_pattern + 
    "[^\\r]*?)\\r\\n[^\\r]*?\\r\\nipaddr:([^\\r]*?)\\r\\n";
   
   if ( DEBUG >= 2 )
   {
    WScript.Echo( strVm_name_pattern );
   }
   
   rxVM_name = new RegExp( strVm_name_pattern, "gi" );
  }

  var mVM_name;

  while ( ( mVM_name = rxVM_name.exec( strTask_std_out ) ) != null )
  {
   var strVM_name = mVM_name[ 1 ]
   var strVM_ip = mVM_name[ 2 ];

   if ( DEBUG >= 1 )
   {
    WScript.Echo( "nm: " + strVM_name );
    WScript.Echo( "ip: " + strVM_ip );
   }

   arr_str_all_vms.push( strVM_name );
   
   // Do not attempt to back the VM up if it has a space
   // in its name. This will fail because the SDK snapshot
   // method does not support spaces in the name.
   var rx_vm = /^\S+$/;
   
   if ( rx_vm.test( strVM_name ) )
   {
    var strVM_name = strVM_name + "-FullVM";
    if ( !IsVMDuplicate( vmArray, strVM_name ) )
    {
     vmArray.push( strVM_name );
    }
   }
  }
 }
 else
 {
  for ( index=3; index < args.length; index++ ) 
  {
      if ( !IsVMDuplicate(vmArray, args( index ) ) ) 
   {
        vmArray.push( args( index ) );
      }
  }
 }

 if ( DEBUG >= 1 )
 {
  WScript.Echo( vmArray.join( "\r\n" ) );
  WScript.Echo( "Backing up " + vmArray.length + " VMs out of " + arr_str_all_vms.length );
 } 
 
 return ( vmArray );
}

</code>

With the changes we have implemented, it will be easier to back up multiple VMs. For example, suppose we want to perform full backups on vm01.foo.com, vm02.foo.com and vm03.foo.com. With the stock scripts, we would have to write a back up command similar to:

<vcb-path>\backupexec\pre-command.bat <jobname> <BACKUPROOT>\vm01.foo.com-FullVM 

<BACKUPROOT>\vm02.foo.com-FullVM <BACKUPROOT>\vm03.foo.com-FullVM

Wow, that is long. After modifying the above function, we can rewrite this command as:

<vcb-path>\backupexec\pre-command.bat <jobname> rx:vm0[1-3]-FullVM

Ahhh, much better.

We still need to edit two other parts of veritas.js, or an individual VM that fails to back up properly will still cause the entire backup job to fail.

The first function we need to look at is DoPreJobCommand. This is the function that Veritas BackupExec calls prior to backing up data -- it quiesces running VMs and takes snapshots of them onto the backup proxy. We need to edit that function so that it will continue gracefully if a VM backup fails:

<code>

// EDIT - 2006/09/06 - do not exit but continue to the next VM
if (vcbErrOk != result) {
StdErr.Write("failed to prepare " + vmInfo.name +
     " for backup, PrepareForBackup() returned error " +
     result + "\n");
}
/*
if (fd != null) {
  fd.Close();
}

DoPostJobCommand(jobName, defaultPath, browseFlag)
throw Error(result);
}*/

</code>

We also need to comment out a section of code in the DoPostJobCommand function so that, if there is a problem with removing a single VM snapshot after the backup job completes, the entire post job command won't fail.

<code>
a
 if (vcbErrOk == result) {
    fso.DeleteFile(jobFileName);
  } else {
    // EDIT - 2006/10/05 - do not throw an error, backupexec will complain
 // throw Error(result);
  }
  
</code>

After you upload those files to your VCB proxy, your VCB backups will be much easier to manage.

If you are having trouble with VCB scripts, you can always run them manually from the command line. The debug output gets logged to a file in your user's temp directory, usually at c:\documents and settings\%USERNAME%\Local Settings\Temp, in a file named like "pre_ESX-FullVMs92200673315.log" or "post_ESX-FullVMs92200673315.log". Replace the numbers with your own timestamp, obviously. When BackupExec runs the scripts, the logs are most likely in the temp directory inside of the Windows directory.

Andrew Kutz is deeply embedded in the dark, dangerous world of virtualization. Andrew is an avid fan of .NET, open source, Terminal Services, coding and comics. He is a Microsoft Certified Solutions Developer (MCSD), a SANS/GIAC Certified Windows Security Administrator (GCWN, and a VMware Certified Professional (VCP) in VI3. Andrew graduated from the University of Texas at Austin with a BA in Ancient History and Classical Civilization and currently lives in Austin with his wife Mandy and their two puppies, Lucy and CJ.

This was first published in October 2007

There are Comments. Add yours.

 
TIP: Want to include a code block in your comment? Use <pre> or <code> tags around the desired text. Ex: <code>insert code</code>

REGISTER or login:

Forgot Password?
By submitting you agree to receive email from TechTarget and its partners. If you reside outside of the United States, you consent to having your personal data transferred to and processed in the United States. Privacy
Sort by: OldestNewest

Forgot Password?

No problem! Submit your e-mail address below. We'll send you an email containing your password.

Your password has been sent to:

Disclaimer: Our Tips Exchange is a forum for you to share technical advice and expertise with your peers and to learn from other enterprise IT professionals. TechTarget provides the infrastructure to facilitate this sharing of information. However, we cannot guarantee the accuracy or validity of the material submitted. You agree that your use of the Ask The Expert services and your reliance on any questions, answers, information or other materials received through this Web site is at your own risk.