Monday, October 29, 2007

Getting started with Ruby on Ubuntu 7.10

 

Update 20100922: Apparently this article is so out of date that I even get e-mail to get this article down (or replace it).

Therefore: please do not use this article, in fact don't even rely on the Ubuntu packages as they are not all maintained properly.

One approach that may be fine (I did not try, don't blame me), is on http://krainboltgreene.github.com/l/3/. Good luck!

 

 

So now I have a new server, and a new 10Mbit/s internet connection. Its time for some applications! Here are my experiences with installing Rails, Radiant and Camping on a fresh Ubuntu 7.10 server installation.

First of all, if your server is running in a closet somewhere (like mine) or worse: in a remote data center, you need to disable apt-get asking for the installation CD. Edit /etc/apt/sources.list and comment the line that refers to the installation cdrom.

The next step of course it to install Ruby and Ruby Gems: sudo apt-get install ruby rubygems ruby1.8-dev Without the ruby1.8-dev you can not do much, don't forget it!

Where would you be without irb? The default install however does not link it! sudo ln -s /usr/bin/irb1.8 /usr/bin/irb

Any serious Ruby web application uses Mongrel. However, Mongrel compiles some of its stuff during the install. So you first need to get the compilation tools:
sudo apt-get install make gcc libc6

Mongrel is a trusted enterprise application nowadays, so you can install it with a certificate:

wget http://rubyforge.org/frs/download.php/25325/mongrel-public_cert.pem
gem cert --add mongrel-public_cert.pem
rm mongrel-public_cert.pem
gem install mongrel --include-dependencies -P HighSecurity
Select the highest version followed by (ruby).

Luckily, installing Rails is still a simple: sudo gem install rails --include-dependencies

If you want Camping, you'll first need to install sqlite: sudo apt-get install libsqlite3 libsqlite3-dev

Now you can:

sudo gem install camping --source http://code.whytheluckystiff.net
sudo gem install camping-omnibus --source http://code.whytheluckystiff.net

Radiant is a simple: sudo gem install radiant

For some reason the gem executables do not get added to the path. Make sure they do by adding /var/lib/gems/1.8/bin to your path. For example by adding the following line at the end of /etc/bash.bashrc: export PATH="$PATH:/var/lib/gems/1.8/bin".

The favorite database amongst Railers is of course MySQL. I assume you selected LAMP during the Ubuntu server installation, that means you already have MySQL installed. To use MySQL with ActiveRecord, its best to install the MySQL native adapter. Before you can install that, you first need to install all the compile stuff from above and some more: sudo apt-get install libmysqlclient15-dev sudo gem install mysql Again, for the gem select highest version number followed by (ruby).

Have fun!

Wednesday, October 24, 2007

How to really test RAM, or My search for system stability

I recently bought a Mac because my previous system kept crashing. It would just beep, and reboot without a visible cause. Since I still wanted to use the old system for my Linux firewall, I needed to find out what the culprit was.

Over time I found out that:
- Reboots started intermittently after placing new memory. However, Memtest86 reported no problems whatsoever.
- Over time the reboots occurred more and more often.
- The problem occurred more often during heavy disk activity, sometimes after only 2 minutes. I could not even finish a long Cygwin install session.
- According to SpeedFan my processor heated up quite a bit (up to 65ºC), after putting a bit of heat sink paste between the CPU and the heat sink, that problem was solved.
- The same SpeedFan reported that my harddisk went to high temperatures as well, reaching 50ºC but still rising when the system went down. Some searches taught me that this is high but acceptable. A full copy of the harddisk (as a USB drive) did not give any problems.
- Replacing the power unit did not help.

When I had moved everything to another motherboard an interesting thing happened: once, just once out of many reboots I got a memory failure. Got you!

I finally was able to pin the wrong RAM module using an old memory test from Doug Ledford.

Since the shown script can not be used as is, here is what I did to make it work on Ubuntu 7.10:
- Download a Linux kernel from kernel.org (we are not going to compile a kernel, we just need a large zip file): wget http://kernel.org/pub/linux/kernel/v2.6/linux-2.6.23.1.tar.bz2
- Transform it to a gzipped tar:
bunzip2 linux-2.6.23.1.tar.bz2
gzip linux-2.6.23.1.tar
cp linux-2.6.23.1.tar.gz /tmp

- Download the adapted memtest.sh. My changes auto-detects files named linux-*.tar.gz, and uses the file name to predict the name of the root folder in the tar.
- One by one place a memory module in your computer and run memtest.sh for each configuration.

The original memtest.sh site has more information on how the script works and why Memtest86 is actually useless. The point is that a modern CPU can not put enough load on your memory. With concurrent DMA transfers more errors are detected.

Tuesday, October 23, 2007

Help! Looking for a Java LDAP client library!

I often read that Java is very mature and that you can find Java libraries for everything. Wrong!

At least 5 complete working days I have spend investigating how to implement the LDAP synchronization protocol as supported by the OpenLdap server (RFC4533) in our Java product. Here are the libraries I investigated. None of them support RFC455 out of the box.

JNDI
Sun's implementation is alright for most things, and now that the JVM is being open sourced, you can actually see the com.sun classes you need to program with (BerEncoder and BerDecoder) for new LDAP controls. Unfortunately, JNDI is not actively developed anymore. As far as I can see the required LDAP Intermediate Response Messages (RFC4511, the most recent definition of LDAP) is not supported. No idea on how to add this to JNDI either.

OpenDS
Another Sun initiative, the open source directory server. The code shows support for the LDAP Intermediate Response Message however, all code is written from a server perspective. I did not see how this code could be used in a client.

ApacheDS
The code of this directory server has clearly separated code that could be used by both client and server. However, again, no support for the Intermediate Response Message.

JLDAP
I could not download the sources as our firewall does not allow CVS to go through. I'll investigate later. I doubt that Intermediate Response Messages are supported as there is not much development going on here. I think Novel's resources are all tied to their newer products.

So, still no go. What should I do? Any synchronization supported by OpenLdap will do. Help!

Update 2007-10-23: It seems that JLDAP has support for Intermediate Response Messages after all! Meanwhile a friendly colleague at another location has downloaded the code for me.

Wednesday, October 10, 2007

Announcement: Version 99 Does Not Exist

Last update: 2011-12-19

Update 2011-08-15: DNS for Version 99 is offline.

In a previous post I announced no-commons-logging (a.k.a. commons-logging version 99.0-does-not-exist). After a request to add no-commons-logging-api I immediately realized that this can be generalized. So here it is: Version 99 Does Not Exist.

Features
Version 99 Does Not Exist emulates a Maven 2 repository and serves empty jars for any valid package that has version number 99.0-does-not-exist. It also generates poms, metadata files and of course the appropriate hashes.

For example the following links will give an empty jar, its pom and the maven metadata for commons-logging.

Why?
To get rid of dependencies that maven 2 insists on including on your classpath (like commons-logging while you want to use jcl-over-slf4j).

How do you use it?
First of all: if you were using no-commons-logging before, you do not need to change anything! Version 99 Does Not Exist is fully backward compatible with no-commons-logging. Otherwise, read on.

In your pom.xml declare the following 2 things: 1) the Version 99 Does Not Exist repository, and 2) for each jar that you get but do not want, declare a dependency with version 99.0-does-not-exist.

