Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion systemvm/debian/opt/cloud/bin/configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -1609,7 +1609,7 @@ def process(self):
CsHelper.save_iptables("ip6tables-save", "/etc/iptables/rules.v6")

# Save nftables configuration
CsHelper.save_iptables("nft list ruleset", "/etc/iptables/rules.nftables")
CsHelper.save_nftables("/etc/iptables/rules.nftables")

def main(argv):
# The file we are currently processing, if it is "cmd_line.json" everything will be processed.
Expand Down
36 changes: 30 additions & 6 deletions systemvm/debian/opt/cloud/bin/cs/CsHelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,13 +210,37 @@ def save_iptables(command, iptables_file):
""" Execute command """
logging.debug("Saving iptables for %s" % command)

result = execute(command)
fIptables = open(iptables_file, "w+")
write_lines(iptables_file, execute(command))

for line in result:
fIptables.write(line)
fIptables.write("\n")
fIptables.close()

def write_lines(path, lines):
with open(path, "w+") as f:
for line in lines:
f.write(line)
f.write("\n")


IPTABLES_FAMILIES = ["ip", "ip6", "arp", "bridge"]
IPTABLES_TABLES = ["filter", "nat", "mangle", "raw", "security", "broute"]


def save_nftables(nftables_file):
""" Save the tables that only nftables manages, such as the IPv6 firewall and ACLs. The iptables-nft tables are
saved by save_iptables and restored with iptables-restore. nft can't load them, and one of them in the file fails
the whole restore at boot. """
logging.debug("Saving nftables tables to %s" % nftables_file)

rules = []
for line in execute("nft list tables"):
table = line.split()
if len(table) != 3 or table[0] != "table":
continue
family, name = table[1], table[2]
if family in IPTABLES_FAMILIES and name in IPTABLES_TABLES:
continue
rules.extend(execute("nft list table %s %s" % (family, name)))

write_lines(nftables_file, rules)


def execute2(command, wait=True):
Expand Down
31 changes: 31 additions & 0 deletions systemvm/test/TestCsHelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.

import tempfile
import unittest
import mock
from cs import CsHelper
Expand All @@ -31,6 +32,36 @@ def test_execute(self, mock_subprocess):
result = CsHelper.execute("/bin/false")
self.assertTrue(result is not None)

@mock.patch('cs.CsHelper.execute')
def test_save_iptables_writes_the_command_output(self, mock_execute):
mock_execute.return_value = ["*filter", "COMMIT"]

with tempfile.NamedTemporaryFile(mode="r") as saved:
CsHelper.save_iptables("iptables-save", saved.name)
self.assertEqual("*filter\nCOMMIT\n", saved.read())
mock_execute.assert_called_once_with("iptables-save")

@mock.patch('cs.CsHelper.execute')
def test_save_nftables_leaves_out_iptables_tables(self, mock_execute):
tables = ["table ip filter", "table ip nat", "table ip mangle", "table ip6 filter", "table ip6 raw",
"table bridge broute", "table ip6 ip6_firewall", "table ip ip4_firewall", "table inet cloudstack"]
mock_execute.side_effect = lambda command: tables if command == "nft list tables" else \
["%s {" % command.replace("nft list ", ""), "}"]

with tempfile.NamedTemporaryFile(mode="r") as saved:
CsHelper.save_nftables(saved.name)
content = saved.read()

self.assertEqual("table ip6 ip6_firewall {\n}\ntable ip ip4_firewall {\n}\ntable inet cloudstack {\n}\n", content)

@mock.patch('cs.CsHelper.execute')
def test_save_nftables_writes_an_empty_file_without_nftables_tables(self, mock_execute):
mock_execute.side_effect = lambda command: ["table ip filter", "table ip nat"] if command == "nft list tables" else ["x"]

with tempfile.NamedTemporaryFile(mode="r") as saved:
CsHelper.save_nftables(saved.name)
self.assertEqual("", saved.read())


if __name__ == '__main__':
unittest.main()