diff options
| author | William Wolf <throughnothing@gmail.com> | 2011-08-11 15:49:58 -0400 |
|---|---|---|
| committer | William Wolf <throughnothing@gmail.com> | 2011-08-11 15:49:58 -0400 |
| commit | 5704f0a0cbc06c04a8ed6bf72bc1b5214016d083 (patch) | |
| tree | 3bcee1f95393fce3273aa6618638fa6f4d3a986b | |
| parent | 4275c9062e2d89c30472ba6646fd3c2503c0e984 (diff) | |
| parent | fe0bde67193ce76376e72a7263b89240a63722a8 (diff) | |
| download | nova-5704f0a0cbc06c04a8ed6bf72bc1b5214016d083.tar.gz nova-5704f0a0cbc06c04a8ed6bf72bc1b5214016d083.tar.xz nova-5704f0a0cbc06c04a8ed6bf72bc1b5214016d083.zip | |
merge from trunk
| -rw-r--r-- | nova/console/xvp.py | 1 | ||||
| -rw-r--r-- | nova/flags.py | 3 | ||||
| -rw-r--r-- | nova/network/linux_net.py | 142 | ||||
| -rw-r--r-- | nova/tests/fake_utils.py | 8 | ||||
| -rw-r--r-- | nova/tests/test_libvirt.py | 10 | ||||
| -rw-r--r-- | nova/tests/test_volume.py | 10 | ||||
| -rw-r--r-- | nova/tests/test_xenapi.py | 10 | ||||
| -rw-r--r-- | nova/utils.py | 15 | ||||
| -rw-r--r-- | nova/virt/disk.py | 47 | ||||
| -rw-r--r-- | nova/virt/libvirt/connection.py | 14 | ||||
| -rw-r--r-- | nova/virt/libvirt/vif.py | 16 | ||||
| -rw-r--r-- | nova/virt/xenapi/vm_utils.py | 15 | ||||
| -rw-r--r-- | nova/virt/xenapi/vmops.py | 26 | ||||
| -rw-r--r-- | nova/virt/xenapi/volume_utils.py | 4 | ||||
| -rw-r--r-- | nova/volume/driver.py | 101 |
15 files changed, 216 insertions, 206 deletions
diff --git a/nova/console/xvp.py b/nova/console/xvp.py index 3cd287183..2d6842044 100644 --- a/nova/console/xvp.py +++ b/nova/console/xvp.py @@ -20,7 +20,6 @@ import fcntl import os import signal -import subprocess from Cheetah import Template diff --git a/nova/flags.py b/nova/flags.py index eb6366ed9..7916501a4 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -392,3 +392,6 @@ DEFINE_bool('start_guests_on_host_boot', False, 'Whether to restart guests when the host reboots') DEFINE_bool('resume_guests_state_on_host_boot', False, 'Whether to start guests, that was running before the host reboot') + +DEFINE_string('root_helper', 'sudo', + 'Command prefix to use for running commands as root') diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 8ace07884..4e1e1f85a 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -296,14 +296,14 @@ class IptablesManager(object): for cmd, tables in s: for table in tables: - current_table, _ = self.execute('sudo', - '%s-save' % (cmd,), + current_table, _ = self.execute('%s-save' % (cmd,), '-t', '%s' % (table,), + run_as_root=True, attempts=5) current_lines = current_table.split('\n') new_filter = self._modify_rules(current_lines, tables[table]) - self.execute('sudo', '%s-restore' % (cmd,), + self.execute('%s-restore' % (cmd,), run_as_root=True, process_input='\n'.join(new_filter), attempts=5) @@ -396,21 +396,22 @@ def init_host(): def bind_floating_ip(floating_ip, check_exit_code=True): """Bind ip to public interface.""" - _execute('sudo', 'ip', 'addr', 'add', floating_ip, + _execute('ip', 'addr', 'add', floating_ip, 'dev', FLAGS.public_interface, - check_exit_code=check_exit_code) + run_as_root=True, check_exit_code=check_exit_code) def unbind_floating_ip(floating_ip): """Unbind a public ip from public interface.""" - _execute('sudo', 'ip', 'addr', 'del', floating_ip, - 'dev', FLAGS.public_interface) + _execute('ip', 'addr', 'del', floating_ip, + 'dev', FLAGS.public_interface, run_as_root=True) def ensure_metadata_ip(): """Sets up local metadata ip.""" - _execute('sudo', 'ip', 'addr', 'add', '169.254.169.254/32', - 'scope', 'link', 'dev', 'lo', check_exit_code=False) + _execute('ip', 'addr', 'add', '169.254.169.254/32', + 'scope', 'link', 'dev', 'lo', + run_as_root=True, check_exit_code=False) def ensure_vlan_forward(public_ip, port, private_ip): @@ -464,9 +465,11 @@ def ensure_vlan(vlan_num, bridge_interface): interface = 'vlan%s' % vlan_num if not _device_exists(interface): LOG.debug(_('Starting VLAN inteface %s'), interface) - _execute('sudo', 'vconfig', 'set_name_type', 'VLAN_PLUS_VID_NO_PAD') - _execute('sudo', 'vconfig', 'add', bridge_interface, vlan_num) - _execute('sudo', 'ip', 'link', 'set', interface, 'up') + _execute('vconfig', 'set_name_type', 'VLAN_PLUS_VID_NO_PAD', + run_as_root=True) + _execute('vconfig', 'add', bridge_interface, vlan_num, + run_as_root=True) + _execute('ip', 'link', 'set', interface, 'up', run_as_root=True) return interface @@ -487,58 +490,62 @@ def ensure_bridge(bridge, interface, net_attrs=None): """ if not _device_exists(bridge): LOG.debug(_('Starting Bridge interface for %s'), interface) - _execute('sudo', 'brctl', 'addbr', bridge) - _execute('sudo', 'brctl', 'setfd', bridge, 0) - # _execute('sudo brctl setageing %s 10' % bridge) - _execute('sudo', 'brctl', 'stp', bridge, 'off') - _execute('sudo', 'ip', 'link', 'set', bridge, 'up') + _execute('brctl', 'addbr', bridge, run_as_root=True) + _execute('brctl', 'setfd', bridge, 0, run_as_root=True) + _execute('brctl', 'stp', bridge, 'off', run_as_root=True) + _execute('ip', 'link', 'set', bridge, 'up', run_as_root=True) if net_attrs: # NOTE(vish): The ip for dnsmasq has to be the first address on the # bridge for it to respond to reqests properly suffix = net_attrs['cidr'].rpartition('/')[2] - out, err = _execute('sudo', 'ip', 'addr', 'add', + out, err = _execute('ip', 'addr', 'add', '%s/%s' % (net_attrs['dhcp_server'], suffix), 'brd', net_attrs['broadcast'], 'dev', bridge, + run_as_root=True, check_exit_code=False) if err and err != 'RTNETLINK answers: File exists\n': raise exception.Error('Failed to add ip: %s' % err) if(FLAGS.use_ipv6): - _execute('sudo', 'ip', '-f', 'inet6', 'addr', + _execute('ip', '-f', 'inet6', 'addr', 'change', net_attrs['cidr_v6'], - 'dev', bridge) + 'dev', bridge, run_as_root=True) # NOTE(vish): If the public interface is the same as the # bridge, then the bridge has to be in promiscuous # to forward packets properly. if(FLAGS.public_interface == bridge): - _execute('sudo', 'ip', 'link', 'set', - 'dev', bridge, 'promisc', 'on') + _execute('ip', 'link', 'set', + 'dev', bridge, 'promisc', 'on', run_as_root=True) if interface: # NOTE(vish): This will break if there is already an ip on the # interface, so we move any ips to the bridge gateway = None - out, err = _execute('sudo', 'route', '-n') + out, err = _execute('route', '-n', run_as_root=True) for line in out.split('\n'): fields = line.split() if fields and fields[0] == '0.0.0.0' and fields[-1] == interface: gateway = fields[1] - _execute('sudo', 'route', 'del', 'default', 'gw', gateway, - 'dev', interface, check_exit_code=False) - out, err = _execute('sudo', 'ip', 'addr', 'show', 'dev', interface, - 'scope', 'global') + _execute('route', 'del', 'default', 'gw', gateway, + 'dev', interface, + check_exit_code=False, run_as_root=True) + out, err = _execute('ip', 'addr', 'show', 'dev', interface, + 'scope', 'global', run_as_root=True) for line in out.split('\n'): fields = line.split() if fields and fields[0] == 'inet': params = fields[1:-1] - _execute(*_ip_bridge_cmd('del', params, fields[-1])) - _execute(*_ip_bridge_cmd('add', params, bridge)) + _execute(*_ip_bridge_cmd('del', params, fields[-1]), + run_as_root=True) + _execute(*_ip_bridge_cmd('add', params, bridge), + run_as_root=True) if gateway: - _execute('sudo', 'route', 'add', 'default', 'gw', gateway) - out, err = _execute('sudo', 'brctl', 'addif', bridge, interface, - check_exit_code=False) + _execute('route', 'add', 'default', 'gw', gateway, + run_as_root=True) + out, err = _execute('brctl', 'addif', bridge, interface, + check_exit_code=False, run_as_root=True) if (err and err != "device %s is already a member of a bridge; can't " "enslave it to bridge %s.\n" % (interface, bridge)): @@ -602,18 +609,33 @@ def update_dhcp(context, network_ref): check_exit_code=False) if conffile in out: try: - _execute('sudo', 'kill', '-HUP', pid) + _execute('kill', '-HUP', pid, run_as_root=True) return except Exception as exc: # pylint: disable=W0703 LOG.debug(_('Hupping dnsmasq threw %s'), exc) else: LOG.debug(_('Pid %d is stale, relaunching dnsmasq'), pid) - # FLAGFILE and DNSMASQ_INTERFACE in env - env = {'FLAGFILE': FLAGS.dhcpbridge_flagfile, - 'DNSMASQ_INTERFACE': network_ref['bridge']} - command = _dnsmasq_cmd(network_ref) - _execute(*command, addl_env=env) + cmd = ['FLAGFILE=%s' % FLAGS.dhcpbridge_flagfile, + 'DNSMASQ_INTERFACE=%s' % network_ref['bridge'], + 'dnsmasq', + '--strict-order', + '--bind-interfaces', + '--interface=%s' % network_ref['bridge'], + '--conf-file=%s' % FLAGS.dnsmasq_config_file, + '--domain=%s' % FLAGS.dhcp_domain, + '--pid-file=%s' % _dhcp_file(network_ref['bridge'], 'pid'), + '--listen-address=%s' % network_ref['dhcp_server'], + '--except-interface=lo', + '--dhcp-range=%s,static,120s' % network_ref['dhcp_start'], + '--dhcp-lease-max=%s' % len(netaddr.IPNetwork(network_ref['cidr'])), + '--dhcp-hostsfile=%s' % _dhcp_file(network_ref['bridge'], 'conf'), + '--dhcp-script=%s' % FLAGS.dhcpbridge, + '--leasefile-ro'] + if FLAGS.dns_server: + cmd += ['-h', '-R', '--server=%s' % FLAGS.dns_server] + + _execute(*cmd, run_as_root=True) @utils.synchronized('radvd_start') @@ -646,13 +668,17 @@ interface %s % pid, check_exit_code=False) if conffile in out: try: - _execute('sudo', 'kill', pid) + _execute('kill', pid, run_as_root=True) except Exception as exc: # pylint: disable=W0703 LOG.debug(_('killing radvd threw %s'), exc) else: LOG.debug(_('Pid %d is stale, relaunching radvd'), pid) - command = _ra_cmd(network_ref) - _execute(*command) + + cmd = ['radvd', + '-C', '%s' % _ra_file(network_ref['bridge'], 'conf'), + '-p', '%s' % _ra_file(network_ref['bridge'], 'pid')] + + _execute(*cmd, run_as_root=True) def _host_lease(fixed_ip_ref): @@ -696,43 +722,13 @@ def _device_exists(device): return not err -def _dnsmasq_cmd(net): - """Builds dnsmasq command.""" - cmd = ['sudo', '-E', 'dnsmasq', - '--strict-order', - '--bind-interfaces', - '--interface=%s' % net['bridge'], - '--conf-file=%s' % FLAGS.dnsmasq_config_file, - '--domain=%s' % FLAGS.dhcp_domain, - '--pid-file=%s' % _dhcp_file(net['bridge'], 'pid'), - '--listen-address=%s' % net['dhcp_server'], - '--except-interface=lo', - '--dhcp-range=%s,static,120s' % net['dhcp_start'], - '--dhcp-lease-max=%s' % len(netaddr.IPNetwork(net['cidr'])), - '--dhcp-hostsfile=%s' % _dhcp_file(net['bridge'], 'conf'), - '--dhcp-script=%s' % FLAGS.dhcpbridge, - '--leasefile-ro'] - if FLAGS.dns_server: - cmd += ['-h', '-R', '--server=%s' % FLAGS.dns_server] - return cmd - - -def _ra_cmd(net): - """Builds radvd command.""" - cmd = ['sudo', '-E', 'radvd', -# '-u', 'nobody', - '-C', '%s' % _ra_file(net['bridge'], 'conf'), - '-p', '%s' % _ra_file(net['bridge'], 'pid')] - return cmd - - def _stop_dnsmasq(network): """Stops the dnsmasq instance for a given network.""" pid = _dnsmasq_pid_for(network) if pid: try: - _execute('sudo', 'kill', '-TERM', pid) + _execute('kill', '-TERM', pid, run_as_root=True) except Exception as exc: # pylint: disable=W0703 LOG.debug(_('Killing dnsmasq threw %s'), exc) @@ -788,7 +784,7 @@ def _ra_pid_for(bridge): def _ip_bridge_cmd(action, params, device): """Build commands to add/del ips to bridges/devices.""" - cmd = ['sudo', 'ip', 'addr', action] + cmd = ['ip', 'addr', action] cmd.extend(params) cmd.extend(['dev', device]) return cmd diff --git a/nova/tests/fake_utils.py b/nova/tests/fake_utils.py index be59970c9..84ab641ea 100644 --- a/nova/tests/fake_utils.py +++ b/nova/tests/fake_utils.py @@ -64,8 +64,10 @@ def fake_execute(*cmd_parts, **kwargs): global _fake_execute_repliers process_input = kwargs.get('process_input', None) - addl_env = kwargs.get('addl_env', None) check_exit_code = kwargs.get('check_exit_code', 0) + delay_on_retry = kwargs.get('delay_on_retry', True) + attempts = kwargs.get('attempts', 1) + run_as_root = kwargs.get('run_as_root', False) cmd_str = ' '.join(str(part) for part in cmd_parts) LOG.debug(_("Faking execution of cmd (subprocess): %s"), cmd_str) @@ -87,7 +89,9 @@ def fake_execute(*cmd_parts, **kwargs): # Alternative is a function, so call it reply = reply_handler(cmd_parts, process_input=process_input, - addl_env=addl_env, + delay_on_retry=delay_on_retry, + attempts=attempts, + run_as_root=run_as_root, check_exit_code=check_exit_code) except exception.ProcessExecutionError as e: LOG.debug(_('Faked command raised an exception %s' % str(e))) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index 17f1be967..2180cf4f0 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -921,18 +921,18 @@ class IptablesFirewallTestCase(test.TestCase): # self.fw.add_instance(instance_ref) def fake_iptables_execute(*cmd, **kwargs): process_input = kwargs.get('process_input', None) - if cmd == ('sudo', 'ip6tables-save', '-t', 'filter'): + if cmd == ('ip6tables-save', '-t', 'filter'): return '\n'.join(self.in6_filter_rules), None - if cmd == ('sudo', 'iptables-save', '-t', 'filter'): + if cmd == ('iptables-save', '-t', 'filter'): return '\n'.join(self.in_filter_rules), None - if cmd == ('sudo', 'iptables-save', '-t', 'nat'): + if cmd == ('iptables-save', '-t', 'nat'): return '\n'.join(self.in_nat_rules), None - if cmd == ('sudo', 'iptables-restore'): + if cmd == ('iptables-restore',): lines = process_input.split('\n') if '*filter' in lines: self.out_rules = lines return '', '' - if cmd == ('sudo', 'ip6tables-restore'): + if cmd == ('ip6tables-restore',): lines = process_input.split('\n') if '*filter' in lines: self.out6_rules = lines diff --git a/nova/tests/test_volume.py b/nova/tests/test_volume.py index c0f89601f..7888b6b0b 100644 --- a/nova/tests/test_volume.py +++ b/nova/tests/test_volume.py @@ -414,8 +414,9 @@ class ISCSITestCase(DriverTestCase): self.mox.StubOutWithMock(self.volume.driver, '_execute') for i in volume_id_list: tid = db.volume_get_iscsi_target_num(self.context, i) - self.volume.driver._execute("sudo", "ietadm", "--op", "show", - "--tid=%(tid)d" % locals()) + self.volume.driver._execute("ietadm", "--op", "show", + "--tid=%(tid)d" % locals(), + run_as_root=True) self.stream.truncate(0) self.mox.ReplayAll() @@ -433,8 +434,9 @@ class ISCSITestCase(DriverTestCase): # the first vblade process isn't running tid = db.volume_get_iscsi_target_num(self.context, volume_id_list[0]) self.mox.StubOutWithMock(self.volume.driver, '_execute') - self.volume.driver._execute("sudo", "ietadm", "--op", "show", - "--tid=%(tid)d" % locals()).AndRaise( + self.volume.driver._execute("ietadm", "--op", "show", + "--tid=%(tid)d" % locals(), + run_as_root=True).AndRaise( exception.ProcessExecutionError()) self.mox.ReplayAll() diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 952277e3f..1deb5a780 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -548,8 +548,8 @@ class XenAPIVMTestCase(test.TestCase): return '', '' fake_utils.fake_execute_set_repliers([ - # Capture the sudo tee .../etc/network/interfaces command - (r'(sudo\s+)?tee.*interfaces', _tee_handler), + # Capture the tee .../etc/network/interfaces command + (r'tee.*interfaces', _tee_handler), ]) self._test_spawn(glance_stubs.FakeGlance.IMAGE_MACHINE, glance_stubs.FakeGlance.IMAGE_KERNEL, @@ -592,9 +592,9 @@ class XenAPIVMTestCase(test.TestCase): return '', '' fake_utils.fake_execute_set_repliers([ - (r'(sudo\s+)?mount', _mount_handler), - (r'(sudo\s+)?umount', _umount_handler), - (r'(sudo\s+)?tee.*interfaces', _tee_handler)]) + (r'mount', _mount_handler), + (r'umount', _umount_handler), + (r'tee.*interfaces', _tee_handler)]) self._test_spawn(1, 2, 3, check_injection=True) # tee must not run in this case, where an injection-capable diff --git a/nova/utils.py b/nova/utils.py index 4b068e3a5..36374dbbb 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -28,6 +28,7 @@ import netaddr import os import random import re +import shlex import socket import struct import sys @@ -131,40 +132,42 @@ def execute(*cmd, **kwargs): :cmd Passed to subprocess.Popen. :process_input Send to opened process. - :addl_env Added to the processes env. :check_exit_code Defaults to 0. Raise exception.ProcessExecutionError unless program exits with this code. :delay_on_retry True | False. Defaults to True. If set to True, wait a short amount of time before retrying. :attempts How many times to retry cmd. + :run_as_root True | False. Defaults to False. If set to True, + the command is prefixed by the command specified + in the root_helper FLAG. :raises exception.Error on receiving unknown arguments :raises exception.ProcessExecutionError """ process_input = kwargs.pop('process_input', None) - addl_env = kwargs.pop('addl_env', None) check_exit_code = kwargs.pop('check_exit_code', 0) delay_on_retry = kwargs.pop('delay_on_retry', True) attempts = kwargs.pop('attempts', 1) + run_as_root = kwargs.pop('run_as_root', False) if len(kwargs): raise exception.Error(_('Got unknown keyword args ' 'to utils.execute: %r') % kwargs) + + if run_as_root: + cmd = shlex.split(FLAGS.root_helper) + list(cmd) cmd = map(str, cmd) while attempts > 0: attempts -= 1 try: LOG.debug(_('Running cmd (subprocess): %s'), ' '.join(cmd)) - env = os.environ.copy() - if addl_env: - env.update(addl_env) _PIPE = subprocess.PIPE # pylint: disable=E1101 obj = subprocess.Popen(cmd, stdin=_PIPE, stdout=_PIPE, stderr=_PIPE, - env=env) + close_fds=True) result = None if process_input is not None: result = obj.communicate(process_input) diff --git a/nova/virt/disk.py b/nova/virt/disk.py index f8aea1f34..19f3ec185 100644 --- a/nova/virt/disk.py +++ b/nova/virt/disk.py @@ -73,7 +73,7 @@ def inject_data(image, key=None, net=None, partition=None, nbd=False): try: if not partition is None: # create partition - out, err = utils.execute('sudo', 'kpartx', '-a', device) + out, err = utils.execute('kpartx', '-a', device, run_as_root=True) if err: raise exception.Error(_('Failed to load partition: %s') % err) mapped_device = '/dev/mapper/%sp%s' % (device.split('/')[-1], @@ -90,14 +90,14 @@ def inject_data(image, key=None, net=None, partition=None, nbd=False): mapped_device) # Configure ext2fs so that it doesn't auto-check every N boots - out, err = utils.execute('sudo', 'tune2fs', - '-c', 0, '-i', 0, mapped_device) + out, err = utils.execute('tune2fs', '-c', 0, '-i', 0, + mapped_device, run_as_root=True) tmpdir = tempfile.mkdtemp() try: # mount loopback to dir - out, err = utils.execute( - 'sudo', 'mount', mapped_device, tmpdir) + out, err = utils.execute('mount', mapped_device, tmpdir, + run_as_root=True) if err: raise exception.Error(_('Failed to mount filesystem: %s') % err) @@ -106,14 +106,14 @@ def inject_data(image, key=None, net=None, partition=None, nbd=False): inject_data_into_fs(tmpdir, key, net, utils.execute) finally: # unmount device - utils.execute('sudo', 'umount', mapped_device) + utils.execute('umount', mapped_device, run_as_root=True) finally: # remove temporary directory utils.execute('rmdir', tmpdir) finally: if not partition is None: # remove partitions - utils.execute('sudo', 'kpartx', '-d', device) + utils.execute('kpartx', '-d', device, run_as_root=True) finally: _unlink_device(device, nbd) @@ -128,7 +128,7 @@ def setup_container(image, container_dir=None, nbd=False): """ try: device = _link_device(image, nbd) - utils.execute('sudo', 'mount', device, container_dir) + utils.execute('mount', device, container_dir, run_as_root=True) except Exception, exn: LOG.exception(_('Failed to mount filesystem: %s'), exn) _unlink_device(device, nbd) @@ -144,9 +144,9 @@ def destroy_container(target, instance, nbd=False): """ try: container_dir = '%s/rootfs' % target - utils.execute('sudo', 'umount', container_dir) + utils.execute('umount', container_dir, run_as_root=True) finally: - out, err = utils.execute('sudo', 'losetup', '-a') + out, err = utils.execute('losetup', '-a', run_as_root=True) for loop in out.splitlines(): if instance['name'] in loop: device = loop.split(loop, ':') @@ -157,7 +157,7 @@ def _link_device(image, nbd): """Link image to device using loopback or nbd""" if nbd: device = _allocate_device() - utils.execute('sudo', 'qemu-nbd', '-c', device, image) + utils.execute('qemu-nbd', '-c', device, image, run_as_root=True) # NOTE(vish): this forks into another process, so give it a chance # to set up before continuuing for i in xrange(FLAGS.timeout_nbd): @@ -166,7 +166,8 @@ def _link_device(image, nbd): time.sleep(1) raise exception.Error(_('nbd device %s did not show up') % device) else: - out, err = utils.execute('sudo', 'losetup', '--find', '--show', image) + out, err = utils.execute('losetup', '--find', '--show', image, + run_as_root=True) if err: raise exception.Error(_('Could not attach image to loopback: %s') % err) @@ -176,10 +177,10 @@ def _link_device(image, nbd): def _unlink_device(device, nbd): """Unlink image from device using loopback or nbd""" if nbd: - utils.execute('sudo', 'qemu-nbd', '-d', device) + utils.execute('qemu-nbd', '-d', device, run_as_root=True) _free_device(device) else: - utils.execute('sudo', 'losetup', '--detach', device) + utils.execute('losetup', '--detach', device, run_as_root=True) _DEVICES = ['/dev/nbd%s' % i for i in xrange(FLAGS.max_nbd_devices)] @@ -220,12 +221,12 @@ def _inject_key_into_fs(key, fs, execute=None): fs is the path to the base of the filesystem into which to inject the key. """ sshdir = os.path.join(fs, 'root', '.ssh') - utils.execute('sudo', 'mkdir', '-p', sshdir) # existing dir doesn't matter - utils.execute('sudo', 'chown', 'root', sshdir) - utils.execute('sudo', 'chmod', '700', sshdir) + utils.execute('mkdir', '-p', sshdir, run_as_root=True) + utils.execute('chown', 'root', sshdir, run_as_root=True) + utils.execute('chmod', '700', sshdir, run_as_root=True) keyfile = os.path.join(sshdir, 'authorized_keys') - utils.execute('sudo', 'tee', '-a', keyfile, - process_input='\n' + key.strip() + '\n') + utils.execute('tee', '-a', keyfile, + process_input='\n' + key.strip() + '\n', run_as_root=True) def _inject_net_into_fs(net, fs, execute=None): @@ -234,8 +235,8 @@ def _inject_net_into_fs(net, fs, execute=None): net is the contents of /etc/network/interfaces. """ netdir = os.path.join(os.path.join(fs, 'etc'), 'network') - utils.execute('sudo', 'mkdir', '-p', netdir) # existing dir doesn't matter - utils.execute('sudo', 'chown', 'root:root', netdir) - utils.execute('sudo', 'chmod', 755, netdir) + utils.execute('mkdir', '-p', netdir, run_as_root=True) + utils.execute('chown', 'root:root', netdir, run_as_root=True) + utils.execute('chmod', 755, netdir, run_as_root=True) netfile = os.path.join(netdir, 'interfaces') - utils.execute('sudo', 'tee', netfile, process_input=net) + utils.execute('tee', netfile, process_input=net, run_as_root=True) diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 16efa7292..6d043577a 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -43,7 +43,6 @@ import os import random import re import shutil -import subprocess import sys import tempfile import time @@ -612,9 +611,10 @@ class LibvirtConnection(driver.ComputeDriver): if virsh_output.startswith('/dev/'): LOG.info(_("cool, it's a device")) - out, err = utils.execute('sudo', 'dd', + out, err = utils.execute('dd', "if=%s" % virsh_output, 'iflag=nonblock', + run_as_root=True, check_exit_code=False) return out else: @@ -637,7 +637,7 @@ class LibvirtConnection(driver.ComputeDriver): console_log = os.path.join(FLAGS.instances_path, instance['name'], 'console.log') - utils.execute('sudo', 'chown', os.getuid(), console_log) + utils.execute('chown', os.getuid(), console_log, run_as_root=True) if FLAGS.libvirt_type == 'xen': # Xen is special @@ -685,10 +685,10 @@ class LibvirtConnection(driver.ComputeDriver): ajaxterm_cmd = 'sudo socat - %s' \ % get_pty_for_instance(instance['name']) - cmd = '%s/tools/ajaxterm/ajaxterm.py --command "%s" -t %s -p %s' \ - % (utils.novadir(), ajaxterm_cmd, token, port) + cmd = ['%s/tools/ajaxterm/ajaxterm.py' % utils.novadir(), + '--command', ajaxterm_cmd, '-t', token, '-p', port] - subprocess.Popen(cmd, shell=True) + utils.execute(cmd) return {'token': token, 'host': host, 'port': port} def get_host_ip_addr(self): @@ -947,7 +947,7 @@ class LibvirtConnection(driver.ComputeDriver): ' data into image %(img_id)s (%(e)s)') % locals()) if FLAGS.libvirt_type == 'uml': - utils.execute('sudo', 'chown', 'root', basepath('disk')) + utils.execute('chown', 'root', basepath('disk'), run_as_root=True) if FLAGS.libvirt_type == 'uml': _disk_prefix = 'ubd' diff --git a/nova/virt/libvirt/vif.py b/nova/virt/libvirt/vif.py index 711b05bae..e243d4fa0 100644 --- a/nova/virt/libvirt/vif.py +++ b/nova/virt/libvirt/vif.py @@ -103,16 +103,18 @@ class LibvirtOpenVswitchDriver(VIFDriver): dev = "tap-%s" % vif_id iface_id = "nova-" + vif_id if not linux_net._device_exists(dev): - utils.execute('sudo', 'ip', 'tuntap', 'add', dev, 'mode', 'tap') - utils.execute('sudo', 'ip', 'link', 'set', dev, 'up') - utils.execute('sudo', 'ovs-vsctl', '--', '--may-exist', 'add-port', + utils.execute('ip', 'tuntap', 'add', dev, 'mode', 'tap', + run_as_root=True) + utils.execute('ip', 'link', 'set', dev, 'up', run_as_root=True) + utils.execute('ovs-vsctl', '--', '--may-exist', 'add-port', FLAGS.libvirt_ovs_bridge, dev, '--', 'set', 'Interface', dev, "external-ids:iface-id=%s" % iface_id, '--', 'set', 'Interface', dev, "external-ids:iface-status=active", '--', 'set', 'Interface', dev, - "external-ids:attached-mac=%s" % mapping['mac']) + "external-ids:attached-mac=%s" % mapping['mac'], + run_as_root=True) result = { 'script': '', @@ -126,9 +128,9 @@ class LibvirtOpenVswitchDriver(VIFDriver): vif_id = str(instance['id']) + "-" + str(network['id']) dev = "tap-%s" % vif_id try: - utils.execute('sudo', 'ovs-vsctl', 'del-port', - network['bridge'], dev) - utils.execute('sudo', 'ip', 'link', 'delete', dev) + utils.execute('ovs-vsctl', 'del-port', + network['bridge'], dev, run_as_root=True) + utils.execute('ip', 'link', 'delete', dev, run_as_root=True) except exception.ProcessExecutionError: LOG.warning(_("Failed while unplugging vif of instance '%s'"), instance['name']) diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index d20746076..6c44d53d4 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -967,7 +967,7 @@ def _stream_disk(dev, image_type, virtual_size, image_file): offset = MBR_SIZE_BYTES _write_partition(virtual_size, dev) - utils.execute('sudo', 'chown', os.getuid(), '/dev/%s' % dev) + utils.execute('chown', os.getuid(), '/dev/%s' % dev, run_as_root=True) with open('/dev/%s' % dev, 'wb') as f: f.seek(offset) @@ -986,10 +986,11 @@ def _write_partition(virtual_size, dev): def execute(*cmd, **kwargs): return utils.execute(*cmd, **kwargs) - execute('sudo', 'parted', '--script', dest, 'mklabel', 'msdos') - execute('sudo', 'parted', '--script', dest, 'mkpart', 'primary', + execute('parted', '--script', dest, 'mklabel', 'msdos', run_as_root=True) + execute('parted', '--script', dest, 'mkpart', 'primary', '%ds' % primary_first, - '%ds' % primary_last) + '%ds' % primary_last, + run_as_root=True) LOG.debug(_('Writing partition table %s done.'), dest) @@ -1002,9 +1003,9 @@ def get_name_label_for_image(image): def _mount_filesystem(dev_path, dir): """mounts the device specified by dev_path in dir""" try: - out, err = utils.execute('sudo', 'mount', + out, err = utils.execute('mount', '-t', 'ext2,ext3', - dev_path, dir) + dev_path, dir, run_as_root=True) except exception.ProcessExecutionError as e: err = str(e) return err @@ -1056,7 +1057,7 @@ def _mounted_processing(device, key, net): disk.inject_data_into_fs(tmpdir, key, net, utils.execute) finally: - utils.execute('sudo', 'umount', dev_path) + utils.execute('umount', dev_path, run_as_root=True) else: LOG.info(_('Failed to mount filesystem (expected for ' 'non-linux instances): %s') % err) diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 50aa0d3b2..b9cd59946 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -1334,12 +1334,6 @@ class VMOps(object): ######################################################################## -def _runproc(cmd): - pipe = subprocess.PIPE - return subprocess.Popen([cmd], shell=True, stdin=pipe, stdout=pipe, - stderr=pipe, close_fds=True) - - class SimpleDH(object): """ This class wraps all the functionality needed to implement @@ -1396,22 +1390,18 @@ class SimpleDH(object): mpi = M2Crypto.m2.bn_to_mpi(bn) return mpi - def _run_ssl(self, text, extra_args=None): - if not extra_args: - extra_args = '' - cmd = 'enc -aes-128-cbc -A -a -pass pass:%s -nosalt %s' % ( - self._shared, extra_args) - proc = _runproc('openssl %s' % cmd) - proc.stdin.write(text) - proc.stdin.close() - proc.wait() - err = proc.stderr.read() + def _run_ssl(self, text, decrypt=False): + cmd = ['openssl', 'aes-128-cbc', '-A', '-a', '-pass', + 'pass:%s' % self._shared, '-nosalt'] + if decrypt: + cmd.append('-d') + out, err = utils.execute(*cmd, process_input=text) if err: raise RuntimeError(_('OpenSSL error: %s') % err) - return proc.stdout.read() + return out def encrypt(self, text): return self._run_ssl(text).strip('\n') def decrypt(self, text): - return self._run_ssl(text, '-d') + return self._run_ssl(text, decrypt=True) diff --git a/nova/virt/xenapi/volume_utils.py b/nova/virt/xenapi/volume_utils.py index 7821a4f7e..5d5eb824f 100644 --- a/nova/virt/xenapi/volume_utils.py +++ b/nova/virt/xenapi/volume_utils.py @@ -252,10 +252,10 @@ def _get_target(volume_id): volume_id) result = (None, None) try: - (r, _e) = utils.execute('sudo', 'iscsiadm', + (r, _e) = utils.execute('iscsiadm', '-m', 'discovery', '-t', 'sendtargets', - '-p', volume_ref['host']) + '-p', volume_ref['host'], run_as_root=True) except exception.ProcessExecutionError, exc: LOG.exception(exc) else: diff --git a/nova/volume/driver.py b/nova/volume/driver.py index 23e845deb..c99534c07 100644 --- a/nova/volume/driver.py +++ b/nova/volume/driver.py @@ -65,14 +65,14 @@ class VolumeDriver(object): self._execute = execute self._sync_exec = sync_exec - def _try_execute(self, *command): + def _try_execute(self, *command, **kwargs): # NOTE(vish): Volume commands can partially fail due to timing, but # running them a second time on failure will usually # recover nicely. tries = 0 while True: try: - self._execute(*command) + self._execute(*command, **kwargs) return True except exception.ProcessExecutionError: tries = tries + 1 @@ -84,24 +84,26 @@ class VolumeDriver(object): def check_for_setup_error(self): """Returns an error if prerequisites aren't met""" - out, err = self._execute('sudo', 'vgs', '--noheadings', '-o', 'name') + out, err = self._execute('vgs', '--noheadings', '-o', 'name', + run_as_root=True) volume_groups = out.split() if not FLAGS.volume_group in volume_groups: raise exception.Error(_("volume group %s doesn't exist") % FLAGS.volume_group) def _create_volume(self, volume_name, sizestr): - self._try_execute('sudo', 'lvcreate', '-L', sizestr, '-n', - volume_name, FLAGS.volume_group) + self._try_execute('lvcreate', '-L', sizestr, '-n', + volume_name, FLAGS.volume_group, run_as_root=True) def _copy_volume(self, srcstr, deststr, size_in_g): - self._execute('sudo', 'dd', 'if=%s' % srcstr, 'of=%s' % deststr, - 'count=%d' % (size_in_g * 1024), 'bs=1M') + self._execute('dd', 'if=%s' % srcstr, 'of=%s' % deststr, + 'count=%d' % (size_in_g * 1024), 'bs=1M', + run_as_root=True) def _volume_not_present(self, volume_name): path_name = '%s/%s' % (FLAGS.volume_group, volume_name) try: - self._try_execute('sudo', 'lvdisplay', path_name) + self._try_execute('lvdisplay', path_name, run_as_root=True) except Exception as e: # If the volume isn't present return True @@ -112,9 +114,10 @@ class VolumeDriver(object): # zero out old volumes to prevent data leaking between users # TODO(ja): reclaiming space should be done lazy and low priority self._copy_volume('/dev/zero', self.local_path(volume), size_in_g) - self._try_execute('sudo', 'lvremove', '-f', "%s/%s" % + self._try_execute('lvremove', '-f', "%s/%s" % (FLAGS.volume_group, - self._escape_snapshot(volume['name']))) + self._escape_snapshot(volume['name'])), + run_as_root=True) def _sizestr(self, size_in_g): if int(size_in_g) == 0: @@ -147,10 +150,11 @@ class VolumeDriver(object): # TODO(yamahata): lvm can't delete origin volume only without # deleting derived snapshots. Can we do something fancy? - out, err = self._execute('sudo', 'lvdisplay', '--noheading', + out, err = self._execute('lvdisplay', '--noheading', '-C', '-o', 'Attr', '%s/%s' % (FLAGS.volume_group, - volume['name'])) + volume['name']), + run_as_root=True) # fake_execute returns None resulting unit test error if out: out = out.strip() @@ -162,10 +166,10 @@ class VolumeDriver(object): def create_snapshot(self, snapshot): """Creates a snapshot.""" orig_lv_name = "%s/%s" % (FLAGS.volume_group, snapshot['volume_name']) - self._try_execute('sudo', 'lvcreate', '-L', + self._try_execute('lvcreate', '-L', self._sizestr(snapshot['volume_size']), '--name', self._escape_snapshot(snapshot['name']), - '--snapshot', orig_lv_name) + '--snapshot', orig_lv_name, run_as_root=True) def delete_snapshot(self, snapshot): """Deletes a snapshot.""" @@ -233,13 +237,14 @@ class AOEDriver(VolumeDriver): blade_id) = self.db.volume_allocate_shelf_and_blade(context, volume['id']) self._try_execute( - 'sudo', 'vblade-persist', 'setup', + 'vblade-persist', 'setup', shelf_id, blade_id, FLAGS.aoe_eth_dev, "/dev/%s/%s" % (FLAGS.volume_group, - volume['name'])) + volume['name']), + run_as_root=True) # NOTE(vish): The standard _try_execute does not work here # because these methods throw errors if other # volumes on this host are in the process of @@ -248,28 +253,29 @@ class AOEDriver(VolumeDriver): # just wait a bit for the current volume to # be ready and ignore any errors. time.sleep(2) - self._execute('sudo', 'vblade-persist', 'auto', 'all', - check_exit_code=False) - self._execute('sudo', 'vblade-persist', 'start', 'all', - check_exit_code=False) + self._execute('vblade-persist', 'auto', 'all', + check_exit_code=False, run_as_root=True) + self._execute('vblade-persist', 'start', 'all', + check_exit_code=False, run_as_root=True) def remove_export(self, context, volume): """Removes an export for a logical volume.""" (shelf_id, blade_id) = self.db.volume_get_shelf_and_blade(context, volume['id']) - self._try_execute('sudo', 'vblade-persist', 'stop', - shelf_id, blade_id) - self._try_execute('sudo', 'vblade-persist', 'destroy', - shelf_id, blade_id) + self._try_execute('vblade-persist', 'stop', + shelf_id, blade_id, run_as_root=True) + self._try_execute('vblade-persist', 'destroy', + shelf_id, blade_id, run_as_root=True) def discover_volume(self, context, _volume): """Discover volume on a remote host.""" (shelf_id, blade_id) = self.db.volume_get_shelf_and_blade(context, _volume['id']) - self._execute('sudo', 'aoe-discover') - out, err = self._execute('sudo', 'aoe-stat', check_exit_code=False) + self._execute('aoe-discover', run_as_root=True) + out, err = self._execute('aoe-stat', check_exit_code=False, + run_as_root=True) device_path = 'e%(shelf_id)d.%(blade_id)d' % locals() if out.find(device_path) >= 0: return "/dev/etherd/%s" % device_path @@ -285,8 +291,8 @@ class AOEDriver(VolumeDriver): (shelf_id, blade_id) = self.db.volume_get_shelf_and_blade(context, volume_id) - cmd = ('sudo', 'vblade-persist', 'ls', '--no-header') - out, _err = self._execute(*cmd) + cmd = ('vblade-persist', 'ls', '--no-header') + out, _err = self._execute(*cmd, run_as_root=True) exported = False for line in out.split('\n'): param = line.split(' ') @@ -348,16 +354,18 @@ class ISCSIDriver(VolumeDriver): iscsi_name = "%s%s" % (FLAGS.iscsi_target_prefix, volume['name']) volume_path = "/dev/%s/%s" % (FLAGS.volume_group, volume['name']) - self._sync_exec('sudo', 'ietadm', '--op', 'new', + self._sync_exec('ietadm', '--op', 'new', "--tid=%s" % iscsi_target, '--params', "Name=%s" % iscsi_name, + run_as_root=True, check_exit_code=False) - self._sync_exec('sudo', 'ietadm', '--op', 'new', + self._sync_exec('ietadm', '--op', 'new', "--tid=%s" % iscsi_target, '--lun=0', '--params', "Path=%s,Type=fileio" % volume_path, + run_as_root=True, check_exit_code=False) def _ensure_iscsi_targets(self, context, host): @@ -378,13 +386,13 @@ class ISCSIDriver(VolumeDriver): volume['host']) iscsi_name = "%s%s" % (FLAGS.iscsi_target_prefix, volume['name']) volume_path = "/dev/%s/%s" % (FLAGS.volume_group, volume['name']) - self._execute('sudo', 'ietadm', '--op', 'new', + self._execute('ietadm', '--op', 'new', '--tid=%s' % iscsi_target, - '--params', 'Name=%s' % iscsi_name) - self._execute('sudo', 'ietadm', '--op', 'new', + '--params', 'Name=%s' % iscsi_name, run_as_root=True) + self._execute('ietadm', '--op', 'new', '--tid=%s' % iscsi_target, '--lun=0', '--params', - 'Path=%s,Type=fileio' % volume_path) + 'Path=%s,Type=fileio' % volume_path, run_as_root=True) def remove_export(self, context, volume): """Removes an export for a logical volume.""" @@ -399,18 +407,18 @@ class ISCSIDriver(VolumeDriver): try: # ietadm show will exit with an error # this export has already been removed - self._execute('sudo', 'ietadm', '--op', 'show', - '--tid=%s' % iscsi_target) + self._execute('ietadm', '--op', 'show', + '--tid=%s' % iscsi_target, run_as_root=True) except Exception as e: LOG.info(_("Skipping remove_export. No iscsi_target " + "is presently exported for volume: %d"), volume['id']) return - self._execute('sudo', 'ietadm', '--op', 'delete', + self._execute('ietadm', '--op', 'delete', '--tid=%s' % iscsi_target, - '--lun=0') - self._execute('sudo', 'ietadm', '--op', 'delete', - '--tid=%s' % iscsi_target) + '--lun=0', run_as_root=True) + self._execute('ietadm', '--op', 'delete', + '--tid=%s' % iscsi_target, run_as_root=True) def _do_iscsi_discovery(self, volume): #TODO(justinsb): Deprecate discovery and use stored info @@ -419,8 +427,9 @@ class ISCSIDriver(VolumeDriver): volume_name = volume['name'] - (out, _err) = self._execute('sudo', 'iscsiadm', '-m', 'discovery', - '-t', 'sendtargets', '-p', volume['host']) + (out, _err) = self._execute('iscsiadm', '-m', 'discovery', + '-t', 'sendtargets', '-p', volume['host'], + run_as_root=True) for target in out.splitlines(): if FLAGS.iscsi_ip_prefix in target and volume_name in target: return target @@ -483,10 +492,10 @@ class ISCSIDriver(VolumeDriver): return properties def _run_iscsiadm(self, iscsi_properties, iscsi_command): - (out, err) = self._execute('sudo', 'iscsiadm', '-m', 'node', '-T', + (out, err) = self._execute('iscsiadm', '-m', 'node', '-T', iscsi_properties['target_iqn'], '-p', iscsi_properties['target_portal'], - iscsi_command) + iscsi_command, run_as_root=True) LOG.debug("iscsiadm %s: stdout=%s stderr=%s" % (iscsi_command, out, err)) return (out, err) @@ -560,8 +569,8 @@ class ISCSIDriver(VolumeDriver): tid = self.db.volume_get_iscsi_target_num(context, volume_id) try: - self._execute('sudo', 'ietadm', '--op', 'show', - '--tid=%(tid)d' % locals()) + self._execute('ietadm', '--op', 'show', + '--tid=%(tid)d' % locals(), run_as_root=True) except exception.ProcessExecutionError, e: # Instances remount read-only in this case. # /etc/init.d/iscsitarget restart and rebooting nova-volume |
