Using the CloudBees Flow Perl API

You can use the CloudBees Flow Perl API to

  • Model and deploy applications

  • Create and manage resources

  • Create environment models and add resources to them

  • Model and run pipelines

  • Model and run releases

  • Create and call procedures

  • Create and manage artifacts

  • Create and manage object properties

The Perl APIs can be used from a command-line interface, in a shell script, or in a batch file. The CloudBees Flow API supports ectool and ec-perl commands:

  • ectool is a command-line tool developed to script CloudBees Flow operations.

  • ec-perl is delivered as a Perl package during CloudBees Flow installation, or you can use any Perl of your choice.

This topic describes ectool and ec-perl usage and their differences, because ectool and ec-perl can work together.

Using ectool

ectool is a command-line application that provides operational control over the CloudBees Flow system. ectool supports a large collection of commands, each of which translates to a message sent to the CloudBees Flow server. For example, ectool getProjects returns information about all projects defined in the server.

  • ectool --help displays a summary of all commands and other command-line options.

  • For information about a particular command, use --help followed by the command name. For example, ectool --help modifyStep returns information about the modifyStep command.

Logging In

If you use ectool ` outside of a job, you must invoke the `ectool login command to log in to the server. After logging in, ectool saves information about the login session for use in future ectool invocations. If you run ectool as part of a CloudBees Flow job, you do not need to log in—ectool uses the login session (and credentials) for that job.

To log in to a specific server, see the example below, which includes the server name, user name, and password.

ectool --server bldg1server login "Ellen Ernst" "ee123"

General syntax for ectool command usage:

ectool [global argument] <command> <positional arguments> [named arguments]

Global Arguments (Optional)

See Common Global Options for more information.

Character Restrictions in Arguments

ectool ` does not support any argument value that begins with a `-- (double hyphen), because this is reserved as the prefix for argument names.

Passing Lists as Arguments

Some API commands include arguments that expect a list of values. Two list forms: value lists and name/value pairs. The syntax to specify a list depends on whether you are using ectool or ec-perl.

For ectool

  • value list—each value is specified as a separate argument on the command line Example:

ectool addUsersToGroup group1 --userNames user1 user2 user3
  • name/value pairs—each pair is specified as a separate argument in the form name=value Example:

ectool runProcedure proj1 --procedureName proc1 --actualParameter parm1=value1 parm2=value2

For ec-perl

  • value list —the argument value is a reference to an array of values Example:

$cmdr->addUsersToGroup({ groupName => group1,                          userName => ['user1', 'user2']});
  • name/value pairs—the argument value is a reference to an array of hash references. Each hash contains a pair of entries, one for the name and one for the value. The hash keys depend on the specific API. Example:

$cmdr->runProcedure({ projectName   => 'proj1',
                      procedureName => 'proc1',
                      actualParameter => [ { actualParameterName => 'parm1',
                                            value => 'value1'},
                                           { actualParameterName => 'parm2',
                                            value => 'value2'}
										 ]
					 });

Using ec-perl

When CloudBees Flow is installed—Server, Agent, or Tools (using the express or advanced installation type)—a copy of Perl is installed. This Perl is pre-configured with all the packages you need to run the CloudBees Flow Perl API. CloudBees Flow does not, however, automatically add this version of Perl to your path because:

  • The CloudBees Flow installation must not interfere with existing scripts , which depend on finding another copy of Perl you already use.

  • Special environment variables need to be set before calling Perl.

Both of these issues are addressed with a small wrapper program called ec-perl. The wrapper is installed as part of CloudBees Flow, and it is in a directory that is added to your path. When the ec-perl wrapper runs, it sets up the environment, finds, and calls the CloudBees Flow copy of Perl, passing all of its parameters to Perl.

To run ec-perl from a command line (or in a CloudBees Flow step) enter:

ec-perl yourPerlOptions yourPerlScript.pl

The Perl script can include API calls to CloudBees Flow with no other special handling required.

For a CloudBees Flow step, you can enter the Perl script directly into the "Command" field, and set the "Shell" field to ec-perl. The CloudBees Flow-installed Perl is used to process the Perl script.

You can develop Perl scripts to access the Perl API directly. Because ectool uses the Perl API to execute its commands, any ectool command you can execute can be executed using the Perl API. If you are writing (or currently using) a script that makes tens or hundreds of calls, the Perl API provides a significant performance improvement over ectool.

