diff --git a/shade/_tasks.py b/shade/_tasks.py index 6f72bdd2a..1c4d3c005 100644 --- a/shade/_tasks.py +++ b/shade/_tasks.py @@ -472,6 +472,11 @@ class ObjectMetadata(task_manager.Task): return client.swift_client.head_object(**self.args) +class ObjectGet(task_manager.Task): + def main(self, client): + return client.swift_client.get_object(**self.args) + + class SubnetCreate(task_manager.Task): def main(self, client): return client.neutron_client.create_subnet(**self.args) diff --git a/shade/openstackcloud.py b/shade/openstackcloud.py index 0e3b92669..23a3dacd4 100644 --- a/shade/openstackcloud.py +++ b/shade/openstackcloud.py @@ -3751,6 +3751,31 @@ class OpenStackCloud(object): "Object metadata fetch failed: %s (%s/%s)" % ( e.http_reason, e.http_host, e.http_path)) + def get_object(self, container, obj, query_string=None, + resp_chunk_size=None): + """Get the headers and body of an object from swift + + :param string container: name of the container. + :param string obj: name of the object. + :param string query_string: query args for uri. + (delimiter, prefix, etc.) + :param int resp_chunk_size: chunk size of data to read. + + :returns: Tuple (headers, body) of the object, or None if the object + is not found (404) + :raises: OpenStackCloudException on operation error. + """ + try: + return self.manager.submitTask(_tasks.ObjectGet( + container=container, obj=obj, query_string=query_string, + resp_chunk_size=resp_chunk_size)) + except swift_exceptions.ClientException as e: + if e.http_status == 404: + return None + raise OpenStackCloudException( + "Object fetch failed: %s (%s/%s)" % ( + e.http_reason, e.http_host, e.http_path)) + def create_subnet(self, network_name_or_id, cidr, ip_version=4, enable_dhcp=False, subnet_name=None, tenant_id=None, allocation_pools=None, diff --git a/shade/task_manager.py b/shade/task_manager.py index 4bcc85d05..e949e0f6f 100644 --- a/shade/task_manager.py +++ b/shade/task_manager.py @@ -82,7 +82,7 @@ class Task(object): if type(self._result) == list: return meta.obj_list_to_dict(self._result) elif type(self._result) not in (bool, int, float, str, set, - types.GeneratorType): + tuple, types.GeneratorType): return meta.obj_to_dict(self._result) else: return self._result diff --git a/shade/tests/functional/test_object.py b/shade/tests/functional/test_object.py index e2818238e..6413f46fd 100644 --- a/shade/tests/functional/test_object.py +++ b/shade/tests/functional/test_object.py @@ -64,6 +64,8 @@ class TestObject(base.TestCase): ) self.assertIsNotNone( self.cloud.get_object_metadata(container_name, name)) + self.assertIsNotNone( + self.cloud.get_object(container_name, name)) self.assertEqual( name, self.cloud.list_objects(container_name)[0]['name']) diff --git a/shade/tests/unit/test_object.py b/shade/tests/unit/test_object.py index b27edb32e..2132ad1a7 100644 --- a/shade/tests/unit/test_object.py +++ b/shade/tests/unit/test_object.py @@ -322,3 +322,32 @@ class TestObject(base.TestCase): self.assertRaises(shade.OpenStackCloudException, self.cloud.delete_object, container_name, object_name) + + @mock.patch.object(shade.OpenStackCloud, 'swift_client') + def test_get_object(self, mock_swift): + fake_resp = ({'headers': 'yup'}, 'test body') + mock_swift.get_object.return_value = fake_resp + container_name = 'container_name' + object_name = 'object_name' + resp = self.cloud.get_object(container_name, object_name) + self.assertEqual(fake_resp, resp) + + @mock.patch.object(shade.OpenStackCloud, 'swift_client') + def test_get_object_not_found(self, mock_swift): + mock_swift.get_object.side_effect = swift_exc.ClientException( + 'ERROR', http_status=404) + container_name = 'container_name' + object_name = 'object_name' + self.assertIsNone(self.cloud.get_object(container_name, object_name)) + mock_swift.get_object.assert_called_once_with( + container=container_name, obj=object_name, + query_string=None, resp_chunk_size=None) + + @mock.patch.object(shade.OpenStackCloud, 'swift_client') + def test_get_object_exception(self, mock_swift): + mock_swift.get_object.side_effect = swift_exc.ClientException("ERROR") + container_name = 'container_name' + object_name = 'object_name' + self.assertRaises(shade.OpenStackCloudException, + self.cloud.get_object, + container_name, object_name)