Posts in this category are not included in the main feed. You can subscribe here.

Multiple arguments in Django template filters

Author: nme · Tuesday, 5 July, 2011 · No comments ·

By default, it is not currently possible to pass multiple arguments to Django template filter — documentation states: "Custom filters are just Python functions that take one or two arguments".

Here I describe solution that allows passing more arguments.

Lets say we have key and current query_string in our template context. We loop in paginator and alter query_string current key value with page. The key is to group arguments in an array. We use following custom filter:

@register.filter
def keys (first,second):
    if isinstance(first,list):
        return first+[second]
    else:
        return [first,second]

following filter allows us to:

{{ "1"|keys:"2"|keys:"3" }}

which will return in our template:

[u'1', u'2', u'3']

Returning to described query_string altering problem — we use alter_query filter:

@register.filter
def alter_query (keys, query_string):
    from django.http import QueryDict
    query_dict = QueryDict(query_string, mutable=True)
    query_dict[keys[0]] = keys[1]
    return query_dict.urlencode()

inside pagination template, we use following code:

<a href="?{{ key|keys:page|alter_query:query_string }}">{{ page }}</a>

Doesn't look pretty, but works perfectly.

hv — kvm virtualization swiss knife (requires kvm-admin)

Author: nme · Saturday, 12 February, 2011 · No comments ·

Kvm is currently one of best choices for virtualization under GNU Linux operating systems. It is fast and stable. No wonder there are many frontend utilities that handles it.

RedHat Enterprise Linux and Ubuntu Server Linux are both suggesting to relay on libvirt, but whenever I try to use that I always finish with "It is not good enough yet", "new features come, old bugs still exist" etc. As I suppose — it will never be good enough. The reason is the libvirt layer which completly separates system administrator from kvm console.

In opposition to libvirt — we can use kvm and qemu tools, but sooner or later we will start to look after another toolkit to make life easier. I found mine — kvmtools — it is slick, lightweight, written in Python language and offers possibility to perform most tasks using single command. It is really great, but... I don't like kvm-admin command syntax. That is why I created hv — simple bash script that makes kvm-admin more friendly — especially — for (former) virsh users.

Mercurial repository for hv util is available here.
You can download it using the following command: hg clone http://nme.pl/pub/repos/hv
hv
Usage:
hv (list|running) hv (boot|bootp|reboot|kill) domain-name (bootp = boot domain-name, but keep it in paused state) hv (vnc|vncinfo) domain-name hv serial domain-name hv monitor domain-name qemu-monitor-command hv (pause|cont|status) domain-name hv edit domain-name hv snapshots domain-name hv (savevm|loadvm|delvm|bootvm) domain-name snapshot-name hv shutdown domain-name hv verify hv example-domain
Commands might be shortened, eg. hv li

What does hv offer?

List of all commands with examples, like mentioned in hv usage above — it is possible to shorten commands, as long as they are unambiguous. hv offers as much syntatic sweetness as I could figure out ;)

More verbose help:

hv listlist all available virtual machines.
hv runninglist running virtual machines.
hv boot domain-namestart given virtual machine.
hv bootp domain-namestart given virtual machine in a paused state.
hv reboot domain-namewarm reboot virtual machine.
hv kill domain-namepower off virtual machine.
hv vnc domain-nameconnect vncviewer with virtual machine (and keep it turning on when it disconnects — in case of resolution change etc, ^C breakable).
hv vncinfo domain-namereturn vnc listen ip:port.
hv serial domain-nameconnect to serial tty of virtual machine.
hv monitor domain-name qemu-monitor-commandkvm monitor interface — if no monitor-command is given, issuing help command will be suggested.
hv pause domain-namefreeze virtual machine.
hv cont domain-namecontinue feezed virtual machine.
hv status domain-namevirtual machine status.
hv edit domain-namesame as vim /etc/kvm/domain/name.
hv snapshots domain-namelist current virtual-machine snapshots.
hv savevm domain-name snapshot-namecreate snapshot for virtual-machine
hv loadvm domain-name snapshot-nameapply (load) snapshot for virtual-machine
hv delvm domain-name snapshot-namedelete snapshot
hv bootvm domain-name snapshot-nameboot domain and apply (load) snapshot
hv shutdown domain-namegracefully shutdown virtual machine (requires acpid / acpi support on virtual-machine).
hv verifysimplifies manual check of all virtual machines configuration — disks, mac addresses, tap interfaces and vnc ports.
hv example-domainbootstrap configuration of virtual machine, eg. hv example >/etc/kvm/domain/new-vm

Feedback?

As usual — every opinion and suggestion is appreciated!

Upgrading Postgres 8.4 to 9.0 — Ubuntu / GNU Debian step by step

Author: nme · Saturday, 12 February, 2011 · No comments ·

If your safe-upgrade just upgraded your postgresql to 9.0, your databases probably does not work and there is no postgresql-8.4 in your system. It is an unfortunate behavior, but we can simply migrate our data to new Postgres, here is how:

First, install your old postgres 8.4:

