Sunday, March 18, 2012

OpenShift test drive

I'm looking for an all-in-one PaaS solution. Currently, my little Android app hosts its data on AWS SimpleDB (I need to swap this out with something relational) and uses GAE for authentication services. While it's been interesting to use these systems, I'd like a single solution.

OpenShift had a booth at PyCon 2012 plus they were handing out free tee shirts. Sold! The only code I'm interested in right now is Java and Python which they of course support (among others). OpenShift also comes with MySQL and MongoDB. I don't believe OpenShift is in production status so I don't know what the pricing structure will be. Whatever it is, I'm sure I'll stay firmly in the 'free' range just as with AWS and GAE. Maybe one day I'll code something that does real volume and I'll have to pay! ;-)

Getting started was a snap. Their control panel UI is still pretty new and can use some polish but OpenShift is very straightforward so it wasn't confusing. git does all the heavy lifting in terms of deploying code, at least for an Express app. They provide a very nice Django example which was much appreciated and worked out of the box. I'm interested in checking out Tornado which is easily stood up in OpenShift. I use the requests module all the time (requests is a urllib2 replacement) and bringing it into my OpenShift app took like 10 characters of typing. I can even ssh to my virtual app, write to the filesystem and fire up daemons at will!

I'm leaning towards porting my Android app to run on OpenShift. If I don't, I'm sure I'll find something else to use it for (probably something for my graduate studies). Check it out.

UPDATE 5/5/12: I used OpenShift to host my semester project for a grad school class I'm taking.  It's available (for now, probably not forever) at http://tornado-ryancutter.rhcloud.com/.  The app attempts to process large amounts of Google+ content and rank attached links intelligently.

The only issue I had with OpenShift was a lack of support for python multiprocessing.  The issue is documented here.  When I discovered the problem, I hopped on IRC and was able to immediately talk to an OpenShift rep (on a Saturday, no less).  Talk about customer service!  Hopefully it'll be fixed one day.  I was able to use python threading to do what I needed to do but I can see how this would be a showstopper for some people.

Overall, very impressed with OpenShift.

Friday, March 2, 2012

Running Jython apps using HBase

Jython is a great tool to have in your arsenal - currently using it for prototyping but it could do much more I'm sure. After yum installing jython onto a Centos 6 machine (not recommended as much newer versions exist), I used this great writeup to set up Jython and HBase:

$ export HBASE_HOME=/usr/bin/hbase
$ export JYTHON_HOME=/usr/bin/jython
$ export CLASSPATH=`$HBASE_HOME classpath`
$ alias pyhbase='HBASE_OPTS="-Dpython.path=$JYTHON_HOME" HBASE_CLASSPATH=/usr/share/java/jython.jar $HBASE_HOME org.python.util.jython'
$ pyhbase
Jython 2.2.1 on java1.6.0_30
>>> from org.apache.hadoop.hbase.client import HTable
>>>

Once the environment is set up, you can write an app. Let's say you have a table called 'test' with a column family named 'stuff' and column named 'value'.

import java.lang
from org.apache.hadoop.hbase import HBaseConfiguration, HTableDescriptor, HColumnDescriptor, HConstants
from org.apache.hadoop.hbase.client import HBaseAdmin, HTable, Get
from org.apache.hadoop.hbase.util import Bytes

conf = HBaseConfiguration()
admin = HBaseAdmin(conf)

tablename = "test"
table = HTable(conf, tablename)

row = 'some_row_key'
g = Get(Bytes.toBytes(row))
res = table.get(g)

val = res.getValue(Bytes.toBytes('stuff'), Bytes.toBytes('value'))

print Bytes.toString(val, 0, len(val))

The only weird behavior I couldn't explain is the need to overload that last Bytes.toString() call. I posted a question on StackOverflow but didn't get any great feedback. I'm thinking it's something in Jython maybe(?).

Wednesday, January 25, 2012

Setting up Duplicity with GnuPG

Really enjoy the functionality of Duplicity. On CentOS:

sudo yum install duplicity

If you get "No package duplicity available.", you need to install EPEL. For CentOS 6:

sudo rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-5.noarch.rpm

Then try yum again.

To make a key using GnuPG:

gpg --gen-key

The defaults are fine. When the key is complete, make sure you copy down the key (made bold) because you'll pass it to duplicity:

gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
pub 2048R/12345678 2012-01-26
.....

You might need to export the key if another user will use it. In my case, I had to create the keys with one user but another user would execute the backups.

gpg --output secret --export-secret-keys
gpg --output public --export

Then the other user needs to:

gpg --import /path/to/secret
gpg --import /path/to/public

You can verify the keys are there by:

gpg --list-keys

If when using the key you get these errors:

gpg: : There is no assurance this key belongs to the named user
gpg: [stdin]: sign+encrypt failed: Unusable public key

You should (as the user experiencing this error):

gpg --edit-key [key]
> trust
// decide how much to trust it
> save

Now to actually use duplicity, it'll most likely be cron'd so a shell script would work nice. I like the way Justin Hartman did it so there's really no need to re-invent what he did. Just ignore the AWS stuff if you're not backing up there.

Saturday, January 7, 2012

Issues with new NIC on Centos 6.0 server

A Dell Poweredge went down with an E1410 error which I couldn't clear. The Motherboard/NIC had to be replaced. This resolved the error but brought about an annoying networking situation.

