Merge "Add support for glance-download import method"
This commit is contained in:
commit
f2999ce752
glanceclient
releasenotes/notes
@ -113,8 +113,8 @@ class BaseController(testtools.TestCase):
|
||||
resp = self.controller.deassociate(*args)
|
||||
self._assertRequestId(resp)
|
||||
|
||||
def image_import(self, *args):
|
||||
resp = self.controller.image_import(*args)
|
||||
def image_import(self, *args, **kwargs):
|
||||
resp = self.controller.image_import(*args, **kwargs)
|
||||
self._assertRequestId(resp)
|
||||
|
||||
|
||||
|
@ -1201,7 +1201,7 @@ class TestController(testtools.TestCase):
|
||||
body = ''.join([b for b in body])
|
||||
self.assertEqual('GOODCHECKSUM', body)
|
||||
|
||||
def test_image_import(self):
|
||||
def test_image_import_web_download(self):
|
||||
uri = 'http://example.com/image.qcow'
|
||||
data = [('method', {'name': 'web-download',
|
||||
'uri': uri})]
|
||||
@ -1211,6 +1211,24 @@ class TestController(testtools.TestCase):
|
||||
data)]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
|
||||
def test_image_import_glance_download(self):
|
||||
region = 'REGION2'
|
||||
remote_image_id = '75baf7b6-253a-11ed-8307-4b1057986a78'
|
||||
image_id = '606b0e88-7c5a-4d54-b5bb-046105d4de6f'
|
||||
service_interface = 'public'
|
||||
data = [('method',
|
||||
{'name': 'glance-download',
|
||||
'glance_region': region,
|
||||
'glance_image_id': remote_image_id,
|
||||
'glance_service_interface': service_interface})]
|
||||
self.controller.image_import(
|
||||
image_id, 'glance-download', remote_region=region,
|
||||
remote_image_id=remote_image_id,
|
||||
remote_service_interface=service_interface)
|
||||
expect = [('POST', '/v2/images/%s/import' % image_id, {},
|
||||
data)]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
|
||||
def test_download_no_data(self):
|
||||
resp = utils.FakeResponse(headers={}, status_code=204)
|
||||
self.controller.controller.http_client.get = mock.Mock(
|
||||
|
@ -957,12 +957,14 @@ class ShellV2Test(testtools.TestCase):
|
||||
'progress': False,
|
||||
'file': None,
|
||||
'uri': None,
|
||||
'remote_region': None,
|
||||
'import_method': None}
|
||||
|
||||
import_info_response = {'import-methods': {
|
||||
'type': 'array',
|
||||
'description': 'Import methods available.',
|
||||
'value': ['glance-direct', 'web-download', 'copy-image']}}
|
||||
'value': ['glance-direct', 'web-download', 'copy-image',
|
||||
'glance-download']}}
|
||||
|
||||
def _mock_utils_exit(self, msg):
|
||||
sys.exit(msg)
|
||||
@ -1451,6 +1453,100 @@ class ShellV2Test(testtools.TestCase):
|
||||
pass
|
||||
mock_utils_exit.assert_called_once_with(expected_msg)
|
||||
|
||||
@mock.patch('glanceclient.common.utils.exit')
|
||||
@mock.patch('sys.stdin', autospec=True)
|
||||
def test_neg_image_create_via_import_glance_download_no_region_and_id(
|
||||
self, mock_stdin, mock_utils_exit):
|
||||
expected_msg = ('REMOTE GlANCE REGION and REMOTE IMAGE ID are '
|
||||
'required for glance-download import method. '
|
||||
'Please use --remote-region <region> and '
|
||||
'--remote-image-id <remote-image-id>.')
|
||||
my_args = self.base_args.copy()
|
||||
my_args['import_method'] = 'glance-download'
|
||||
args = self._make_args(my_args)
|
||||
mock_stdin.isatty = lambda: True
|
||||
mock_utils_exit.side_effect = self._mock_utils_exit
|
||||
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')
|
||||
@mock.patch('sys.stdin', autospec=True)
|
||||
def test_neg_image_create_via_import_glance_download_with_uri(
|
||||
self, mock_stdin, mock_utils_exit):
|
||||
expected_msg = ('You cannot specify a --uri with the '
|
||||
'glance-download import method.')
|
||||
my_args = self.base_args.copy()
|
||||
my_args['import_method'] = 'glance-download'
|
||||
my_args['remote_region'] = 'REGION2'
|
||||
my_args['remote_image_id'] = 'IMG2'
|
||||
my_args['uri'] = 'https://example.com/some/stuff'
|
||||
args = self._make_args(my_args)
|
||||
mock_stdin.isatty = lambda: True
|
||||
mock_utils_exit.side_effect = self._mock_utils_exit
|
||||
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')
|
||||
@mock.patch('sys.stdin', autospec=True)
|
||||
def test_neg_image_create_via_import_glance_download_with_file(
|
||||
self, mock_stdin, mock_utils_exit):
|
||||
expected_msg = ('You cannot specify a --file with the '
|
||||
'glance-download import method.')
|
||||
my_args = self.base_args.copy()
|
||||
my_args['import_method'] = 'glance-download'
|
||||
my_args['remote_region'] = 'REGION2'
|
||||
my_args['remote_image_id'] = 'IMG2'
|
||||
my_args['file'] = 'my.browncow'
|
||||
args = self._make_args(my_args)
|
||||
mock_stdin.isatty = lambda: True
|
||||
mock_utils_exit.side_effect = self._mock_utils_exit
|
||||
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')
|
||||
@mock.patch('sys.stdin', autospec=True)
|
||||
def test_neg_image_create_via_import_glance_download_with_data(
|
||||
self, mock_stdin, mock_utils_exit):
|
||||
expected_msg = ('You cannot pass data via stdin with the '
|
||||
'glance-download import method.')
|
||||
my_args = self.base_args.copy()
|
||||
my_args['import_method'] = 'glance-download'
|
||||
my_args['remote_region'] = 'REGION2'
|
||||
my_args['remote_image_id'] = 'IMG2'
|
||||
args = self._make_args(my_args)
|
||||
mock_stdin.isatty = lambda: False
|
||||
mock_utils_exit.side_effect = self._mock_utils_exit
|
||||
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')
|
||||
@mock.patch('sys.stdin', autospec=True)
|
||||
def test_neg_image_create_via_import_bad_method(
|
||||
@ -2114,13 +2210,16 @@ class ShellV2Test(testtools.TestCase):
|
||||
mock_import.return_value = None
|
||||
test_shell.do_image_import(self.gc, args)
|
||||
mock_import.assert_called_once_with(
|
||||
'IMG-01', 'glance-direct', None, backend=None,
|
||||
all_stores=None, allow_failure=True, stores=None)
|
||||
'IMG-01', 'glance-direct', uri=None,
|
||||
remote_region=None, remote_image_id=None,
|
||||
remote_service_interface=None,
|
||||
backend=None, all_stores=None,
|
||||
allow_failure=True, stores=None)
|
||||
|
||||
def test_image_import_web_download(self):
|
||||
args = self._make_args(
|
||||
{'id': 'IMG-01', 'uri': 'http://example.com/image.qcow',
|
||||
'import_method': 'web-download'})
|
||||
'import_method': 'web-download'})
|
||||
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,
|
||||
@ -2133,7 +2232,33 @@ class ShellV2Test(testtools.TestCase):
|
||||
test_shell.do_image_import(self.gc, args)
|
||||
mock_import.assert_called_once_with(
|
||||
'IMG-01', 'web-download',
|
||||
'http://example.com/image.qcow',
|
||||
uri='http://example.com/image.qcow',
|
||||
remote_region=None, remote_image_id=None,
|
||||
remote_service_interface=None,
|
||||
all_stores=None, allow_failure=True,
|
||||
backend=None, stores=None)
|
||||
|
||||
def test_image_import_glance_download(self):
|
||||
args = self._make_args(
|
||||
{'id': 'IMG-01', 'uri': None, 'remote-region': 'REGION2',
|
||||
'remote-image-id': 'IMG-02',
|
||||
'import_method': 'glance-download',
|
||||
'remote-service-interface': 'public'})
|
||||
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': 'queued',
|
||||
'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-01', 'glance-download',
|
||||
uri=None, remote_region='REGION2',
|
||||
remote_image_id='IMG-02',
|
||||
remote_service_interface='public',
|
||||
all_stores=None, allow_failure=True,
|
||||
backend=None, stores=None)
|
||||
|
||||
@ -2175,9 +2300,11 @@ class ShellV2Test(testtools.TestCase):
|
||||
mock_import.return_value = None
|
||||
test_shell.do_image_import(self.gc, args)
|
||||
mock_import.assert_called_once_with(
|
||||
'IMG-02', 'glance-direct', None, all_stores=None,
|
||||
allow_failure=True, stores=['site1', 'site2'],
|
||||
backend=None)
|
||||
'IMG-02', 'glance-direct', uri=None,
|
||||
remote_region=None, remote_image_id=None,
|
||||
remote_service_interface=None,
|
||||
all_stores=None, allow_failure=True,
|
||||
stores=['site1', 'site2'], backend=None)
|
||||
|
||||
@mock.patch('glanceclient.common.utils.print_image')
|
||||
@mock.patch('glanceclient.v2.shell._validate_backend')
|
||||
@ -2197,9 +2324,11 @@ class ShellV2Test(testtools.TestCase):
|
||||
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)
|
||||
'IMG-02', 'copy-image', uri=None,
|
||||
remote_region=None, remote_image_id=None,
|
||||
remote_service_interface=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(
|
||||
|
@ -353,8 +353,9 @@ class Controller(object):
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def image_import(self, image_id, method='glance-direct', uri=None,
|
||||
backend=None, stores=None, allow_failure=True,
|
||||
all_stores=None):
|
||||
remote_region=None, remote_image_id=None,
|
||||
remote_service_interface=None, backend=None,
|
||||
stores=None, allow_failure=True, all_stores=None):
|
||||
"""Import Image via method."""
|
||||
headers = {}
|
||||
url = '/v2/images/%s/import' % image_id
|
||||
@ -370,6 +371,13 @@ class Controller(object):
|
||||
if allow_failure:
|
||||
data['all_stores_must_succeed'] = False
|
||||
|
||||
if remote_region and remote_image_id:
|
||||
if remote_service_interface:
|
||||
data['method']['glance_service_interface'] = \
|
||||
remote_service_interface
|
||||
data['method']['glance_region'] = remote_region
|
||||
data['method']['glance_image_id'] = remote_image_id
|
||||
|
||||
if uri:
|
||||
if method == 'web-download':
|
||||
data['method']['uri'] = uri
|
||||
|
@ -148,6 +148,14 @@ def do_image_create(gc, args):
|
||||
'record if no import-method and no data is supplied'))
|
||||
@utils.arg('--uri', metavar='<IMAGE_URL>', default=None,
|
||||
help=_('URI to download the external image.'))
|
||||
@utils.arg('--remote-region', metavar='<GLANCE_REGION>', default=None,
|
||||
help=_('REMOTE_GLANCE_REGION to download the image.'))
|
||||
@utils.arg('--remote-image-id', metavar='<REMOTE_IMAGE_ID>', default=None,
|
||||
help=_('The IMAGE ID of the image of remote glance, which needs'
|
||||
'to be imported with glance-download'))
|
||||
@utils.arg('--remote-service-interface', metavar='<REMOTE_SERVICE_INTERFACE>',
|
||||
default='public',
|
||||
help=_('The Remote Glance Service Interface for glance-download'))
|
||||
@utils.arg('--store', metavar='<STORE>',
|
||||
default=utils.env('OS_IMAGE_STORE', default=None),
|
||||
help='Backend store to upload image to.')
|
||||
@ -293,6 +301,22 @@ def do_image_create_via_import(gc, args):
|
||||
utils.exit("You cannot pass data via stdin with the web-download "
|
||||
"import method.")
|
||||
|
||||
if args.import_method == 'glance-download':
|
||||
if not (args.remote_region and args.remote_image_id):
|
||||
utils.exit("REMOTE GlANCE REGION and REMOTE IMAGE ID are "
|
||||
"required for glance-download import method. "
|
||||
"Please use --remote-region <region> and "
|
||||
"--remote-image-id <remote-image-id>.")
|
||||
if args.uri:
|
||||
utils.exit("You cannot specify a --uri with the glance-download "
|
||||
"import method.")
|
||||
if file_name:
|
||||
utils.exit("You cannot specify a --file with the glance-download "
|
||||
"import method.")
|
||||
if using_stdin:
|
||||
utils.exit("You cannot pass data via stdin with the "
|
||||
"glance-download import method.")
|
||||
|
||||
# process
|
||||
image = gc.images.create(**fields)
|
||||
try:
|
||||
@ -726,6 +750,14 @@ def do_image_stage(gc, args):
|
||||
'"image-stage".'))
|
||||
@utils.arg('--uri', metavar='<IMAGE_URL>', default=None,
|
||||
help=_('URI to download the external image.'))
|
||||
@utils.arg('--remote-region', metavar='<REMOTE_GLANCE_REGION>', default=None,
|
||||
help=_('REMOTE GLANCE REGION to download the image.'))
|
||||
@utils.arg('--remote-image-id', metavar='<REMOTE_IMAGE_ID>', default=None,
|
||||
help=_('The IMAGE ID of the image of remote glance, which needs'
|
||||
'to be imported with glance-download'))
|
||||
@utils.arg('--remote-service-interface', metavar='<REMOTE_SERVICE_INTERFACE>',
|
||||
default='public',
|
||||
help=_('The Remote Glance Service Interface for glance-download'))
|
||||
@utils.arg('id', metavar='<IMAGE_ID>',
|
||||
help=_('ID of image to import.'))
|
||||
@utils.arg('--store', metavar='<STORE>',
|
||||
@ -757,6 +789,10 @@ def do_image_import(gc, args):
|
||||
stores = getattr(args, "stores", None)
|
||||
all_stores = getattr(args, "os_all_stores", None)
|
||||
allow_failure = getattr(args, "os_allow_failure", True)
|
||||
uri = getattr(args, "uri", None)
|
||||
remote_region = getattr(args, "remote-region", None)
|
||||
remote_image_id = getattr(args, "remote-image-id", None)
|
||||
remote_service_interface = getattr(args, "remote-service-interface", None)
|
||||
|
||||
if not getattr(args, 'from_create', False):
|
||||
if (args.store and (stores or all_stores)) or (stores and all_stores):
|
||||
@ -800,6 +836,20 @@ def do_image_import(gc, args):
|
||||
utils.exit("Import method should be 'web-download' if URI is "
|
||||
"provided.")
|
||||
|
||||
if args.import_method == 'glance-download' and \
|
||||
not (remote_region and remote_image_id):
|
||||
utils.exit("Provide REMOTE_IMAGE_ID and remote-region for "
|
||||
"'glance-download' import method.")
|
||||
if remote_region and args.import_method != 'glance-download':
|
||||
utils.exit("Import method should be 'glance-download' if "
|
||||
"REMOTE REGION is provided.")
|
||||
if remote_image_id and args.import_method != 'glance-download':
|
||||
utils.exit("Import method should be 'glance-download' if "
|
||||
"REMOTE IMAGE ID is provided.")
|
||||
if remote_service_interface and args.import_method != 'glance-download':
|
||||
utils.exit("Import method should be 'glance-download' if "
|
||||
"REMOTE SERVICE INTERFACE 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.")
|
||||
@ -827,10 +877,12 @@ def do_image_import(gc, args):
|
||||
"an image with status 'active'.")
|
||||
|
||||
# finally, do the import
|
||||
gc.images.image_import(args.id, args.import_method, args.uri,
|
||||
backend=backend,
|
||||
stores=stores, all_stores=all_stores,
|
||||
allow_failure=allow_failure)
|
||||
gc.images.image_import(args.id, args.import_method, uri=uri,
|
||||
remote_region=remote_region,
|
||||
remote_image_id=remote_image_id,
|
||||
remote_service_interface=remote_service_interface,
|
||||
backend=backend, stores=stores,
|
||||
all_stores=all_stores, allow_failure=allow_failure)
|
||||
|
||||
image = gc.images.get(args.id)
|
||||
utils.print_image(image)
|
||||
|
5
releasenotes/notes/add-support-for-glance-download-import-method-10525254db3e8e7a.yaml
Normal file
5
releasenotes/notes/add-support-for-glance-download-import-method-10525254db3e8e7a.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Add support for new ``glance-download`` image-import method to
|
||||
import image from another glance/region in federated deployment.
|
Loading…
x
Reference in New Issue
Block a user