← Back to team overview

linaro-release team mailing list archive

[Merge] lp:~mwhudson/lava-dispatcher/config-clients-merge into lp:lava-dispatcher

 

Michael Hudson-Doyle has proposed merging lp:~mwhudson/lava-dispatcher/config-clients-merge into lp:lava-dispatcher.

Requested reviews:
  Linaro Validation Team (linaro-validation)

For more details, see:
https://code.launchpad.net/~mwhudson/lava-dispatcher/config-clients-merge/+merge/74712

Finally, ready enough for a review!  I need to update some things in the doc/ directory, hopefully I'll get to that later today.

Reviewers should start by looking at the lava_scheduler/default-config directory.  Is that what you would like the config files to look like?  If not, please yell :-)

I'm more or less happy with the rest of the code.  The config.py changes are rather hackish, but heck, they work.

I will prepare branches adding the qemu and ssh clients when I've managed to get them to work :-) 
-- 
https://code.launchpad.net/~mwhudson/lava-dispatcher/config-clients-merge/+merge/74712
Your team Linaro Validation Team is requested to review the proposed merge of lp:~mwhudson/lava-dispatcher/config-clients-merge into lp:lava-dispatcher.
=== modified file '.bzrignore'
--- .bzrignore	2011-04-07 01:21:51 +0000
+++ .bzrignore	2011-09-09 01:07:35 +0000
@@ -3,3 +3,6 @@
 ./.virtualenv
 ./bin
 ./lava.egg-info
+./dist
+./lava_dispatcher.egg-info
+./build

=== added file 'MANIFEST.in'
--- MANIFEST.in	1970-01-01 00:00:00 +0000
+++ MANIFEST.in	2011-09-09 01:07:35 +0000
@@ -0,0 +1,2 @@
+include README
+recursive-include lava_dispatcher/default-config *.conf
\ No newline at end of file

=== modified file 'lava_dispatcher/__init__.py'
--- lava_dispatcher/__init__.py	2011-09-08 22:12:27 +0000
+++ lava_dispatcher/__init__.py	2011-09-09 01:07:35 +0000
@@ -27,16 +27,19 @@
 import pexpect
 
 from lava_dispatcher.actions import get_all_cmds
+from lava_dispatcher.config import get_config, get_device_config
 from lava_dispatcher.client import LavaClient, CriticalError, GeneralError
 from lava_dispatcher.android_client import LavaAndroidClient
 
-__version__ = "0.2.2"
+__version__ = "0.3a1"
 
 class LavaTestJob(object):
     def __init__(self, job_json, oob_file):
         self.job_status = 'pass'
         self.load_job_data(job_json)
-        self.context = LavaContext(self.target, self.image_type, oob_file)
+        dispatcher_config = get_config("lava-dispatcher")
+        self.context = LavaContext(
+            self.target, self.image_type, dispatcher_config, oob_file)
 
     def load_job_data(self, job_json):
         self.job_data = json.loads(job_json)
@@ -76,6 +79,7 @@
                 else:
                     status = 'pass'
                 finally:
+                    err_msg = ""
                     if status == 'fail':
                         err_msg = "Lava failed at action %s with error: %s\n" %\
                                   (cmd['command'], err)
@@ -102,11 +106,17 @@
 
 
 class LavaContext(object):
-    def __init__(self, target, image_type, oob_file):
-        if image_type != "android":
-            self._client = LavaClient(target)
+    def __init__(self, target, image_type, dispatcher_config, oob_file):
+        self.config = dispatcher_config
+        device_config = get_device_config(target)
+        if device_config.get('client_type') != 'serial':
+            raise RuntimeError(
+                "this version of lava-dispatcher only supports serial "
+                "clients, not %r" % device_config.get('client_type'))
+        if image_type == "android":
+            self._client = LavaAndroidClient(self, device_config)
         else:
-            self._client = LavaAndroidClient(target)
+            self._client = LavaClient(self, device_config)
         self.test_data = LavaTestData()
         self.oob_file = oob_file
 
@@ -114,6 +124,26 @@
     def client(self):
         return self._client
 
+    @property
+    def lava_server_ip(self):
+        return self.config.get("LAVA_SERVER_IP")
+
+    @property
+    def lava_image_tmpdir(self):
+        return self.config.get("LAVA_IMAGE_TMPDIR")
+
+    @property
+    def lava_image_url(self):
+        return self.config.get("LAVA_IMAGE_URL")
+
+    @property
+    def lava_result_dir(self):
+        return self.config.get("LAVA_RESULT_DIR")
+
+    @property
+    def lava_cachedir(self):
+        return self.config.get("LAVA_CACHEDIR")
+
 
 class LavaTestData(object):
     def __init__(self, test_id='lava'):

=== modified file 'lava_dispatcher/actions/android_basic.py'
--- lava_dispatcher/actions/android_basic.py	2011-09-02 03:00:59 +0000
+++ lava_dispatcher/actions/android_basic.py	2011-09-09 01:07:35 +0000
@@ -60,7 +60,7 @@
             test_case_result['result'] = "fail"
 
         results['test_results'].append(test_case_result)
-        savebundlefile("monkey", results, timestring)
+        savebundlefile("monkey", results, timestring, self.context.lava_result_dir)
         self.client.proc.sendline("")
 
 
@@ -146,5 +146,5 @@
             test_case_result['result'] = "fail"
 
         results['test_results'].append(test_case_result)
-        savebundlefile("basic", results, timestring)
+        savebundlefile("basic", results, timestring, self.context.lava_result_dir)
         self.client.proc.sendline("")

=== modified file 'lava_dispatcher/actions/android_deploy.py'
--- lava_dispatcher/actions/android_deploy.py	2011-09-05 21:52:35 +0000
+++ lava_dispatcher/actions/android_deploy.py	2011-09-09 01:07:35 +0000
@@ -20,7 +20,6 @@
 # along with this program; if not, see <http://www.gnu.org/licenses>.
 
 from lava_dispatcher.actions import BaseAction
-from lava_dispatcher.config import LAVA_IMAGE_TMPDIR, LAVA_IMAGE_URL
 import os
 import sys
 import shutil
@@ -31,6 +30,8 @@
 
 class cmd_deploy_linaro_android_image(BaseAction):
     def run(self, boot, system, data, use_cache=True):
+        LAVA_IMAGE_TMPDIR = self.context.lava_image_tmpdir
+        LAVA_IMAGE_URL = self.context.lava_image_url
         client = self.client
         print "deploying Android on %s" % client.hostname
         print "  boot: %s" % boot
