Move parse_data to utils.serialization

Move and rename VMwareGuestInfoService._parse_data to
cloudbaseinit.utils.serialization.parse_json_yaml so that it can be
easiliy reused.

Change-Id: I3b86efd5e2b2062f89ffc7745f6f0481ec665078
This commit is contained in:
Adrian Vladu 2020-04-03 19:06:03 +03:00
parent 3e5b5f37ff
commit fcb68a4dc7
4 changed files with 91 additions and 47 deletions

View File

@ -16,9 +16,7 @@
import base64
import gzip
import io
import json
import os
import yaml
from oslo_log import log as oslo_logging
@ -26,16 +24,12 @@ from cloudbaseinit import conf as cloudbaseinit_conf
from cloudbaseinit import exception
from cloudbaseinit.metadata.services import base
from cloudbaseinit.osutils import factory as osutils_factory
from cloudbaseinit.utils import serialization
CONF = cloudbaseinit_conf.CONF
LOG = oslo_logging.getLogger(__name__)
class YamlParserConfigError(Exception):
"""Exception for Yaml parsing failures"""
pass
class VMwareGuestInfoService(base.BaseMetadataService):
def __init__(self):
super(VMwareGuestInfoService, self).__init__()
@ -44,19 +38,6 @@ class VMwareGuestInfoService(base.BaseMetadataService):
self._meta_data = {}
self._user_data = None
@staticmethod
def _parse_data(raw_data):
"""Parse data as json. Fallback to yaml if json parsing fails"""
try:
return json.loads(raw_data)
except (TypeError, ValueError, AttributeError):
loader = getattr(yaml, 'CLoader', yaml.Loader)
try:
return yaml.load(raw_data, Loader=loader)
except (TypeError, ValueError, AttributeError):
raise YamlParserConfigError("Invalid yaml data provided.")
@staticmethod
def _decode_data(raw_data, is_base64, is_gzip):
"""Decode raw_data from base64 / ungzip"""
@ -133,7 +114,8 @@ class VMwareGuestInfoService(base.BaseMetadataService):
% self._rpc_tool_path)
return False
self._meta_data = self._parse_data(self._get_guest_data('metadata'))
self._meta_data = serialization.parse_json_yaml(
self._get_guest_data('metadata'))
if not isinstance(self._meta_data, dict):
LOG.warning("Instance metadata is not a dictionary.")
self._meta_data = {}

View File

@ -16,7 +16,6 @@ import importlib
import unittest
import ddt
import yaml
try:
import unittest.mock as mock
@ -46,30 +45,6 @@ class VMwareGuestInfoServiceTest(unittest.TestCase):
self._service = (self._module.VMwareGuestInfoService())
self.snatcher = testutils.LogSnatcher(BASE_MODULE_PATH)
@ddt.data((b'', (None, False)),
(b'{}', ({}, False)),
(b'---', (None, True)),
(b'test: test', ({"test": "test"}, True)))
@ddt.unpack
@mock.patch("json.loads")
@mock.patch("yaml.load")
def test_parse_data(self, stream, expected_parsed_output,
mock_yaml_load, mock_json_loads):
if not expected_parsed_output[1]:
mock_json_loads.return_value = expected_parsed_output[0]
else:
mock_json_loads.side_effect = TypeError("Failed to parse json")
mock_yaml_load.return_value = expected_parsed_output[0]
parsed_output = self._service._parse_data(stream)
mock_json_loads.assert_called_once_with(stream)
if expected_parsed_output[1]:
loader = getattr(yaml, 'CLoader', yaml.Loader)
mock_yaml_load.assert_called_once_with(stream, Loader=loader)
self.assertEqual(parsed_output, expected_parsed_output[0])
@ddt.data(((None, False, False), None),
(('', False, False), None),
(('dGVzdCANCg==', True, False), b'test \r\n'),
@ -111,7 +86,7 @@ class VMwareGuestInfoServiceTest(unittest.TestCase):
self._test_load_no_rpc_tool(expected_output, 'fake_path')
@mock.patch('os.path.exists')
@mock.patch(MODULE_PATH + "._parse_data")
@mock.patch('cloudbaseinit.utils.serialization.parse_json_yaml')
@mock.patch(MODULE_PATH + "._get_guest_data")
def _test_load_meta_data(self, mock_get_guestinfo, mock_parse,
mock_os_path_exists, parse_return=None,

View File

@ -0,0 +1,53 @@
# Copyright 2014 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 unittest
import ddt
import yaml
try:
import unittest.mock as mock
except ImportError:
import mock
from cloudbaseinit.utils import serialization
@ddt.ddt
class SerializationUtilsTests(unittest.TestCase):
@ddt.data((b'', (None, False)),
(b'{}', ({}, False)),
(b'---', (None, True)),
(b'test: test', ({"test": "test"}, True)))
@ddt.unpack
@mock.patch("json.loads")
@mock.patch("yaml.load")
def test_parse_data(self, stream, expected_parsed_output,
mock_yaml_load, mock_json_loads):
if not expected_parsed_output[1]:
mock_json_loads.return_value = expected_parsed_output[0]
else:
mock_json_loads.side_effect = TypeError("Failed to parse json")
mock_yaml_load.return_value = expected_parsed_output[0]
parsed_output = serialization.parse_json_yaml(stream)
mock_json_loads.assert_called_once_with(stream)
if expected_parsed_output[1]:
loader = getattr(yaml, 'CLoader', yaml.Loader)
mock_yaml_load.assert_called_once_with(stream, Loader=loader)
self.assertEqual(parsed_output, expected_parsed_output[0])

View File

@ -0,0 +1,34 @@
# Copyright 2020 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 json
import yaml
class YamlParserConfigError(Exception):
"""Exception for Yaml parsing failures"""
pass
def parse_json_yaml(raw_data):
"""Parse data as json. Fallback to yaml if json parsing fails"""
try:
return json.loads(raw_data)
except (TypeError, ValueError, AttributeError):
loader = getattr(yaml, 'CLoader', yaml.Loader)
try:
return yaml.load(raw_data, Loader=loader)
except (TypeError, ValueError, AttributeError):
raise YamlParserConfigError("Invalid yaml data provided.")