# # 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. from oslo_log import log as logging import six from heat.common import exception from heat.common.i18n import _ from heat.common.i18n import _LE from heat.common.i18n import _LW from heat.engine.resources import signal_responder LOG = logging.getLogger(__name__) class BaseWaitConditionHandle(signal_responder.SignalResponder): ''' Base WaitConditionHandle resource. The main point of this class is to : - have no dependencies (so the instance can reference it) - create credentials to allow for signalling from the instance. - handle signals from the instance, validate and store result ''' properties_schema = {} WAIT_STATUSES = ( STATUS_FAILURE, STATUS_SUCCESS, ) = ( 'FAILURE', 'SUCCESS', ) def handle_create(self): super(BaseWaitConditionHandle, self).handle_create() self.resource_id_set(self._get_user_id()) def _status_ok(self, status): return status in self.WAIT_STATUSES def _metadata_format_ok(self, metadata): if sorted(tuple(six.iterkeys(metadata))) == sorted(self.METADATA_KEYS): return self._status_ok(metadata[self.STATUS]) def handle_signal(self, metadata=None): signal_reason = None if self._metadata_format_ok(metadata): rsrc_metadata = self.metadata_get(refresh=True) if metadata[self.UNIQUE_ID] in rsrc_metadata: LOG.warn(_LW("Overwriting Metadata item for id %s!"), metadata[self.UNIQUE_ID]) safe_metadata = {} for k in self.METADATA_KEYS: if k == self.UNIQUE_ID: continue safe_metadata[k] = metadata[k] rsrc_metadata.update({metadata[self.UNIQUE_ID]: safe_metadata}) self.metadata_set(rsrc_metadata) signal_reason = ('status:%s reason:%s' % (safe_metadata[self.STATUS], safe_metadata[self.REASON])) else: LOG.error(_LE("Metadata failed validation for %s"), self.name) raise ValueError(_("Metadata format invalid")) return signal_reason def get_status(self): ''' Return a list of the Status values for the handle signals ''' return [v[self.STATUS] for v in six.itervalues(self.metadata_get(refresh=True))] def get_status_reason(self, status): ''' Return a list of reasons associated with a particular status ''' return [v[self.REASON] for v in six.itervalues(self.metadata_get(refresh=True)) if v[self.STATUS] == status] class WaitConditionFailure(exception.Error): def __init__(self, wait_condition, handle): reasons = handle.get_status_reason(handle.STATUS_FAILURE) super(WaitConditionFailure, self).__init__(';'.join(reasons)) class WaitConditionTimeout(exception.Error): def __init__(self, wait_condition, handle): reasons = handle.get_status_reason(handle.STATUS_SUCCESS) vals = {'len': len(reasons), 'count': wait_condition.properties[wait_condition.COUNT]} if reasons: vals['reasons'] = ';'.join(reasons) message = (_('%(len)d of %(count)d received - %(reasons)s') % vals) else: message = (_('%(len)d of %(count)d received') % vals) super(WaitConditionTimeout, self).__init__(message)