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'):
|
if user_data.startswith(b'#cloud-config'):
|
||||||
user_data_plugins = factory.load_plugins()
|
user_data_plugins = factory.load_plugins()
|
||||||
cloud_config_plugin = user_data_plugins.get('text/cloud-config')
|
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:
|
else:
|
||||||
ret_val = userdatautils.execute_user_data_script(user_data)
|
ret_val = userdatautils.execute_user_data_script(user_data)
|
||||||
|
|
||||||
|
@ -98,10 +98,15 @@ class CloudConfigPlugin(base.BaseUserDataPlugin):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(CloudConfigPlugin, self).__init__("text/cloud-config")
|
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:
|
try:
|
||||||
executor = CloudConfigPluginExecutor.from_yaml(part)
|
executor = CloudConfigPluginExecutor.from_yaml(part)
|
||||||
except CloudConfigError:
|
except CloudConfigError:
|
||||||
LOG.error("Could not process the type %r", type(part))
|
LOG.error("Could not process the type %r", type(part))
|
||||||
else:
|
else:
|
||||||
executor.execute()
|
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
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import pkgutil
|
||||||
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import unittest.mock as mock
|
import unittest.mock as mock
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import mock
|
import mock
|
||||||
from oslo.config import cfg
|
|
||||||
|
|
||||||
from cloudbaseinit.metadata.services import base as metadata_services_base
|
from cloudbaseinit.metadata.services import base as metadata_services_base
|
||||||
from cloudbaseinit.plugins import base
|
from cloudbaseinit.plugins import base
|
||||||
from cloudbaseinit.plugins.windows import userdata
|
from cloudbaseinit.plugins.windows import userdata
|
||||||
from cloudbaseinit.tests.metadata import fake_json_response
|
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):
|
class UserDataPluginTest(unittest.TestCase):
|
||||||
@ -281,5 +295,26 @@ class UserDataPluginTest(unittest.TestCase):
|
|||||||
user_data=user_data)
|
user_data=user_data)
|
||||||
|
|
||||||
mock_load_plugins.assert_called_once_with()
|
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)
|
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))
|
""".format(tmp))
|
||||||
with testutils.LogSnatcher('cloudbaseinit.plugins.windows.'
|
with testutils.LogSnatcher('cloudbaseinit.plugins.windows.'
|
||||||
'userdataplugins.cloudconfig') as snatcher:
|
'userdataplugins.cloudconfig') as snatcher:
|
||||||
self.plugin.process(code)
|
self.plugin.process_non_multipart(code)
|
||||||
|
|
||||||
self.assertTrue(os.path.exists(tmp),
|
self.assertTrue(os.path.exists(tmp),
|
||||||
"Expected path does not exist.")
|
"Expected path does not exist.")
|
||||||
@ -121,7 +121,7 @@ class WriteFilesPluginTests(unittest.TestCase):
|
|||||||
with testutils.LogSnatcher('cloudbaseinit.plugins.windows.'
|
with testutils.LogSnatcher('cloudbaseinit.plugins.windows.'
|
||||||
'userdataplugins.cloudconfigplugins.'
|
'userdataplugins.cloudconfigplugins.'
|
||||||
'write_files') as snatcher:
|
'write_files') as snatcher:
|
||||||
self.plugin.process(code)
|
self.plugin.process_non_multipart(code)
|
||||||
|
|
||||||
self.assertEqual(expected_return, snatcher.output)
|
self.assertEqual(expected_return, snatcher.output)
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ class WriteFilesPluginTests(unittest.TestCase):
|
|||||||
|
|
||||||
with testutils.LogSnatcher('cloudbaseinit.plugins.windows.'
|
with testutils.LogSnatcher('cloudbaseinit.plugins.windows.'
|
||||||
'userdataplugins.cloudconfig') as snatcher:
|
'userdataplugins.cloudconfig') as snatcher:
|
||||||
self.plugin.process(code)
|
self.plugin.process_non_multipart(code)
|
||||||
|
|
||||||
self.assertTrue(snatcher.output[0].startswith(
|
self.assertTrue(snatcher.output[0].startswith(
|
||||||
"Processing plugin write_files failed"))
|
"Processing plugin write_files failed"))
|
||||||
|
@ -64,7 +64,7 @@ class CloudConfigPluginTests(unittest.TestCase):
|
|||||||
def test_invalid_type(self):
|
def test_invalid_type(self):
|
||||||
with testutils.LogSnatcher('cloudbaseinit.plugins.windows.'
|
with testutils.LogSnatcher('cloudbaseinit.plugins.windows.'
|
||||||
'userdataplugins.cloudconfig') as snatcher:
|
'userdataplugins.cloudconfig') as snatcher:
|
||||||
self.plugin.process({'unsupported'})
|
self.plugin.process_non_multipart({'unsupported'})
|
||||||
|
|
||||||
expected = ["Invalid yaml stream provided.",
|
expected = ["Invalid yaml stream provided.",
|
||||||
"Could not process the type %r" % set]
|
"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