Skip to content

Commit d07ae42

Browse files
Jenkinsopenstack-gerrit
authored andcommitted
Merge "Close files on image create"
2 parents d140d89 + ca783f4 commit d07ae42

2 files changed

Lines changed: 42 additions & 28 deletions

File tree

‎openstackclient/image/v1/image.py‎

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
"""Image V1 Action Implementations"""
1717

18+
import io
1819
import logging
1920
import os
2021
import six
@@ -214,40 +215,46 @@ def take_action(self, parsed_args):
214215
elif parsed_args.file:
215216
# Send an open file handle to glanceclient so it will
216217
# do a chunked transfer
217-
kwargs["data"] = open(parsed_args.file, "rb")
218+
kwargs["data"] = io.open(parsed_args.file, "rb")
218219
else:
219220
# Read file from stdin
220-
kwargs["data"] = None
221221
if sys.stdin.isatty() is not True:
222222
if msvcrt:
223223
msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
224224
# Send an open file handle to glanceclient so it will
225225
# do a chunked transfer
226226
kwargs["data"] = sys.stdin
227227

228+
# Wrap the call to catch exceptions in order to close files
228229
try:
229-
image = utils.find_resource(
230-
image_client.images,
231-
parsed_args.name,
232-
)
233-
234-
# Preserve previous properties if any are being set now
235-
if image.properties:
236-
if parsed_args.properties:
237-
image.properties.update(kwargs['properties'])
238-
kwargs['properties'] = image.properties
239-
240-
except exceptions.CommandError:
241-
if not parsed_args.volume:
242-
# This is normal for a create or reserve (create w/o an image)
243-
# But skip for create from volume
244-
image = image_client.images.create(**kwargs)
245-
else:
246-
# Update an existing reservation
230+
try:
231+
image = utils.find_resource(
232+
image_client.images,
233+
parsed_args.name,
234+
)
247235

248-
# If an image is specified via --file, --location or
249-
# --copy-from let the API handle it
250-
image = image_client.images.update(image.id, **kwargs)
236+
# Preserve previous properties if any are being set now
237+
if image.properties:
238+
if parsed_args.properties:
239+
image.properties.update(kwargs['properties'])
240+
kwargs['properties'] = image.properties
241+
242+
except exceptions.CommandError:
243+
if not parsed_args.volume:
244+
# This is normal for a create or reserve (create w/o
245+
# an image), but skip for create from volume
246+
image = image_client.images.create(**kwargs)
247+
else:
248+
# Update an existing reservation
249+
250+
# If an image is specified via --file, --location or
251+
# --copy-from let the API handle it
252+
image = image_client.images.update(image.id, **kwargs)
253+
finally:
254+
# Clean up open files - make sure data isn't a string
255+
if ('data' in kwargs and hasattr(kwargs['data'], 'close') and
256+
kwargs['data'] != sys.stdin):
257+
kwargs['data'].close()
251258

252259
info = {}
253260
info.update(image._info)

‎openstackclient/tests/image/v1/test_image.py‎

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -139,14 +139,17 @@ def test_image_reserve_options(self):
139139
self.assertEqual(image_fakes.IMAGE_columns, columns)
140140
self.assertEqual(image_fakes.IMAGE_data, data)
141141

142-
@mock.patch('six.moves.builtins.open')
143-
def test_image_create_file(self, open_mock):
142+
@mock.patch('openstackclient.image.v1.image.io.open', name='Open')
143+
def test_image_create_file(self, mock_open):
144+
mock_file = mock.MagicMock(name='File')
145+
mock_open.return_value = mock_file
146+
mock_open.read.return_value = image_fakes.image_data
144147
mock_exception = {
145148
'find.side_effect': exceptions.CommandError('x'),
146149
'get.side_effect': exceptions.CommandError('x'),
147150
}
148151
self.images_mock.configure_mock(**mock_exception)
149-
open_mock.return_value = image_fakes.image_data
152+
150153
arglist = [
151154
'--file', 'filer',
152155
'--unprotected',
@@ -169,7 +172,11 @@ def test_image_create_file(self, open_mock):
169172
# DisplayCommandBase.take_action() returns two tuples
170173
columns, data = self.cmd.take_action(parsed_args)
171174

172-
open_mock.assert_called_with('filer', 'rb')
175+
# Ensure input file is opened
176+
mock_open.assert_called_with('filer', 'rb')
177+
178+
# Ensure the input file is closed
179+
mock_file.close.assert_called_with()
173180

174181
# ImageManager.get(name)
175182
self.images_mock.get.assert_called_with(image_fakes.image_name)
@@ -185,7 +192,7 @@ def test_image_create_file(self, open_mock):
185192
'Alpha': '1',
186193
'Beta': '2',
187194
},
188-
data=image_fakes.image_data,
195+
data=mock_file,
189196
)
190197

191198
# Verify update() was not called, if it was show the args

0 commit comments

Comments
 (0)