Twitter?

Date28 Jun 2011 ContentComments

It appears twitter decided to have a re-style once again as can be seen below;

2011

2010

2009

They also keep playing with the web theme as well, mainly the homepage which has changed twice this year and the login link colours which last week where orange but are now back to white.

I think they should focus more on scaling their API and web stack so that they can remove the API limits and increase the platform stability.

Things could change now they have purchased tweetdeck however this may just slowly replace the "official" twitter client.

The recent changes to send email notifications on events also seems to be a step backwards - they are moving things away from near-real time to slow time. The notifications also seem to be quite slow along with the search feeds which I hope they speed up soon.

The one notification I wouldn't mind getting via email is unfollow notifications, I currently rely on third-party services +a bunch of Perl for them.

Quick update

Date28 Jun 2011 ContentComments

Well, it has been a while.

Currently just merging wiki.damianzaremba.co.uk (most the stuff is hidden at the moment) and thegeekstop.net into this single blog.

Once everything is merged learnabouttheweb.co.uk and thegeekstop.net will point to damianzaremba.co.uk/blog/!

Apart from my tumblr account (which I post random pictures too) I don't see the point in having separate blogs all over the place.

Here will become my random content, how to, scripts and generally anything I get time to post about.

Some topics I'm trying to catch up on at the moment are:

  • Camping/outdoor skills

  • Bushcraft skills

  • New equipment

  • Tech items

  • Events

  • Other stuff...