@@ -85,14 +86,16 @@
         :param data_url: url of the Linaro Android data tarball to download
         :param use_cache: whether or not to use the cached copy (if it exists)
         """
+        lava_cachedir = self.context.lava_cachedir
+        LAVA_IMAGE_TMPDIR = self.context.lava_image_tmpdir
         self.tarball_dir = mkdtemp(dir=LAVA_IMAGE_TMPDIR)
         tarball_dir = self.tarball_dir
         os.chmod(tarball_dir, 0755)
 
         if use_cache:
-            boot_path = download_with_cache(boot_url, tarball_dir)
-            system_path = download_with_cache(system_url, tarball_dir)
-            data_path = download_with_cache(data_url, tarball_dir)
+            boot_path = download_with_cache(boot_url, tarball_dir, lava_cachedir)
+            system_path = download_with_cache(system_url, tarball_dir, lava_cachedir)
+            data_path = download_with_cache(data_url, tarball_dir, lava_cachedir)
         else:
             boot_path = download(boot_url, tarball_dir)
             system_path = download(system_url, tarball_dir)

=== modified file 'lava_dispatcher/actions/deploy.py'
--- lava_dispatcher/actions/deploy.py	2011-09-08 04:23:59 +0000
+++ lava_dispatcher/actions/deploy.py	2011-09-09 01:07:35 +0000
@@ -26,13 +26,14 @@
 from tempfile import mkdtemp
 
 from lava_dispatcher.actions import BaseAction
-from lava_dispatcher.config import LAVA_IMAGE_TMPDIR, LAVA_IMAGE_URL
 from lava_dispatcher.utils import download, download_with_cache
 from lava_dispatcher.client import CriticalError
 
 
 class cmd_deploy_linaro_image(BaseAction):
     def run(self, hwpack, rootfs, use_cache=True):
+        LAVA_IMAGE_TMPDIR = self.context.lava_image_tmpdir
+        LAVA_IMAGE_URL = self.context.lava_image_url
         client = self.client
         print "deploying on %s" % client.hostname
         print "  hwpack: %s" % hwpack
@@ -112,30 +113,31 @@
         :param hwpack_url: url of the Linaro hwpack to download
         :param rootfs_url: url of the Linaro image to download
         """
+        lava_cachedir = self.context.lava_cachedir
+        LAVA_IMAGE_TMPDIR = self.context.lava_image_tmpdir
         client = self.client
         self.tarball_dir = mkdtemp(dir=LAVA_IMAGE_TMPDIR)
         tarball_dir = self.tarball_dir
         os.chmod(tarball_dir, 0755)
         if use_cache:
-            hwpack_path = download_with_cache(hwpack_url, tarball_dir)
-            rootfs_path = download_with_cache(rootfs_url, tarball_dir)
+            hwpack_path = download_with_cache(hwpack_url, tarball_dir, lava_cachedir)
+            rootfs_path = download_with_cache(rootfs_url, tarball_dir, lava_cachedir)
         else:
             hwpack_path = download(hwpack_url, tarball_dir)
             rootfs_path = download(rootfs_url, tarball_dir)
 
         image_file = os.path.join(tarball_dir, "lava.img")
-        board = client.board
         cmd = ("sudo linaro-media-create --hwpack-force-yes --dev %s "
                "--image_file %s --binary %s --hwpack %s --image_size 3G" %
-               (board.type, image_file, rootfs_path, hwpack_path))
+               (client.device_type, image_file, rootfs_path, hwpack_path))
         rc, output = getstatusoutput(cmd)
         if rc:
             shutil.rmtree(tarball_dir)
             tb = traceback.format_exc()
             client.sio.write(tb)
             raise RuntimeError("linaro-media-create failed: %s" % output)
-        boot_offset = self._get_partition_offset(image_file, board.boot_part)
-        root_offset = self._get_partition_offset(image_file, board.root_part)
+        boot_offset = self._get_partition_offset(image_file, client.boot_part)
+        root_offset = self._get_partition_offset(image_file, client.root_part)
         boot_tgz = os.path.join(tarball_dir, "boot.tgz")
         root_tgz = os.path.join(tarball_dir, "root.tgz")
         try:
@@ -159,7 +161,7 @@
         client.run_cmd_master('mount /dev/disk/by-label/testrootfs /mnt/root')
         client.run_cmd_master(
             'wget -qO- %s |tar --numeric-owner -C /mnt/root -xzf -' % rootfs,
-            timeout = 3600)
+            timeout=3600)
         client.run_cmd_master('echo linaro > /mnt/root/etc/hostname')
         #DO NOT REMOVE - diverting flash-kernel and linking it to /bin/true
         #prevents a serious problem where packages getting installed that

=== modified file 'lava_dispatcher/actions/launch_control.py' (properties changed: +x to -x)
--- lava_dispatcher/actions/launch_control.py	2011-09-06 09:35:13 +0000
+++ lava_dispatcher/actions/launch_control.py	2011-09-09 01:07:35 +0000
@@ -25,8 +25,6 @@
 import shutil
 import tarfile
 from lava_dispatcher.actions import BaseAction
-from lava_dispatcher.config import LAVA_RESULT_DIR
-from lava_dispatcher.config import LAVA_IMAGE_TMPDIR
 from lava_dispatcher.client import NetworkError
 from lava_dispatcher.utils import download
 from tempfile import mkdtemp
@@ -40,9 +38,9 @@
                 allow_none=True, use_datetime=True)
 
         #Upload bundle files to dashboard
-        bundle_list = os.listdir("/tmp/%s" % LAVA_RESULT_DIR)
+        bundle_list = os.listdir("/tmp/%s" % self.context.lava_result_dir)
         for bundle_name in bundle_list:
-            bundle = "/tmp/%s/%s" % (LAVA_RESULT_DIR, bundle_name)
+            bundle = "/tmp/%s/%s" % (self.context.lava_result_dir, bundle_name)
             f = open(bundle)
             content = f.read()
             f.close()
@@ -53,6 +51,7 @@
                 print "xmlrpclib.Fault occurred"
                 print "Fault code: %d" % err.faultCode
                 print "Fault string: %s" % err.faultString
+
             # After uploading, remove the bundle file at the host side
             os.remove(bundle)
 
@@ -79,49 +78,50 @@
         client.run_cmd_master('mkdir -p /mnt/root')
         client.run_cmd_master(
             'mount /dev/disk/by-label/%s /mnt/root' % result_disk)
