Masterzen’s Blog

Journey in a software world…

Archive for the ‘Java’ Category

Puppet and JRuby a love story!

As announced in my last edit of my yesterday post Puppet and JRuby a love and hate story, I finally managed to run a webrick puppetmaster under JRuby with a MRI client connecting and fetching it’s config.

The Recipe

Puppet side

Unfortunately Puppet creates its first certificate with a serial number of 0, which JRuby-OpenSSL finds invalid (in fact that’s Bouncy Castle JCE Provider). So the first thing is to check if you already have some certificate generated with a serial of 0. If you have none, then everything is great you can skip this.

You can see a certificate content with openssl:


% openssl x509 -text -in /path/to/my/puppet/ssl/ca/ca_cert.pem

Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha1WithRSAEncryption
Issuer: CN=ca
Validity
Not Before: May 23 18:38:19 2009 GMT
Not After : May 22 18:38:19 2014 GMT
Subject: CN=ca
...

If no certificate has a serial of 0, then it’s OK, otherwise I’m afraid you’ll have to start the PKI from scratch (which means rm -rf $vardir/ssl and authenticate clients again), after applying the following Puppet patch:


JRuby fix: make sure certificate serial > 0

JRuby OpenSSL implementation is more strict than real ruby one and
requires certificate serial number to be strictly positive.

Signed-off-by: Brice Figureau <brice-puppet@daysofwonder.com>

diff --git a/lib/puppet/ssl/certificate_authority.rb b/lib/puppet/ssl/certificate_authority.rb
index 08feff0..4a7d461 100644
--- a/lib/puppet/ssl/certificate_authority.rb
+++ b/lib/puppet/ssl/certificate_authority.rb
@@ -184,7 +184,7 @@ class Puppet::SSL::CertificateAuthority
# it, but with a mode we can't actually read in some cases.  So, use
# a default before the lock.
unless FileTest.exist?(Puppet[:serial])
-            serial = 0x0
+            serial = 0x1
end

Puppet.settings.readwritelock(:serial) { |f|

I’ll post this patch to puppet-dev soon, so I hope it’ll eventually get merged soon in mainline.

JRuby

You need the freshest JRuby available at this time. My test were conducted with latest JRuby as of commit “3aadd8a”. The best is to clone the github jruby repository, and build it (it requires of course a JDK and Ant, but that’s pretty much all).

Then install jruby in your path (if you need assistance for this, I’m not sure this blog post is for you :-) )

JRuby-OpenSSL

As I explained in my previous blog post about the same subject, Puppet exercises a lot the Ruby OpenSSL subsystem. During this experiment, I found a few shortcomings in the current JRuby-OpenSSL 0.5, including missing methods, or missing behaviors needed by Puppet to run fine.

So to get a fully Puppet enabled JRuby-OpenSSL you need either to get the very latest JRuby-OpenSSL from its own github repository (or checkout the puppet-fixes branch of my fork of said repository on github) and or apply manually the following patches on top of the 0.5 source tarballs:

  • JRUBY-3689: OpenSSL::X509::CRL can’t be created with PEM content
  • JRUBY-3690: OpenSSL::X509::Request can’t be created from PEM content
  • JRUBY-3691: Implement OpenSSL::X509::Request#to_pem
  • JRUBY-3692: Implement OpenSSL::X509::Store#add_file
  • JRUBY-3693: OpenSSL::X509::Certificate#check_private_key is not implemented
  • JRUBY-3556: Webrick doesn’t start in https
  • JRUBY-3694: Webrick HTTPS produces some SSL stack trace

Then rebuild JRuby-OpenSSL which is a straightforward process (copy build.properties.SAMPLE to build.properties, adjust jruby.jar path, and then issue ant jar to build the jopenssl.jar).

Once done, install the 0.5 JRuby-OpenSSL gem in your jruby install, and copy other the built jar in lib/ruby/gems/1.8/gems/jruby-openssl-0.5/lib.

Let’s try it!

Then it’s time to run your puppetmaster, just start it with jruby instead of ruby. Of course you need the puppet dependencies installed (Facter).

My next try will be to run Puppet on Jruby and mongrel (or what replaces it in JRuby world), then try with storeconfig on…

Hope that helps, and for any question, please post in the puppet-dev list.

Puppet and JRuby, a love and hate story

Since I heard about JRuby about a year ago, I wanted to try to run my favorite ruby program on it. I’m working with Java almost all day long, so I know for sure that the Sun JVM is a precious tool for running long-lived server. It is pretty fast, and has a very good (and tunable) garbage collector.

In a word: the perfect system to run a long-lived puppetmaster!

The first time I tried, back in February 2009, I unfortunately encountered the bug JRUBY-3349 which prevented Puppet to run quite early, because the Fcntl constants weren’t defined. Since my understanding of JRuby internal is near zero, I left there.

But thanks to Luke Kanies (Puppet creator), one of the JRuby main developers Charles Oliver Nutter fixed the issue a couple of weeks ago (thanks to him, and they even fixed another issue at about the same time about fcntl which didn’t support SET_FD).

That was just in time for another test…

But what I forgot was that Puppet is not every ruby app on the block. It uses lots of cryptography behind the scene. Remember that Puppet manages its own PKI, including:

  • a full Certification Authority.
  • a CRL.
  • authenticated clients connections, through SSL.

That just means Puppet exercise a lot the Ruby OpenSSL extension.

The main issue is that MRI uses OpenSSL for all the cryptographic stuff, and JRuby uses a specific Java version of this extension. Of course this later is still young (presently at v 0.5) and doesn’t contain yet everything needed to be able to run Puppet.

