Introducing SWORD

Student WOrker Relational Database (SWORD) is a student worker database for use in schools with work study programs. It’s the project I’ve been working on for the past 6 months or so.

http://code.google.com/p/student-worker-relational-database/

It’s a great example of leveraging Django to create a full website in very little time (Until recently it was just a side project I worked on occasionally) . I’m releasing it open source to help distribute it for use in other schools. Right now the installation process is a little ugly though. I’ll have to learn how to make Debian  and RPM packages sooner or later. Next steps will be to integrate it with some other programs, possibly Schooltool and  SugarCRM. It’s already working with CAS for Single Sign On. If you know any schools that might be able to use this please comment or email. I may be offering it as a hosted solution soon.

Thoughts on Centrify

Centrify Express is a gratis but not open source client for integrating various platforms (such as Linux and Mac) to active directory. I wrote about Likewise Open before when trying to get Linux on Active Directory with some success. Today I deployed Centrify on a few machines to see if it could fare any better.

Ubuntu 10.04 Server: Centrify worked very well for this. Likewise open has many bugs that annoy me in Ubuntu so that’s what really motivated me to try something new. I ran into a little trouble installing it, but after running apt-get -f install it worked fine. Likewise in Ubuntu has a default domain bug and it also doesn’t seem to like installing on my Proxmox template for some reason. Of course Centrify isn’t (and probably never will be) in Ubuntu’s repositories which make it slightly harder to install.

Ubuntu 10.04 Desktop: Desktop support is always where I get problems in trying to make linux work in Active Directory. The biggest annoyance is getting it to work in a wifi environment. Turn on wireless laptop, new user logs in, authentication failure. It has to do with network-manager not really connecting as soon as you think it would (even if available to all users is checked off). This is what really kills Linux for me in a place where people need to use different computers (ie school). Removing network-manager fixes it somewhat, but I still have issues where I have to wait a few minutes before it allows domain logins. It does at least appear that Centrify works as soon as network is available while likewise seems to just sit for a couple minutes before it works. Centrify however is missing some features that are a great in a company network. Likewise will pass on login information to pam and when connecting to samba shares. Centrify does not (edit, it can be made to work with pam_mount with some work arounds). Also when I log in with GDM in centrify I have to enter the password twice for gnome-keyring to work then again every time I connect to a samba share. There is a “centrified” version of Samba that I wasn’t able to get installed. Likewise just works in this case.

Centrify Pro’s:

  • Less buggy to set up
  • Assumes default domain
  • Mitigates wifi issue at least a little bit

Centrify Con’s

  • Not open source
  • Not in Ubuntu repository
  • Must enter password twice on login for gnome-keyring when using GDM, though there is a work around.
  • Doesn’t pass credentials to Samba shares
  • Little documentation. * edit they do have a pdf manual but they don’t have the forums history likewise does. When I Google Likewise <description of problem> I get results, while with Centrify I really have to hunt.

Once again Linux can integrate well with AD in server land but has issues for end user desktops. Workswithu did a article comparing the two programs too for those interested. Overall Centrify is an acceptable solution, but falls short of a Linux Active Directory integration that “just works.”

Django and Google Maps

Adding a Google Maps address preview to the Django admin interface.

Last post I wrote about extending the Django Admin interface by adding a little dynamic data to the help_text field. For more advanced things you need to customize the html widget itself.

One thing I want to do is have a Django model automatically get a Google Map of the address I have stored and save this file. For my purposes though I don’t want this to be automatic, I’d rather an admin user check the map first then decide to overwrite any previous map file. I’ll extend the a widget to get this effect.

First I need a preview box. I want to insert some extra html, I’m actually going to put this into a checkbox form, you will see why later. I need to override the render def on the widget to add some code.


class MapImageWidget(forms.CheckboxInput):
def render(self, name, value, attrs=None):
output = []
output.append(super(MapImageWidget, self).render(name, value, attrs))
output.append("If checked, the above map file will be overwritten with Google Maps.<table><tr><td><a href=\"javascript:get_map()\">Preview Google Maps</a></td></tr><tr><td> <iframe width=\"400px\" height=\"400px\" name=\"mapframe\"></iframe> </td></tr></table>")

return mark_safe(u''.join(output))

I’m using Google Maps static maps url to get my previews. I made a javascript function called get_map to look up the url based on the address field on my model. I want it to actually use the currently typed in address rather than some ajax solution which may get the currently saved address.


