podman: get cpus allowed list only when isolcpus in cmdline

When building the podman command, only get cpus allowed list when there
is isolcpus in the /proc/cmdline otherwise skip the argument.

Note: re-working the Mocks for cpu affinity so we can properly test the
/proc/cmdline reads.

Change-Id: I270c90d3adc8824991896443c6074f8f7357c942
Related-Bug: #1884765
Co-Authored-By: Alex Schultz <aschultz@redhat.com>
(cherry picked from commit 7ea9455221)
This commit is contained in:
Emilien Macchi 2020-06-23 08:51:03 -04:00 committed by Alex Schultz
parent f7c39f6a04
commit c8661e0505
5 changed files with 43 additions and 37 deletions

View File

@ -91,7 +91,10 @@ class ComposeV1Builder(base.BaseBuilder):
if cconfig['cpuset_cpus'] != 'all': if cconfig['cpuset_cpus'] != 'all':
cmd.append('--cpuset-cpus=%s' % cconfig['cpuset_cpus']) cmd.append('--cpuset-cpus=%s' % cconfig['cpuset_cpus'])
else: else:
cmd.append('--cpuset-cpus=%s' % common.get_cpus_allowed_list()) with open('/proc/cmdline') as cmdline:
if 'isolcpus' in cmdline.read():
cmd.append('--cpuset-cpus=%s' %
common.get_cpus_allowed_list())
self.string_arg(cconfig, cmd, self.string_arg(cconfig, cmd,
'stop_grace_period', '--stop-timeout', 'stop_grace_period', '--stop-timeout',

View File

@ -100,7 +100,10 @@ class PodmanBuilder(base.BaseBuilder):
if cconfig['cpuset_cpus'] != 'all': if cconfig['cpuset_cpus'] != 'all':
cmd.append('--cpuset-cpus=%s' % cconfig['cpuset_cpus']) cmd.append('--cpuset-cpus=%s' % cconfig['cpuset_cpus'])
else: else:
cmd.append('--cpuset-cpus=%s' % common.get_cpus_allowed_list()) with open('/proc/cmdline') as cmdline:
if 'isolcpus' in cmdline.read():
cmd.append('--cpuset-cpus=%s' %
common.get_cpus_allowed_list())
self.string_arg(cconfig, cmd, self.string_arg(cconfig, cmd,
'stop_grace_period', '--stop-timeout', 'stop_grace_period', '--stop-timeout',

View File

@ -16,6 +16,7 @@ import collections
import inspect import inspect
import json import json
import mock import mock
import sys
import tenacity import tenacity
from paunch.builder import base as basebuilder from paunch.builder import base as basebuilder
@ -26,10 +27,20 @@ from paunch.tests import base
class TestBaseBuilder(base.TestCase): class TestBaseBuilder(base.TestCase):
@mock.patch("psutil.Process.cpu_affinity", return_value=[0, 1, 2, 3]) def setUp(self):
super(TestBaseBuilder, self).setUp()
mock_cpu_obj = mock.MagicMock()
mock_cpu_aff = mock.MagicMock()
mock_cpu_aff.return_value = [0, 1, 2, 3]
mock_cpu_obj.cpu_affinity = mock_cpu_aff
self.psutil_mock = mock.patch('psutil.Process',
return_value=mock_cpu_obj)
self.psutil_mock.start()
self.addCleanup(self.psutil_mock.stop)
@mock.patch("paunch.builder.base.BaseBuilder.delete_updated", @mock.patch("paunch.builder.base.BaseBuilder.delete_updated",
return_value=False) return_value=False)
def test_apply(self, mock_delete_updated, mock_cpu): def test_apply(self, mock_delete_updated):
orig_call = tenacity.wait.wait_random_exponential.__call__ orig_call = tenacity.wait.wait_random_exponential.__call__
orig_argspec = inspect.getargspec(orig_call) orig_argspec = inspect.getargspec(orig_call)
config = { config = {
@ -168,7 +179,7 @@ three-12345678 three''', '', 0),
'--label', 'container_name=one', '--label', 'container_name=one',
'--label', 'managed_by=tester', '--label', 'managed_by=tester',
'--label', 'config_data=%s' % json.dumps(config['one']), '--label', 'config_data=%s' % json.dumps(config['one']),
'--detach=true', '--cpuset-cpus=0,1,2,3', '--detach=true',
'centos:7'], mock.ANY 'centos:7'], mock.ANY
), ),
# run two # run two
@ -178,7 +189,7 @@ three-12345678 three''', '', 0),
'--label', 'container_name=two', '--label', 'container_name=two',
'--label', 'managed_by=tester', '--label', 'managed_by=tester',
'--label', 'config_data=%s' % json.dumps(config['two']), '--label', 'config_data=%s' % json.dumps(config['two']),
'--detach=true', '--cpuset-cpus=0,1,2,3', '--detach=true',
'centos:7'], mock.ANY 'centos:7'], mock.ANY
), ),
# run four # run four
@ -188,7 +199,7 @@ three-12345678 three''', '', 0),
'--label', 'container_name=four', '--label', 'container_name=four',
'--label', 'managed_by=tester', '--label', 'managed_by=tester',
'--label', 'config_data=%s' % json.dumps(config['four']), '--label', 'config_data=%s' % json.dumps(config['four']),
'--detach=true', '--cpuset-cpus=0,1,2,3', '--detach=true',
'centos:7'], mock.ANY 'centos:7'], mock.ANY
), ),
# execute within four # execute within four
@ -198,11 +209,10 @@ three-12345678 three''', '', 0),
), ),
]) ])
@mock.patch("psutil.Process.cpu_affinity", return_value=[0, 1, 2, 3])
@mock.patch("paunch.runner.BaseRunner.container_names") @mock.patch("paunch.runner.BaseRunner.container_names")
@mock.patch("paunch.runner.BaseRunner.discover_container_name", @mock.patch("paunch.runner.BaseRunner.discover_container_name",
return_value='one') return_value='one')
def test_apply_idempotency(self, mock_dname, mock_cnames, mock_cpu): def test_apply_idempotency_with_isolcpus(self, mock_dname, mock_cnames):
config = { config = {
# running with the same config and given an ephemeral name # running with the same config and given an ephemeral name
'one': { 'one': {
@ -270,7 +280,13 @@ three-12345678 three''', '', 0),
r.execute = exe r.execute = exe
builder = compose1.ComposeV1Builder('foo', config, r) builder = compose1.ComposeV1Builder('foo', config, r)
stdout, stderr, deploy_status_code = builder.apply() if (sys.version_info > (3, 0)):
open_builtins = "builtins.open"
else:
open_builtins = "__builtin__.open"
with mock.patch(open_builtins,
mock.mock_open(read_data="isolcpus")):
stdout, stderr, deploy_status_code = builder.apply()
self.assertEqual(0, deploy_status_code) self.assertEqual(0, deploy_status_code)
self.assertEqual([ self.assertEqual([
'Created two-12345678', 'Created two-12345678',
@ -470,8 +486,7 @@ three-12345678 three''', '', 0),
self.assertIn(arg, cmd) self.assertIn(arg, cmd)
@mock.patch('paunch.runner.DockerRunner', autospec=True) @mock.patch('paunch.runner.DockerRunner', autospec=True)
@mock.patch("psutil.Process.cpu_affinity", return_value=[0, 1, 2, 3]) def test_container_run_args_lists(self, runner):
def test_container_run_args_lists(self, mock_cpu, runner):
config = { config = {
'one': { 'one': {
'image': 'centos:7', 'image': 'centos:7',
@ -503,7 +518,6 @@ three-12345678 three''', '', 0),
'--group-add=docker', '--group-add=zuul', '--group-add=docker', '--group-add=zuul',
'--volume=/foo:/foo:rw', '--volume=/bar:/bar:ro', '--volume=/foo:/foo:rw', '--volume=/bar:/bar:ro',
'--volumes-from=two', '--volumes-from=three', '--volumes-from=two', '--volumes-from=three',
'--cpuset-cpus=0,1,2,3',
'--cap-add=SYS_ADMIN', '--cap-add=SETUID', '--cap-drop=NET_RAW', '--cap-add=SYS_ADMIN', '--cap-add=SETUID', '--cap-drop=NET_RAW',
'centos:7', 'ls', '-l', '/foo'], 'centos:7', 'ls', '-l', '/foo'],
cmd cmd

View File

@ -20,8 +20,7 @@ from paunch.tests import test_builder_base as tbb
class TestComposeV1Builder(tbb.TestBaseBuilder): class TestComposeV1Builder(tbb.TestBaseBuilder):
@mock.patch('paunch.runner.DockerRunner', autospec=True) @mock.patch('paunch.runner.DockerRunner', autospec=True)
@mock.patch("psutil.Process.cpu_affinity", return_value=[0, 1, 2, 3]) def test_cont_run_args(self, runner):
def test_cont_run_args(self, mock_cpu, runner):
config = { config = {
'one': { 'one': {
'image': 'centos:7', 'image': 'centos:7',
@ -84,8 +83,7 @@ class TestComposeV1Builder(tbb.TestBaseBuilder):
) )
@mock.patch('paunch.runner.DockerRunner', autospec=True) @mock.patch('paunch.runner.DockerRunner', autospec=True)
@mock.patch("psutil.Process.cpu_affinity", return_value=[0, 1, 2, 3]) def test_cont_run_args_validation_true(self, runner):
def test_cont_run_args_validation_true(self, mock_cpu, runner):
config = { config = {
'one': { 'one': {
'image': 'foo', 'image': 'foo',
@ -99,15 +97,12 @@ class TestComposeV1Builder(tbb.TestBaseBuilder):
self.assertTrue(builder.container_run_args(cmd, 'one')) self.assertTrue(builder.container_run_args(cmd, 'one'))
self.assertEqual( self.assertEqual(
['docker', '--detach=true', ['docker', '--detach=true',
'--volume=/foo:/foo:rw', '--volume=/bar:/bar:ro', '--volume=/foo:/foo:rw', '--volume=/bar:/bar:ro', 'foo'],
'--cpuset-cpus=0,1,2,3',
'foo'],
cmd cmd
) )
@mock.patch('paunch.runner.DockerRunner', autospec=True) @mock.patch('paunch.runner.DockerRunner', autospec=True)
@mock.patch("psutil.Process.cpu_affinity", return_value=[0, 1, 2, 3]) def test_cont_run_args_validation_false(self, runner):
def test_cont_run_args_validation_false(self, mock_cpu, runner):
config = { config = {
'one': { 'one': {
'image': 'foo', 'image': 'foo',
@ -121,7 +116,6 @@ class TestComposeV1Builder(tbb.TestBaseBuilder):
self.assertFalse(builder.container_run_args(cmd, 'one')) self.assertFalse(builder.container_run_args(cmd, 'one'))
self.assertEqual( self.assertEqual(
['docker', '--detach=true', ['docker', '--detach=true',
'--volume=/foo:/foo:rw', '--volume=/bar:/bar:ro', '--volume=/foo:/foo:rw', '--volume=/bar:/bar:ro', 'foo'],
'--cpuset-cpus=0,1,2,3', 'foo'],
cmd cmd
) )

View File

@ -20,8 +20,7 @@ from paunch.tests import test_builder_base as base
class TestPodmanBuilder(base.TestBaseBuilder): class TestPodmanBuilder(base.TestBaseBuilder):
@mock.patch("psutil.Process.cpu_affinity", return_value=[0, 1, 2, 3]) def test_cont_run_args(self):
def test_cont_run_args(self, mock_cpu):
config = { config = {
'one': { 'one': {
'image': 'centos:7', 'image': 'centos:7',
@ -67,16 +66,13 @@ class TestPodmanBuilder(base.TestBaseBuilder):
'--hostname=foohostname', '--hostname=foohostname',
'--add-host=foohost:127.0.0.1', '--add-host=foohost:127.0.0.1',
'--add-host=barhost:127.0.0.2', '--add-host=barhost:127.0.0.2',
'--cpuset-cpus=0,1,2,3',
'--cap-add=SYS_ADMIN', '--cap-add=SETUID', '--cap-drop=NET_RAW', '--cap-add=SYS_ADMIN', '--cap-add=SETUID', '--cap-drop=NET_RAW',
'centos:7'], 'centos:7'],
cmd cmd
) )
@mock.patch("psutil.Process.cpu_affinity",
return_value=[0, 1, 2, 3, 4, 5, 6, 7])
@mock.patch('paunch.runner.PodmanRunner', autospec=True) @mock.patch('paunch.runner.PodmanRunner', autospec=True)
def test_cont_run_args_validation_true(self, runner, mock_cpu): def test_cont_run_args_validation_true(self, runner):
config = { config = {
'one': { 'one': {
'image': 'foo', 'image': 'foo',
@ -90,15 +86,12 @@ class TestPodmanBuilder(base.TestBaseBuilder):
self.assertTrue(builder.container_run_args(cmd, 'one')) self.assertTrue(builder.container_run_args(cmd, 'one'))
self.assertEqual( self.assertEqual(
['podman', '--conmon-pidfile=/var/run/one.pid', '--detach=true', ['podman', '--conmon-pidfile=/var/run/one.pid', '--detach=true',
'--volume=/foo:/foo:rw', '--volume=/bar:/bar:ro', '--volume=/foo:/foo:rw', '--volume=/bar:/bar:ro', 'foo'],
'--cpuset-cpus=0,1,2,3,4,5,6,7', 'foo'],
cmd cmd
) )
@mock.patch("psutil.Process.cpu_affinity",
return_value=[0, 1, 2, 3, 4, 5, 6, 7])
@mock.patch('paunch.runner.PodmanRunner', autospec=True) @mock.patch('paunch.runner.PodmanRunner', autospec=True)
def test_cont_run_args_validation_false(self, runner, mock_cpu): def test_cont_run_args_validation_false(self, runner):
config = { config = {
'one': { 'one': {
'image': 'foo', 'image': 'foo',
@ -112,7 +105,6 @@ class TestPodmanBuilder(base.TestBaseBuilder):
self.assertFalse(builder.container_run_args(cmd, 'one')) self.assertFalse(builder.container_run_args(cmd, 'one'))
self.assertEqual( self.assertEqual(
['podman', '--conmon-pidfile=/var/run/one.pid', '--detach=true', ['podman', '--conmon-pidfile=/var/run/one.pid', '--detach=true',
'--volume=/foo:/foo:rw', '--volume=/bar:/bar:ro', '--volume=/foo:/foo:rw', '--volume=/bar:/bar:ro', 'foo'],
'--cpuset-cpus=0,1,2,3,4,5,6,7', 'foo'],
cmd cmd
) )