If you need to run a Unix command on a remote server with a LoadRunner script (running on Windows), then there is a neat program called plink that you will find very useful.

If you use any variety of Unix, you will probably already by using PuTTY; well plink is is distributed with PuTTY, and allows you to run remote Unix commands from your DOS prompt.

In this example, I have used it to collect disk I/O metrics from a remote Solaris server.

You may need to refer to some background material for the different components that are used for this example.

To capture the %busy metric for each disk, I can run iostat -xc. This gives the following output:

                 extended device statistics                      cpu
device    r/s    w/s   kr/s   kw/s wait actv  svc_t  %w  %b  us sy wt id
md0       0.5    0.6    8.5    0.8  0.0  0.0   19.9   0   0   1  1  0 98
md1       6.3    6.8   50.3   54.5  0.0  0.3   24.0   0   0
md3       0.2    0.7   12.7   12.6  0.0  0.0   11.0   0   1
md5       0.0    0.0    2.7    0.3  0.0  0.0    8.0   0   0
md6       0.0    0.0    0.0    0.0  0.0  0.0    3.6   0   0
md10      0.3    0.6    4.2    0.8  0.0  0.0   21.3   0   0
md11      3.1    6.8   25.1   54.5  0.0  0.3   25.6   0   0
md13      0.1    0.7    6.4   12.6  0.0  0.0    8.7   0   0

Using AWK to just grab the device name and the %b column can be done by running iostat -xc | awk ‘NR >2 {print $1, $9}’, which gives:

md0 0
md1 0
md3 1
md5 0
md6 0
md10 0
md11 0
md13 0

Putting this in a LoadRunner script that will save the %b value for each device using lr_user_data_point() looks like this:

/*
 * This script retrieves Disk IO stats from a Solaris server and plots them in the Controller using lr_user_data_point().
 */

#define BUFFER_SIZE 10240 // 10 KB

extern char* strtok(char *token, const char *delimiter); // Explicit declaration required for functions that do not return an int.

Action()
{
    long fp; // file/stream pointer
    int count; // number of characters that have been read from the stream.
    char buffer[BUFFER_SIZE]; // allocate memory for the output of the command.
    char * row_token; // for each row in the output of the command.
    char field_name[100]; // for the first column in the row.
    int field_value; // for the second column in the row.
    char lrudp_name[100]; // buffer to hold the LR user data point name.
    int rc; // return code for sscanf.

    lr_start_transaction("Monitor Disk IO");

    // The command we want to run is: plink -ssh -l username -pw password hostname command
    lr_save_string("stuart", "UserName");
    lr_save_string("asdf7890", "Password");
    lr_save_string("sdb526.sysdomain.local", "Server");
    lr_save_string("iostat -xc | awk 'NR >2 {print $1, $10}'", "Command"); // run iostat, and retrieve the "device" and "%b" column from the output.
    lr_save_string(lr_eval_string("C:\\Progra~1\\PuTTY\\plink -ssh -l {UserName} -pw {Password} {Server} \"{Command}\" 2>&1 0< nul:"), "CompleteCommand"); // Note: plink refuses to work without stdin redirected
    fp = popen(lr_eval_string("{CompleteCommand}"), "r"); 
    if (fp == NULL) {
        lr_error_message("Error opening stream.");
        return -1;
    }

    count = fread(buffer, sizeof(char), BUFFER_SIZE, fp); // read up to 10KB
    if (feof(fp) == 0) {
        lr_error_message("Did not reach the end of the input stream when reading. Try increasing BUFFER_SIZE.");
        return -1;
    }
    if (ferror(fp)) {
        lr_error_message ("I/O error during read."); 
        return -1;
    } 
    if (count == 0) {
        lr_error_message("Something went wrong when running command. No output returned.");
        return -1;
    }
    buffer[count] = NULL;

    /*
    The command should return data formatted like this:

    md0 0
    md1 0
    md3 1
    md5 0
    md6 0
    md10 0
    md11 0
    md13 0

    Iterate through each row, and save the name and value.
    */
    row_token = (char*) strtok(buffer, "\n"); // Split the buffer at each newline character 
    if (row_token == NULL) { 
        lr_error_message ("Something went wrong. No token found"); 
        return -1; 
    }
    while (row_token != NULL) { // While there are still rows in the buffer...
        rc = sscanf(row_token, "%s %d", field_name, &field_value); // Grab the field name and value.
        if (rc != 2) {
            lr_error_message("Incorrect number of items read from the row.");
            return -1;
        }

        // Create a user data point, so this value can be graphed in the LoadRunner Controller (and in LoadRunner Analysis).
        sprintf(lrudp_name, "disk_busy_%s", field_name);
        lr_user_data_point(lrudp_name, field_value);

        row_token = (char*) strtok(NULL, "\n");
    }

    /*
    Output will be 
        Notify: Data Point "disk_busy_md0" value = 0.0000.
        Notify: Data Point "disk_busy_md1" value = 0.0000.
        Notify: Data Point "disk_busy_md3" value = 1.0000.
        Notify: Data Point "disk_busy_md5" value = 0.0000.
        Notify: Data Point "disk_busy_md6" value = 0.0000.
        Notify: Data Point "disk_busy_md10" value = 0.0000.
        Notify: Data Point "disk_busy_md11" value = 0.0000.
        Notify: Data Point "disk_busy_md13" value = 0.0000.
    */

    pclose(fp);

    lr_end_transaction("Monitor Disk IO", LR_AUTO);

    return 0;
}

