def test_initiate_propagate_rsrc_retriggers_check_rsrc_on_new_stack_update( self, mock_stack_load, mock_rcr, mock_cru, mock_crc, mock_pcr, mock_csc, mock_cid ): key = sync_point.make_key(self.resource.id, self.stack.current_traversal, self.is_update) mock_pcr.side_effect = sync_point.SyncPointNotFound(key) updated_stack = stack.Stack( self.ctx, self.stack.name, self.stack.t, self.stack.id, current_traversal="some_newy_trvl_uuid" ) mock_stack_load.return_value = updated_stack self.worker._initiate_propagate_resource( self.ctx, self.resource.id, self.stack.current_traversal, self.is_update, self.resource, self.stack ) mock_rcr.assert_called_once_with(self.ctx, self.is_update, self.resource.id, updated_stack)
def _retrigger_check_resource(self, cnxt, is_update, resource_id, stack): current_traversal = stack.current_traversal graph = self._compute_dependencies(stack).graph() key = sync_point.make_key(resource_id, current_traversal, is_update) predecessors = graph[key] def do_check(target_key, data): self.check_resource(resource_id, current_traversal, data) try: sync_point.sync(cnxt, resource_id, current_traversal, is_update, do_check, predecessors, {key: None}) except sync_point.sync_points.NotFound: pass
def test_initiate_propagate_rsrc_retriggers_check_rsrc_on_new_stack_update( self, mock_stack_load, mock_rcr, mock_cru, mock_crc, mock_pcr, mock_csc, mock_cid): key = sync_point.make_key(self.resource.id, self.stack.current_traversal, self.is_update) mock_pcr.side_effect = sync_point.SyncPointNotFound(key) updated_stack = stack.Stack(self.ctx, self.stack.name, self.stack.t, self.stack.id, current_traversal='some_newy_trvl_uuid') mock_stack_load.return_value = updated_stack self.worker._initiate_propagate_resource(self.ctx, self.resource.id, self.stack.current_traversal, self.is_update, self.resource, self.stack) mock_rcr.assert_called_once_with(self.ctx, self.is_update, self.resource.id, updated_stack)
def check_resource(self, cnxt, resource_id, current_traversal, data, is_update): ''' Process a node in the dependency graph. The node may be associated with either an update or a cleanup of its associated resource. ''' adopt_data = data.get('adopt_stack_data') data = dict(sync_point.deserialize_input_data(data)) try: cache_data = {in_data.get( 'name'): in_data for in_data in data.values() if in_data is not None} cache_data['adopt_stack_data'] = adopt_data rsrc, stack = resource.Resource.load(cnxt, resource_id, is_update, cache_data) except (exception.ResourceNotFound, exception.NotFound): return tmpl = stack.t if current_traversal != rsrc.stack.current_traversal: LOG.debug('[%s] Traversal cancelled; stopping.', current_traversal) return current_deps = ([tuple(i), (tuple(j) if j is not None else None)] for i, j in rsrc.stack.current_deps['edges']) deps = dependencies.Dependencies(edges=current_deps) graph = deps.graph() if is_update: if (rsrc.replaced_by is not None and rsrc.current_template_id != tmpl.id): return try: check_resource_update(rsrc, tmpl.id, data, self.engine_id) except resource.UpdateReplace: new_res_id = rsrc.make_replacement(tmpl.id) LOG.info("Replacing resource with new id %s", new_res_id) data = sync_point.serialize_input_data(data) self._rpc_client.check_resource(cnxt, new_res_id, current_traversal, data, is_update) return except resource.UpdateInProgress: if self._try_steal_engine_lock(cnxt, resource_id): self._rpc_client.check_resource(cnxt, resource_id, current_traversal, data, is_update) return except exception.ResourceFailure as ex: reason = 'Resource %s failed: %s' % (stack.action, six.text_type(ex)) self._handle_resource_failure( cnxt, stack.id, current_traversal, reason) return input_data = construct_input_data(rsrc) else: try: check_resource_cleanup(rsrc, tmpl.id, data, self.engine_id) except resource.UpdateInProgress: if self._try_steal_engine_lock(cnxt, resource_id): self._rpc_client.check_resource(cnxt, resource_id, current_traversal, data, is_update) return except exception.ResourceFailure as ex: reason = 'Resource %s failed: %s' % (stack.action, six.text_type(ex)) self._handle_resource_failure( cnxt, stack.id, current_traversal, reason) return graph_key = (resource_id, is_update) if graph_key not in graph and rsrc.replaces is not None: # If we are a replacement, impersonate the replaced resource for # the purposes of calculating whether subsequent resources are # ready, since everybody has to work from the same version of the # graph. Our real resource ID is sent in the input_data, so the # dependencies will get updated to point to this resource in time # for the next traversal. graph_key = (rsrc.replaces, is_update) try: for req, fwd in deps.required_by(graph_key): propagate_check_resource( cnxt, self._rpc_client, req, current_traversal, set(graph[(req, fwd)]), graph_key, input_data if fwd else None, fwd) check_stack_complete(cnxt, rsrc.stack, current_traversal, resource_id, deps, is_update) except sync_point.SyncPointNotFound: # Reload the stack to determine the current traversal, and check # the SyncPoint for the current node to determine if it is ready. # If it is, then retrigger the current node with the appropriate # data for the latest traversal. stack = parser.Stack.load(cnxt, stack_id=rsrc.stack.id) if current_traversal == rsrc.stack.current_traversal: LOG.debug('[%s] Traversal sync point missing.', current_traversal) return current_traversal = stack.current_traversal current_deps = ([tuple(i), (tuple(j) if j is not None else None)] for i, j in stack.current_deps['edges']) deps = dependencies.Dependencies(edges=current_deps) key = sync_point.make_key(resource_id, current_traversal, is_update) predecessors = deps.graph()[key] def do_check(target_key, data): self.check_resource(resource_id, current_traversal, data) try: sync_point.sync(cnxt, resource_id, current_traversal, is_update, do_check, predecessors, {key: None}) except sync_point.sync_points.NotFound: pass