Thank You, Micah! and zend-framework 1.10.2

For your notice, zend-framework 1.10.2 is uploaded to Ubuntu Lucid which will be Ubuntu 10.04 LTS.

But that’s not worth a blog entry, because you know that we are trying to give you the latest and hottest stuff out there.

Why I’m writing this:

In our PPA of the zend-framework team, you’ll find the latest release from Lucid for other Ubuntu releases.
As I’m busy with other things during these days, one Ubuntu colleague stepped up and helps us here to give you the zend-framework backport packages just in time.

Micah Gersten is this colleague and he deserves our love. Especially from all our PHP Lovers and Zend Framework hackers out in the Ubuntu Universe.

So, please go to hall-of-fame.ubuntu.com and nominate Micah (lp id: micahg) as “Featured Contributor”.

Micah is the man of the hour…he does all the underlaying work for the zend-framework packages, he testbuilds them, files official backport requests etc. pp.

So, all my “Thanks” goes to Micah Gersten, a man who makes my Ubuntu work life a bit easier.

My last post…

couldn’t be understandable the way as it should be.
Problem was, that there was no picture in it (at least I hope so…)

So here is the picture, to understand what #sysadmins are….

(Curtesy to xkcd.com: http://www.xkcd.com/705/)

The Truth of Automation and System Administration

Thanks to Sven for pointing out these true words:

Some of these things may seem like a lot of work.
Configuration management is work.
Building your own packages is work.
Learning way more about your Linux distro than you ever though possible, is definitely work.
But in the end, you can be certain that servers will be configured exactly as you expect.
Security patches or even distro version upgrades (sometimes) can be applied with little worry
that all the services you’ve configured will break.
In the end, it’s a lot less work.

(Original Article: Charlie Schluting: Stop Fighting Linux and Learn Your Distro)

I’m sometimes suprised…

…that Dilbert is more real than my daily surreality

Dilbert.com

JQuery: resizing iframes

I found that snippet very comfortable, when using jQuery for resizing iframes:

1
2
3
4
5
6
7
8
$(document).ready(function()
{
// Get Iframe
   var iFrame = $("iframe#special");
   iFrame.load(function() {
       iFrame.css("height",$($(this).contents()).height()+70+"px");
   });
});

or does anyone know a better one?

Cross Origin Resource Sharing in Firefox >= 3.5 and Google Chrome => FAIL

Disclaimer: If you are reading this via PlanetPlanet or a non-javascript aggregator, please visit the real page to read more

You know, we are living in a world of SOA. And even if we don’t like the new world order of the web, sometimes it can make our lifes easier.

We think that, right?

Right now I’m working on the re-implementation on my DjangoFAIed project. Which means, I’m in need of a separation between shiny new bling bling named web frontend and boring looking jsonrpc or xmlrpc for the web backend.

As you know, I’m working with Django for the daily system development, so here I’m in love with Django and RPC4Django.

The good thing about RPC4Django is that it gives me an easy way to provide two RPC types but only writing one backend.

So, having this in place, and doing some xmlrpc calls from the FAI side of life, I just need to find a way to deal with the web frontend.

So, here we are, my high rated topic: XMLHttpRequests, Javascript and Browsers, and what are they supporting.

There are at least 4 browsers I would care about:

  1. Firefox >= 3.5
  2. Google Chrome
  3. IE8
  4. Safari

No. 1 is my choice when developing some bling bling, No. 2 comes to my mind if I want to have a fast Javascript Execution time, No. 3 and No. 4, oh well, I use FF and Chrome even on windows, and I never had to do anything with Apple ;)

Creating our testbed

Now, let’s setup a testbed for the application. Let’s assume:

  1. http://testrpc/ -> this is the domain where Django lives. It’s setup and runs like a charm
  2. http://testhtml/ -> this is where our test web application is living. It consits right now of one web page, named index.html
  3. For doing some simple javascript work we are using jQuery delivered by the google cdn
  4. Our webserver is Apache 2.2.x
  5. We are using WSGI as gateway to our application (mod_wsgi)

