Merge "Handle situation when a configdrive is already mounted"
This commit is contained in:
commit
8d5862d8b2
@ -1028,21 +1028,35 @@ class TestCopyConfigFromVmedia(testtools.TestCase):
|
|||||||
mock_copy.assert_not_called()
|
mock_copy.assert_not_called()
|
||||||
|
|
||||||
def test_no_files(self, mock_execute, mock_copy, mock_find_device):
|
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'
|
mock_find_device.return_value = '/dev/something'
|
||||||
utils.copy_config_from_vmedia()
|
utils.copy_config_from_vmedia()
|
||||||
mock_execute.assert_has_calls([
|
mock_execute.assert_has_calls([
|
||||||
|
mock.call('findmnt', '-n', '-oTARGET', '/dev/something'),
|
||||||
mock.call('mount', '/dev/something', mock.ANY),
|
mock.call('mount', '/dev/something', mock.ANY),
|
||||||
mock.call('umount', mock.ANY),
|
mock.call('umount', mock.ANY),
|
||||||
])
|
])
|
||||||
mock_copy.assert_not_called()
|
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)
|
@mock.patch.object(os, 'makedirs', autospec=True)
|
||||||
def test_copy(self, mock_makedirs, mock_execute, mock_copy,
|
def test_copy(self, mock_makedirs, mock_execute, mock_copy,
|
||||||
mock_find_device):
|
mock_find_device):
|
||||||
mock_find_device.return_value = '/dev/something'
|
mock_find_device.return_value = '/dev/something'
|
||||||
path = None
|
path = None
|
||||||
|
|
||||||
def _fake_exec(command, arg1, arg2=None):
|
def _fake_exec(command, arg1, arg2=None, *args):
|
||||||
nonlocal path
|
nonlocal path
|
||||||
if command == 'mount':
|
if command == 'mount':
|
||||||
path = arg2
|
path = arg2
|
||||||
@ -1059,6 +1073,8 @@ class TestCopyConfigFromVmedia(testtools.TestCase):
|
|||||||
with open(os.path.join(path, 'etc', 'ironic-python-agent.d',
|
with open(os.path.join(path, 'etc', 'ironic-python-agent.d',
|
||||||
'ironic.conf'), 'wt') as fp:
|
'ironic.conf'), 'wt') as fp:
|
||||||
fp.write('I am a config')
|
fp.write('I am a config')
|
||||||
|
elif command == 'findmnt':
|
||||||
|
raise processutils.ProcessExecutionError("")
|
||||||
else:
|
else:
|
||||||
self.assertEqual('umount', command)
|
self.assertEqual('umount', command)
|
||||||
|
|
||||||
@ -1080,3 +1096,39 @@ class TestCopyConfigFromVmedia(testtools.TestCase):
|
|||||||
mock.call(mock.ANY, '/etc/ironic-python-agent.d/ironic.conf'),
|
mock.call(mock.ANY, '/etc/ironic-python-agent.d/ironic.conf'),
|
||||||
], any_order=True)
|
], any_order=True)
|
||||||
self.assertFalse(os.path.exists(path))
|
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)
|
||||||
|
@ -212,6 +212,39 @@ def _early_log(msg, *args):
|
|||||||
print('ironic-python-agent:', msg % args, file=sys.stderr)
|
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():
|
def copy_config_from_vmedia():
|
||||||
"""Copies any configuration from a virtual media device.
|
"""Copies any configuration from a virtual media device.
|
||||||
|
|
||||||
@ -223,29 +256,12 @@ def copy_config_from_vmedia():
|
|||||||
_early_log('No virtual media device detected')
|
_early_log('No virtual media device detected')
|
||||||
return
|
return
|
||||||
|
|
||||||
with _mounted(vmedia_device_file) as vmedia_mount_point:
|
mounted = _find_mount_point(vmedia_device_file)
|
||||||
for ext in ('', '.d'):
|
if mounted:
|
||||||
src = os.path.join(vmedia_mount_point, 'etc',
|
_copy_config_from(mounted)
|
||||||
'ironic-python-agent%s' % ext)
|
else:
|
||||||
if not os.path.isdir(src):
|
with _mounted(vmedia_device_file) as vmedia_mount_point:
|
||||||
_early_log('%s not found', src)
|
_copy_config_from(vmedia_mount_point)
|
||||||
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 _get_cached_params():
|
def _get_cached_params():
|
||||||
|
Loading…
x
Reference in New Issue
Block a user