I also intend to get the calendar up to date (it is missing a LOT of stuff at the moment but the first items on that to-do list are syncing up the scout calendars with the activity plans for the year. If I can find a decent video editing app/camera then I might start using you tube more for publishing content.

Currently quite busy as there is a lot of stuff going on, lots of ideas for next year and plans for this - will post more about them later.

Meth stove

Date28 Jun 2011 ContentComments

I saw pretty cool stove the other day and decided to have a go at it.

The final stove was a little messy but should work fine - I'm going to test it on Thursday and see if it works or not.

Some notes before starting that I found out the hard way:

  • Be careful once you start making cuts - You end up with tiny bits of metal that are very sharp.
  • File off the edges - It makes the metal easier to work with and stops you from slicing your fingers open.
  • Measure the height of your inner wall - It makes fitting the thing together much easier.
  • Don't slice down the side of the can when scoring off the bottoms - This makes it easier to get the bottoms off but means you need a spare can for the inner.
  • Be careful when making the holes in the top - I started out with a pin that made nice round holes then broke it so used a knife that made much bigger "slots".
  • When rolling your inner wall use a bit of tape - it will burn off later.

How to

First you are going to need:

  • 2 x Empty drinks cans
  • 1 x Very sharp knife
  • 1 x File
  • 1 x Saw (You could use your knife but a saw makes it easier)
  • 1 pair of scissors (Once again you could use your knife but this makes it easier)

Step1

Firstly take 1 empty can and turn it upside down so the end without a hole is at the top for you to work on.

Carefully punch a bunch of holes around the outside for burners and a few holes right in the middle for filling.

Make sure not to put the middle holes too close to the outside - you need enough space for the middle wall to separate the fuel.

You should end up with something like this...

Step2

Next you need to cut off the bottom of the can (the actual bottom, where you just made holes in). This will be the "top" of your burner.

An easy way is to clip your knife onto the back of a book then score around the outside.

Once you have a good score line take your saw and run it around to make a cut.

Then after you have just the bottom of the can left take your file and smooth off the top. If need be use your scissors/knife to trim off any crap.

Step3

Now you need to make an inner wall which fits around the "dip" in your burners top.

Slice down the side of the can (use the bit you just cut off) and remove the top of the can.

You should be left with basically the body of the can (you may need to use another can depending how big you cut the top of your stove)

Now roll it up to fit around the dip in your burners top and mark it with your knife.

Take a pair of scissors and cut it down to size then tape both ends just to hold it in place.

I taped it a little smaller than it needed to be then pushed it around the dip - this made a tight fit so the next step was easier.

Step4

Cut out some notches in the top of your inner wall - this will be where the fuel can flow though into the bottom of the burner.

You should end up with a circle of notches sticking out the top of your burner top.

Step5

Now to make the burner bottom, take another empty can and measure it against your burner top.

You want to make it about 1½ times the size of the burner top.

This will fit over your burner top and make the base of the burner where the fuel flows into.

Step6

Now we need to fix the bottom to the top.

You want to end up with your inner wall matching up with your little dip in the bottom of the burner as you did with the top.

You can use a spare piece of the side to help you ease the cans together.

You should get a really tight fit - I had to cut down and file off the outer can after as I did the measuring wrong.

Now you should basically have a can with an inner can - You put the fuel in the middle and it flows down to the bottom of the can where you can light it.

Footnotes

I've seen a few other people's stoves and they seem to cut them down to just under 2".

Mine ended up slightly bigger as can be seen below. I'm not sure how this will affect its performance but it should produce a better cooking height.

Another thing that was done differently was the number of burners - this will probably use more fuel but should produce a larger heat.

Other

I'm going to light this on Thursday and see if it works fine - It might explode or work fine. I think I slightly crimped the inner wall while fitting it together.

If it works fine I'll probably build another and document it better else I'll do a design review. As long as my phone doesn't die on me I'll try to get a video of lighting it which could turn out quite funny...

Update: The stove didn't work very well - upon lighting it the meths burnt off in a big puff of singed hair and wouldn't turn into anything more.

I'm guessing the holes where too big causes a massive rush of oxygen into the fuel "store" and it burning off very quickly.

I'll have another go at building one some time soon as I burnt this attempted (we had a reasonably sized fire, what else would you do) and let you know if it turns out any better.

Example of building nagios configs from LDAP

Date28 Jun 2011 ContentComments

Over at ClueNet we have a bunch of servers all stored in LDAP with owners and admins linked to user accounts also stored in LDAP! One thing we wanted to implement (as well as graphing, but cacti sorts that out) was service monitoring.

After getting a box up and a bot in IRC to relay stuff I set about hacking up a script to add in servers and add owners/admins as contacts (so they can get notifications and access the Nagios web interface to disable checks and stuff (it uses mod_auth_krb to let people login over HTTPS)).

Some notes about this script:

  • Currently we don't store attributes in the servers entry relating to what services to monitor, this is something I'm looking at implementing

  • IP addresses and SSH ports are stored in LDAP

  • Server owners AND admins should have access to update the server in Nagios (they do in LDAP!)

  • There is no attribute under the users entry to determine if we should notify them about alerts so we don't atm!

  • The only way people know about alerts is the relay channel on IRC or the web interface

The main thing I want to implement that would improve this script is per service attributes in the servers entry following the standard for ClueNet.

I propose the attribute clueServiceMonitoring be added into the ldap scheme and added to the servers entries.

An example is as below: Server: hex Services to be monitored:

  • ping (via ICMP)

  • ssh (will use port listed in LDAP)

  • http (port 8080)

  • ldap

  • kerberos


dn: cn=hex,ou=servers,dc=cluenet,dc=org
 changetype: modify
 add: clueServiceMonitoring
 clueServiceMonitoring: ping^ICMP

dn: cn=hex,ou=servers,dc=cluenet,dc=org
 changetype: modify
 add: clueServiceMonitoring
 clueServiceMonitoring: ssh

dn: cn=hex,ou=servers,dc=cluenet,dc=org
 changetype: modify
 add: clueServiceMonitoring
 clueServiceMonitoring: http^8080

dn: cn=hex,ou=servers,dc=cluenet,dc=org
 changetype: modify
 add: clueServiceMonitoring
 clueServiceMonitoring: ldap

dn: cn=hex,ou=servers,dc=cluenet,dc=org
 changetype: modify
 add: clueServiceMonitoring
 clueServiceMonitoring: kerberos

This would allow the script to check for the attributes and write out the services definitions as necessary. The current solution works but is a little inflexible.

Also, the Perl could do with tidying up a little as I'm not the best Perl programmer on the planet.

#!/usr/bin/env perl
use strict;
use File::Path;
use Net::LDAP;
use Data::Dumper;

# Config stuff
my $base_dir = "/usr/local/nagios/etc/cluenet/";

# Main code
my $ldap = Net::LDAP->new("ldap.cluenet.org", timeout => 30);
if(!$ldap) {
    print "Could not connect to ldap\n";
}

print "Clearing current configs\n";
rmtree($base_dir);
mkdir($base_dir);

my @admins = ();
my @owners = ();
my $mesg = $ldap->search(
    filter => "(&(objectClass=server)(isActive=TRUE))",
    base => "ou=servers,dc=cluenet,dc=org"
);
my @entries = $mesg->entries;

print "Starting server configs\n";
foreach (@entries) {
    my $entry = $_;
    print "Starting " . $entry->get_value('cn') . "\n";

    my $hostname = $entry->get_value('cn');
    if(!$hostname) {
        print "Skipping - missing hostname\n";
        next;
    }

    my $servername = $hostname;
    $servername =~ s/\.cluenet\.org$//;

    my $owner = $entry->get_value('owner');
    $owner =~ s/uid=(.*),ou=people,dc=cluenet,dc=org/$1/;

    if(!$owner) {
        print "Skipping - missing owner\n";
        next;
    }

    my $ip_address = $entry->get_value('ipAddress');
    if(!$ip_address) {
        print "Skipping - missing ip address\n";
        next;
    }

    my $ssh_port = $entry->get_value('sshPort');

    my $description = $entry->get_value('description');
    if(!$description) {
        $description = "";
    }

    my $os = $entry->get_value('operatingSystem');
    if(!$os) {
        $os = 'linux'; # windows sux
    }

    open(FH, ">", "$base_dir/$hostname.cfg");
    # Write the host out
    print FH <define host {
    host_name $hostname
    alias $servername
    address $ip_address
    hostgroups $owner\_servers
    max_check_attempts 5
    check_period 24x7
    contacts $owner
    contact_groups $servername\_admins
    notification_period 24x7
}

EOS
;

    # Write out the services
    # - I'd like these to be ldap attributes but I'm not sure how we can do shit for now so hardcoding
    print "Adding ping check\n";
    print FH <define service {
    host_name $hostname
    service_description PING check
    notification_period 24x7
    check_period 24x7
    max_check_attempts 3
    normal_check_interval 5
    retry_check_interval 1
    notification_interval 30
    notification_options w,u,c,r,f,s
    check_command check_ping!100.0,20%!500.00,60%
}

EOS
;

    if(grep(/windows/i, $os)) {

    } else {
        if($ssh_port) {
            print "Adding SSH check on port $ssh_port\n";
            print FH <get_value('authorizedAdministrator')) {
        my $user = $_;
        $user =~ s/uid=(.*),ou=people,dc=cluenet,dc=org/$1/;
        $members = $members . ", " . $user;

        if(!grep(/$user/, @admins)) {
            push(@admins, $user);
        }
    }

    print FH <get_value('cn') . "\n";
}
print "Finished server configs\n";

print "Starting user config\n";
open(FH, ">", "$base_dir/users.cfg");
print "Adding __nagiosbot__\n";
print FH <define contact {
    contact_name __nagiosbot__
    alias General nagios bot
    host_notification_period 24x7
    service_notification_period 24x7
    host_notification_commands host-notify-by-irc
    service_notification_commands notify-by-irc

}
EOS
;

foreach(@admins) {
    print "Adding user $_ \n";
    print FH <search(
        filter => "(&(objectClass=person)(uid=" . $_ . "))",
        base => "ou=people,dc=cluenet,dc=org"
    );

    foreach($mesg->entries) {
        my $entry = $_;

        my $gecos = $entry->get_value('gecos');
        if($gecos) {
            print FH "\talias $gecos\n";
        }

        my $mail = $entry->get_value('mail');
        if($mail) {
            print FH "#\temail $mail\n";
        }
    }
    print FH <}

EOS
;
}

foreach(@owners) {
    print FH <define hostgroup {
    hostgroup_name $_\_servers
    alias $_\'s servers
}

EOS
;
}

close(FH);
print "Finished user config\n";

print "Reloading\n";
`/etc/init.d/nagios reload`

Download festival hack

I didn't make it to download this year but the pictures look awesome, before they disappear into nowhere I wanted to grab a copy so I hacked up a bit of Python to do some scraping and it works (not very well, but it was more of a 5min thing rather than a let's make a good job of it thing.). Script is as below:

