* Removes rogue direct usage of subprocess module by proper utils.execute calls

* Adds a run_as_root parameter to utils.execute, that prefixes your command with FLAG.root_helper (which defaults to 'sudo')
* Turns all sudo calls into run_as_root=True calls
* Update fakes accordingly
* Replaces usage of "sudo -E" and "addl_env" parameter into passing environment in the command (allows it to be compatible with alternative sudo_helpers)
* Additionally, forces close_fds=True on all utils.execute calls, since it's a more secure default
This commit is contained in:
Thierry Carrez
2011-08-11 12:34:04 +00:00
committed by Tarmac
15 changed files with 216 additions and 206 deletions

View File

@@ -20,7 +20,6 @@
import fcntl
import os
import signal
import subprocess
from Cheetah import Template

View File

@@ -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')

View File

@@ -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

View File

@@ -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)))

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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'

View File

@@ -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'])

View File

@@ -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)

View File

@@ -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)

View File

@@ -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:

View File

@@ -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