image: Migrate 'create image' volume calls to SDK

Change-Id: Ie57a5c17a6df5a333abd6b11e28b65833740e102
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
Stephen Finucane 2024-07-15 10:44:52 +01:00
parent 30aa27b7f9
commit 181bb194c7
2 changed files with 57 additions and 57 deletions

View File

@ -17,14 +17,15 @@
import argparse import argparse
from base64 import b64encode from base64 import b64encode
import copy
import logging import logging
import os import os
import sys import sys
import typing as ty import typing as ty
from cinderclient import api_versions
from openstack import exceptions as sdk_exceptions from openstack import exceptions as sdk_exceptions
from openstack.image import image_signer from openstack.image import image_signer
from openstack import utils as sdk_utils
from osc_lib.api import utils as api_utils from osc_lib.api import utils as api_utils
from osc_lib.cli import format_columns from osc_lib.cli import format_columns
from osc_lib.cli import parseractions from osc_lib.cli import parseractions
@ -576,7 +577,7 @@ class CreateImage(command.ShowOne):
return _format_image(image) return _format_image(image)
def _take_action_volume(self, parsed_args): def _take_action_volume(self, parsed_args):
volume_client = self.app.client_manager.volume volume_client = self.app.client_manager.sdk_connection.volume
unsupported_opts = { unsupported_opts = {
# 'name', # 'name' is a positional argument and will always exist # 'name', # 'name' is a positional argument and will always exist
@ -607,15 +608,14 @@ class CreateImage(command.ShowOne):
# version # version
LOG.warning(msg % opt_name) LOG.warning(msg % opt_name)
source_volume = utils.find_resource( source_volume = volume_client.find_volume(
volume_client.volumes, parsed_args.volume, ignore_missing=False
parsed_args.volume,
) )
kwargs: dict[str, ty.Any] = { kwargs: dict[str, ty.Any] = {
'visibility': None, 'visibility': None,
'protected': None, 'protected': None,
} }
if volume_client.api_version < api_versions.APIVersion('3.1'): if not sdk_utils.supports_microversion(volume_client, '3.1'):
if parsed_args.visibility or parsed_args.is_protected is not None: if parsed_args.visibility or parsed_args.is_protected is not None:
msg = _( msg = _(
'--os-volume-api-version 3.1 or greater is required ' '--os-volume-api-version 3.1 or greater is required '
@ -627,15 +627,15 @@ class CreateImage(command.ShowOne):
kwargs['visibility'] = parsed_args.visibility or 'private' kwargs['visibility'] = parsed_args.visibility or 'private'
kwargs['protected'] = parsed_args.is_protected or False kwargs['protected'] = parsed_args.is_protected or False
response, body = volume_client.volumes.upload_to_image( response = volume_client.upload_volume_to_image(
source_volume.id, source_volume.id,
parsed_args.force,
parsed_args.name, parsed_args.name,
parsed_args.container_format, force=parsed_args.force,
parsed_args.disk_format, disk_format=parsed_args.disk_format,
container_format=parsed_args.container_format,
**kwargs, **kwargs,
) )
info = body['os-volume_upload_image'] info = copy.deepcopy(response)
try: try:
info['volume_type'] = info['volume_type']['name'] info['volume_type'] = info['volume_type']['name']
except TypeError: except TypeError:

View File

@ -17,8 +17,9 @@ import io
import tempfile import tempfile
from unittest import mock from unittest import mock
from cinderclient import api_versions from openstack.block_storage.v2 import volume as _volume
from openstack import exceptions as sdk_exceptions from openstack import exceptions as sdk_exceptions
from openstack.test import fakes as sdk_fakes
from osc_lib.cli import format_columns from osc_lib.cli import format_columns
from osc_lib import exceptions from osc_lib import exceptions
@ -37,12 +38,6 @@ class TestImage(image_fakes.TestImagev2, volume_fakes.TestVolume):
self.project_mock.reset_mock() self.project_mock.reset_mock()
self.domain_mock = self.identity_client.domains self.domain_mock = self.identity_client.domains
self.domain_mock.reset_mock() self.domain_mock.reset_mock()
self.volumes_mock = self.volume_client.volumes
fake_body = {
'os-volume_upload_image': {'volume_type': {'name': 'fake_type'}}
}
self.volumes_mock.upload_to_image.return_value = (200, fake_body)
self.volumes_mock.reset_mock()
class TestImageCreate(TestImage): class TestImageCreate(TestImage):
@ -312,7 +307,6 @@ class TestImageCreate(TestImage):
columns, data = self.cmd.take_action(parsed_args) columns, data = self.cmd.take_action(parsed_args)
# ImageManager.create(name=, **)
self.image_client.create_image.assert_called_with( self.image_client.create_image.assert_called_with(
name=self.new_image.name, name=self.new_image.name,
allow_duplicates=True, allow_duplicates=True,
@ -322,20 +316,19 @@ class TestImageCreate(TestImage):
) )
self.image_client.get_image.assert_called_once_with(self.new_image) self.image_client.get_image.assert_called_once_with(self.new_image)
@mock.patch('osc_lib.utils.find_resource')
@mock.patch('openstackclient.image.v2.image.get_data_from_stdin') @mock.patch('openstackclient.image.v2.image.get_data_from_stdin')
def test_image_create_from_volume(self, mock_get_data_f, mock_get_vol): def test_image_create_from_volume(self, mock_get_data_f):
fake_vol_id = 'fake-volume-id'
mock_get_data_f.return_value = None mock_get_data_f.return_value = None
class FakeVolume: volume = sdk_fakes.generate_fake_resource(_volume.Volume)
id = fake_vol_id self.volume_sdk_client.find_volume.return_value = volume
self.volume_sdk_client.upload_volume_to_image.return_value = {
mock_get_vol.return_value = FakeVolume() 'volume_type': {'name': 'fake_type'}
}
arglist = [ arglist = [
'--volume', '--volume',
fake_vol_id, volume.id,
self.new_image.name, self.new_image.name,
] ]
verifylist = [ verifylist = [
@ -345,53 +338,60 @@ class TestImageCreate(TestImage):
columns, data = self.cmd.take_action(parsed_args) columns, data = self.cmd.take_action(parsed_args)
self.volumes_mock.upload_to_image.assert_called_with( self.volume_sdk_client.upload_volume_to_image.assert_called_once_with(
fake_vol_id, volume.id,
False,
self.new_image.name, self.new_image.name,
'bare', force=False,
'raw', disk_format='raw',
container_format='bare',
visibility=None, visibility=None,
protected=None, protected=None,
) )
@mock.patch('osc_lib.utils.find_resource')
@mock.patch('openstackclient.image.v2.image.get_data_from_stdin') @mock.patch('openstackclient.image.v2.image.get_data_from_stdin')
def test_image_create_from_volume_fail( def test_image_create_from_volume_pre_v31(self, mock_get_data_f):
self, mock_get_data_f, mock_get_vol
):
fake_vol_id = 'fake-volume-id'
mock_get_data_f.return_value = None mock_get_data_f.return_value = None
class FakeVolume: volume = sdk_fakes.generate_fake_resource(_volume.Volume)
id = fake_vol_id self.volume_sdk_client.find_volume.return_value = volume
self.volume_sdk_client.upload_volume_to_image.return_value = {
'volume_type': {'name': 'fake_type'}
}
mock_get_vol.return_value = FakeVolume() arglist = [
'--volume',
arglist = ['--volume', fake_vol_id, self.new_image.name, '--public'] volume.id,
self.new_image.name,
'--public',
]
verifylist = [ verifylist = [
('name', self.new_image.name), ('name', self.new_image.name),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises( exc = self.assertRaises(
exceptions.CommandError, self.cmd.take_action, parsed_args exceptions.CommandError, self.cmd.take_action, parsed_args
) )
self.assertIn('--os-volume-api-version 3.1 or greater ', str(exc))
@mock.patch('osc_lib.utils.find_resource')
@mock.patch('openstackclient.image.v2.image.get_data_from_stdin') @mock.patch('openstackclient.image.v2.image.get_data_from_stdin')
def test_image_create_from_volume_v31(self, mock_get_data_f, mock_get_vol): def test_image_create_from_volume_v31(self, mock_get_data_f):
self.volume_client.api_version = api_versions.APIVersion('3.1') self.set_volume_api_version('3.1')
fake_vol_id = 'fake-volume-id'
mock_get_data_f.return_value = None mock_get_data_f.return_value = None
class FakeVolume: volume = sdk_fakes.generate_fake_resource(_volume.Volume)
id = fake_vol_id self.volume_sdk_client.find_volume.return_value = volume
self.volume_sdk_client.upload_volume_to_image.return_value = {
'volume_type': {'name': 'fake_type'}
}
mock_get_vol.return_value = FakeVolume() arglist = [
'--volume',
arglist = ['--volume', fake_vol_id, self.new_image.name, '--public'] volume.id,
self.new_image.name,
'--public',
]
verifylist = [ verifylist = [
('name', self.new_image.name), ('name', self.new_image.name),
] ]
@ -399,12 +399,12 @@ class TestImageCreate(TestImage):
columns, data = self.cmd.take_action(parsed_args) columns, data = self.cmd.take_action(parsed_args)
self.volumes_mock.upload_to_image.assert_called_with( self.volume_sdk_client.upload_volume_to_image.assert_called_once_with(
fake_vol_id, volume.id,
False,
self.new_image.name, self.new_image.name,
'bare', force=False,
'raw', disk_format='raw',
container_format='bare',
visibility='public', visibility='public',
protected=False, protected=False,
) )