#!/usr/bin/env python
'''
Uber hack to download images from download website, kinda works.
Very messy as I ripped most the code out of other scripts I've written.
'''
import os
import urllib
import hashlib
import threading
import Queue
import urlparse
from BeautifulSoup import BeautifulSoup
base_dir = '/home/damian/Pictures/download-2011'

def get_total_pages():
 uh = urllib.urlopen("http://photos.downloadfestival.co.uk/view/")
 soup = BeautifulSoup(uh)
 uh.close()

count = str(soup.find("div", {"class": "page_count"}).string.strip())
 count = int(count.replace('Page 1 of ', ''))
 return count

def get_images(page):
 images = []
 uh = urllib.urlopen("http://photos.downloadfestival.co.uk/view/?page=%d" % page)
 soup = BeautifulSoup(uh)
 uh.close()

r = soup.find("ul", {"class": "item_list"})
 for sr in r.findAll("li"):
 image = sr.a.img['src']
 images.append(image)
 return images

class Runner(threading.Thread):
 def __init__(self, queue):
 threading.Thread.__init__(self)
 self.queue = queue

def run(self):
 while True:
 url = self.queue.get()
 self.get_image(url)
 self.queue.task_done()

def get_image(self, url):
 urldata = urlparse.urlparse(url)

ext = '.'.join(urldata.path.split('.')[-1:])
 file_name = "%s.%s" % (hashlib.md5(url).hexdigest(), ext)
 file_path = os.path.join(base_dir, file_name)

uh = urllib.urlopen(url)
 fh = open(file_path, 'w')
 fh.write(uh.read())
 fh.close()
 uh.close()
 print "Downloaded image to %s" % file_path

if __name__ == "__main__":
 if not os.path.isdir(base_dir):
 os.makedirs(base_dir)

total = get_total_pages()
 images = []

print "%d pages found" % total
 for p in range(1, total):
 print "Processing page %d" % p
 i = get_images(p)

print "Found %d images" % len(i)
 images.extend(i)

 print "Downloading %d images" % len(images)
 queue = Queue.Queue()
 for i in range(20):
 thread = Runner(queue)
 thread.setDaemon(True)
 thread.start()

for image in images:
 queue.put(image)
 queue.join()