Kubernetes integration with OpenStack networking
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
4.9 KiB

# Copyright (c) 2016 Mirantis, Inc.
# 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 itertools
import time
import requests
from openstack import exceptions as os_exc
from oslo_log import log as logging
from oslo_utils import excutils
from kuryr_kubernetes import clients
from kuryr_kubernetes import exceptions
from kuryr_kubernetes.handlers import base
from kuryr_kubernetes import utils
LOG = logging.getLogger(__name__)
class Retry(base.EventHandler):
"""Retries handler on failure.
`Retry` can be used to decorate another `handler` to be retried whenever
it raises any of the specified `exceptions`. If the `handler` does not
succeed within the time limit specified by `timeout`, `Retry` will
raise the exception risen by `handler`. `Retry` does not interrupt the
`handler`, so the actual time spent within a single call to `Retry` may
exceed the `timeout` depending on responsiveness of the `handler`.
`handler` is retried for the same `event` (expected backoff E(c) =
interval * 2 ** c / 2).
def __init__(self, handler, exceptions=Exception,
self._handler = handler
self._exceptions = exceptions
self._timeout = timeout
self._interval = interval
self._k8s = clients.get_kubernetes_client()
def __call__(self, event, *args, **kwargs):
start_time = time.time()
deadline = time.time() + self._timeout
for attempt in itertools.count(1):
if event.get('type') in ['MODIFIED', 'ADDED']:
obj = event.get('object')
if obj:
obj_link = utils.get_res_link(obj)
except KeyError:
LOG.debug("Unknown object, skipping: %s", obj)
except exceptions.K8sResourceNotFound:
LOG.debug("There is no need to process the "
"retry as the object %s has already "
"been deleted.", obj_link)
except (exceptions.K8sClientException,
LOG.debug("Kubernetes client error getting the "
"object. Continuing with handler "
info = {
'elapsed': time.time() - start_time
self._handler(event, *args, retry_info=info, **kwargs)
except os_exc.ConflictException as ex:
if ex.details.startswith('Quota exceeded for resources'):
with excutils.save_and_reraise_exception() as ex:
if self._sleep(deadline, attempt, ex.value):
ex.reraise = False
except self._exceptions:
with excutils.save_and_reraise_exception() as ex:
if self._sleep(deadline, attempt, ex.value):
ex.reraise = False
LOG.debug('Report handler unhealthy %s', self._handler)
except Exception:
LOG.exception('Report handler unhealthy %s', self._handler)
def _sleep(self, deadline, attempt, exception):
LOG.debug("Handler %s failed (attempt %s; %s)",
self._handler, attempt, exceptions.format_msg(exception))
interval = utils.exponential_sleep(deadline, attempt,
if not interval:
LOG.debug("Handler %s failed (attempt %s; %s), "
"timeout exceeded (%s seconds)",
self._handler, attempt, exceptions.format_msg(exception),
return 0
LOG.debug("Resumed after %s seconds. Retry handler %s", interval,
return interval