summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathaniel Potter <nathaniel.potter@intel.com>2015-10-02 14:37:28 -0500
committerNate Potter <nathaniel.potter@intel.com>2016-04-21 17:51:43 +0000
commit7590fe4b7d8a0b75b3257f6676c773052c8019c0 (patch)
tree4469c43b3a13fb4305943a3a65886d4b8ae5d6b8
parent8d79acda0f5ff0e33ece7c84e65f5168b9b465bf (diff)
downloadpython-cinderclient-7590fe4b7d8a0b75b3257f6676c773052c8019c0.tar.gz
Add options when uploading images to Glance
Added --visibility and --protected options when uploading volumes to the image service. DocImpact Change-Id: Ie639179c5bbbaca4de62b42b368830afcfd8f7ac Closes-Bug: #1288131 Depends-On: I6e6b2276af22b7809ea88289427c6873211b3faf Signed-off-by: Nathaniel Potter <nathaniel.potter@intel.com>
-rw-r--r--cinderclient/api_versions.py2
-rw-r--r--cinderclient/tests/unit/v2/fakes.py3
-rw-r--r--cinderclient/tests/unit/v2/test_shell.py37
-rw-r--r--cinderclient/v3/shell.py12
-rw-r--r--cinderclient/v3/volumes.py25
5 files changed, 74 insertions, 5 deletions
diff --git a/cinderclient/api_versions.py b/cinderclient/api_versions.py
index 7235d00..a74f3af 100644
--- a/cinderclient/api_versions.py
+++ b/cinderclient/api_versions.py
@@ -32,7 +32,7 @@ if not LOG.handlers:
# key is a deprecated version and value is an alternative version.
DEPRECATED_VERSIONS = {"1": "2"}
-MAX_VERSION = "3.0"
+MAX_VERSION = "3.1"
_SUBSTITUTIONS = {}
diff --git a/cinderclient/tests/unit/v2/fakes.py b/cinderclient/tests/unit/v2/fakes.py
index 40c57d1..5e4ff3a 100644
--- a/cinderclient/tests/unit/v2/fakes.py
+++ b/cinderclient/tests/unit/v2/fakes.py
@@ -463,6 +463,9 @@ class FakeHTTPClient(base_client.HTTPClient):
assert 'key' in body[action]
elif action == 'os-show_image_metadata':
assert body[action] is None
+ elif action == 'os-volume_upload_image':
+ assert 'image_name' in body[action]
+ _body = body
else:
raise AssertionError("Unexpected action: %s" % action)
return (resp, {}, _body)
diff --git a/cinderclient/tests/unit/v2/test_shell.py b/cinderclient/tests/unit/v2/test_shell.py
index 156df53..07f27c1 100644
--- a/cinderclient/tests/unit/v2/test_shell.py
+++ b/cinderclient/tests/unit/v2/test_shell.py
@@ -355,6 +355,43 @@ class ShellTest(utils.TestCase):
self.assert_called_anytime('POST', '/volumes', partial_body=expected)
self.assert_called('GET', '/volumes/1234')
+ def test_upload_to_image(self):
+ expected = {'os-volume_upload_image': {'force': False,
+ 'container_format': 'bare',
+ 'disk_format': 'raw',
+ 'image_name': 'test-image',
+ 'protected': False,
+ 'visibility': 'private'}}
+ self.run_command('upload-to-image 1234 test-image')
+ self.assert_called_anytime('GET', '/volumes/1234')
+ self.assert_called_anytime('POST', '/volumes/1234/action',
+ body=expected)
+
+ def test_upload_to_image_force(self):
+ expected = {'os-volume_upload_image': {'force': 'True',
+ 'container_format': 'bare',
+ 'disk_format': 'raw',
+ 'image_name': 'test-image',
+ 'protected': False,
+ 'visibility': 'private'}}
+ self.run_command('upload-to-image --force=True 1234 test-image')
+ self.assert_called_anytime('GET', '/volumes/1234')
+ self.assert_called_anytime('POST', '/volumes/1234/action',
+ body=expected)
+
+ def test_upload_to_image_public_protected(self):
+ expected = {'os-volume_upload_image': {'force': False,
+ 'container_format': 'bare',
+ 'disk_format': 'raw',
+ 'image_name': 'test-image',
+ 'protected': 'True',
+ 'visibility': 'public'}}
+ self.run_command('upload-to-image --visibility=public '
+ '--protected=True 1234 test-image')
+ self.assert_called_anytime('GET', '/volumes/1234')
+ self.assert_called_anytime('POST', '/volumes/1234/action',
+ body=expected)
+
def test_create_size_required_if_not_snapshot_or_clone(self):
self.assertRaises(SystemExit, self.run_command, 'create')
diff --git a/cinderclient/v3/shell.py b/cinderclient/v3/shell.py
index f28dedb..7f79eff 100644
--- a/cinderclient/v3/shell.py
+++ b/cinderclient/v3/shell.py
@@ -1256,6 +1256,14 @@ def _find_volume_type(cs, vtype):
help='The new image name.')
@utils.arg('--image_name',
help=argparse.SUPPRESS)
+@utils.arg('--visibility',
+ metavar='<public|private>',
+ help='Makes image publicly accessible. Default=private.',
+ default='private')
+@utils.arg('--protected',
+ metavar='<True|False>',
+ help='Prevents image from being deleted. Default=False.',
+ default=False)
@utils.service_type('volumev3')
def do_upload_to_image(cs, args):
"""Uploads volume to Image Service as an image."""
@@ -1263,7 +1271,9 @@ def do_upload_to_image(cs, args):
_print_volume_image(volume.upload_to_image(args.force,
args.image_name,
args.container_format,
- args.disk_format))
+ args.disk_format,
+ args.visibility,
+ args.protected))
@utils.arg('volume', metavar='<volume>', help='ID of volume to migrate.')
diff --git a/cinderclient/v3/volumes.py b/cinderclient/v3/volumes.py
index f8d2432..eb9c3bc 100644
--- a/cinderclient/v3/volumes.py
+++ b/cinderclient/v3/volumes.py
@@ -15,6 +15,7 @@
"""Volume interface (v3 extension)."""
+from cinderclient import api_versions
from cinderclient import base
from cinderclient.openstack.common.apiclient import base as common_base
@@ -110,10 +111,11 @@ class Volume(base.Resource):
return self.manager.show_image_metadata(self)
def upload_to_image(self, force, image_name, container_format,
- disk_format):
+ disk_format, visibility, protected):
"""Upload a volume to image service as an image."""
return self.manager.upload_to_image(self, force, image_name,
- container_format, disk_format)
+ container_format, disk_format,
+ visibility, protected)
def force_delete(self):
"""Delete the specified volume ignoring its current state.
@@ -451,8 +453,9 @@ class VolumeManager(base.ManagerWithFind):
"""
return self._action("os-show_image_metadata", volume)
+ @api_versions.wraps("2.0", "3.0")
def upload_to_image(self, volume, force, image_name, container_format,
- disk_format):
+ disk_format, visibility, protected):
"""Upload volume to image service as image.
:param volume: The :class:`Volume` to upload.
@@ -464,6 +467,22 @@ class VolumeManager(base.ManagerWithFind):
'container_format': container_format,
'disk_format': disk_format})
+ @api_versions.wraps("3.1")
+ def upload_to_image(self, volume, force, image_name, container_format,
+ disk_format, visibility, protected):
+ """Upload volume to image service as image.
+
+ :param volume: The :class:`Volume` to upload.
+ """
+ return self._action('os-volume_upload_image',
+ volume,
+ {'force': force,
+ 'image_name': image_name,
+ 'container_format': container_format,
+ 'disk_format': disk_format,
+ 'visibility': visibility,
+ 'protected': protected})
+
def force_delete(self, volume):
"""Delete the specified volume ignoring its current state.