From cf64c4c4f6d4589cccd0339837fe8e908d69a822 Mon Sep 17 00:00:00 2001 From: Wayne Werner Date: Tue, 23 Apr 2019 17:54:57 -0500 Subject: [PATCH 1/2] Linux containers are containers Both Docker and LXC. Also, if we have a virtual_subtype then we're virtual of *some* kind. Maybe we can't be specific, but we really shouldn't be saying that we're *physical* --- salt/grains/core.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/salt/grains/core.py b/salt/grains/core.py index c48da391f912..c6a884b773a5 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -944,11 +944,13 @@ def _virtual(osdata): with salt.utils.files.fopen('/proc/1/cgroup', 'r') as fhr: fhr_contents = fhr.read() if ':/lxc/' in fhr_contents: + grains['virtual'] = 'container' grains['virtual_subtype'] = 'LXC' else: if any(x in fhr_contents for x in (':/system.slice/docker', ':/docker/', ':/docker-ce/')): + grains['virtual'] = 'container' grains['virtual_subtype'] = 'Docker' except IOError: pass @@ -1051,6 +1053,11 @@ def _virtual(osdata): if os.path.isfile('/var/run/xenconsoled.pid'): grains['virtual_subtype'] = 'Xen Dom0' + # If we have a virtual_subtype, we're virtual, but maybe we couldn't + # figure out what specific virtual type we were? + if grains['virtual_subtype'] and grains['virtual'] == 'physical': + grains['virtual'] = 'virtual' + for command in failed_commands: log.info( "Although '%s' was found in path, the current user " From cdf165624075bed4cea76023bf106bea308e674d Mon Sep 17 00:00:00 2001 From: Wayne Werner Date: Wed, 24 Apr 2019 12:46:26 -0500 Subject: [PATCH 2/2] Add tests for virtual grains --- salt/grains/core.py | 2 +- tests/unit/grains/test_core.py | 58 ++++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/salt/grains/core.py b/salt/grains/core.py index c6a884b773a5..a4b0e16d0a56 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -1055,7 +1055,7 @@ def _virtual(osdata): # If we have a virtual_subtype, we're virtual, but maybe we couldn't # figure out what specific virtual type we were? - if grains['virtual_subtype'] and grains['virtual'] == 'physical': + if grains.get('virtual_subtype') and grains['virtual'] == 'physical': grains['virtual'] = 'virtual' for command in failed_commands: diff --git a/tests/unit/grains/test_core.py b/tests/unit/grains/test_core.py index 6dbeb42a754f..9b6740484385 100644 --- a/tests/unit/grains/test_core.py +++ b/tests/unit/grains/test_core.py @@ -796,7 +796,7 @@ def test_bsd_memdata(self): @skipIf(salt.utils.platform.is_windows(), 'System is Windows') def test_docker_virtual(self): ''' - Test if OS grains are parsed correctly in Ubuntu Xenial Xerus + Test if virtual grains are parsed correctly in Docker. ''' with patch.object(os.path, 'isdir', MagicMock(return_value=False)): with patch.object(os.path, @@ -810,10 +810,37 @@ def test_docker_virtual(self): 'Testing Docker cgroup substring \'%s\'', cgroup_substr) with patch('salt.utils.files.fopen', mock_open(read_data=cgroup_data)): with patch.dict(core.__salt__, {'cmd.run_all': MagicMock()}): + grains = core._virtual({'kernel': 'Linux'}) self.assertEqual( - core._virtual({'kernel': 'Linux'}).get('virtual_subtype'), + grains.get('virtual_subtype'), 'Docker' ) + self.assertEqual( + grains.get('virtual'), + 'container', + ) + + @skipIf(salt.utils.platform.is_windows(), 'System is Windows') + def test_lxc_virtual(self): + ''' + Test if virtual grains are parsed correctly in LXC. + ''' + with patch.object(os.path, 'isdir', MagicMock(return_value=False)): + with patch.object(os.path, + 'isfile', + MagicMock(side_effect=lambda x: True if x == '/proc/1/cgroup' else False)): + cgroup_data = '10:memory:/lxc/a_long_sha256sum' + with patch('salt.utils.files.fopen', mock_open(read_data=cgroup_data)): + with patch.dict(core.__salt__, {'cmd.run_all': MagicMock()}): + grains = core._virtual({'kernel': 'Linux'}) + self.assertEqual( + grains.get('virtual_subtype'), + 'LXC' + ) + self.assertEqual( + grains.get('virtual'), + 'container', + ) @skipIf(salt.utils.platform.is_windows(), 'System is Windows') def test_xen_virtual(self): @@ -830,6 +857,33 @@ def test_xen_virtual(self): 'Xen PV DomU' ) + def test_if_virtual_subtype_exists_virtual_should_fallback_to_virtual(self): + def mockstat(path): + if path == '/': + return 'fnord' + elif path == '/proc/1/root/.': + return 'roscivs' + return None + with patch.dict( + core.__salt__, + { + 'cmd.run': MagicMock(return_value=''), + 'cmd.run_all': MagicMock(return_value={'retcode': 0, 'stdout': ''}), + } + ): + with patch.multiple( + os.path, + isfile=MagicMock(return_value=False), + isdir=MagicMock(side_effect=lambda x: x == '/proc'), + ): + with patch.multiple( + os, + stat=MagicMock(side_effect=mockstat), + ): + grains = core._virtual({'kernel': 'Linux'}) + assert grains.get('virtual_subtype') is not None + assert grains.get('virtual') == 'virtual' + def _check_ipaddress(self, value, ip_v): ''' check if ip address in a list is valid