In another life I wrote a proprietary cryptographic Java library, so I’m not a complete cryptography newcomer (OK, I forgot almost everything, but I still have some good books to refer to). So I decided to implement what is missing in JRuby-openssl to allow a webrick Puppetmaster to run.

You can find my contributions in the various JRUBY-3689, JRUBY-3690, JRUBY-3691, JRUBY-3692, JRUBY-3693 bugs.

I still have another a minor patch to submit (OpenSSL::X509::Certificate#to_text implementation).

So the question is: with all that patches applied, did I get a puppetmaster running?

And the answer is unfortunately no.

I can get the puppetmaster to start on a fresh configuration (ie it creates everything SSL related and such), but it fails as soon a client connects (hey that’s way better than before I started :-) ).

All comes from SSL. The issue is that with the C OpenSSL implementation it is possible to get the peer certificate anytime, but the java SSL implementation (which is provided by the Sun virtual machine) requires the client to be authenticated before anyone get access to the peer certificate.

That’s unfortunate because to be able to authenticate a not-yet-registered client, we must have access to its certificate. I couldn’t find any easy code fix, so I stopped my investigations there.

There is still some possible workarounds, like running in mongrel mode (provided JRuby supports mongrel which I didn’t check) and let Nginx (or Apache) handle the SSL stuff, but still it would be great to be able to run a full-fledged puppetmaster on JRuby.

I tried with a known client and get the same issue, so maybe that’s a whole different issue, I guess I’ll have to dig deeper in the Java SSL code, which unfortunately is not available :-)

Stay tuned for more info about this. I hope to be able to have a full puppetmaster running on JRuby soon!

EDIT: I could run a full puppetmaster on webrick from scratch under JRuby with a normal ruby client. I’ll post the recipe in a subsequent article soon.

How do you like your Mocks served?

I like them refreshing, of course:

Mockito is the new Java mock library on the block, with lots of interesting features. It replaced JMock in almost all my Java projects, mainly because:

  • the syntax produces clear and readable test code (see below for an example), because it doesn’t abuse of anonymous class and methods are really methods.
  • stub and verification happens logically, and at different place
  • no replay or framework control methods ala EasyMock
  • fully integrated to Junit (using @RunWith for instance)
  • helpful annotations to create mock automagically
  • it promotes simple tests by nature (and that’s essential to my eyes)

Basically, you can only do two things with Mockito:

  • stub, or
  • verify :-)

Enough discussion, let’s focus on an example:

@Test
public void itShouldComputeAndSetThePlayerRank()
{
  // creating a mock from an interface
  // is as easy as that:
  Player p = mock(Player.class)

  // stub a method
  when(p.getScore()).thenReturn(5);

  // our imaginary SUT
  ELOCalculator.computeRank(p);

  // let's verify our rank has been computed
  verify(p).setRank(12);
}

Due to its use of Generics and Java 5 autoboxing, the syntax is very clean, clear and readable.
But that’s not all, Mockito provide a Junit 4 runner that simplifies mock creation with the help of annotations:

@RunWith(MockitoJUnit44Runner.class)
public class OurImaginaryTestCase
{
  @Mock
  private Player player;

  @Test
  public void playerShouldBeRanked()
  {
     // we can use player directly here,
     // it is mocked to the Player Interface
  }
}

Of course during the verification phase of the test you can check for

  • the number of calls (or check for no calls at all)
  • the arguments (Mockito defines lots of useful arguments matcher, and you can plug any Hamcrest matchers),
  • the call order,
  • and for stubbing, you can also throw exception, return values, or define callbacks that will be called when a return value is needed.

In a word it’s really powerful.

It is also possible to spy on concrete objects however as the manual says this is not partial mocking: so you can’t use this method to check that the method under test calls other methods of the same object.

Here’s an example of what I mean (the following test passes):

public class RealObject {
  public int a() {
    return 10;
  }
  public int b() {
    return 20 + a();
  }
}

@Test
public final void test1()
{
  RealObject real = new RealObject();
  RealObject spy = spy(real);

  when(spy.a()).thenReturn(12);

  // notice the 30 here
  assertThat(spy.b(), equalTo(30));
}

See Mockito author’s last blog post about the subject or this mockito mailing list post. Basically the code should be refactored or we could use a subclass to overcome this.

There is also a debate about stubbing and verifying (the same call). Usually you don’t want to do that. Stubbing should be enough, if you’re code succeed then the call was implicitly verified. So usually if you stub there is no need to verify, and if you verify you don’t need to stub (except if you need to return something critical to the rest of the code, in which case you don’t need verification).

Once again, Mockito’s author has a great post on the stubbing or verifying debate.

Of course if you are an Eclipse user, do not forget to add to the list of Favorites all Mockito static import, so that Content Assist knows all the matchers.

Happy unit testing with Mockito :-)

Masterzen's Pictures

Participants
Ticket to Ride World Championship 2010

Participants Ticket to Ride World Championship 2010

masterzen's photo

masterzen's photo

masterzen's photo

masterzen's photo

Erick (CA)
Ticket to Ride World Championship 2010

Erick (CA) Ticket to Ride World Championship 2010

Qualifacation Round - Table1
Ticket to Ride World Championship 2010

Qualifacation Round - Table1 Ticket to Ride World Championship...

Rémi (FR) during Qualification Round
Ticket to Ride World Championship 2010

Rémi (FR) during Qualification Round Ticket to Ride World Championship...

masterzen's photo

masterzen's photo

Ticket to Ride World Championship 2010

Ticket to Ride World Championship 2010