Exemplo 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 exception.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 exception.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]
                    })
            group.adjust(self.properties[self.SCALING_ADJUSTMENT],
                         self.properties[self.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]))
Exemplo n.º 2
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(
            exception.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()
Exemplo n.º 3
0
    def adjust(self, adjustment,
               adjustment_type=sc_util.CFN_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 exception.NoActionRequired()
            else:
                return

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

        new_capacity = sc_util.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))
Exemplo n.º 4
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=exception.NoActionRequired())
     mock_fin_scaling = self.patchobject(up_policy, '_finished_scaling')
     with mock.patch.object(up_policy,
                            '_is_scaling_allowed',
                            return_value=True) as mock_isa:
         self.assertRaises(exception.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)
Exemplo n.º 5
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 = exception.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()
Exemplo n.º 6
0
    def adjust(self,
               adjustment,
               adjustment_type=sc_util.CFN_CHANGE_IN_CAPACITY,
               min_adjustment_step=None):
        """Adjust the size of the scaling group if the cooldown permits."""
        if self.status != self.COMPLETE:
            LOG.info(
                _LI("%s NOT performing scaling adjustment, "
                    "when status is not COMPLETE") % self.name)
            raise exception.NoActionRequired()

        capacity = grouputils.get_size(self)
        new_capacity = self._get_new_capacity(capacity, adjustment,
                                              adjustment_type,
                                              min_adjustment_step)
        if new_capacity == capacity:
            LOG.info(
                _LI("%s NOT performing scaling adjustment, "
                    "as there is no change in capacity.") % self.name)
            raise exception.NoActionRequired()

        if not self._is_scaling_allowed():
            LOG.info(
                _LI("%(name)s NOT performing scaling adjustment, "
                    "cooldown %(cooldown)s") % {
                        'name': self.name,
                        'cooldown': self.properties[self.COOLDOWN]
                    })
            raise exception.NoActionRequired()

        # 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',
        }
        size_changed = False
        try:
            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:
                size_changed = True
                notif.update({
                    'suffix': 'end',
                    'capacity': new_capacity,
                    'message': _("End resizing the group %(group)s") % {
                        'group': notif['groupname']
                    },
                })
                notification.send(**notif)
        except Exception:
            LOG.error(
                _LE("Error in performing scaling adjustment for"
                    "group %s.") % self.name)
            raise
        finally:
            self._finished_scaling("%s : %s" % (adjustment_type, adjustment),
                                   size_changed=size_changed)
Exemplo n.º 7
0
    def handle_signal(self, details=None):
        # Template author can use scaling policy with any of the actions
        # of an alarm (i.e alarm_actions, insufficient_data_actions) and
        # it would be actioned irrespective of the alarm state. It's
        # fair to assume that the alarm state would be the appropriate one.
        # The responsibility of using a scaling policy with desired actions
        # lies with the template author, though this is normally expected to
        # be used with 'alarm_actions'.
        #
        # We also assume that the alarm state is 'alarm' when 'details' is None
        # or no 'current'/'state' key in 'details'. Watchrule has upper case
        # states, so we lower() them. This is only used for logging the alarm
        # state.

        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
        })

        asgn_id = self.properties[self.AUTO_SCALING_GROUP_NAME]
        group = self.stack.resource_by_refid(asgn_id)

        if group is None:
            raise exception.NotFound(
                _('Alarm %(alarm)s could not find '
                  'scaling group named "%(group)s"') % {
                      'alarm': self.name,
                      'group': asgn_id
                  })

        if not self._is_scaling_allowed():
            LOG.info(
                _LI("%(name)s NOT performing scaling action, "
                    "cooldown %(cooldown)s") % {
                        'name': self.name,
                        'cooldown': self.properties[self.COOLDOWN]
                    })
            raise exception.NoActionRequired()

        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]
                })

        size_changed = False
        try:
            group.adjust(self.properties[self.SCALING_ADJUSTMENT],
                         self.properties[self.ADJUSTMENT_TYPE],
                         self.properties[self.MIN_ADJUSTMENT_STEP])
            size_changed = True
        except Exception as ex:
            if not isinstance(ex, exception.NoActionRequired):
                LOG.error(
                    _LE("Error in performing scaling adjustment with "
                        "%(name)s alarm for group %(group)s.") % {
                            'name': self.name,
                            'group': group.name
                        })
            raise
        finally:
            self._finished_scaling("%s : %s" %
                                   (self.properties[self.ADJUSTMENT_TYPE],
                                    self.properties[self.SCALING_ADJUSTMENT]),
                                   size_changed=size_changed)