The Perl API is delivered as a collection of Perl packages pre-installed in a Perl 5.8 distribution. The main API package is called ElectricCommander.

Perl API Structure

The Perl API has the same four elements as ectool, but the way these elements are specified is quite different.

Specifying global options

To use the CloudBees Flow Perl API, you must first create an object. Global arguments are specified at the time the object is created. These arguments are passed as members of an anonymous hash reference, as shown in the following example:

use ElectricCommander;
$cmdr = ElectricCommander->new({
    server      =>  "vm-xpsp2",      port        =>   "8000",    securePort  =>  "8443",    debug       => "1",
});

In the example above, port options are not really necessary because they specify default values. When you want to specify the server name only, you can use the “shorthand” form:

use ElectricCommander;
$cmdr = ElectricCommander->new("vm-xpsp2");

An even simpler form can be used if you call the Perl API from a script running as part of a CloudBees Flow job step. In this case, the CloudBees Flow package sets the server name based on the environment variable, COMMANDER_SERVER, set by the CloudBees Flow agent.

use ElectricCommander;
$cmdr = ElectricCommander->new();

To see a complete list of global commands you can use with Perl, click here.

If your script uses International characters (non-ASCII), add the following block to the top of your ec-perl command block:

use utf8;
ElectricCommander::initEncodings();

Specifying Subcommands

For each subcommand, there is a corresponding CloudBees Flow object function.

For example, to retrieve a list of jobs, use

$cmdr->getJobs();

Specifying Arguments

Most subcommands expect one or more arguments. Arguments are specified as key value pairs in a hash ref passed as the final argument to the subcommand. Additionally, as a convenience, some arguments may be specified as positional arguments prior to the options hash ref.

For example, setProperty has two positional arguments, propertyName and value, and an optional jobId argument that can be specified in either of the following forms:

$cmdr->setProperty("/projects/test/buildNumber", "22",
    {jobId => $jobId});

or

$cmdr->setProperty({   propertyName => "/projects/test/buildNumber",          value => "22",          jobId => $jobId });

Handling Return Values

Every function to the object returns an object of type XML::XPath. This is an object that returns a parsed representation of the CloudBees Flow returned XML block. See documentation on CPAN for more information.

$xPath = $cmdr\->setProperty("filename", "temp.xml");
print "Return data from Commander:\n".
$xPath->findnodes_as_string ("/") . "\n";

Error Handling

If a function call to the CloudBees Flow object encounters an error, by default, it "dies" inside Perl and prints an error message. If you want to handle errors yourself and continue processing, you must set a flag to disable internal error handling and handle the error in your code. For example:

$cmdr->abortOnError(0);
$xPath = $cmdr\->getResource("NonExistent Resource");
if ($xPath) {
     my $code = $xPath->findvalue('//code')->value();
     if ($code ne "") {
          my $mesg = $xPath->findvalue('//message');
          print "Returned code is '$code'\n$mesg\n";
          exit 1;
     }
}

An alternative to using the abortOnError flag:

eval {$cmdr\->get...};
if ($@) {
print "bad stuff: $@";
exit 1;
}

Specifying a Named Object

Any API argument that refers to a named object (for example, projectName, procedureName ) performs property reference expansion before looking in the database for the object. This process allows constructs like the following to work without making two separate server requests:

$cmdr->getProject ('$[/server/defaultProject]')

Property reference expansion for names occurs in the global context, so context-relative shortcuts like "myProject" are not available.

Common Global Options

Global arguments can be used alone or in conjunction with other commands. These arguments are used to control communication with the server and can be used with the ectool or ec-perl APIs.

Global Arguments Description

--help

Display an online version of ectool commands with a short description. Display command information if followed by a command name.

--version

Display the ectool version number.

--server <hostname>

CloudBees Flow server address. Defaults to the COMMANDER_SERVER environment variable. If this variable does not exist, the default is to the last server contacted through the API. However, if there is no record for which server was contacted, the default is to localhost.

If you are using multiple servers, you should use the server option to ensure the correct server is specified for your task. For example, if you are using the import API, the server option may be particularly important.

Do not use in a step context: we recommend that steps running ectool or Perl scripts should never provide the server option if the intention is to communicate with the server that launched the step. If the intention is to communicate with a different server, this agent must be a registered, enabled resource in the second server. Thus, that server will ping the agent, and the agent will learn how to communicate with that server.

