Merge "Fix useless api_version of Manager class"

This commit is contained in:
Jenkins
2016-08-24 10:03:24 +00:00
committed by Gerrit Code Review
7 changed files with 142 additions and 19 deletions

View File

@@ -26,7 +26,6 @@ import os
import six import six
from six.moves.urllib import parse from six.moves.urllib import parse
from cinderclient import api_versions
from cinderclient import exceptions from cinderclient import exceptions
from cinderclient.openstack.common.apiclient import base as common_base from cinderclient.openstack.common.apiclient import base as common_base
from cinderclient import utils from cinderclient import utils
@@ -63,12 +62,11 @@ class Manager(common_base.HookableMixin):
resource_class = None resource_class = None
def __init__(self, api): def __init__(self, api):
self._api_version = api_versions.APIVersion()
self.api = api self.api = api
@property @property
def api_version(self): def api_version(self):
return self._api_version return self.api.api_version
def _list(self, url, response_key, obj_class=None, body=None, def _list(self, url, response_key, obj_class=None, body=None,
limit=None, items=None): limit=None, items=None):

View File

@@ -18,7 +18,9 @@ import mock
from cinderclient import api_versions from cinderclient import api_versions
from cinderclient import exceptions from cinderclient import exceptions
from cinderclient.v3 import client
from cinderclient.tests.unit import utils from cinderclient.tests.unit import utils
from cinderclient.tests.unit import test_utils
@ddt.ddt @ddt.ddt
@@ -93,6 +95,37 @@ class APIVersionTestCase(utils.TestCase):
api_versions.APIVersion().get_string) api_versions.APIVersion().get_string)
class ManagerTest(utils.TestCase):
def test_api_version(self):
# The function manager.return_api_version has two versions,
# when called with api version 3.1 it should return the
# string '3.1' and when called with api version 3.2 or higher
# it should return the string '3.2'.
version = api_versions.APIVersion('3.1')
api = client.Client(api_version=version)
manager = test_utils.FakeManagerWithApi(api)
self.assertEqual('3.1', manager.return_api_version())
version = api_versions.APIVersion('3.2')
api = client.Client(api_version=version)
manager = test_utils.FakeManagerWithApi(api)
self.assertEqual('3.2', manager.return_api_version())
# pick up the highest version
version = api_versions.APIVersion('3.3')
api = client.Client(api_version=version)
manager = test_utils.FakeManagerWithApi(api)
self.assertEqual('3.2', manager.return_api_version())
version = api_versions.APIVersion('3.0')
api = client.Client(api_version=version)
manager = test_utils.FakeManagerWithApi(api)
# An exception will be returned here because the function
# return_api_version doesn't support version 3.0
self.assertRaises(exceptions.VersionNotFoundForAPIMethod,
manager.return_api_version)
class UpdateHeadersTestCase(utils.TestCase): class UpdateHeadersTestCase(utils.TestCase):
def test_api_version_is_null(self): def test_api_version_is_null(self):
headers = {} headers = {}

View File

@@ -17,6 +17,7 @@ import sys
import mock import mock
from six import moves from six import moves
from cinderclient import api_versions
from cinderclient import exceptions from cinderclient import exceptions
from cinderclient import utils from cinderclient import utils
from cinderclient import base from cinderclient import base
@@ -61,6 +62,17 @@ class FakeManager(base.ManagerWithFind):
return common_base.ListWithMeta(self.resources, fakes.REQUEST_ID) return common_base.ListWithMeta(self.resources, fakes.REQUEST_ID)
class FakeManagerWithApi(base.Manager):
@api_versions.wraps('3.1')
def return_api_version(self):
return '3.1'
@api_versions.wraps('3.2')
def return_api_version(self):
return '3.2'
class FakeDisplayResource(object): class FakeDisplayResource(object):
NAME_ATTR = 'display_name' NAME_ATTR = 'display_name'

View File

