Sin ley

Blog on Ruby, AWS, Mono, .NET...

Amazon EC2: Automatic EBS volume snapshots using Ruby

Remember this? This is how to achieve the same effect with Ruby:

require 'aws-sdk'
# Environment vars. AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY set
ec2 = AWS::EC2.new

ec2.volumes.each do |volume|
  next if volume.status != :in_use
  name = volume.tags['Name']
  snapshot = volume.create_snapshot
  snapshot.add_tag('Name', :value => name) if name
  puts "Snapshot of #{volume.id} (#{name}) initiated at #{snapshot.start_time}"
end

Amazon EC2: Automatic EBS volume snapshots using C#

Amazon EC2 lets you create snapshots of the EBS volumes using the Amazon Console or the EC2 Java-based command-line tools. The Console works fine until you have to manage a decent amount of volumes or need frequent snapshots. As for the Java-based command-line tools, well, they are Java-based...

Another alternative is to use the .NET API so you can customize what volumes are backed up and how often, the retention criteria, and anything you want while using your favorite programming language. You have to start by downloading the AWS dll from Amazon. Click on Download the DLL and Samples.

The following program takes a snapshot of all the volumes that are in use in your account. The snapshot name matches the name of the source volume:

using System;
using System.Configuration;
using System.Collections.Generic;
using System.Net;
using System.Linq;
using Amazon;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace AWSBackup {
    class Program {
        static void Main (string [] args)
        {
            // The following line is not needed in .NET.
            // In Mono, it is not needed if you trust the AWS certificate chain
            // See http://stackoverflow.com/questions/3285489/mono-problems-with-cert-and-mozroots
            ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => { return true; };

            var volumes = GetVolumes ();
            foreach (var v in volumes) {
                if (String.IsNullOrEmpty (v.VolumeId) || String.CompareOrdinal (v.Status, "in-use") != 0)
                    continue;
                var name = v.Tag.FirstOrDefault (t => t.Key == "Name").Value;
                var snapshot = CreateSnapshot (v, name);
                Console.WriteLine ("Snapshot of {0} initiated at {1}", name, snapshot.StartTime);
            }
        }

        static IEnumerable<Volume> GetVolumes ()
        {
            AmazonEC2 ec2 = GetEC2Client ();
            var request = new DescribeVolumesRequest ();
            var response = ec2.DescribeVolumes (request);
            return response.DescribeVolumesResult.Volume;
        }

        static Snapshot CreateSnapshot (Volume v, string name)
        {
            AmazonEC2 ec2 = GetEC2Client ();
            var request = new CreateSnapshotRequest ()
                            .WithVolumeId (v.VolumeId)
                            .WithDescription (name);
            var response = ec2.CreateSnapshot (request);
            var snapshot = response.CreateSnapshotResult.Snapshot;

            if (!String.IsNullOrEmpty (name)) {
                ec2.CreateTags (new CreateTagsRequest ()
                                .WithResourceId (snapshot.SnapshotId)
                                .WithTag (new Tag { Key = "Name", Value = name })
                );
            }
            return snapshot;
        }

        static AmazonEC2 GetEC2Client ()
        {
            var settings = ConfigurationManager.AppSettings;
            return AWSClientFactory.CreateAmazonEC2Client (settings ["AWSAccessKey"], settings ["AWSSecretKey"]);
        }
    }
}

...And that's it! Instead of a shell script that executes several programs per volume, we have a single program that runs on both MS.NET and Mono. Add it to your crontab or the Windows Task Scheduler and you get automatic backups for your volumes. Automatic deletion of old backups is left as an exercise for the reader.

C# source, application configuration file, and Makefile can be downloaded from here: ec2-backup.zip.

Introducing Mono.Dns

The internal implementation of System.Net.Dns in Mono ends up calling getaddrinfo () or some other similar function in libc. This is perfectly fine for most applications. However, sophisticated applications that perform more than just a few DNS queries, like crawlers, aggregators, and log processors, are taking a big performance hit when running under Mono. One of the issues is that the libc implementation is not optimized to be used from multiple threads. Barring an external library dependency, there is not much that can be done to address that problem. Another issue is that the implementation of the asynchronous methods in System.Net.Dns are based on asynchronous delegates invoking the synchronous version of the methods. In other words, calling, for instance, Dns.BeginGetHostAddresses () will use a threadpool thread to block on the call to Dns.GetHostAddresses (). Mono.Dns is here to address these problems and more.

The Mono.Dns assembly provides a set of classes that can help you implement a DNS client or server. There is also an implementation of a simple asynchronous DNS resolver with an API inspired by the System.Net.Socket.Socket.*Async() set of methods. The source code is available in the Mono.Dns GitHub repository. There is an example of use in test/resolver.cs.