-        client.run_cmd_master('mkdir -p /tmp/%s' % LAVA_RESULT_DIR)
+        client.run_cmd_master('mkdir -p /tmp/%s' % self.context.lava_result_dir)
         client.run_cmd_master(
-            'cp /mnt/root/%s/*.bundle /tmp/%s' % (LAVA_RESULT_DIR,
-                LAVA_RESULT_DIR))
+            'cp /mnt/root/%s/*.bundle /tmp/%s' % (self.context.lava_result_dir,
+                self.context.lava_result_dir))
         client.run_cmd_master('umount /mnt/root')
 
         #Create tarball of all results
         client.run_cmd_master('cd /tmp')
         client.run_cmd_master(
-            'tar czf /tmp/lava_results.tgz -C /tmp/%s .' % LAVA_RESULT_DIR)
+            'tar czf /tmp/lava_results.tgz -C /tmp/%s .' % self.context.lava_result_dir)
 
         master_ip = client.get_master_ip()
-        if master_ip != None:
-            # Set 80 as server port
-            client.run_cmd_master('python -m SimpleHTTPServer 80 &> /dev/null &')
-            time.sleep(3)
-
-            result_tarball = "http://%s/lava_results.tgz"; % master_ip
-            tarball_dir = mkdtemp(dir=LAVA_IMAGE_TMPDIR)
-            os.chmod(tarball_dir, 0755)
-
-            # download test result with a retry mechanism
-            # set retry timeout to 2mins
-            now = time.time()
-            timeout = 120
-            while time.time() < now+timeout:
-                try:
-                    result_path = download(result_tarball, tarball_dir)
-                except:
-                    if time.time() >= now+timeout:
-                        raise
-
-            client.run_cmd_master('kill %1')
-
-            tar = tarfile.open(result_path)
-            for tarinfo in tar:
-                if os.path.splitext(tarinfo.name)[1] == ".bundle":
-                    f = tar.extractfile(tarinfo)
-                    content = f.read()
-                    f.close()
-                    self.all_bundles.append(json.loads(content))
-            tar.close()
-            shutil.rmtree(tarball_dir)
+        if master_ip == None:
+            raise NetworkError("Getting master image IP address failed")
+        # Set 80 as server port
+        client.run_cmd_master('python -m SimpleHTTPServer 80 &> /dev/null &')
+        time.sleep(3)
+
+        result_tarball = "http://%s/lava_results.tgz"; % master_ip
+        tarball_dir = mkdtemp(dir=self.context.lava_image_tmpdir)
+        os.chmod(tarball_dir, 0755)
+
+        # download test result with a retry mechanism
+        # set retry timeout to 2mins
+        now = time.time()
+        timeout = 120
+        while time.time() < now+timeout:
+            try:
+                result_path = download(result_tarball, tarball_dir)
+            except:
+                if time.time() >= now+timeout:
+                    raise
+
+        client.run_cmd_master('kill %1')
+
+        tar = tarfile.open(result_path)
+        for tarinfo in tar:
+            if os.path.splitext(tarinfo.name)[1] == ".bundle":
+                f = tar.extractfile(tarinfo)
+                content = f.read()
+                f.close()
+                self.all_bundles.append(json.loads(content))
+        tar.close()
+        shutil.rmtree(tarball_dir)
 
         #flush the serial log
         client.run_shell_command("")

=== modified file 'lava_dispatcher/actions/lava-test.py' (properties changed: +x to -x)
--- lava_dispatcher/actions/lava-test.py	2011-09-08 04:23:59 +0000
+++ lava_dispatcher/actions/lava-test.py	2011-09-09 01:07:35 +0000
@@ -24,7 +24,7 @@
 import traceback
 from lava_dispatcher.actions import BaseAction
 from lava_dispatcher.client import OperationFailed
-from lava_dispatcher.config import LAVA_RESULT_DIR, MASTER_STR
+
 
 
 def _setup_testrootfs(client):
@@ -50,10 +50,9 @@
         'cp -f /mnt/root/etc/resolv.conf.bak /mnt/root/etc/resolv.conf')
     cmd = ('cat /proc/mounts | awk \'{print $2}\' | grep "^/mnt/root/dev"'
         '| sort -r | xargs umount')
-    client.run_cmd_master(
-        cmd)
-    client.run_cmd_master(
-        'umount /mnt/root')
+    client.run_cmd_master(cmd)
+    client.run_cmd_master('umount /mnt/root')
+
 
 
 def _install_lava_test(client):
@@ -73,11 +72,10 @@
         client.run_shell_command(
             'chroot /mnt/root lava-test help',
             response="list-test", timeout=10)
-        client.proc.expect(MASTER_STR, timeout=10)
+        client.proc.expect(client.master_str, timeout=10)
     except:
         tb = traceback.format_exc()
         client.sio.write(tb)
-        _teardown_testrootfs(client)
         raise OperationFailed("lava-test deployment failed")
 
 
@@ -86,12 +84,12 @@
         #Make sure in test image now
         client = self.client
         client.in_test_shell()
-        client.run_cmd_tester('mkdir -p %s' % LAVA_RESULT_DIR)
+        client.run_cmd_tester('mkdir -p %s' % self.context.lava_result_dir)
         client.export_display()
         bundle_name = test_name + "-" + datetime.now().strftime("%H%M%S")
         client.run_cmd_tester(
             'lava-test run %s -o %s/%s.bundle' % (
-                test_name, LAVA_RESULT_DIR, bundle_name),
+                test_name, self.context.lava_result_dir, bundle_name),
             timeout=timeout)
 
 

=== modified file 'lava_dispatcher/android_client.py'
--- lava_dispatcher/android_client.py	2011-09-08 04:23:59 +0000
+++ lava_dispatcher/android_client.py	2011-09-09 01:07:35 +0000
@@ -20,12 +20,9 @@
 import pexpect
 import sys
 from lava_dispatcher.client import LavaClient, OperationFailed
-from lava_dispatcher.android_config import BOARDS, TESTER_STR
+from utils import string_to_list
 
 class LavaAndroidClient(LavaClient):
-    def __init__(self, hostname):
-        super(LavaAndroidClient, self).__init__(hostname)
-        self.board = BOARDS[hostname]
 
     def run_adb_shell_command(self, dev_id, cmd, response, timeout=-1):
         adb_cmd = "adb -s %s shell %s" % (dev_id, cmd)
@@ -42,7 +39,7 @@
         """ Check that we are in a shell on the test image
         """
         self.proc.sendline("")
