summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2020-12-21 14:09:04 +0000
committerGerrit Code Review <review@openstack.org>2020-12-21 14:09:04 +0000
commit8d5862d8b2ea9123807042e44e4263a5196b68e7 (patch)
treec9562eebe157be6a1523f23eb29e4620b860337c
parent4fb8163717e94468da08090ebfa8b137076d744a (diff)
parentd69f12e0fd379d57443c73c169149593a6a87240 (diff)
downloadironic-python-agent-8d5862d8b2ea9123807042e44e4263a5196b68e7.tar.gz
Merge "Handle situation when a configdrive is already mounted"6.5.0
-rw-r--r--ironic_python_agent/tests/unit/test_utils.py54
-rw-r--r--ironic_python_agent/utils.py62
2 files changed, 92 insertions, 24 deletions
diff --git a/ironic_python_agent/tests/unit/test_utils.py b/ironic_python_agent/tests/unit/test_utils.py
index f5972b5b..3dd7a5cb 100644
--- a/ironic_python_agent/tests/unit/test_utils.py
+++ b/ironic_python_agent/tests/unit/test_utils.py
@@ -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)
diff --git a/ironic_python_agent/utils.py b/ironic_python_agent/utils.py
index b2310d00..a897210e 100644
--- a/ironic_python_agent/utils.py
+++ b/ironic_python_agent/utils.py
@@ -212,6 +212,39 @@ def _early_log(msg, *args):
print('ironic-python-agent:', msg % args, file=sys.stderr)
+def _copy_config_from(path):
+ for ext in ('', '.d'):
+ src = os.path.join(path, 'etc', 'ironic-python-agent%s' % ext)
+ if not os.path.isdir(src):
+ _early_log('%s not found', src)
+ continue
+
+ dest = '/etc/ironic-python-agent%s' % ext
+ _early_log('Copying configuration from %s to %s', src, dest)
+ try:
+ os.makedirs(dest, exist_ok=True)
+
+ # TODO(dtantsur): use shutil.copytree(.., dirs_exist_ok=True)
+ # when the minimum supported Python is 3.8.
+ for name in os.listdir(src):
+ src_file = os.path.join(src, name)
+ dst_file = os.path.join(dest, name)
+ shutil.copy(src_file, dst_file)
+ except Exception as exc:
+ msg = ("Unable to copy vmedia configuration %s to %s: %s"
+ % (src, dest, exc))
+ 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.
@@ -223,29 +256,12 @@ def copy_config_from_vmedia():
_early_log('No virtual media device detected')
return
- with _mounted(vmedia_device_file) as vmedia_mount_point:
- for ext in ('', '.d'):
- src = os.path.join(vmedia_mount_point, 'etc',
- 'ironic-python-agent%s' % ext)
- if not os.path.isdir(src):
- _early_log('%s not found', src)
- continue
-
- dest = '/etc/ironic-python-agent%s' % ext
- _early_log('Copying configuration from %s to %s', src, dest)
- try:
- os.makedirs(dest, exist_ok=True)
-
- # TODO(dtantsur): use shutil.copytree(.., dirs_exist_ok=True)
- # when the minimum supported Python is 3.8.
- for name in os.listdir(src):
- src_file = os.path.join(src, name)
- dst_file = os.path.join(dest, name)
- shutil.copy(src_file, dst_file)
- except Exception as exc:
- msg = ("Unable to copy vmedia configuration %s to %s: %s"
- % (src, dest, exc))
- raise errors.VirtualMediaBootError(msg)
+ 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():