function get_map(){
var address = document.getElementById("id_address").value;
var city = document.getElementById("id_city").value;
var state = document.getElementById("id_state").value;
var zip = document.getElementById("id_zip").value;
parent.mapframe.location="http://maps.google.com/maps/api/staticmap?sensor=false&size=400x400&markers=size:mid|color:red|" + address + "," + city + "," + state + "," + zip;
}

I put the javascript into my change_form.html admin template. This function is only for previewing by the user and has nothing to do with actually saving my map image. For that I have a checkbox as in this screen shot

Maps preview in admin edit page

When the user checks off the box, Django will know to get that image and set it to the map ImageField. I do this by overriding the save function on my model.


def save(self, *args, **kwargs):
if (self.use_google_maps):
self.use_google_maps = False;
image = urllib.urlretrieve("http://maps.google.com/maps/api/staticmap? sensor=false&size=400x400&markers=size:mid|color:red|" + \
self.address + "," + self.city + "," + self.state + "," + self.zip)
self.map.save(self.company_name + "_map.jpg", File(open(image[0])))
super(Company, self).save(*args, **kwargs)

I use urllib to “wget” the file. This process will replace the previous practice of manually looking up maps, saving them, and uploading them. Of course if I trusted Google maps (or my addresses to be correct) I could just have it dynamically get that image when needed instead of storing the image file.

How I use Google Wave (and what I wish it could do)

Google Wave seems like a strange tool at first and has so many use cases it can seem overwhelming. One thing I use it for is as a wiki. To keep organized I first make a main wave that just has links other waves of the same topic. Google Wave makes it easy to just drag and drop links and files (though it’s a little buggy currently). Next I put whatever into the wave say a design specification. Under I can put blips (which are like reply’s in a forum) to discuss the document.

That said there are some shortcomings I hope will be fixed before Google takes it out of beta. I’d love to be able to export the wave blips to other sites. Say I have an official documentation site for some project that I want nice looking information. This information could be the design spec I mentioned but only the first blip so comments and changes could be made in Wave will a nice finished product always exists elsewhere. Currently it does integrate with blogspot, hopefully more will come and it can be used almost as a content management system, this would be really awesome.

Another problem I run into is knowing when a wave is updated. I solve this with firefox/chrome extensions but this isn’t ideal when trying to work with someone else who doesn’t have them and isn’t alerted to when the wave is updated.

Linux and Active Directory

* See my newer post, it’s much better.

Getting Linux to work well with LDAP is a pain. Here is how I set it up to match what one typically finds in a corporate environment, that is Logging in with a domain name and having access to various shares.

Logging in
First is just getting it to login. It’s actually not that hard, I went with using likewise-open which can be installed in Ubuntu via
sudo apt-get install likewise-open
Now to configure we run
sudo domainjoin-cli join yourdomain.yourserver.com Administrator
Now assuming you only use one domain you probably want to make it default.

In 9.10 you need to edit /etc/likewise-open5/lsassd.conf and set “assume-default-domain” to yes

In 10.04 there is a bug that keeps this from working. See https://bugs.launchpad.net/ubuntu/+source/likewise-open/+bug/534629 Basically you need to get a ppa version and then Change AssumeDefaultDomain to dword:00000001 in /etc/likewise-open/lsassd.reg

Now if you reboot you should be able to log in via the domain user.

Shares
Now you need to mount all the shares, perhaps a company wide share and a personal one. Run this
sudo apt-get install libpam_mount
Sadly the Ubuntu packages don’t configure it right. Edit /etc/pam.d/common-session and rearrange to lines near the bottom so it looks like this
session optional pam_mount.so
session sufficient pam_lsass.so

Now it will work. The problem is that pam ignores pam_mount when using the likewise open module by default.
Next /etc/security/pam_mount.conf.xml
You can use variables like %USER to have it mount the user’s personal share. Mine looks like this

<pam_mount>
<!-- Volume definitions -->
<volume user="*" fstype="cifs" server="server" path="users/%(USER)" mountpoint="~/Documents" />

* in 10.04 %(USER) gives you the domain/user.  If you just want the user use %(DOMAIN_USER)

Don’t try mounting anything as Desktop because gnome won’t allow it. Too bad.

Wifi
Likewise open doesn’t work with wifi unless you login as a user first, which seems not to be a solution. It’s because network-manager sucks and doesn’t connect until some user logs in. So you need to not use network-manager. I uninstalled it and setup wifi by editing /etc/network/interfaces. It works well but now I can’t change the wifi myself. Useful if the computer never leaves the building. In my case this is acceptable. I hear wicd is a network-manager replacement that can do this. Didn’t try it myself.

