#!/usr/bin/env python # This script was lifted from http://ros.org/wiki/regression_tests/reproducing # Check there for updates and fixes. # Usage: # mkdir tmp # ./devel_run_chroot.py --interactive --workspace tmp --distro lucid --arch i386 import subprocess import os, sys import time import shutil import tempfile import optparse import traceback import urllib # Valid options valid_archs = ['i386', 'i686', 'amd64', 'armel'] valid_ubuntu_distros = ['hardy', 'jaunty', 'karmic', 'lucid', 'maverick', 'natty', 'oneiric'] valid_debian_distros = ['lenny', 'squeeze'] valid_redhat_distros = ['fedora-15'] # arm requires qemu > 0.13 for lucid and maverick, natty not working yet # mock requires patched version https://bugs.launchpad.net/ubuntu/+source/mock/+bug/600564 # also you must be a member of mock group # usermod -a -G mock myusername def local_check_call(cmd, display_output=False): if not display_output: with open(os.devnull, 'w') as fh: subprocess.check_call(cmd, stderr = fh, stdout=fh) return p = subprocess.Popen(cmd, stderr = subprocess.STDOUT, stdout=subprocess.PIPE) while True: l = p.stdout.readline() if not l: break print l, ##extra comma because lines already have \n. I"m assuming this is lower overhead than l.strip() if p.returncode == None: #print "stdout finished but process not exited!!!" p.communicate() if p.returncode != 0: raise subprocess.CalledProcessError(p.returncode, cmd) def local_call(cmd, display_output=False): if not display_output: with open(os.devnull, 'w') as fh: return subprocess.call(cmd, stderr = fh, stdout=fh) p = subprocess.Popen(cmd, stderr = subprocess.STDOUT, stdout=subprocess.PIPE) while True: l = p.stdout.readline() if not l: break print l, ##extra comma because lines already have \n. I"m assuming this is lower overhead than l.strip() if p.returncode == None: print "stdout finished but process not exited!!!" p.communicate() return p.returncode # else: # return subprocess.call(cmd, stderr = subprocess.STDOUT) def get_mount_points(pattern = "chroot"): mnt = subprocess.Popen("mount", stdout=subprocess.PIPE) out = mnt.communicate()[0] lines = out.split('\n') mounts = [] for l in lines: if pattern in l: elements = l.split() if len(elements) == 6: mount_point = elements[2] # TODO use os.path.ismount to verify mounts.append(mount_point) return mounts def get_chroot_processes(patterns): mnt = subprocess.Popen(["sudo", "lsof"], stdout=subprocess.PIPE) out = mnt.communicate()[0] lines = out.split('\n') processes = set() for l in lines: for p in patterns: if p in l: elements = l.split() if len(elements) > 6: process = elements[1] processes.add(process) return processes def unmount_directories(mounts): for m in mounts: print "Unmounting %s:"%m cmd = "sudo umount -f %s"%m local_call(cmd.split()) def kill_processes(processes, level=''): for p in processes: print "Killing %s %s:"%(level, p) cmd = "sudo kill %s %s"%(level, p) local_call(cmd.split()) def add_binfmg_misc_mounts(mounts): """ binfmg_misc gets mounted inside the chroot and prevents cleanup add this for all proc mounts at the top. """ additions = [os.path.join(m, 'sys', 'fs', 'binfmt_misc') for m in mounts if m.endswith('proc')] print "adding", additions return additions + mounts def clean_up_chroots(): ### Try 1 mounts = get_mount_points() mounts.reverse() if len(mounts) > 0: print "Cleaning up mount points", mounts else: print "No mounts need cleaning" return True mounted_processes = get_chroot_processes(mounts) for p in mounted_processes: print "the following processes are in chroot", p kill_processes(mounted_processes) remaining_processes = get_chroot_processes(mounts) print "Remaining processes %s"%remaining_processes mounts = add_binfmg_misc_mounts(mounts) unmount_directories(mounts) mounts = get_mount_points() mounts.reverse() # test for success if len(remaining_processes) == 0 and len(mounts) == 0: return True print "Escalating to -9 kills" remaining_processes = get_chroot_processes(mounts) print "Remaining processes %s"%remaining_processes kill_processes(remaining_processes, '-9') mounts = add_binfmg_misc_mounts(mounts) unmount_directories(mounts) remaining_processes = get_chroot_processes(mounts) mounts = get_mount_points() if len(remaining_processes) == 0 and len(mounts) == 0: return True return False class ChrootInstance: def __init__(self, distro, arch, path, host_workspace, clear_chroot = True, ssh_key_path = None, use_wg_sources = False, scratch_dir=None, hdd_tmp_dir=None, debug_chroot=False, repo_url=None): #logging self.profile = [] self.chroot_path = path self.host_workspace = host_workspace self.mount_path = "/tmp/workspace" self.ccache_dir = "/tmp/ccache" self.host_ccache_dir = "~/.ccache" self.ccache_remote_dir = os.path.join(self.chroot_path, self.ccache_dir[1:]) self.ws_remote_path = os.path.join(self.chroot_path, self.mount_path[1:]) self.failure = False self.arch = arch self.distro = distro self.clear_chroot = clear_chroot self.workspace_successfully_copied = False self.ssh_key_path = ssh_key_path self.use_wg_sources = use_wg_sources self.hdd_remote_mount = "" self.hdd_tmp_dir = hdd_tmp_dir self.scratch_dir = scratch_dir self.local_scratch_dir = None self.debug_chroot = debug_chroot # if enabled print to screen during setup and teardown self.repo_url = repo_url def clean(self): self.unmount_proc_sys() # clear chroot if it exists print "Removing tree %s"%self.chroot_path #shutil.rmtree(self.chroot_path, True) cmd = ["sudo", "rm", "-rf", self.chroot_path] print "executing", cmd self.call(cmd) def unmount_proc_sys(self): cmd = ['sudo', 'umount', '-f', "%s/proc"%self.chroot_path] print cmd self.call(cmd) cmd = ['sudo', 'umount', '-f', "%s/dev/pts"%self.chroot_path] print cmd self.call(cmd) cmd = ['sudo', 'umount', '-f', "%s/sys"%self.chroot_path] print cmd self.call(cmd) def mount_proc_sys(self): #hack since we mount it in 2 places and umount is safe print "unmounting before mounting to prevent double mounting" self.unmount_proc_sys() cmd = ['sudo', 'mount', '--bind', "/proc", "%s/proc"%self.chroot_path] print cmd self.call(cmd) cmd = ['sudo', 'mount', '--bind', "/dev/pts", "%s/dev/pts"%self.chroot_path] print cmd self.call(cmd) cmd = ['sudo', 'mount', '--bind', "/sys", "%s/sys"%self.chroot_path] print cmd self.call(cmd) def bootstrap(self): if self.distro in valid_debian_distros + valid_ubuntu_distros: self.debian_bootstrap() if self.distro in valid_redhat_distros: self.redhat_bootstrap() def redhat_bootstrap(self): cmd = ['sudo', 'apt-get', 'install', 'mock'] print cmd self.check_call(cmd) print "ready to redhat chroot..." cmd = ['/usr/bin/mock', '--init','--resultdir', '/tmp/result', '--configdir', '/home/tfoote/rcom/ros_release/hudson/mock_configs'] print cmd print "This will take a few minutes. Please be patient." self.check_call(cmd) print "Finished mock initing" def debian_bootstrap(self): cmd = ['sudo', 'apt-get', 'install', 'debootstrap'] print cmd self.check_call(cmd) deboot_url = 'http://us.archive.ubuntu.com/ubuntu' if self.distro in valid_debian_distros: deboot_url = 'http://ftp.us.debian.org/debian/' if self.distro in valid_ubuntu_distros and self.arch == 'armel': deboot_url = 'http://ports.ubuntu.com/ubuntu-ports/' if self.repo_url: # override if necessary deboot_url = self.repo_url cmd = [] if self.arch =='armel': #cmd = ['sudo', 'build-arm-chroot', self.distro, self.chroot_path] #aptproxy doesn't have armel yet, deboot_url] cmd = ['sudo', 'qemu-debootstrap', '--arch', self.arch, self.distro, self.chroot_path, deboot_url] else: cmd = ['sudo', 'debootstrap', '--arch', self.arch, self.distro, self.chroot_path, deboot_url] print cmd print "This will take a few minutes. Please be patient." self.check_call(cmd) print "Finished debootstrap" # replicate host settings cmd = ['sudo', 'cp', '/etc/resolv.conf', os.path.join(self.chroot_path, 'etc')] print "Runing cmd", cmd self.check_call(cmd) cmd = ['sudo', 'cp', '/etc/hosts', os.path.join(self.chroot_path, 'etc')] print "Runing cmd", cmd self.check_call(cmd) if self.distro in valid_ubuntu_distros: # Move sources.list to apt-proxy sources=os.path.join(self.chroot_path, 'etc', 'apt', 'sources.list.d', 'bootstrap.list') with tempfile.NamedTemporaryFile() as tf: print "Setting sources to %s"%deboot_url, sources tf.write("deb %s %s main restricted universe multiverse\n" % (deboot_url, self.distro)) tf.write("deb %s %s-updates main restricted universe multiverse\n" % (deboot_url, self.distro)) tf.write("deb %s %s-security main restricted universe multiverse\n" % (deboot_url, self.distro)) tf.flush() cmd = ['sudo', 'cp', tf.name, sources] print "Runing cmd", cmd self.check_call(cmd) self.add_ros_sources() # This extra source is to pull in the very latest # nvidia-current package from our mirror. It's only guaranteed # to be available for Lucid, but we only need it for Lucid. if self.use_wg_sources: self.add_wg_sources() #disable start-stop-daemon and invokerc with tempfile.NamedTemporaryFile() as tf: tf.write("#!/bin/sh\n") tf.write("exit 0\n") tf.flush() startstop=os.path.join(self.chroot_path,'sbin/start-stop-daemon') print "disabling start-stop", startstop self.check_call(['sudo', 'cp', tf.name, startstop]) invokerc=os.path.join(self.chroot_path,'usr/sbin/invoke-rc.d') print "disabling start-stop", invokerc self.check_call(['sudo', 'cp', tf.name, invokerc]) self.mount_proc_sys() if self.distro in valid_ubuntu_distros: self.execute(['locale-gen', 'en_US.UTF-8']) self.execute(['apt-get', 'update'], robust=True) if self.distro in valid_debian_distros: self.execute(['apt-get', 'install', 'sudo', 'lsb-release', '-y', '--force-yes']) # Fix the sudoers file sudoers_path = os.path.join(self.chroot_path, 'etc/sudoers') self.check_call(['sudo', 'chown', '0.0', sudoers_path]) print "debconf executing" chrootcmd = ['sudo', 'chroot', self.chroot_path] subprocess.Popen(chrootcmd + ['debconf-set-selections'], stdin=subprocess.PIPE).communicate(""" hddtemp hddtemp/port string 7634 hddtemp hddtemp/interface string 127.0.0.1 hddtemp hddtemp/daemon boolean false hddtemp hddtemp/syslog string 0 hddtemp hddtemp/SUID_bit boolean false sun-java6-bin shared/accepted-sun-dlj-v1-1 boolean true sun-java6-jdk shared/accepted-sun-dlj-v1-1 boolean true sun-java6-jre shared/accepted-sun-dlj-v1-1 boolean true grub-pc grub2/linux_cmdline string grub-pc grub-pc/install_devices_empty boolean true """); print "debconf complete" # If we're on lucid, pull in the nvidia drivers, in case we're # going to run Gazebo-based tests, which need the GPU. if self.distro == 'lucid' and self.arch != 'armel': # The --force-yes is necessary to accept the nvidia-current # package without a valid GPG signature. self.execute(['apt-get', 'install', '-y', '--force-yes', 'linux-headers-2.6.32-23']) self.execute(['apt-get', 'install', '-y', '--force-yes', 'linux-headers-2.6.32-23-generic']) self.execute(['apt-get', 'install', '-y', '--force-yes', 'linux-image-2.6.32-23-generic']) self.execute(['apt-get', 'install', '-y', '--force-yes', 'nvidia-current']) self.execute(['mknod', '/dev/nvidia0', 'c', '195', '0']) self.execute(['mknod', '/dev/nvidiactl', 'c', '195', '255']) self.execute(['chmod', '666', '/dev/nvidia0', '/dev/nvidiactl']) cmd = ("sudo tee -a %s"%sudoers_path).split() print "making rosbuild have no passwd", cmd tempf = tempfile.TemporaryFile() tempf.write("rosbuild ALL = NOPASSWD: ALL\n") tempf.seek(0) subprocess.check_call(cmd, stdin = tempf) #fix sudo permissions self.execute(['chown', '-R', 'root:root', '/usr/bin/sudo']) self.execute(['chmod', '4755', '-R', '/usr/bin/sudo']) if self.distro in valid_debian_distros + valid_ubuntu_distros: self.debian_setup_rosbuild() else: raise NotImplementedError("non debian rosbuild setup not implemented") def debian_setup_rosbuild(self): cmd = "useradd rosbuild -m --groups sudo".split() print self.execute(cmd) self.debian_setup_ssh_client() self.setup_svn_ssl_certs() def add_ros_sources(self): """ Add code.ros.org sources to the apt sources """ ros_source=os.path.join(self.chroot_path, 'etc', 'apt', 'sources.list.d', 'ros-latest.list') with tempfile.NamedTemporaryFile() as tf: print "Adding packages.ros.org as source" #tf.write("deb http://code.ros.org/packages/ros/ubuntu %s main\n" % self.distro) tf.write("deb http://packages.ros.org/ros-shadow-fixed/ubuntu %s main\n" % self.distro) tf.flush() cmd = ['sudo', 'cp', tf.name, ros_source] print "Runing cmd", cmd self.check_call(cmd) print "adding code.ros.org gpg key" key_file = 'tmp/ros.key' abs_key_file =os.path.join(self.chroot_path, key_file) urllib.urlretrieve('http://code.ros.org/packages/ros.key', abs_key_file) #with open(abs_key_file) as f: # print "key file:", f.read() cmd = ['apt-key', 'add', os.path.join('/', key_file)] self.execute(cmd) def add_wg_sources(self): """ Add wg-packages to apt sources for nvidia-current drivers. """ nvidia_source=os.path.join(self.chroot_path, 'etc', 'apt', 'sources.list.d', 'wg.list') with tempfile.NamedTemporaryFile() as tf: print "Adding code.ros.org as source" tf.write("deb http://wgs1.willowgarage.com/wg-packages/ %s-wg main\n" % self.distro) tf.flush() cmd = ['sudo', 'cp', tf.name, nvidia_source] print "Runing cmd", cmd self.check_call(cmd) print "adding wg gpg key" key_file = 'tmp/wg.key' abs_key_file =os.path.join(self.chroot_path, key_file) urllib.urlretrieve('http://wgs1.willowgarage.com/wg-packages/wg.key', abs_key_file) #with open(abs_key_file) as f: # print "key file:", f.read() cmd = ['apt-key', 'add', os.path.join('/', key_file)] self.execute(cmd) def debian_setup_ssh_client(self): print 'Setting up ssh client' # Pull in ssh, and drop a private key that will allow the slave to # upload results of the build. self.execute(['apt-get', 'install', '-y', '--force-yes', 'openssh-client']) if self.ssh_key_path: # Pull down a tarball of rosbuild's .ssh directory tardestdir = os.path.join(self.chroot_path, 'home', 'rosbuild',) #tardestname = os.path.join(tardestdir, 'rosbuild-ssh.tar') #if not os.path.exists(tardestname): local_tmp_dir = tempfile.mkdtemp() local_tmp = os.path.join(local_tmp_dir, "rosbuild_ssh.tar.gz") print "retrieving %s to %s"%(self.ssh_key_path, local_tmp) shutil.copy(self.ssh_key_path, local_tmp) if not os.path.exists(tardestdir): os.makedirs(tardestdir) print "untarring %s"%local_tmp subprocess.check_call(['sudo', 'tar', 'xf', local_tmp], cwd=tardestdir) #subprocess.check_call(['sudo', 'rm', '-rf', local_tmp_dir]) shutil.rmtree(local_tmp_dir) #self.execute(['tar', 'xf', os.path.join('home', 'rosbuild', 'rosbuild-ssh.tar')], cwd=os.path.join('home', 'rosbuild')) self.execute(['chown', '-R', 'rosbuild:rosbuild', '/home/rosbuild']) def setup_svn_ssl_certs(self): print 'Setting up ssl certs' self.execute(["apt-get", "update"], robust=True) cmd = "apt-get install subversion -y --force-yes".split() self.execute(cmd) cmd = "svn co https://code.ros.org/svn/ros/stacks/rosorg/trunk/rosbrowse/certs /tmp/chroot_certs".split() self.execute(cmd) print "successfully checked out certs" cmd = "mkdir -p /home/rosbuild/.subversion/auth/svn.ssl.server".split() self.execute(cmd) cmd = ["bash", '-c', "cp /tmp/chroot_certs/* /home/rosbuild/.subversion/auth/svn.ssl.server/"] self.execute(cmd, display=True) self.execute(['chown', '-R', 'rosbuild:rosbuild', '/home/rosbuild/.subversion']) def replecate_workspace(self): print "Linking in workspace" self.check_call(["sudo", "mkdir", "-p", self.ws_remote_path]); # backwards compatability /tmp/ros self.check_call(["sudo", "mkdir", "-p", os.path.join(self.ws_remote_path, "../ros")]); self.check_call(['sudo', 'mount', '--bind', self.host_workspace, self.ws_remote_path]) #backwards compatability /tmp/ros self.check_call(['sudo', 'mount', '--bind', self.host_workspace, os.path.join(self.ws_remote_path, "../ros")]) cmd = ['chown', '-R', 'rosbuild:rosbuild', self.mount_path] self.execute(cmd) if self.scratch_dir: self.local_scratch_dir = tempfile.mkdtemp(dir=self.hdd_tmp_dir) self.hdd_remote_mount = os.path.join(self.chroot_path, self.scratch_dir.lstrip('/')) print "created tempdir", self.local_scratch_dir self.check_call(['sudo', 'mkdir', '-p', self.hdd_remote_mount]) self.check_call(['sudo', 'mount', '--bind', self.local_scratch_dir, self.hdd_remote_mount]) print "mounting tempdir to %s"%os.path.join(self.chroot_path, self.scratch_dir) def write_back_workspace(self): print "unmounting workspace %s"%self.ws_remote_path self.call(['ls', self.ws_remote_path]) self.call(['sudo', 'umount', '-f', self.ws_remote_path]) #backwards compatability /tmp/ros self.call(['sudo', 'umount', '-f', os.path.join(self.ws_remote_path, "../ros")]) print "Cleaning up permissions on workspace." self.call(['sudo', 'chown', '-R', '%d:%d'%(os.geteuid(), os.geteuid()), self.host_workspace]) if self.scratch_dir: print "Cleaning up scratch mount %s"%self.hdd_remote_mount self.call(['sudo', 'umount', '-f', self.hdd_remote_mount]) print "deleting tempdir", self.hdd_tmp_dir if self.local_scratch_dir: shutil.rmtree(self.local_scratch_dir) else: print >>sys.stderr, "self.local_scratch_dir should have existed if we get here." def manual_init(self): print "Starting init" if self.clear_chroot and os.path.isdir(self.chroot_path): print"Clean build requested and directory exists cleaning up old path first." self.clean() self.bootstrap() elif not os.path.isdir(self.chroot_path): self.bootstrap() # bootstrap if cleaned or uninitialized print "finished bootstrap" else: print "configuring" self.execute(['dpkg', '--configure', '-a']) # clean up in case dpkg was previously interrupted # Even if we're reusing the chroot, we re-mount /proc and /sys. self.mount_proc_sys() self.replecate_workspace() def __enter__(self): return self def __exit__(self, mtype, value, tb): if tb: if isinstance(value, subprocess.CalledProcessError): print "Command failed, shutting down chroot:\n-------------------------------------------\n%s\n------------------------------------------\n"%traceback.extract_tb(tb) else: print "Exception in chroot, shutting down chroot" self.shutdown() def print_profile(self): print "chroot Profile:" total_time = 0 for line in self.profile: print " %.1f: %s"%(line[0], line[1]) total_time += line[0] print "Total Time: %f"%(total_time) def shutdown(self): print "Shutting down chroot" self.unmount_proc_sys() self.write_back_workspace() def execute(self, cmd, robust = False, user='root', display = False): start_time = time.time() if robust: try: self.execute_chroot(cmd, user, display) except subprocess.CalledProcessError, ex: pass else: self.execute_chroot(cmd, user, display) net_time = time.time() - start_time self.profile.append((net_time, "executed: %s"%cmd)) def execute_chroot(self, cmd, user='root', display = False): if user == 'root': full_cmd = ["sudo", "chroot", self.chroot_path] full_cmd.extend(cmd) else: envs = [] hudson_envs = ["BUILD_NUMBER", 'BUILD_ID', 'JOB_NAME', 'BUILD_TAG', 'EXECUTOR_NUMBER', 'HUDSON_URL', 'BUILD_URL', 'JOB_URL', 'SVN_REVISION'] for k,v in os.environ.copy().iteritems(): if k in hudson_envs: envs.append("%s='%s'"%(k, v)) full_cmd = ['sudo', 'chroot', self.chroot_path, 'su', user, '-s', '/bin/bash', '-c', '%s %s'%(" ".join(envs), " ".join(cmd))] print "Executing", full_cmd self.check_call(full_cmd, display) def check_call(self, cmd, display = False): local_check_call(cmd, display or self.debug_chroot) def call(self, cmd, display = False): return local_call(cmd, display or self.debug_chroot) def run_chroot(options, path, workspace, hdd_tmp_dir): with ChrootInstance(options.distro, options.arch, path, workspace, clear_chroot = not options.persist, ssh_key_path=options.ssh_key_path, use_wg_sources = options.use_wg_sources, scratch_dir = options.hdd_scratch, hdd_tmp_dir=hdd_tmp_dir, debug_chroot= options.debug_chroot, repo_url=options.repo_url) as chrti: #initialization here so that if it throws the cleanup is called. chrti.manual_init() print "returning early for debug" cmd = "apt-get update".split() chrti.execute(cmd, robust=True) # continue cmd = "apt-get install -y --force-yes build-essential python-yaml cmake subversion mercurial bzr git-core wget python-setuptools".split() chrti.execute(cmd) cmd = "easy_install -U rosinstall".split() chrti.execute(cmd) if options.arch in ['i386', 'i686']: setarch = 'setarch %s'%(options.arch) else: setarch = '' if options.script: remote_script_name = os.path.join("/tmp", os.path.basename(options.script)) cmd = ["cp", options.script, os.path.join(chrti.chroot_path, "tmp")] print "Executing", cmd local_check_call(cmd); cmd = ("chown rosbuild:rosbuild %s"%remote_script_name).split() chrti.execute(cmd) cmd = ("chmod +x %s"%remote_script_name).split() chrti.execute(cmd) cmd = [remote_script_name] if options.arch in ['i386', 'i686']: cmd.insert(0, options.arch) cmd.insert(0, "setarch") print "Executing Script", cmd print "vvvvvvvvvvvvvvvvvvv Begin Script Output vvvvvvvvvvvvvvvvvv" chrti.execute(cmd, user="rosbuild", display=True) print "^^^^^^^^^^^^^^^^^^^ End Script Output ^^^^^^^^^^^^^^^^^^^^" if options.interactive: print "xhost localhost" local_check_call(["xhost", "localhost"]) cmd = "apt-get install -y xterm".split() print chrti.execute(cmd) cmd = ["xterm", "bash"] print chrti.execute(cmd) print chrti.print_profile() class TempRamFS: def __init__(self, path, size_str): self.path = path self.size= size_str def __enter__(self): cmd = ['sudo', 'mkdir', '-p', self.path] local_check_call(cmd) cmd = ['sudo', 'mount', '-t', 'tmpfs', '-o', 'size=%s,mode=0755'%self.size, 'tmpfs', self.path] local_check_call(cmd) return self def __exit__(self, mtype, value, tb): if tb: if isinstance(value, subprocess.CalledProcessError): print >> sys.stderr, "Command failed, closing out ramdisk" else: print >> sys.stderr, "Caught exception, closing out ramdisk" cmd = ['sudo', 'umount', '-f', self.path] if not local_call(cmd): print "WARNING: UNCLEAN TMPFS CHROOT UNMONT" else: print "Successfully umounted tmpfs chroot." parser = optparse.OptionParser() parser.add_option("--arch", type="string", dest="arch", help="What architecture %s"%valid_archs) parser.add_option("--distro", type="string", dest="distro", help="What distro %s "%(valid_ubuntu_distros + valid_debian_distros)) parser.add_option("--persist-chroot", action="store_true", dest="persist", default=False, help="do not clear the chroot before running") parser.add_option("--chroot-dir", action="store", dest="chroot_dir", default="/home/rosbuild/chroot", type="string", help="Where to put the chroot, + JOB_NAME") parser.add_option("--ramdisk-size", action="store", dest="ramdisk_size", default="20000M", type="string", help="Ramdisk size string, default '20GB'") parser.add_option("--ramdisk", action="store_true", dest="ramdisk", default=False, help="Run chroot in a ramdisk") parser.add_option("--hdd-scratch", action="store", dest="hdd_scratch", default=False, help="Mount a tempdir on the hdd in this location in the chroot.") parser.add_option("--use-wg-sources", action="store_true", dest="use_wg_sources", default=False, help="Use internal wg sources.") parser.add_option("--script", action="store", dest="script", type="string", help="Script filename to execute on the remote machine") parser.add_option("--ssh-key-file", action="store", dest="ssh_key_path", default=None, type="string", help="filename to use for ssh key tarball, instead of URI") parser.add_option("--workspace", action="store", dest="workspace", default=None, type="string", help="The directory to replecate into the chroot. Overrides WORKSPACE in env.") parser.add_option("--interactive", action="store_true", dest="interactive", default=False, help="Pop up an xterm to interact in.") parser.add_option("--debug-chroot", action="store_true", dest="debug_chroot", default=False, help="Display chroot setup console output.") parser.add_option("--repo-url", action="store", dest="repo_url", default=None, type="string", help="The url of the package repo") (options, args) = parser.parse_args() if options.distro not in (valid_ubuntu_distros + valid_debian_distros + valid_redhat_distros): parser.error("%s is not a valid distro: %s"%(options.distro, valid_ubuntu_distros+ valid_debian_distros)) if options.arch not in valid_archs: parser.error("%s is not a valid arch: %s"%(options.arch, valid_archs)) workspace = os.getenv("WORKSPACE") if options.workspace: workspace = options.workspace if not workspace: parser.error("you must export WORKSPACE or set --workspace") hdd_tmp_dir = os.getenv("HDD_TMP_DIR", "/tmp") path = os.path.join(options.chroot_dir, os.getenv("JOB_NAME", "job_name_unset")) print "chroot path", path print "parameters" print "distro", options.distro print "arch", options.arch print "workspace", workspace print "Checking for abandoned chroots" if not clean_up_chroots(): print "Failed to clean up abandoned chroots, continuing." local_check_call(['sudo', 'mkdir', '-p', path]) try: if options.ramdisk: with TempRamFS(path, options.ramdisk_size): run_chroot(options, path, workspace, hdd_tmp_dir) else: run_chroot(options, path, workspace, hdd_tmp_dir) sys.exit(0) except subprocess.CalledProcessError, e: print >> sys.stderr, "Command failed: %s"%(str(e)) sys.exit(1)