-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Fail delete policy if pipeline exists #44438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
If a pipeline that refrences the policy exists, we should not allow the policy to be deleted. The user will need to remove the processor from the pipeline before deleting the policy. This commit adds a check to ensure that the policy cannot be deleted if it is referenced by any pipeline in the system.
|
Pinging @elastic/es-core-features |
|
@elasticmachine run elasticsearch-ci/1 |
jbaiera
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, though I think we have a minor issue with how Processors can be nested (and thus hidden) within other Processors.
| if (enrichProcessor.getPolicyName().equals(request.getName())) { | ||
| listener.onFailure( | ||
| new ElasticsearchStatusException("Could not delete policy [{}] because a pipeline is referencing it [{}]", | ||
| RestStatus.INTERNAL_SERVER_ERROR, request.getName(), pipeline.getId())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be BAD_REQUEST instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would think CONFLICT - 409
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| for (PipelineConfiguration pc: pipelines) { | ||
| Pipeline pipeline = ingestService.getPipeline(pc.getId()); | ||
|
|
||
| for (Processor processor: pipeline.getProcessors()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be a little bit of a conundrum in that the processors returned here could be complex processors that contain processors within them. For instance: The ForEachProcessor could contain an ExactMatchProcessor that is called on each value in field.
A quick fix to get more coverage would be to use
| for (Processor processor: pipeline.getProcessors()) { | |
| for (Processor processor: pipeline.flattenAllProcessors()) { |
But that only flattens processors from CompoundProcessors which things like ForEachProcessor are not subclassed... Maybe we need to introduce an interface that allows for flattening all sub-processors when a processor contains any?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ForEachProcessor and ConditionalProcessor are wrapping processor, meaning that they wrap other processor implementations. In both cases the .getProcessor() should return the processor that is wrapped. (I think those are the only 2 wrappers) ... so flattenAllProcessors should work for those.
However, if a wrapper processor wraps another wrapper e.g. if on a ForEachProcessor will result in ConditionalProcessor wrapping a ForEachProcessor which would miss the real processor. I think if add
if (processor instanceof ConditionalProcessor) {
processor = ((ConditionalProcessor) processor).getProcessor()
in the loop it handle that edge case.
Other then that edge case, i think @jbaiera suggestion to use flattenAllProcessors() will work. Also, it may make sense to add ^^ to flattenAllProcessors() since a conditional processor wrapping the real processor is an implementation detail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ug... I just took a look deeper look and getProcessor() is not called by the flattenAllProcessors() ... so your loop would need to also take into account ForEachProcessor
if (processor instanceof ConditionalProcessor) {
processor = ((ConditionalProcessor) processor).getProcessor()
if (processor instanceof ForEachProcessor) {
processor = ((ForEachProcessor) processor).getProcessor()
We may want to consider adding in a interface like WrappedProcessor that exposes getProcessor() and possibly handle the unwrapping inside flattenAllProcessors(boolean unWrap)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all of this conversation was handled in 4ec68ec
|
|
||
| public abstract class AbstractEnrichProcessor extends AbstractProcessor { | ||
|
|
||
| protected final String policyName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: protected -> private
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| for (Processor processor: pipeline.getProcessors()) { | ||
| if (processor instanceof AbstractEnrichProcessor) { | ||
| AbstractEnrichProcessor enrichProcessor = (AbstractEnrichProcessor) processor; | ||
| if (enrichProcessor.getPolicyName().equals(request.getName())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can we treat the policy names case-insensitive (e.g. equalsIgnoreCase)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we do not do this anywhere else best of my knowledge, so PUT /policyA and PUT /policya will create 2... its probably a good idea to change this tho
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The equals ignore case is here.
...h/src/main/java/org/elasticsearch/xpack/enrich/action/TransportDeleteEnrichPolicyAction.java
Outdated
Show resolved
Hide resolved
| new ElasticsearchStatusException("Could not delete policy [{}] because a pipeline is referencing it [{}]", | ||
| RestStatus.INTERNAL_SERVER_ERROR, request.getName(), pipeline.getId())); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we collect all pipelines that may have a reference, so the user doesn't need to fix one, get the error, fix one, repeat. ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[1] shows the list used to glean all of the pipelines that could be in use to display
| for (PipelineConfiguration pc: pipelines) { | ||
| Pipeline pipeline = ingestService.getPipeline(pc.getId()); | ||
|
|
||
| for (Processor processor: pipeline.getProcessors()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ForEachProcessor and ConditionalProcessor are wrapping processor, meaning that they wrap other processor implementations. In both cases the .getProcessor() should return the processor that is wrapped. (I think those are the only 2 wrappers) ... so flattenAllProcessors should work for those.
However, if a wrapper processor wraps another wrapper e.g. if on a ForEachProcessor will result in ConditionalProcessor wrapping a ForEachProcessor which would miss the real processor. I think if add
if (processor instanceof ConditionalProcessor) {
processor = ((ConditionalProcessor) processor).getProcessor()
in the loop it handle that edge case.
Other then that edge case, i think @jbaiera suggestion to use flattenAllProcessors() will work. Also, it may make sense to add ^^ to flattenAllProcessors() since a conditional processor wrapping the real processor is an implementation detail.
| if (enrichProcessor.getPolicyName().equals(request.getName())) { | ||
| listener.onFailure( | ||
| new ElasticsearchStatusException("Could not delete policy [{}] because a pipeline is referencing it [{}]", | ||
| RestStatus.INTERNAL_SERVER_ERROR, request.getName(), pipeline.getId())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would think CONFLICT - 409
...n/enrich/qa/common/src/main/java/org/elasticsearch/test/enrich/CommonEnrichRestTestCase.java
Show resolved
Hide resolved
| if (pipelinesWithProcessors.isEmpty() == false) { | ||
| listener.onFailure( | ||
| new ElasticsearchStatusException("Could not delete policy [{}] because a pipeline is referencing it {}", | ||
| RestStatus.CONFLICT, request.getName(), pipelinesWithProcessors)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you need to collect and join (comma seperated) these pipelines, and likely adjust the corresponding test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, this is already resolving it to a list (which is why there is no [] in the second arg in the string). I just for fun, added another processor to the test and got this error.
{"error":{"root_cause":[{"type":"status_exception","reason":"Could not delete policy [my_policy] because a pipeline is referencing it [my_pipeline, another_pipeline]"}],"type":"status
_exception","reason":"Could not delete policy [my_policy] because a pipeline is referencing it [my_pipeline, another_pipeline]"},"status":409}
jakelandis
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
jbaiera
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
If a pipeline that refrences the policy exists, we should not allow the policy to be deleted. The user will need to remove the processor from the pipeline before deleting the policy. This commit adds a check to ensure that the policy cannot be deleted if it is referenced by any pipeline in the system.
If a pipeline that refrences the policy exists, we should not allow the
policy to be deleted. The user will need to remove the processor from
the pipeline before deleting the policy. This commit adds a check to
ensure that the policy cannot be deleted if it is referenced by any
pipeline in the system.