As an example of the performance advantage, grab the plainolddns.cs file, compile it, and download this file. Make sure you pull the latest Mono from the master branch and run the program like this:

$ mono plainolddns.exe $(cat google-domains.txt)
...A BUNCH OF NAMES and IP ADDRESSES
...
00:00:18.4342605

And then run it again, but this time set the MONO_DNS environment variable:

$ MONO_DNS=1 mono plainolddns.exe $(cat google-domains.txt)
...THE SAME BUNCH OF NAMES and IP ADDRESSES
...
00:00:00.6138950

Yep, about 30 times faster!

A partial copy of Mono.Dns is now integrated in the master branch of Mono and will be enabled when you set the environment variable MONO_DNS. By default, the old code will be used for DNS resolution and, once the variable is set, the managed resolver implementation will be used for any internal name resolution operation (WebRequest,...).

Caveat: if you are using /etc/nsswitch.conf, setting the variable is not an option for you.

ASP.NET Razor in Mono

After Marek Habersack's work on getting ASP.NET MVC 3 working on Mono, we just needed a couple of fixes to have Razor in Mono.

This is how the photo gallery sample I got from WebMatrix looks in Mono:

pager

You will need Mono master/a2ed4f6 if you want to try Razor out. Publish your Razor web site and remove Microsoft.Web.Infrastructure.dll from the bin directory, Mono will load its own from the GAC.

Update: You can get a zip file with the sample from here. Unzip it, 'cd webdeploy', run 'xsp4 --applications /test:.' and browse http://127.0.0.1:8080/test/nodb.cshtml.

Exceptions in thread pool threads

When .NET 2.0 came out back in January 2006 there was a significant change in how the .NET runtime treats exception in thread pool threads: they terminate the process if they are not handled. There are a couple of exceptions to the rule, the most common one being Thread.Abort() called on the thread.

Until now Mono was not compatible in this regard and instead we behaved like the .NET 1.x runtime, i.e., exceptions in thread pool threads were silently ignored. Finally, as some folks already running Mono from master have noticed, Mono behaves like .NET 2.0. The first release incorporating this change will be Mono 2.8.

Code samples

  1. An exception in a thread pool thread causes this code to terminate the process when executed

         ThreadPool.QueueUserWorkItem ((a) => { throw new Exception ("From the threadpoool"); });
  2. The program is also terminated if the callback of an asynchronous delegate invocation throws.

         void Method ()
         {
              WaitCallback wcb = new WaitCallback ((a) => {
                   Console.WriteLine ("Here");
              });
              wcb.BeginInvoke (wcb, OnCBFinished, null);
              ...
         }

         static void OnCBFinished (object arg)
         {
              throw new Exception ("Whatever");
         }

  3. Surprise! If the BeginInvoke() call does not have a callback, the exception is ignored as in the good old 1.x days

         WaitCallback wcb = new WaitCallback ((a) => { 
              throw new Exception ("From the threadpoool");
         });     
         wcb.BeginInvoke (wcb, nullnull);

    Update: yes, if EndInvoke() is called, the exception will be raised in the caller thread. The surprise is the difference between this case and (2), since EndInvoke() is not called in (2).

Effects of this change to the Mono runtime

We have fixed the classes in Mono that were not handling exceptions thrown in the thread pool. If you find one that we've missed, please, let me know.

If your application uses the thread pool explicitly or through Delegate.BeginInvoke(), make sure you are handling the exceptions that might happen there. Look for occurences of (1) and (2) above, but ignore (3). If there are too many to count, you can start by applying the workaround described later or by adding an unhandled exception handler to the root application domain:

        static int Main ()
        {
                AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
                ...
                return 0;
        }

        static void OnUnhandledException (object sender, UnhandledExceptionEventArgs e)
        {
                if (Thread.CurrentThread.IsThreadPoolThread)
                        return// Ignore exceptions in thread pool threads
                Console.Error.WriteLine (e.ExceptionObject);
                Environment.Exit (1);
        }

Workaround: legacy compatibility

If you are an end user stuck with an old application (or a lazy developer), adding the following legacyUnhandledExceptionPolicy to your application configuration file will make exceptions in the thread pool behave like in .NET 1.x:

     <configuration>
          <runtime>
               <legacyUnhandledExceptionPolicy enabled="1"/>
          </runtime>
     </configuration>

Microbenchmark: Mono's new generational GC vs Boehm GC

The Mono Generational GC (a.k.a. SGEN) has been in the works for quite some time now. Given the no-hassle way to use it these days, I decided to compare the performance of both garbage collectors.

The test itself is very simple. I used xsp listening on port 8080 and hit empty.ashx, which is an IHttpHandler that serves a 0-length web page. In both cases, Boehm and SGEN, I warmed up the server by hitting it once and then ran the following command:

