Fix problem where image data is not read from a pipe.

For image-updae and image-create commands, glanceclient attempts to
determine whether image data should be uploaded based on the presence
of data on stdin. Unforunately it is difficult to determine if data is
available, especially when standard in is from a pipe.

This is especially problematic for update operations, where data must
only be uploaded if the image is in queued state. For example data may
be uploaded when the user only wants to rename an image, but the rename
will be rejected because data cannot be uploaded to an unqueued image.

This patch removes the check that attempts to determine if data is
available to read as it didn't work for pipes. It also re-introduces a
check for image state in the update operation, so that glanceclient only
attempts to read data if the image being updated is in queued state.

The image state check is part of the original patchset that was removed
so the patchset could have a single focus [1]

This patch also removes a test for handling empty stdin, and adds a test
for reading stdin from a pipe.

[1] https://review.openstack.org/#/c/27536/3/glanceclient/v1/shell.py

Fixes: bug 1184566
Related to: bug 1173044

Change-Id: I8d37f6412a0bf9ca21cbd75cde6a4d5a174e5545
This commit is contained in:
Hugh Saunders
2013-06-03 15:24:51 +01:00
parent 7d48783434
commit 9fda0dc815
2 changed files with 33 additions and 20 deletions
+4 -3
View File
@@ -121,12 +121,12 @@ def _set_data_field(fields, args):
# (3) no image data provided:
# glance ...
try:
stat_result = os.fstat(0)
os.fstat(0)
except OSError:
# (1) stdin is not valid (closed...)
fields['data'] = None
return
if not sys.stdin.isatty() and stat_result.st_size != 0:
if not sys.stdin.isatty():
# (2) image data is provided through standard input
if msvcrt:
msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
@@ -294,7 +294,8 @@ def do_image_update(gc, args):
UPDATE_PARAMS = glanceclient.v1.images.UPDATE_PARAMS
fields = dict(filter(lambda x: x[0] in UPDATE_PARAMS, fields.items()))
_set_data_field(fields, args)
if image.status == 'queued':
_set_data_field(fields, args)
image = gc.images.update(image, purge_props=args.purge_props, **fields)
_image_show(image, args.human_readable)
+29 -17
View File
@@ -18,6 +18,7 @@
import argparse
import json
import os
import subprocess
import tempfile
import testtools
@@ -385,23 +386,8 @@ class ShellStdinHandlingTests(testtools.TestCase):
or self.collected_args[1]['data'] is None
)
def test_image_update_empty_stdin(self):
"""Supply glanceclient with an open but empty stdin, and perform an
image update to an active image. Glanceclient should not attempt to
read stdin.
"""
self._do_update()
self.assertTrue(
'data' not in self.collected_args[1]
or self.collected_args[1]['data'] is None
)
def test_image_update_data_is_read(self):
"""Ensure that data is read from stdin when image is in queued
status and data is available.
"""
def test_image_update_data_is_read_from_file(self):
"""Ensure that data is read from a file."""
try:
@@ -417,6 +403,8 @@ class ShellStdinHandlingTests(testtools.TestCase):
self.assertTrue('data' in self.collected_args[1])
self.assertIsInstance(self.collected_args[1]['data'], file)
self.assertEqual(self.collected_args[1]['data'].read(),
'Some Data')
finally:
try:
@@ -424,3 +412,27 @@ class ShellStdinHandlingTests(testtools.TestCase):
os.remove(f.name)
except:
pass
def test_image_update_data_is_read_from_pipe(self):
"""Ensure that data is read from a pipe."""
try:
# NOTE(hughsaunders): Setup a pipe, duplicate it to stdin
# ensure it is read.
process = subprocess.Popen(['/bin/echo', 'Some Data'],
stdout=subprocess.PIPE)
os.dup2(process.stdout.fileno(), 0)
self._do_update('44d2c7e1-de4e-4612-8aa2-ba26610c444f')
self.assertTrue('data' in self.collected_args[1])
self.assertIsInstance(self.collected_args[1]['data'], file)
self.assertEqual(self.collected_args[1]['data'].read(),
'Some Data\n')
finally:
try:
process.stdout.close()
except:
pass