Exemple #1
0
    def consume_in_thread(self):
        """Runs the ZmqProxy service."""
        ipc_dir = CONF.rpc_zmq_ipc_dir
        consume_in = "tcp://%s:%s" % \
            (CONF.rpc_zmq_bind_address,
             CONF.rpc_zmq_port)
        consumption_proxy = InternalContext(None)

        try:
            os.makedirs(ipc_dir)
        except os.error:
            if not os.path.isdir(ipc_dir):
                with excutils.save_and_reraise_exception():
                    LOG.error(_("Required IPC directory does not exist at"
                                " %s") % (ipc_dir, ))
        try:
            self.register(consumption_proxy,
                          consume_in,
                          zmq.PULL)
        except zmq.ZMQError:
            if os.access(ipc_dir, os.X_OK):
                with excutils.save_and_reraise_exception():
                    LOG.error(_("Permission denied to IPC directory at"
                                " %s") % (ipc_dir, ))
            with excutils.save_and_reraise_exception():
                LOG.error(_("Could not create ZeroMQ receiver daemon. "
                            "Socket may already be in use."))

        super(ZmqProxy, self).consume_in_thread()
Exemple #2
0
    def consume_in_thread(self):
        """Runs the ZmqProxy service"""
        ipc_dir = CONF.rpc_zmq_ipc_dir
        consume_in = "tcp://%s:%s" % \
            (CONF.rpc_zmq_bind_address,
             CONF.rpc_zmq_port)
        consumption_proxy = InternalContext(None)

        if not os.path.isdir(ipc_dir):
            try:
                utils.execute('mkdir', '-p', ipc_dir, run_as_root=True)
                utils.execute('chown',
                              "%s:%s" % (os.getuid(), os.getgid()),
                              ipc_dir,
                              run_as_root=True)
                utils.execute('chmod', '750', ipc_dir, run_as_root=True)
            except utils.ProcessExecutionError:
                with excutils.save_and_reraise_exception():
                    LOG.error(
                        _("Could not create IPC directory %s") % (ipc_dir, ))

        try:
            self.register(consumption_proxy,
                          consume_in,
                          zmq.PULL,
                          out_bind=True)
        except zmq.ZMQError:
            with excutils.save_and_reraise_exception():
                LOG.error(
                    _("Could not create ZeroMQ receiver daemon. "
                      "Socket may already be in use."))

        super(ZmqProxy, self).consume_in_thread()
Exemple #3
0
    def _action_recorder(self, action, expected_exceptions=tuple()):
        '''Return a context manager to record the progress of an action.

        Upon entering the context manager, the state is set to IN_PROGRESS.
        Upon exiting, the state will be set to COMPLETE if no exception was
        raised, or FAILED otherwise. Non-exit exceptions will be translated
        to ResourceFailure exceptions.

        Expected exceptions are re-raised, with the Resource left in the
        IN_PROGRESS state.
        '''
        try:
            self.state_set(action, self.IN_PROGRESS)
            yield
        except expected_exceptions as ex:
            with excutils.save_and_reraise_exception():
                LOG.debug('%s', six.text_type(ex))
        except Exception as ex:
            LOG.info('%(action)s: %(info)s', {
                "action": action,
                "info": str(self)
            },
                     exc_info=True)
            failure = exception.ResourceFailure(ex, self, action)
            self.state_set(action, self.FAILED, six.text_type(failure))
            raise failure
        except:  # noqa
            with excutils.save_and_reraise_exception():
                try:
                    self.state_set(action, self.FAILED, '%s aborted' % action)
                except Exception:
                    LOG.exception(_('Error marking resource as failed'))
        else:
            self.state_set(action, self.COMPLETE)
Exemple #4
0
    def consume_in_thread(self):
        """Runs the ZmqProxy service."""
        ipc_dir = CONF.rpc_zmq_ipc_dir
        consume_in = "tcp://%s:%s" % \
            (CONF.rpc_zmq_bind_address,
             CONF.rpc_zmq_port)
        consumption_proxy = InternalContext(None)

        try:
            os.makedirs(ipc_dir)
        except os.error:
            if not os.path.isdir(ipc_dir):
                with excutils.save_and_reraise_exception():
                    LOG.error(
                        _("Required IPC directory does not exist at"
                          " %s") % (ipc_dir, ))
        try:
            self.register(consumption_proxy, consume_in, zmq.PULL)
        except zmq.ZMQError:
            if os.access(ipc_dir, os.X_OK):
                with excutils.save_and_reraise_exception():
                    LOG.error(
                        _("Permission denied to IPC directory at"
                          " %s") % (ipc_dir, ))
            with excutils.save_and_reraise_exception():
                LOG.error(
                    _("Could not create ZeroMQ receiver daemon. "
                      "Socket may already be in use."))

        super(ZmqProxy, self).consume_in_thread()
Exemple #5
0
    def _action_recorder(self, action, expected_exceptions=tuple()):
        """Return a context manager to record the progress of an action.

        Upon entering the context manager, the state is set to IN_PROGRESS.
        Upon exiting, the state will be set to COMPLETE if no exception was
        raised, or FAILED otherwise. Non-exit exceptions will be translated
        to ResourceFailure exceptions.

        Expected exceptions are re-raised, with the Resource left in the
        IN_PROGRESS state.
        """
        try:
            self.state_set(action, self.IN_PROGRESS)
            yield
        except expected_exceptions as ex:
            with excutils.save_and_reraise_exception():
                LOG.debug("%s", six.text_type(ex))
        except Exception as ex:
            LOG.exception("%s: %s" % (action, str(self)))  # noqa
            failure = exception.ResourceFailure(ex, self, action)
            self.state_set(action, self.FAILED, six.text_type(failure))
            raise failure
        except:  # noqa
            with excutils.save_and_reraise_exception():
                try:
                    self.state_set(action, self.FAILED, "%s aborted" % action)
                except Exception:
                    LOG.exception(_("Error marking resource as failed"))
        else:
            self.state_set(action, self.COMPLETE)
Exemple #6
0
    def create(self):
        '''
        Create the resource. Subclasses should provide a handle_create() method
        to customise creation.
        '''
        assert self.state is None, 'Resource create requested in invalid state'

        logger.info('creating %s' % str(self))

        # Re-resolve the template, since if the resource Ref's
        # the AWS::StackId pseudo parameter, it will change after
        # the parser.Stack is stored (which is after the resources
        # are __init__'d, but before they are create()'d)
        self.t = self.stack.resolve_static_data(self.json_snippet)
        self.properties = Properties(self.properties_schema,
                                     self.t.get('Properties', {}),
                                     self.stack.resolve_runtime_data,
                                     self.name)
        try:
            self.properties.validate()
            self.state_set(self.CREATE_IN_PROGRESS)
            create_data = None
            if callable(getattr(self, 'handle_create', None)):
                create_data = self.handle_create()
                yield
            while not self.check_create_complete(create_data):
                yield
        except greenlet.GreenletExit:
            # Older versions of greenlet erroneously had GreenletExit inherit
            # from Exception instead of BaseException
            with excutils.save_and_reraise_exception():
                try:
                    self.state_set(self.CREATE_FAILED, 'Creation aborted')
                except Exception:
                    logger.exception('Error marking resource as failed')
        except Exception as ex:
            logger.exception('create %s', str(self))
            failure = exception.ResourceFailure(ex)
            self.state_set(self.CREATE_FAILED, str(failure))
            raise failure
        except:
            with excutils.save_and_reraise_exception():
                try:
                    self.state_set(self.CREATE_FAILED, 'Creation aborted')
                except Exception:
                    logger.exception('Error marking resource as failed')
        else:
            self.state_set(self.CREATE_COMPLETE)
