FOURPROC

This blog has been migrated from Posterous to the open web

Today, I moved this blog from Posterous to the open web (ie a cloud server I host at RackSpace). This blog is just a bunch of static pages, images and css. No corporate blogging silo. No database. Many fewer moving parts.

The blog is generated using jekyll and Bootstrap. I will be posting my implementation notes for installation, configuration and content generation for this blog in a few days.

The blog is a bit barebones right now. Comments, RSS feed and tag pages will be available shortly.

I hope you find it useful.

-Brian

PS: I know I that I still use the Posterous for my tripReports blog. I am getting to it, give me a little time.

PSS: I like Posterous and it has served up my sites very nicely over the years. But I want to make sure I own my content and always have access to it, no matter if the company suddenly does not like me or the governments decides to put the company under a takedown order. (I still have not figured out how to make a copy of my original trip reports blog. I made it so secure, I cannot get into and download all the content heheheā€¦. )

.....

Accessing a LabKey Server with Python, Node.js or wget

* Update: Modified and slightly revised version of this post is available on the LabKey Blog in two parts. See Part1 and Part2

As you may or may not know, the LabKey Server has a whole suite of client APIs that can be used to programmatically access data inside your LabKey Server. Like any other open source project, some of these APIs have seen a lot more development than others (see the functionality available in the Javascript API, which is one of the first we developed; compared to our newest API, Python which was written last month by Elizabeth in her spare time).

Periodically, I will need to access data in a LabKey Server in an unsupported language(for example NODE.js or BASH). In these cases, one of the first hurdles that you need to get over is simply authenticating to the server. In this entry, I am going to provide some sample code for how to authenticate to the LabKey Server in a variety of languages (shell script, python and node.js).

How Does Authentication in the LabKey Server work?

LabKey Server uses form-based authentication, by default, for all user-agents (ie browsers). However, it will correctly accept HTTP basic authentication headers if presented. I recommend using Basic Auth when programmatically accessing the server.

Please note that when using either form-based authentication or basic authentication, your credentials are passed in clear text, thus I strongly recommend implementing SSL on your LabKey Server.

Here is a very simplistic example of how Basic Auth works:

  1. You attempt to connect to a web page which requires authentication
  2. The server will respond with an Authorization Required error message (HTTP response code = 401).
  3. In addition, the server will add a new HTTP header to the response. It will be similar toWWW-Authenticate: Basic realm="Default"
  4. If you are using a browser, the browser will then pop-up a dialog box asking you to enter a username and password to gain access.

This is how the LabKey Server works for all the APIs, which are designed to be accessed programmatically.

For all other pages(where the LabKey Server assumes you will accessing via a browser) the LabKey Server will not behave in the way described above but will behave completely different. Here is an example:

  1. You attempt to connect to a web page which requires authentication
  2. The server will respond with an Moved Temporarily error message (HTTP response code = 302).
    • The server does not include the WWW-Authenticate:... header in the response headers
  3. If you are using a browser, the browser be redirected to the LabKey Server login page.
  4. If you are not using a browser, but accessing the server programmatically you simply get this error message

In general, the actions which respond with the WWW-Authenticate:... HTTP Header are

  • All API requests (any page whose names ends with .api)
    • Both POST and GET

All other pages do not respond with the WWW-Authenticate:... HTTP Header, but redirect you to the LabKey Server login page. This includes actions such as

  • Most Admin actions (creating new folders, viewing the Audit Log)
  • Submitting MS2 searches to the server
  • Viewing and managing Wikis
  • Viewing or posting messages to a Message board or Issue tracker.

This is an important point. When accessing the LabKey Server programmatically tools (wget, curl, etc) or programming libraries which handle Basic Auth authentication will work properly when accessing an API, but will not work when accessing any other page on the server.

A very easy way to determine the authentication behavior of page is to make an unauthenticated connection to the web page and review the response HTTP Headers. You can do this using python

import urllib2
try: 
    f = urllib2.urlopen('http://my.labkey.server/labkey/your/page')
    print f.info()
except urllib2.HTTPError, e:
    print e.info()\

or using wget

wget --server-response http://my.labkey.server/labkey/your/page

Let me use an example to illustrate the behavior I explained above. Lets use wget to view a secured wiki page on the server

wget --server-response --max-redirects=0 https://www.labkey.org/wiki/Home/page.view?name=secureWiki

the response is

HTTP request sent, awaiting response... 
  HTTP/1.1 302 Moved Temporarily
  Server: Apache-Coyote/1.1
  Expires: Thu, 01 Jan 1970 00:00:00 GMT
  Cache-Control: no-cache
  Location: /login/Internal/login.view?returnUrl=%wiki%2FHome%page.view%3Fname=secureWiki
  Content-Length: 156
  Date: Wed, 24 Aug 2011 01:01:19 GMT
  Connection: keep-alive
Location: /login/Internal/login.view?returnUrl=%wiki%2FHome%page.view%3Fname=secureWiki [following]

You can see that server:

  1. Does not respond with a WWW-Authenticate:... HTTP Header, but
  2. Redirects the browser to the login page

