Astara appliance oslo.rootwrap

Use oslo.rootwrap to replace the default root_helper sudo.

Change-Id: I5875cd647a4cc4f60f3058a98ea8a829cf056c43
Implements: blueprint astara-rootwrap
This commit is contained in:
Xiayu 2016-02-17 01:45:05 +00:00
parent a8a67c3f9d
commit abd07978e0
25 changed files with 190 additions and 74 deletions

View File

@ -29,12 +29,33 @@
- name: install gunicorn config file
template: src=gunicorn.j2 dest=/etc/astara_gunicorn_config.py
- name: add gunicorn user
command: useradd -r gunicorn
- name: install init.d files
copy: src={{playbook_dir}}/../scripts/etc/init.d/{{item}} dest=/etc/init.d/{{item}} mode=0555
with_items:
- metadata
- astara-router-api-server
- name: install rootwrap config file
copy: src={{playbook_dir}}/../etc/rootwrap.conf dest=/etc/rootwrap.conf mode=0555
- name: create /etc/rootwrap.d/
file: path=/etc/rootwrap.d/ state=directory
- name: install rootwrap rules file
copy: src={{playbook_dir}}/../etc/rootwrap.d/ dest=/etc/rootwrap.d/ mode=0555
with_items:
- network.filters
- stat: path=/etc/sudoers.d
register: sudoers_dir
- name: install sudoer file
when: sudoers_dir.stat.exists == True
template: src=gunicorn dest=/etc/sudoers.d/gunicorn mode=0440
- name: create /usr/local/share/astara/
file: path=/usr/local/share/astara state=directory

View File

@ -0,0 +1 @@
gunicorn ALL = (root) NOPASSWD: /usr/local/bin/astara-rootwrap /etc/rootwrap.conf *

View File

@ -42,7 +42,7 @@ def _get_cache():
_cache = make_region().configure(
'dogpile.cache.dbm',
arguments={
"filename": "/etc/astara-state"
"filename": "/tmp/astara-state"
}
)
return _cache

View File

@ -83,7 +83,7 @@ class ARPManager(base.Manager):
A class to interact with entries in the ARP cache. Currently only really
provides support for deleting stuff from the cache.
"""
EXECUTABLE = '/usr/sbin/arp'
EXECUTABLE = 'arp'
def send_gratuitous_arp_for_floating_ips(self, config, generic_to_host):
"""

View File

@ -24,7 +24,7 @@ class Manager(object):
modules.
"""
def __init__(self, root_helper='sudo'):
def __init__(self, root_helper='sudo astara-rootwrap /etc/rootwrap.conf'):
"""
Initializes Manager class. <root_helper> provides a facility to specify
how this class accesses escalated privileges. Defaults to 'sudo'.

View File

@ -30,7 +30,7 @@ class BirdManager(base.Manager):
"""
A class to interact with BIRD, an internet routing protocol daemon.
"""
def __init__(self, root_helper='sudo'):
def __init__(self, root_helper='sudo astara-rootwrap /etc/rootwrap.conf'):
"""
Initializes BirdManager class.
@ -59,11 +59,11 @@ class BirdManager(base.Manager):
Restart the BIRD daemon using the system provided init scripts.
"""
try:
utils.execute(['/etc/init.d/bird6', 'status'], self.root_helper)
utils.execute(['service', 'bird6', 'status'], self.root_helper)
except: # pragma no cover
utils.execute(['/etc/init.d/bird6', 'start'], self.root_helper)
utils.execute(['service', 'bird6', 'start'], self.root_helper)
else: # pragma no cover
utils.execute(['/etc/init.d/bird6', 'reload'], self.root_helper)
utils.execute(['service', 'bird6', 'reload'], self.root_helper)
def build_config(config, interface_map):

View File

