1825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart# Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 2825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart# Use of this source code is governed by a BSD-style license that can be 3825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart# found in the LICENSE file. 4825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 55f0a57585e4ea85033b7ffcb68177174ecd1e685Paul Stewartimport errno 6825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewartimport os 70174334399baf09670d361acfb2ac84ab951b3b4Paul Stewartimport shutil 8825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewartimport time 9825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 10825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewartfrom autotest_lib.client.bin import utils 11825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 12825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewartclass NetworkChroot(object): 13825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """Implements a chroot environment that runs in a separate network 14825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart namespace from the caller. This is useful for network tests that 15825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart involve creating a server on the other end of a virtual ethernet 16825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart pair. This object is initialized with an interface name to pass 17825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart to the chroot, as well as the IP address to assign to this 18825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart interface, since in passing the interface into the chroot, any 19825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart pre-configured address is removed. 20825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 21825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart The startup of the chroot is an orchestrated process where a 22825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart small startup script is run to perform the following tasks: 23825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart - Write out pid file which will be a handle to the 24825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart network namespace that that |interface| should be passed to. 25825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart - Wait for the network namespace to be passed in, by performing 26825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart a "sleep" and writing the pid of this process as well. Our 27825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart parent will kill this process to resume the startup process. 28825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart - We can now configure the network interface with an address. 29825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart - At this point, we can now start any user-requested server 30825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart processes. 31825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """ 3260dc4d6a6ea7620898027f77f1818f2a8acd72dbPaul Stewart BIND_ROOT_DIRECTORIES = ('bin', 'dev', 'dev/pts', 'lib', 'lib32', 'lib64', 33825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 'proc', 'sbin', 'sys', 'usr', 'usr/local') 3460dc4d6a6ea7620898027f77f1818f2a8acd72dbPaul Stewart # Subset of BIND_ROOT_DIRECTORIES that should be mounted writable. 3560dc4d6a6ea7620898027f77f1818f2a8acd72dbPaul Stewart BIND_ROOT_WRITABLE_DIRECTORIES = frozenset(('dev/pts',)) 366adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley # Directories we'll bind mount when we want to bridge DBus namespaces. 376adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley # Includes directories containing the system bus socket and machine ID. 386adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley DBUS_BRIDGE_DIRECTORIES = ('var/run/dbus/', 'var/lib/dbus/') 3960dc4d6a6ea7620898027f77f1818f2a8acd72dbPaul Stewart 40825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart ROOT_DIRECTORIES = ('etc', 'tmp', 'var', 'var/log', 'var/run') 41825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart STARTUP = 'etc/chroot_startup.sh' 42825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart STARTUP_DELAY_SECONDS = 5 430174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart STARTUP_PID_FILE = 'var/run/vpn_startup.pid' 440174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart STARTUP_SLEEPER_PID_FILE = 'var/run/vpn_sleeper.pid' 450174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart COPIED_CONFIG_FILES = [ 460174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart 'etc/ld.so.cache' 470174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart ] 48825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart CONFIG_FILE_TEMPLATES = { 49825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart STARTUP: 50825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart '#!/bin/sh\n' 51825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 'exec > /var/log/startup.log 2>&1\n' 52825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 'set -x\n' 53825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 'echo $$ > /%(startup-pidfile)s\n' 54825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 'sleep %(startup-delay-seconds)d &\n' 55825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 'echo $! > /%(sleeper-pidfile)s &\n' 56825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 'wait\n' 57825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 'ip addr add %(local-ip-and-prefix)s dev %(local-interface-name)s\n' 58825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 'ip link set %(local-interface-name)s up\n' 59825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart } 60825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart CONFIG_FILE_VALUES = { 610174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart 'sleeper-pidfile': STARTUP_SLEEPER_PID_FILE, 62825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 'startup-delay-seconds': STARTUP_DELAY_SECONDS, 630174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart 'startup-pidfile': STARTUP_PID_FILE 64825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart } 65825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 66825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart def __init__(self, interface, address, prefix): 67825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart self._interface = interface 68825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 69825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart # Copy these values from the class-static since specific instances 70825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart # of this class are allowed to modify their contents. 716adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley self._bind_root_directories = list(self.BIND_ROOT_DIRECTORIES) 72825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart self._root_directories = list(self.ROOT_DIRECTORIES) 730174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart self._copied_config_files = list(self.COPIED_CONFIG_FILES) 74825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart self._config_file_templates = self.CONFIG_FILE_TEMPLATES.copy() 75825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart self._config_file_values = self.CONFIG_FILE_VALUES.copy() 76825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 77825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart self._config_file_values.update({ 78825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 'local-interface-name': interface, 79825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 'local-ip': address, 80825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 'local-ip-and-prefix': '%s/%d' % (address, prefix) 81825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart }) 82825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 83825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 84825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart def startup(self): 85825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """Create the chroot and start user processes.""" 86825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart self.make_chroot() 87825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart self.write_configs() 88825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart self.run(['/bin/bash', os.path.join('/', self.STARTUP), '&']) 89825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart self.move_interface_to_chroot_namespace() 900174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart self.kill_pid_file(self.STARTUP_SLEEPER_PID_FILE) 91825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 92825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 93825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart def shutdown(self): 94825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """Remove the chroot filesystem in which the VPN server was running""" 95825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart # TODO(pstew): Some processes take a while to exit, which will cause 96825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart # the cleanup below to fail to complete successfully... 9789003937480a6ca69bfe30c04d7ec198fc7bcf46Paul Stewart time.sleep(10) 98825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart utils.system_output('rm -rf --one-file-system %s' % self._temp_dir, 99825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart ignore_status=True) 100825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 101825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 102825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart def add_config_templates(self, template_dict): 103825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """Add a filename-content dict to the set of templates for the chroot 104825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 105825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart @param template_dict dict containing filename-content pairs for 106825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart templates to be applied to the chroot. The keys to this dict 107825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart should not contain a leading '/'. 108825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 109825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """ 110825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart self._config_file_templates.update(template_dict) 111825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 112825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 113825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart def add_config_values(self, value_dict): 114825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """Add a name-value dict to the set of values for the config template 115825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 116825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart @param value_dict dict containing key-value pairs of values that will 117825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart be applied to the config file templates. 118825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 119825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """ 120825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart self._config_file_values.update(value_dict) 121825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 122825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 1236adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley def add_copied_config_files(self, files): 1246adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley """Add |files| to the set to be copied to the chroot. 1256adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley 1266adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley @param files iterable object containing a list of files to 1276adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley be copied into the chroot. These elements should not contain a 1286adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley leading '/'. 1296adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley 1306adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley """ 1316adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley self._copied_config_files += files 1326adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley 1336adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley 134825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart def add_root_directories(self, directories): 135825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """Add |directories| to the set created within the chroot. 136825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 137825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart @param directories list/tuple containing a list of directories to 138825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart be created in the chroot. These elements should not contain a 139825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart leading '/'. 140825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 141825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """ 142825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart self._root_directories += directories 143825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 144825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 145825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart def add_startup_command(self, command): 146825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """Add a command to the script run when the chroot starts up. 147825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 148825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart @param command string containing the command line to run. 149825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 150825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """ 151825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart self._config_file_templates[self.STARTUP] += '%s\n' % command 152825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 153825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 154825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart def get_log_contents(self): 155825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """Return the logfiles from the chroot.""" 156825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart return utils.system_output("head -10000 %s" % 1570174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart self.chroot_path("var/log/*")) 1580174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart 1590174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart 1606adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley def bridge_dbus_namespaces(self): 1616adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley """Make the system DBus daemon visible inside the chroot.""" 1626adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley # Need the system socket and the machine-id. 1636adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley self._bind_root_directories += self.DBUS_BRIDGE_DIRECTORIES 1646adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley 1656adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley 1660174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart def chroot_path(self, path): 1670174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart """Returns the the path within the chroot for |path|. 1680174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart 1690174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart @param path string filename within the choot. This should not 1700174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart contain a leading '/'. 1710174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart 1720174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart """ 1730174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart return os.path.join(self._temp_dir, path.lstrip('/')) 174825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 175825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 17689003937480a6ca69bfe30c04d7ec198fc7bcf46Paul Stewart def get_pid_file(self, pid_file, missing_ok=False): 177825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """Returns the integer contents of |pid_file| in the chroot. 178825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 179825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart @param pid_file string containing the filename within the choot 180825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart to read and convert to an integer. This should not contain a 181825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart leading '/'. 1825f0a57585e4ea85033b7ffcb68177174ecd1e685Paul Stewart @param missing_ok bool indicating whether exceptions due to failure 1835f0a57585e4ea85033b7ffcb68177174ecd1e685Paul Stewart to open the pid file should be caught. If true a missing pid 1845f0a57585e4ea85033b7ffcb68177174ecd1e685Paul Stewart file will cause this method to return 0. If false, a missing 1855f0a57585e4ea85033b7ffcb68177174ecd1e685Paul Stewart pid file will cause an exception. 186825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 187825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """ 18889003937480a6ca69bfe30c04d7ec198fc7bcf46Paul Stewart chroot_pid_file = self.chroot_path(pid_file) 1895f0a57585e4ea85033b7ffcb68177174ecd1e685Paul Stewart try: 1905f0a57585e4ea85033b7ffcb68177174ecd1e685Paul Stewart with open(chroot_pid_file) as f: 1915f0a57585e4ea85033b7ffcb68177174ecd1e685Paul Stewart return int(f.read()) 1925f0a57585e4ea85033b7ffcb68177174ecd1e685Paul Stewart except IOError, e: 1935f0a57585e4ea85033b7ffcb68177174ecd1e685Paul Stewart if not missing_ok or e.errno != errno.ENOENT: 1945f0a57585e4ea85033b7ffcb68177174ecd1e685Paul Stewart raise e 1955f0a57585e4ea85033b7ffcb68177174ecd1e685Paul Stewart 19689003937480a6ca69bfe30c04d7ec198fc7bcf46Paul Stewart return 0 197825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 198825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 19989003937480a6ca69bfe30c04d7ec198fc7bcf46Paul Stewart def kill_pid_file(self, pid_file, missing_ok=False): 200825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """Kills the process belonging to |pid_file| in the chroot. 201825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 20289003937480a6ca69bfe30c04d7ec198fc7bcf46Paul Stewart @param pid_file string filename within the chroot to gain the process ID 203825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart which this method will kill. 20489003937480a6ca69bfe30c04d7ec198fc7bcf46Paul Stewart @param missing_ok bool indicating whether a missing pid file is okay, 20589003937480a6ca69bfe30c04d7ec198fc7bcf46Paul Stewart and should be ignored. 206825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 207825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """ 2086adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley pid = self.get_pid_file(pid_file, missing_ok=missing_ok) 20989003937480a6ca69bfe30c04d7ec198fc7bcf46Paul Stewart if missing_ok and pid == 0: 21089003937480a6ca69bfe30c04d7ec198fc7bcf46Paul Stewart return 21189003937480a6ca69bfe30c04d7ec198fc7bcf46Paul Stewart utils.system('kill %d' % pid, ignore_status=True) 212825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 213825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 214825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart def make_chroot(self): 215825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """Make a chroot filesystem.""" 216825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart self._temp_dir = utils.system_output('mktemp -d /tmp/chroot.XXXXXXXXX') 21789003937480a6ca69bfe30c04d7ec198fc7bcf46Paul Stewart utils.system('chmod go+rX %s' % self._temp_dir) 218825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart for rootdir in self._root_directories: 2190174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart os.mkdir(self.chroot_path(rootdir)) 220825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 221825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart self._jail_args = [] 2226adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley for rootdir in self._bind_root_directories: 223825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart src_path = os.path.join('/', rootdir) 2240174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart dst_path = self.chroot_path(rootdir) 225825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart if not os.path.exists(src_path): 226825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart continue 227825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart elif os.path.islink(src_path): 228825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart link_path = os.readlink(src_path) 229825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart os.symlink(link_path, dst_path) 230825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart else: 2316adc4bc45def76077f00302ff0afebb3a9552a6bChristopher Wiley os.makedirs(dst_path) # Recursively create directories. 23260dc4d6a6ea7620898027f77f1818f2a8acd72dbPaul Stewart mount_arg = '%s,%s' % (src_path, src_path) 23360dc4d6a6ea7620898027f77f1818f2a8acd72dbPaul Stewart if rootdir in self.BIND_ROOT_WRITABLE_DIRECTORIES: 23460dc4d6a6ea7620898027f77f1818f2a8acd72dbPaul Stewart mount_arg += ',1' 23560dc4d6a6ea7620898027f77f1818f2a8acd72dbPaul Stewart self._jail_args += [ '-b', mount_arg ] 236825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 2370174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart for config_file in self._copied_config_files: 2380174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart src_path = os.path.join('/', config_file) 2390174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart dst_path = self.chroot_path(config_file) 2400174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart if os.path.exists(src_path): 2410174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart shutil.copyfile(src_path, dst_path) 2420174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart 243825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 244825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart def move_interface_to_chroot_namespace(self): 245825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """Move network interface to the network namespace of the server.""" 246825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart utils.system('ip link set %s netns %d' % 2470174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart (self._interface, 2480174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart self.get_pid_file(self.STARTUP_PID_FILE))) 249825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 250825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 251e6f9e43354f1fb248530ce2beea6cb448cb7fba0Paul Stewart def run(self, args, ignore_status=False): 252825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """Run a command in a chroot, within a separate network namespace. 253825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 254825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart @param args list containing the command line arguments to run. 255e6f9e43354f1fb248530ce2beea6cb448cb7fba0Paul Stewart @param ignore_status bool set to true if a failure should be ignored. 256825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 257825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """ 258825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart utils.system('minijail0 -e -C %s %s' % 259e6f9e43354f1fb248530ce2beea6cb448cb7fba0Paul Stewart (self._temp_dir, ' '.join(self._jail_args + args)), 260e6f9e43354f1fb248530ce2beea6cb448cb7fba0Paul Stewart ignore_status=ignore_status) 261825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 262825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart 263825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart def write_configs(self): 264825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart """Write out config files""" 265825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart for config_file, template in self._config_file_templates.iteritems(): 2660174334399baf09670d361acfb2ac84ab951b3b4Paul Stewart with open(self.chroot_path(config_file), 'w') as f: 267825b19d16d586a0bd48ae3364e3b4da36c300933Paul Stewart f.write(template % self._config_file_values) 268