In a step context, ectool and the Perl API proxy server requests through the step’s agent. If the agent does not recognize the provided server-name, it rejects the request. ectool/Perl API retry the operation because at some point the server should ping the agent, and then the agent will have learned how to communicate with the server.

Generally, the issue is that the server publicizes its name as a fully-qualified domain name and ectool/Perl API issue requests with a simple-name for the server. This can happen if the step explicitly states which server it is connecting to. Fix your steps that invoke ectool so they no longer include the server-name, and ectool will default to the server-name that the server provided.

--port <port>

HTTP listener port on the CloudBees Flow server. Defaults to port 8000.

--securePort <secureport>

HTTPS listener port on the CloudBees Flow server. Defaults to port 8443.

--secure <0|1>

Use HTTPS to communicate with the CloudBees Flow server. Defaults to 1.

Certain requests (for example, login, createUser, and modifyUser ) automatically use HTTPS because passwords are being sent, which means it is not necessary to specify secure for those APIs.

--timeout <s>

An API call waits for a response from the server for a specified amount of time. Timeout for server communication defaults to 180 seconds (3 minutes) if no other time is specified. After the timeout, the API call stops waiting for a response, but the server continues to process the command.

You can also use the global CloudBees Flow COMMANDER_ECTOOL_TIMEOUT environment variable. The --timeout <s> argument overrides the value of this environment variable if it is set.

--retryTimeout <s>

This is a separate timer, independent of the retry flag, and is used to control CloudBees Flow’s automatic error recovery. When the API cannot contact the CloudBees Flow server, it keeps trying to contact the server for this length of time. When the API is called from inside a step, it defaults to 24 hours.

You can also use the global CloudBees Flow COMMANDER_ECTOOL_RETRY_TIMEOUT environment variable. The --retryTimeout <s> argument overrides the value of this environment variable if it is set.

--retry <0|1>

Retry the request if it times out based on the "timeout" value. Default is "0" and should be changed rarely.

--user <username>

Use the session associated with the user. Defaults to the user who last logged in.

--service <spn>

Specify the service principal name to use for Kerberos. Defaults to HTTP@host.domain.

--setDefault <0|1>

Use the current session as the default for subsequent invocations. Defaults to 1.

encoding <charEncoding>

Use the specified encoding for input/output. For example, for charEncoding, enter UTF-8, cp 437, and so on. Default is autodetected.

--dryrun

Displays session information and the request that would be sent, without communicating with the server. If a subcommand is specified, the server request that would be sent is displayed. This option can also be used to change the default user/server value by specifying the --user or --server options.

--silent

Suppresses printing the result. For example: ectool --silent createResource foo will not print the resource name, agent state, any modify information, create time, owner, port, or any other information otherwise displayed when you create a resource.

--valueOf

This option can return the value of a unique element. Because many ectool APIs return an XML result, it is inconvenient to use ectool in shell scripts and makefiles where you might want a piece of the ectool result to incorporate into some other logic. Using the --valueOf <path> option evaluates the XML result and emits the value of that node to satisfy such use cases. For example: $ ectool --valueOf '//version' getServerStatus returns only "4.1.0.48418".

--format <format>

Specifies the response format. Must be one of 'xml' or 'json'. Defaults to 'xml'. For example, you might specify: ectool --format json setProperty summary hello

--ignoreEnvironment

Force ectool to ignore COMMANDER_ENV variables.

The Batch API

The Perl API supports a batch operation mode that allows you to send multiple API requests in a single "envelope", which has several advantages over standard, individual API calls in some situations. For example, you could use the batch API when you need to set 10 or even 100 property values.

The batch API reduces "round-trip" transmissions. All setProperty requests can be sent in a single envelope. You can choose an option that changes all properties in a single database transaction in the server. This means changes are made using an "all or none" approach. If one change fails, they all fail, which allows you to keep your data in a consistent state. When you make a large number of requests in one envelope, the single database transaction option provides much better performance.

Using the Batch API

To use the batch API, first create a object as you would for a standard API. From your newly created object, create a batch object using the newBatch method. The `newBatch ` method takes a single argument, which is the "request processor mode". This argument tells the server how to process multiple requests. There are three "request processor modes":

  1. serial —each request in the envelope is processed serially, each in its own transaction.

  2. parallel —each request in the envelope is processed in parallel, each in its own transaction.

  3. single —each request in the envelope is processed serially, all in the same transaction.