Now, I hope you have a django installation (I’m already using 1.2 beta) and installed RPC4Django. Create a new django application and add to the __init__.py file these methods:

1
2
3
4
5
6
# Create your views here.
from rpc4django import rpcmethod

@rpcmethod(name="hello_world",signature=['string'])
def helloworld():
    return "Hello World"

This is how we define a new xmlrpc/jsonrpc call which just returns “Hello World”.

Now add to your djangoproject urls.py this endpoint for our RPC calls:

(r'^RPC2/$', 'rpc4django.views.serve_rpc_request')

and add your new application and the rpc4django application to your settings.INSTALLED_APPS.

Setup your apache installation to serve your application, don’t forget your wsgi_handler.py.

Now, if we start a browser and enter “http://testrpc/RPC2/” into the location bar, you will get something like this:

(Picture taken from: David Fischer RPC4Django)

To test if our application is working just create this little xmlrpc client app:

1
2
3
4
5
6
#!/usr/bin/python
import xmlrpclib

if __name__=="__main__":
    proxy = xmlrpclib.ServerProxy("http://testrpc/RPC2/")
    print proxy.hello_world()

It should print out “Hello World”.

Creating the web frontend

As said before, we are using jQuery as DOM library to make our lifes easier, regarding Events and Ajax things.

Let’s see how this goes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<html><head><title>testhtml</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js"></script> <script src="json2.js"></script>
<script>// < ![CDATA[
(function($){
// jsonRPC taken from http://plugins.jquery.com/project/jsonRpc (C) by <a href="http://veged.ya.ru/">Sergey Berezhnoy
$.jsonRpc = $.jsonRpc || function(options) {
    options.type = options.type || 'GET';
    var ajaxOptions = {
        contentType: 'application/json',
        dataType: options.type == 'GET' ? 'jsonp' : 'json',
        processData: options.type == 'GET'
    };

    var data = {
        version: options.version || '1.0',
        method: options.method || 'system.listMethods',
        params: options.params || [],
        id: options.id || "djangorpc"
    };
    $.each(data, function(i){ delete options[i] });

    function send() {
        options.data = JSON.stringify(data);
        if (options.type == 'GET') options.data = {json: options.data};
        $.ajax($.extend(ajaxOptions, options));
    }

    if (typeof JSON == 'undefined') {
        $.getScript('http://www.json.org/json2.js', function(){ send() });    } else {
        send();
    }
    return $;
};

})(jQuery);
// ]]></script>
<script type="text/javascript">// < ![CDATA[
   $(document).ready(function() {
       $("#testOutput").bind("click",function() {
           var me=this;
           $.jsonRpc({
               type:"POST",
               url:"http://testrpc/RPC2/",
               method:"hello_world",
               dataType:"json",
               success: function(data) {
                    $(me).html(data.result);
               },
               error:function(xhrReq,statusbar,foo) {
                    console.log(xhrReq.responseText);
                   console.log(foo);
                   console.log(statusbar);
                   console.log("hello error");
               }
           })
       });
   });
// ]]></script>
<body>
<div id="testOutput">click here</div>
</body>
</head></html>

This page includes the jQuery Script from the Google API CDN, you need to get the json2.js from http://www.json.org/
and put it in your documentroot or in your directory where the html file is saved.
When you point your browser now to this page, and you click with your mouse on “click here”, the javascript fires an click event, and inside this click event, it starts to make a Ajax Request against our rpc django app.
The result of this ajax request should be, that the content of the “<DIV> with the ID of “#testOutput will change its content and displays “Hello World”.

“Oh, but you can’t do XMLHttpRequests across different domains! It will fail, and you should know about the same origin policy !” you will say now, and you are right.
But, thanks to the “Web Applications Working Group” we have something new: CORS or simply named: Cross Origin Resource Sharing.

Cross Origin Resource Sharing – CORS