ab -c 20 -n 100000 -k http://127.0.0.1:8080/1.1/handlers/empty.ashx

This will fetch 100k empty pages with 20 concurrent requests over keep-alive connections. The results at the end of each run follows:

Boehm SGEN
Time (s) 29.194 24.687
Memory in use (MB, RSS) 80 61
Requests per second 3425.36 4050.70
Average CPU use (%) 82 93

Over 600 req/s more and using 19MB less memory! Amazing! Kudos to the guys doing all the work, specially Mark.

Gnome-keyring-sharp 1.0.2 released

There is a new gnome-keyring-sharp available for download.

The only changes from 1.0.1 are related to a breaking change in gnome-keyring: the socket interface is no longer there as of GNOME 2.30+.

Thanks a lot to Chris Halse Rogers at Canonical for doing all the work.

msnbot/2.0b and robots.txt

Looks like the new MSN spider is having some trouble following the rules. While they fix it, this can be blocked in Apache by doing:
 SetEnvIfNoCase user-agent "^msnbot/2.0b" banned_by_now
 ...
 <Directory "/srv/www/htdocs/">
    Order allow,deny
    Allow from all
    Deny from env=banned_by_now
 </Directory>

Precompiled ASP.NET web sites in Mono

I just added support for running precompiled non-updatable ASP.NET web sites in mono. The benefit from this, apart from the well-known faster initial request and not shipping source code, is that now you will be able to run you ASP.NET applications written in VB.NET in mono without crossing your fingers and expecting our VB.NET compiler to not give you any problem.

The support for precompiled web sites will be in the upcoming Mono 2.4 release and is already in SVN HEAD for those of you not afraid to compile Mono from sources.

Given a web project, you can generate the precompiled version either form Visual Studio or from the command line, like:

c:\test\>aspnet_compiler -f -p c:\test\BlogEngine.Web -v /blog c:\test\output

This command will precompile BlogEngine.net and leave all the generated files in c:\test\output. With the above commands, there are no source files in the output folder at all. Now, to run this on Mono, all you need to do is copy the output folder to your linux machine and configure Apache/mod_mono to serve that folder at /blog/. If you just want to do a quick test, assuming you copied c:\test\output to /tmp/output:

$ cd /tmp/output
$ xsp2 --applications /blog:.

...and then go to http://localhost:8080/blog/ with your browser.

For this application in particular, the time taken to display the first page is about 2s on my laptop, while the non-precompiled site takes about 18s.

Not all browsers are created equal

Somebody reported that the nice little pager that I posted a few days ago didn't work properly on IE if you use the zoom-in/zoom-out feature (hold the Ctrl key and move the mouse wheel). Parts of the text are hidden behind the input textbox. Probably a bug in IE...?

I couldn't figure out how to make it work in IE with CSS, so the new code uses a table and different cells for each part of the pager. The updated code is here.

Nice GridView pager without images

The predefined options for the GridView , which can be set through the PagerSettings.Mode property are:

  • NextPrevious
  • NextPreviousFirstLast
  • Numeric
  • NumericFirstLast
Additionally, you can set the text (FirstPageText, NextPageText,...) or image URL (FirstPageImageUrl, NextPageImageUrl, ...) to be displayed for each of those LinkButtons to be shown in the pager.

I wanted to avoid using images and tried to use the Unicode characters for 'left-pointing pointer' (\u25c4 ◄) and 'right-pointing pointer' (\u25ba ►). Also, to make it nicer, I wanted to have a TextBox in which the user can type the page he wants to go to

In the end, I decided to create a class implementing ITemplate, set the GridView's PagerTemplate to this class and add the controls I needed manually. The final result looks like this:

pager
Pager with no images.

To use this ITemplate in a GridView, you can do something like:

     protected void Page_Init (object sender, EventArgs e) {
          myGridView.PagerTemplate = new FancyPagerTemplate (myGridView);
     }

...and you're all set. The events generated by a change in the TextBox or a click on the LinkButtons and the TextBox width will be taken care of.

You can download the source code for the ITemplate from FancyPagerTemplate.cs. Feel free to customize it to your needs.

More on Novell and Microsoft

Many have written about the agreement that Novell and Microsoft reached a few days ago. Most of the blogs and emails that I've read express doubts about Novell's intentions. Others, after years of trying to spread FUD on Mono, give another twist to their own conspiracy theories. And last, but not least, someone that gets what is going on: read this article from Steven J. Vaughan-Nichols. I dig it.

Fun with google-sharp

The last version of F-spot is using google-sharp to export pictures to Picasa Web. Some users reported that it didn't work for them and it seemed like the creative use I was doing with HttpWebRequest was the culprit.