Now lets look at an attempt to use the getQuery API (which you can use to query data in the LabKey Server).

wget --server-response --max-redirects=0 https://www.labkey.org/query/Internal/getQuery.api

the response is

HTTP request sent, awaiting response... 
  HTTP/1.1 401 Unauthorized
  Server: Apache-Coyote/1.1
  WWW-Authenticate: Basic realm="LabKey Server and CPAS Distribution and Support"
  Content-Type: text/html
  Content-Length: 2871
  Vary: Accept-Encoding
  Date: Wed, 24 Aug 2011 01:05:35 GMT
  Connection: keep-alive

In this example, you can see that the server

  1. Responded with a HTTP response code of 401
  2. Added the WWW-Authenticate: Basic realm="LabKey Server and CPAS Distribution and Support" header which you can then programmatically use to authenticate using Basic Auth.

Now that I have shown you how the LabKey Server will respond to authentication requests, I can provide some examples of how to authenticate to the LabKey Server using various programming languages. Before we get to the examples, here are few links to documentation for programmatically accessing a LabKey Server and using the LabKey APIs

In the examples below, you will see two URLs used; one is meant to represent viewing a secured wiki page and the other is for reading the contents of a list. The URLs are:


Authenticating to LabKey Server using Python

LabKey currently ships a client PYTHON client API. The PYTHON client api currently supports (as of 01/01/2012):

  • reading data inside LabKey Server (selectRows)
  • inserting new data inside LabKey Server (insertRows)
  • deleting existing data inside LabKey Server (deleteRows)
  • updating data inside LabKey Server (updateRows)
  • executing SQL statements (executeSql)
  • updating a wiki page
  • posting a message to a message board

The client API will handle the authentication for you. If there are other tasks you need to perform, you can use the example code below to authenticate to the server

Authenticate to an API page

In this example, I will use the urllib2 library. I will load my creadentials into the a password manager and then let the OpenerDirector object handle passing the Basic Auth headers to the server when requested.

import urllib2
myemail = 'email'
mypassword = 'password'

# Create a password manager
passmanager = urllib2.HTTPPasswordMgrWithDefaultRealm()

# Add login info to the password manager
passmanager.add_password(None, mymachine, myemail, mypassword)

# Create the AuthHandler
authhandler = urllib2.HTTPBasicAuthHandler(passmanager)

# Create opener
opener = urllib2.build_opener(authhandler)

# Build the URL for querying LabKey Server (Replace SCHEMA, QUERY with the schema name and query name of your choice)
myurl = ' https://your.labkey.server/labkey/query/Home/getQuery.api?schemaName=lists&query.queryName=listName'     
# Get authenticated to send URL requests
opener =_create_opener()

# Use the opener to fetch a URL request
myrequest = urllib2.Request(myurl)
try:
    response = opener.open(myrequest)
    print response.read()
except urllib2.HTTPError, e:
    print e.code
    print e.read()

Authenticate to an non API page

In this example, I will load my creadentials into the a password manager and in addition add the Basic Auth Header to all requests using the OpenerDirector object.

import urllib2
myemail = 'email'
mypassword = 'password'

# Create a password manager
passmanager = urllib2.HTTPPasswordMgrWithDefaultRealm()

# Add login info to the password manager
passmanager.add_password(None, mymachine, myemail, mypassword)

# Create the AuthHandler
authhandler = urllib2.HTTPBasicAuthHandler(passmanager)

# Create the Basic Authentication Header
authHeader = base64.encodestring("%s:%s" % (myemail, mypassword))[:-1]
authHeader = "Basic %s" % authHeader

# Create opener
opener = urllib2.build_opener(authhandler)

# Build the URL for viewing a secured wiki on LabKey Server
myurl = 'https://your.labkey.server/labkey/wiki/Home/page.view?name=securedWiki'     
# Get authenticated to send URL requests
opener =_create_opener()

# Use the opener to fetch a URL request
myrequest = urllib2.Request(myurl)
try:
    response = opener.open(myrequest)
    print response.read()
except urllib2.HTTPError, e:
    print e.code
    print e.read()

NOTE: If you want to use only one opener for both API and non-API pages, you simply can use the 2nd example for accessing all pages.


Authenicating to LabKey Server with Node.js

There is currently not a client API for the Node.js language yet. (If you are using Node.js to work with data in your LabKey Server and want to assist in writing an client API, please post a message to the Developer Community Forum as we would love to work with you.)

As we saw above, with Python, there are two ways to authenticate. For API pages, the OpenerDirector object handles chaining of requests together and will properly resubmit a request if it receives a 401 HTTP response code with theWWW Authenicate: header. There is not something similar for NODE.js and thus there is only one way to authenticate to the server.

NOTE: Full disclosure, I am a Node.js novice, there are probably many better ways to do this. If you know a much better, simpler way, please post it in the comments and I will update this example.

https = require("https");

var email = 'myemail';
var password = 'mypassword';
var auth = 'Basic ' + new Buffer(email + ':' + password).toString('base64');


var authHeaders = {
    Authorization: auth
};

