// Then we've already loaded the configuration for this
// stack in the direct stack call.
continue
block.FinalSourceAddr=effectiveSourceAddr
current:=ret
for_,step:=rangetarget.Stack{
current=current.Children[step.Name]
ifcurrent==nil{
// this is invalid, we can't have orphaned removed blocks
// so we'll just return an error and skip this block.
diags=diags.Append(&hcl.Diagnostic{
Severity:hcl.DiagError,
Summary:"Invalid removed block",
Detail:"The linked removed block was not executed because the `from` attribute of the removed block targets a component or embedded stack within an orphaned embedded stack.\n\nIn order to remove an entire stack, update your removed block to target the entire removed stack itself instead of the specific elements within it.",
// error, we have an embedded stack call and a removed block
// pointing at the same instance
diags=diags.Append(&hcl.Diagnostic{
Severity:hcl.DiagError,
Summary:"Cannot remove stack instance",
Detail:fmt.Sprintf("The stack instance %s is targeted by an embedded stack block and cannot be removed. The relevant embedded stack is defined at %s.",rsc.from,embeddedCall.config.config.DeclRange.ToHCL()),
// error, we have an embedded stack call and a removed block
// pointing at the same instance
diags=diags.Append(&hcl.Diagnostic{
Severity:hcl.DiagError,
Summary:"Cannot remove stack instance",
Detail:fmt.Sprintf("The stack instance %s is targeted by an embedded stack block and cannot be removed. The relevant embedded stack is defined at %s.",rsc.from,embeddedCall.config.config.DeclRange.ToHCL()),
Detail:fmt.Sprintf("The component instance %s could not be removed. The linked removed block was not executed because the `from` attribute of the removed block targets a component or embedded stack within an orphaned embedded stack.\n\nIn order to remove an entire stack, update your removed block to target the entire removed stack itself instead of the specific elements within it.",inst.String()),
Subject:removed.DeclRange.ToHCL().Ptr(),
})
continue
}
// If we fall out here, then we found no relevant removed blocks
// so we can return the generic error message!
diags=diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Unclaimed component instance",
@ -856,3 +893,81 @@ func (s *Stack) tracingName() string {
}
returnaddr.String()
}
// validateMissingInstanceAgainstRemovedBlocks returns the removed config most
// applicable to the target address if it exists.
//
// We have an edge case where a user has written a removed block that targets
// a stacks or components within stacks that are not defined anywhere in the
// stack (either in a removed blocks or an embedded stack). We consider this to
// be an error - if you remove an entire stack from the configuration then you
// should write a removed block that targets that stack not several removed
// blocks that target things inside the removed block.
//
// The above edge case is exposed when we check that all component instances
// in state are included in the plan. This function is called with the absolute
// address of the problematic component (the target). The error we would
// normally return would say that the component isn't targeted by any component
// or removed blocks. This is misleading for the discussed edge case, as the
// user may have written a removed block that targets the component specifically
// but it is just not getting executed as it is in a stack that is also not
// in the configuration.
//
// The function aims to discover if a removed block does exist that might target
// this component. Note, that since we can have removed blocks that target
// entire stacks we do check both removed blocks and direct components on the
// assumption that a removed stack might expand to include the target component
// and we want to capture that removed stack specifically.
Detail:"The component instance stack.child.component.self is not claimed by any component or removed block in the configuration. Make sure it is instantiated by a component block, or targeted for removal by a removed block.",
Detail:"The stack instance stack.simple[\"component\"] is targeted by an embedded stack block and cannot be removed. The relevant embedded stack is defined at git::https://example.com/test.git//with-single-input/removed-stack-instance-dynamic/removed-stack-instance-dynamic.tfstack.hcl:25,1-15.",
Detail:"The stack instance stack.embedded[\"component\"].stack.simple[\"component\"] is targeted by an embedded stack block and cannot be removed. The relevant embedded stack is defined at git::https://example.com/test.git//with-single-input/removed-stack-instance-dynamic/removed-stack-instance-dynamic.tfstack.hcl:25,1-15.",
Detail:"The component instance stack.simple[\"component\"].component.self is targeted by a component block and cannot be removed. The relevant component is defined at git::https://example.com/test.git//with-single-input/valid/valid.tfstack.hcl:19,1-17.",
Detail:"The component instance stack.simple[\"component\"].component.self could not be removed. The linked removed block was not executed because the `from` attribute of the removed block targets a component or embedded stack within an orphaned embedded stack.\n\nIn order to remove an entire stack, update your removed block to target the entire removed stack itself instead of the specific elements within it.",
Detail:"The component instance stack.embedded[\"component\"].stack.simple[\"component\"].component.self could not be removed. The linked removed block was not executed because the `from` attribute of the removed block targets a component or embedded stack within an orphaned embedded stack.\n\nIn order to remove an entire stack, update your removed block to target the entire removed stack itself instead of the specific elements within it.",
Detail:"The component instance stack.embedded.component.self could not be removed. The linked removed block was not executed because the `from` attribute of the removed block targets a component or embedded stack within an orphaned embedded stack.\n\nIn order to remove an entire stack, update your removed block to target the entire removed stack itself instead of the specific elements within it.",