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:
Claudiu Popa 2014-12-28 16:59:10 +02:00
parent b957aadc47
commit c4297a029f
7 changed files with 63 additions and 9 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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())

View File

@ -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"))

View File

@ -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]

View 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'