Ejemplo n.º 1
0
    def handle_signal(self, details=None):
        # ceilometer sends details like this:
        # {u'alarm_id': ID, u'previous': u'ok', u'current': u'alarm',
        #  u'reason': u'...'})
        # in this policy we currently assume that this gets called
        # only when there is an alarm. But the template writer can
        # put the policy in all the alarm notifiers (nodata, and ok).
        #
        # our watchrule has upper case states so lower() them all.
        if details is None:
            alarm_state = 'alarm'
        else:
            alarm_state = details.get('current', details.get('state',
                                                             'alarm')).lower()

        LOG.info(_LI('Alarm %(name)s, new state %(state)s'), {
            'name': self.name,
            'state': alarm_state
        })

        if alarm_state != 'alarm':
            raise resource.NoActionRequired()
        if self._cooldown_inprogress():
            LOG.info(
                _LI("%(name)s NOT performing scaling action, "
                    "cooldown %(cooldown)s"), {
                        'name': self.name,
                        'cooldown': self.properties[self.COOLDOWN]
                    })
            raise resource.NoActionRequired()

        asgn_id = self.properties[self.AUTO_SCALING_GROUP_NAME]
        group = self.stack.resource_by_refid(asgn_id)
        try:
            if group is None:
                raise exception.NotFound(
                    _('Alarm %(alarm)s could not find '
                      'scaling group named "%(group)s"') % {
                          'alarm': self.name,
                          'group': asgn_id
                      })

            LOG.info(
                _LI('%(name)s Alarm, adjusting Group %(group)s with id '
                    '%(asgn_id)s by %(filter)s'), {
                        'name': self.name,
                        'group': group.name,
                        'asgn_id': asgn_id,
                        'filter': self.properties[self.SCALING_ADJUSTMENT]
                    })
            adjustment_type = self._get_adjustement_type()
            group.adjust(self.properties[self.SCALING_ADJUSTMENT],
                         adjustment_type,
                         self.properties[self.MIN_ADJUSTMENT_STEP],
                         signal=True)

        finally:
            self._cooldown_timestamp(
                "%s : %s" % (self.properties[self.ADJUSTMENT_TYPE],
                             self.properties[self.SCALING_ADJUSTMENT]))
Ejemplo n.º 2
0
    def _check_scaling_allowed(self):
        metadata = self.metadata_get()
        # WRS: If heat-engine is killed after setting scaling_in_progress
        # and before clearing the flag, the cooldown is blocked forever.
        # scaling_date provides a way of triggering a cleanup later
        if metadata.get('scaling_in_progress'):
            sd = metadata.get('scaling_date', None)
            if sd is None:
                LOG.info(
                    "Can not perform scaling action: resource %s "
                    "is already in scaling.", self.name)
                reason = _('due to scaling activity')
                raise resource.NoActionRequired(res_name=self.name,
                                                reason=reason)
            scale_max_time = CONF.cooldown.scaling_wait_time
            if not timeutils.is_older_than(sd, scale_max_time):
                LOG.info(
                    "Can not perform scaling action: resource %s "
                    "is already in scaling.", self.name)
                reason = _('due to scaling activity')
                raise resource.NoActionRequired(res_name=self.name,
                                                reason=reason)
        try:
            # Negative values don't make sense, so they are clamped to zero
            cooldown = max(0, self.properties[self.COOLDOWN])
        except TypeError:
            # If not specified, it will be None, same as cooldown == 0
            cooldown = 0

        if cooldown != 0:
            try:
                if 'cooldown' not in metadata:
                    # Note: this is for supporting old version cooldown logic
                    if metadata:
                        last_adjust = next(six.iterkeys(metadata))
                        self._cooldown_check(cooldown, last_adjust)
                else:
                    last_adjust = next(six.iterkeys(metadata['cooldown']))
                    self._cooldown_check(cooldown, last_adjust)
            except ValueError:
                # occurs when metadata has only {scaling_in_progress: False}
                pass

        # Assumes _finished_scaling is called
        # after the scaling operation completes
        metadata['scaling_in_progress'] = True
        metadata['scaling_date'] = timeutils.utcnow().isoformat()
        self.metadata_set(metadata)
