@@ -52,6 +52,7 @@ import org.apache.linkis.manager.persistence.{
5252 ResourceManagerPersistence
5353}
5454import org .apache .linkis .manager .rm .domain .RMLabelContainer
55+ import org .apache .linkis .manager .rm .external .domain .ExternalResourceIdentifier
5556import org .apache .linkis .manager .rm .external .service .ExternalResourceService
5657import org .apache .linkis .manager .rm .external .yarn .{YarnAppInfo , YarnResourceIdentifier }
5758import org .apache .linkis .manager .rm .restful .vo .{UserCreatorEngineType , UserResourceVo }
@@ -574,6 +575,174 @@ class RMMonitorRest extends Logging {
574575 appendMessageData(message, " queues" , clusters)
575576 }
576577
578+ @ ApiOperation (value = " getBatchQueueResource" , notes = " get batch queue resource" )
579+ @ RequestMapping (path = Array (" batchqueueresources" ), method = Array (RequestMethod .POST ))
580+ def getBatchQueueResource (
581+ request : HttpServletRequest ,
582+ @ RequestBody param : util.Map [String , AnyRef ]
583+ ): Message = {
584+ ModuleUserUtils .getOperationUser(request, " getBatchQueueResource" )
585+ val message = Message .ok(" " )
586+ val queueNamesParam = param.get(" queueNames" )
587+ if (queueNamesParam == null ) {
588+ return Message .error(" queueNames parameter is required" )
589+ }
590+ val queueNames = queueNamesParam match {
591+ case list : java.util.List [_] =>
592+ list.asScala.map(_.toString.trim).filter(StringUtils .isNotBlank).toArray
593+ case array : Array [_] =>
594+ array.map(_.toString.trim).filter(StringUtils .isNotBlank)
595+ case _ =>
596+ return Message .error(" queueNames parameter must be an array or comma-separated string" )
597+ }
598+ if (queueNames.isEmpty) {
599+ return Message .error(" queueNames parameter is empty" )
600+ }
601+ var clustername = param.get(" clustername" ).asInstanceOf [String ]
602+ val crossCluster = java.lang.Boolean .parseBoolean(
603+ param.getOrDefault(" crossCluster" , " false" ).asInstanceOf [String ]
604+ )
605+ if (crossCluster) {
606+ clustername = AMConfiguration .PRIORITY_CLUSTER_TARGET
607+ }
608+ val clusterLabel = labelFactory.createLabel(classOf [ClusterLabel ])
609+ clusterLabel.setClusterName(clustername)
610+ clusterLabel.setClusterType(param.get(" clustertype" ).asInstanceOf [String ])
611+ val labelContainer = new RMLabelContainer (Lists .newArrayList(clusterLabel))
612+ val queueInfoMap = new mutable.HashMap [String , AnyRef ]()
613+
614+ try {
615+ // Process queue names and create identifiers
616+ import java .util .ArrayList
617+ val identifiers = new ArrayList [ExternalResourceIdentifier ]()
618+ queueNames.foreach { queueName =>
619+ var processedQueueName = queueName
620+ if (
621+ StringUtils .isNotBlank(processedQueueName) && processedQueueName.startsWith(queuePrefix)
622+ ) {
623+ logger.info(
624+ " Queue name {} starts with '{}', remove '{}'" ,
625+ processedQueueName,
626+ queuePrefix,
627+ queuePrefix
628+ )
629+ processedQueueName = processedQueueName.substring(queuePrefix.length)
630+ }
631+ identifiers.add(new YarnResourceIdentifier (processedQueueName))
632+ }
633+
634+ // Use batch API to get all queue resources at once
635+ val batchResources =
636+ externalResourceService.getBatchResource(ResourceType .Yarn , labelContainer, identifiers)
637+
638+ // Process the results
639+ import scala .collection .JavaConverters ._
640+ batchResources.asScala.foreach { case (queueName, nodeResource) =>
641+ (
642+ nodeResource.getMaxResource.asInstanceOf [YarnResource ],
643+ nodeResource.getUsedResource.asInstanceOf [YarnResource ]
644+ ) match {
645+ case (maxResource, usedResource) =>
646+ val queueInfo = new mutable.HashMap [String , AnyRef ]()
647+ queueInfo.put(" queuename" , maxResource)
648+ queueInfo.put(
649+ " maxResources" ,
650+ Map (
651+ " memory" -> maxResource.getQueueMemory,
652+ " cores" -> maxResource.getQueueCores
653+ ).asJava
654+ )
655+ queueInfo.put(
656+ " usedResources" ,
657+ Map (
658+ " memory" -> usedResource.getQueueMemory,
659+ " cores" -> usedResource.getQueueCores
660+ ).asJava
661+ )
662+ val usedMemoryPercentage = usedResource.getQueueMemory
663+ .asInstanceOf [Double ] / maxResource.getQueueMemory.asInstanceOf [Double ]
664+ val usedCPUPercentage = usedResource.getQueueCores
665+ .asInstanceOf [Double ] / maxResource.getQueueCores.asInstanceOf [Double ]
666+ queueInfo.put(
667+ " usedPercentage" ,
668+ Map (" memory" -> usedMemoryPercentage, " cores" -> usedCPUPercentage).asJava
669+ )
670+ queueInfo.put(" maxApps" , nodeResource.getMaxApps.asInstanceOf [AnyRef ])
671+ queueInfo.put(" numActiveApps" , nodeResource.getNumActiveApps.asInstanceOf [AnyRef ])
672+ queueInfo.put(" numPendingApps" , nodeResource.getNumPendingApps.asInstanceOf [AnyRef ])
673+ queueInfoMap.put(queueName, queueInfo.asJava)
674+ case _ =>
675+ logger.warn(s " Failed to get queue resource for $queueName" )
676+ }
677+ }
678+ } catch {
679+ case e : Exception =>
680+ logger.error(" Failed to get batch queue resources" , e)
681+ // Fall back to individual requests if batch API fails
682+ queueNames.foreach { queueName =>
683+ try {
684+ var processedQueueName = queueName
685+ if (
686+ StringUtils
687+ .isNotBlank(processedQueueName) && processedQueueName.startsWith(queuePrefix)
688+ ) {
689+ processedQueueName = processedQueueName.substring(queuePrefix.length)
690+ }
691+ val yarnIdentifier = new YarnResourceIdentifier (processedQueueName)
692+ val providedYarnResource =
693+ externalResourceService.getResource(ResourceType .Yarn , labelContainer, yarnIdentifier)
694+ (
695+ providedYarnResource.getMaxResource.asInstanceOf [YarnResource ],
696+ providedYarnResource.getUsedResource.asInstanceOf [YarnResource ]
697+ ) match {
698+ case (maxResource, usedResource) =>
699+ val queueInfo = new mutable.HashMap [String , AnyRef ]()
700+ queueInfo.put(
701+ " maxResources" ,
702+ Map (
703+ " memory" -> maxResource.getQueueMemory,
704+ " cores" -> maxResource.getQueueCores
705+ ).asJava
706+ )
707+ queueInfo.put(
708+ " usedResources" ,
709+ Map (
710+ " memory" -> usedResource.getQueueMemory,
711+ " cores" -> usedResource.getQueueCores
712+ ).asJava
713+ )
714+ val usedMemoryPercentage = usedResource.getQueueMemory
715+ .asInstanceOf [Double ] / maxResource.getQueueMemory.asInstanceOf [Double ]
716+ val usedCPUPercentage = usedResource.getQueueCores
717+ .asInstanceOf [Double ] / maxResource.getQueueCores.asInstanceOf [Double ]
718+ queueInfo.put(
719+ " usedPercentage" ,
720+ Map (" memory" -> usedMemoryPercentage, " cores" -> usedCPUPercentage).asJava
721+ )
722+ queueInfo.put(" maxApps" , providedYarnResource.getMaxApps.asInstanceOf [AnyRef ])
723+ queueInfo.put(
724+ " numActiveApps" ,
725+ providedYarnResource.getNumActiveApps.asInstanceOf [AnyRef ]
726+ )
727+ queueInfo.put(
728+ " numPendingApps" ,
729+ providedYarnResource.getNumPendingApps.asInstanceOf [AnyRef ]
730+ )
731+ queueInfoMap.put(queueName, queueInfo.asJava)
732+ case _ =>
733+ logger.warn(s " Failed to get queue resource for $queueName" )
734+ }
735+ } catch {
736+ case ex : Exception =>
737+ logger.error(s " Failed to get queue resource for $queueName" , ex)
738+ }
739+ }
740+ }
741+
742+ appendMessageData(message, " queueInfos" , queueInfoMap.asJava)
743+ message
744+ }
745+
577746 private def getEngineNodesByUserList (
578747 userList : List [String ],
579748 withResource : Boolean = false
0 commit comments