Specifying serial, parallel, or single is optional. If you do not specify an option, the server determines the best mode to use based on the requests in the envelope.

Example—creating a batch object:

use ElectricCommander;
my $cmdr = ElectricCommander;
# Create the batch API objectmy
$batch = $cmdr\->newBatch("parallel");

The batch object supports all the same calls as the standard API. The result of each call is a numeric requestId that can be used to locate a response from an individual request within the batch.

Example—creating multiple requests in a batch:

# Create multiple requestsmy
@reqIds = (  $batch->setProperty("/myJob/p1", 99),  $batch->incrementProperty("/myJob/p2"));

After the batch is created, submit it to the server for processing. The return from the submit() call is an XPath object that represents an XML document containing the responses for all of the API requests.

Example—submitting the batch:

# Submit all the requests in a single envelope
$batch->submit();

Sample response from this example:

<responses xmlns:xsi=\https://www.w3.org/2001/XMLSchema-instance
    xsi:
   version="2.1" dispatchId=1680
   <response requestId="1">
     <property>
       <propertyId>199827</propertyId>
       <propertyName>p1</propertyName>
       <createTime>2010-07-21T16:41:20.003Z</createTime>
       <expandable>1</expandable>
       <lastModifiedBy>project: EA Articles</lastModifiedBy>
       <modifyTime>2010-07-21T16:41:20.003Z</modifyTime>
       <owner>project: EA Articles</owner>
       <value>99</value>
    </property>
  </response>
  <response requestId="2">
    <property>
      <propertyId>199828</propertyId>
      <propertyName>p2</propertyName>
      <createTime>2010-07-21T16:41:20.019Z</createTime>
      <expandable>1</expandable>
      <lastModifiedBy>project: EA Articles</lastModifiedBy>
      <modifyTime>2010-07-21T16:41:20.019Z</modifyTime>
      <owner>project: EA Articles</owner>
      <value>1</value>
    </property>
  </response>
</responses>

To extract information from the response to a request, use standard XPath syntax, and enter the requestId returned by that specific API call to either the find or findvalue functions on the batch object.

Example—extracting response information:

# Extract the value from the "increment" requestmy
$value = $batch->findvalue($reqIds[0], 'property/value');
print "New value is $value\n";

Single-transaction batch processing can continue after errors if you enter an ignoreErrors attribute in the request and/or requests elements. The ignoreErrors value is evaluated as a regular expression against any error codes from the batch. If the expression matches, an error will not cause the batch to fail.

There are two ways to specify ignoreErrors when issuing a single-transaction batch call:

  1. Specify the ignoreErrors attribute when creating the batch object. In this case, the attribute applies to all requests in the batch: my $batch = $N→newBatch('single', 'DuplicateResourceName');

  2. Specify the ignoreErrors attribute as an argument to an individual request. In this case, the attribute applies only to that request and will override any global value specified: my $req2 = $batch→createResource($resource, {ignoreErrors ⇒ 'DuplicateResourceName'});

Installing CloudBees Flow Perl Modules into Your Perl Distribution

You may want to use your existing Perl distribution. If so, CloudBees Flow uses a CPAN style module, located in <installdir>/src, that can be installed with the following commands:

tar xzvf ElectricCommander-<your version>.tar.gzcd ElectricCommander-<your version>perl Makefile.PLmake install;
# Use nmake on Windows

These commands install the CloudBees Flow Perl and all of its submodules. If some prerequisite modules are missing, the Makefile.PL script will indicate which modules are needed.

Installing Perl Modules into the CloudBees Flow Perl Distribution

You may want expand the CloudBees Flow Perl distribution by adding Perl modules from CPAN or third party vendors.

Install Perl modules using the CPAN installer. The installer comes with the CloudBees Flow Perl distribution in <CloudBees_Flow_Dir>/perl/bin.

During a CloudBees Flow upgrade, the installer makes every attempt to preserve Perl packages. However, future CloudBees Flow versions may contain an upgraded Perl version, which may then require a reinstall of any added Perl packages.

For Linux

From the command line use: <CloudBees_Flow_Dir>/perl/bin/perl -MCPAN -e 'install <module>'

For Windows

