113 lines
4.2 KiB
Python
113 lines
4.2 KiB
Python
# Copyright (c) 2013 Mirantis Inc.
|
|
#
|
|
# 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 re
|
|
|
|
from keystoneauth1.access import service_catalog as keystone_service_catalog
|
|
from keystoneauth1 import exceptions as keystone_ex
|
|
from oslo_config import cfg
|
|
from oslo_log import log as logging
|
|
from oslo_serialization import jsonutils as json
|
|
from six.moves.urllib import parse as urlparse
|
|
|
|
from sahara import context
|
|
from sahara import exceptions as ex
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
# List of the errors, that can be retried
|
|
ERRORS_TO_RETRY = [408, 413, 429, 500, 502, 503, 504]
|
|
|
|
opts = [
|
|
cfg.IntOpt('retries_number',
|
|
default=5,
|
|
help='Number of times to retry the request to client before '
|
|
'failing'),
|
|
cfg.IntOpt('retry_after',
|
|
default=10,
|
|
help='Time between the retries to client (in seconds).')
|
|
]
|
|
|
|
retries = cfg.OptGroup(name='retries',
|
|
title='OpenStack clients calls retries')
|
|
|
|
CONF = cfg.CONF
|
|
CONF.register_group(retries)
|
|
CONF.register_opts(opts, group=retries)
|
|
|
|
|
|
def url_for(service_catalog=None, service_type='identity',
|
|
endpoint_type="internalURL"):
|
|
if not service_catalog:
|
|
service_catalog = context.current().service_catalog
|
|
try:
|
|
return keystone_service_catalog.ServiceCatalogV2(
|
|
json.loads(service_catalog)).url_for(
|
|
service_type=service_type, interface=endpoint_type,
|
|
region_name=CONF.os_region_name)
|
|
except keystone_ex.EndpointNotFound:
|
|
return keystone_service_catalog.ServiceCatalogV3(
|
|
json.loads(service_catalog)).url_for(
|
|
service_type=service_type, interface=endpoint_type,
|
|
region_name=CONF.os_region_name)
|
|
|
|
|
|
def prepare_auth_url(auth_url, version):
|
|
info = urlparse.urlparse(auth_url)
|
|
url_path = info.path.rstrip("/")
|
|
# replacing current api version to empty string
|
|
url_path = re.sub('/(v3/auth|v3|v2\.0)', '', url_path)
|
|
url_path = (url_path + "/" + version).lstrip("/")
|
|
return "%s://%s/%s" % (info[:2] + (url_path,))
|
|
|
|
|
|
def retrieve_auth_url(endpoint_type="internalURL", version=None):
|
|
if not version:
|
|
version = 'v3' if CONF.use_identity_api_v3 else 'v2.0'
|
|
ctx = context.current()
|
|
if ctx.service_catalog:
|
|
auth_url = url_for(ctx.service_catalog, 'identity', endpoint_type)
|
|
else:
|
|
auth_url = CONF.trustee.auth_url
|
|
return prepare_auth_url(auth_url, version)
|
|
|
|
|
|
def execute_with_retries(method, *args, **kwargs):
|
|
attempts = CONF.retries.retries_number + 1
|
|
while attempts > 0:
|
|
try:
|
|
return method(*args, **kwargs)
|
|
except Exception as e:
|
|
error_code = getattr(e, 'http_status', None) or getattr(
|
|
e, 'status_code', None) or getattr(e, 'code', None)
|
|
if error_code in ERRORS_TO_RETRY:
|
|
LOG.warning('Occasional error occurred during "{method}" '
|
|
'execution: {error_msg} ({error_code}). '
|
|
'Operation will be retried.'.format(
|
|
method=method.__name__,
|
|
error_msg=e,
|
|
error_code=error_code))
|
|
attempts -= 1
|
|
retry_after = getattr(e, 'retry_after', 0)
|
|
context.sleep(max(retry_after, CONF.retries.retry_after))
|
|
else:
|
|
LOG.debug('Permanent error occurred during "{method}" '
|
|
'execution: {error_msg}.'.format(
|
|
method=method.__name__, error_msg=e))
|
|
raise e
|
|
else:
|
|
attempts = CONF.retries.retries_number
|
|
raise ex.MaxRetriesExceeded(attempts, method.__name__)
|