What is “CORS”? you will ask now. The working draft abstracts it like this:

This document defines a mechanism to enable client-side cross-origin requests. Specifications that want to enable cross-origin requests in an API they define can use the algorithms defined by this specification. If such an API is used on http://example.org resources, a resource on http://hello-world.example can opt in using the mechanism described by this specification (e.g., specifying Access-Control-Allow-Origin: http://example.org as response header), which would allow that resource to be fetched cross-origin from http://example.org.

(from: Cross-Origin Resource Sharing, W3C Working Draft 17 March 2009

This really sounds important, right? What it just says is, that now it’s possible to make Cross Site XMLHttpRequests under special cicumstancas.
What we just need to know is that Mozilla implemented this feature already in all Firefox Browsers >= 3.5.
Mozilla calls it “HTTP access control“.

Now, you will bring this example to work when you enable mod_header of your apache installation and add to your test virtualhost something like this:

1
2
3
4
5
6
7
<virtualhost *:80>
    Header set Access-Control-Allow-Origin "*"
    DocumentRoot /whereever/that/is/
    ServerName testrpc
    AddDefaultCharset utf-8
    <some more config statements about wsgi and your django application>
</some></virtualhost>

Pay a bit of attention to the “Header” line. What it will do is easy: It will spit out a new Access-Control-Allow-Origin Header, which is set for anybody to make cross site XHR requests to your site.
It’s just like a bit when you tell Adobe Flash Crossdomain.xml to ‘allow-from-domain “*”‘. Different names, same result.

Now, restart your apache server and try the demo page again, now it should work like a charm. The contents of the div will change to “Hello World” and we are done.

Are we really done?

Oh well, not quite done. Now we need to test this positive result in another browser, let’s choose Google Chrome.

To make a long story short, somehow this example doesn’t work, but regarding all the postings on the fantastic lazyweb, Google Chrome does support CORS!
Well, not really. It does support this feature under special circumstancas. This document tells us more.

Regular web pages can use the XMLHttpRequest object to send and receive data from remote servers,
but they’re limited by the same origin policy.
Extensions aren’t so limited. An extension can talk to remote servers outside of its origin, as
long as it first requests cross-origin permissions.

(taken from: Google Chrome Extentions: Cross-Origin XMLHttpRequest)

There is another explanation.

Content scripts are JavaScript files that run in the context of web pages. By using the standard Document Object Model (DOM), they can read details of the web pages the browser visits, or make changes to them.
Here are some examples of what content scripts can do:

  • Find unlinked URLs in web pages and convert them into hyperlinks
  • Increase the font size to make text more legible
  • Find and process microformat data in the DOM

However, content scripts have some limitations. They cannot:

  • Use chrome.* APIs (except for parts of chrome.extension)
  • Use variables or functions defined by their extension’s pages
  • Use variables or functions defined by web pages or by other content scripts
  • Make cross-site XMLHttpRequests

(taken from: Google Chrome Extentions: Content Scripts)

Now what?

Now we have a good, fast and cool browser named Chrome, and it does not work as expected.
It should support this out of the box, and it should work like Mozillas implementation.
There are discussions in the background, regarding Greasemonkey and CORS.

Honestly, I’m writing “intranet” applications, I don’t want to use CORS in external applications. But regarding the CORS specification, I do like the way how this goes.
No need anymore to do cross site XHR via iframe (which works, but is actually painful). Furthermore, it can be a nice standard.
What we need to avoid is that really good browsers like Mozilla FF and Googles Chrome are doing what we always hated about MS: Going two different ways.

I also don’t want to write two or three different JS implementation to do the one thing. I really don’t want to support more then one browsers javascript implementation.
So, how can I get this to work without doing the old painful “iframe” way, and without writing a google extention?

Zend Framework 1.10.1 is reaching Ubuntu Lucid aka Ubuntu 10.4 LTS

As always,

the latest Zend Framework release is reaching Ubuntu Lucid.

The changes and fixes about this release you can find here.

Shiny micro{blog,tweet,dent,facebook}ing

Good Stuff Well Done Really Shiny…I can’t say more…speechless

Playing with KVM Part 2

Let’s think about this creating command:

vmbuilder kvm -c karmic.cfg \
--domain ubuntu-server.eu \
--dest /vmachines/kvm/ \
--bridge br0 \
--hostname testvm02 \
--user shermann \
--pass foobar \
--mem=256 \
--ip=<whatevr ip> \
--mask=255.255.255.0 \
--dns=<your dns server >\
--gw=<your default gw> \
--libvirt qemu:///system \
--tmpfs=-

The correspondent karmic.cfg looks like this:

[DEFAULT]
arch = i386
part = ubuntu-karmic.part
user = shermann
[ubuntu]
mirror = <your package mirror>
suite = karmic
flavour = server
addpkg = openssh-server, vim-nox
[kvm]
libvirt = qemu:///system

and the partition file looks like this:

root 5000
/boot 100
swap 1000
---
/var/log 2000
/home 1900
Now, when creating the VM everything works fine. But after creation and starting of the VM via virsh, the machine doesn’t boot up.
Could be that this is all my fault ;) Or I’m too ESX…or I’m hitting a bug…

