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
This commit is contained in:
parent
48d9e6464a
commit
3f60c8e3f7
@ -27,6 +27,7 @@ from oslo_utils import excutils
|
|||||||
|
|
||||||
from vif_plug_ovs import exception
|
from vif_plug_ovs import exception
|
||||||
from vif_plug_ovs.i18n import _LE
|
from vif_plug_ovs.i18n import _LE
|
||||||
|
from vif_plug_ovs import privsep
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -37,13 +38,14 @@ def _ovs_vsctl(args, timeout=None):
|
|||||||
full_args += ['--timeout=%s' % timeout]
|
full_args += ['--timeout=%s' % timeout]
|
||||||
full_args += args
|
full_args += args
|
||||||
try:
|
try:
|
||||||
return processutils.execute(*full_args, run_as_root=True)
|
return processutils.execute(*full_args)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error(_LE("Unable to execute %(cmd)s. Exception: %(exception)s"),
|
LOG.error(_LE("Unable to execute %(cmd)s. Exception: %(exception)s"),
|
||||||
{'cmd': full_args, 'exception': e})
|
{'cmd': full_args, 'exception': e})
|
||||||
raise exception.AgentError(method=full_args)
|
raise exception.AgentError(method=full_args)
|
||||||
|
|
||||||
|
|
||||||
|
@privsep.vif_plug.entrypoint
|
||||||
def create_ovs_vif_port(bridge, dev, iface_id, mac, instance_id, mtu,
|
def create_ovs_vif_port(bridge, dev, iface_id, mac, instance_id, mtu,
|
||||||
timeout=None):
|
timeout=None):
|
||||||
_ovs_vsctl(['--', '--if-exists', 'del-port', dev, '--',
|
_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)
|
_set_device_mtu(dev, mtu)
|
||||||
|
|
||||||
|
|
||||||
|
@privsep.vif_plug.entrypoint
|
||||||
def delete_ovs_vif_port(bridge, dev, timeout=None):
|
def delete_ovs_vif_port(bridge, dev, timeout=None):
|
||||||
_ovs_vsctl(['--', '--if-exists', 'del-port', bridge, dev],
|
_ovs_vsctl(['--', '--if-exists', 'del-port', bridge, dev],
|
||||||
timeout=timeout)
|
timeout=timeout)
|
||||||
delete_net_dev(dev)
|
_delete_net_dev(dev)
|
||||||
|
|
||||||
|
|
||||||
def device_exists(device):
|
def device_exists(device):
|
||||||
@ -68,74 +71,65 @@ def device_exists(device):
|
|||||||
return os.path.exists('/sys/class/net/%s' % 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."""
|
"""Delete a network device only if it exists."""
|
||||||
if device_exists(dev):
|
if device_exists(dev):
|
||||||
try:
|
try:
|
||||||
processutils.execute('ip', 'link', 'delete', dev,
|
processutils.execute('ip', 'link', 'delete', dev,
|
||||||
check_exit_code=[0, 2, 254],
|
check_exit_code=[0, 2, 254])
|
||||||
run_as_root=True)
|
|
||||||
LOG.debug("Net device removed: '%s'", dev)
|
LOG.debug("Net device removed: '%s'", dev)
|
||||||
except processutils.ProcessExecutionError:
|
except processutils.ProcessExecutionError:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
LOG.error(_LE("Failed removing net device: '%s'"), dev)
|
LOG.error(_LE("Failed removing net device: '%s'"), dev)
|
||||||
|
|
||||||
|
|
||||||
|
@privsep.vif_plug.entrypoint
|
||||||
def create_veth_pair(dev1_name, dev2_name, mtu):
|
def create_veth_pair(dev1_name, dev2_name, mtu):
|
||||||
"""Create a pair of veth devices with the specified names,
|
"""Create a pair of veth devices with the specified names,
|
||||||
deleting any previous devices with those names.
|
deleting any previous devices with those names.
|
||||||
"""
|
"""
|
||||||
for dev in [dev1_name, dev2_name]:
|
for dev in [dev1_name, dev2_name]:
|
||||||
delete_net_dev(dev)
|
_delete_net_dev(dev)
|
||||||
|
|
||||||
processutils.execute('ip', 'link', 'add', dev1_name,
|
processutils.execute('ip', 'link', 'add', dev1_name,
|
||||||
'type', 'veth', 'peer', 'name', dev2_name,
|
'type', 'veth', 'peer', 'name', dev2_name)
|
||||||
run_as_root=True)
|
|
||||||
for dev in [dev1_name, dev2_name]:
|
for dev in [dev1_name, dev2_name]:
|
||||||
processutils.execute('ip', 'link', 'set', dev, 'up',
|
processutils.execute('ip', 'link', 'set', dev, 'up')
|
||||||
run_as_root=True)
|
|
||||||
processutils.execute('ip', 'link', 'set', dev, 'promisc', 'on')
|
processutils.execute('ip', 'link', 'set', dev, 'promisc', 'on')
|
||||||
_set_device_mtu(dev, mtu)
|
_set_device_mtu(dev, mtu)
|
||||||
|
|
||||||
|
|
||||||
|
@privsep.vif_plug.entrypoint
|
||||||
def ensure_bridge(bridge):
|
def ensure_bridge(bridge):
|
||||||
if not device_exists(bridge):
|
if not device_exists(bridge):
|
||||||
processutils.execute('brctl', 'addbr', bridge,
|
processutils.execute('brctl', 'addbr', bridge)
|
||||||
run_as_root=True)
|
processutils.execute('brctl', 'setfd', bridge, 0)
|
||||||
processutils.execute('brctl', 'setfd', bridge, 0,
|
processutils.execute('brctl', 'stp', bridge, 'off')
|
||||||
run_as_root=True)
|
|
||||||
processutils.execute('brctl', 'stp', bridge, 'off',
|
|
||||||
run_as_root=True)
|
|
||||||
syspath = '/sys/class/net/%s/bridge/multicast_snooping'
|
syspath = '/sys/class/net/%s/bridge/multicast_snooping'
|
||||||
syspath = syspath % bridge
|
syspath = syspath % bridge
|
||||||
processutils.execute('tee', syspath, process_input='0',
|
processutils.execute('tee', syspath, process_input='0',
|
||||||
check_exit_code=[0, 1],
|
check_exit_code=[0, 1])
|
||||||
run_as_root=True)
|
|
||||||
disv6 = ('/proc/sys/net/ipv6/conf/%s/disable_ipv6' %
|
disv6 = ('/proc/sys/net/ipv6/conf/%s/disable_ipv6' %
|
||||||
bridge)
|
bridge)
|
||||||
if os.path.exists(disv6):
|
if os.path.exists(disv6):
|
||||||
processutils.execute('tee',
|
processutils.execute('tee',
|
||||||
disv6,
|
disv6,
|
||||||
process_input='1',
|
process_input='1',
|
||||||
run_as_root=True,
|
|
||||||
check_exit_code=[0, 1])
|
check_exit_code=[0, 1])
|
||||||
|
|
||||||
|
|
||||||
|
@privsep.vif_plug.entrypoint
|
||||||
def delete_bridge(bridge, dev):
|
def delete_bridge(bridge, dev):
|
||||||
if device_exists(bridge):
|
if device_exists(bridge):
|
||||||
processutils.execute('brctl', 'delif', bridge, dev,
|
processutils.execute('brctl', 'delif', bridge, dev)
|
||||||
run_as_root=True)
|
processutils.execute('ip', 'link', 'set', bridge, 'down')
|
||||||
processutils.execute('ip', 'link', 'set', bridge, 'down',
|
processutils.execute('brctl', 'delbr', bridge)
|
||||||
run_as_root=True)
|
|
||||||
processutils.execute('brctl', 'delbr', bridge,
|
|
||||||
run_as_root=True)
|
|
||||||
|
|
||||||
|
|
||||||
|
@privsep.vif_plug.entrypoint
|
||||||
def add_bridge_port(bridge, dev):
|
def add_bridge_port(bridge, dev):
|
||||||
processutils.execute('ip', 'link', 'set', bridge, 'up',
|
processutils.execute('ip', 'link', 'set', bridge, 'up')
|
||||||
run_as_root=True)
|
processutils.execute('brctl', 'addif', bridge, dev)
|
||||||
processutils.execute('brctl', 'addif', bridge, dev,
|
|
||||||
run_as_root=True)
|
|
||||||
|
|
||||||
|
|
||||||
def _set_device_mtu(dev, mtu):
|
def _set_device_mtu(dev, mtu):
|
||||||
|
24
vif_plug_ovs/privsep.py
Normal file
24
vif_plug_ovs/privsep.py
Normal file
@ -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],
|
||||||
|
)
|
@ -19,6 +19,7 @@ import testtools
|
|||||||
from oslo_concurrency import processutils
|
from oslo_concurrency import processutils
|
||||||
|
|
||||||
from vif_plug_ovs import linux_net
|
from vif_plug_ovs import linux_net
|
||||||
|
from vif_plug_ovs import privsep
|
||||||
|
|
||||||
|
|
||||||
if six.PY2:
|
if six.PY2:
|
||||||
@ -32,6 +33,11 @@ else:
|
|||||||
|
|
||||||
class LinuxNetTest(testtools.TestCase):
|
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(processutils, "execute")
|
||||||
@mock.patch.object(linux_net, "device_exists", return_value=True)
|
@mock.patch.object(linux_net, "device_exists", return_value=True)
|
||||||
def test_ensure_bridge_exists(self, mock_dev_exists, mock_execute):
|
def test_ensure_bridge_exists(self, mock_dev_exists, mock_execute):
|
||||||
@ -50,12 +56,11 @@ class LinuxNetTest(testtools.TestCase):
|
|||||||
linux_net.ensure_bridge("br0")
|
linux_net.ensure_bridge("br0")
|
||||||
|
|
||||||
self.assertEqual(mock_execute.mock_calls, [
|
self.assertEqual(mock_execute.mock_calls, [
|
||||||
mock.call('brctl', 'addbr', 'br0', run_as_root=True),
|
mock.call('brctl', 'addbr', 'br0'),
|
||||||
mock.call('brctl', 'setfd', 'br0', 0, run_as_root=True),
|
mock.call('brctl', 'setfd', 'br0', 0),
|
||||||
mock.call('brctl', 'stp', 'br0', "off", run_as_root=True),
|
mock.call('brctl', 'stp', 'br0', "off"),
|
||||||
mock.call('tee', '/sys/class/net/br0/bridge/multicast_snooping',
|
mock.call('tee', '/sys/class/net/br0/bridge/multicast_snooping',
|
||||||
check_exit_code=[0, 1], process_input='0',
|
check_exit_code=[0, 1], process_input='0'),
|
||||||
run_as_root=True),
|
|
||||||
])
|
])
|
||||||
self.assertEqual(mock_dev_exists.mock_calls, [
|
self.assertEqual(mock_dev_exists.mock_calls, [
|
||||||
mock.call("br0")
|
mock.call("br0")
|
||||||
@ -69,15 +74,13 @@ class LinuxNetTest(testtools.TestCase):
|
|||||||
linux_net.ensure_bridge("br0")
|
linux_net.ensure_bridge("br0")
|
||||||
|
|
||||||
self.assertEqual(mock_execute.mock_calls, [
|
self.assertEqual(mock_execute.mock_calls, [
|
||||||
mock.call('brctl', 'addbr', 'br0', run_as_root=True),
|
mock.call('brctl', 'addbr', 'br0'),
|
||||||
mock.call('brctl', 'setfd', 'br0', 0, run_as_root=True),
|
mock.call('brctl', 'setfd', 'br0', 0),
|
||||||
mock.call('brctl', 'stp', 'br0', "off", run_as_root=True),
|
mock.call('brctl', 'stp', 'br0', "off"),
|
||||||
mock.call('tee', '/sys/class/net/br0/bridge/multicast_snooping',
|
mock.call('tee', '/sys/class/net/br0/bridge/multicast_snooping',
|
||||||
check_exit_code=[0, 1], process_input='0',
|
check_exit_code=[0, 1], process_input='0'),
|
||||||
run_as_root=True),
|
|
||||||
mock.call('tee', '/proc/sys/net/ipv6/conf/br0/disable_ipv6',
|
mock.call('tee', '/proc/sys/net/ipv6/conf/br0/disable_ipv6',
|
||||||
check_exit_code=[0, 1], process_input='1',
|
check_exit_code=[0, 1], process_input='1'),
|
||||||
run_as_root=True),
|
|
||||||
])
|
])
|
||||||
self.assertEqual(mock_dev_exists.mock_calls, [
|
self.assertEqual(mock_dev_exists.mock_calls, [
|
||||||
mock.call("br0")
|
mock.call("br0")
|
||||||
@ -99,9 +102,9 @@ class LinuxNetTest(testtools.TestCase):
|
|||||||
linux_net.delete_bridge("br0", "vnet1")
|
linux_net.delete_bridge("br0", "vnet1")
|
||||||
|
|
||||||
self.assertEqual(mock_execute.mock_calls, [
|
self.assertEqual(mock_execute.mock_calls, [
|
||||||
mock.call('brctl', 'delif', 'br0', 'vnet1', run_as_root=True),
|
mock.call('brctl', 'delif', 'br0', 'vnet1'),
|
||||||
mock.call('ip', 'link', 'set', 'br0', 'down', run_as_root=True),
|
mock.call('ip', 'link', 'set', 'br0', 'down'),
|
||||||
mock.call('brctl', 'delbr', 'br0', run_as_root=True),
|
mock.call('brctl', 'delbr', 'br0'),
|
||||||
])
|
])
|
||||||
self.assertEqual(mock_dev_exists.mock_calls, [
|
self.assertEqual(mock_dev_exists.mock_calls, [
|
||||||
mock.call("br0")
|
mock.call("br0")
|
||||||
@ -112,6 +115,6 @@ class LinuxNetTest(testtools.TestCase):
|
|||||||
linux_net.add_bridge_port("br0", "vnet1")
|
linux_net.add_bridge_port("br0", "vnet1")
|
||||||
|
|
||||||
self.assertEqual(mock_execute.mock_calls, [
|
self.assertEqual(mock_execute.mock_calls, [
|
||||||
mock.call('ip', 'link', 'set', 'br0', 'up', run_as_root=True),
|
mock.call('ip', 'link', 'set', 'br0', 'up'),
|
||||||
mock.call('brctl', 'addif', 'br0', 'vnet1', run_as_root=True),
|
mock.call('brctl', 'addif', 'br0', 'vnet1'),
|
||||||
])
|
])
|
||||||
|
Loading…
Reference in New Issue
Block a user