@ -29,7 +29,7 @@ DEFAULT_LEASE = 86400
class DHCPManager(base.Manager):
"""A class to manage dnsmasq."""
def __init__(self, root_helper='sudo'):
def __init__(self, root_helper='sudo astara-rootwrap /etc/rootwrap.conf'):
"""
Initializes DHCPManager class.
@ -45,7 +45,8 @@ class DHCPManager(base.Manager):
"""
for f in os.listdir(CONF_DIR):
if f.endswith('.conf'):
os.remove(os.path.join(CONF_DIR, f))
utils.execute(['rm', '-f', os.path.join(CONF_DIR, f)],
self.root_helper)
def update_network_dhcp_config(self, ifname, network):
"""
@ -139,7 +140,7 @@ class DHCPManager(base.Manager):
Restarts dnsmasq service using the system provided init script.
"""
try:
utils.execute([RC_PATH, 'stop'], self.root_helper)
utils.execute(['service', 'dnsmasq', 'stop'], self.root_helper)
except:
pass
@ -149,7 +150,7 @@ class DHCPManager(base.Manager):
remaining -= 1
try:
utils.execute(
[RC_PATH, 'start'], self.root_helper
['service', 'dnsmasq', 'start'], self.root_helper
)
return
except Exception:

View File

@ -20,7 +20,7 @@ from astara_router import utils
class HostnameManager(base.Manager):
EXECUTABLE = '/bin/hostname'
EXECUTABLE = 'hostname'
def update(self, config):
self.update_hostname(config)

View File

@ -39,9 +39,9 @@ class IPManager(base.Manager):
configuration information.
"""
EXECUTABLE = '/sbin/ip'
EXECUTABLE = 'ip'
def __init__(self, root_helper='sudo'):
def __init__(self, root_helper='sudo astara-rootwrap /etc/rootwrap.conf'):
"""Initializes resources for the IPManager class"""
super(IPManager, self).__init__(root_helper)
self.next_generic_index = 0

View File

@ -89,14 +89,14 @@ class IPTablesManager(base.Manager):
netfilter-persistent as a plugin, so use that instead if it is
available
'''
_init = '/etc/init.d/%s-persistent'
if os.path.isfile(_init % 'netfilter'):
_init = '%s-persistent'
if os.path.isfile('/etc/init.d/netfilter-persistent'):
init = _init % 'netfilter'
else:
init = _init % 'iptables'
utils.execute(
[init, 'restart'],
['service', init, 'restart'],
self.root_helper
)
@ -108,8 +108,8 @@ class IPTablesManager(base.Manager):
:rtype: str
'''
v4 = utils.execute(['iptables', '-L', '-n'])
v6 = utils.execute(['ip6tables', '-L', '-n'])
v4 = utils.execute(['iptables', '-L', '-n'], self.root_helper)
v6 = utils.execute(['ip6tables', '-L', '-n'], self.root_helper)
return v4 + v6
def get_external_network(self, config):

View File

@ -33,7 +33,7 @@ class NginxLB(base.Manager):
os.path.dirname(__file__), 'nginx.conf.template')
INIT = 'nginx'
def __init__(self, root_helper='sudo'):
def __init__(self, root_helper='sudo astara-rootwrap /etc/rootwrap.conf'):
"""
Initializes DHCPManager class.

View File

