This web site should be used for installations up to gLite 3.2. For EMI installations please refer to the new web site https://wiki.italiangrid.it/CREAM

Prerequisites

We assume the following prerequisites:

  • Strong understanding of the C++ language and the STL template library.
  • Basic knowledge of the boost library.
  • What a job is and its description language (JDL).
  • Knowledge of what a CREAM CE is, what it does, what it doesn't do; the difference between job registration and job submission in the context of CREAM; the concept of lease time.
  • what a remote call (or remote operation) invocation is on a Web Service.
  • Usage and concepts of the Unix/Linux operating system

Introduction

This tutorial shows how to write a simple C++ client for the CREAM CE Web Service using the C++ API provided by the glite package org.glite.ce.cream-client-api-c (to download the RPM click here; please use always the latest version). This RPM also depends on the following runtime dependencies:

Software dependencies

(The above links refer to platform SLC4_X86_64; please go to Etics repository to look for different platforms and/or source code to compile).

  • Also make sure to have boost and boost-devel and libxml2 installed. In some installation I found the libxml2.so missing. There're libxml2.so.NUMBER instead (in /usr/lib and /usr/lib64). In order to build the example code a symlink (libxml2.so -> libxml2.so.NUMBER) is needed to fix it.

API

Currently, the C++ API implements the following operations:

The API architecture is founded on a super- and abstract class AbsCreamProxy that exposes 3 relevant public methods:

The execute(...) method is responsible for the connection to the remote web service, sending the request, receiving the response and unserializing it. All SOAP communication and authentication details are hidden to the user.

As mentioned above, AbsCreamProxy is abstract (the execute(...) method is pure virtual) and thus cannot be instantiated. It has several child classes that implement the execute(...) method. Each subclass represents a CREAM operation (JobRegister, JobInfo, JobList, etc.); so, each execute(...) implementation is different.

The subclasses have private constructors, so the user cannot instantiate them; a factory (CreamProxyFactory) is provided to properly build an instance of a AbsCreamProxy's subclass. For instance,

CreamProxyFactory::make_CreamProxyRegister(...)

returns a polimorphic object of type AbsCreamProxy, that is actually an instance of the subclass CreamProxy_Register.

The user is not required to know anything about these subclasses; she only receives a pointer to an AbsCreamProxy object (that must be checked for 'nullness') and only has to invoke the methods setCredential(...) and execute(...) (and optionally setConnectionTimeout(...)) on it.

At the end this pointer must be freed (with delete).

Step by step Job Submission explanation

Proxy Delegation

In order to register a job, the user must previously delegate a proxy into the remote CREAM CE service. The procedure is a matter of a few steps:

  1. define a string containing a delegation identifier (it will be used later as job registration parameter)
  2. create an instance of a subclass of AbsCreamProxy with the invocation of the static method CreamProxyFactory::make_CreamProxyDelegate(...)
  3. invoke the setCredential(...) method on the instance created above
  4. invoke the execute(...) method on the instance created above
  5. delete the AbsCreamProxy instance

Download the example code here for Proxy Delegation. Makefile needed to build all the examples; please note that it is written to build examples on SLC5 64bit; adapting it to different platforms should be straightforward.


Job Registration

The steps for the 'JobRegister operation are:

  1. Prepare a string containing the JDL description of the job to submit;
  2. Be prepared to use an identifier of a pre-delegated delegate proxy;
  3. Prepare a JobDescriptionWrapper object to send to the CREAM CE WebService;
  4. Create an instance of a subclass of AbsCreamProxy with the invocation of the static method CreamProxyFactory::make_CreamProxyRegister(...);
  5. Invoke the setCredential(...) method on the instance created above;
  6. Invoke the execute(...) method on the instance created above;
  7. Process the output;
  8. Delete the AbsCreamProxy instance.

The input and output arguments of the CreamProxyFactory::make_CreamProxyRegister(...) are a bit more complicated than in the case of the Proxy Delegation. As described in the API reference, the input and output arguments are:

They are typedef for (respectively):

