pxmlw6n2f/Gazebo_Distributed_MPI/tools/devel_run_chroot.py

777 lines
30 KiB
Python
Executable File

#!/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)