Ideally, we should do what the Picasa2 client does on windows, but there's no information available on that. The problem is that the authentication takes place over HTTPS and I needed to figure out a way of getting the unencrypted data. Sebastien, our cryptoman, suggested looking for something that overrides winsock2 SSL layer, but I couldn't find anything. So he suggested the use of webscarab, a java web application review tool. I downloaded the jar and run the program like:

$ java -jar webscarab-selfcontained-20060718-1904.jar

This thing is really nice for debugging web applications. One of the goodies is that it works as a web proxy and can show you the unencrypted data that goes over HTTPS. How?

  • It creates one encrypted connection to the server.
  • It creates one encrypted connection to the client. This one uses a self-signed certificate for the server side.

The data that comes from the client or the server is first unencrypted and then encrypted again over a different connection. The pitfall is that the connection to the client is using a self-signed certificate.

I started a proxy on port 3128 and then made the windows computer point at that. Then run Picasa and try to log in to Picasa Web. No luck. Picasa2 didn't like the self-signed certificate that it got. I tried installing the self-signed certificate in the trusted roots store, but still couldn't get it to work.

I decided to use XSP and did the following:

  • Set up a certificate following the instructions in the Mono site. This certificate had a 'CN=www.google.com' and 'O=Google Inc'. Not that it matters, but just in case they were only checking those values.
  • Copied the Picasa2.exe to linux, overwriting the one installed from RPMs that does not support Picasa Web uploading.
  • Added this line to /etc/hosts:
    127.0.0.1   www.google.com
    
  • Modified XSP a little bit to display all the request data it got and run, as root:
    # xsp --https --port 443 --p12file yo.p12 --pkpwd secret
    

When I run Picasa and tried to log in to Picasa Web, it connected to XSP and I was finally able to see how they were authenticating. The two interesting URLs were:

  • https://www.google.com/accounts/ClientAuth
    Posting the user name and password here gives us back a LSID and a SID value.
  • https://www.google.com/accounts/IssueAuthToken
    Posting the SID, LSID and service name (lh2 for Picasa Web) gives us an AuthToken.

Now that we've got the AuthToken, we just need to append it to the query string as auth=AuthToken when getting Picasa Web API information from http://picasaweb.google.com/api/urls?version=1. If you get that URL without the AuthToken, you will only get the read-only stuff, but adding the AuthToken gives you the post value, which is the URL used when sending commands to the server and also a cookie that should be used on the rest of the session to prove that you're authorized.

The authentication process now requires 2 POSTs and 1 GET, while before it was trying to emulate a web browser and got a bunch of redirections and lots of cookies being set and unset. Oh, and now google-sharp works on windows with the MS runtime too!

F-spot patch supporting Picasa Web

Amazing. While I was sleeping, Stephane Delcroix implemented a plug-in for f-spot that uses Mono.Google assembly to allow exporting pictures to Picasa Web.

The patch is attached to http://bugzilla.gnome.org/show_bug.cgi?id=344851.

Google-sharp

There's a new assembly available in the mono svn repository, module google-sharp. The classes it contains lets you authenticate to a Google service and there also support for managing your Picasa web galleries. As a plus, it also contains monodoc documentation.

Authenticating

The authentication process logs securely into the service as a web browser would do and retrieves the cookies needed. Once we those cookies, we can access the service over HTTP.

using Mono.Google;
class Test {
     public GoogleConnection Connect (string user, string passwd)
     {
          GoogleConnection conn = new GoogleConnection (GoogleService.Picasa);
          ServicePointManager.CertificatePolicy = new NoCheckCertificatePolicy ();
          conn.Authenticate (user, passwd);
          return conn;
     }
}

In the example, we create a GoogleConnection to be used with Picasa web and do the authentication for the given user and password. Setting the CertificatePolicy to that value will make it accept any server certificate when using an HTTPS connection. To know more about why that is needed (and other ways of achieving the same) see the Mono security FAQ.

Managing a Picasa Web gallery

Once you're authenticated, you can create an album:

PicasaWeb picasa = new PicasaWeb (conn);
string unique_id = picasa.CreateAlbum ("My first album");
PicasaAlbumCollection coll = picasa.GetAlbums ();
PicasaAlbum album = coll [unique_id];

Download all the pictures in it:

PicasaPictureCollection pics = album.GetPictures ();
foreach (PicasaPicture picture in pics.AllValues) {
     using (Stream stream = File.OpenWrite (picture.Title)) {
          picture.DownloadToStream (stream);
     }
}

Upload a new picture to an album:

album.UploadPicture ("some-picture.jpg");

Of course, there's a caveat: currently the authentication process fails when running under MS.NET (too many redirections), so that means that:

  1. We have a bug in Mono that I'm not going to fix by now.
  2. I have to figure out how to make that work on MS

Hopefully, this will open the door for a Picasa Web plugin for f-spot, as Picasa for linux lacks support for Picasa Web. A command-line tool for uploading pictures is on the way.

Enjoy!