Handle situation when a configdrive is already mounted

Glean mounts the configdrive and does not unmount it afterwards.
If a mount point already exists, just use it.

Change-Id: Ia62279afbb9fd9770864942dc40629b69ae8f4ae
This commit is contained in:
Dmitry Tantsur 2020-12-16 18:17:24 +01:00
parent 9ae99506c0
commit d69f12e0fd
2 changed files with 92 additions and 24 deletions

View File

@ -1028,21 +1028,35 @@ class TestCopyConfigFromVmedia(testtools.TestCase):
mock_copy.assert_not_called()
def test_no_files(self, mock_execute, mock_copy, mock_find_device):
mock_execute.side_effect = [
processutils.ProcessExecutionError,
('', ''),
('', ''),
]
mock_find_device.return_value = '/dev/something'
utils.copy_config_from_vmedia()
mock_execute.assert_has_calls([
mock.call('findmnt', '-n', '-oTARGET', '/dev/something'),
mock.call('mount', '/dev/something', mock.ANY),
mock.call('umount', mock.ANY),
])
mock_copy.assert_not_called()
def test_mounted_no_files(self, mock_execute, mock_copy, mock_find_device):
mock_execute.return_value = '/some/path', ''
mock_find_device.return_value = '/dev/something'
utils.copy_config_from_vmedia()
mock_execute.assert_called_once_with(
'findmnt', '-n', '-oTARGET', '/dev/something')
mock_copy.assert_not_called()
@mock.patch.object(os, 'makedirs', autospec=True)
def test_copy(self, mock_makedirs, mock_execute, mock_copy,
mock_find_device):
mock_find_device.return_value = '/dev/something'
path = None
def _fake_exec(command, arg1, arg2=None):
def _fake_exec(command, arg1, arg2=None, *args):
nonlocal path
if command == 'mount':
path = arg2
@ -1059,6 +1073,8 @@ class TestCopyConfigFromVmedia(testtools.TestCase):
with open(os.path.join(path, 'etc', 'ironic-python-agent.d',
'ironic.conf'), 'wt') as fp:
fp.write('I am a config')
elif command == 'findmnt':
raise processutils.ProcessExecutionError("")
else:
self.assertEqual('umount', command)
@ -1080,3 +1096,39 @@ class TestCopyConfigFromVmedia(testtools.TestCase):
mock.call(mock.ANY, '/etc/ironic-python-agent.d/ironic.conf'),
], any_order=True)
self.assertFalse(os.path.exists(path))
@mock.patch.object(os, 'makedirs', autospec=True)
def test_copy_mounted(self, mock_makedirs, mock_execute, mock_copy,
mock_find_device):
mock_find_device.return_value = '/dev/something'
path = tempfile.mkdtemp()
self.addCleanup(lambda: shutil.rmtree(path))
# NOTE(dtantsur): makedirs is mocked
os.mkdir(os.path.join(path, 'etc'))
os.mkdir(os.path.join(path, 'etc', 'ironic-python-agent'))
os.mkdir(os.path.join(path, 'etc', 'ironic-python-agent.d'))
with open(os.path.join(path, 'not copied'), 'wt') as fp:
fp.write('not copied')
with open(os.path.join(path, 'etc', 'ironic-python-agent',
'ironic.crt'), 'wt') as fp:
fp.write('I am a cert')
with open(os.path.join(path, 'etc', 'ironic-python-agent.d',
'ironic.conf'), 'wt') as fp:
fp.write('I am a config')
mock_execute.return_value = path, ''
mock_find_device.return_value = '/dev/something'
utils.copy_config_from_vmedia()
mock_makedirs.assert_has_calls([
mock.call('/etc/ironic-python-agent', exist_ok=True),
mock.call('/etc/ironic-python-agent.d', exist_ok=True),
], any_order=True)
mock_execute.assert_called_once_with(
'findmnt', '-n', '-oTARGET', '/dev/something')
mock_copy.assert_has_calls([
mock.call(mock.ANY, '/etc/ironic-python-agent/ironic.crt'),
mock.call(mock.ANY, '/etc/ironic-python-agent.d/ironic.conf'),
], any_order=True)

View File

@ -212,21 +212,9 @@ def _early_log(msg, *args):
print('ironic-python-agent:', msg % args, file=sys.stderr)
def copy_config_from_vmedia():
"""Copies any configuration from a virtual media device.
Copies files under /etc/ironic-python-agent and /etc/ironic-python-agent.d.
"""
vmedia_device_file = _find_device_by_labels(
['config-2', 'vmedia_boot_iso'])
if not vmedia_device_file:
_early_log('No virtual media device detected')
return
with _mounted(vmedia_device_file) as vmedia_mount_point:
def _copy_config_from(path):
for ext in ('', '.d'):
src = os.path.join(vmedia_mount_point, 'etc',
'ironic-python-agent%s' % ext)
src = os.path.join(path, 'etc', 'ironic-python-agent%s' % ext)
if not os.path.isdir(src):
_early_log('%s not found', src)
continue
@ -248,6 +236,34 @@ def copy_config_from_vmedia():
raise errors.VirtualMediaBootError(msg)
def _find_mount_point(device):
try:
path, _e = execute('findmnt', '-n', '-oTARGET', device)
except processutils.ProcessExecutionError:
return
else:
return path.strip()
def copy_config_from_vmedia():
"""Copies any configuration from a virtual media device.
Copies files under /etc/ironic-python-agent and /etc/ironic-python-agent.d.
"""
vmedia_device_file = _find_device_by_labels(
['config-2', 'vmedia_boot_iso'])
if not vmedia_device_file:
_early_log('No virtual media device detected')
return
mounted = _find_mount_point(vmedia_device_file)
if mounted:
_copy_config_from(mounted)
else:
with _mounted(vmedia_device_file) as vmedia_mount_point:
_copy_config_from(vmedia_mount_point)
def _get_cached_params():
"""Helper method to get cached params to ease unit testing."""
return AGENT_PARAMS_CACHED