I hope you find this useful - both for the general concept of using LoadRunner to invoke commands (or shell scripts) on a remote Unix host and retrieve the output, and for the ability to monitor disk IO on Solaris without using SiteScope.

 

Published On: August 24, 2010Tags: ,

16 Comments

  1. Stuart Moncrieff August 25, 2010 at 12:25 pm - Reply

    Note that the first time you connect to a server using plink, you are likely to get a message like this:

    The server's host key is not cached in the registry. You
    have no guarantee that the server is the computer you
    think it is.
    The server's rsa2 key fingerprint is:
    ssh-rsa 1024 b1:bf:3b:e2:ae:b2:99:92:f8:90:61:2e:35:64:76:33
    If you trust this host, enter "y" to add the key to
    PuTTY's cache and carry on connecting.
    If you want to carry on connecting just once, without
    adding the key to the cache, enter "n".
    If you do not trust this host, press Return to abandon the
    connection.
    Store key in cache? (y/n) Connection abandoned.
    

    …and you will have to add the key to the cache before you can run plink from LoadRunner.

    • Stuart Moncrieff August 25, 2010 at 5:14 pm - Reply

      Another hot tip:

      If you use this script for monitoring, run it from a separate load generator, rather than from your Controller, because every time the DOS command is invoked, it briefly pops up an annoying cmd.exe window.

    • Piya November 7, 2010 at 9:58 am - Reply

      But how I will connect with LoadRunner? Can you describe a more please.

    • Samar December 3, 2010 at 7:22 am - Reply

      Hi,
      Great article..Am trying this out now.

      But how do i add the key to server cache ? From LoadRunner or some other means…

  2. Suresh Kolli November 20, 2010 at 4:10 am - Reply

    Hi,

    I am using PuTTy for running UNIX Commonds.The actions I do regularly are :

    1.Open PuTTy , give Host , Port and Protocal informtaion
    2.Login using UserID & Password…
    3. Goto Prticular folder and ececute some scripts in UNIX.
    4.The scripts need to be executed sequentially , preferably one by one…
    5.Monitor Server performance

    I never automated UNIX commonds by PuTTy using LoadRunner,could you help me..

    My email id :ilusuresh236@yahoo.com

    Regards,
    Suresh Kolli
    00447890996950

  3. AJ December 4, 2010 at 7:14 am - Reply

    Stuart,

    This is a wonderful solution to folk who wish to capture the server vitals while performing load tests without the need to login to unix servers. However from my experience(call me bad coder) of using custom code generously within LR scripts, would eventually lead to memory access violation errors which are annoying to troubleshoot. Should try writing the statistics captured to file using file I/O operations in C. Any comments!

    Thanks for sharing this info though!
    Rgds,
    -AJ

  4. harry lei April 20, 2012 at 2:12 am - Reply

    Please suggest any suitable tool for the load testing of Flex based web application?

  5. Vishal Saxena July 10, 2012 at 10:14 pm - Reply

    Hello Stuart,
    Thanks for such informative post.
    It gives a good guidance in initiating Unix implementation with LR.
    We are in a middle of a situation where we would require your guidance. The performance testing of an application based on Unix platform is to be done. The application is deployed on Unix servers & does not have any Web GUI.
    I have no clue from where to initiate with the process. How to record such applications with LR? What protocol should be used? How would Client-Server request look like?

    It would be highly appreciated if you can guide us on the same, since the work needs to be started soon. It would also be great if, if its possible for you to provide one such recorded sample script.
    Thanks in advance
    Vishal Saxena

  6. orlando September 18, 2012 at 12:32 am - Reply

    Hi, Stuart. Nice to see your instruction on how to run UNIX command using LR controller under windows. I tried to use LR agent to run a LR script that calls system() function to run a UNIX command, and when using mdrv -usr *.usr, all seems ok. The transaction can pass. However, when I using LR controller under WINDOWS to run the compiled script under $M_LROOT/bin the transaction failed. I used the “Not to use RSH” option. Do you think I should use RSH instead? Any suggestions? Thank you in advance.

    • Stuart Moncrieff September 21, 2012 at 7:45 am - Reply

      It sounds like you are running your vusers from an agent on a Linux/Unix load generator.

      The example above runs the Unix command remotely from a Windows load generator.

      Unfortunately I am not sure what the problem might be in your case.

      On a side-note, I would not recommend that you use Unix/Linux-based load generators for LoadRunner.

  7. keep it simple July 26, 2013 at 3:51 pm - Reply

    Hi Stuart,

    After following your steps to execute remote Unix commands I’m getting the below error.

    “RVM is not a function, selecting rubies with ‘rvm use …’ will not work.

    You need to change your terminal emulator preferences to allow login shell.
    Sometimes it is required to use `/bin/bash –login` as the command.”

    Also suggest me what I should do to execute series(at least 4) of commands in a single session…

    Thank You

  8. Anees November 26, 2013 at 9:22 pm - Reply

    Hi

    When I executed the script with my server details. The buffer stores only “avg-cpu:”.
    Due to this, the script throws error from line 71.

    But when I run the formed command manually, the value is:
    avg-cpu:
    0.67

    Am I missing something here?

  9. Dixit February 27, 2014 at 5:26 pm - Reply

    Hi Stuart,

    For SFTP in load runner where to add Private Key so that from load runner i can connect multiple sessions for the user.For me in VUGEN am unable to upload and download but from controller am getting authentication errors. Please help in this regard.

    Thanks,
    Dixit

  10. Natarajan July 25, 2014 at 2:12 am - Reply

    Hi Sturat,
    I have similar requirement. We are using HP BSM and would like to develop the VuGen script to monitor the Heap usage and fail the transactions like “lr_end_transaction(“Heap_Space_Is_Low”,LR_FAIL)’…..so that each time this script runs, we can get an alert. Is this the right way of doing it if we want to do it from BSM tool? Thanks in advance.

  11. syed November 3, 2015 at 8:49 am - Reply

    Hi Stuart,

    I am trying to connect to my servers using putty by it also needs a certificte to be added to connect to those aws servers. How can i implement that

  12. saif November 3, 2015 at 8:50 am - Reply

    Hi Stuart,

    I am trying to connect to my servers using putty by it also needs a certificte to be added to connect to those aws servers. How can i implement that

Leave A Comment