sudo -i
aptitude install postgresql-8.4

Stop all services using postgres databases and make backup of all databases and roles:

su - postgres
pg_dumpall >migration
exit

Make copy of your data (just to be sure you have backup):

cp ~postgres/migration /root/
Purge old Postgres 8.4 and install Postgres 9.0:
aptitude purge postgresql-8.4
aptitude install postgresql-9.0
Get all of your data back to Postgres:
su - postgres
psql <migration
exit

Turn your services back online, check if everything works again — if it does, remove migration data from postgres user and make a bz2 compressed archive containing all databases and roles:

rm ~postgres/migration
bzip2 migration
mv migration.bz2 `date +%Y-%m-%d`-migration.bz2

Keep that backup for a while until you will be sure that is safe to delete it.

Real-time graph using Javascript

Author: nme · Thursday, 20 January, 2011 · No comments · Tags: javascript ·

Post below describes solution which requires Raphaël JS to draw graph using SVG.
I've also made a cleaner version — html5 canvas real-time graph — enjoy!

This idea was wandering through my mind for quite some time now, and finally I got a project I'm working on where it will be perfect to fit. That is why I decided to try to put this idea to the test. Suprisingly, it works :)

I was never a fan of Flash technology which would solve real-time graphing very fast so I had to pick Javascript libraries that will do the work. One of them is jQuery, because I like to have clean code. The other is Raphaël JS — Javascript library which aims allowing web developers to draw using SVG.

So, here is the effect of "step" scrolling:

Full sources are published and dual licensed under MIT and GPL. The above example is called step.html.

As an alternative, there is also "smooth" scrolling example included, but unfortunately — it makes web browser to consume 100% time of one CPU core. It might not be a problem on a desktop computer, but some older laptops will most likely "feel" the issue. If you know how to solve the problem — please let me know.

The actual source code consists of three parts:

animatedGraph jQuery plugin

// animatedGraph jQuery plugin, requires jQuery and Raphael libraries
(function($) {
    $.fn.extend({
        animatedGraph: function(width, height, steps, max, single, many, ms) {
            var path = function(array, step, left) {
                var scale = height/max,
                    path = '',          
                    x=-left,            
                    y=0;                
                for (var i=0;i<array.length;i++) {
                    if (i) {            
                        path += "S" + [(x += step), (y = height — array[i]*scale), x, y];
                    } else {            
                        path += "M" + [-10, (y = height — array[i]*scale)]; 
                        path += "C" + [0, (y = height — array[i]*scale)]; 
                    }                   
                }               
                return path+'L'+(array.length*step+10)+','+(height+10)+' '+(-10)+','+(height+10)+'+z';
            };          
            return this.each(function() {
                var self = this;
                self.step = width/(steps-1);
                $(self)         
                    .css('width',width+'px')
                    .css('height',height+'px');
                self.r = Raphael(self, width, height); 
                self.data = many(steps);
                self.path = self.r.path(path(self.data, self.step, 0))
                    .attr({             
                        stroke: '#66f',         
                        fill: '#ddf',           
                        'stroke-width': 2,      
                        'clip-rect': ''+[0,0,width-1,height]
                    });                 
                setInterval(function() {
                    self.data.shift();  
                    self.data.push(single());
                    self.path.animate({path:path(self.data, self.step, 0)});
                }, ms);         
            });         
        }       
    }); 
})(jQuery);

Pseudo-random source data generator

// rotating across pseudo-random values array
var Rotator = function() {
    var self = this;
    self.data = [ 
        16,23,41,38,45,31,29,22,27,22,25,29,32,45,88,30,
        26,22,45,23,36,48,99,22,32,26,22,27,5,0,0,3,15
    ];  
    self.index = 0;
    self.single = function() {
        self.index += 1;
        if (self.index > self.data.length) {
            self.index = 1;
        }       
        return self.data[self.index-1];
    };  
    self.many = function(length) {
        var results = [];
        for (var i=0;i<length;i++) {
            results.push(self.single());
        }       
        return results;
    };  
};

The main function

$(document).ready(function() {
    var self = this;
    $('#animatedgraph-demo')
        .replaceWith(function() {
            return $('<div id="animatedgraph-demo"></div>');
        });     
    var rotator = new Rotator();
    $('#animatedgraph-demo')
        .animatedGraph(200, 50, 20, 100, rotator.single, rotator.many, 1000);
});

Django application development

Author: nme · Sunday, 25 July, 2010 · No comments ·

Most developers work on their startups far away from the daylight — they keep it in complete secret till the end. I've decided to do something new — I have started a project which is available to preview during the whole development. It is available at urevs.com. I also share all the project info on dedicated blog: blog.urevs.com.

This project consists currently of authentication framework and a lot of backend solutions. Site allows users to login using OpenID's, Google, Twitter, Facebook or Yahoo Accounts. Full details are available here — social bootstrap engine for Django.

I'd be very glad to hear from You, about every suggestion You have.

urevs.com has been dropped. I've merged its functionality into this blog site but it is not currently available to public.