diff options
author | Abhishek Kekane <akekane@redhat.com> | 2020-02-21 10:10:42 +0000 |
---|---|---|
committer | Abhishek Kekane <akekane@redhat.com> | 2020-02-27 06:49:11 +0000 |
commit | 2e0396c0c9576924703d79429f5c3f14619d8b8d (patch) | |
tree | 536bfa544667fbd20b8f4e60991a16d0baceaa1a /glanceclient | |
parent | c23d86738fcfd55301471e8da2512642fd66eba3 (diff) | |
download | python-glanceclient-2e0396c0c9576924703d79429f5c3f14619d8b8d.tar.gz |
Add support for copy-image import method3.0.0
This change adds support for copy-image import method which will
copy existing images into multiple stores.
Change-Id: I748a8fb3dbaf9c2e4d887a2ecd4325e27a8429c4
bp: copy-image-multiple-stores
Diffstat (limited to 'glanceclient')
-rw-r--r-- | glanceclient/tests/unit/v2/test_shell_v2.py | 99 | ||||
-rw-r--r-- | glanceclient/v2/shell.py | 12 |
2 files changed, 110 insertions, 1 deletions
diff --git a/glanceclient/tests/unit/v2/test_shell_v2.py b/glanceclient/tests/unit/v2/test_shell_v2.py index 994993c..f137d30 100644 --- a/glanceclient/tests/unit/v2/test_shell_v2.py +++ b/glanceclient/tests/unit/v2/test_shell_v2.py @@ -842,7 +842,7 @@ class ShellV2Test(testtools.TestCase): import_info_response = {'import-methods': { 'type': 'array', 'description': 'Import methods available.', - 'value': ['glance-direct', 'web-download']}} + 'value': ['glance-direct', 'web-download', 'copy-image']}} def _mock_utils_exit(self, msg): sys.exit(msg) @@ -871,6 +871,27 @@ class ShellV2Test(testtools.TestCase): mock_utils_exit.assert_called_once_with(expected_msg) @mock.patch('glanceclient.common.utils.exit') + def test_neg_image_create_via_import_copy_image( + self, mock_utils_exit): + expected_msg = ("Import method 'copy-image' cannot be used " + "while creating the image.") + mock_utils_exit.side_effect = self._mock_utils_exit + my_args = self.base_args.copy() + my_args.update( + {'id': 'IMG-01', 'import_method': 'copy-image'}) + args = self._make_args(my_args) + + with mock.patch.object(self.gc.images, + 'get_import_info') as mocked_info: + mocked_info.return_value = self.import_info_response + try: + test_shell.do_image_create_via_import(self.gc, args) + self.fail("utils.exit should have been called") + except SystemExit: + pass + mock_utils_exit.assert_called_once_with(expected_msg) + + @mock.patch('glanceclient.common.utils.exit') def test_neg_image_create_via_import_stores_all_stores_specified( self, mock_utils_exit): expected_msg = ('Only one of --store, --stores and --all-stores can ' @@ -1988,6 +2009,82 @@ class ShellV2Test(testtools.TestCase): allow_failure=True, stores=['site1', 'site2'], backend=None) + @mock.patch('glanceclient.common.utils.print_image') + @mock.patch('glanceclient.v2.shell._validate_backend') + def test_image_import_copy_image(self, mocked_utils_print_image, + msvb): + args = self._make_args( + {'id': 'IMG-02', 'uri': None, 'import_method': 'copy-image', + 'from_create': False, 'stores': 'file1,file2'}) + with mock.patch.object(self.gc.images, 'image_import') as mock_import: + with mock.patch.object(self.gc.images, 'get') as mocked_get: + with mock.patch.object(self.gc.images, + 'get_import_info') as mocked_info: + mocked_get.return_value = {'status': 'active', + 'container_format': 'bare', + 'disk_format': 'raw'} + mocked_info.return_value = self.import_info_response + mock_import.return_value = None + test_shell.do_image_import(self.gc, args) + mock_import.assert_called_once_with( + 'IMG-02', 'copy-image', None, all_stores=None, + allow_failure=True, stores=['file1', 'file2'], + backend=None) + + @mock.patch('glanceclient.common.utils.exit') + def test_neg_image_import_copy_image_not_active( + self, mock_utils_exit): + expected_msg = ("The 'copy-image' import method can only be used on " + "an image with status 'active'.") + mock_utils_exit.side_effect = self._mock_utils_exit + args = self._make_args( + {'id': 'IMG-02', 'uri': None, 'import_method': 'copy-image', + 'disk_format': 'raw', + 'container_format': 'bare', + 'from_create': False, 'stores': 'file1,file2'}) + with mock.patch.object( + self.gc.images, + 'get_stores_info') as mocked_stores_info: + with mock.patch.object(self.gc.images, 'get') as mocked_get: + with mock.patch.object(self.gc.images, + 'get_import_info') as mocked_info: + + mocked_stores_info.return_value = self.stores_info_response + mocked_get.return_value = {'status': 'uploading', + 'container_format': 'bare', + 'disk_format': 'raw'} + mocked_info.return_value = self.import_info_response + try: + test_shell.do_image_import(self.gc, args) + self.fail("utils.exit should have been called") + except SystemExit: + pass + mock_utils_exit.assert_called_once_with(expected_msg) + + @mock.patch('glanceclient.common.utils.exit') + def test_neg_image_import_stores_all_stores_not_specified( + self, mock_utils_exit): + expected_msg = ("Provide either --stores or --all-stores for " + "'copy-image' import method.") + mock_utils_exit.side_effect = self._mock_utils_exit + my_args = self.base_args.copy() + my_args.update( + {'id': 'IMG-01', 'import_method': 'copy-image', + 'disk_format': 'raw', + 'container_format': 'bare', + }) + args = self._make_args(my_args) + + with mock.patch.object(self.gc.images, + 'get_import_info') as mocked_info: + mocked_info.return_value = self.import_info_response + try: + test_shell.do_image_import(self.gc, args) + self.fail("utils.exit should have been called") + except SystemExit: + pass + mock_utils_exit.assert_called_once_with(expected_msg) + def test_image_download(self): args = self._make_args( {'id': 'IMG-01', 'file': 'test', 'progress': True, diff --git a/glanceclient/v2/shell.py b/glanceclient/v2/shell.py index b3ac56f..3193a88 100644 --- a/glanceclient/v2/shell.py +++ b/glanceclient/v2/shell.py @@ -210,6 +210,10 @@ def do_image_create_via_import(gc, args): if args.import_method is None and (file_name or using_stdin): args.import_method = 'glance-direct' + if args.import_method == 'copy-image': + utils.exit("Import method 'copy-image' cannot be used " + "while creating the image.") + # determine whether the requested import method is valid import_methods = gc.images.get_import_info().get('import-methods') if args.import_method and args.import_method not in import_methods.get( @@ -735,6 +739,10 @@ def do_image_import(gc, args): utils.exit("Import method should be 'web-download' if URI is " "provided.") + if args.import_method == 'copy-image' and not (stores or all_stores): + utils.exit("Provide either --stores or --all-stores for " + "'copy-image' import method.") + # check image properties image = gc.images.get(args.id) container_format = image.get('container_format') @@ -752,6 +760,10 @@ def do_image_import(gc, args): if image_status != 'queued': utils.exit("The 'web-download' import method can only be applied " "to an image in status 'queued'") + if args.import_method == 'copy-image': + if image_status != 'active': + utils.exit("The 'copy-image' import method can only be used on " + "an image with status 'active'.") # finally, do the import gc.images.image_import(args.id, args.import_method, args.uri, |