From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from gandalf.ozlabs.org (gandalf.ozlabs.org [150.107.74.76]) by passt.top (Postfix) with ESMTPS id 077505A0279 for ; Thu, 20 Apr 2023 03:11:28 +0200 (CEST) Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4Q203Y6QkNz4xMv; Thu, 20 Apr 2023 11:11:21 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=201602; t=1681953081; bh=G1slIsh0gnmD4Z1+OWM6WuXXbwLAu5GzHp5Qe2ayvMM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KhKqnM4fWJBDalCf42wTN/2JAoiHCKFTil/ck+Vzu7HOKLb3Gkcy3bqkMPFLhBYEG U7eq8rjEmDhT6FDwhPg/KwBDwfV+49nD16vfFTJ4Y+RQ9lSKBQ8X/E4qvG0kdZlJC9 qt4zsQ5x6SrGiNmFGbps0vTZv6K1GtA6WB+2fXTM= From: David Gibson To: passt-dev@passt.top, Stefano Brivio Subject: [PATCH 5/7] avocado: Helper functions and classes to run commands via nstool Date: Thu, 20 Apr 2023 11:11:06 +1000 Message-Id: <20230420011108.494181-6-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20230420011108.494181-1-david@gibson.dropbear.id.au> References: <20230420011108.494181-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: YYKW3GLH6E65UXCNCIWLZQF7AXKW5IMF X-Message-ID-Hash: YYKW3GLH6E65UXCNCIWLZQF7AXKW5IMF X-MailFrom: dgibson@gandalf.ozlabs.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: David Gibson X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: These are roughly equivalent to the 'context' subsystem in the existing shell test framework. Signed-off-by: David Gibson --- avocado/common.py | 117 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-) diff --git a/avocado/common.py b/avocado/common.py index 036ef3d..94308b8 100644 --- a/avocado/common.py +++ b/avocado/common.py @@ -7,8 +7,15 @@ # Copyright Red Hat # Author: David Gibson +import json +import os.path +import sys + import avocado -from avocado.utils.process import system_output, CmdError +from avocado.utils.process import system_output, SubProcess, CmdError + + +NSTOOL = './test/nstool' class BaseTest(avocado.Test): @@ -19,6 +26,51 @@ class BaseTest(avocado.Test): return system_output(cmd, **kwargs) +class NsTool: + def __init__(self, sockpath): + self.sockpath = sockpath + pid = system_output( + '{} info -wp {}'.format(NSTOOL, sockpath), timeout=1) + self.pid = int(pid) + print('NsTool object: sockpath={} PID={}'.format(sockpath, self.pid), + file=sys.stderr) + + def pid(self): + return self.pid + + def _xcmd(self, cmd, sudo=False): + if sudo: + opts = '--keep-caps' + else: + opts = '' + return '{} exec {} {} -- {}'.format(NSTOOL, opts, self.sockpath, cmd) + + def subprocess(self, cmd, sudo=False, **kwargs): + return SubProcess(self._xcmd(cmd, sudo), **kwargs) + + def system_output(self, cmd, sudo=False, **kwargs): + return system_output(self._xcmd(cmd, sudo), **kwargs) + + +class NsToolUnshare(NsTool): + def __init__(self, workdir, sockname, unshare_opts, parent=None): + sockpath = os.path.join(workdir, sockname) + holdcmd = 'unshare {} -- {} hold {}'.format( + unshare_opts, NSTOOL, sockpath) + if parent is None: + self.holder = SubProcess(holdcmd) + else: + self.holder = parent.subprocess(holdcmd, sudo=True) + + self.holder.start() + super().__init__(sockpath) + + def __del__(self): + cmd = '{} stop {}'.format(NSTOOL, self.sockpath) + system_output(cmd) + self.holder.stop() + + # # Tests for the test infrastructure itself # @@ -29,3 +81,66 @@ class HostExecTests(BaseTest): def test_false(self): self.assertRaises(CmdError, self.hostx, 'false') + + +class UserNsTests(BaseTest): + def setUp(self): + super().setUp() + + self.ns = NsToolUnshare(self.workdir, 'userns', '-Uc') + + def tearDown(self): + del(self.ns) + + super().tearDown() + + def test(self): + capcmd = 'capsh --has-p=CAP_SETUID' + self.assertRaises(CmdError, self.hostx, capcmd) + self.ns.system_output(capcmd, sudo=True) + + +class NestedNsTests(BaseTest): + def setUp(self): + super().setUp() + + self.userns = NsToolUnshare(self.workdir, 'userns', '-Uc') + self.netns = NsToolUnshare( + self.workdir, 'netns', '-n', parent=self.userns) + + def tearDown(self): + del(self.netns) + del(self.userns) + super().tearDown() + + def test_unnested(self): + # Shouldn't have permission to create a netns without nesting + # it in the userns + self.assertRaises(CmdError, NsToolUnshare, + self.workdir, 'netns2', '-n') + + def test_nested(self): + self.netns.system_output('true') + output = self.netns.system_output('ip -j link show') + ifs = json.loads(output) + self.assertEquals(len(ifs), 1) + self.assertEquals(ifs[0]['ifname'], 'lo') + + +class NsConnectTests(BaseTest): + def setUp(self): + super().setUp() + + self.sockpath = os.path.join(self.workdir, 'hostns') + holdcmd = '{} hold {}'.format(NSTOOL, self.sockpath) + self.holder = SubProcess(holdcmd) + self.holder.start() + + def tearDown(self): + self.holder.stop() + + super().tearDown() + + def test_connect(self): + hostns = NsTool(self.sockpath) + hostns.system_output('true') -- 2.40.0