var addUserURL = {
  host: 'your.labkey.server',
  port: 443,
  path: ' /labkey/wiki/Home/page.view?name=securedWiki',
  method: 'GET',
  headers: authHeaders  
};

var request = https.request(addUserURL, function(response) {
  response.setEncoding('utf8');
  responseData = '';
  response.on('data', function (chunk) {  
      responseData += chunk;
  });
  response.on('error', function(e){
      console.log("An error occurred during the request.")
      console.log('HTTP Response Code: ' + response.statusCode);
      console.log('HTTP Response Headers: ' +r esponse.headers);
      return;
  });
  response.on('end', function(){
      console.log("Response Output: " + responseData)
      console.log('HTTP Response Code: ' + response.statusCode);
      console.log('HTTP Response Headers: ' + response.headers);
  });
});

request.end();

Authenticating to the LabKey Server using wget

Now, if you do not want to bother with these programming languages and just want to grab a page quickly or download some data and parse it with sed, you can just use wget. (To be completely honest, I use wget all the time for testing and/or grabbing a single page).

Authenticating to an API page.

This case is pretty simple one liner

wget --server-response --http-user=myEmail --http-password=myPassword \
 "https://your.labkey.server/labkey/query/Home/getQuery.api?schemaName=lists&query.queryName=listName"

Authenticating to a non-API page.

For this case, you will need to make two wget requests. The first to login and the 2nd to access the secured page.

wget --server-response --save-cookies cookies.cpas --keep-session-cookies \
https://your.labkey.server/Login/login.post --post-data "email=myEmail&password=myPassword"

wget --load-cookies cookies.cpas https://your.labkey.server/labkey/wiki/Home/page.view?name=securedWiki

Now that you have gotten past the authentication, you can start doing all sorts of fun things with your data.

There are a few other languages that I have used in the past, namely perl, that I should have included in these examples. I will try and get to those in a later post(s). (If you are using perl, see the Perl Client API for an example)

I hope this is helpful and understandable. If you have any questions, please post a comment or post a message to the Developer Community Forum

.....

Deploying your Application to the Cloud talk from Cascadia IT Conference

I have attached the slide deck from the talk at the Cascadia IT 2011 Conference.


(download)

For those of you that came to the talk, thank you for taking the time to stop and give me some support and I hope you found the talk informative and entertaining. 

.....

Giving a talk at Cascadia IT Conference

I will be giving a talk at the Cascadia IT Conference here in Seattle. The conference is scheduled for Friday and Saturday, March 11th and 12th. My talk is


Deploying your Application to Cloud: Lessons Learned from Five Different Applications.
Over the past 2 years, I have been asked to migrate 5 different applications "to the cloud".  Three of the five applications were successfully migrated. For the other two applications, the migration to the cloud did not make sense for either performance or financial reasons. In this talk, I will review the types of clouds that are available. Discuss how to evaluate if an application is "ready for the cloud" and guidelines for how to move an application from your datacenter or traditional hosting company to the cloud. Then using each of the five applications as examples, I will discuss why there successfully migrated or not and the technical lessons learned during each migration.
(NOTE: The example applications in this talk cover migrations to Amazon Web Services (EC2, S3, etc) and Rackspace's Cloud.)

 


The talk is scheduled for 4:30 -> 5pm on Saturday. You can see the other talks scheduled for Saturday at http://www.casitconf.org/casitconf11/Tech_track_1.html and http://www.casitconf.org/casitconf11/Tech_track_2.html.  

The conference looks pretty interesting. If you haven't looked into it yet, please do. Registration is still open and you can follow @casitconf for more information. 

.....

Redirect all requests to a maintenance/site-down page using NGINX

Last week I rolled out a new web application for a customer of mine. This application is configured in a warm-standby failover configuration. However, in the case of a failure, the customer wanted the application to failover to a static webpage (in a future post I will go over the monitoring implementation). The reason for doing this, was the customer’s staff wanted to review the cause of the failure before deciding to redirect all traffic to the warm-standby server. At this time, the application did not require 99.99% uptime or even 99.9% uptime, so this is a fine plan.

The static “site is down” webpage is running in a separate server from web application (in a different datacenter). In the case of a failure, the IP address of the server hosting the web application would be moved to this server. The server is running nginx for as the HTTP/HTTPS server.

The nginx configuration was very vanilla, except that had to

  1. For all incoming requests, no matter the URL, return a simple static page and all associated images and css files.
  2. The URL in the browser should not be re-written.
    • This allows the user to refresh the page and return to the same place in the application as they were before the failure.

This was handled using the nginx rewrite module. I used the following configuration

server {
    listen   80;
    location / {
        root   /var/www/default;
        index  index.html index.htm;
        rewrite ^(.*)$ /sitedown/ last;
    }
    location /sitedown {
        root   /var/www/sitedown;
        index  index.html index.htm;
    }
    ...
    ...
}

The webpage and any required css,js or image files will need to be placed in the /var/www/sitedown/sitedown directory. The src attribute for any image, css or js file will need to be prefaced with /sitedown. For example, if the image filename is maintenance.jpg and it is located in the /var/www/sitedown/sitedown directory, then the image tag should look like

<img src="/sitedown/maintenance.jpg">

.....