Compatibility with CloudBees Flow is important. CloudBees Flow 5.0 and later use Perl 5.8 for ec-perl.

If the Perl package is not Perl-only and requires compiling (for example, for C code):

  • Use Windows Visual Studio VC6 (the same version used by CloudBees Flow).

  • Make sure that cl and nmake are both in your path. The Visual Studio install has a Command Prompt with these executables already in the path.

Extra steps are needed for Windows because of a problem with Perl and CPAN if you are running from a directory with spaces in the name. (By default, CloudBees Flow has spaces in the installed directory.)

  • Use a network drive to eliminate references to spaces. Use subst to mount the Perl directory under a different drive letter: c:\> subst x: "c:\program files\Electric Cloud\ElectricCommander" Start CPAN from the new location: c:\> x:\perl\bin\perl -MCPAN -e shell Configure CPAN to install into the new location: cpan> o conf makepl_arg PREFIX=x:/perl Install the module: ` cpan> install <module>` Ending CPAN: ` cpan> quit `

  • Change the <CloudBees Flow_Dir>\perl\lib\config.pm file to eliminate spaces in references to the CloudBees Flow path. For example:

#archlibexp => 'C:\Program Files\\Electric Cloud\ElectricCommander\perl\lib',  archlibexp => 'X:\perl\lib',#privlibexp => 'C:\Program Files\\Electric Cloud\ElectricCommander\perl\lib',  privlibexp => 'X:\perl\lib',#scriptdir => 'C:\Program Files\\Electric Cloud\ElectricCommander\perl\lib',  scriptdir => 'X:\perl\lib',#sitearchexp => 'C:\Program Files\\Electric Cloud\ElectricCommander\perl\site\lib',  sitearchexp => 'X:\perl\lib',#sitelibexp => 'C:\Program Files\\Electric Cloud\ElectricCommander\perl\site\lib',  sitelibexp => 'X:\perl\lib',
  • Temporarily add X:\perl\bin to your Windows path.

Using Perl API Commands in Javascript

You can use CloudBees Flow Perl API commands in Javascript. In previous releases, Javascript was read-only, and only getProperty and setProperty were called in Javascript.

These are examples of how to use Perl API commands in Javascript:

  • To create a project:

    ectool evalScript --value "(api.createProject(
        { 'projectName':'alex34' } )).project.projectName ; " alex34
    
    [source,txt]
  • To return the object type, use this Javascript script:

    ectool evalScript --value "api.getResources({})" [object Object]
  • For a parsed object, use the "JSON.stringify()" call:

    ectool evalScript --value "JSON.stringify(api.getResources({})) "{
       "resource":{
          "resourceId":"ceecfce5-2d0d-11e4-8888-005056330afe",
          "resourceName":"local",
          "agentState":{
             "alive":"1",
             "details":"The agent is alive",
             "hostOS":"Linux qa-ub1210-64-2 3.5.0-19-generic
                       #30-Ubuntu SMP Tue Nov 13 17:48:01 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux",
             "hostPlatform":"linux",
             "message":"The agent is alive",
             "pingToken":"1409049660",
             "protocolVersion":"6",
             "state":"alive",
             "time":"2014-08-26T10:43:25.802Z",
             "version":"5.0.3.76444"
          },
          "createTime":"2014-08-26T10:43:25.617Z",
          "description":"Local resource created during installation.",
          "hostName":"qa-ub1210-64-2.electric-cloud.com",
          "hostOS":"Linux qa-ub1210-64-2 3.5.0-19-generic
                    #30-Ubuntu SMP Tue Nov 13 17:48:01 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux",
          "hostPlatform":"linux",
          "lastModifiedBy":"project: zebra",
          "lastRunTime":"2014-08-26T10:50:23.786Z",
          "modifyTime":"2014-08-26T10:50:23.786Z",
          "owner":"admin",
          "port":"7800",
          "proxyPort":"",
          "resourceAgentState":"alive",
          "resourceAgentVersion":"5.0.3.76444",
          "resourceDisabled":"0",
          "stepCount":"0",
          "stepLimit":"",
          "trusted":"0",
          "useSSL":"1",
          "propertySheetId":"ceee8387-2d0d-11e4-8888-005056330afe",
          "zoneName":"default",
          "pools":"default"
       }
    }
  • To get the first resourceName :

    ectool evalScript --value "api.getResources({}).resource[0].resourceName"