Mass deployment
Next you might want to be deploying it on many computers and not one by one. If you want to mess with the default user setup you could install and run sabayon. It crashes a lot, but its actually really useful. Next you need to change the hostname of every machine. I made this script and put it on crontab @restart.
#!/bin/bash
# If hostname is netbook, assume this is a fresh image that needs setup
hostCurrent=$(/bin/hostname)
hostOld='freshimage'
if [ "$hostCurrent" == "$hostOld" ]
then
# set hostname based on Serial Number
host1=$(/usr/sbin/dmidecode | /bin/grep 'Serial Number: ' | /bin/sed 's/.*: \(.*\)/\1/;q')
host2='linux'
host=$host1$host2
host=$(echo $host | sed 's/ //g')
echo $host
/bin/hostname $host
/bin/echo $host > /etc/hostname
# wait for wifi
sleep 10
# join AD
/usr/bin/domainjoin-cli join domain.server.org Administrator 'mypassword'
fi

It automatically makes up a unique hostname and joins my domain at first boot. I set the cloning image’s hostname to “freshinstall” which the script looks for. Clone the hard drive boot it. Wait for GDM to come up, reboot and your good.  This is actually way better than joining many Windows computers to a domain, which requires many reboots.

Odds and Ends
I still don’t know a great way to mount ~/Desktop
If you must have MS Office you could try wine, but you may need to use Crossover Linux Pro which generally costs a lot. With CX Pro you can set up Office to multiple users.
I’ll write a follow up post on how the deployments go.

Creating a video game

I’m finally putting some real work into making a video game for the Android OS that combines aircraft shooter with some role playing elements. My plan is to have a game where the player goes between typical shooter action and storyline, gaining XP, going to shop for upgrades, ect. The player will have a computer controlled wingmate too that will level up as well. I’ll be building it with the open source sprite engine rokon.

I’m making all the levels read in as xml so anyone can make a level. At some point I’ll release the core game as open source and sell Level packs on the Android Market. Here’s a screenshot

Not much to look at yet. Hopefully my next post will feature a demo video. It actually works but a few bugs make it less than impressive. It really does read level data off an xml file though which is super cool. That means I can write in xml that a certain enemy appears on the level at a certain time.

I’m using Google Wave for all the specifications. If you want to help out let me know, many more details are there.

Hacking the G1

Last Friday I finally decided to root my G1 android phone, probably from envy of the new Droid phone. I must say I’m surprised by how much faster it is now. It’s far more responsive and loading times seems to be vastly improved. Aldiko ebook reader went from taking around 30 seconds to open a certain book to 5. One annoyance I used to have was the home screen freezing for 5 to 10 seconds making multi tasking very annoying. This is now completely gone. I was expecting a slightly faster phone, but this is really like a brand new phone. Wifi tether is always nice too. Here’s what I did.

Rooted it with this guide. A tad many steps involved, but all very easy to follow.
Installed an overclock app from the market.
Partitioned my sd card with a 2GB ext4 and 32MB swap with gparted.
Enabled compcache with the “spare parts” application.
Installed the Cyanogenmod updater from the app market and updated to the latest Cyanogenmod. This neat program makes updates very easy, something I though might be annoying after rooting the phone.

So that’s it. If you have an android phone and don’t mind the slight risk, it’s very much worth rooting your phone.

Django

I mentioned the Django app I made in the previous post so I thought I would provide some info about what it is. Essentially the goal was to reduce duplicate work everywhere possible be moving data from spreadsheets and other database’s into one central database. Also to allow a non skilled worker to edit this data, then allow for reporting to remake all the excel sheets that were originally needed. Here’s my setup

Ubuntu 9.04 server running Django, MySQL, and Apache (LAMD?) Data models are defined in Django which automatically makes an Admin interface with some customization options.

data entry

Django also makes short work of authentication with is done against Active Directory. Reporting is done with PyExcelerator and pyRTF to make downloadable excel and rtf documents.

reporting

It’s a pretty basic database but it really saves a lot of time compared to maintaining lots of xls documents and mail merges. Also it allows a technical worker to import exported data from other database into MySQL. Ideally this program could also be linked with other MySQL backend programs. So say I want to use SugarCRM I could symlink the contacts table so both Sugar and Django use the same one for perfect 2-way syncing. The real beauty of this is that it was so quick to develop. This is just been a side project for me. Doing it in PHP or .NET would have easily taken 3 times as long.