Exemple #7
0
    def create(self):
        '''
        Create the resource. Subclasses should provide a handle_create() method
        to customise creation.
        '''
        assert self.state is None, 'Resource create requested in invalid state'

        logger.info('creating %s' % str(self))

        # Re-resolve the template, since if the resource Ref's
        # the AWS::StackId pseudo parameter, it will change after
        # the parser.Stack is stored (which is after the resources
        # are __init__'d, but before they are create()'d)
        self.t = self.stack.resolve_static_data(self.json_snippet)
        self.properties = Properties(self.properties_schema,
                                     self.t.get('Properties', {}),
                                     self.stack.resolve_runtime_data,
                                     self.name)
        try:
            self.properties.validate()
            self.state_set(self.CREATE_IN_PROGRESS)
            create_data = None
            if callable(getattr(self, 'handle_create', None)):
                create_data = self.handle_create()
                yield
            while not self.check_create_complete(create_data):
                yield
        except greenlet.GreenletExit:
            # Older versions of greenlet erroneously had GreenletExit inherit
            # from Exception instead of BaseException
            with excutils.save_and_reraise_exception():
                try:
                    self.state_set(self.CREATE_FAILED, 'Creation aborted')
                except Exception:
                    logger.exception('Error marking resource as failed')
        except Exception as ex:
            logger.exception('create %s', str(self))
            failure = exception.ResourceFailure(ex)
            self.state_set(self.CREATE_FAILED, str(failure))
            raise failure
        except:
            with excutils.save_and_reraise_exception():
                try:
                    self.state_set(self.CREATE_FAILED, 'Creation aborted')
                except Exception:
                    logger.exception('Error marking resource as failed')
        else:
            self.state_set(self.CREATE_COMPLETE)
Exemple #8
0
    def handle_create(self):
        """Allocate a floating IP for the current tenant."""
        ips = None
        if self.properties[self.DOMAIN]:
            from heat.engine.resources.internet_gateway import InternetGateway

            ext_net = InternetGateway.get_external_network_id(self.neutron())
            props = {'floating_network_id': ext_net}
            ips = self.neutron().create_floatingip({
                'floatingip': props})['floatingip']
            self.ipaddress = ips['floating_ip_address']
            self.resource_id_set(ips['id'])
            LOG.info(_('ElasticIp create %s') % str(ips))
        else:
            try:
                ips = self.nova().floating_ips.create()
            except Exception as e:
                with excutils.save_and_reraise_exception():
                    if self.client_plugin('nova').is_not_found(e):
                        msg = _("No default floating IP pool configured. "
                                "Set 'default_floating_pool' in nova.conf.")
                        LOG.error(msg)

            if ips:
                self.ipaddress = ips.ip
                self.resource_id_set(ips.id)
                LOG.info(_('ElasticIp create %s') % str(ips))

        instance_id = self.properties[self.INSTANCE_ID]
        if instance_id:
            server = self.nova().servers.get(instance_id)
            server.add_floating_ip(self._ipaddress())
Exemple #9
0
    def handle_create(self):
        """Allocate a floating IP for the current tenant."""
        ips = None
        if self.properties[self.DOMAIN]:
            from heat.engine.resources.internet_gateway import InternetGateway

            ext_net = InternetGateway.get_external_network_id(self.neutron())
            props = {'floating_network_id': ext_net}
            ips = self.neutron().create_floatingip({'floatingip':
                                                    props})['floatingip']
            self.ipaddress = ips['floating_ip_address']
            self.resource_id_set(ips['id'])
            LOG.info(_('ElasticIp create %s') % str(ips))
        else:
            try:
                ips = self.nova().floating_ips.create()
            except Exception as e:
                with excutils.save_and_reraise_exception():
                    if self.client_plugin('nova').is_not_found(e):
                        msg = _("No default floating IP pool configured. "
                                "Set 'default_floating_pool' in nova.conf.")
                        LOG.error(msg)

            if ips:
                self.ipaddress = ips.ip
                self.resource_id_set(ips.id)
                LOG.info(_('ElasticIp create %s') % str(ips))

        instance_id = self.properties[self.INSTANCE_ID]
        if instance_id:
            server = self.nova().servers.get(instance_id)
            server.add_floating_ip(self._ipaddress())
Exemple #10
0
    def __call__(self):
        """Return a co-routine which runs the task group."""
        raised_exceptions = []
        while any(self._runners.itervalues()):
            try:
                for k, r in self._ready():
                    r.start()

                yield

                for k, r in self._running():
                    if r.step():
                        del self._graph[k]
            except Exception:
                exc_info = sys.exc_info()
                if self.aggregate_exceptions:
                    self._cancel_recursively(k, r)
                else:
                    self.cancel_all(grace_period=self.error_wait_time)
                raised_exceptions.append(exc_info)
            except:  # noqa
                with excutils.save_and_reraise_exception():
                    self.cancel_all()

        if raised_exceptions:
            if self.aggregate_exceptions:
                raise ExceptionGroup(v for t, v, tb in raised_exceptions)
            else:
                exc_type, exc_val, traceback = raised_exceptions[0]
                raise exc_type, exc_val, traceback
Exemple #11
0
    def _start_thread_with_lock(self, cnxt, stack, func, *args):
        """
        Try to acquire a stack lock and, if successful, run the method in a
        sub-thread.

        :param cnxt: RPC context
        :param stack: Stack to be operated on
        :type stack: heat.engine.parser.Stack
        :param func: Callable to be invoked in sub-thread
        :type func: function or instancemethod
        :param args: Args to be passed to func
        """
        lock = stack_lock.StackLock(cnxt, stack)

        def release(gt, *args, **kwargs):
            """
            Callback function that will be passed to GreenThread.link().
            """
            lock.release()

        lock.acquire()
        try:
            th = self._start_in_thread(stack.id, func, *args)
            th.link(release)
        except:
            with excutils.save_and_reraise_exception():
                lock.release()
