21
21
import java .util .Arrays ;
22
22
import java .util .Deque ;
23
23
import java .util .List ;
24
+ import java .util .Locale ;
24
25
import java .util .Map ;
25
26
import java .util .Objects ;
27
+ import java .util .concurrent .CopyOnWriteArrayList ;
26
28
import java .util .concurrent .CountDownLatch ;
27
29
import java .util .concurrent .atomic .AtomicBoolean ;
28
30
import java .util .function .Function ;
@@ -264,19 +266,9 @@ private void checkAgentBeforeDeleteModel(String modelId, ActionListener<Boolean>
264
266
if (searchHits .length == 0 ) {
265
267
actionListener .onResponse (true );
266
268
} else {
267
- List <String > relatedAgents = new ArrayList <>();
268
- for (SearchHit hit : searchHits ) {
269
- relatedAgents .add (hit .getId ());
270
- }
271
- actionListener
272
- .onFailure (
273
- new OpenSearchStatusException (
274
- searchHits .length
275
- + " agents are still using this model, please delete or update the agents first: "
276
- + Arrays .toString (relatedAgents .toArray (new String [0 ])),
277
- RestStatus .CONFLICT
278
- )
279
- );
269
+ String errorMessage = formatAgentErrorMessage (searchHits );
270
+
271
+ actionListener .onFailure (new OpenSearchStatusException (errorMessage , RestStatus .CONFLICT ));
280
272
}
281
273
282
274
}, e -> {
@@ -305,9 +297,13 @@ private void checkIngestPipelineBeforeDeleteModel(String modelId, ActionListener
305
297
actionListener
306
298
.onFailure (
307
299
new OpenSearchStatusException (
308
- allDependentPipelineIds .size ()
309
- + " ingest pipelines are still using this model, please delete or update the pipelines first: "
310
- + Arrays .toString (allDependentPipelineIds .toArray (new String [0 ])),
300
+ String
301
+ .format (
302
+ Locale .ROOT ,
303
+ "%d ingest pipelines are still using this model, please delete or update the pipelines first: %s" ,
304
+ allDependentPipelineIds .size (),
305
+ Arrays .toString (allDependentPipelineIds .toArray (new String [0 ]))
306
+ ),
311
307
RestStatus .CONFLICT
312
308
)
313
309
);
@@ -335,9 +331,13 @@ private void checkSearchPipelineBeforeDeleteModel(String modelId, ActionListener
335
331
actionListener
336
332
.onFailure (
337
333
new OpenSearchStatusException (
338
- allDependentPipelineIds .size ()
339
- + " search pipelines are still using this model, please delete or update the pipelines first: "
340
- + Arrays .toString (allDependentPipelineIds .toArray (new String [0 ])),
334
+ String
335
+ .format (
336
+ Locale .ROOT ,
337
+ "%d search pipelines are still using this model, please delete or update the pipelines first: %s" ,
338
+ allDependentPipelineIds .size (),
339
+ Arrays .toString (allDependentPipelineIds .toArray (new String [0 ]))
340
+ ),
341
341
RestStatus .CONFLICT
342
342
)
343
343
);
@@ -353,24 +353,23 @@ private void checkSearchPipelineBeforeDeleteModel(String modelId, ActionListener
353
353
private void checkDownstreamTaskBeforeDeleteModel (String modelId , Boolean isHidden , ActionListener <DeleteResponse > actionListener ) {
354
354
CountDownLatch countDownLatch = new CountDownLatch (3 );
355
355
AtomicBoolean noneBlocked = new AtomicBoolean (true );
356
- List <String > errorMessages = new ArrayList <>();
356
+ CopyOnWriteArrayList <String > errorMessages = new CopyOnWriteArrayList <>();
357
357
ActionListener <Boolean > countDownActionListener = ActionListener .wrap (b -> {
358
358
countDownLatch .countDown ();
359
359
noneBlocked .compareAndSet (true , b );
360
360
if (countDownLatch .getCount () == 0 ) {
361
361
if (noneBlocked .get ()) {
362
362
deleteModel (modelId , isHidden , actionListener );
363
363
} else {
364
- actionListener .onFailure (new OpenSearchStatusException (String .join (", " , errorMessages ), RestStatus .CONFLICT ));
364
+ actionListener .onFailure (new OpenSearchStatusException (String .join (". " , errorMessages ), RestStatus .CONFLICT ));
365
365
}
366
366
}
367
367
}, e -> {
368
368
countDownLatch .countDown ();
369
369
noneBlocked .compareAndSet (true , false );
370
- // actionListener.onFailure(e);
371
370
errorMessages .add (e .getMessage ());
372
371
if (countDownLatch .getCount () == 0 ) {
373
- actionListener .onFailure (new OpenSearchStatusException (String .join (", " , errorMessages ), RestStatus .CONFLICT ));
372
+ actionListener .onFailure (new OpenSearchStatusException (String .join (". " , errorMessages ), RestStatus .CONFLICT ));
374
373
}
375
374
376
375
});
@@ -487,19 +486,19 @@ private <T> List<String> findDependentPipelines(
487
486
List <String > dependentPipelineConfigurations = new ArrayList <>();
488
487
for (T pipelineConfiguration : pipelineConfigurations ) {
489
488
Map <String , Object > config = getConfigFunction .apply (pipelineConfiguration );
490
- if (searchThroughConfig (config , candidateModelId , "" )) {
489
+ if (searchThroughConfig (config , candidateModelId )) {
491
490
dependentPipelineConfigurations .add (getIdFunction .apply (pipelineConfiguration ));
492
491
}
493
492
}
494
493
return dependentPipelineConfigurations ;
495
494
}
496
495
497
- // This method is to go through the pipeline configs and only when the key is model id and value is
498
- // 1. String and equal to candidate id 2. A list of String containing candidate id We will return True. Otherwise False
499
- private Boolean searchThroughConfig (Object searchCandidate , String candidateId , String targetModelKey ) {
496
+ // This method is to go through the pipeline configs and he configuration is a map of string to objects.
497
+ // Objects can be a list or a map. we will search exhaustively through the configuration for any match of the candidateId.
498
+ private Boolean searchThroughConfig (Object searchCandidate , String candidateId ) {
500
499
// Use a stack to store the elements to be processed
501
500
Deque <Pair <String , Object >> stack = new ArrayDeque <>();
502
- stack .push (Pair .of (targetModelKey , searchCandidate ));
501
+ stack .push (Pair .of ("" , searchCandidate ));
503
502
504
503
while (!stack .isEmpty ()) {
505
504
// Pop an item from the stack
@@ -531,6 +530,29 @@ private Boolean searchThroughConfig(Object searchCandidate, String candidateId,
531
530
return false ;
532
531
}
533
532
533
+ private String formatAgentErrorMessage (SearchHit [] hits ) {
534
+ boolean isHidden = false ;
535
+ for (SearchHit hit : hits ) {
536
+ Map <String , Object > sourceAsMap = hit .getSourceAsMap ();
537
+ isHidden = isHidden || Boolean .parseBoolean ((String ) sourceAsMap .getOrDefault (IS_HIDDEN_FIELD , false ));
538
+ }
539
+ if (isHidden ) {
540
+ return String
541
+ .format (Locale .ROOT , "%d agents are still using this model, please delete or update the agents first" , hits .length );
542
+ }
543
+ List <String > agentIds = new ArrayList <>();
544
+ for (SearchHit hit : hits ) {
545
+ agentIds .add (hit .getId ());
546
+ }
547
+ return String
548
+ .format (
549
+ Locale .ROOT ,
550
+ "%d agents are still using this model, please delete or update the agents first: %s" ,
551
+ hits .length ,
552
+ Arrays .toString (agentIds .toArray (new String [0 ]))
553
+ );
554
+ }
555
+
534
556
// this method is only to stub static method.
535
557
@ VisibleForTesting
536
558
boolean isSuperAdminUserWrapper (ClusterService clusterService , Client client ) {
0 commit comments