Add support for multipart cloudconfig format
This patch moves the current behaviour from CloudConfigPlugin.process to another function, process_non_multipart, which handles data in the yaml format. Also, the 'process' function obtains the payload of the parameter and passes it to the process_non_multipart function. Change-Id: I49e214771a17090e842f90f1ad34ca9e37c3021d Closes-Bug: #1409268
This commit is contained in:
parent
b957aadc47
commit
c4297a029f
@ -164,7 +164,7 @@ class UserDataPlugin(base.BasePlugin):
|
||||
if user_data.startswith(b'#cloud-config'):
|
||||
user_data_plugins = factory.load_plugins()
|
||||
cloud_config_plugin = user_data_plugins.get('text/cloud-config')
|
||||
ret_val = cloud_config_plugin.process(user_data)
|
||||
ret_val = cloud_config_plugin.process_non_multipart(user_data)
|
||||
else:
|
||||
ret_val = userdatautils.execute_user_data_script(user_data)
|
||||
|
||||
|
@ -98,10 +98,15 @@ class CloudConfigPlugin(base.BaseUserDataPlugin):
|
||||
def __init__(self):
|
||||
super(CloudConfigPlugin, self).__init__("text/cloud-config")
|
||||
|
||||
def process(self, part):
|
||||
def process_non_multipart(self, part):
|
||||
"""Process the given data, if it can be loaded through yaml."""
|
||||
try:
|
||||
executor = CloudConfigPluginExecutor.from_yaml(part)
|
||||
except CloudConfigError:
|
||||
LOG.error("Could not process the type %r", type(part))
|
||||
else:
|
||||
executor.execute()
|
||||
|
||||
def process(self, part):
|
||||
payload = part.get_payload()
|
||||
self.process_non_multipart(payload)
|
||||
|
@ -12,20 +12,34 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import pkgutil
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
try:
|
||||
import unittest.mock as mock
|
||||
except ImportError:
|
||||
import mock
|
||||
from oslo.config import cfg
|
||||
|
||||
from cloudbaseinit.metadata.services import base as metadata_services_base
|
||||
from cloudbaseinit.plugins import base
|
||||
from cloudbaseinit.plugins.windows import userdata
|
||||
from cloudbaseinit.tests.metadata import fake_json_response
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
class FakeService(object):
|
||||
def __init__(self, user_data):
|
||||
self.user_data = user_data
|
||||
|
||||
def get_user_data(self):
|
||||
return self.user_data.encode()
|
||||
|
||||
|
||||
def _create_tempfile():
|
||||
fd, tmp = tempfile.mkstemp()
|
||||
os.close(fd)
|
||||
return tmp
|
||||
|
||||
|
||||
class UserDataPluginTest(unittest.TestCase):
|
||||
@ -281,5 +295,26 @@ class UserDataPluginTest(unittest.TestCase):
|
||||
user_data=user_data)
|
||||
|
||||
mock_load_plugins.assert_called_once_with()
|
||||
mock_cloud_config_plugin.process.assert_called_once_with(user_data)
|
||||
(mock_cloud_config_plugin
|
||||
.process_non_multipart
|
||||
.assert_called_once_with(user_data))
|
||||
self.assertEqual(mock_return_value, return_value)
|
||||
|
||||
|
||||
class TestCloudConfig(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.plugin = userdata.UserDataPlugin()
|
||||
cls.userdata = pkgutil.get_data('cloudbaseinit.tests.resources',
|
||||
'cloud_config_userdata').decode()
|
||||
|
||||
def test_cloud_config_multipart(self):
|
||||
tmp = _create_tempfile()
|
||||
self.addCleanup(os.remove, tmp)
|
||||
|
||||
service = FakeService(self.userdata.format(b64=tmp))
|
||||
self.plugin.execute(service, {})
|
||||
self.assertTrue(os.path.exists(tmp))
|
||||
|
||||
with open(tmp) as stream:
|
||||
self.assertEqual('42', stream.read())
|
||||
|
@ -90,7 +90,7 @@ class WriteFilesPluginTests(unittest.TestCase):
|
||||
""".format(tmp))
|
||||
with testutils.LogSnatcher('cloudbaseinit.plugins.windows.'
|
||||
'userdataplugins.cloudconfig') as snatcher:
|
||||
self.plugin.process(code)
|
||||
self.plugin.process_non_multipart(code)
|
||||
|
||||
self.assertTrue(os.path.exists(tmp),
|
||||
"Expected path does not exist.")
|
||||
@ -121,7 +121,7 @@ class WriteFilesPluginTests(unittest.TestCase):
|
||||
with testutils.LogSnatcher('cloudbaseinit.plugins.windows.'
|
||||
'userdataplugins.cloudconfigplugins.'
|
||||
'write_files') as snatcher:
|
||||
self.plugin.process(code)
|
||||
self.plugin.process_non_multipart(code)
|
||||
|
||||
self.assertEqual(expected_return, snatcher.output)
|
||||
|
||||
@ -137,7 +137,7 @@ class WriteFilesPluginTests(unittest.TestCase):
|
||||
|
||||
with testutils.LogSnatcher('cloudbaseinit.plugins.windows.'
|
||||
'userdataplugins.cloudconfig') as snatcher:
|
||||
self.plugin.process(code)
|
||||
self.plugin.process_non_multipart(code)
|
||||
|
||||
self.assertTrue(snatcher.output[0].startswith(
|
||||
"Processing plugin write_files failed"))
|
||||
|
@ -64,7 +64,7 @@ class CloudConfigPluginTests(unittest.TestCase):
|
||||
def test_invalid_type(self):
|
||||
with testutils.LogSnatcher('cloudbaseinit.plugins.windows.'
|
||||
'userdataplugins.cloudconfig') as snatcher:
|
||||
self.plugin.process({'unsupported'})
|
||||
self.plugin.process_non_multipart({'unsupported'})
|
||||
|
||||
expected = ["Invalid yaml stream provided.",
|
||||
"Could not process the type %r" % set]
|
||||
|
0
cloudbaseinit/tests/resources/__init__.py
Normal file
0
cloudbaseinit/tests/resources/__init__.py
Normal file
14
cloudbaseinit/tests/resources/cloud_config_userdata
Normal file
14
cloudbaseinit/tests/resources/cloud_config_userdata
Normal file
@ -0,0 +1,14 @@
|
||||
Content-Type: multipart/mixed; boundary="===============1598784645116016685=="
|
||||
MIME-Version: 1.0
|
||||
|
||||
--===============1598784645116016685==
|
||||
Content-Type: text/cloud-config; charset="us-ascii"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Content-Disposition: attachment; filename="cloud-config"
|
||||
|
||||
write_files:
|
||||
- encoding: b64
|
||||
content: NDI=
|
||||
path: {b64}
|
||||
permissions: '0644'
|
Loading…
x
Reference in New Issue
Block a user