-        id = self.proc.expect([TESTER_STR , pexpect.TIMEOUT])
+        id = self.proc.expect([self.tester_str , pexpect.TIMEOUT])
         if id == 1:
             raise OperationFailed
 
@@ -55,11 +52,11 @@
         except:
             self.hard_reboot()
             self.enter_uboot()
-        uboot_cmds = self.board.uboot_cmds
-        self.proc.sendline(uboot_cmds[0])
-        for line in range(1, len(uboot_cmds)):
+        boot_cmds = string_to_list(self.config.get('boot_cmds_android'))
+        self.proc.sendline(boot_cmds[0])
+        for line in range(1, len(boot_cmds)):
             self.proc.expect("#")
-            self.proc.sendline(uboot_cmds[line])
+            self.proc.sendline(boot_cmds[line])
         self.in_test_shell()
         self.proc.sendline("export PS1=\"root@linaro: \"")
 
@@ -106,7 +103,7 @@
 
     def check_adb_status(self):
         # XXX: IP could be assigned in other way in the validation farm
-        network_interface = self.board.default_network_interface 
+        network_interface = self.default_network_interface
         try:
             self.run_cmd_tester(
                 'netcfg %s dhcp' % network_interface, timeout=60)

=== removed file 'lava_dispatcher/android_config.py'
--- lava_dispatcher/android_config.py	2011-08-16 00:15:08 +0000
+++ lava_dispatcher/android_config.py	1970-01-01 00:00:00 +0000
@@ -1,65 +0,0 @@
-# Copyright (C) 2011 Linaro Limited
-#
-# Author: Linaro Validation Team <linaro-dev@xxxxxxxxxxxxxxxx>
-#
-# This file is part of LAVA Dispatcher.
-#
-# LAVA Dispatcher is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# LAVA Dispatcher is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, see <http://www.gnu.org/licenses>.
-
-from lava_dispatcher.config import Board
-
-class BeagleBoard(Board):
-    uboot_cmds = ["mmc init",
-        "mmc part 0",
-        "setenv bootcmd 'fatload mmc 0:3 0x80000000 uImage;"
-        "fatload mmc 0:3 0x81600000 uInitrd;"
-        "bootm 0x80000000 0x81600000'",
-        "setenv bootargs 'console=tty0 console=ttyO2,115200n8 "
-        "rootwait rw earlyprintk fixrtc nocompcache "
-        "vram=12M omapfb.debug=y omapfb.mode=dvi:1280x720MR-16@60 "
-        "init=/init androidboot.console=ttyO2'",
-        "boot"]
-    type = "beagle"
-
-
-class PandaBoard(Board):
-    uboot_cmds = ["mmc init",
-        "mmc part 0",
-        "setenv bootcmd 'fatload mmc 0:3 0x80200000 uImage;"
-        "fatload mmc 0:3 0x81600000 uInitrd;"
-        "bootm 0x80200000 0x81600000'",
-        "setenv bootargs 'console=tty0 console=ttyO2,115200n8 "
-        "rootwait rw earlyprintk fixrtc nocompcache vram=32M "
-        "omapfb.vram=0:8M mem=456M@0x80000000 mem=512M@0xA0000000 "
-        "omapfb.debug=y omapfb.mode=dvi:1280x720MR-16@60 "
-        "init=/init androidboot.console=ttyO2'",
-        "boot"]
-    type = "panda"
-
-
-#Here, it still needs to maintain a map from boardid to board, for there is only
-#boardid in jobfile.json
-BOARDS = {
-        "beagle01": BeagleBoard,
-        "beagle02": BeagleBoard,
-        "beagle03": BeagleBoard,
-        "beagle04": BeagleBoard,
-        "panda01": PandaBoard,
-        "panda02": PandaBoard,
-        "panda03": PandaBoard,
-        "panda04": PandaBoard,
-        }
-
-#Test image recognization string
-TESTER_STR = "root@linaro:"

=== modified file 'lava_dispatcher/android_util.py'
--- lava_dispatcher/android_util.py	2011-06-27 04:55:08 +0000
+++ lava_dispatcher/android_util.py	2011-09-09 01:07:35 +0000
@@ -22,11 +22,10 @@
 from datetime import datetime
 import json
 import subprocess
-from lava_dispatcher.config import LAVA_RESULT_DIR
 import time
 
 # TODO: Result saving could be replaced by linaro_dashboard_bundle probably.
-def savebundlefile(testname, results, starttime):
+def savebundlefile(testname, results, starttime, lava_result_dir):
     """
     Save results as .bundle file under /tmp/LAVA_RESULT_DIR/
     """
@@ -42,9 +41,9 @@
     testdata['test_runs'] = test_runs
     testdata['test_runs'][0].update(results)
     bundle = testdata
-    subprocess.call(["mkdir", "-p", "/tmp/%s" % LAVA_RESULT_DIR])
+    subprocess.call(["mkdir", "-p", "/tmp/%s" % lava_result_dir])
     # The file name should be unique to be distinguishable from others
-    filename = "/tmp/%s/" % LAVA_RESULT_DIR + testname + \
+    filename = "/tmp/%s/" % lava_result_dir + testname + \
         str(time.mktime(datetime.utcnow().timetuple())) + ".bundle"
     with open(filename, "wt") as stream:
         json.dump(bundle, stream)

=== modified file 'lava_dispatcher/client.py'
--- lava_dispatcher/client.py	2011-09-08 04:23:59 +0000
+++ lava_dispatcher/client.py	2011-09-09 01:07:35 +0000
@@ -22,35 +22,56 @@
 import sys
 import time
 from cStringIO import StringIO
-
-from lava_dispatcher.config import (
-    BOARDS,
-    LAVA_SERVER_IP,
-    MASTER_STR,
-    TESTER_STR,
-    )
-
+from utils import string_to_list
 
 class LavaClient(object):
-    def __init__(self, hostname):
-        self._master_str = MASTER_STR
-        self._tester_str = TESTER_STR
-        cmd = "conmux-console %s" % hostname
+    def __init__(self, context, config):
+        self.context = context
+        self.config = config
+        cmd = "conmux-console %s" % self.hostname
         self.sio = SerialIO(sys.stdout)
         self.proc = pexpect.spawn(cmd, timeout=3600, logfile=self.sio)
         #serial can be slow, races do funny things if you don't increase delay
         self.proc.delaybeforesend=1