@ -30,7 +30,7 @@ class MetadataManager(base.Manager):
A class to provide facilities to interact with the Nova metadata service.
"""
def __init__(self, root_helper='sudo'):
def __init__(self, root_helper='sudo astara-rootwrap /etc/rootwrap.conf'):
"""
Initializes MetataManager class.
@ -88,20 +88,20 @@ class MetadataManager(base.Manager):
determined to be stopped.
"""
try:
execute(['/etc/init.d/metadata', 'status'], self.root_helper)
execute(['service', 'metadata', 'status'], self.root_helper)
except:
execute(['/etc/init.d/metadata', 'start'], self.root_helper)
execute(['service', 'metadata', 'start'], self.root_helper)
def restart(self):
"""
Restarts the metadata service using the init script.
"""
try:
execute(['/etc/init.d/metadata', 'stop'], self.root_helper)
execute(['service', 'metadata', 'stop'], self.root_helper)
except:
# failure is ok here
pass
execute(['/etc/init.d/metadata', 'start'], self.root_helper)
execute(['service', 'metadata', 'start'], self.root_helper)
def build_config(config):

View File

@ -28,11 +28,11 @@ class PingManager(base.Manager):
"""
exe_map = {
4: '/bin/ping',
6: '/bin/ping6'
4: 'ping',
6: 'ping6'
}
def __init__(self, root_helper='sudo'):
def __init__(self, root_helper='sudo astara-rootwrap /etc/rootwrap.conf'):
"""
Initializes PingManager class.

View File

@ -0,0 +1 @@
vim:

27
etc/rootwrap.conf Normal file
View File

@ -0,0 +1,27 @@
# Configuration for astara-rootwrap
# This file should be owned by (and only-writeable by) the root user
[DEFAULT]
# List of directories to load filter definitions from (separated by ',').
# These directories MUST all be only writeable by root !
filters_path=/etc/rootwrap.d
# List of directories to search executables in, in case filters do not
# explicitely specify a full path (separated by ',')
# If not specified, defaults to system PATH environment variable.
# These directories MUST all be only writeable by root !
exec_dirs=/sbin,/usr/sbin,/bin,/usr/bin
# Enable logging to syslog
# Default value is False
use_syslog=False
# Which syslog facility to use.
# Valid values include auth, authpriv, syslog, local0, local1...
# Default value is 'syslog'
syslog_log_facility=syslog
# Which messages to log.
# INFO means log all usage
# ERROR means only log unsuccessful attempts
syslog_log_level=ERROR

View File

@ -0,0 +1,38 @@
# astara-rootwrap command filters for astara-appliance
# This file should be owned by (and only-writeable by) the root user
[Filters]
# astara_router/drivers/bird.py:
mv_bird: RegExpFilter, mv, root, mv, /tmp/bird6\.conf, /etc/bird/bird6\.conf
# astara_router/drivers/arp.py: 'arp'..
arp: CommandFilter, /usr/sbin/arp, root
# astara_router/drivers/dnsmasq.py:
mv_dnsmasq: RegExpFilter, mv, root, mv, /tmp/dnsmasq\.conf, /etc/dnsmasq\.d/.*\.conf
rm: CommandFilter, rm, root
# astara_router/drivers/hostname.py:
hostname: CommandFilter, /bin/hostname, root
mv_hostname: RegExpFilter, mv, root, mv, /tmp/hostname, /etc/hostname
mv_hosts: RegExpFilter, mv, root, mv, /tmp/hosts, /etc/hosts
# astara_router/drivers/ip.py:
ip: IpFilter, ip, root
sysctl: CommandFilter, sysctl, root
conntrack: CommandFilter, conntrack, root
# astara_router/drivers/ping.py:
ping: CommandFilter, ping, root
ping6: CommandFilter, ping6, root
# astara_router/drivers/iptables.py:
mv_rules: RegExpFilter, mv, root, mv, /tmp/ip.*tables\.rules, /etc/iptables/rules\.v.*
iptables: CommandFilter, iptables, root
ip6tables: CommandFilter, ip6tables, root
# astara_router/drivers/metadata.py:
mv_metadata: RegExpFilter, mv, root, mv, /tmp/metadata\.conf, /etc/metadata\.conf
# astara services
services: CommandFilter, service, root

View File

@ -7,3 +7,4 @@ netaddr!=0.7.16,>=0.7.12 # BSD
eventlet>=0.18.2 # MIT
requests!=2.9.0,>=2.8.1 # Apache-2.0
greenlet>=0.3.2 # MIT
oslo.rootwrap>=2.0.0 # Apache-2.0

View File

@ -13,7 +13,7 @@
PATH=/bin:/usr/bin:/sbin:/usr/sbin
DAEMON="/usr/bin/gunicorn"
NAME="astara-router-api-server"
OPTIONS="--pythonpath /usr/local/share/astara -c /etc/astara_gunicorn_config.py astara_router.api.server:app"
OPTIONS="--user gunicorn --pythonpath /usr/local/share/astara -c /etc/astara_gunicorn_config.py astara_router.api.server:app"
PIDFILE=/var/run/gunicorn.pid
test -x $DAEMON || exit 0

View File

@ -35,6 +35,7 @@ console_scripts =
astara-api-dev-server=astara_router.api.server:main
astara-metadata-proxy=astara_router.metadata_proxy:main
astara-gratuitous-arp=astara_router.drivers.arp:send_gratuitous_arp
astara-rootwrap=oslo_rootwrap.cmd:main
[build_sphinx]
all_files = 1

View File

@ -131,16 +131,20 @@ class ARPTest(unittest2.TestCase):
)
assert execute.call_args_list == [
mock.call(
['astara-gratuitous-arp', 'eth1', '172.16.77.50'], 'sudo'
['astara-gratuitous-arp', 'eth1', '172.16.77.50'],
'sudo astara-rootwrap /etc/rootwrap.conf'
),
mock.call(
['astara-gratuitous-arp', 'eth1', '172.16.77.51'], 'sudo'
['astara-gratuitous-arp', 'eth1', '172.16.77.51'],
'sudo astara-rootwrap /etc/rootwrap.conf'
),
mock.call(
['astara-gratuitous-arp', 'eth1', '172.16.77.52'], 'sudo'
['astara-gratuitous-arp', 'eth1', '172.16.77.52'],
'sudo astara-rootwrap /etc/rootwrap.conf'
),
mock.call(
['astara-gratuitous-arp', 'eth1', '172.16.77.53'], 'sudo'
['astara-gratuitous-arp', 'eth1', '172.16.77.53'],
'sudo astara-rootwrap /etc/rootwrap.conf'
)
]

View File

@ -90,14 +90,16 @@ class BirdTestCase(TestCase):
)
self.mock_execute.assert_called_once_with(
['mv', '/tmp/bird6.conf', '/etc/bird/bird6.conf'],
'sudo'
'sudo astara-rootwrap /etc/rootwrap.conf'
)
def test_restart(self):
self.mgr.restart()
self.mock_execute.assert_has_calls([
mock.call(['/etc/init.d/bird6', 'status'], 'sudo'),
mock.call(['/etc/init.d/bird6', 'reload'], 'sudo'),
mock.call(['service', 'bird6', 'status'],
'sudo astara-rootwrap /etc/rootwrap.conf'),
mock.call(['service', 'bird6', 'reload'],
'sudo astara-rootwrap /etc/rootwrap.conf'),
])
def test_restart_failure(self):
@ -105,8 +107,10 @@ class BirdTestCase(TestCase):
execute.side_effect = [Exception('status failed!'), None]
self.mgr.restart()
execute.assert_has_calls([
mock.call(['/etc/init.d/bird6', 'status'], 'sudo'),
mock.call(['/etc/init.d/bird6', 'start'], 'sudo'),
mock.call(['service', 'bird6', 'status'],
'sudo astara-rootwrap /etc/rootwrap.conf'),
mock.call(['service', 'bird6', 'start'],
'sudo astara-rootwrap /etc/rootwrap.conf'),
])
def test_build_config(self):

View File

@ -109,7 +109,7 @@ class DnsmasqTestCase(TestCase):
)
self.mock_execute.assert_called_once_with(
['mv', '/tmp/dnsmasq.conf', '/etc/dnsmasq.d/em1.conf'],
'sudo'
'sudo astara-rootwrap /etc/rootwrap.conf'
)
def test_build_dhcp_config(self):
@ -136,6 +136,8 @@ class DnsmasqTestCase(TestCase):
def test_restart(self):
self.mgr.restart()
self.mock_execute.assert_has_calls([
mock.call(['/etc/init.d/dnsmasq', 'stop'], 'sudo'),
mock.call(['/etc/init.d/dnsmasq', 'start'], 'sudo')
mock.call(['service', 'dnsmasq', 'stop'],
'sudo astara-rootwrap /etc/rootwrap.conf'),
mock.call(['service', 'dnsmasq', 'start'],
'sudo astara-rootwrap /etc/rootwrap.conf')
])

View File

@ -41,8 +41,10 @@ class HostnameTestCase(TestCase):
def test_update_hostname(self):
self.mgr.update_hostname(CONFIG)
self.mock_execute.assert_has_calls([
mock.call(['/bin/hostname', 'astara'], 'sudo'),
mock.call(['mv', '/tmp/hostname', '/etc/hostname'], 'sudo')
mock.call(['hostname', 'astara'],
'sudo astara-rootwrap /etc/rootwrap.conf'),
mock.call(['mv', '/tmp/hostname', '/etc/hostname'],
'sudo astara-rootwrap /etc/rootwrap.conf')
])
def test_update_hosts(self):
@ -53,6 +55,7 @@ class HostnameTestCase(TestCase):
]))
self.mgr.update_hosts(CONFIG)
self.mock_execute.assert_has_calls([
mock.call(['mv', '/tmp/hosts', '/etc/hosts'], 'sudo')
mock.call(['mv', '/tmp/hosts', '/etc/hosts'],
'sudo astara-rootwrap /etc/rootwrap.conf')
])
self.mock_replace_file.assert_has_calls([expected])

View File

@ -75,7 +75,7 @@ class IPTestCase(TestCase):
self.assertEqual(interfaces, [iface_a, iface_b])
self.mock_execute.assert_has_calls(
[mock.call(['/sbin/ip', 'addr', 'show'])])
[mock.call(['ip', 'addr', 'show'])])
def test_get_interface(self):
iface_a = mock.Mock()
@ -93,7 +93,7 @@ class IPTestCase(TestCase):
self.assertEqual(iface_a.ifname, 'ge0')
self.mock_execute.assert_has_calls(
[mock.call(['/sbin/ip', 'addr', 'show'])])
[mock.call(['ip', 'addr', 'show'])])
def test_ensure_mapping(self):
attr = 'get_interfaces'
@ -149,7 +149,8 @@ class IPTestCase(TestCase):
mgr.generic_mapping = {'ge0': 'em0'}
mgr.up(iface)
self.mock_execute.assert_has_calls(
[mock.call(['/sbin/ip', 'link', 'set', 'em0', 'up'], 'sudo')])
[mock.call(['ip', 'link', 'set', 'em0', 'up'],
'sudo astara-rootwrap /etc/rootwrap.conf')])
def test_down(self):
iface = mock.Mock()
@ -164,7 +165,8 @@ class IPTestCase(TestCase):
mgr.down(iface)
self.mock_execute.assert_has_calls(
[mock.call(['/sbin/ip', 'link', 'set', 'em0', 'down'], 'sudo')])
[mock.call(['ip', 'link', 'set', 'em0', 'down'],
'sudo astara-rootwrap /etc/rootwrap.conf')])
def test_set_mtu(self):
iface = mock.Mock()
@ -180,8 +182,8 @@ class IPTestCase(TestCase):
mgr.set_mtu(iface)
self.mock_execute.assert_has_calls(
[mock.call(['/sbin/ip', 'link', 'set', 'em0', 'mtu', '1280'],
'sudo')])
[mock.call(['ip', 'link', 'set', 'em0', 'mtu', '1280'],
'sudo astara-rootwrap /etc/rootwrap.conf')])
def _update_interface_test_hlpr(self, new_iface, old_iface,
ignore_link_local=True):
@ -263,7 +265,7 @@ class IPTestCase(TestCase):
)
def test_address_add(self):
cmd = '/sbin/ip'
cmd = 'ip'
v4 = netaddr.IPNetwork('192.168.105.2/24')
v6 = netaddr.IPNetwork('fdca:3ba5:a17a:acda:20c:29ff:fe94:723d/64')
iface = mock.Mock(all_addresses=[v4, v6], ifname='em0')
@ -278,19 +280,21 @@ class IPTestCase(TestCase):
mock.call([
cmd, 'addr', 'add', '192.168.105.2/24', 'brd', '+', 'dev',
'em0'
], 'sudo'),
mock.call([cmd, 'link', 'set', 'em0', 'up'], 'sudo'),
], 'sudo astara-rootwrap /etc/rootwrap.conf'),
mock.call([cmd, 'link', 'set', 'em0', 'up'],
'sudo astara-rootwrap /etc/rootwrap.conf'),
mock.call([cmd, 'addr', 'show', 'em0']),
mock.call([
cmd, '-6', 'addr', 'add',
'fdca:3ba5:a17a:acda:20c:29ff:fe94:723d/64', 'dev', 'em0'
], 'sudo'),
mock.call([cmd, 'link', 'set', 'em0', 'up'], 'sudo'),
], 'sudo astara-rootwrap /etc/rootwrap.conf'),
mock.call([cmd, 'link', 'set', 'em0', 'up'],
'sudo astara-rootwrap /etc/rootwrap.conf'),
mock.call([cmd, 'addr', 'show', 'em0'])
]
def test_address_remove(self):
cmd = '/sbin/ip'
cmd = 'ip'
v4 = netaddr.IPNetwork('192.168.105.2/24')
v6 = netaddr.IPNetwork('fdca:3ba5:a17a:acda:20c:29ff:fe94:723d/64')
iface = mock.Mock(all_addresses=[])
@ -299,12 +303,15 @@ class IPTestCase(TestCase):
mgr = ip.IPManager()
mgr._update_addresses('em0', iface, old_iface)
assert self.mock_execute.call_args_list == [
mock.call([cmd, 'addr', 'del', str(v4), 'dev', 'em0'], 'sudo'),
mock.call(['conntrack', '-D', '-d', str(v4.ip)], 'sudo'),
mock.call(['conntrack', '-D', '-q', str(v4.ip)], 'sudo'),
mock.call([cmd, 'addr', 'del', str(v4), 'dev', 'em0'],
'sudo astara-rootwrap /etc/rootwrap.conf'),
mock.call(['conntrack', '-D', '-d', str(v4.ip)],
'sudo astara-rootwrap /etc/rootwrap.conf'),
mock.call(['conntrack', '-D', '-q', str(v4.ip)],
'sudo astara-rootwrap /etc/rootwrap.conf'),
mock.call([
cmd, '-6', 'addr', 'del', str(v6), 'dev', 'em0'
], 'sudo'),
], 'sudo astara-rootwrap /etc/rootwrap.conf'),
]
def test_update_set(self):
@ -331,15 +338,18 @@ class IPTestCase(TestCase):
assert self.mock_execute.call_args_list == [
mock.call([
'/sbin/ip', 'addr', 'add', str(a), 'dev', 'em0'
], 'sudo'),
mock.call(['/sbin/ip', 'link', 'set', 'em0', 'up'], 'sudo'),
mock.call(['/sbin/ip', 'addr', 'show', 'em0']),
'ip', 'addr', 'add', str(a), 'dev', 'em0'
], 'sudo astara-rootwrap /etc/rootwrap.conf'),
mock.call(['ip', 'link', 'set', 'em0', 'up'],
'sudo astara-rootwrap /etc/rootwrap.conf'),
mock.call(['ip', 'addr', 'show', 'em0']),
mock.call([
'/sbin/ip', 'addr', 'del', str(c), 'dev', 'em0'
], 'sudo'),
mock.call(['conntrack', '-D', '-d', str(c.ip)], 'sudo'),
mock.call(['conntrack', '-D', '-q', str(c.ip)], 'sudo'),
'ip', 'addr', 'del', str(c), 'dev', 'em0'
], 'sudo astara-rootwrap /etc/rootwrap.conf'),
mock.call(['conntrack', '-D', '-d', str(c.ip)],
'sudo astara-rootwrap /etc/rootwrap.conf'),
mock.call(['conntrack', '-D', '-q', str(c.ip)],
'sudo astara-rootwrap /etc/rootwrap.conf'),
]
def test_update_set_no_diff(self):
@ -394,7 +404,7 @@ class TestDisableDAD(TestCase):
assert self.mock_execute.call_args_list == [
mock.call([
'sysctl', '-w', 'net.ipv6.conf.eth0.accept_dad=0'
], 'sudo'),
], 'sudo astara-rootwrap /etc/rootwrap.conf'),
]
def test_dad_for_internal(self):
@ -409,7 +419,7 @@ class TestDisableDAD(TestCase):
assert self.mock_execute.call_args_list == [
mock.call([
'sysctl', '-w', 'net.ipv6.conf.eth2.accept_dad=0'
], 'sudo'),
], 'sudo astara-rootwrap /etc/rootwrap.conf'),
]
def test_sysctl_failure(self):

View File

@ -163,11 +163,11 @@ class TestIPTablesRouterConfiguration(TestCase):
assert self.execute.call_args_list == [
mock.call(
['mv', '/tmp/ip4tables.rules', '/etc/iptables/rules.v4'],
'sudo'
'sudo astara-rootwrap /etc/rootwrap.conf'
),
mock.call(
['mv', '/tmp/ip6tables.rules', '/etc/iptables/rules.v6'],
'sudo'
'sudo astara-rootwrap /etc/rootwrap.conf'
)
]
@ -177,7 +177,8 @@ class TestIPTablesRouterConfiguration(TestCase):
mgr = iptables.IPTablesManager()
mgr.restart()
assert self.execute.call_args_list == [
mock.call(['/etc/init.d/iptables-persistent', 'restart'], 'sudo')
mock.call(['service', 'iptables-persistent', 'restart'],
'sudo astara-rootwrap /etc/rootwrap.conf')
]
@mock.patch('os.path.isfile')
@ -186,7 +187,8 @@ class TestIPTablesRouterConfiguration(TestCase):
mgr = iptables.IPTablesManager()
mgr.restart()
assert self.execute.call_args_list == [
mock.call(['/etc/init.d/netfilter-persistent', 'restart'], 'sudo')
mock.call(['service', 'netfilter-persistent', 'restart'],
'sudo astara-rootwrap /etc/rootwrap.conf')
]
def test_mixed_floating_ip_versions(self):