In my quest for the perfect network setup for a VM here is a piece of
code that will allocate mac addresses from a pool.

It's not that polished yet. So far you can only allocate based on the
pool:

  fe:fd:12:aa:bb:cc

where aa:bb:cc are the pool. However, that is 17 million different mac
addresses so it's quite a lot.

The code forms a REST webservice that accepts a POST to / and responds
with a Location header indicating the new mac address.

That mac address resources accept a DELETE to return the address to
the pool.

There are other options that define a client for the webservice.

So the idea is that you do this on 'someserver':

  python macserv.py start

and then later, when you want to start a VM:

  MACADDR=`python macserv.py clientpost someserver 8000`
  ./umlkernel ubda=fs eth0=tuntap,,$MACADDR ...

and when the VM stops you do:

  python macserv.py clientdelete $MACADDR someserver 8000

This doesn't help you discover IP addresses (my other obsession) but
it does deletgate control over macs to a central point. Obtaining a
mac is such an infrequent operation (I have some apps where VMs are
highly disposable but I still don't create macs that often) that a
single server like this could easily handle a network of hundreds of
machines.

If anyone uses it let me know... my personal publishing systems (for
code and such) are in a little bit of flux right now but it will go
into source control eventually.

-- 
Nic Ferrier
http://www.tapsellferrier.co.uk   for all your tapsell ferrier needs

#!/usr/bin/python


import BaseHTTPServer
import os
import os.path
import shutil
import sys
import re
import urllib
import logging
import dbhash
import time


# This should be a param
# It indicates what byte follows fe:fd in the mac address; eg: fe:fd:12:aa:bb:cc
mac_3rd_byte=12

# The map of allocated MACs; we use mac: time-allocated
allocated_map = None
freed_map = None

def init_mac_seed():
    global allocated_map
    keys = allocated_map.keys()
    if len(keys) == 0:
        return 0
    else:
        keys.sort(lambda a,b: cmp(allocated_map[a], allocated_map[b]))
        last_mac = keys[-1]
        mac_re = "fe:fd:([0-9a-fA-F]{2})((:([0-9a-fA-F]{2})){3})"
        last_id = int("".join(re.split(":", re.match(mac_re, last_mac).groups()[1])), 16)
        return last_id 

# Default for the first mac address
id = None

def next_mac():
    global id
    global mac_3rd_byte
    global allocated_map
    global freed_map
    freed_keys = freed_map.keys()
    if len(freed_keys):
        mac, t = freed_map.popitem()
        return mac
    else:
        id = id + 1
        mac_end = ":".join(filter(lambda x: not(x == ''), re.split("(.{2})", "%06x" % (id))))
        mac = "fe:fd:%s:%s" % (mac_3rd_byte, mac_end)
        allocated_map[mac] = "%f" % (time.time())
        return mac

def mark_free(mac):
    global allocated_map
    try:
        print mac
        allocated_map[mac]
    except KeyError:
        return False
    else:
        global freed_map
        freed_map[mac] = "%f" % (time.time())
        allocated_map.pop(mac)
        return True


# The HTTP server we're using
# It implements a simple REST service for acquiring and returning a MAC address
class MACSERVEHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    """XRT http handler."""

    def handle_one_request(self):
        """Handle a single HTTP request. Pinched from XRT and before that, python."""

        self.raw_requestline = self.rfile.readline()
        if not self.raw_requestline:
            self.close_connection = 1
            return

        if not self.parse_request(): # An error code has been sent, just exit
            return

        if self.command == "POST":
            the_mac_address = next_mac()
            self.send_response(201, "Created")
            self.send_header("Location", "/" + the_mac_address)
            self.end_headers()
            
        elif self.command == "DELETE":
            # Needs to return the resource to be deleted... where is the resource?
            the_mac_address = self.path.strip("/")
            # Check that we think the mac is assigned

            if mark_free(the_mac_address):
                self.send_response(204, "Deleted")
                self.end_headers()
            else:
                self.send_error(500, "Not assigned")

        else:
            self.send_error(500, "bad HTTP method")

        return


def run(HandlerClass = MACSERVEHTTPRequestHandler,
        ServerClass = BaseHTTPServer.HTTPServer):
    BaseHTTPServer.test(HandlerClass, ServerClass)
    return



if __name__ == '__main__':
    import pdb
    import sys

    def runit():
        global allocated_map
        global freed_map
        global id
        allocated_map = dbhash.open("/var/run/macserve_allocated.dbm", "c")
        freed_map = dbhash.open("/var/run/macserve_freed.dbm", "c")
        id = init_mac_seed()
        run()        

    if sys.argv[1] == "run":
        sys.argv=[]  # for some reason the stupid BaseHTTPServer reads argv by default
        pdb.runcall(runit)

    elif sys.argv[1] == "start":
        ret = os.fork()
        if ret == 0:
            sys.argv=[]  # for some reason the stupid BaseHTTPServer reads argv by default
            runit()
        else:
            pidfile = open("/var/run/macserver", "w")
            pidfile.write("%s" % (ret))
            pidfile.close()

    elif sys.argv[1] == "stop":
        if os.path.exists("/var/run/macserver"):
            pidfile = open("/var/run/macserver")
            pid = int(pidfile.read().strip())
            os.kill(pid, 3)

    elif sys.argv[1] == "clientpost":
        import httplib
        httpcon = httplib.HTTPConnection(sys.argv[2], int(sys.argv[3]))
        try:
            httpcon.request("POST", "/")
            resp = httpcon.getresponse()
            if resp.status == 201:
                print resp.getheader("Location").split("/")[-1]
            else:
                print >>sys.stderr, resp.reason
        finally:
            httpcon.close()

    elif sys.argv[1] == "clientdelete":
        import httplib
        httpcon = httplib.HTTPConnection(sys.argv[3], int(sys.argv[4]))
        try:
            httpcon.request("DELETE", "/" + sys.argv[2])
            resp = httpcon.getresponse()
            if resp.status != 204:
                print >>sys.stderr, resp.reason
        finally:
            httpcon.close()

# End
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
User-mode-linux-user mailing list
User-mode-linux-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/user-mode-linux-user

Reply via email to