-        self.hostname = hostname
-        # will eventually come from the database
-        self.board = BOARDS[hostname]
+
+    def device_option(self, option_name):
+        return self.config.get(option_name)
+
+    def device_option_int(self, option_name):
+        return self.config.getint(option_name)
+
+    @property
+    def hostname(self):
+        return self.device_option("hostname")
+
+    @property
+    def tester_str(self):
+        return self.device_option("TESTER_STR")
 
     @property
     def master_str(self):
-        return self._master_str
-
-    @property
-    def tester_str(self):
-        return self._tester_str
+        return self.device_option("MASTER_STR")
+
+    @property
+    def boot_cmds(self):
+        uboot_str = self.device_option("boot_cmds")
+        return string_to_list(uboot_str)
+
+    @property
+    def device_type(self):
+        return self.device_option("device_type")
+
+    @property
+    def boot_part(self):
+        return self.device_option_int("boot_part")
+
+    @property
+    def root_part(self):
+        return self.device_option_int("root_part")
+
+    @property
+    def default_network_interface(self):
+        return self.device_option("default_network_interface")
 
     def in_master_shell(self):
         """ Check that we are in a shell on the master image
@@ -91,16 +112,16 @@
         except:
             self.hard_reboot()
             self.enter_uboot()
-        uboot_cmds = self.board.uboot_cmds
-        self.proc.sendline(uboot_cmds[0])
-        for line in range(1, len(uboot_cmds)):
-            if self.board.type in ["mx51evk", "mx53loco"]:
+        boot_cmds = self.boot_cmds
+        self.proc.sendline(boot_cmds[0])
+        for line in range(1, len(boot_cmds)):
+            if self.device_type in ["mx51evk", "mx53loco"]:
                 self.proc.expect(">", timeout=300)
-            elif self.board.type == "snowball_sd":
+            elif self.device_type == "snowball_sd":
                 self.proc.expect("\$", timeout=300)
             else:
                 self.proc.expect("#", timeout=300)
-            self.proc.sendline(uboot_cmds[line])
+            self.proc.sendline(boot_cmds[line])
         self.in_test_shell()
 
     def enter_uboot(self):
@@ -131,7 +152,8 @@
         self.run_shell_command(cmd, self.tester_str, timeout)
 
     def check_network_up(self):
-        self.proc.sendline("LC_ALL=C ping -W4 -c1 %s" % LAVA_SERVER_IP)
+        lava_server_ip = self.context.lava_server_ip
+        self.proc.sendline("LC_ALL=C ping -W4 -c1 %s" % lava_server_ip)
         id = self.proc.expect(["1 received", "0 received",
             "Network is unreachable"], timeout=5)
         self.proc.expect(self.master_str)
@@ -154,7 +176,7 @@
         #pattern1 = ".*\n(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"
         pattern1 = "(\d?\d?\d?\.\d?\d?\d?\.\d?\d?\d?\.\d?\d?\d?)"
         cmd = ("ifconfig %s | grep 'inet addr' | awk -F: '{print $2}' |"
-                "awk '{print $1}'" % self.board.default_network_interface)
+                "awk '{print $1}'" % self.default_network_interface)
         self.proc.sendline(cmd)
         #if running from ipython, it needs another Enter, don't know why:
         #self.proc.sendline("")

=== modified file 'lava_dispatcher/config.py'
--- lava_dispatcher/config.py	2011-08-16 00:15:08 +0000
+++ lava_dispatcher/config.py	2011-09-09 01:07:35 +0000
@@ -18,113 +18,72 @@
 # along
 # with this program; if not, see <http://www.gnu.org/licenses>.
 
-"""
-This is an ugly hack, the uboot commands for a given board type and the board
-type of a test machine need to come from the device registry.  This is an
-easy way to look it up for now though, just to show the rest of the code
-around it
-"""
-
-class Board:
-    uboot_cmds = None
-    type = None
-    # boot partition number, counting from 1
-    boot_part = 1
-    # root partition number, counting from 1
-    root_part = 2
-    default_network_interface = "eth0"
-
-class BeagleBoard(Board):
-    uboot_cmds = ["mmc init",
-        "mmc part 0",
-        "setenv bootcmd 'fatload mmc 0:3 0x80000000 uImage; fatload mmc "
-        "0:3 0x81600000 uInitrd; bootm 0x80000000 0x81600000'",
-        "setenv bootargs ' console=tty0 console=ttyO2,115200n8 "
-        "root=LABEL=testrootfs rootwait ro earlyprintk fixrtc nocompcache "
-        "vram=12M omapfb.debug=y omapfb.mode=dvi:1280x720MR-16@60'",
-        "boot"]
-    type = "beagle"
-
-class PandaBoard(Board):
-    uboot_cmds = ["mmc init",
-        "mmc part 0",
-        "setenv bootcmd 'fatload mmc 0:3 0x80200000 uImage; fatload mmc "
-        "0:3 0x81600000 uInitrd; bootm 0x80200000 0x81600000'",
-        "setenv bootargs ' console=tty0 console=ttyO2,115200n8 "
-        "root=LABEL=testrootfs rootwait ro earlyprintk fixrtc nocompcache "
-        "vram=48M omapfb.vram=0:24M mem=456M@0x80000000 mem=512M@0xA0000000'",
-        "boot"]
-    type = "panda"
-
-class Snowball(Board):
-    uboot_cmds = ["mmc init",
-        "mmc rescan 1",
-        "setenv bootcmd 'fat load mmc 1:3 0x00100000 /uImage;"
-        "bootm 0x00100000'",
-        "setenv bootargs 'console=tty0 console=ttyAMA2,115200n8 "
-        "root=LABEL=testrootfs rootwait ro earlyprintk rootdelay=1 "
-        "fixrtc nocompcache mem=96M@0 mem_modem=32M@96M mem=44M@128M "
-        "pmem=22M@172M mem=30M@194M mem_mali=32M@224M pmem_hwb=54M@256M "
-        "hwmem=48M@302M mem=152M@360M'",
-        "boot"]
-    type = "snowball_sd"
-
-class Mx51evkBoard(Board):
-    boot_part = 2
-    root_part = 3
-    uboot_cmds = ["mmc init",
-        "mmc part 0",
-        "setenv bootcmd 'fatload mmc 0:5 0x90000000 uImage; fatload mmc 0:5 "
-        "0x92000000 uInitrd; fatload mmc 0:5 0x91ff0000 board.dtb; bootm "
-        "0x90000000 0x92000000 0x91ff0000'",
-        "setenv bootargs ' console=tty0 console=ttymxc0,115200n8 "
-        "root=LABEL=testrootfs rootwait ro'",
-        "boot"]
-    type = "mx51evk"
-
-class Mx53locoBoard(Board):
-    boot_part = 2
-    root_part = 3
-    uboot_cmds = ["mmc init",
-        "mmc part 0",
-        "setenv bootcmd 'fatload mmc 0:5 0x70800000 uImage; fatload mmc "
-        "0:5 0x71800000 uInitrd; bootm 0x70800000 0x71800000'",
-        "setenv bootargs ' console=tty0 console=ttymxc0,115200n8 "
-        "root=LABEL=testrootfs rootwait ro'",
-        "boot"]
-    type = "mx53loco"
-
-#Here, it still needs to maintain a map from boardid to board, for there is
-#only boardid in jobfile.json
-BOARDS = {
-        "panda01": PandaBoard,
-        "panda02": PandaBoard,
-        "panda03": PandaBoard,
-        "panda04": PandaBoard,
-        "beaglexm01": BeagleBoard,
-        "beaglexm02": BeagleBoard,
-        "beaglexm03": BeagleBoard,
-        "beaglexm04": BeagleBoard,
-        "mx51evk01": Mx51evkBoard,
-        "mx53loco01": Mx53locoBoard,
-        "snowball01": Snowball,
-        "snowball02": Snowball,
-        "snowball03": Snowball,
-        "snowball04": Snowball,
-        }
-
-#Main LAVA server IP in the boards farm
-LAVA_SERVER_IP = "192.168.1.10"
-#Location for hosting rootfs/boot tarballs extracted from images
-LAVA_IMAGE_TMPDIR = "/linaro/images/tmp"
-#URL where LAVA_IMAGE_TMPDIR can be accessed remotely
-LAVA_IMAGE_URL = "http://%s/images/tmp"; % LAVA_SERVER_IP
-#Default test result storage path
-LAVA_RESULT_DIR = "/lava/results"
-#Location for caching downloaded artifacts such as hwpacks and images
-LAVA_CACHEDIR = "/linaro/images/cache"
-
-#Master image recognization string
-MASTER_STR = "root@master:"
-#Test image recognization string
-TESTER_STR = "root@linaro:"
+from ConfigParser import ConfigParser
+import os
+import StringIO
+
+
+default_config_path = os.path.join(
+    os.path.dirname(__file__), 'default-config')
+
+
+def load_config_paths(name):
+    for directory in [os.path.expanduser("~/.config"),
+                      "/etc/xdg", default_config_path]:
+        path = os.path.join(directory, name)
+        if os.path.isdir(path):
+            yield path
+
+
+def _read_into(path, cp):
+    s = StringIO.StringIO()
+    s.write('[DEFAULT]\n')
+    s.write(open(path).read())
+    s.seek(0)
+    cp.readfp(s)
+
+
+def _get_config(name, cp=None):
+    """Read a config file named name + '.conf'.
+
+    This checks and loads files from the source tree, site wide location and
+    home directory -- in that order, so home dir settings override site
+    settings which override source settings.
+    """
+    config_files = []
+    for directory in load_config_paths('lava-dispatcher'):
+        path = os.path.join(directory, '%s.conf' % name)
+        if os.path.exists(path):
+            config_files.append(path)
+    if not config_files:
+        raise Exception("no config files named %r found" % (name + ".conf"))
+    config_files.reverse()
+    if cp is None:
+        cp = ConfigParser()
+    print "About to read %s" % str(config_files)
+    for path in config_files:
+        _read_into(path, cp)
+    return cp
+
+
+class ConfigWrapper(object):
+    def __init__(self, cp):
+        self.cp = cp
+    def get(self, key):
+        return self.cp.get("DEFAULT", key)
+    def getint(self, key):
+        return self.cp.getint("DEFAULT", key)
+
+
+def get_config(name):
+    return ConfigWrapper(_get_config(name))
+
+
+def get_device_config(name):
+    device_config = _get_config("devices/%s" % name)
+    cp = _get_config("device-defaults")
+    _get_config(
+        "device-types/%s" % device_config.get('DEFAULT', 'device_type'), cp)
+    _get_config("devices/%s" % name, cp)
+    cp.set("DEFAULT", "hostname", name)
+    return ConfigWrapper(cp)

=== added directory 'lava_dispatcher/default-config'
=== added directory 'lava_dispatcher/default-config/lava-dispatcher'
=== added file 'lava_dispatcher/default-config/lava-dispatcher/README'
--- lava_dispatcher/default-config/lava-dispatcher/README	1970-01-01 00:00:00 +0000
+++ lava_dispatcher/default-config/lava-dispatcher/README	2011-09-09 01:07:35 +0000
@@ -0,0 +1,41 @@
+Configuration files for lava-dispatcher
+=======================================
+
+lava-dispatcher looks for files in:
+
+ * Alongside the installation/source tree for the default values
+   (i.e. this directory).
+
+ * /etc/xdg/lava-dispatcher for system-wide settings.
+
+ * ~/.config/lava-dispatcher for user settings.
+
+Each config directory can contain two files and two directories:
+
+ * lava-dispatcher.conf
+
+   This file defines global settings of the dispatcher.  You will
+   almost certainly need to customize LAVA_SERVER_IP for your install.
+
+ * device-defaults.conf
+
+   This file defines default values for all devices.  You probably
+   won't need to customize it.
+
+ * device-types/
+
+   This directory contains a config file for each device type.  You
+   probably won't need to customize the settings for device types that
+   are already supported by lava-dispatcher, but if you are working on
+   supporting a new class of device, you will need to add a file here.
+
+   Note that the device-type name must match the --dev argument to
+   linaro-media-create.
+
+ * devices/
+
+   This directory contains a file per device that can be targeted by
+   lava-dispatcher.  For the most part this file just needs to contain
+   a line "device_type = <device type>", although other settings can
+   be included here.  You will definitely need to tell lava-dispatcher
+   about the devices you have!

=== added file 'lava_dispatcher/default-config/lava-dispatcher/device-defaults.conf'
--- lava_dispatcher/default-config/lava-dispatcher/device-defaults.conf	1970-01-01 00:00:00 +0000
+++ lava_dispatcher/default-config/lava-dispatcher/device-defaults.conf	2011-09-09 01:07:35 +0000
@@ -0,0 +1,50 @@
+# The default device settings.
+
+# All device settings default to these values unless they are
+# overwritten by the specific device type file
+# (device-types/${TYPE}.conf) or the specific device file
+# (devices/${DEVICE}.conf).
+
+# The client_type.  Only 'serial' (meaning we communicate with the
+# device over a serial line via conmux) is supported today but 'qemu'
+# and 'ssh' are coming.
+client_type = serial
+
+# The bootloader commands to boot the device into the test image (we
+# assume that the device boots into the master image without bootloader
+# intervention).
+#
+# XXX should be called # boot_test_image_commands ?
+boot_cmds =
+
+# The bootloader commands to boot the device into an android-based test
+# image.
+#
+# XXX should be called # boot_android_test_image_commands ?
+boot_cmds_android =
+
+# The device type.  Settings in device-types/${TYPE}.conf override
+# settings in this file, but are overridden by the
+# devices/${DEVICE}.conf file.
+type =
+
+# The network interface that comes up by default
+default_network_interface = eth0
+
+# boot partition number, counting from 1
+#
+# This is used to divide up the image produced by linaro-media-create
+# into sections to write onto the device.
+boot_part = 1
+
+# root partition number, counting from 1
+#
+# This is used to divide up the image produced by linaro-media-create
+# into sections to write onto the device.
+root_part = 2
+
+# Master image recognization string
+MASTER_STR = root@master:
+
+# Test image recognization string
+TESTER_STR = root@linaro:

=== added directory 'lava_dispatcher/default-config/lava-dispatcher/device-types'
=== added file 'lava_dispatcher/default-config/lava-dispatcher/device-types/beagle-xm.conf'
--- lava_dispatcher/default-config/lava-dispatcher/device-types/beagle-xm.conf	1970-01-01 00:00:00 +0000
+++ lava_dispatcher/default-config/lava-dispatcher/device-types/beagle-xm.conf	2011-09-09 01:07:35 +0000
@@ -0,0 +1,20 @@
+boot_cmds = mmc init, 
+	mmc part 0, 
+    setenv bootcmd "'fatload mmc 0:3 0x80000000 uImage; 
+    fatload mmc 0:3 0x81600000 uInitrd; 
+    bootm 0x80000000 0x81600000'",
+    setenv bootargs "' console=tty0 console=ttyO2,115200n8
+    root=LABEL=testrootfs rootwait ro earlyprintk fixrtc nocompcache
+    vram=12M omapfb.debug=y omapfb.mode=dvi:1280x720MR-16@60'",
+    boot
+
+boot_cmds_android = mmc init,
+	mmc part 0,
+	setenv bootcmd "'fatload mmc 0:3 0x80000000 uImage;
+	fatload mmc 0:3 0x81600000 uInitrd;
+	bootm 0x80000000 0x81600000'",
+	setenv bootargs "'console=tty0 console=ttyO2,115200n8 
+	rootwait rw earlyprintk fixrtc nocompcache 
+	vram=12M omapfb.debug=y omapfb.mode=dvi:1280x720MR-16@60 
+	init=/init androidboot.console=ttyO2'",
+	boot

=== added file 'lava_dispatcher/default-config/lava-dispatcher/device-types/mx51evk.conf'
--- lava_dispatcher/default-config/lava-dispatcher/device-types/mx51evk.conf	1970-01-01 00:00:00 +0000
+++ lava_dispatcher/default-config/lava-dispatcher/device-types/mx51evk.conf	2011-09-09 01:07:35 +0000
@@ -0,0 +1,10 @@
+boot_part = 2
+root_part = 3
+boot_cmds = mmc init,
+    mmc part 0,
+    setenv bootcmd "'fatload mmc 0:5 0x90000000 uImage; fatload mmc 0:5 
+    0x92000000 uInitrd; fatload mmc 0:5 0x91ff0000 board.dtb; bootm 
+    0x90000000 0x92000000 0x91ff0000'",
+    setenv bootargs "' console=tty0 console=ttymxc0,115200n8 
+    root=LABEL=testrootfs rootwait ro'",
+    boot

=== added file 'lava_dispatcher/default-config/lava-dispatcher/device-types/mx53loco.conf'
--- lava_dispatcher/default-config/lava-dispatcher/device-types/mx53loco.conf	1970-01-01 00:00:00 +0000
+++ lava_dispatcher/default-config/lava-dispatcher/device-types/mx53loco.conf	2011-09-09 01:07:35 +0000
@@ -0,0 +1,9 @@
+boot_part = 2
+root_part = 3
+boot_cmds = mmc init,
+    mmc part 0,
+    setenv bootcmd "'fatload mmc 0:5 0x70800000 uImage; fatload mmc 
+    0:5 0x71800000 uInitrd; bootm 0x70800000 0x71800000'",
+    setenv bootargs "' console=tty0 console=ttymxc0,115200n8 
+    root=LABEL=testrootfs rootwait ro'",
+    boot

=== added file 'lava_dispatcher/default-config/lava-dispatcher/device-types/panda.conf'
--- lava_dispatcher/default-config/lava-dispatcher/device-types/panda.conf	1970-01-01 00:00:00 +0000
+++ lava_dispatcher/default-config/lava-dispatcher/device-types/panda.conf	2011-09-09 01:07:35 +0000
@@ -0,0 +1,19 @@
+boot_cmds = mmc init,
+    mmc part 0,
+    setenv bootcmd "'fatload mmc 0:3 0x80200000 uImage; fatload mmc 
+    0:3 0x81600000 uInitrd; bootm 0x80200000 0x81600000'",
+    setenv bootargs "' console=tty0 console=ttyO2,115200n8 
+    root=LABEL=testrootfs rootwait ro earlyprintk fixrtc nocompcache 
+    vram=48M omapfb.vram=0:24M mem=456M@0x80000000 mem=512M@0xA0000000'",
+    boot
+boot_cmds_android = mmc init,
+    mmc part 0,
+    setenv bootcmd "'fatload mmc 0:3 0x80200000 uImage;
+    fatload mmc 0:3 0x81600000 uInitrd;
+    bootm 0x80200000 0x81600000'",
+    setenv bootargs "'console=tty0 console=ttyO2,115200n8 
+    rootwait rw earlyprintk fixrtc nocompcache vram=32M 
+    omapfb.vram=0:8M mem=456M@0x80000000 mem=512M@0xA0000000 
+    omapfb.debug=y omapfb.mode=dvi:1280x720MR-16@60 
+    init=/init androidboot.console=ttyO2'",
+    boot

=== added file 'lava_dispatcher/default-config/lava-dispatcher/device-types/snowball.conf'
--- lava_dispatcher/default-config/lava-dispatcher/device-types/snowball.conf	1970-01-01 00:00:00 +0000
+++ lava_dispatcher/default-config/lava-dispatcher/device-types/snowball.conf	2011-09-09 01:07:35 +0000
@@ -0,0 +1,12 @@
+boot_cmds = mmc init,
+    mmc rescan 1,
+    setenv bootcmd "'fat load mmc 1:3 0x00100000 /uImage;
+    bootm 0x00100000'",
+    setenv bootargs "'console=tty0 console=ttyAMA2,115200n8 
+    root=LABEL=testrootfs rootwait ro earlyprintk rootdelay=1 
+    fixrtc nocompcache mem=96M@0 mem_modem=32M@96M mem=44M@128M 
+    pmem=22M@172M mem=30M@194M mem_mali=32M@224M pmem_hwb=54M@256M 
+    hwmem=48M@302M mem=152M@360M'",
+    boot
+
+#boot_cmds_android = TBD
\ No newline at end of file

=== added directory 'lava_dispatcher/default-config/lava-dispatcher/devices'
=== added file 'lava_dispatcher/default-config/lava-dispatcher/lava-dispatcher.conf'
--- lava_dispatcher/default-config/lava-dispatcher/lava-dispatcher.conf	1970-01-01 00:00:00 +0000
+++ lava_dispatcher/default-config/lava-dispatcher/lava-dispatcher.conf	2011-09-09 01:07:35 +0000
@@ -0,0 +1,19 @@
+# General lava-dispatcher settings.
+
+# Main LAVA server IP in the lab.
+#
+# This is the IP the device downloads the image parts from.
+LAVA_SERVER_IP = 192.168.1.10
+
+# Location for rootfs/boot tarballs extracted from images
+LAVA_IMAGE_TMPDIR = /linaro/images/tmp
+
+# URL where LAVA_IMAGE_TMPDIR can be accessed remotely
+LAVA_IMAGE_URL = http://%(LAVA_SERVER_IP)s/images/tmp
+
+# Location on the device for storing test results.
+LAVA_RESULT_DIR = /lava/results
+
+# Location for caching downloaded artifacts such as hwpacks and images
+LAVA_CACHEDIR = /linaro/images/cache
+

=== modified file 'lava_dispatcher/tests/test_config.py'
--- lava_dispatcher/tests/test_config.py	2011-06-27 04:55:08 +0000
+++ lava_dispatcher/tests/test_config.py	2011-09-09 01:07:35 +0000
@@ -19,12 +19,15 @@
 
 from unittest import TestCase
 
-from lava_dispatcher.config import BOARDS, LAVA_SERVER_IP
+from lava_dispatcher.config import get_config, get_device_config
+from lava_dispatcher.utils import string_to_list
 
 class TestConfigData(TestCase):
     def test_beagle01_uboot_cmds(self):
+        beagle01_config = get_device_config("beaglexm01")
         expected = [
             "mmc init",
+            "mmc part 0",
             "setenv bootcmd 'fatload mmc 0:3 0x80000000 uImage; fatload mmc "
                 "0:3 0x81600000 uInitrd; bootm 0x80000000 0x81600000'",
             "setenv bootargs ' console=tty0 console=ttyO2,115200n8 "
@@ -32,11 +35,12 @@
                 "nocompcache vram=12M omapfb.debug=y "
                 "omapfb.mode=dvi:1280x720MR-16@60'",
             "boot"]
-        brd = BOARDS["beagle01"]
-        uboot_cmds = brd.uboot_cmds
-        self.assertEquals(expected, uboot_cmds)
+        uboot_cmds = beagle01_config.get("boot_cmds")
+        self.assertEquals(expected, string_to_list(uboot_cmds))
 
     def test_server_ip(self):
+        server_config = get_config("lava-dispatcher")
         expected = "192.168.1.10"
-        self.assertEqual(expected, LAVA_SERVER_IP)
+        lava_server_ip = server_config.get("LAVA_SERVER_IP")
+        self.assertEqual(expected, lava_server_ip)
 

=== modified file 'lava_dispatcher/utils.py'
--- lava_dispatcher/utils.py	2011-08-18 20:38:38 +0000
+++ lava_dispatcher/utils.py	2011-09-09 01:07:35 +0000
@@ -22,8 +22,7 @@
 import shutil
 import urllib2
 import urlparse
-
-from lava_dispatcher.config import LAVA_CACHEDIR
+from shlex import shlex
 
 def download(url, path=""):
     urlpath = urlparse.urlsplit(url).path
@@ -41,8 +40,8 @@
         raise RuntimeError("Could not retrieve %s" % url)
     return filename
 
-def download_with_cache(url, path=""):
-    cache_loc = url_to_cache(url)
+def download_with_cache(url, path="", cachedir=""):
+    cache_loc = url_to_cache(url, cachedir)
     if os.path.exists(cache_loc):
         filename = os.path.basename(cache_loc)
         file_location = os.path.join(path, filename)
@@ -61,8 +60,16 @@
             #so ignore
     return file_location
 
-def url_to_cache(url):
+def url_to_cache(url, cachedir):
     url_parts = urlparse.urlsplit(url)
-    path = os.path.join(LAVA_CACHEDIR, url_parts.netloc,
+    path = os.path.join(cachedir, url_parts.netloc,
         url_parts.path.lstrip(os.sep))
     return path
+
+def string_to_list(string):
+    splitter = shlex(string, posix=True)
+    splitter.whitespace = ","
+    splitter.whitespace_split = True
+    newlines_to_spaces = lambda x: x.replace('\n', ' ')
+    strip_newlines = lambda x: newlines_to_spaces(x).strip(' ')    
+    return map(strip_newlines, list(splitter))

=== modified file 'setup.py'
--- setup.py	2011-07-21 16:55:47 +0000
+++ setup.py	2011-09-09 01:07:35 +0000
@@ -12,6 +12,15 @@
     author='Linaro Validation Team',
     author_email='linaro-dev@xxxxxxxxxxxxxxxx',
     packages=find_packages(),
+    package_data= {
+        'lava_dispatcher': [
+            'default-config/lava-dispatcher/lava-dispatcher.conf',
+            'default-config/lava-dispatcher/lava-dispatcher.conf',
+            'default-config/lava-dispatcher/device-defaults.conf',
+            'default-config/lava-dispatcher/device-types/*.conf',
+            'default-config/lava-dispatcher/devices/*.conf',
+            ],
+        },
     scripts = [
         'lava-dispatch'
     ],