Exemple #12
0
    def adjust(self, adjustment, adjustment_type=CHANGE_IN_CAPACITY):
        """
        Adjust the size of the scaling group if the cooldown permits.
        """
        if self._cooldown_inprogress():
            LOG.info(
                _("%(name)s NOT performing scaling adjustment, "
                  "cooldown %(cooldown)s") % {
                      'name': self.name,
                      'cooldown': self.properties[self.COOLDOWN]
                  })
            return

        capacity = len(self.get_instances())
        lower = self.properties[self.MIN_SIZE]
        upper = self.properties[self.MAX_SIZE]

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

        if new_capacity == capacity:
            LOG.debug('no change in capacity %d' % capacity)
            return

        # 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),
                    })
                    notification.send(**notif)
                except Exception:
                    LOG.exception(_('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)

        self._cooldown_timestamp("%s : %s" % (adjustment_type, adjustment))
Exemple #13
0
    def delete(self):
        """
        Delete the resource. Subclasses should provide a handle_delete() method
        to customise deletion.
        """
        if self.state == self.DELETE_COMPLETE:
            return
        if self.state == self.DELETE_IN_PROGRESS:
            raise exception.Error("Resource deletion already in progress")
        # No need to delete if the resource has never been created
        if self.state is None:
            return

        logger.info("deleting %s" % str(self))

        try:
            self.state_set(self.DELETE_IN_PROGRESS)

            if callable(getattr(self, "handle_delete", None)):
                self.handle_delete()
        except Exception as ex:
            logger.exception("Delete %s", str(self))
            failure = exception.ResourceFailure(ex)
            self.state_set(self.DELETE_FAILED, str(failure))
            raise failure
        except:
            with excutils.save_and_reraise_exception():
                try:
                    self.state_set(self.DELETE_FAILED, "Deletion aborted")
                except Exception:
                    logger.exception("Error marking resource deletion failed")
        else:
            self.state_set(self.DELETE_COMPLETE)
Exemple #14
0
    def handle_create(self):
        """Allocate a floating IP for the current tenant."""
        ips = None
        if self.properties['Domain'] and clients.neutronclient:
            from heat.engine.resources.internet_gateway import InternetGateway

            ext_net = InternetGateway.get_external_network_id(self.neutron())
            props = {'floating_network_id': ext_net}
            ips = self.neutron().create_floatingip({
                'floatingip': props})['floatingip']
            self.ipaddress = ips['floating_ip_address']
            self.resource_id_set(ips['id'])
            logger.info('ElasticIp create %s' % str(ips))
        else:
            if self.properties['Domain']:
                raise exception.Error('Domain property can not be set on '
                                      'resource %s without Neutron available' %
                                      self.name)
            try:
                ips = self.nova().floating_ips.create()
            except clients.novaclient.exceptions.NotFound:
                with excutils.save_and_reraise_exception():
                    msg = ("No default floating IP pool configured."
                           "Set 'default_floating_pool' in nova.conf.")
                    logger.error(msg)

            if ips:
                self.ipaddress = ips.ip
                self.resource_id_set(ips.id)
                logger.info('ElasticIp create %s' % str(ips))

        if self.properties['InstanceId']:
            server = self.nova().servers.get(self.properties['InstanceId'])
            res = server.add_floating_ip(self._ipaddress())
Exemple #15
0
    def start_with_acquired_lock(self, stack, lock, func, *args, **kwargs):
        """
        Run the given method in a sub-thread and release the provided lock
        when the thread finishes.

        :param stack: Stack to be operated on
        :type stack: heat.engine.parser.Stack
        :param lock: The acquired stack lock
        :type lock: heat.engine.stack_lock.StackLock
        :param func: Callable to be invoked in sub-thread
        :type func: function or instancemethod
        :param args: Args to be passed to func
        :param kwargs: Keyword-args to be passed to func

        """
        def release(gt, *args):
            """
            Callback function that will be passed to GreenThread.link().
            """
            lock.release(*args)

        try:
            th = self.start(stack.id, func, *args, **kwargs)
            th.link(release, stack.id)
        except:
            with excutils.save_and_reraise_exception():
                lock.release(stack.id)
Exemple #16
0
    def handle_create(self):
        """Allocate a floating IP for the current tenant."""
        ips = None
        if self.properties[self.DOMAIN] and clients.neutronclient:
            from heat.engine.resources.internet_gateway import InternetGateway

            ext_net = InternetGateway.get_external_network_id(self.neutron())
            props = {'floating_network_id': ext_net}
            ips = self.neutron().create_floatingip({'floatingip':
                                                    props})['floatingip']
            self.ipaddress = ips['floating_ip_address']
            self.resource_id_set(ips['id'])
            logger.info(_('ElasticIp create %s') % str(ips))
        else:
            if self.properties[self.DOMAIN]:
                raise exception.Error(
                    _('Domain property can not be set on '
                      'resource %s without Neutron available') % self.name)
            try:
                ips = self.nova().floating_ips.create()
            except clients.novaclient.exceptions.NotFound:
                with excutils.save_and_reraise_exception():
                    msg = _("No default floating IP pool configured. "
                            "Set 'default_floating_pool' in nova.conf.")
                    logger.error(msg)

            if ips:
                self.ipaddress = ips.ip
                self.resource_id_set(ips.id)
                logger.info(_('ElasticIp create %s') % str(ips))

        instance_id = self.properties[self.INSTANCE_ID]
        if instance_id:
            server = self.nova().servers.get(instance_id)
            server.add_floating_ip(self._ipaddress())
Exemple #17
0
    def __call__(self):
        """Return a co-routine which runs the task group."""
        raised_exceptions = []
        while any(self._runners.itervalues()):
            try:
                for k, r in self._ready():
                    r.start()

                yield

                for k, r in self._running():
                    if r.step():
                        del self._graph[k]
            except Exception:
                exc_info = sys.exc_info()
                if self.aggregate_exceptions:
                    self._cancel_recursively(k, r)
                else:
                    self.cancel_all(grace_period=self.error_wait_time)
                raised_exceptions.append(exc_info)
            except:  # noqa
                with excutils.save_and_reraise_exception():
                    self.cancel_all()

        if raised_exceptions:
            if self.aggregate_exceptions:
                raise ExceptionGroup(v for t, v, tb in raised_exceptions)
            else:
                exc_type, exc_val, traceback = raised_exceptions[0]
                raise exc_type, exc_val, traceback
Exemple #18
0
    def __call__(self):
        """Return a co-routine which runs the task group."""
        raised_exceptions = []
        try:
            while any(self._runners.itervalues()):
                try:
                    for k, r in self._ready():
                        r.start()

                    yield

                    for k, r in self._running():
                        if r.step():
                            del self._graph[k]
                except Exception as e:
                    self._cancel_recursively(k, r)
                    if not self.aggregate_exceptions:
                        raise
                    raised_exceptions.append(e)
        except:
            with excutils.save_and_reraise_exception():
                for r in self._runners.itervalues():
                    r.cancel()

        if raised_exceptions:
            raise ExceptionGroup(raised_exceptions)
Exemple #19
0
    def abandon_stack(self, cnxt, stack_identity):
        """
        The abandon_stack method abandons a given stack.
        :param cnxt: RPC context.
        :param stack_identity: Name of the stack you want to abandon.
        """
        st = self._get_stack(cnxt, stack_identity)
        logger.info(_('abandoning stack %s') % st.name)
        stack = parser.Stack.load(cnxt, stack=st)
        lock = stack_lock.StackLock(cnxt, stack, self.engine_id)
        acquire_result = lock.try_acquire()

        # If an action is in progress, 'try_acquire' returns engine UUID. If
        # the returned engine is alive, then throw ActionInProgress exception
        if (acquire_result and
                (acquire_result == self.engine_id or
                 stack_lock.StackLock.engine_alive(cnxt, acquire_result))):
            raise exception.ActionInProgress(stack_name=stack.name,
                                             action=stack.action)

        try:
            # Get stack details before deleting it.
            stack_info = stack.get_abandon_data()
            # Set deletion policy to 'Retain' for all resources in the stack.
            stack.set_deletion_policy(resource.RETAIN)
        except:
            with excutils.save_and_reraise_exception():
                lock.release(stack.id)

        self.thread_group_mgr.start_with_acquired_lock(stack,
                                                       lock,
                                                       stack.delete)
        return stack_info
Exemple #20
0
    def abandon_stack(self, cnxt, stack_identity):
        """
        The abandon_stack method abandons a given stack.
        :param cnxt: RPC context.
        :param stack_identity: Name of the stack you want to abandon.
        """
        st = self._get_stack(cnxt, stack_identity)
        logger.info(_('abandoning stack %s') % st.name)
        stack = parser.Stack.load(cnxt, stack=st)
        lock = stack_lock.StackLock(cnxt, stack, self.engine_id)
        acquire_result = lock.try_acquire()

        # If an action is in progress, 'try_acquire' returns engine UUID. If
        # the returned engine is alive, then throw ActionInProgress exception
        if (acquire_result and
            (acquire_result == self.engine_id
             or stack_lock.StackLock.engine_alive(cnxt, acquire_result))):
            raise exception.ActionInProgress(stack_name=stack.name,
                                             action=stack.action)

        try:
            # Get stack details before deleting it.
            stack_info = stack.prepare_abandon()
        except:
            with excutils.save_and_reraise_exception():
                lock.release(stack.id)

        self.thread_group_mgr.start_with_acquired_lock(stack, lock,
                                                       stack.delete)
        return stack_info
Exemple #21
0
    def handle_create(self):
        """Allocate a floating IP for the current tenant."""
        ips = None
        if self.properties[self.DOMAIN] and clients.neutronclient:
            from heat.engine.resources.internet_gateway import InternetGateway

            ext_net = InternetGateway.get_external_network_id(self.neutron())
            props = {"floating_network_id": ext_net}
            ips = self.neutron().create_floatingip({"floatingip": props})["floatingip"]
            self.ipaddress = ips["floating_ip_address"]
            self.resource_id_set(ips["id"])
            LOG.info(_("ElasticIp create %s") % str(ips))
        else:
            if self.properties[self.DOMAIN]:
                raise exception.Error(
                    _("Domain property can not be set on " "resource %s without Neutron available") % self.name
                )
            try:
                ips = self.nova().floating_ips.create()
            except clients.novaclient.exceptions.NotFound:
                with excutils.save_and_reraise_exception():
                    msg = _("No default floating IP pool configured. " "Set 'default_floating_pool' in nova.conf.")
                    LOG.error(msg)

            if ips:
                self.ipaddress = ips.ip
                self.resource_id_set(ips.id)
                LOG.info(_("ElasticIp create %s") % str(ips))

        instance_id = self.properties[self.INSTANCE_ID]
        if instance_id:
            server = self.nova().servers.get(instance_id)
            server.add_floating_ip(self._ipaddress())
Exemple #22
0
    def __call__(self):
        """Return a co-routine which runs the task group."""
        raised_exceptions = []
        try:
            while any(self._runners.itervalues()):
                try:
                    for k, r in self._ready():
                        r.start()

                    yield

                    for k, r in self._running():
                        if r.step():
                            del self._graph[k]
                except Exception as e:
                    self._cancel_recursively(k, r)
                    if not self.aggregate_exceptions:
                        raise
                    raised_exceptions.append(e)
        except:  # noqa
            with excutils.save_and_reraise_exception():
                for r in self._runners.itervalues():
                    r.cancel()

        if raised_exceptions:
            raise ExceptionGroup(raised_exceptions)
Exemple #23
0
    def start_with_acquired_lock(self, stack, lock, func, *args, **kwargs):
        """
        Run the given method in a sub-thread and release the provided lock
        when the thread finishes.

        :param stack: Stack to be operated on
        :type stack: heat.engine.parser.Stack
        :param lock: The acquired stack lock
        :type lock: heat.engine.stack_lock.StackLock
        :param func: Callable to be invoked in sub-thread
        :type func: function or instancemethod
        :param args: Args to be passed to func
        :param kwargs: Keyword-args to be passed to func

        """
        def release(gt, *args, **kwargs):
            """
            Callback function that will be passed to GreenThread.link().
            """
            lock.release(*args)

        try:
            th = self.start(stack.id, func, *args)
            th.link(release, stack.id)
        except:
            with excutils.save_and_reraise_exception():
                lock.release(stack.id)
Exemple #24
0
    def update(self, after, before=None, prev_resource=None):
        '''
        update the resource. Subclasses should provide a handle_update() method
        to customise update, the base-class handle_update will fail by default.
        '''
        action = self.UPDATE

        (cur_class_def, cur_ver) = self.implementation_signature()
        prev_ver = cur_ver
        if prev_resource is not None:
            (prev_class_def,
             prev_ver) = prev_resource.implementation_signature()
            if prev_class_def != cur_class_def:
                raise UpdateReplace(self.name)

        if before is None:
            before = self.parsed_template()
        if prev_ver == cur_ver and before == after:
            return

        if (self.action, self.status) in ((self.CREATE, self.IN_PROGRESS),
                                          (self.UPDATE, self.IN_PROGRESS),
                                          (self.ADOPT, self.IN_PROGRESS)):
            exc = Exception(_('Resource update already requested'))
            raise exception.ResourceFailure(exc, self, action)

        logger.info('updating %s' % str(self))

        try:
            self.updated_time = datetime.utcnow()
            self.state_set(action, self.IN_PROGRESS)
            properties = Properties(self.properties_schema,
                                    after.get('Properties', {}),
                                    self._resolve_runtime_data,
                                    self.name,
                                    self.context)
            properties.validate()
            tmpl_diff = self.update_template_diff(after, before)
            prop_diff = self.update_template_diff_properties(after, before)
            if callable(getattr(self, 'handle_update', None)):
                handle_data = self.handle_update(after, tmpl_diff, prop_diff)
                yield
                if callable(getattr(self, 'check_update_complete', None)):
                    while not self.check_update_complete(handle_data):
                        yield
        except UpdateReplace:
            with excutils.save_and_reraise_exception():
                logger.debug(_("Resource %s update requires replacement") %
                             self.name)
        except Exception as ex:
            logger.exception('update %s : %s' % (str(self), str(ex)))
            failure = exception.ResourceFailure(ex, self, action)
            self.state_set(action, self.FAILED, str(failure))
            raise failure
        else:
            self.json_snippet = copy.deepcopy(after)
            self.reparse()
            self.state_set(action, self.COMPLETE)
Exemple #25
0
    def update(self, after, before=None, prev_resource=None):
        '''
        update the resource. Subclasses should provide a handle_update() method
        to customise update, the base-class handle_update will fail by default.
        '''
        action = self.UPDATE

        (cur_class_def, cur_ver) = self.implementation_signature()
        prev_ver = cur_ver
        if prev_resource is not None:
            (prev_class_def,
             prev_ver) = prev_resource.implementation_signature()
            if prev_class_def != cur_class_def:
                raise UpdateReplace(self.name)

        if before is None:
            before = self.parsed_template()
        if prev_ver == cur_ver and before == after:
            return

        if (self.action, self.status) in ((self.CREATE, self.IN_PROGRESS),
                                          (self.UPDATE, self.IN_PROGRESS),
                                          (self.ADOPT, self.IN_PROGRESS)):
            exc = Exception(_('Resource update already requested'))
            raise exception.ResourceFailure(exc, self, action)

        logger.info('updating %s' % str(self))

        try:
            self.updated_time = datetime.utcnow()
            self.state_set(action, self.IN_PROGRESS)
            properties = Properties(self.properties_schema,
                                    after.get('Properties', {}),
                                    self._resolve_runtime_data,
                                    self.name,
                                    self.context)
            properties.validate()
            tmpl_diff = self.update_template_diff(after, before)
            prop_diff = self.update_template_diff_properties(after, before)
            if callable(getattr(self, 'handle_update', None)):
                handle_data = self.handle_update(after, tmpl_diff, prop_diff)
                yield
                if callable(getattr(self, 'check_update_complete', None)):
                    while not self.check_update_complete(handle_data):
                        yield
        except UpdateReplace:
            with excutils.save_and_reraise_exception():
                logger.debug(_("Resource %s update requires replacement") %
                             self.name)
        except Exception as ex:
            logger.exception('update %s : %s' % (str(self), str(ex)))
            failure = exception.ResourceFailure(ex, self, action)
            self.state_set(action, self.FAILED, str(failure))
            raise failure
        else:
            self.json_snippet = copy.deepcopy(after)
            self.reparse()
            self.state_set(action, self.COMPLETE)
Exemple #26
0
    def adjust(self, adjustment, adjustment_type=CHANGE_IN_CAPACITY):
        """
        Adjust the size of the scaling group if the cooldown permits.
        """
        if self._cooldown_inprogress():
            LOG.info(_("%(name)s NOT performing scaling adjustment, "
                       "cooldown %(cooldown)s")
                     % {'name': self.name,
                        'cooldown': self.properties[self.COOLDOWN]})
            return

        capacity = len(self.get_instances())
        lower = self.properties[self.MIN_SIZE]
        upper = self.properties[self.MAX_SIZE]

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

        if new_capacity == capacity:
            LOG.debug('no change in capacity %d' % capacity)
            return

        # 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),
                                  })
                    notification.send(**notif)
                except Exception:
                    LOG.exception(_('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)

        self._cooldown_timestamp("%s : %s" % (adjustment_type, adjustment))
Exemple #27
0
    def delete(self):
        '''
        Delete the resource. Subclasses should provide a handle_delete() method
        to customise deletion.
        '''
        action = self.DELETE

        if (self.action, self.status) == (self.DELETE, self.COMPLETE):
            return
        # No need to delete if the resource has never been created
        if self.action == self.INIT:
            return

        initial_state = self.state

        logger.info(_('deleting %s') % str(self))

        try:
            self.state_set(action, self.IN_PROGRESS)

            if self.abandon_in_progress:
                deletion_policy = RETAIN
            else:
                deletion_policy = self.t.get('DeletionPolicy', DELETE)
            handle_data = None
            if deletion_policy == DELETE:
                if callable(getattr(self, 'handle_delete', None)):
                    handle_data = self.handle_delete()
                    yield
            elif deletion_policy == SNAPSHOT:
                if callable(getattr(self, 'handle_snapshot_delete', None)):
                    handle_data = self.handle_snapshot_delete(initial_state)
                    yield

            if (deletion_policy != RETAIN and callable(
                    getattr(self, 'check_delete_complete', None))):
                while not self.check_delete_complete(handle_data):
                    yield

        except Exception as ex:
            logger.exception(_('Delete %s') % str(self))
            failure = exception.ResourceFailure(ex, self, self.action)
            self.state_set(action, self.FAILED, six.text_type(failure))
            raise failure
        except:
            with excutils.save_and_reraise_exception():
                try:
                    self.state_set(action, self.FAILED, 'Deletion aborted')
                except Exception:
                    logger.exception(
                        _('Error marking resource deletion '
                          'failed'))
        else:
            self.state_set(action, self.COMPLETE)
Exemple #28
0
    def delete(self):
        '''
        Delete the resource. Subclasses should provide a handle_delete() method
        to customise deletion.
        '''
        action = self.DELETE

        if (self.action, self.status) == (self.DELETE, self.COMPLETE):
            return
        # No need to delete if the resource has never been created
        if self.action == self.INIT:
            return

        initial_state = self.state

        logger.info(_('deleting %s') % str(self))

        try:
            self.state_set(action, self.IN_PROGRESS)

            if self.abandon_in_progress:
                deletion_policy = RETAIN
            else:
                deletion_policy = self.t.get('DeletionPolicy', DELETE)
            handle_data = None
            if deletion_policy == DELETE:
                if callable(getattr(self, 'handle_delete', None)):
                    handle_data = self.handle_delete()
                    yield
            elif deletion_policy == SNAPSHOT:
                if callable(getattr(self, 'handle_snapshot_delete', None)):
                    handle_data = self.handle_snapshot_delete(initial_state)
                    yield

            if (deletion_policy != RETAIN and
                    callable(getattr(self, 'check_delete_complete', None))):
                while not self.check_delete_complete(handle_data):
                    yield

        except Exception as ex:
            logger.exception(_('Delete %s') % str(self))
            failure = exception.ResourceFailure(ex, self, self.action)
            self.state_set(action, self.FAILED, six.text_type(failure))
            raise failure
        except:
            with excutils.save_and_reraise_exception():
                try:
                    self.state_set(action, self.FAILED,
                                   'Deletion aborted')
                except Exception:
                    logger.exception(_('Error marking resource deletion '
                                     'failed'))
        else:
            self.state_set(action, self.COMPLETE)
Exemple #29
0
def _serialize(data):
    """Serialization wrapper.

    We prefer using JSON, but it cannot encode all types.
    Error if a developer passes us bad data.
    """
    try:
        return jsonutils.dumps(data, ensure_ascii=True)
    except TypeError:
        with excutils.save_and_reraise_exception():
            LOG.error(_("JSON serialization failed."))
Exemple #30
0
def remove_path_on_error(path):
    """Protect code that wants to operate on PATH atomically.
    Any exception will cause PATH to be removed.

    :param path: File to work with
    """
    try:
        yield
    except Exception:
        with excutils.save_and_reraise_exception():
            delete_if_exists(path)
Exemple #31
0
def _serialize(data):
    """Serialization wrapper.

    We prefer using JSON, but it cannot encode all types.
    Error if a developer passes us bad data.
    """
    try:
        return jsonutils.dumps(data, ensure_ascii=True)
    except TypeError:
        with excutils.save_and_reraise_exception():
            LOG.error(_("JSON serialization failed."))
Exemple #32
0
 def thread_lock(self, stack_id):
     """
     Acquire a lock and release it only if there is an exception.  The
     release method still needs to be scheduled to be run at the
     end of the thread using the Thread.link method.
     """
     try:
         self.acquire()
         yield
     except:  # noqa
         with excutils.save_and_reraise_exception():
             self.release(stack_id)
Exemple #33
0
 def thread_lock(self, stack_id):
     """
     Acquire a lock and release it only if there is an exception.  The
     release method still needs to be scheduled to be run at the
     end of the thread using the Thread.link method.
     """
     try:
         self.acquire()
         yield
     except:
         with excutils.save_and_reraise_exception():
             self.release(stack_id)
    def handle_create(self):
        try:
            pool = self.properties.get(self.POOL)
            floating_ip = self.nova().floating_ips.create(pool=pool)
        except clients.novaclient.exceptions.NotFound:
            with excutils.save_and_reraise_exception():
                if pool is None:
                    msg = _('Could not allocate floating IP. Probably there '
                            'is no default floating IP pool is configured.')
                    logger.error(msg)

        self.resource_id_set(floating_ip.id)
        self._floating_ip = floating_ip
Exemple #35
0
    def handle_create(self):
        try:
            pool = self.properties.get(self.POOL)
            floating_ip = self.nova().floating_ips.create(pool=pool)
        except clients.novaclient.exceptions.NotFound:
            with excutils.save_and_reraise_exception():
                if pool is None:
                    msg = _('Could not allocate floating IP. Probably there '
                            'is no default floating IP pool is configured.')
                    LOG.error(msg)

        self.resource_id_set(floating_ip.id)
        self._floating_ip = floating_ip
Exemple #36
0
def remove_path_on_error(path, remove=delete_if_exists):
    """Protect code that wants to operate on PATH atomically.
    Any exception will cause PATH to be removed.

    :param path: File to work with
    :param remove: Optional function to remove passed path
    """

    try:
        yield
    except Exception:
        with excutils.save_and_reraise_exception():
            remove(path)
Exemple #37
0
    def consume_in_thread(self):
        """Runs the ZmqProxy service"""
        ipc_dir = CONF.rpc_zmq_ipc_dir
        consume_in = "tcp://%s:%s" % (CONF.rpc_zmq_bind_address, CONF.rpc_zmq_port)
        consumption_proxy = InternalContext(None)

        if not os.path.isdir(ipc_dir):
            try:
                utils.execute("mkdir", "-p", ipc_dir, run_as_root=True)
                utils.execute("chown", "%s:%s" % (os.getuid(), os.getgid()), ipc_dir, run_as_root=True)
                utils.execute("chmod", "750", ipc_dir, run_as_root=True)
            except utils.ProcessExecutionError:
                with excutils.save_and_reraise_exception():
                    LOG.error(_("Could not create IPC directory %s") % (ipc_dir,))

        try:
            self.register(consumption_proxy, consume_in, zmq.PULL, out_bind=True)
        except zmq.ZMQError:
            with excutils.save_and_reraise_exception():
                LOG.error(_("Could not create ZeroMQ receiver daemon. " "Socket may already be in use."))

        super(ZmqProxy, self).consume_in_thread()
Exemple #38
0
    def _do_action(self, action, pre_func=None, resource_data=None):
        '''
        Perform a transition to a new state via a specified action
        action should be e.g self.CREATE, self.UPDATE etc, we set
        status based on this, the transition is handled by calling the
        corresponding handle_* and check_*_complete functions
        Note pre_func is an optional function reference which will
        be called before the handle_<action> function

        If the resource does not declare a check_$action_complete function,
        we declare COMPLETE status as soon as the handle_$action call has
        finished, and if no handle_$action function is declared, then we do
        nothing, useful e.g if the resource requires no action for a given
        state transition
        '''
        assert action in self.ACTIONS, 'Invalid action %s' % action

        try:
            self.state_set(action, self.IN_PROGRESS)

            action_l = action.lower()
            handle = getattr(self, 'handle_%s' % action_l, None)
            check = getattr(self, 'check_%s_complete' % action_l, None)

            if callable(pre_func):
                pre_func()

            handle_data = None
            if callable(handle):
                handle_data = (handle(resource_data) if resource_data else
                               handle())
                yield
                if callable(check):
                    while not check(handle_data):
                        yield
        except Exception as ex:
            LOG.exception('%s : %s' % (action, str(self)))  # noqa
            failure = exception.ResourceFailure(ex, self, action)
            self.state_set(action, self.FAILED, six.text_type(failure))
            raise failure
        except:
            with excutils.save_and_reraise_exception():
                try:
                    self.state_set(action, self.FAILED,
                                   '%s aborted' % action)
                except Exception:
                    LOG.exception(_('Error marking resource as failed'))
        else:
            self.state_set(action, self.COMPLETE)
Exemple #39
0
    def _do_action(self, action, pre_func=None, resource_data=None):
        '''
        Perform a transition to a new state via a specified action
        action should be e.g self.CREATE, self.UPDATE etc, we set
        status based on this, the transition is handled by calling the
        corresponding handle_* and check_*_complete functions
        Note pre_func is an optional function reference which will
        be called before the handle_<action> function

        If the resource does not declare a check_$action_complete function,
        we declare COMPLETE status as soon as the handle_$action call has
        finished, and if no handle_$action function is declared, then we do
        nothing, useful e.g if the resource requires no action for a given
        state transition
        '''
        assert action in self.ACTIONS, 'Invalid action %s' % action

        try:
            self.state_set(action, self.IN_PROGRESS)

            action_l = action.lower()
            handle = getattr(self, 'handle_%s' % action_l, None)
            check = getattr(self, 'check_%s_complete' % action_l, None)

            if callable(pre_func):
                pre_func()

            handle_data = None
            if callable(handle):
                handle_data = (handle(resource_data) if resource_data else
                               handle())
                yield
                if callable(check):
                    while not check(handle_data):
                        yield
        except Exception as ex:
            logger.exception('%s : %s' % (action, str(self)))
            failure = exception.ResourceFailure(ex, self, action)
            self.state_set(action, self.FAILED, str(failure))
            raise failure
        except:
            with excutils.save_and_reraise_exception():
                try:
                    self.state_set(action, self.FAILED,
                                   '%s aborted' % action)
                except Exception:
                    logger.exception(_('Error marking resource as failed'))
        else:
            self.state_set(action, self.COMPLETE)
Exemple #40
0
    def __call__(self):
        """Return a co-routine which runs the task group."""
        runners = [TaskRunner(t) for t in self._tasks]

        try:
            for r in runners:
                r.start()

            while runners:
                yield
                runners = list(itertools.dropwhile(lambda r: r.step(), runners))
        except:
            with excutils.save_and_reraise_exception():
                for r in runners:
                    r.cancel()
Exemple #41
0
 def try_thread_lock(self, stack_id):
     """
     Similar to thread_lock, but acquire the lock using try_acquire
     and only release it upon any exception after a successful
     acquisition.
     """
     result = None
     try:
         result = self.try_acquire()
         yield result
     except:
         if result is None:  # Lock was successfully acquired
             with excutils.save_and_reraise_exception():
                 self.release(stack_id)
         raise
Exemple #42
0
    def handle_create(self):
        try:
            pool = self.properties.get(self.POOL)
            floating_ip = self.nova().floating_ips.create(pool=pool)
        except Exception as e:
            with excutils.save_and_reraise_exception():
                if self.client_plugin().is_not_found(e):
                    if pool is None:
                        msg = _('Could not allocate floating IP. Probably '
                                'there is no default floating IP pool is '
                                'configured.')
                        LOG.error(msg)

        self.resource_id_set(floating_ip.id)
        self._floating_ip = floating_ip
Exemple #43
0
    def handle_create(self):
        try:
            pool = self.properties.get(self.POOL)
            floating_ip = self.nova().floating_ips.create(pool=pool)
        except Exception as e:
            with excutils.save_and_reraise_exception():
                if self.client_plugin().is_not_found(e):
                    if pool is None:
                        msg = _('Could not allocate floating IP. Probably '
                                'there is no default floating IP pool is '
                                'configured.')
                        LOG.error(msg)

        self.resource_id_set(floating_ip.id)
        self._floating_ip = floating_ip
Exemple #44
0
 def try_thread_lock(self, stack_id):
     """
     Similar to thread_lock, but acquire the lock using try_acquire
     and only release it upon any exception after a successful
     acquisition.
     """
     result = None
     try:
         result = self.try_acquire()
         yield result
     except:  # noqa
         if result is None:  # Lock was successfully acquired
             with excutils.save_and_reraise_exception():
                 self.release(stack_id)
         raise
Exemple #45
0
    def delete(self):
        """
        Delete the resource. Subclasses should provide a handle_delete() method
        to customise deletion.
        """
        action = self.DELETE

        if (self.action, self.status) == (self.DELETE, self.COMPLETE):
            return
        # No need to delete if the resource has never been created
        if self.action == self.INIT:
            return

        initial_state = self.state

        logger.info(_("deleting %s") % str(self))

        try:
            self.state_set(action, self.IN_PROGRESS)

            deletion_policy = self.t.get("DeletionPolicy", DELETE)
            handle_data = None
            if deletion_policy == DELETE:
                if callable(getattr(self, "handle_delete", None)):
                    handle_data = self.handle_delete()
                    yield
            elif deletion_policy == SNAPSHOT:
                if callable(getattr(self, "handle_snapshot_delete", None)):
                    handle_data = self.handle_snapshot_delete(initial_state)
                    yield

            if deletion_policy != RETAIN and callable(getattr(self, "check_delete_complete", None)):
                while not self.check_delete_complete(handle_data):
                    yield

        except Exception as ex:
            logger.exception(_("Delete %s"), str(self))
            failure = exception.ResourceFailure(ex, self, self.action)
            self.state_set(action, self.FAILED, str(failure))
            raise failure
        except:
            with excutils.save_and_reraise_exception():
                try:
                    self.state_set(action, self.FAILED, "Deletion aborted")
                except Exception:
                    logger.exception(_("Error marking resource deletion " "failed"))
        else:
            self.state_set(action, self.COMPLETE)
Exemple #46
0
    def __call__(self):
        """Return a co-routine which runs the task group."""
        try:
            while any(self._runners.itervalues()):
                for k, r in self._ready():
                    r.start()

                yield

                for k, r in self._running():
                    if r.step():
                        del self._graph[k]
        except:
            with excutils.save_and_reraise_exception():
                for r in self._runners.itervalues():
                    r.cancel()
Exemple #47
0
    def __call__(self):
        """Return a co-routine which runs the task group."""
        runners = [TaskRunner(t) for t in self._tasks]

        try:
            for r in runners:
                r.start()

            while runners:
                yield
                runners = list(itertools.dropwhile(lambda r: r.step(),
                                                   runners))
        except:
            with excutils.save_and_reraise_exception():
                for r in runners:
                    r.cancel()
Exemple #48
0
    def __call__(self):
        """Return a co-routine which runs the task group."""
        try:
            while any(self._runners.itervalues()):
                for k, r in self._ready():
                    r.start()

                yield

                for k, r in self._running():
                    if r.step():
                        del self._graph[k]
        except:
            with excutils.save_and_reraise_exception():
                for r in self._runners.itervalues():
                    r.cancel()
Exemple #49
0
    def handle_create(self):
        """Allocate a floating IP for the current tenant."""
        try:
            ips = self.nova().floating_ips.create()
        except clients.novaclient.exceptions.NotFound:
            with excutils.save_and_reraise_exception():
                msg = ("No default floating IP pool configured."
                       "Set 'default_floating_pool' in nova.conf.")
                logger.error(msg)

        if ips:
            logger.info('ElasticIp create %s' % str(ips))
            self.ipaddress = ips.ip
            self.resource_id_set(ips.id)

        if self.properties['InstanceId']:
            server = self.nova().servers.get(self.properties['InstanceId'])
            res = server.add_floating_ip(self._ipaddress())
Exemple #50
0
 def __iter__(self):
     """Return a result until we get a 'None' response from consumer"""
     if self._done:
         raise StopIteration
     while True:
         try:
             self._iterator.next()
         except Exception:
             with excutils.save_and_reraise_exception():
                 self.done()
         if self._got_ending:
             self.done()
             raise StopIteration
         result = self._result
         if isinstance(result, Exception):
             self.done()
             raise result
         yield result
Exemple #51
0
 def __iter__(self):
     """Return a result until we get a 'None' response from consumer"""
     if self._done:
         raise StopIteration
     while True:
         try:
             self._iterator.next()
         except Exception:
             with excutils.save_and_reraise_exception():
                 self.done()
         if self._got_ending:
             self.done()
             raise StopIteration
         result = self._result
         if isinstance(result, Exception):
             self.done()
             raise result
         yield result
Exemple #52
0
    def update(self, after, before=None):
        """
        update the resource. Subclasses should provide a handle_update() method
        to customise update, the base-class handle_update will fail by default.
        """
        action = self.UPDATE

        if before is None:
            before = self.parsed_template()
        elif before == after:
            return

        if (self.action, self.status) in ((self.CREATE, self.IN_PROGRESS), (self.UPDATE, self.IN_PROGRESS)):
            exc = Exception(_("Resource update already requested"))
            raise exception.ResourceFailure(exc, self, action)

        logger.info("updating %s" % str(self))

        try:
            self.state_set(action, self.IN_PROGRESS)
            properties = Properties(
                self.properties_schema, after.get("Properties", {}), self._resolve_runtime_data, self.name
            )
            properties.validate()
            tmpl_diff = self.update_template_diff(after, before)
            prop_diff = self.update_template_diff_properties(after, before)
            if callable(getattr(self, "handle_update", None)):
                handle_data = self.handle_update(after, tmpl_diff, prop_diff)
                yield
                if callable(getattr(self, "check_update_complete", None)):
                    while not self.check_update_complete(handle_data):
                        yield
        except UpdateReplace:
            with excutils.save_and_reraise_exception():
                logger.debug(_("Resource %s update requires replacement") % self.name)
        except Exception as ex:
            logger.exception("update %s : %s" % (str(self), str(ex)))
            failure = exception.ResourceFailure(ex, self, action)
            self.state_set(action, self.FAILED, str(failure))
            raise failure
        else:
            self.t = self.stack.resolve_static_data(after)
            self.state_set(action, self.COMPLETE)
Exemple #53
0
    def delete(self):
        '''
        Delete the resource. Subclasses should provide a handle_delete() method
        to customise deletion.
        '''
        action = self.DELETE

        if (self.action, self.status) == (self.DELETE, self.COMPLETE):
            return
        # No need to delete if the resource has never been created
        if self.action == self.INIT:
            return

        initial_state = self.state

        logger.info('deleting %s' % str(self))

        try:
            self.state_set(action, self.IN_PROGRESS)

            deletion_policy = self.t.get('DeletionPolicy', 'Delete')
            if deletion_policy == 'Delete':
                if callable(getattr(self, 'handle_delete', None)):
                    self.handle_delete()
            elif deletion_policy == 'Snapshot':
                if callable(getattr(self, 'handle_snapshot_delete', None)):
                    self.handle_snapshot_delete(initial_state)
        except Exception as ex:
            logger.exception('Delete %s', str(self))
            failure = exception.ResourceFailure(ex, self, self.action)
            self.state_set(action, self.FAILED, str(failure))
            raise failure
        except:
            with excutils.save_and_reraise_exception():
                try:
                    self.state_set(action, self.FAILED,
                                   'Deletion aborted')
                except Exception:
                    logger.exception('Error marking resource deletion failed')
        else:
            self.state_set(action, self.COMPLETE)
Exemple #54
0
 def __iter__(self):
     """Return a result until we get a reply with an 'ending' flag."""
     if self._done:
         raise StopIteration
     while True:
         try:
             data = self._dataqueue.get(timeout=self._timeout)
             result = self._process_data(data)
         except queue.Empty:
             self.done()
             raise rpc_common.Timeout()
         except Exception:
             with excutils.save_and_reraise_exception():
                 self.done()
         if self._got_ending:
             self.done()
             raise StopIteration
         if isinstance(result, Exception):
             self.done()
             raise result
         yield result
Exemple #55
0
    def delete(self):
        '''
        Delete the resource. Subclasses should provide a handle_delete() method
        to customise deletion.
        '''
        action = self.DELETE

        if (self.action, self.status) == (self.DELETE, self.COMPLETE):
            return
        # No need to delete if the resource has never been created
        if self.action == self.INIT:
            return

        initial_state = self.state

        logger.info('deleting %s' % str(self))

        try:
            self.state_set(action, self.IN_PROGRESS)

            deletion_policy = self.t.get('DeletionPolicy', 'Delete')
            if deletion_policy == 'Delete':
                if callable(getattr(self, 'handle_delete', None)):
                    self.handle_delete()
            elif deletion_policy == 'Snapshot':
                if callable(getattr(self, 'handle_snapshot_delete', None)):
                    self.handle_snapshot_delete(initial_state)
        except Exception as ex:
            logger.exception('Delete %s', str(self))
            failure = exception.ResourceFailure(ex, self, self.action)
            self.state_set(action, self.FAILED, str(failure))
            raise failure
        except:
            with excutils.save_and_reraise_exception():
                try:
                    self.state_set(action, self.FAILED, 'Deletion aborted')
                except Exception:
                    logger.exception('Error marking resource deletion failed')
        else:
            self.state_set(action, self.COMPLETE)
Exemple #56
0
    def adjust(self, adjustment, adjustment_type=CHANGE_IN_CAPACITY):
        """
        Adjust the size of the scaling group if the cooldown permits.
        """
        if self._cooldown_inprogress():
            logger.info(
                _("%(name)s NOT performing scaling adjustment, "
                  "cooldown %(cooldown)s") % {
                      'name': self.name,
                      'cooldown': self.properties[self.COOLDOWN]
                  })
            return

        capacity = len(self.get_instances())
        if adjustment_type == CHANGE_IN_CAPACITY:
            new_capacity = capacity + adjustment
        elif adjustment_type == EXACT_CAPACITY:
            new_capacity = adjustment
        else:
            # PercentChangeInCapacity
            delta = capacity * adjustment / 100.0
            if math.fabs(delta) < 1.0:
                rounded = int(
                    math.ceil(delta) if delta > 0.0 else math.floor(delta))
            else:
                rounded = int(
                    math.floor(delta) if delta > 0.0 else math.ceil(delta))
            new_capacity = capacity + rounded

        upper = self.properties[self.MAX_SIZE]
        lower = self.properties[self.MIN_SIZE]

        if new_capacity > upper:
            if upper > capacity:
                logger.info(_('truncating growth to %s') % upper)
                new_capacity = upper
            else:
                logger.warn(_('can not exceed %s') % upper)
                return
        if new_capacity < lower:
            if lower < capacity:
                logger.info(_('truncating shrinkage to %s') % lower)
                new_capacity = lower
            else:
                logger.warn(_('can not be less than %s') % lower)
                return

        if new_capacity == capacity:
            logger.debug('no change in capacity %d' % capacity)
            return

        # 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),
                    })
                    notification.send(**notif)
                except Exception:
                    logger.exception(_('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)

        self._cooldown_timestamp("%s : %s" % (adjustment_type, adjustment))
Exemple #57
0
    def update(self, after, before=None, prev_resource=None):
        '''
        update the resource. Subclasses should provide a handle_update() method
        to customise update, the base-class handle_update will fail by default.
        '''
        action = self.UPDATE

        assert isinstance(after, rsrc_defn.ResourceDefinition)

        (cur_class_def, cur_ver) = self.implementation_signature()
        prev_ver = cur_ver
        if prev_resource is not None:
            (prev_class_def,
             prev_ver) = prev_resource.implementation_signature()
            if prev_class_def != cur_class_def:
                raise UpdateReplace(self.name)

        if before is None:
            before = self.parsed_template()
        if prev_ver == cur_ver and before == after:
            return

        if (self.action, self.status) in ((self.CREATE, self.IN_PROGRESS),
                                          (self.UPDATE, self.IN_PROGRESS),
                                          (self.ADOPT, self.IN_PROGRESS)):
            exc = Exception(_('Resource update already requested'))
            raise exception.ResourceFailure(exc, self, action)

        LOG.info(_('updating %s') % str(self))

        try:
            self.updated_time = datetime.utcnow()
            self.state_set(action, self.IN_PROGRESS)
            before_properties = Properties(self.properties_schema,
                                           before.get('Properties',
                                                      {}), function.resolve,
                                           self.name, self.context)
            after_properties = after.properties(self.properties_schema,
                                                self.context)
            after_properties.validate()
            tmpl_diff = self.update_template_diff(function.resolve(after),
                                                  before)
            prop_diff = self.update_template_diff_properties(
                after_properties, before_properties)
            if callable(getattr(self, 'handle_update', None)):
                handle_data = self.handle_update(after, tmpl_diff, prop_diff)
                yield
                if callable(getattr(self, 'check_update_complete', None)):
                    while not self.check_update_complete(handle_data):
                        yield
        except UpdateReplace:
            with excutils.save_and_reraise_exception():
                LOG.debug("Resource %s update requires replacement" %
                          self.name)
        except Exception as ex:
            LOG.exception(
                _('update %(resource)s : %(err)s') % {
                    'resource': str(self),
                    'err': ex
                })
            failure = exception.ResourceFailure(ex, self, action)
            self.state_set(action, self.FAILED, six.text_type(failure))
            raise failure
        else:
            self.t = after
            self.reparse()
            self.state_set(action, self.COMPLETE)