@@ -71,13 +71,24 @@ class ShellTest(utils.TestCase):
self.assert_called('GET', '/os-availability-zone') self.assert_called('GET', '/os-availability-zone')
def test_upload_to_image(self): def test_upload_to_image(self):
expected = {'os-volume_upload_image': {'force': False,
'container_format': 'bare',
'disk_format': 'raw',
'image_name': 'test-image'}}
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_private_not_protected(self):
expected = {'os-volume_upload_image': {'force': False, expected = {'os-volume_upload_image': {'force': False,
'container_format': 'bare', 'container_format': 'bare',
'disk_format': 'raw', 'disk_format': 'raw',
'image_name': 'test-image', 'image_name': 'test-image',
'protected': False, 'protected': False,
'visibility': 'private'}} 'visibility': 'private'}}
self.run_command('upload-to-image 1234 test-image') self.run_command('--os-volume-api-version 3.1 '
'upload-to-image 1234 test-image')
self.assert_called_anytime('GET', '/volumes/1234') self.assert_called_anytime('GET', '/volumes/1234')
self.assert_called_anytime('POST', '/volumes/1234/action', self.assert_called_anytime('POST', '/volumes/1234/action',
body=expected) body=expected)
@@ -89,7 +100,8 @@ class ShellTest(utils.TestCase):
'image_name': 'test-image', 'image_name': 'test-image',
'protected': 'True', 'protected': 'True',
'visibility': 'public'}} 'visibility': 'public'}}
self.run_command('upload-to-image --visibility=public ' self.run_command('--os-volume-api-version 3.1 '
'upload-to-image --visibility=public '
'--protected=True 1234 test-image') '--protected=True 1234 test-image')
self.assert_called_anytime('GET', '/volumes/1234') self.assert_called_anytime('GET', '/volumes/1234')
self.assert_called_anytime('POST', '/volumes/1234/action', self.assert_called_anytime('POST', '/volumes/1234/action',

View File

@@ -0,0 +1,42 @@
# Copyright 2016 FUJITSU LIMITED
#
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from cinderclient import api_versions
from cinderclient.tests.unit import utils
from cinderclient.tests.unit.v3 import fakes
from cinderclient.v3.volumes import Volume
from cinderclient.v3.volumes import VolumeManager
class VolumesTest(utils.TestCase):
def test_volume_manager_upload_to_image(self):
expected = {'os-volume_upload_image':
{'force': False,
'container_format': 'bare',
'disk_format': 'raw',
'image_name': 'name',
'visibility': 'public',
'protected': True}}
api_version = api_versions.APIVersion('3.1')
cs = fakes.FakeClient(api_version)
manager = VolumeManager(cs)
fake_volume = Volume(manager, {'id': 1234,
'name': 'sample-volume'},
loaded=True)
fake_volume.upload_to_image(False, 'name', 'bare', 'raw',
visibility='public', protected=True)
cs.assert_called_anytime('POST', '/volumes/1234/action', body=expected)

View File

@@ -1424,22 +1424,31 @@ def _find_group_type(cs, gtype):
help=argparse.SUPPRESS) help=argparse.SUPPRESS)
@utils.arg('--visibility', @utils.arg('--visibility',
metavar='<public|private>', metavar='<public|private>',
help='Makes image publicly accessible. Default=private.', help='Set image visibility to either public or private. '
default='private') 'Default=private.',
default='private',
start_version='3.1')
@utils.arg('--protected', @utils.arg('--protected',
metavar='<True|False>', metavar='<True|False>',
help='Prevents image from being deleted. Default=False.', help='Prevents image from being deleted. Default=False.',
default=False) default=False,
start_version='3.1')
@utils.service_type('volumev3') @utils.service_type('volumev3')
def do_upload_to_image(cs, args): def do_upload_to_image(cs, args):
"""Uploads volume to Image Service as an image.""" """Uploads volume to Image Service as an image."""
volume = utils.find_volume(cs, args.volume) volume = utils.find_volume(cs, args.volume)
if cs.api_version >= api_versions.APIVersion("3.1"):
_print_volume_image(volume.upload_to_image(args.force, _print_volume_image(volume.upload_to_image(args.force,
args.image_name, args.image_name,
args.container_format, args.container_format,
args.disk_format, args.disk_format,
args.visibility, args.visibility,
args.protected)) args.protected))
else:
_print_volume_image(volume.upload_to_image(args.force,
args.image_name,
args.container_format,
args.disk_format))
@utils.arg('volume', metavar='<volume>', help='ID of volume to migrate.') @utils.arg('volume', metavar='<volume>', help='ID of volume to migrate.')

View File

@@ -111,11 +111,28 @@ class Volume(base.Resource):
return self.manager.show_image_metadata(self) return self.manager.show_image_metadata(self)
def upload_to_image(self, force, image_name, container_format, def upload_to_image(self, force, image_name, container_format,
disk_format, visibility, protected): disk_format, visibility=None,
"""Upload a volume to image service as an image.""" protected=None):
"""Upload a volume to image service as an image.
:param force: Boolean to enables or disables upload of a volume that
is attached to an instance.
:param image_name: The new image name.
:param container_format: Container format type.
:param disk_format: Disk format type.
:param visibility: The accessibility of image (allowed for
3.1-latest).
:param protected: Boolean to decide whether prevents image from being
deleted (allowed for 3.1-latest).
"""
if self.manager.api_version >= api_versions.APIVersion("3.1"):
visibility = 'private' if visibility is None else visibility
protected = False if protected is None else protected
return self.manager.upload_to_image(self, force, image_name, return self.manager.upload_to_image(self, force, image_name,
container_format, disk_format, container_format, disk_format,
visibility, protected) visibility, protected)
else:
return self.manager.upload_to_image(self, force, image_name,
container_format, disk_format)
def force_delete(self): def force_delete(self):
"""Delete the specified volume ignoring its current state. """Delete the specified volume ignoring its current state.