The first one is simply a C++ STL list where the user has to insert pointers to JobDescriptionWrapper objects; the second one is a complex structure based on the boost::tuple library. Each JobDescriptionWrapper object is built with a JobDescription identifier (a string chosen by user) and other parameters that can been seen in the example below.

After the invocation of the execute(...) method, the second argument passed to the CreamProxyFactory::make_CreamProxyRegister(...) function will be filled as follows:

  • The key of the map is the JobDescription identifier (as defined by the user, see above)
  • The value corresponding to the key is a boost::tuple; this tuple groups three elements:

As shown in the source code, a mandatory argument is autostart. In the example it is set to false; this means that the job is ONLY REGISTERED and NOT STARTED. Below it is explained the usefulness of autostart set to false. If she needs to start the job immediately after registration she can set to true the autostart parameter.

An array of properties (implemented as a std::map<string, string>, key -> value ) is embedded in the JobIdWrapper object returned by JobRegister operation. At the moment the only relevant property returned by CREAM is the remote path in the CE the user can send its InputSandbox to. Please see the method JobIdWrapper::getProperties for more details and the source code example below.


Download the example code here. Example code for multiple job registration with a single remote call is here. Makefile to build all the examples; please note that it is written to build examples on SLC5 64bit; adapting it to different platforms should be straightforward.


Job start

In the previous example, jobs are simply registered in the CREAM CE (autostart is set to false). This is useful if the user needs to do something between job registration and job start (e.g.: sending an input sandbox in the remote path specified by the CREAM CE for each job after the registration). To explicitly start a job the user must:

  1. Obtain the Cream Job IDs of the jobs to start (as result of JobRegister operation)
  2. Build the JobIdWrapper object representing the jobs to start (one for each Cream Job ID to start)
  3. Define a time range (specified by two variables fromDate and toDate) which will allow her to only start the jobs that were registered in the time range [fromDate, toDate]
  4. Build a JobFilterWrapper with all the JobIdWrapper objects representing the jobs to start, and the time range.
  5. Create the proper subclass of AbsCreamProxy by invoking the static method of the CreamProxyFactory::make_CreamProxyStart(...) factory
  6. Invoke, as usual, the setCredential(...) and execute(...) methods on the previously created AbsCreamProxy's instance.

To start all her jobs, the user has to use an empty vector of JobIdWrapper objects as argument of the JobFilterWrapper's costructor.


Download the example code here. Makefile to build all the examples; please note that it is written to build examples on SLC5 64bit; adapting it to different platforms should be straightforward.


Cancelling, Suspending, Resuming and Purging jobs

The code for these four operations is basically the same. The user must prepare a JobFilterWrapper object and pass a pointer to it as first argument of the static method CreamProxyFactory::make_CreamProxyCancel(...)/CreamProxyFactory::make_CreamProxySuspend(...)/CreamProxyFactory::make_CreamProxyResume(...)/CreamProxyFactory::make_CreamProxyPurge(...). The second argument is a pointer to a ResultWrapper object that will be filled-in with the results sent back by CREAM.

Like in the JobStart case, to process all her jobs, the user has to use an empty vector of JobIdWrapper objects as argument of the JobFilterWrapper's costructor.


Download the example code here. Makefile to build all the examples; please note that it is written to build examples on SLC5 64bit; adapting it to different platforms should be straightforward.


Listing jobs in a CREAM CE

The code for listing all the jobs submitted to a CREAM CE is very simple. A few simple parameters are needed for the factory. A look at the source code should be enough to understand what the user has to do.


Download the example code here. Makefile to build all the examples; please note that it is written to build examples on SLC5 64bit; adapting it to different platforms should be straightforward.


Getting Information about jobs submitted to a CREAM CE

A user can invoke two operations to get information on one or more jobs submitted to a CREAM CE: JobInfo and and JobStatus. The latter is quicker but provides less information than the former. In both cases the user must prepare a JobFilterWrapper object that collects all the identifier strings of the jobs to query and the conditions the jobs must satisfy in order to be included in the result. For example a user might need the status of all jobs submitted between 8:00am and 15:00am of a particular day (if they were not purged out yet). Or she might need extended information on all the jobs that are in the "RUNNING" OR "DONE-OK" states... and so on. Please see the documentation of JobFilterWrapper to see what filters a user can define.