So, for example, if you do not want to be bothered with commons-logging, include the following in your pom.xml:

<repositories>
    <repository>
        <id>Version99</id>
        <name>Version 99 Does Not Exist Maven repository</name>
        <layout>default</layout>
        <url>http://no-commons-logging.zapto.org/mvn2</url>
    </repository>
</repositories>
<dependencies>
    <!-- get empty jar instead of commons-logging -->
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>99.0-does-not-exist</version>
    </dependency>
</dependencies>
When? Right now. As I received questions on how stable this service will be, I hereby promise to keep this maven repository on-line for at least 5 years (or until no-ip stops offering their free dns service). Read further if you want to run Version 99 Does Not Exist yourself.

How?
Version 99 Does Not Exist is implemented in a single file as a Camping application.

Where is the code?
If you want to run it yourself you'll need the following: Version 99 Does Not Exist download (rb file, 4Kb, MIT license), Ruby, Ruby Gems and Camping. Version 99 Does Not Exist is started with a simple camping version99.rb. Good camping!

Update 2007-11-06: The empty jar is no longer completely empty as 'mvn site' fails on it. Thanks to Stefan Fußenegger for the report.

Update 2007-12-14: The repository was off line for a day or so because I goofed while switching internet provider. Now, it is not only working again, but reachability is better then ever: 10 Mbit/s up and down!

Update 2008-02-09: Version 1.2: another update to the empty jar. Sasha Ovsankin reported that the compiler could not open it. The jar now contains a valid manifest. Thanks Sacha!

Update 2009-05-01: During my move from Amsterdam to Haarlem the server has been off line for a day or so. I am now on ADSL so my internet connection is a lot slower. If anyone want to run a mirror, I am happy to set up a rotating DNS.

Update 2009-07-24: Version 1.3: artifacts with a groupid that contain a dot are now supported. Éric Vigeant, thanks for the bug report!

Update 2009-10-17: Version 2.0: Éric Vigeant's problems were still not over. Now removed metadata support, this will hopefully make some proxies behave better.

Update 2011-08-15: DNS for Version 99 is offline.

Update 2011-12-19: I just found an alternative with almost the same name: version99.qos.ch. It is a static maven repository with a limited number of version 99 jars.

Monday, October 8, 2007

Watch where you place those Camping constants!

Finally got that bastard Camping application to work properly. I kept getting a ERROR: wrong number of arguments (0 for 3) on the first request. Subsequent requests would sometimes succeed, sometimes not. The funny thing was, the get method was not even called yet!

With deep gratitude for ruby guru Remco van 't Veer who found out that you can not use constants in a Camping Controller (actually, I already knew it from a previous camping app, but I had stupidly forgotten it). Move it up to the main module and you're good to go.

Wrong

Camping.goes :Nowhere module Nowhere module Controllers MY_CONSTANT = 'wrong' # Camping going nowhere end end

Correct
Camping.goes :ForPresident module ForPresident MY_CONSTANT = 'fine' module Controllers end end

See my next post to see what this is all about.

Monday, October 1, 2007

Camping: optional group in regular expression

Recently I finished a Camping application where I wanted to handle URIs with an optional part. Like so:
class Jar < R '/(.*)\.jar(\.sha1|\.md5)?' def get(jarname, hash) # does not work ... end end
Unfortunately this does not work. (Does this look familiar? See my next post!) In the end it turned out to be as simple as:
class Jar < R '/(.*)\.jar(\.sha1|\.md5)?' def get(jarname, hash = nil) ... end end
At RailsconfEurope Manfred taught me another trick:
n = 4 class DigitParty < R "/" + ("(\\d)?" * n) def get(*args) args.length # -> 4 args[0] # -> first digit or nil args[n - 1] # -> last digit or nil end end
This matches anything from 0 to n digits where a group is created for each digit. Using * in the parameter list will make method get work for any value of n. For URI's with less then n digits, the corresponding array elements are nil.