Friday, October 30, 2009
OGCE Website Down for Upgrade
We are upgrading the OGCE website (www.collab-ogce.org). The site should be up again soon.
Thursday, October 22, 2009
Making a MyProxy Gadget
In an earlier post we looked at a simple example that described how to build a Web interface to MyProxy with the Cyberaide JavaScript API. Now we will turn it into a gadget. This is straightforward, and you can easily test it out with iGoogle, Apache Shindig, or Google Code's wiki. We can reuse most of the previous example, so we will only discuss changes below.
Step 0: Wrap the HTML and JavaScript in the CDATA section of a new file, MyProxyGadget.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="MyProxy Gadget"
height="500">
</ModulePrefs>
<Content type="html">
<![CDATA[
Actual code goes here
]]>
</Content>
</Module>
It is also possible to use an iFrame for simplicity. The iframe can be embedded in the CDATA section and point to the HTML file's URL, or you can use a "url" gadget. In this case, change Content's type attribute value from "html" to "url" and provide the URL for the HTML code you want to embed.
Step 1: You will need to use full paths to all imported JavaScript libraries, images, and so on. Relative paths will not work. So for example, you import the CogKit2.js library like so:
<script type="text/javascript" src="https://my.host.com/grid/CogKit2.js"></script>
where my.host.com should be replaced with your Cyberaide deployment server. Note this also applies to the Cyberaide agent server URL. This must be changed from
var url="../agent/services/agent";
to
var url="https://my.host.com/agent/services/agent";
Step 2: You will need to use a modified SOAP JavaScript library, soapclientGadget.js. This replaces soapclient24NSMod.js. This is our modification. The library is available from our SVN repository.
Step 3: Load your gadget in your favorite gadget container. To use iGoogle, create an account and log in if necessary and then click the "Add Stuff" link in the upper right. Assuming you haven't published your gadget yet, click the "Add feed or gadget" link in the lower left side of the page. Type in the full URL to your gadget and submit. That's it.
Step 0: Wrap the HTML and JavaScript in the CDATA section of a new file, MyProxyGadget.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="MyProxy Gadget"
height="500">
</ModulePrefs>
<Content type="html">
<![CDATA[
Actual code goes here
]]>
</Content>
</Module>
It is also possible to use an iFrame for simplicity. The iframe can be embedded in the CDATA section and point to the HTML file's URL, or you can use a "url" gadget. In this case, change Content's type attribute value from "html" to "url" and provide the URL for the HTML code you want to embed.
Step 1: You will need to use full paths to all imported JavaScript libraries, images, and so on. Relative paths will not work. So for example, you import the CogKit2.js library like so:
<script type="text/javascript" src="https://my.host.com/grid/CogKit2.js"></script>
where my.host.com should be replaced with your Cyberaide deployment server. Note this also applies to the Cyberaide agent server URL. This must be changed from
var url="../agent/services/agent";
to
var url="https://my.host.com/agent/services/agent";
Step 2: You will need to use a modified SOAP JavaScript library, soapclientGadget.js. This replaces soapclient24NSMod.js. This is our modification. The library is available from our SVN repository.
Step 3: Load your gadget in your favorite gadget container. To use iGoogle, create an account and log in if necessary and then click the "Add Stuff" link in the upper right. Assuming you haven't published your gadget yet, click the "Add feed or gadget" link in the lower left side of the page. Type in the full URL to your gadget and submit. That's it.
Tuesday, October 20, 2009
More on JavaScript and Globus GRAM
In the previous post, we looked at how to submit a job using the JavaScript CoG API (a.k.a Cyberaide JavaScript). We'll now look at the remaining parts of the job management API: listing all jobs, checking status of a particular job, listing outputs of a job, and viewing output. We'll just show the JavaScript codes and not the full HTML. The complete example is JobSubGadget.html.
As we saw last time, after a job is submitted, we are returned a job id. We actually treat all jobs as workflows, so this will be colloquially referred to as a wfid in the text. Also as we saw in the last post, all our function calls are accompanied by a callback function. JavaScript is a functional language, so you can pass functions as arguments to other functions. The recipient function then invokes your function.
Listing All Your Jobs
All of your jobs are stored persistently (using a lightweight database and the file system), so you can list all of your jobs' IDs with the function below. The callback function receives a JSON-formatted WFID list, which you can cast directly into a JavaScript variable if you choose.
/*--------------------------------------------------*/
// List jobs
/*--------------------------------------------------*/
function showJobs() {
jscog.listMyWf(listMyWfResponse);
}
//The call back.
function listMyWfResponse(jsonRet){
alert(jsonRet);
}
Checking the Status of a Particular Job
This method returns the status of a particular job as a JSON object. It takes a WFID as input. In the example, we obtain the WFID from the value of an HTML element called "wfid-status". This line of the example is not required.
/*--------------------------------------------------*/
// Check job status
/*--------------------------------------------------*/
function showStatus() {
var wfid=document.getElementById("wfid-status").value;
jscog.statusQuery(wfid,statusQueryResponse,"");
}
//The callback function.
function statusQueryResponse(jsonRet,loc) {
alert(jsonRet);
}
Listing Job Output Files
This function lists the output files associated with a particular WFID. In the previous example, this is the standard output file. Once again the output is JSON-encoded, and the input is obtained from a document element's value (wfid-list in this case). Again, this method for determining the input WFID value is only illustrative.
/*--------------------------------------------------*/
// List job output files
/*--------------------------------------------------*/
function listOutputFiles() {
var wfid=document.getElementById("wfid-list").value;
jscog.listOutput(wfid,listOutputResponse,"");
}
function listOutputResponse(jsonRet) {
alert(jsonRet);
}
Show the Output of a Job
Finally, we can view one of the output files as shown below. The return value is JSON-encoded as before.
/*--------------------------------------------------*/
// Show job output
/*--------------------------------------------------*/
function displayResult() {
var wfid=document.getElementById("wfid-display").value;
var outputfile=document.getElementById("wfid-outputfile").value;
jscog.displayResult(wfid,outputfile,fetchOutputResponse,"");
}
function fetchOutputResponse(jsonRet) {
alert(jsonRet);
}
function fetchOutputResponse(jsonRet,loc) {
alert(jsonRet);
}
As we saw last time, after a job is submitted, we are returned a job id. We actually treat all jobs as workflows, so this will be colloquially referred to as a wfid in the text. Also as we saw in the last post, all our function calls are accompanied by a callback function. JavaScript is a functional language, so you can pass functions as arguments to other functions. The recipient function then invokes your function.
Listing All Your Jobs
All of your jobs are stored persistently (using a lightweight database and the file system), so you can list all of your jobs' IDs with the function below. The callback function receives a JSON-formatted WFID list, which you can cast directly into a JavaScript variable if you choose.
/*--------------------------------------------------*/
// List jobs
/*--------------------------------------------------*/
function showJobs() {
jscog.listMyWf(listMyWfResponse);
}
//The call back.
function listMyWfResponse(jsonRet){
alert(jsonRet);
}
Checking the Status of a Particular Job
This method returns the status of a particular job as a JSON object. It takes a WFID as input. In the example, we obtain the WFID from the value of an HTML element called "wfid-status". This line of the example is not required.
/*--------------------------------------------------*/
// Check job status
/*--------------------------------------------------*/
function showStatus() {
var wfid=document.getElementById("wfid-status").value;
jscog.statusQuery(wfid,statusQueryResponse,"");
}
//The callback function.
function statusQueryResponse(jsonRet,loc) {
alert(jsonRet);
}
Listing Job Output Files
This function lists the output files associated with a particular WFID. In the previous example, this is the standard output file. Once again the output is JSON-encoded, and the input is obtained from a document element's value (wfid-list in this case). Again, this method for determining the input WFID value is only illustrative.
/*--------------------------------------------------*/
// List job output files
/*--------------------------------------------------*/
function listOutputFiles() {
var wfid=document.getElementById("wfid-list").value;
jscog.listOutput(wfid,listOutputResponse,"");
}
function listOutputResponse(jsonRet) {
alert(jsonRet);
}
Show the Output of a Job
Finally, we can view one of the output files as shown below. The return value is JSON-encoded as before.
/*--------------------------------------------------*/
// Show job output
/*--------------------------------------------------*/
function displayResult() {
var wfid=document.getElementById("wfid-display").value;
var outputfile=document.getElementById("wfid-outputfile").value;
jscog.displayResult(wfid,outputfile,fetchOutputResponse,"");
}
function fetchOutputResponse(jsonRet) {
alert(jsonRet);
}
function fetchOutputResponse(jsonRet,loc) {
alert(jsonRet);
}
Monday, October 19, 2009
Submitting a Grid Job with OGCE JavaScript API
In the previous post, we showed how to get a MyProxy credential with the OGCE's Cyberaide JavaScript API. We'll now look at how to submit a simple job. We'll build up a very simple HTML page to do this, but you should note that we have much more appealing clients than this if you want to use something out of the box.
Let's start by building upon our earlier MyProxyGaget.html example. This file is called JobSubGadget.html and is in the client subdirectory of the source code. We will combine the MyProxy form with a Job Submission form to simplify security issues; that is, the user will be presented with a form to get a proxy credential (shown last time) and a form to launch a job. The job launching form only appears after the user successfully authenticates.
To do this, we will start with a little jQuery trick. We'll wrap the two tables in <div> classes called proxyFormClass and jobSubClass and define the following CSS entries:
.proxyFormClass {
}
.jobSubClass{
display: none;
}
Then in the authentication callback function (see previous post), we put the code snippet below:
$('div.jobSubClass').show();
$('div.proxyFormClass').hide();
This will turn off the proxy form fields and turn on the job submission fields.
Now we're ready for the job submission form itself. Here's a very bare bones one:
<div class="jobSubClass" id="jobSub">
Fill in the form below to launch a job.
<table>
<tr>
<td>Command</td>
<td><input name="cmd" type="text" id="cmd" size="50" value="/bin/ls"/></td>
</tr>
<tr>
<td>Arguments</td>
<td><input name="arg" type="text" id="arg" size="50" value="-l"/></td>
</tr>
<tr>
<td>GRAM Host</td>
<td><input name="rHost" type="text" id="rHost" size="50" value="grid-co.ncsa.teragrid.org"/>
</td>
</tr>
<tr>
<td>GridFTP Host</td>
<td><input name="ftpHost" type="text" id="ftpHost" size="50" value="gridftp-co.ncsa.teragrid.org"/>
</td>
</tr>
<tr>
<td>Standard Output</td>
<td><input name="stdout" type="text" id="stdout" size="50" value="junk-ls.out"/>
</td>
</tr>
<tr>
<td>Provider</td>
<td><input name="provider" type="radio" id="gt2" checked>GT2
<input name="provider" type="radio" id="gt4">GT4</td>
</tr>
<tr>
<div name="submitStatus" id="submitStatus"/>
</tr>
</table>
<input name="button1" type="button" class="runButton" id="button1" onclick="submitJob();return false" value="Submit job"/>
</div>
This should look familiar. One important thing to note (besides the little div wrapper) is that we need to provide the hostname for both the GRAM and GridFTP hosts. We need this to both run the job and pull back the output. Not all grid installations (notably the TeraGrid) run both the GRAM and GridFTP server on the same machine (network file systems), so we have to allow for this.
Now let's look at some minimal JavaScript code to invoke the service. The main thing we need to do is collect the submission form's parameters and invoke the service.
function submitJob() {
/* extract job specification */
var cmd = document.getElementById("cmd").value;
var arg = document.getElementById("arg").value;
var rHost = document.getElementById("rHost").value;
var ftpHost=document.getElementById("ftpHost").value;
var stdout = document.getElementById("stdout").value;
var provider = document.getElementsByName("provider");
var prov = null;
if(provider[0].checked){
prov = "GT2";
}
else {
prov = "GT4";
}
/* construct karajan workflow */
var strProj = jscog.constructRemoteJob(cmd, arg, rHost, stdout, ftpHost, stdout, prov);
document.getElementById("submitStatus").innerHTML = "Job Submitting";
loc="";
jscog.submitWf(strProj,submitResponse,loc);
}
Job submission is actually a two step process in the API: first we construct the job's workflow (we use the CoG's Karajan on the backend), and then we submit the constructed workflow script (jscog.submitWf()). We also need to write a callback handler (submitResponse in the submitWf() command) to see if the job was submitted successfully. Here is a really simple one:
/*
* Callback to handle the submission response.
*/
function submitResponse(ret) {
document.getElementById("submitStatus").innerHTML="Your job has been submitted with workflow ticket "+ret;
}
The callback function gets an integer ret back from the server. If submission was successful, then this integer will be the job ticket, which you can use to query status and get back results or error messages.
Let's start by building upon our earlier MyProxyGaget.html example. This file is called JobSubGadget.html and is in the client subdirectory of the source code. We will combine the MyProxy form with a Job Submission form to simplify security issues; that is, the user will be presented with a form to get a proxy credential (shown last time) and a form to launch a job. The job launching form only appears after the user successfully authenticates.
To do this, we will start with a little jQuery trick. We'll wrap the two tables in <div> classes called proxyFormClass and jobSubClass and define the following CSS entries:
.proxyFormClass {
}
.jobSubClass{
display: none;
}
Then in the authentication callback function (see previous post), we put the code snippet below:
$('div.jobSubClass').show();
$('div.proxyFormClass').hide();
This will turn off the proxy form fields and turn on the job submission fields.
Now we're ready for the job submission form itself. Here's a very bare bones one:
<div class="jobSubClass" id="jobSub">
Fill in the form below to launch a job.
<table>
<tr>
<td>Command</td>
<td><input name="cmd" type="text" id="cmd" size="50" value="/bin/ls"/></td>
</tr>
<tr>
<td>Arguments</td>
<td><input name="arg" type="text" id="arg" size="50" value="-l"/></td>
</tr>
<tr>
<td>GRAM Host</td>
<td><input name="rHost" type="text" id="rHost" size="50" value="grid-co.ncsa.teragrid.org"/>
</td>
</tr>
<tr>
<td>GridFTP Host</td>
<td><input name="ftpHost" type="text" id="ftpHost" size="50" value="gridftp-co.ncsa.teragrid.org"/>
</td>
</tr>
<tr>
<td>Standard Output</td>
<td><input name="stdout" type="text" id="stdout" size="50" value="junk-ls.out"/>
</td>
</tr>
<tr>
<td>Provider</td>
<td><input name="provider" type="radio" id="gt2" checked>GT2
<input name="provider" type="radio" id="gt4">GT4</td>
</tr>
<tr>
<div name="submitStatus" id="submitStatus"/>
</tr>
</table>
<input name="button1" type="button" class="runButton" id="button1" onclick="submitJob();return false" value="Submit job"/>
</div>
This should look familiar. One important thing to note (besides the little div wrapper) is that we need to provide the hostname for both the GRAM and GridFTP hosts. We need this to both run the job and pull back the output. Not all grid installations (notably the TeraGrid) run both the GRAM and GridFTP server on the same machine (network file systems), so we have to allow for this.
Now let's look at some minimal JavaScript code to invoke the service. The main thing we need to do is collect the submission form's parameters and invoke the service.
function submitJob() {
/* extract job specification */
var cmd = document.getElementById("cmd").value;
var arg = document.getElementById("arg").value;
var rHost = document.getElementById("rHost").value;
var ftpHost=document.getElementById("ftpHost").value;
var stdout = document.getElementById("stdout").value;
var provider = document.getElementsByName("provider");
var prov = null;
if(provider[0].checked){
prov = "GT2";
}
else {
prov = "GT4";
}
/* construct karajan workflow */
var strProj = jscog.constructRemoteJob(cmd, arg, rHost, stdout, ftpHost, stdout, prov);
document.getElementById("submitStatus").innerHTML = "Job Submitting";
loc="";
jscog.submitWf(strProj,submitResponse,loc);
}
Job submission is actually a two step process in the API: first we construct the job's workflow (we use the CoG's Karajan on the backend), and then we submit the constructed workflow script (jscog.submitWf()). We also need to write a callback handler (submitResponse in the submitWf() command) to see if the job was submitted successfully. Here is a really simple one:
/*
* Callback to handle the submission response.
*/
function submitResponse(ret) {
document.getElementById("submitStatus").innerHTML="Your job has been submitted with workflow ticket "+ret;
}
The callback function gets an integer ret back from the server. If submission was successful, then this integer will be the job ticket, which you can use to query status and get back results or error messages.
Using OGCE's JavaScript API to MyProxy
We are in the process of releasing a JavaScript COG API, Cyberaide, that works with common Grid services like MyProxy, GRAM, and GridFTP. Our goal is to provide a method for embedding these calls into many different frameworks, including non-Java languages and tools such as PHP and Ruby on Rails. We are want to provide tools that can be used to build Open Social gadgets that perform Grid operations.
For a fuller description of the project, see http://cyberaide.org/projects/cyberaide/cyberaide-javascript. To browse or download the working version of the code, see http://code.google.com/p/cyberaide/. The examples (very actively developed) can be built using one command,
mvn clean install
from the cyberaide source's top level directory. Edit the top level pom.xml file's properties first. Use the version of Maven provided in the download. You can also rebuild portions of the system with the command
mvn clean install -f client/pom.xml
where client is one of the project modules. After you build everything, start up Tomcat (use the startup-tomcat.sh convenience script). Point your browser to http://localhost:8080/jsportal.html to see some examples.
To shut down everything, you can use the shutdown scripts (shutdown-tomcat.sh and shutdown-mediator.sh). To see debugging information, check out the log files: agent.log and mediator/mediator.log.
MyProxy API Example
The full example is called "MyProxyGadget.html" and is located in the subdirectory client of the source code. To start, you need a set of HTML input fields as usual:
<table>
<tr>
<div id="authStatus" name="authStatus"/>
</tr>
<tr>
<td>Myproxy Server Host:</td>
<td><input name="host" type="text" id="myproxy.host" size="50" value="myproxy.teragrid.org"/></td>
</tr>
<tr>
<td>Myproxy Server Port:</td>
<td><input name="port" type="text" id="myproxy.port" size="50" value="7512"/></td>
</tr>
<tr>
<td>Myproxy Username:</td>
<td><input name="user" type="text" id="myproxy.user" size="50"/></td>
</tr>
<tr>
<td>Myproxy Passphrase:</td>
<td><input name="password" type="password" id="myproxy.password" size="50"/></td>
</tr>
</table>
<input name="button0" type="button" class="runButton" id="button0" onclick="auth();return false" value="Authenticate"/>
Next, you need to import the COG JavaScript library:
<script type="text/javascript" src="CogKit2.js"/>
Now implement the auth() method from your button's onclick attribute. This should of course be located in a section <script language="javascript" > section.
/* Initialize the JavaScript COG */
var url = "../agent/services/agent";
var jscog = new CogKit2(url);
var authStatus = false;
//Define your auth function here.
function auth(){
//These point to the elements in the table above.
var host = document.getElementById("myproxy.host").value;
var port = document.getElementById("myproxy.port").value;
var user = document.getElementById("myproxy.user").value;
var password = document.getElementById("myproxy.password").value;
//A little window dressing
document.getElementById("authStatus").innerHTML=" Authenticating";
//Now invoke the JS CoG auth method from the imported library.
jscog.auth(host, port, user, password, authResponse);
}
The last argument, authResponse, is a callback function that you can use to determine if authentication was successful or not. A sample implementation is shown below.
/*
* the authenticate callback function
*/
function authResponse(ret) {
if(ret){
authStatus = true;
document.getElementById("authStatus").innerHTML="Authenticated successfully!";
document.getElementsByName("password")[0].value="";
} else{
authStatus = false;
document.getElementById("authStatus").innerHTML="Failed to Authenticate!";
document.getElementsByName("password")[0].value="";
}
}
We'll look at more functions in upcoming posts.
For a fuller description of the project, see http://cyberaide.org/projects/cyberaide/cyberaide-javascript. To browse or download the working version of the code, see http://code.google.com/p/cyberaide/. The examples (very actively developed) can be built using one command,
mvn clean install
from the cyberaide source's top level directory. Edit the top level pom.xml file's properties first. Use the version of Maven provided in the download. You can also rebuild portions of the system with the command
mvn clean install -f client/pom.xml
where client is one of the project modules. After you build everything, start up Tomcat (use the startup-tomcat.sh convenience script). Point your browser to http://localhost:8080/jsportal.html to see some examples.
To shut down everything, you can use the shutdown scripts (shutdown-tomcat.sh and shutdown-mediator.sh). To see debugging information, check out the log files: agent.log and mediator/mediator.log.
MyProxy API Example
The full example is called "MyProxyGadget.html" and is located in the subdirectory client of the source code. To start, you need a set of HTML input fields as usual:
<table>
<tr>
<div id="authStatus" name="authStatus"/>
</tr>
<tr>
<td>Myproxy Server Host:</td>
<td><input name="host" type="text" id="myproxy.host" size="50" value="myproxy.teragrid.org"/></td>
</tr>
<tr>
<td>Myproxy Server Port:</td>
<td><input name="port" type="text" id="myproxy.port" size="50" value="7512"/></td>
</tr>
<tr>
<td>Myproxy Username:</td>
<td><input name="user" type="text" id="myproxy.user" size="50"/></td>
</tr>
<tr>
<td>Myproxy Passphrase:</td>
<td><input name="password" type="password" id="myproxy.password" size="50"/></td>
</tr>
</table>
<input name="button0" type="button" class="runButton" id="button0" onclick="auth();return false" value="Authenticate"/>
Next, you need to import the COG JavaScript library:
<script type="text/javascript" src="CogKit2.js"/>
Now implement the auth() method from your button's onclick attribute. This should of course be located in a section <script language="javascript" > section.
/* Initialize the JavaScript COG */
var url = "../agent/services/agent";
var jscog = new CogKit2(url);
var authStatus = false;
//Define your auth function here.
function auth(){
//These point to the elements in the table above.
var host = document.getElementById("myproxy.host").value;
var port = document.getElementById("myproxy.port").value;
var user = document.getElementById("myproxy.user").value;
var password = document.getElementById("myproxy.password").value;
//A little window dressing
document.getElementById("authStatus").innerHTML=" Authenticating";
//Now invoke the JS CoG auth method from the imported library.
jscog.auth(host, port, user, password, authResponse);
}
The last argument, authResponse, is a callback function that you can use to determine if authentication was successful or not. A sample implementation is shown below.
/*
* the authenticate callback function
*/
function authResponse(ret) {
if(ret){
authStatus = true;
document.getElementById("authStatus").innerHTML="Authenticated successfully!";
document.getElementsByName("password")[0].value="";
} else{
authStatus = false;
document.getElementById("authStatus").innerHTML="Failed to Authenticate!";
document.getElementsByName("password")[0].value="";
}
}
We'll look at more functions in upcoming posts.
Subscribe to:
Posts (Atom)