Fast info query (JobStatus)

With the invocation of the JobStatus remote operation CREAM will return a minimal set of information about the jobs; essentially the current status of the job, the timestamp of the last status change, the exit code of the job and the failure reason (if the job finished or aborted). To query the states of some jobs, the user must prepare a JobFilterWrapper object and fill it with JobIdWrapper objects (one for each job to query) and with other constraints to select a particular set of jobs (see the JobFilterWrapper documentation).

As usual a user can query for the states of all her jobs. This can be achieved by using an empty vector of JobIdWrapper objects as argument of the JobFilterWrapper's costructor.

See the CreamProxyFactory::make_CreamProxyStatus and JobStatusWrapper documentation for more details about the structure of the information returned by CREAM.

As usual some example code is the best way to explain how it works...


Download the example code here. Makefile to build all the examples; please note that it is written to build examples on SLC5 64bit; adapting it to different platforms should be straightforward.


Slow info query (JobInfo)

To get complete information about jobs the user must invoke the remote call JobInfo. The procedure is much similar to the fast call: the user has to prepare a JobFilterWrapper object to select jobs and filters; then the result will be put in a JobInfoWrapper structure instead of a JobStatusWrapper one as in the case of the fast call. The data structure containing the output of the JobInfo operation is very similar to that one for the JobStatus operation.

See the CreamProxyFactory::make_CreamProxyInfo and JobInfoWrapper documentation for more details about the structure of the information returned by CREAM.


Download the example code here. Makefile to build all the examples; please note that it is written to build examples on SLC5 64bit; adapting it to different platforms should be straightforward.


Getting Service Information from a deployed CREAM CE running service

This remote operation is quite simple too; the factory just needs a simple parameter that is a pointer to a ServiceInfoWrapper object; this class exposes methods to obtain information on the CREAM service which should be self-explanatory.


Download the example code here. Makefile to build all the examples; please note that it is written to build examples on SLC5 64bit; adapting it to different platforms should be straightforward.


Renewing a Delegated Proxy

To register a job to a CREAM CE a client must first delegate a proxy to the CE and save an identifier string associated with this delegation; this identifier will be used to register jobs. But the proxy are not valid forever. At some point the delegated proxy must be renewed. The procedure is as simple as in the delegation case. The user has just to put the delegation identifier string into the factory method that creates the proper AbsCreamProxy subclass and invoke, as usual, setCredential(...) and execute(...). Taking a look at the example source code is the fastest way to understand this very simple procedure.


Download the example code here. Makefile to build all the examples; please note that it is written to build examples on SLC5 64bit; adapting it to different platforms should be straightforward.


Enabling, Disabling the Job Submission Service

Depending on the role of the user, she can enable/disable the job submission on a remote CREAM CE. The code is so simple that, as usual, the example speaks for itself.


Download the example code here. Makefile to build all the examples; please note that it is written to build examples on SLC5 64bit; adapting it to different platforms should be straightforward.


Querying the Status of the Job Submission Service

This availability is returned as service information with the remote call ServiceInfo. See ServiceInfo

QueryEvent

WORK IN PROGRESS...

A new operation has been added to CREAM capabilities: QueryEvent. A user that invokes a QueryEvent on a CE, receives all her jobs's status changes. The query has two filter:

  1. time range (from, to)
  2. ID range (from ,to)

Time range has a quite intuitive meaning; the ID a few less. Each event generated in a CE for a certain user, has an incremental ID (64bit unsigned integer). A user can be interested to a certain events identified by a recent ID range that correspond to recent jobs. This function is particularly useful to the ICE component that memorizes the last EventID received in the last call for each couple (user_DN, CE_URL), resulting in a quite small information exchange with the CE about job states.

In order to perform a QueryEvent the user must obtain a pointer to an AbsCreamProxy object by mean of CreamProxyFactory::make_CreamProxy_QueryEvent, invoke the execute(...) method on it, and delete it as usual. The invocation of execute will fill up the list of EventWrapper pointers (that is an argument of the CreamProxyFactory::make_CreamProxy_QueryEvent function).