'Update the resource synchronously.
Persist the resource\'s current_template_id to template_id and
resource\'s requires to list of the required resource ids from the given
resource_data and existing resource\'s requires, then updates the
resource by invoking the scheduler TaskRunner.'

def update_convergence(self, template_id, resource_data, engine_id, timeout, new_stack, progress_callback=None):

    def update_templ_id_and_requires(persist=True):
        self.current_template_id = template_id
        self.requires = list(set((data.primary_key for data in resource_data.values() if (data is not None))))
        if (not persist):
            return
        rs = {'current_template_id': self.current_template_id, 'updated_at': self.updated_time, 'requires': self.requires}
        if (not resource_objects.Resource.select_and_update_by_id(self.context, self.id, rs, expected_engine_id=None, atomic_key=self._atomic_key)):
            LOG.info("Resource    %s    is    locked,    can't    set    template", six.text_type(self))
            LOG.debug('Resource    id:%(resource_id)s    locked.    Expected    atomic_key:%(atomic_key)s,    accessing    from    engine_id:%(engine_id)s', {'resource_id': self.id, 'atomic_key': self._atomic_key, 'engine_id': self._calling_engine_id})
            raise exception.UpdateInProgress(self.name)
        self._incr_atomic_key(self._atomic_key)
    self._calling_engine_id = engine_id
    registry = new_stack.env.registry
    new_res_def = new_stack.defn.resource_definition(self.name)
    new_res_type = registry.get_class_to_instantiate(new_res_def.resource_type, resource_name=self.name)
    restricted_actions = registry.get_rsrc_restricted_actions(self.name)
    is_substituted = self.check_is_substituted(new_res_type)
    if ((type(self) is not new_res_type) and (not is_substituted)):
        self._check_for_convergence_replace(restricted_actions)
    action_rollback = (self.stack.action == self.stack.ROLLBACK)
    status_in_progress = (self.stack.status == self.stack.IN_PROGRESS)
    if (action_rollback and status_in_progress and self.replaced_by):
        try:
            self.restore_prev_rsrc(convergence=True)
        except Exception as e:
            failure = exception.ResourceFailure(e, self, self.action)
            self.state_set(self.UPDATE, self.FAILED, six.text_type(failure))
            raise failure
    if is_substituted:
        substitute = new_res_type(self.name, self.t, self.stack)
        self.stack.resources[self.name] = substitute
        substitute._calling_engine_id = engine_id
        updater = substitute.update
    else:
        updater = self.update
    runner = scheduler.TaskRunner(updater, new_res_def, update_templ_func=update_templ_id_and_requires)
    try:
        runner(timeout=timeout, progress_callback=progress_callback)
    except UpdateReplace:
        raise
    except BaseException:
        with excutils.save_and_reraise_exception():
            update_templ_id_and_requires(persist=True)
