Merge "Refactoring: flatten the glance service module"
This commit is contained in:
commit
f52b386b4c
ironic
common
tests/unit
common
drivers/modules
@ -1,199 +0,0 @@
|
||||
# Copyright 2010 OpenStack Foundation
|
||||
# Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||
# 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.
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from glanceclient import client
|
||||
from glanceclient import exc as glance_exc
|
||||
from oslo_log import log
|
||||
import sendfile
|
||||
import six
|
||||
import six.moves.urllib.parse as urlparse
|
||||
|
||||
from ironic.common import exception
|
||||
from ironic.common.glance_service import service_utils
|
||||
from ironic.common.i18n import _
|
||||
from ironic.common import keystone
|
||||
from ironic.conf import CONF
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
_GLANCE_SESSION = None
|
||||
|
||||
|
||||
def _translate_image_exception(image_id, exc_value):
|
||||
if isinstance(exc_value, (glance_exc.Forbidden,
|
||||
glance_exc.Unauthorized)):
|
||||
return exception.ImageNotAuthorized(image_id=image_id)
|
||||
if isinstance(exc_value, glance_exc.NotFound):
|
||||
return exception.ImageNotFound(image_id=image_id)
|
||||
if isinstance(exc_value, glance_exc.BadRequest):
|
||||
return exception.Invalid(exc_value)
|
||||
return exc_value
|
||||
|
||||
|
||||
def check_image_service(func):
|
||||
"""Creates a glance client if doesn't exists and calls the function."""
|
||||
@six.wraps(func)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
"""Wrapper around methods calls.
|
||||
|
||||
:param image_href: href that describes the location of an image
|
||||
"""
|
||||
|
||||
if self.client:
|
||||
return func(self, *args, **kwargs)
|
||||
|
||||
global _GLANCE_SESSION
|
||||
if not _GLANCE_SESSION:
|
||||
_GLANCE_SESSION = keystone.get_session('glance')
|
||||
|
||||
# NOTE(pas-ha) glanceclient uses Adapter-based SessionClient,
|
||||
# so we can pass session and auth separately, makes things easier
|
||||
service_auth = keystone.get_auth('glance')
|
||||
|
||||
adapter = keystone.get_adapter('glance', session=_GLANCE_SESSION,
|
||||
auth=service_auth)
|
||||
self.endpoint = adapter.get_endpoint()
|
||||
|
||||
user_auth = None
|
||||
# NOTE(pas-ha) our ContextHook removes context.auth_token in noauth
|
||||
# case, so when ironic is in noauth but glance is not, we will not
|
||||
# enter the next if-block and use auth from [glance] config section
|
||||
if self.context.auth_token:
|
||||
user_auth = keystone.get_service_auth(self.context, self.endpoint,
|
||||
service_auth)
|
||||
self.client = client.Client(2, session=_GLANCE_SESSION,
|
||||
auth=user_auth or service_auth,
|
||||
endpoint_override=self.endpoint,
|
||||
global_request_id=self.context.global_id)
|
||||
return func(self, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class BaseImageService(object):
|
||||
|
||||
def __init__(self, client=None, context=None):
|
||||
self.client = client
|
||||
self.context = context
|
||||
self.endpoint = None
|
||||
|
||||
def call(self, method, *args, **kwargs):
|
||||
"""Call a glance client method.
|
||||
|
||||
If we get a connection error,
|
||||
retry the request according to CONF.num_retries.
|
||||
|
||||
:param context: The request context, for access checks.
|
||||
:param method: The method requested to be called.
|
||||
:param args: A list of positional arguments for the method called
|
||||
:param kwargs: A dict of keyword arguments for the method called
|
||||
|
||||
:raises: GlanceConnectionFailed
|
||||
"""
|
||||
retry_excs = (glance_exc.ServiceUnavailable,
|
||||
glance_exc.InvalidEndpoint,
|
||||
glance_exc.CommunicationError)
|
||||
image_excs = (glance_exc.Forbidden,
|
||||
glance_exc.Unauthorized,
|
||||
glance_exc.NotFound,
|
||||
glance_exc.BadRequest)
|
||||
num_attempts = 1 + CONF.glance.num_retries
|
||||
|
||||
# TODO(pas-ha) use retrying lib here
|
||||
for attempt in range(1, num_attempts + 1):
|
||||
try:
|
||||
return getattr(self.client.images, method)(*args, **kwargs)
|
||||
except retry_excs as e:
|
||||
error_msg = ("Error contacting glance endpoint "
|
||||
"%(endpoint)s for '%(method)s', attempt "
|
||||
"%(attempt)s of %(num_attempts)s failed.")
|
||||
LOG.exception(error_msg, {'endpoint': self.endpoint,
|
||||
'num_attempts': num_attempts,
|
||||
'attempt': attempt,
|
||||
'method': method})
|
||||
if attempt == num_attempts:
|
||||
raise exception.GlanceConnectionFailed(
|
||||
endpoint=self.endpoint, reason=e)
|
||||
time.sleep(1)
|
||||
except image_excs as e:
|
||||
exc_type, exc_value, exc_trace = sys.exc_info()
|
||||
new_exc = _translate_image_exception(
|
||||
args[0], exc_value)
|
||||
six.reraise(type(new_exc), new_exc, exc_trace)
|
||||
|
||||
@check_image_service
|
||||
def _show(self, image_href, method='get'):
|
||||
"""Returns a dict with image data for the given opaque image id.
|
||||
|
||||
:param image_href: The opaque image identifier.
|
||||
:returns: A dict containing image metadata.
|
||||
|
||||
:raises: ImageNotFound
|
||||
:raises: ImageUnacceptable if the image status is not active
|
||||
"""
|
||||
LOG.debug("Getting image metadata from glance. Image: %s",
|
||||
image_href)
|
||||
image_id = service_utils.parse_image_id(image_href)
|
||||
|
||||
image = self.call(method, image_id)
|
||||
|
||||
if not service_utils.is_image_active(image):
|
||||
raise exception.ImageUnacceptable(
|
||||
image_id=image_id,
|
||||
reason=_("The image is required to be in an active state."))
|
||||
|
||||
if not service_utils.is_image_available(self.context, image):
|
||||
raise exception.ImageNotFound(image_id=image_id)
|
||||
|
||||
base_image_meta = service_utils.translate_from_glance(image)
|
||||
return base_image_meta
|
||||
|
||||
@check_image_service
|
||||
def _download(self, image_href, data=None, method='data'):
|
||||
"""Calls out to Glance for data and writes data.
|
||||
|
||||
:param image_href: The opaque image identifier.
|
||||
:param data: (Optional) File object to write data to.
|
||||
"""
|
||||
image_id = service_utils.parse_image_id(image_href)
|
||||
|
||||
if 'file' in CONF.glance.allowed_direct_url_schemes:
|
||||
location = self._get_location(image_id)
|
||||
url = urlparse.urlparse(location)
|
||||
if url.scheme == "file":
|
||||
with open(url.path, "r") as f:
|
||||
filesize = os.path.getsize(f.name)
|
||||
sendfile.sendfile(data.fileno(), f.fileno(), 0, filesize)
|
||||
return
|
||||
|
||||
image_chunks = self.call(method, image_id)
|
||||
# NOTE(dtantsur): when using Glance V2, image_chunks is a wrapper
|
||||
# around real data, so we have to check the wrapped data for None.
|
||||
if image_chunks.wrapped is None:
|
||||
raise exception.ImageDownloadFailed(
|
||||
image_href=image_href, reason=_('image contains no data.'))
|
||||
|
||||
if data is None:
|
||||
return image_chunks
|
||||
else:
|
||||
for chunk in image_chunks:
|
||||
data.write(chunk)
|
188
ironic/common/glance_service/v2/image_service.py → ironic/common/glance_service/image_service.py
188
ironic/common/glance_service/v2/image_service.py → ironic/common/glance_service/image_service.py
@ -14,15 +14,21 @@
|
||||
# under the License.
|
||||
|
||||
import collections
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
|
||||
from glanceclient import client
|
||||
from glanceclient import exc as glance_exc
|
||||
from oslo_log import log
|
||||
from oslo_utils import uuidutils
|
||||
import sendfile
|
||||
import six
|
||||
from six.moves.urllib import parse as urlparse
|
||||
from swiftclient import utils as swift_utils
|
||||
|
||||
from ironic.common import exception as exc
|
||||
from ironic.common.glance_service import base_image_service
|
||||
from ironic.common import exception
|
||||
from ironic.common.glance_service import service_utils
|
||||
from ironic.common.i18n import _
|
||||
from ironic.common import keystone
|
||||
@ -33,7 +39,62 @@ TempUrlCacheElement = collections.namedtuple('TempUrlCacheElement',
|
||||
['url', 'url_expires_at'])
|
||||
|
||||
|
||||
class GlanceImageService(base_image_service.BaseImageService):
|
||||
LOG = log.getLogger(__name__)
|
||||
_GLANCE_SESSION = None
|
||||
|
||||
|
||||
def _translate_image_exception(image_id, exc_value):
|
||||
if isinstance(exc_value, (glance_exc.Forbidden,
|
||||
glance_exc.Unauthorized)):
|
||||
return exception.ImageNotAuthorized(image_id=image_id)
|
||||
if isinstance(exc_value, glance_exc.NotFound):
|
||||
return exception.ImageNotFound(image_id=image_id)
|
||||
if isinstance(exc_value, glance_exc.BadRequest):
|
||||
return exception.Invalid(exc_value)
|
||||
return exc_value
|
||||
|
||||
|
||||
def check_image_service(func):
|
||||
"""Creates a glance client if doesn't exists and calls the function."""
|
||||
@six.wraps(func)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
"""Wrapper around methods calls.
|
||||
|
||||
:param image_href: href that describes the location of an image
|
||||
"""
|
||||
|
||||
if self.client:
|
||||
return func(self, *args, **kwargs)
|
||||
|
||||
global _GLANCE_SESSION
|
||||
if not _GLANCE_SESSION:
|
||||
_GLANCE_SESSION = keystone.get_session('glance')
|
||||
|
||||
# NOTE(pas-ha) glanceclient uses Adapter-based SessionClient,
|
||||
# so we can pass session and auth separately, makes things easier
|
||||
service_auth = keystone.get_auth('glance')
|
||||
|
||||
adapter = keystone.get_adapter('glance', session=_GLANCE_SESSION,
|
||||
auth=service_auth)
|
||||
self.endpoint = adapter.get_endpoint()
|
||||
|
||||
user_auth = None
|
||||
# NOTE(pas-ha) our ContextHook removes context.auth_token in noauth
|
||||
# case, so when ironic is in noauth but glance is not, we will not
|
||||
# enter the next if-block and use auth from [glance] config section
|
||||
if self.context.auth_token:
|
||||
user_auth = keystone.get_service_auth(self.context, self.endpoint,
|
||||
service_auth)
|
||||
self.client = client.Client(2, session=_GLANCE_SESSION,
|
||||
auth=user_auth or service_auth,
|
||||
endpoint_override=self.endpoint,
|
||||
global_request_id=self.context.global_id)
|
||||
return func(self, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class GlanceImageService(object):
|
||||
|
||||
# A dictionary containing cached temp URLs in namedtuples
|
||||
# in format:
|
||||
@ -45,11 +106,112 @@ class GlanceImageService(base_image_service.BaseImageService):
|
||||
# }
|
||||
_cache = {}
|
||||
|
||||
def show(self, image_id):
|
||||
return self._show(image_id, method='get')
|
||||
def __init__(self, client=None, context=None):
|
||||
self.client = client
|
||||
self.context = context
|
||||
self.endpoint = None
|
||||
|
||||
def download(self, image_id, data=None):
|
||||
return self._download(image_id, method='data', data=data)
|
||||
def call(self, method, *args, **kwargs):
|
||||
"""Call a glance client method.
|
||||
|
||||
If we get a connection error,
|
||||
retry the request according to CONF.num_retries.
|
||||
|
||||
:param context: The request context, for access checks.
|
||||
:param method: The method requested to be called.
|
||||
:param args: A list of positional arguments for the method called
|
||||
:param kwargs: A dict of keyword arguments for the method called
|
||||
|
||||
:raises: GlanceConnectionFailed
|
||||
"""
|
||||
retry_excs = (glance_exc.ServiceUnavailable,
|
||||
glance_exc.InvalidEndpoint,
|
||||
glance_exc.CommunicationError)
|
||||
image_excs = (glance_exc.Forbidden,
|
||||
glance_exc.Unauthorized,
|
||||
glance_exc.NotFound,
|
||||
glance_exc.BadRequest)
|
||||
num_attempts = 1 + CONF.glance.num_retries
|
||||
|
||||
# TODO(pas-ha) use retrying lib here
|
||||
for attempt in range(1, num_attempts + 1):
|
||||
try:
|
||||
return getattr(self.client.images, method)(*args, **kwargs)
|
||||
except retry_excs as e:
|
||||
error_msg = ("Error contacting glance endpoint "
|
||||
"%(endpoint)s for '%(method)s', attempt "
|
||||
"%(attempt)s of %(num_attempts)s failed.")
|
||||
LOG.exception(error_msg, {'endpoint': self.endpoint,
|
||||
'num_attempts': num_attempts,
|
||||
'attempt': attempt,
|
||||
'method': method})
|
||||
if attempt == num_attempts:
|
||||
raise exception.GlanceConnectionFailed(
|
||||
endpoint=self.endpoint, reason=e)
|
||||
time.sleep(1)
|
||||
except image_excs:
|
||||
exc_type, exc_value, exc_trace = sys.exc_info()
|
||||
new_exc = _translate_image_exception(
|
||||
args[0], exc_value)
|
||||
six.reraise(type(new_exc), new_exc, exc_trace)
|
||||
|
||||
@check_image_service
|
||||
def show(self, image_href):
|
||||
"""Returns a dict with image data for the given opaque image id.
|
||||
|
||||
:param image_href: The opaque image identifier.
|
||||
:returns: A dict containing image metadata.
|
||||
|
||||
:raises: ImageNotFound
|
||||
:raises: ImageUnacceptable if the image status is not active
|
||||
"""
|
||||
LOG.debug("Getting image metadata from glance. Image: %s",
|
||||
image_href)
|
||||
image_id = service_utils.parse_image_id(image_href)
|
||||
|
||||
image = self.call('get', image_id)
|
||||
|
||||
if not service_utils.is_image_active(image):
|
||||
raise exception.ImageUnacceptable(
|
||||
image_id=image_id,
|
||||
reason=_("The image is required to be in an active state."))
|
||||
|
||||
if not service_utils.is_image_available(self.context, image):
|
||||
raise exception.ImageNotFound(image_id=image_id)
|
||||
|
||||
base_image_meta = service_utils.translate_from_glance(image)
|
||||
return base_image_meta
|
||||
|
||||
@check_image_service
|
||||
def download(self, image_href, data=None):
|
||||
"""Calls out to Glance for data and writes data.
|
||||
|
||||
:param image_href: The opaque image identifier.
|
||||
:param data: (Optional) File object to write data to.
|
||||
"""
|
||||
image_id = service_utils.parse_image_id(image_href)
|
||||
|
||||
if 'file' in CONF.glance.allowed_direct_url_schemes:
|
||||
location = self._get_location(image_id)
|
||||
url = urlparse.urlparse(location)
|
||||
if url.scheme == "file":
|
||||
with open(url.path, "r") as f:
|
||||
filesize = os.path.getsize(f.name)
|
||||
sendfile.sendfile(data.fileno(), f.fileno(), 0, filesize)
|
||||
return
|
||||
|
||||
image_chunks = self.call('data', image_id)
|
||||
# NOTE(dtantsur): when using Glance V2, image_chunks is a wrapper
|
||||
# around real data, so we have to check the wrapped data for None.
|
||||
if image_chunks.wrapped is None:
|
||||
raise exception.ImageDownloadFailed(
|
||||
image_href=image_href, reason=_('image contains no data.'))
|
||||
|
||||
if data is None:
|
||||
return image_chunks
|
||||
else:
|
||||
for chunk in image_chunks:
|
||||
data.write(chunk)
|
||||
|
||||
def _generate_temp_url(self, path, seconds, key, method, endpoint,
|
||||
image_id):
|
||||
@ -119,7 +281,7 @@ class GlanceImageService(base_image_service.BaseImageService):
|
||||
|
||||
if ('id' not in image_info or not
|
||||
uuidutils.is_uuid_like(image_info['id'])):
|
||||
raise exc.ImageUnacceptable(_(
|
||||
raise exception.ImageUnacceptable(_(
|
||||
'The given image info does not have a valid image id: %s')
|
||||
% image_info)
|
||||
|
||||
@ -138,7 +300,7 @@ class GlanceImageService(base_image_service.BaseImageService):
|
||||
endpoint_url = adapter.get_endpoint()
|
||||
|
||||
if not endpoint_url:
|
||||
raise exc.MissingParameterValue(_(
|
||||
raise exception.MissingParameterValue(_(
|
||||
'Swift temporary URLs require a Swift endpoint URL, but it '
|
||||
'was not found in the service catalog. '
|
||||
'You must provide "swift_endpoint_url" as a config option.'))
|
||||
@ -159,7 +321,7 @@ class GlanceImageService(base_image_service.BaseImageService):
|
||||
key = swift_api.connection.head_account().get(key_header)
|
||||
|
||||
if not key:
|
||||
raise exc.MissingParameterValue(_(
|
||||
raise exception.MissingParameterValue(_(
|
||||
'Swift temporary URLs require a shared secret to be '
|
||||
'created. You must provide "swift_temp_url_key" as a '
|
||||
'config option or pre-generate the key on the project '
|
||||
@ -183,7 +345,7 @@ class GlanceImageService(base_image_service.BaseImageService):
|
||||
"""Validate the required settings for a temporary URL."""
|
||||
if (CONF.glance.swift_temp_url_duration
|
||||
< CONF.glance.swift_temp_url_expected_download_start_delay):
|
||||
raise exc.InvalidParameterValue(_(
|
||||
raise exception.InvalidParameterValue(_(
|
||||
'"swift_temp_url_duration" must be greater than or equal to '
|
||||
'"[glance]swift_temp_url_expected_download_start_delay" '
|
||||
'option, otherwise the Swift temporary URL may expire before '
|
||||
@ -191,7 +353,7 @@ class GlanceImageService(base_image_service.BaseImageService):
|
||||
seed_num_chars = CONF.glance.swift_store_multiple_containers_seed
|
||||
if (seed_num_chars is None or seed_num_chars < 0
|
||||
or seed_num_chars > 32):
|
||||
raise exc.InvalidParameterValue(_(
|
||||
raise exception.InvalidParameterValue(_(
|
||||
"An integer value between 0 and 32 is required for"
|
||||
" swift_store_multiple_containers_seed."))
|
||||
|
||||
@ -238,7 +400,7 @@ class GlanceImageService(base_image_service.BaseImageService):
|
||||
image_meta = self.call('get', image_id)
|
||||
|
||||
if not service_utils.is_image_available(self.context, image_meta):
|
||||
raise exc.ImageNotFound(image_id=image_id)
|
||||
raise exception.ImageNotFound(image_id=image_id)
|
||||
|
||||
return getattr(image_meta, 'direct_url', None)
|
||||
|
@ -29,7 +29,7 @@ from six.moves import http_client
|
||||
import six.moves.urllib.parse as urlparse
|
||||
|
||||
from ironic.common import exception
|
||||
from ironic.common.glance_service.v2 import image_service
|
||||
from ironic.common.glance_service import image_service
|
||||
from ironic.common.i18n import _
|
||||
from ironic.common import utils
|
||||
|
||||
|
@ -27,9 +27,8 @@ import testtools
|
||||
|
||||
from ironic.common import context
|
||||
from ironic.common import exception
|
||||
from ironic.common.glance_service import base_image_service
|
||||
from ironic.common.glance_service import image_service
|
||||
from ironic.common.glance_service import service_utils
|
||||
from ironic.common.glance_service.v2 import image_service as glance_v2
|
||||
from ironic.common import image_service as service
|
||||
from ironic.tests import base
|
||||
from ironic.tests.unit import stubs
|
||||
@ -245,9 +244,9 @@ class TestGlanceImageService(base.TestCase):
|
||||
|
||||
self.config(allowed_direct_url_schemes=['file'], group='glance')
|
||||
|
||||
# patching open in base_image_service module namespace
|
||||
# patching open in image_service module namespace
|
||||
# to make call-spec assertions
|
||||
with mock.patch('ironic.common.glance_service.base_image_service.open',
|
||||
with mock.patch('ironic.common.glance_service.image_service.open',
|
||||
new=mock.mock_open(), create=True) as mock_ironic_open:
|
||||
with open('/whatever/target', 'w') as mock_target_fd:
|
||||
stub_service.download(image_id, mock_target_fd)
|
||||
@ -356,7 +355,7 @@ class CheckImageServiceTestCase(base.TestCase):
|
||||
region_name='SomeRegion',
|
||||
interface='internal',
|
||||
group='glance')
|
||||
base_image_service._GLANCE_SESSION = None
|
||||
image_service._GLANCE_SESSION = None
|
||||
|
||||
def test_check_image_service_client_already_set(self, mock_gclient,
|
||||
mock_sess, mock_adapter,
|
||||
@ -366,7 +365,7 @@ class CheckImageServiceTestCase(base.TestCase):
|
||||
|
||||
self.service.client = True
|
||||
|
||||
wrapped_func = base_image_service.check_image_service(func)
|
||||
wrapped_func = image_service.check_image_service(func)
|
||||
self.assertTrue(wrapped_func(self.service))
|
||||
self.assertEqual(0, mock_gclient.call_count)
|
||||
self.assertEqual(0, mock_sess.call_count)
|
||||
@ -393,7 +392,7 @@ class CheckImageServiceTestCase(base.TestCase):
|
||||
uuid = uuidutils.generate_uuid()
|
||||
params = {'image_href': uuid}
|
||||
|
||||
wrapped_func = base_image_service.check_image_service(func)
|
||||
wrapped_func = image_service.check_image_service(func)
|
||||
self.assertEqual(((), params), wrapped_func(self.service, **params))
|
||||
self._assert_client_call(mock_gclient, 'glance_url')
|
||||
mock_auth.assert_called_once_with('glance')
|
||||
@ -417,7 +416,7 @@ class CheckImageServiceTestCase(base.TestCase):
|
||||
uuid = uuidutils.generate_uuid()
|
||||
params = {'image_href': uuid}
|
||||
|
||||
wrapped_func = base_image_service.check_image_service(func)
|
||||
wrapped_func = image_service.check_image_service(func)
|
||||
self.assertEqual(((), params), wrapped_func(self.service, **params))
|
||||
self._assert_client_call(mock_gclient, 'glance_url', user=True)
|
||||
mock_sess.assert_called_once_with('glance')
|
||||
@ -441,9 +440,9 @@ class CheckImageServiceTestCase(base.TestCase):
|
||||
uuid = uuidutils.generate_uuid()
|
||||
params = {'image_href': uuid}
|
||||
|
||||
wrapped_func = base_image_service.check_image_service(func)
|
||||
wrapped_func = image_service.check_image_service(func)
|
||||
self.assertEqual(((), params), wrapped_func(self.service, **params))
|
||||
self.assertEqual('none', base_image_service.CONF.glance.auth_type)
|
||||
self.assertEqual('none', image_service.CONF.glance.auth_type)
|
||||
self._assert_client_call(mock_gclient, 'foo')
|
||||
mock_sess.assert_called_once_with('glance')
|
||||
mock_adapter.assert_called_once_with('glance',
|
||||
@ -785,8 +784,8 @@ class TestSwiftTempUrlCache(base.TestCase):
|
||||
{'uuid': fake_image['id'], 'exp_time': exp_time}
|
||||
)
|
||||
self.glance_service._cache[fake_image['id']] = (
|
||||
glance_v2.TempUrlCacheElement(url=temp_url,
|
||||
url_expires_at=exp_time)
|
||||
image_service.TempUrlCacheElement(url=temp_url,
|
||||
url_expires_at=exp_time)
|
||||
)
|
||||
|
||||
cleanup_mock = mock.Mock()
|
||||
@ -813,7 +812,7 @@ class TestSwiftTempUrlCache(base.TestCase):
|
||||
)
|
||||
query = '?temp_url_sig=hmacsig&temp_url_expires=%s'
|
||||
self.glance_service._cache[fake_image['id']] = (
|
||||
glance_v2.TempUrlCacheElement(
|
||||
image_service.TempUrlCacheElement(
|
||||
url=(CONF.glance.swift_endpoint_url + path
|
||||
+ query % old_exp_time),
|
||||
url_expires_at=old_exp_time)
|
||||
@ -842,21 +841,21 @@ class TestSwiftTempUrlCache(base.TestCase):
|
||||
|
||||
def test_remove_expired_items_from_cache(self):
|
||||
expired_items = {
|
||||
uuidutils.generate_uuid(): glance_v2.TempUrlCacheElement(
|
||||
uuidutils.generate_uuid(): image_service.TempUrlCacheElement(
|
||||
'fake-url-1',
|
||||
int(time.time()) - 10
|
||||
),
|
||||
uuidutils.generate_uuid(): glance_v2.TempUrlCacheElement(
|
||||
uuidutils.generate_uuid(): image_service.TempUrlCacheElement(
|
||||
'fake-url-2',
|
||||
int(time.time()) + 90 # Agent won't be able to start in time
|
||||
)
|
||||
}
|
||||
valid_items = {
|
||||
uuidutils.generate_uuid(): glance_v2.TempUrlCacheElement(
|
||||
uuidutils.generate_uuid(): image_service.TempUrlCacheElement(
|
||||
'fake-url-3',
|
||||
int(time.time()) + 1000
|
||||
),
|
||||
uuidutils.generate_uuid(): glance_v2.TempUrlCacheElement(
|
||||
uuidutils.generate_uuid(): image_service.TempUrlCacheElement(
|
||||
'fake-url-4',
|
||||
int(time.time()) + 2000
|
||||
)
|
||||
|
@ -23,7 +23,7 @@ import six.moves.builtins as __builtin__
|
||||
from six.moves import http_client
|
||||
|
||||
from ironic.common import exception
|
||||
from ironic.common.glance_service.v2 import image_service as glance_v2_service
|
||||
from ironic.common.glance_service import image_service as glance_v2_service
|
||||
from ironic.common import image_service
|
||||
from ironic.tests import base
|
||||
|
||||
|
@ -25,7 +25,7 @@ from oslo_utils import uuidutils
|
||||
import six
|
||||
|
||||
from ironic.common import exception
|
||||
from ironic.common.glance_service import base_image_service
|
||||
from ironic.common.glance_service import image_service
|
||||
from ironic.common import pxe_utils
|
||||
from ironic.common import states
|
||||
from ironic.common import utils
|
||||
@ -1126,8 +1126,7 @@ class PXEInterfacesTestCase(db_base.DbTestCase):
|
||||
self.assertRaises(exception.MissingParameterValue,
|
||||
pxe_utils.get_image_info, self.node)
|
||||
|
||||
@mock.patch.object(base_image_service.BaseImageService, '_show',
|
||||
autospec=True)
|
||||
@mock.patch.object(image_service.GlanceImageService, 'show', autospec=True)
|
||||
def _test_get_instance_image_info(self, show_mock):
|
||||
properties = {'properties': {u'kernel_id': u'instance_kernel_uuid',
|
||||
u'ramdisk_id': u'instance_ramdisk_uuid'}}
|
||||
@ -1147,8 +1146,7 @@ class PXEInterfacesTestCase(db_base.DbTestCase):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=True) as task:
|
||||
image_info = pxe_utils.get_instance_image_info(task)
|
||||
show_mock.assert_called_once_with(mock.ANY, 'glance://image_uuid',
|
||||
method='get')
|
||||
show_mock.assert_called_once_with(mock.ANY, 'glance://image_uuid')
|
||||
self.assertEqual(expected_info, image_info)
|
||||
|
||||
# test with saved info
|
||||
@ -1183,8 +1181,7 @@ class PXEInterfacesTestCase(db_base.DbTestCase):
|
||||
self.assertEqual({}, image_info)
|
||||
boot_opt_mock.assert_called_once_with(task.node)
|
||||
|
||||
@mock.patch.object(base_image_service.BaseImageService, '_show',
|
||||
autospec=True)
|
||||
@mock.patch.object(image_service.GlanceImageService, 'show', autospec=True)
|
||||
def test_get_instance_image_info_whole_disk_image(self, show_mock):
|
||||
properties = {'properties': None}
|
||||
show_mock.return_value = properties
|
||||
|
@ -26,7 +26,7 @@ from ironic.common import boot_devices
|
||||
from ironic.common import boot_modes
|
||||
from ironic.common import dhcp_factory
|
||||
from ironic.common import exception
|
||||
from ironic.common.glance_service import base_image_service
|
||||
from ironic.common.glance_service import image_service
|
||||
from ironic.common import pxe_utils
|
||||
from ironic.common import states
|
||||
from ironic.common import utils as common_utils
|
||||
@ -91,8 +91,7 @@ class iPXEBootTestCase(db_base.DbTestCase):
|
||||
shared=True) as task:
|
||||
self.assertEqual(expected, task.driver.get_properties())
|
||||
|
||||
@mock.patch.object(base_image_service.BaseImageService, '_show',
|
||||
autospec=True)
|
||||
@mock.patch.object(image_service.GlanceImageService, 'show', autospec=True)
|
||||
def test_validate_good(self, mock_glance):
|
||||
mock_glance.return_value = {'properties': {'kernel_id': 'fake-kernel',
|
||||
'ramdisk_id': 'fake-initr'}}
|
||||
@ -100,16 +99,14 @@ class iPXEBootTestCase(db_base.DbTestCase):
|
||||
shared=True) as task:
|
||||
task.driver.boot.validate(task)
|
||||
|
||||
@mock.patch.object(base_image_service.BaseImageService, '_show',
|
||||
autospec=True)
|
||||
@mock.patch.object(image_service.GlanceImageService, 'show', autospec=True)
|
||||
def test_validate_good_whole_disk_image(self, mock_glance):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=True) as task:
|
||||
task.node.driver_internal_info['is_whole_disk_image'] = True
|
||||
task.driver.boot.validate(task)
|
||||
|
||||
@mock.patch.object(base_image_service.BaseImageService, '_show',
|
||||
autospec=True)
|
||||
@mock.patch.object(image_service.GlanceImageService, 'show', autospec=True)
|
||||
@mock.patch.object(noop_storage.NoopStorage, 'should_write_image',
|
||||
autospec=True)
|
||||
def test_validate_skip_check_write_image_false(self, mock_write,
|
||||
@ -178,7 +175,7 @@ class iPXEBootTestCase(db_base.DbTestCase):
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
task.driver.boot.validate, task)
|
||||
|
||||
@mock.patch.object(base_image_service.BaseImageService, '_show',
|
||||
@mock.patch.object(image_service.GlanceImageService, 'show',
|
||||
autospec=True)
|
||||
def test_validate_fail_no_image_kernel_ramdisk_props(self, mock_glance):
|
||||
mock_glance.return_value = {'properties': {}}
|
||||
@ -188,7 +185,7 @@ class iPXEBootTestCase(db_base.DbTestCase):
|
||||
task.driver.boot.validate,
|
||||
task)
|
||||
|
||||
@mock.patch.object(base_image_service.BaseImageService, '_show',
|
||||
@mock.patch.object(image_service.GlanceImageService, 'show',
|
||||
autospec=True)
|
||||
def test_validate_fail_glance_image_doesnt_exists(self, mock_glance):
|
||||
mock_glance.side_effect = exception.ImageNotFound('not found')
|
||||
@ -197,7 +194,7 @@ class iPXEBootTestCase(db_base.DbTestCase):
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
task.driver.boot.validate, task)
|
||||
|
||||
@mock.patch.object(base_image_service.BaseImageService, '_show',
|
||||
@mock.patch.object(image_service.GlanceImageService, 'show',
|
||||
autospec=True)
|
||||
def test_validate_fail_glance_conn_problem(self, mock_glance):
|
||||
exceptions = (exception.GlanceConnectionFailed('connection fail'),
|
||||
|
@ -27,7 +27,7 @@ from ironic.common import boot_devices
|
||||
from ironic.common import boot_modes
|
||||
from ironic.common import dhcp_factory
|
||||
from ironic.common import exception
|
||||
from ironic.common.glance_service import base_image_service
|
||||
from ironic.common.glance_service import image_service
|
||||
from ironic.common import pxe_utils
|
||||
from ironic.common import states
|
||||
from ironic.common import utils as common_utils
|
||||
@ -93,8 +93,7 @@ class PXEBootTestCase(db_base.DbTestCase):
|
||||
shared=True) as task:
|
||||
self.assertEqual(expected, task.driver.get_properties())
|
||||
|
||||
@mock.patch.object(base_image_service.BaseImageService, '_show',
|
||||
autospec=True)
|
||||
@mock.patch.object(image_service.GlanceImageService, 'show', autospec=True)
|
||||
def test_validate_good(self, mock_glance):
|
||||
mock_glance.return_value = {'properties': {'kernel_id': 'fake-kernel',
|
||||
'ramdisk_id': 'fake-initr'}}
|
||||
@ -102,16 +101,14 @@ class PXEBootTestCase(db_base.DbTestCase):
|
||||
shared=True) as task:
|
||||
task.driver.boot.validate(task)
|
||||
|
||||
@mock.patch.object(base_image_service.BaseImageService, '_show',
|
||||
autospec=True)
|
||||
@mock.patch.object(image_service.GlanceImageService, 'show', autospec=True)
|
||||
def test_validate_good_whole_disk_image(self, mock_glance):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=True) as task:
|
||||
task.node.driver_internal_info['is_whole_disk_image'] = True
|
||||
task.driver.boot.validate(task)
|
||||
|
||||
@mock.patch.object(base_image_service.BaseImageService, '_show',
|
||||
autospec=True)
|
||||
@mock.patch.object(image_service.GlanceImageService, 'show', autospec=True)
|
||||
@mock.patch.object(noop_storage.NoopStorage, 'should_write_image',
|
||||
autospec=True)
|
||||
def test_validate_skip_check_write_image_false(self, mock_write,
|
||||
@ -180,8 +177,7 @@ class PXEBootTestCase(db_base.DbTestCase):
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
task.driver.boot.validate, task)
|
||||
|
||||
@mock.patch.object(base_image_service.BaseImageService, '_show',
|
||||
autospec=True)
|
||||
@mock.patch.object(image_service.GlanceImageService, 'show', autospec=True)
|
||||
def test_validate_fail_no_image_kernel_ramdisk_props(self, mock_glance):
|
||||
mock_glance.return_value = {'properties': {}}
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
@ -190,8 +186,7 @@ class PXEBootTestCase(db_base.DbTestCase):
|
||||
task.driver.boot.validate,
|
||||
task)
|
||||
|
||||
@mock.patch.object(base_image_service.BaseImageService, '_show',
|
||||
autospec=True)
|
||||
@mock.patch.object(image_service.GlanceImageService, 'show', autospec=True)
|
||||
def test_validate_fail_glance_image_doesnt_exists(self, mock_glance):
|
||||
mock_glance.side_effect = exception.ImageNotFound('not found')
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
@ -199,8 +194,7 @@ class PXEBootTestCase(db_base.DbTestCase):
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
task.driver.boot.validate, task)
|
||||
|
||||
@mock.patch.object(base_image_service.BaseImageService, '_show',
|
||||
autospec=True)
|
||||
@mock.patch.object(image_service.GlanceImageService, 'show', autospec=True)
|
||||
def test_validate_fail_glance_conn_problem(self, mock_glance):
|
||||
exceptions = (exception.GlanceConnectionFailed('connection fail'),
|
||||
exception.ImageNotAuthorized('not authorized'),
|
||||
|
Loading…
x
Reference in New Issue
Block a user