I really like this nixCraft Howto for Red Hat simple networking issues. After putting the new MAC address on the HWADDR line in /etc/sysconfig/network-scripts/ifcfg-eth0 and ifcfg-eth1 (just added 1 to eth0's MAC addr), I ran "/etc/init.d/network restart" expecting everything to come up. No such luck - got Fatal "Device eth0 does not seem to be present" errors. Verified the MAC address, swapped the addresses between eth0 and eth1, restarted the server, no joy.

Eventually someone smarter than me to me to look at eth2 and eth3. Turns out the NIC card was binding to eth3. To resolve this, I commented out the HWADDR line in ifcfg-eth0 and ifcfg-eth1 and restarted the server. Running "ifconfig eth0" showed the NIC now attached to eth0. I wanted this to always be the case so now I uncommented the HWADDR line in ifcfg-eth0 and ifcfg-eth1 and restarted again. I probably could have just restarted network not the server and got the same results but everything was good.

Tuesday, October 18, 2011

Parallels config - CentOS Server 5.0 (guest) on Mac OS X (host)

Not much documentation on getting CentOS Server 5.0 to work as a guest OS on Mac OS X so here's some gouge:

Installing Parallels Tools:
  • To enable networking, be in "Shared Network" and run "/sbin/dhclient eth0".
  • Mount the CDROM: "mount /dev/cdrom /mnt/cdrom". You might need to create /mnt/cdrom directory.
  • Install the prereqs: "yum install gcc kernel-devel".
  • The kernel and kernel-devel package must be exactly the same. To check this, run "uname -a ; rpm -qa kernel\* | sort". For me, this returns 2.6.18-274.3.1.e15 for kernel, kernel-devel, and kernel-headers (don't think headers are required but not sure). If you need to update the kernel, "yum install kernel" and reboot.
  • /mnt/cdrom/install should work
  • Once installed, my Mac OS X home directory was available at /media/psf/Home.

Friday, June 24, 2011

Remote backup of SimpleDB domains

So Amazon Web Services is pretty good but they're still lacking some of the small stuff. I'd like to see automated usage reports, warnings about suspicious traffic surges, and better backup options. I really don't understand why they don't assign a few dudes to build these things out because I know people have been begging for them for years.

Anyway, I coded a really simple Python script that will back up my domains. In no way is this a scalable solution - if you have a couple million items in your database, this is likely not a cost effective option. I've got less than a thousand entries today and I'm adding only a few hundred per week. It's hosted on WebFaction, which is a great hosting company - for only a few bucks per month you get access to your own very capable virtual server (no more mooching off friends or using inferior free services). It also uses boto, which is a very mature Python library for all things AWS. I've added it to my crontab to run a few days per week and it sends me an email when it's done. Of course, all usernames, passwords, email addresses removed. So here it is:

#! /usr/bin/env python2.7

from boto.sdb.connection import SDBConnection
from datetime import date
from smtplib import SMTP
from email.mime.text import MIMEText
import os
import settings

conn = SDBConnection('access_key','secret_key')

# backup account domain
account_filename = 'backup/account-' + date.today().isoformat() + '.xml'
f = open(account_filename, 'w')
domain = conn.get_domain("account")
domain.to_xml(f)
f.close()
account_size = os.stat(account_filename)

# backup timelog domain
timelog_filename = 'backup/timelog-' + date.today().isoformat() + '.xml'
f = open(timelog_filename, 'w')
domain = conn.get_domain("timelog")
domain.to_xml(f)
f.close()
timelog_size = os.stat(timelog_filename)

msg = MIMEText("wrote " + account_filename + " (" + str(account_size.st_size) + " bytes)\nwrote " + timelog_filename + " (" + str(timelog_size.st_size) + " bytpes)")
msg['Subject'] = 'Payroll Nanny backup report for ' + date.today().isoformat()
msg['From'] = 'my_app_address'
msg['To'] = 'my_email_address'

s = SMTP()
s.connect('smtp.webfaction.com')
s.login('my_webfaction_username', 'my_webfaction_password')
s.sendmail('my_app_address', 'my_email_address', msg.as_string())
s.quit()

Wednesday, June 22, 2011

Android Market observations

It's been a few weeks since my last post - I've been super busy launching my first app on Android Market. The prototype was built a couple months ago and it's mature enough to be released into the wild. Homepage here and Android Market entry here.

Anyway, the work necessary to get my app on Android Market was suprisingly minimal. Here are some general observations:

  • Google does a great job tying into Eclipse: You can code with any IDE you want but for my money, I have to use Eclipse because it works so seemlessly with Google stuff. Even signing the app is simple.


  • Be very distrustful about network connections: I've been using my app for a couple months and never got presented with a "Force Close" (a crash). However, some of the errors being logged are the result of devices dropping network connection and my code was not catching these conditions sufficiently. I'm pushing an update this week which catches these exceptions, presents an alert dialog that states the network isn't working, and takes the user to a safe activity.


  • Be careful about security: There as a good article this week warning users of Amazon Web Services (which I am one) to get better with protecting credentials. I spent a good amount of time developing authentication middleware and don't use the VMs this article focuses on but it scared me enough to take a closer look at how I use IAM. I'm rolling credentials more, beefing up my personal password security, and paying more attention to my server logs.


  • Testing is hard: I got caught not checking for some basic weird user behavior, like putting spaces in usernames then putting that string in a GET request. Now that I have a bunch of users, I'm fixing these shortcomings.


  • Android Market exhibits some weird behavior for publishers: When trying to push my update, I was presented with "An unexpected error occurred. Please try again later." after clicking the "Upload" button. It seems like this is a catch-all error message that the Market displays whenever there's a problem. Back in April 2011, some servers were down and this was getting displayed all the time. I finally resolved it by logging out of Android Market and back in.