Merge "Add support for loading resources from archive file"
This commit is contained in:
commit
3bf894c097
@ -57,6 +57,10 @@ class InvalidParameterValueError(SushyError):
|
||||
'Valid values are: %(valid_values)s')
|
||||
|
||||
|
||||
class ArchiveParsingError(SushyError):
|
||||
message = 'Failed parsing archive "%(path)s": %(error)s'
|
||||
|
||||
|
||||
class HTTPError(SushyError):
|
||||
"""Basic exception for HTTP errors"""
|
||||
|
||||
|
@ -16,7 +16,10 @@
|
||||
import abc
|
||||
import collections
|
||||
import copy
|
||||
import io
|
||||
import json
|
||||
import logging
|
||||
import zipfile
|
||||
|
||||
import six
|
||||
|
||||
@ -244,13 +247,69 @@ class MappedField(Field):
|
||||
adapter=mapping.get)
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class AbstractJsonReader(object):
|
||||
|
||||
def set_connection(self, connector, path):
|
||||
"""Sets mandatory connection parameters
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param path: path of the resource
|
||||
"""
|
||||
self._conn = connector
|
||||
self._path = path
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_json(self):
|
||||
"""Based on data source get data and parse to JSON"""
|
||||
|
||||
|
||||
class JsonFileReader(AbstractJsonReader):
|
||||
"""Gets the data from JSON file given by path"""
|
||||
|
||||
def get_json(self):
|
||||
"""Gets JSON file from URI directly"""
|
||||
return self._conn.get(path=self._path).json()
|
||||
|
||||
|
||||
class JsonArchiveReader(AbstractJsonReader):
|
||||
"""Gets the data from JSON file in archive"""
|
||||
|
||||
def __init__(self, archive_file):
|
||||
"""Initializes the reader
|
||||
|
||||
:param archive_file: file name of JSON file in archive
|
||||
"""
|
||||
self._archive_file = archive_file
|
||||
|
||||
def get_json(self):
|
||||
"""Gets JSON file from archive. Currently supporting ZIP only"""
|
||||
|
||||
data = self._conn.get(path=self._path)
|
||||
if data.headers.get('content-type') == 'application/zip':
|
||||
try:
|
||||
archive = zipfile.ZipFile(io.BytesIO(data.content))
|
||||
return json.loads(archive.read(self._archive_file)
|
||||
.decode(encoding='utf-8'))
|
||||
except (zipfile.BadZipfile, ValueError) as e:
|
||||
raise exceptions.ArchiveParsingError(
|
||||
path=self._path, error=e)
|
||||
else:
|
||||
LOG.error('Support for %(type)s not implemented',
|
||||
{'type': data.headers['content-type']})
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class ResourceBase(object):
|
||||
|
||||
redfish_version = None
|
||||
"""The Redfish version"""
|
||||
|
||||
def __init__(self, connector, path='', redfish_version=None):
|
||||
def __init__(self,
|
||||
connector,
|
||||
path='',
|
||||
redfish_version=None,
|
||||
reader=JsonFileReader()):
|
||||
"""A class representing the base of any Redfish resource
|
||||
|
||||
Invokes the ``refresh()`` method of resource for the first
|
||||
@ -259,6 +318,8 @@ class ResourceBase(object):
|
||||
:param path: sub-URI path to the resource.
|
||||
:param redfish_version: The version of Redfish. Used to construct
|
||||
the object according to schema of the given version.
|
||||
:param reader: Reader to use to fetch JSON data. Defaults to
|
||||
JsonFileReader
|
||||
"""
|
||||
self._conn = connector
|
||||
self._path = path
|
||||
@ -269,6 +330,9 @@ class ResourceBase(object):
|
||||
# attribute values are fetched.
|
||||
self._is_stale = True
|
||||
|
||||
reader.set_connection(connector, path)
|
||||
self._reader = reader
|
||||
|
||||
self.refresh()
|
||||
|
||||
def _parse_attributes(self):
|
||||
@ -299,7 +363,8 @@ class ResourceBase(object):
|
||||
if not self._is_stale and not force:
|
||||
return
|
||||
|
||||
self._json = self._conn.get(path=self._path).json()
|
||||
self._json = self._reader.get_json()
|
||||
|
||||
LOG.debug('Received representation of %(type)s %(path)s: %(json)s',
|
||||
{'type': self.__class__.__name__,
|
||||
'path': self._path, 'json': self._json})
|
||||
|
BIN
sushy/tests/unit/json_samples/TestRegistry.zip
Normal file
BIN
sushy/tests/unit/json_samples/TestRegistry.zip
Normal file
Binary file not shown.
@ -14,13 +14,15 @@
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
|
||||
import io
|
||||
import mock
|
||||
|
||||
from six.moves import http_client
|
||||
|
||||
from sushy import exceptions
|
||||
from sushy.resources import base as resource_base
|
||||
from sushy.tests.unit import base
|
||||
import zipfile
|
||||
|
||||
|
||||
class BaseResource(resource_base.ResourceBase):
|
||||
@ -59,6 +61,47 @@ class ResourceBaseTestCase(base.TestCase):
|
||||
self.base_resource.invalidate(force_refresh=True)
|
||||
self.conn.get.assert_called_once_with(path='/Foo')
|
||||
|
||||
def test_refresh_archive(self):
|
||||
mock_response = mock.Mock(
|
||||
headers={'content-type': 'application/zip'})
|
||||
with open('sushy/tests/unit/json_samples/TestRegistry.zip', 'rb') as f:
|
||||
mock_response.content = f.read()
|
||||
self.conn.get.return_value = mock_response
|
||||
|
||||
resource = BaseResource(connector=self.conn,
|
||||
path='/Foo',
|
||||
redfish_version='1.0.2',
|
||||
reader=resource_base.
|
||||
JsonArchiveReader('Test.2.0.json'))
|
||||
|
||||
self.assertIsNotNone(resource._json)
|
||||
self.assertEqual('Test.2.0.0', resource._json['Id'])
|
||||
|
||||
@mock.patch.object(resource_base, 'LOG', autospec=True)
|
||||
def test_refresh_archive_not_implemented(self, mock_log):
|
||||
mock_response = mock.Mock(
|
||||
headers={'content-type': 'application/gzip'})
|
||||
self.conn.get.return_value = mock_response
|
||||
BaseResource(connector=self.conn,
|
||||
path='/Foo',
|
||||
redfish_version='1.0.2',
|
||||
reader=resource_base.JsonArchiveReader('Test.2.0.json'))
|
||||
mock_log.error.assert_called_once()
|
||||
|
||||
@mock.patch.object(io, 'BytesIO', autospec=True)
|
||||
def test_refresh_archive_badzip_error(self, mock_io):
|
||||
mock_response = mock.Mock(
|
||||
headers={'content-type': 'application/zip'})
|
||||
mock_io.side_effect = zipfile.BadZipfile('Something wrong')
|
||||
self.conn.get.return_value = mock_response
|
||||
|
||||
self.assertRaises(exceptions.SushyError,
|
||||
BaseResource, connector=self.conn,
|
||||
path='/Foo',
|
||||
redfish_version='1.0.2',
|
||||
reader=resource_base.
|
||||
JsonArchiveReader('Test.2.0.json'))
|
||||
|
||||
|
||||
class TestResource(resource_base.ResourceBase):
|
||||
"""A concrete Test Resource to test against"""
|
||||
|
Loading…
Reference in New Issue
Block a user