Ejemplo n.º 3
0
    def _check_scaling_allowed(self):
        metadata = self.metadata_get()
        if metadata.get('scaling_in_progress'):
            LOG.info(
                _LI("Can not perform scaling action: resource %s "
                    "is already in scaling.") % self.name)
            reason = _('due to scaling activity')
            raise resource.NoActionRequired(res_name=self.name, reason=reason)
        try:
            # Negative values don't make sense, so they are clamped to zero
            cooldown = max(0, self.properties[self.COOLDOWN])
        except TypeError:
            # If not specified, it will be None, same as cooldown == 0
            cooldown = 0

        if cooldown != 0:
            try:
                if 'cooldown' not in metadata:
                    # Note: this is for supporting old version cooldown logic
                    if metadata:
                        last_adjust = next(six.iterkeys(metadata))
                        self._cooldown_check(cooldown, last_adjust)
                else:
                    last_adjust = next(six.iterkeys(metadata['cooldown']))
                    self._cooldown_check(cooldown, last_adjust)
            except ValueError:
                # occurs when metadata has only {scaling_in_progress: False}
                pass

        # Assumes _finished_scaling is called
        # after the scaling operation completes
        metadata['scaling_in_progress'] = True
        self.metadata_set(metadata)
Ejemplo n.º 4
0
    def _check_scaling_allowed(self, cooldown):
        metadata = self.metadata_get()
        if metadata.get('scaling_in_progress'):
            LOG.info(
                "Can not perform scaling action: resource %s "
                "is already in scaling.", self.name)
            reason = _('due to scaling activity')
            raise resource.NoActionRequired(res_name=self.name, reason=reason)
        cooldown = self._sanitize_cooldown(cooldown)
        # if both cooldown and cooldown_end not in metadata
        if all(k not in metadata for k in ('cooldown', 'cooldown_end')):
            # Note: this is for supporting old version cooldown checking
            metadata.pop('scaling_in_progress', None)
            if metadata and cooldown != 0:
                last_adjust = next(six.iterkeys(metadata))
                if not timeutils.is_older_than(last_adjust, cooldown):
                    self._log_and_raise_no_action(cooldown)

        elif 'cooldown_end' in metadata:
            cooldown_end = next(six.iterkeys(metadata['cooldown_end']))
            now = timeutils.utcnow().isoformat()
            if now < cooldown_end:
                self._log_and_raise_no_action(cooldown)

        elif cooldown != 0:
            # Note: this is also for supporting old version cooldown checking
            last_adjust = next(six.iterkeys(metadata['cooldown']))
            if not timeutils.is_older_than(last_adjust, cooldown):
                self._log_and_raise_no_action(cooldown)

        # Assumes _finished_scaling is called
        # after the scaling operation completes
        metadata['scaling_in_progress'] = True
        self.metadata_set(metadata)
Ejemplo n.º 5
0
    def test_signal_no_action(self):
        test_d = {
            'Data': 'foo',
            'Reason': 'bar',
            'Status': 'SUCCESS',
            'UniqueId': '123'
        }

        self.stack = self.create_stack()
        self.stack.create()

        # mock a NoActionRequired from handle_signal()
        self.m.StubOutWithMock(generic_resource.SignalResource,
                               'handle_signal')
        generic_resource.SignalResource.handle_signal(test_d).AndRaise(
            resource.NoActionRequired())

        # _add_event should not be called.
        self.m.StubOutWithMock(generic_resource.SignalResource, '_add_event')

        self.m.ReplayAll()

        rsrc = self.stack['signal_handler']
        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
        self.assertTrue(rsrc.requires_deferred_auth)

        rsrc.signal(details=test_d)

        self.m.VerifyAll()
