
By default, all config drive types are checked. But if somehow, the implementation of each type fails, the metadata service errors out and does not check for the next type. The issue was reported here: https://ask.cloudbase.it/question/3094/windows-server-2016-extendvolumespluginp-doesnt-work/ In that case, in the method is_vfat_drive: match = VOLUME_LABEL_REGEX.search(out) return match.group(1) in CONFIG_DRIVE_LABELS if match value is None, the return line throws an error: AttributeError: 'NoneType' object has no attribute 'group' To make sure that no other implementation will bubble up the error, we catch the error in the config_drive metadata service. Catching the error will allow that the next config_drive type will be checked for metadata. Change-Id: I0d9967ec6a81214c7d78be667cffa4a98758587a
159 lines
6.2 KiB
Python
159 lines
6.2 KiB
Python
# Copyright 2015 Cloudbase Solutions Srl
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import os
|
|
import unittest
|
|
|
|
try:
|
|
import unittest.mock as mock
|
|
except ImportError:
|
|
import mock
|
|
|
|
from cloudbaseinit import exception
|
|
from cloudbaseinit.tests import testutils
|
|
from cloudbaseinit.utils.windows import vfat
|
|
|
|
CONF = vfat.CONF
|
|
|
|
|
|
class TestVfat(unittest.TestCase):
|
|
|
|
def _test_is_vfat_drive(self, execute_process_value,
|
|
expected_logging,
|
|
expected_response):
|
|
|
|
mock_osutils = mock.Mock()
|
|
mock_osutils.execute_process.return_value = execute_process_value
|
|
|
|
with testutils.LogSnatcher('cloudbaseinit.utils.windows.'
|
|
'vfat') as snatcher:
|
|
with testutils.ConfPatcher('mtools_path', 'mtools_path'):
|
|
|
|
response = vfat.is_vfat_drive(mock_osutils,
|
|
mock.sentinel.drive)
|
|
|
|
mdir = os.path.join(CONF.mtools_path, "mlabel.exe")
|
|
mock_osutils.execute_process.assert_called_once_with(
|
|
[mdir, "-i", mock.sentinel.drive, "-s"],
|
|
shell=False)
|
|
|
|
self.assertEqual(expected_logging, snatcher.output)
|
|
self.assertEqual(expected_response, response)
|
|
|
|
def test_is_vfat_drive_fails(self):
|
|
test_stderr = b"test stderr"
|
|
|
|
expected_logging = [
|
|
"Could not retrieve label for VFAT drive path %r"
|
|
% (mock.sentinel.drive),
|
|
"mlabel failed with error %r" % test_stderr,
|
|
]
|
|
execute_process_value = (None, test_stderr, 1)
|
|
expected_response = False
|
|
|
|
self._test_is_vfat_drive(execute_process_value=execute_process_value,
|
|
expected_logging=expected_logging,
|
|
expected_response=expected_response)
|
|
|
|
def test_is_vfat_drive_different_label(self):
|
|
mock_out = b"Volume label is config"
|
|
expected_logging = [
|
|
"Obtained label information for drive %r: %r"
|
|
% (mock.sentinel.drive, mock_out)
|
|
]
|
|
execute_process_value = (mock_out, None, 0)
|
|
expected_response = False
|
|
|
|
self._test_is_vfat_drive(execute_process_value=execute_process_value,
|
|
expected_logging=expected_logging,
|
|
expected_response=expected_response)
|
|
|
|
def test_is_vfat_drive_works(self):
|
|
mock_out = b"Volume label is config-2 \r\n"
|
|
expected_logging = [
|
|
"Obtained label information for drive %r: %r"
|
|
% (mock.sentinel.drive, mock_out)
|
|
]
|
|
execute_process_value = (mock_out, None, 0)
|
|
expected_response = True
|
|
|
|
self._test_is_vfat_drive(execute_process_value=execute_process_value,
|
|
expected_logging=expected_logging,
|
|
expected_response=expected_response)
|
|
|
|
def test_is_vfat_drive_works_uppercase(self):
|
|
mock_out = b"Volume label is CONFIG-2 \r\n"
|
|
expected_logging = [
|
|
"Obtained label information for drive %r: %r"
|
|
% (mock.sentinel.drive, mock_out)
|
|
]
|
|
execute_process_value = (mock_out, None, 0)
|
|
expected_response = True
|
|
|
|
self._test_is_vfat_drive(execute_process_value=execute_process_value,
|
|
expected_logging=expected_logging,
|
|
expected_response=expected_response)
|
|
|
|
def test_is_vfat_drive_with_wrong_label(self):
|
|
mock_out = b"Not volu label \r\n"
|
|
expected_logging = [
|
|
"Obtained label information for drive %r: %r"
|
|
% (mock.sentinel.drive, mock_out)
|
|
]
|
|
execute_process_value = (mock_out, None, 0)
|
|
expected_response = False
|
|
|
|
self._test_is_vfat_drive(execute_process_value=execute_process_value,
|
|
expected_logging=expected_logging,
|
|
expected_response=expected_response)
|
|
|
|
@testutils.ConfPatcher('mtools_path', 'mtools_path')
|
|
@mock.patch('os.chdir')
|
|
def test_copy(self, mock_os_chdir):
|
|
cwd = os.getcwd()
|
|
mock_osutils = mock.Mock()
|
|
|
|
vfat.copy_from_vfat_drive(mock_osutils,
|
|
mock.sentinel.drive,
|
|
mock.sentinel.target_path)
|
|
|
|
mock_os_chdir_calls = [
|
|
mock.call(mock.sentinel.target_path),
|
|
mock.call(cwd),
|
|
]
|
|
self.assertEqual(mock_os_chdir_calls, mock_os_chdir.mock_calls)
|
|
self.assertEqual(os.getcwd(), cwd)
|
|
|
|
mcopy = os.path.join(CONF.mtools_path, "mcopy.exe")
|
|
mock_osutils.execute_process.assert_called_once_with(
|
|
[mcopy, "-s", "-n", "-i", mock.sentinel.drive, "::/", "."],
|
|
shell=False)
|
|
|
|
def test_is_vfat_drive_mtools_not_given(self):
|
|
with self.assertRaises(exception.CloudbaseInitException) as cm:
|
|
vfat.is_vfat_drive(mock.sentinel.osutils,
|
|
mock.sentinel.target_path)
|
|
expected_message = ('"mtools_path" needs to be provided in order '
|
|
'to access VFAT drives')
|
|
self.assertEqual(expected_message, str(cm.exception.args[0]))
|
|
|
|
def test_copy_from_vfat_drive_mtools_not_given(self):
|
|
with self.assertRaises(exception.CloudbaseInitException) as cm:
|
|
vfat.copy_from_vfat_drive(mock.sentinel.osutils,
|
|
mock.sentinel.drive_path,
|
|
mock.sentinel.target_path)
|
|
expected_message = ('"mtools_path" needs to be provided in order '
|
|
'to access VFAT drives')
|
|
self.assertEqual(expected_message, str(cm.exception.args[0]))
|