Running remote Unix commands from LoadRunner

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:

1
2
3
4
5
6
7
8
9
10
                 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:

1
2
3
4
5
6
7
8
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/*
 * 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.

2 Responses to “Running remote Unix commands from LoadRunner”

  1. Stuart Moncrieff says:

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    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 says:

      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.

Leave a Reply