Ejemplo n.º 6
0
    def adjust(self, adjustment, adjustment_type=CHANGE_IN_CAPACITY,
               min_adjustment_step=None, signal=False):
        """
        Adjust the size of the scaling group if the cooldown permits.
        """
        if self._cooldown_inprogress():
            LOG.info(_LI("%(name)s NOT performing scaling adjustment, "
                         "cooldown %(cooldown)s"),
                     {'name': self.name,
                      'cooldown': self.properties[self.COOLDOWN]})
            if signal:
                raise resource.NoActionRequired()
            else:
                return

        capacity = grouputils.get_size(self)
        lower = self.properties[self.MIN_SIZE]
        upper = self.properties[self.MAX_SIZE]

        new_capacity = _calculate_new_capacity(capacity, adjustment,
                                               adjustment_type,
                                               min_adjustment_step,
                                               lower, upper)

        # send a notification before, on-error and on-success.
        notif = {
            'stack': self.stack,
            'adjustment': adjustment,
            'adjustment_type': adjustment_type,
            'capacity': capacity,
            'groupname': self.FnGetRefId(),
            'message': _("Start resizing the group %(group)s") % {
                'group': self.FnGetRefId()},
            'suffix': 'start',
        }
        notification.send(**notif)
        try:
            self.resize(new_capacity)
        except Exception as resize_ex:
            with excutils.save_and_reraise_exception():
                try:
                    notif.update({'suffix': 'error',
                                  'message': six.text_type(resize_ex),
                                  'capacity': grouputils.get_size(self),
                                  })
                    notification.send(**notif)
                except Exception:
                    LOG.exception(_LE('Failed sending error notification'))
        else:
            notif.update({
                'suffix': 'end',
                'capacity': new_capacity,
                'message': _("End resizing the group %(group)s") % {
                    'group': notif['groupname']},
            })
            notification.send(**notif)
        finally:
            self._cooldown_timestamp("%s : %s" % (adjustment_type,
                                                  adjustment))
Ejemplo n.º 7
0
 def _log_and_raise_no_action(self, cooldown):
     LOG.info(
         "Can not perform scaling action: "
         "resource %(name)s is in cooldown (%(cooldown)s).", {
             'name': self.name,
             'cooldown': cooldown
         })
     reason = _('due to cooldown, ' 'cooldown %s') % cooldown
     raise resource.NoActionRequired(res_name=self.name, reason=reason)
Ejemplo n.º 8
0
 def test_scaling_policy_adjust_no_action(self):
     t = template_format.parse(as_template)
     stack = utils.parse_stack(t, params=as_params)
     up_policy = self.create_scaling_policy(t, stack, 'my-policy')
     group = stack['my-group']
     self.patchobject(group,
                      'adjust',
                      side_effect=resource.NoActionRequired())
     self.assertRaises(resource.NoActionRequired, up_policy.handle_signal)
Ejemplo n.º 9
0
 def _cooldown_check(self, cooldown, last_adjust):
     if not timeutils.is_older_than(last_adjust, cooldown):
         LOG.info(
             _LI("Can not perform scaling action: "
                 "resource %(name)s is in cooldown (%(cooldown)s).") % {
                     'name': self.name,
                     'cooldown': cooldown
                 })
         reason = _('due to cooldown, ' 'cooldown %s') % cooldown
         raise resource.NoActionRequired(res_name=self.name, reason=reason)
Ejemplo n.º 10
0
 def test_scaling_policy_adjust_no_action(self):
     t = template_format.parse(as_template)
     stack = utils.parse_stack(t, params=as_params)
     up_policy = self.create_scaling_policy(t, stack, 'my-policy')
     group = stack['my-group']
     self.patchobject(group,
                      'adjust',
                      side_effect=resource.NoActionRequired())
     mock_fin_scaling = self.patchobject(up_policy, '_finished_scaling')
     with mock.patch.object(up_policy,
                            '_check_scaling_allowed') as mock_isa:
         self.assertRaises(resource.NoActionRequired,
                           up_policy.handle_signal)
         mock_isa.assert_called_once_with()
         mock_fin_scaling.assert_called_once_with('change_in_capacity : 1',
                                                  size_changed=False)
Ejemplo n.º 11
0
    def test_signal_no_action(self, mock_handle, mock_add):
        # Setup
        test_d = {
            'Data': 'foo',
            'Reason': 'bar',
            'Status': 'SUCCESS',
            'UniqueId': '123'
        }

        stack = self._create_stack(TEMPLATE_CFN_SIGNAL)

        mock_handle.side_effect = resource.NoActionRequired()
        rsrc = stack['signal_handler']

        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
        self.assertTrue(rsrc.requires_deferred_auth)

        # Test
        mock_add.reset_mock()  # clean up existing calls before test
        rsrc.signal(details=test_d)
        mock_handle.assert_called_once_with(test_d)
        mock_add.assert_not_called()