From 3f60c8e3f7d951eef29c729d7abd857631575e4b Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 2 Mar 2016 11:44:57 +0000 Subject: [PATCH] ovs: convert over to use privsep module Instead of relying on root wrap, convert the openvswitch network code to use the privsep module to run privileged actions. Change-Id: I45208c683fadf97ebcc46e08e2cc9781ff6eedb0 --- vif_plug_ovs/linux_net.py | 52 ++++++++++++---------------- vif_plug_ovs/privsep.py | 24 +++++++++++++ vif_plug_ovs/tests/test_linux_net.py | 37 +++++++++++--------- 3 files changed, 67 insertions(+), 46 deletions(-) create mode 100644 vif_plug_ovs/privsep.py diff --git a/vif_plug_ovs/linux_net.py b/vif_plug_ovs/linux_net.py index f7b3560e..6bf7b7bb 100644 --- a/vif_plug_ovs/linux_net.py +++ b/vif_plug_ovs/linux_net.py @@ -27,6 +27,7 @@ from oslo_utils import excutils from vif_plug_ovs import exception from vif_plug_ovs.i18n import _LE +from vif_plug_ovs import privsep LOG = logging.getLogger(__name__) @@ -37,13 +38,14 @@ def _ovs_vsctl(args, timeout=None): full_args += ['--timeout=%s' % timeout] full_args += args try: - return processutils.execute(*full_args, run_as_root=True) + return processutils.execute(*full_args) except Exception as e: LOG.error(_LE("Unable to execute %(cmd)s. Exception: %(exception)s"), {'cmd': full_args, 'exception': e}) raise exception.AgentError(method=full_args) +@privsep.vif_plug.entrypoint def create_ovs_vif_port(bridge, dev, iface_id, mac, instance_id, mtu, timeout=None): _ovs_vsctl(['--', '--if-exists', 'del-port', dev, '--', @@ -57,10 +59,11 @@ def create_ovs_vif_port(bridge, dev, iface_id, mac, instance_id, mtu, _set_device_mtu(dev, mtu) +@privsep.vif_plug.entrypoint def delete_ovs_vif_port(bridge, dev, timeout=None): _ovs_vsctl(['--', '--if-exists', 'del-port', bridge, dev], timeout=timeout) - delete_net_dev(dev) + _delete_net_dev(dev) def device_exists(device): @@ -68,74 +71,65 @@ def device_exists(device): return os.path.exists('/sys/class/net/%s' % device) -def delete_net_dev(dev): +def _delete_net_dev(dev): """Delete a network device only if it exists.""" if device_exists(dev): try: processutils.execute('ip', 'link', 'delete', dev, - check_exit_code=[0, 2, 254], - run_as_root=True) + check_exit_code=[0, 2, 254]) LOG.debug("Net device removed: '%s'", dev) except processutils.ProcessExecutionError: with excutils.save_and_reraise_exception(): LOG.error(_LE("Failed removing net device: '%s'"), dev) +@privsep.vif_plug.entrypoint def create_veth_pair(dev1_name, dev2_name, mtu): """Create a pair of veth devices with the specified names, deleting any previous devices with those names. """ for dev in [dev1_name, dev2_name]: - delete_net_dev(dev) + _delete_net_dev(dev) processutils.execute('ip', 'link', 'add', dev1_name, - 'type', 'veth', 'peer', 'name', dev2_name, - run_as_root=True) + 'type', 'veth', 'peer', 'name', dev2_name) for dev in [dev1_name, dev2_name]: - processutils.execute('ip', 'link', 'set', dev, 'up', - run_as_root=True) + processutils.execute('ip', 'link', 'set', dev, 'up') processutils.execute('ip', 'link', 'set', dev, 'promisc', 'on') _set_device_mtu(dev, mtu) +@privsep.vif_plug.entrypoint def ensure_bridge(bridge): if not device_exists(bridge): - processutils.execute('brctl', 'addbr', bridge, - run_as_root=True) - processutils.execute('brctl', 'setfd', bridge, 0, - run_as_root=True) - processutils.execute('brctl', 'stp', bridge, 'off', - run_as_root=True) + processutils.execute('brctl', 'addbr', bridge) + processutils.execute('brctl', 'setfd', bridge, 0) + processutils.execute('brctl', 'stp', bridge, 'off') syspath = '/sys/class/net/%s/bridge/multicast_snooping' syspath = syspath % bridge processutils.execute('tee', syspath, process_input='0', - check_exit_code=[0, 1], - run_as_root=True) + check_exit_code=[0, 1]) disv6 = ('/proc/sys/net/ipv6/conf/%s/disable_ipv6' % bridge) if os.path.exists(disv6): processutils.execute('tee', disv6, process_input='1', - run_as_root=True, check_exit_code=[0, 1]) +@privsep.vif_plug.entrypoint def delete_bridge(bridge, dev): if device_exists(bridge): - processutils.execute('brctl', 'delif', bridge, dev, - run_as_root=True) - processutils.execute('ip', 'link', 'set', bridge, 'down', - run_as_root=True) - processutils.execute('brctl', 'delbr', bridge, - run_as_root=True) + processutils.execute('brctl', 'delif', bridge, dev) + processutils.execute('ip', 'link', 'set', bridge, 'down') + processutils.execute('brctl', 'delbr', bridge) +@privsep.vif_plug.entrypoint def add_bridge_port(bridge, dev): - processutils.execute('ip', 'link', 'set', bridge, 'up', - run_as_root=True) - processutils.execute('brctl', 'addif', bridge, dev, - run_as_root=True) + processutils.execute('ip', 'link', 'set', bridge, 'up') + processutils.execute('brctl', 'addif', bridge, dev) def _set_device_mtu(dev, mtu): diff --git a/vif_plug_ovs/privsep.py b/vif_plug_ovs/privsep.py new file mode 100644 index 00000000..dc4438bc --- /dev/null +++ b/vif_plug_ovs/privsep.py @@ -0,0 +1,24 @@ +# +# Copyright (C) 2016 Red Hat, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from oslo_privsep import capabilities as c +from oslo_privsep import priv_context + +vif_plug = priv_context.PrivContext( + "vif_plug_ovs", + cfg_section="vif_plug_ovs_privileged", + pypath=__name__ + ".vif_plug", + capabilities=[c.CAP_NET_ADMIN], +) diff --git a/vif_plug_ovs/tests/test_linux_net.py b/vif_plug_ovs/tests/test_linux_net.py index 2e503c2f..ed10ebdf 100644 --- a/vif_plug_ovs/tests/test_linux_net.py +++ b/vif_plug_ovs/tests/test_linux_net.py @@ -19,6 +19,7 @@ import testtools from oslo_concurrency import processutils from vif_plug_ovs import linux_net +from vif_plug_ovs import privsep if six.PY2: @@ -32,6 +33,11 @@ else: class LinuxNetTest(testtools.TestCase): + def setUp(self): + super(LinuxNetTest, self).setUp() + + privsep.vif_plug.set_client_mode(False) + @mock.patch.object(processutils, "execute") @mock.patch.object(linux_net, "device_exists", return_value=True) def test_ensure_bridge_exists(self, mock_dev_exists, mock_execute): @@ -50,12 +56,11 @@ class LinuxNetTest(testtools.TestCase): linux_net.ensure_bridge("br0") self.assertEqual(mock_execute.mock_calls, [ - mock.call('brctl', 'addbr', 'br0', run_as_root=True), - mock.call('brctl', 'setfd', 'br0', 0, run_as_root=True), - mock.call('brctl', 'stp', 'br0', "off", run_as_root=True), + mock.call('brctl', 'addbr', 'br0'), + mock.call('brctl', 'setfd', 'br0', 0), + mock.call('brctl', 'stp', 'br0', "off"), mock.call('tee', '/sys/class/net/br0/bridge/multicast_snooping', - check_exit_code=[0, 1], process_input='0', - run_as_root=True), + check_exit_code=[0, 1], process_input='0'), ]) self.assertEqual(mock_dev_exists.mock_calls, [ mock.call("br0") @@ -69,15 +74,13 @@ class LinuxNetTest(testtools.TestCase): linux_net.ensure_bridge("br0") self.assertEqual(mock_execute.mock_calls, [ - mock.call('brctl', 'addbr', 'br0', run_as_root=True), - mock.call('brctl', 'setfd', 'br0', 0, run_as_root=True), - mock.call('brctl', 'stp', 'br0', "off", run_as_root=True), + mock.call('brctl', 'addbr', 'br0'), + mock.call('brctl', 'setfd', 'br0', 0), + mock.call('brctl', 'stp', 'br0', "off"), mock.call('tee', '/sys/class/net/br0/bridge/multicast_snooping', - check_exit_code=[0, 1], process_input='0', - run_as_root=True), + check_exit_code=[0, 1], process_input='0'), mock.call('tee', '/proc/sys/net/ipv6/conf/br0/disable_ipv6', - check_exit_code=[0, 1], process_input='1', - run_as_root=True), + check_exit_code=[0, 1], process_input='1'), ]) self.assertEqual(mock_dev_exists.mock_calls, [ mock.call("br0") @@ -99,9 +102,9 @@ class LinuxNetTest(testtools.TestCase): linux_net.delete_bridge("br0", "vnet1") self.assertEqual(mock_execute.mock_calls, [ - mock.call('brctl', 'delif', 'br0', 'vnet1', run_as_root=True), - mock.call('ip', 'link', 'set', 'br0', 'down', run_as_root=True), - mock.call('brctl', 'delbr', 'br0', run_as_root=True), + mock.call('brctl', 'delif', 'br0', 'vnet1'), + mock.call('ip', 'link', 'set', 'br0', 'down'), + mock.call('brctl', 'delbr', 'br0'), ]) self.assertEqual(mock_dev_exists.mock_calls, [ mock.call("br0") @@ -112,6 +115,6 @@ class LinuxNetTest(testtools.TestCase): linux_net.add_bridge_port("br0", "vnet1") self.assertEqual(mock_execute.mock_calls, [ - mock.call('ip', 'link', 'set', 'br0', 'up', run_as_root=True), - mock.call('brctl', 'addif', 'br0', 'vnet1', run_as_root=True), + mock.call('ip', 'link', 'set', 'br0', 'up'), + mock.call('brctl', 'addif', 'br0', 'vnet1'), ])