From 181bb194c7956fa2a909169a86980c55c55d39b7 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Mon, 15 Jul 2024 10:44:52 +0100 Subject: [PATCH] image: Migrate 'create image' volume calls to SDK Change-Id: Ie57a5c17a6df5a333abd6b11e28b65833740e102 Signed-off-by: Stephen Finucane --- openstackclient/image/v2/image.py | 22 ++--- .../tests/unit/image/v2/test_image.py | 92 +++++++++---------- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py index 57f278dcd7..7dbd1609f9 100644 --- a/openstackclient/image/v2/image.py +++ b/openstackclient/image/v2/image.py @@ -17,14 +17,15 @@ import argparse from base64 import b64encode +import copy import logging import os import sys import typing as ty -from cinderclient import api_versions from openstack import exceptions as sdk_exceptions 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.cli import format_columns from osc_lib.cli import parseractions @@ -576,7 +577,7 @@ class CreateImage(command.ShowOne): return _format_image(image) 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 = { # 'name', # 'name' is a positional argument and will always exist @@ -607,15 +608,14 @@ class CreateImage(command.ShowOne): # version LOG.warning(msg % opt_name) - source_volume = utils.find_resource( - volume_client.volumes, - parsed_args.volume, + source_volume = volume_client.find_volume( + parsed_args.volume, ignore_missing=False ) kwargs: dict[str, ty.Any] = { 'visibility': 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: msg = _( '--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['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, - parsed_args.force, parsed_args.name, - parsed_args.container_format, - parsed_args.disk_format, + force=parsed_args.force, + disk_format=parsed_args.disk_format, + container_format=parsed_args.container_format, **kwargs, ) - info = body['os-volume_upload_image'] + info = copy.deepcopy(response) try: info['volume_type'] = info['volume_type']['name'] except TypeError: diff --git a/openstackclient/tests/unit/image/v2/test_image.py b/openstackclient/tests/unit/image/v2/test_image.py index 049510c712..9b44c1578c 100644 --- a/openstackclient/tests/unit/image/v2/test_image.py +++ b/openstackclient/tests/unit/image/v2/test_image.py @@ -17,8 +17,9 @@ import io import tempfile 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.test import fakes as sdk_fakes from osc_lib.cli import format_columns from osc_lib import exceptions @@ -37,12 +38,6 @@ class TestImage(image_fakes.TestImagev2, volume_fakes.TestVolume): self.project_mock.reset_mock() self.domain_mock = self.identity_client.domains 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): @@ -312,7 +307,6 @@ class TestImageCreate(TestImage): columns, data = self.cmd.take_action(parsed_args) - # ImageManager.create(name=, **) self.image_client.create_image.assert_called_with( name=self.new_image.name, allow_duplicates=True, @@ -322,20 +316,19 @@ class TestImageCreate(TestImage): ) 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') - def test_image_create_from_volume(self, mock_get_data_f, mock_get_vol): - fake_vol_id = 'fake-volume-id' + def test_image_create_from_volume(self, mock_get_data_f): mock_get_data_f.return_value = None - class FakeVolume: - id = fake_vol_id - - mock_get_vol.return_value = FakeVolume() + volume = sdk_fakes.generate_fake_resource(_volume.Volume) + self.volume_sdk_client.find_volume.return_value = volume + self.volume_sdk_client.upload_volume_to_image.return_value = { + 'volume_type': {'name': 'fake_type'} + } arglist = [ '--volume', - fake_vol_id, + volume.id, self.new_image.name, ] verifylist = [ @@ -345,53 +338,60 @@ class TestImageCreate(TestImage): columns, data = self.cmd.take_action(parsed_args) - self.volumes_mock.upload_to_image.assert_called_with( - fake_vol_id, - False, + self.volume_sdk_client.upload_volume_to_image.assert_called_once_with( + volume.id, self.new_image.name, - 'bare', - 'raw', + force=False, + disk_format='raw', + container_format='bare', visibility=None, protected=None, ) - @mock.patch('osc_lib.utils.find_resource') @mock.patch('openstackclient.image.v2.image.get_data_from_stdin') - def test_image_create_from_volume_fail( - self, mock_get_data_f, mock_get_vol - ): - fake_vol_id = 'fake-volume-id' + def test_image_create_from_volume_pre_v31(self, mock_get_data_f): mock_get_data_f.return_value = None - class FakeVolume: - id = fake_vol_id + volume = sdk_fakes.generate_fake_resource(_volume.Volume) + 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', fake_vol_id, self.new_image.name, '--public'] + arglist = [ + '--volume', + volume.id, + self.new_image.name, + '--public', + ] verifylist = [ ('name', self.new_image.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.assertRaises( + exc = self.assertRaises( 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') - def test_image_create_from_volume_v31(self, mock_get_data_f, mock_get_vol): - self.volume_client.api_version = api_versions.APIVersion('3.1') + def test_image_create_from_volume_v31(self, mock_get_data_f): + self.set_volume_api_version('3.1') - fake_vol_id = 'fake-volume-id' mock_get_data_f.return_value = None - class FakeVolume: - id = fake_vol_id + volume = sdk_fakes.generate_fake_resource(_volume.Volume) + 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', fake_vol_id, self.new_image.name, '--public'] + arglist = [ + '--volume', + volume.id, + self.new_image.name, + '--public', + ] verifylist = [ ('name', self.new_image.name), ] @@ -399,12 +399,12 @@ class TestImageCreate(TestImage): columns, data = self.cmd.take_action(parsed_args) - self.volumes_mock.upload_to_image.assert_called_with( - fake_vol_id, - False, + self.volume_sdk_client.upload_volume_to_image.assert_called_once_with( + volume.id, self.new_image.name, - 'bare', - 'raw', + force=False, + disk_format='raw', + container_format='bare', visibility='public', protected=False, )