Playing around with KVM on Root Servers

Right now I’m preparing some tests regarding virtualization without VMWare.

Yesterday I tested LXC (aka Linux Containers) on my local desktop, because this machine is too old to have some AMD/Intel virtualization extensions. Anyways, that worked somehow, but using KVM was the goal.

So, looking at my root server (hosted by Hetzner), checking if this machine is able to carry some KVM machines on it.

It does, so I started to grab some documentations from the Ubuntu Documentation about KVM.

Most of the things are straight forward, but what is not as simple as it should, is to bring up the network to play nicely with the Hetzner system.

When you booked a server in 2008 or before that, you got one static IP address from Hetzner. Regarding the contract, you are able to get more then one IP for your root server, you get a 8IP subnet, where 6 IPs can be used.

So, what I can’t use is a bridged interface directly connected with the main ethernet device (eth0).

Therefore I need a virtual tunnel device (tap device from UML).

So what to do:

  1. Get your additional ip subnetwork (for this to work, check your Hetzner Robot Login for this)
  2. sudo apt-get install bridge-utils uml-utilities
  3. add a tap device to your /etc/network/interface
  4. add a bridge device to your /etc/network/interface

So point 1. and 2. are straight forward. Adding a tap device to your /etc/network/interface is mostly simple:

/etc/network/interfaces:

auto tap0
iface tap0 inet manual
   up ifconfig $IFACE 0.0.0.0 up
   down ifconfig $IFACE down
   tunctl_user <your user who runs the virtual machines>

Adding the bridge interface is also not complicated:

/etc/network/interfaces:

auto br0
iface br0 inet static
   address <one address out of the additional ip network, I use the last usable address>
   netmask <netmask of the additional ip network>
   bridge_ports tap0

Now, the address is one of your additional ip addresses you got from Hetzner. I used my last usable address. This IP Address on this bridge interface will be your default gateway inside your KVM machines.

The “bridge_ports tap0″ is important, because if you enter here e.g. your main ethernet device (e.g. eth0) it will give you a non accesible system anymore (you need to rescue it, via Hetzner Robot system -> Rescue system and Reboot System).

What does it do: the tap0 device is a tunnel to your eth0 device. And br0 will bridge all IP traffic from your KVM machines to via this bridge to tap0. The tap0 device then uses your default interface to leave your host and vice versa. (to make this understandable for the non technical audience, the reality what is happening under the hood is more complicated)

After that you can use vmbuilder to create your KVM image, according to the Howto on https://help.ubuntu.com/community/KVM. Just give the KVM machine an IP address from the additional IP subnet (not the one you used for the Host Bridge (br0)) and set the default gateway (–gw) to the IP address of your host bridge (br0).

Return top