This is an automated email from the ASF dual-hosted git repository.

nicholasjiang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/celeborn.git


The following commit(s) were added to refs/heads/main by this push:
     new fc056a3c3 [CELEBORN-1875] Support to get workers topology information 
with RESTful api
fc056a3c3 is described below

commit fc056a3c3a47cea33aaac21082e96dbf0bd35655
Author: Wang, Fei <[email protected]>
AuthorDate: Wed Feb 26 16:27:32 2025 +0800

    [CELEBORN-1875] Support to get workers topology information with RESTful api
    
    ### What changes were proposed in this pull request?
    
    Support to get the workers topology information with RESTful api.
    1. return networkLocation in WorkerData
    2. add new api `/api/v1/workers/topology` to return the grouped workers 
topology info.
    
    ### Why are the changes needed?
    
    1. To get the workers topology information.
    2. To know the rack awareness well.
    
    ### Does this PR introduce _any_ user-facing change?
    
    No break change.
    ### How was this patch tested?
    UT and IT.
    
    <img width="1008" alt="image" 
src="https://github.com/user-attachments/assets/6cb1aa2a-1160-4570-acb1-7602e2ce0b09";
 />
    
    <img width="719" alt="image" 
src="https://github.com/user-attachments/assets/d26c3326-4837-40ad-a344-3cb4204bf607";
 />
    
    Closes #3112 from turboFei/topology.
    
    Authored-by: Wang, Fei <[email protected]>
    Signed-off-by: SteNicholas <[email protected]>
---
 .../deploy/master/http/api/v1/WorkerResource.scala |  19 +++
 .../http/api/v1/ApiV1MasterResourceSuite.scala     |   7 +-
 .../apache/celeborn/rest/v1/master/WorkerApi.java  |  68 ++++++++++
 .../celeborn/rest/v1/model/TopologyInfo.java       | 150 +++++++++++++++++++++
 .../celeborn/rest/v1/model/TopologyResponse.java   | 120 +++++++++++++++++
 .../apache/celeborn/rest/v1/model/WorkerData.java  |  37 ++++-
 .../src/main/openapi3/master_rest_v1.yaml          |  38 ++++++
 .../src/main/openapi3/worker_rest_v1.yaml          |   3 +
 .../server/common/http/api/v1/ApiUtils.scala       |   1 +
 9 files changed, 439 insertions(+), 4 deletions(-)

diff --git 
a/master/src/main/scala/org/apache/celeborn/service/deploy/master/http/api/v1/WorkerResource.scala
 
b/master/src/main/scala/org/apache/celeborn/service/deploy/master/http/api/v1/WorkerResource.scala
index a461b8dac..109c8b0e7 100644
--- 
a/master/src/main/scala/org/apache/celeborn/service/deploy/master/http/api/v1/WorkerResource.scala
+++ 
b/master/src/main/scala/org/apache/celeborn/service/deploy/master/http/api/v1/WorkerResource.scala
@@ -152,6 +152,25 @@ class WorkerResource extends ApiRequestContext {
       new HandleResponse().success(success).message(finalMsg)
     }
 
+  @Operation(description = "List all worker topology info of the master.")
+  @ApiResponse(
+    responseCode = "200",
+    content = Array(new Content(
+      mediaType = MediaType.APPLICATION_JSON,
+      schema = new Schema(implementation = classOf[TopologyResponse]))))
+  @GET
+  @Path("/topology")
+  def getWorkersTopology(): TopologyResponse = {
+    new TopologyResponse()
+      .topologies(
+        
statusSystem.workersMap.values().asScala.groupBy(_.networkLocation).map {
+          case (networkLocation, workers) =>
+            new TopologyInfo()
+              .networkLocation(networkLocation)
+              .workers(workers.map(_.toUniqueId).toSeq.asJava)
+        }.toSeq.asJava)
+  }
+
   private def toWorkerEventType(eunmObj: EventTypeEnum): WorkerEventType = {
     eunmObj match {
       case EventTypeEnum.NONE => WorkerEventType.None
diff --git 
a/master/src/test/scala/org/apache/celeborn/service/deploy/master/http/api/v1/ApiV1MasterResourceSuite.scala
 
b/master/src/test/scala/org/apache/celeborn/service/deploy/master/http/api/v1/ApiV1MasterResourceSuite.scala
index 69dd19e4d..fec1fce56 100644
--- 
a/master/src/test/scala/org/apache/celeborn/service/deploy/master/http/api/v1/ApiV1MasterResourceSuite.scala
+++ 
b/master/src/test/scala/org/apache/celeborn/service/deploy/master/http/api/v1/ApiV1MasterResourceSuite.scala
@@ -22,7 +22,7 @@ import javax.servlet.http.HttpServletResponse
 import javax.ws.rs.client.Entity
 import javax.ws.rs.core.MediaType
 
-import org.apache.celeborn.rest.v1.model.{ApplicationsResponse, 
ExcludeWorkerRequest, HandleResponse, HostnamesResponse, 
RemoveWorkersUnavailableInfoRequest, SendWorkerEventRequest, ShufflesResponse, 
WorkerEventsResponse, WorkerId, WorkersResponse}
+import org.apache.celeborn.rest.v1.model.{ApplicationsResponse, 
ExcludeWorkerRequest, HandleResponse, HostnamesResponse, 
RemoveWorkersUnavailableInfoRequest, SendWorkerEventRequest, ShufflesResponse, 
TopologyResponse, WorkerEventsResponse, WorkerId, WorkersResponse}
 import org.apache.celeborn.server.common.HttpService
 import org.apache.celeborn.server.common.http.api.v1.ApiV1BaseResourceSuite
 import org.apache.celeborn.service.deploy.master.{Master, MasterClusterFeature}
@@ -118,5 +118,10 @@ class ApiV1MasterResourceSuite extends 
ApiV1BaseResourceSuite with MasterCluster
       Entity.entity(sendWorkerEventRequest, MediaType.APPLICATION_JSON))
     assert(HttpServletResponse.SC_BAD_REQUEST == response.getStatus)
     assert(response.readEntity(classOf[String]).contains("None of the workers 
are known"))
+
+    response = 
webTarget.path("workers/topology").request(MediaType.APPLICATION_JSON).get()
+    assert(HttpServletResponse.SC_OK == response.getStatus)
+    val topologyResponse = response.readEntity(classOf[TopologyResponse])
+    assert(topologyResponse.getTopologies.isEmpty)
   }
 }
diff --git 
a/openapi/openapi-client/src/main/java/org/apache/celeborn/rest/v1/master/WorkerApi.java
 
b/openapi/openapi-client/src/main/java/org/apache/celeborn/rest/v1/master/WorkerApi.java
index f8ca948d0..3dd1ee07c 100644
--- 
a/openapi/openapi-client/src/main/java/org/apache/celeborn/rest/v1/master/WorkerApi.java
+++ 
b/openapi/openapi-client/src/main/java/org/apache/celeborn/rest/v1/master/WorkerApi.java
@@ -29,6 +29,7 @@ import org.apache.celeborn.rest.v1.model.ExcludeWorkerRequest;
 import org.apache.celeborn.rest.v1.model.HandleResponse;
 import org.apache.celeborn.rest.v1.model.RemoveWorkersUnavailableInfoRequest;
 import org.apache.celeborn.rest.v1.model.SendWorkerEventRequest;
+import org.apache.celeborn.rest.v1.model.TopologyResponse;
 import org.apache.celeborn.rest.v1.model.WorkerEventsResponse;
 import org.apache.celeborn.rest.v1.model.WorkersResponse;
 
@@ -254,6 +255,73 @@ public class WorkerApi extends BaseApi {
     );
   }
 
+  /**
+   * 
+   * List all worker topology info of the master.
+   * @return TopologyResponse
+   * @throws ApiException if fails to make API call
+   */
+  public TopologyResponse getWorkersTopology() throws ApiException {
+    return this.getWorkersTopology(Collections.emptyMap());
+  }
+
+
+  /**
+   * 
+   * List all worker topology info of the master.
+   * @param additionalHeaders additionalHeaders for this call
+   * @return TopologyResponse
+   * @throws ApiException if fails to make API call
+   */
+  public TopologyResponse getWorkersTopology(Map<String, String> 
additionalHeaders) throws ApiException {
+    Object localVarPostBody = null;
+    
+    // create path and map variables
+    String localVarPath = "/api/v1/workers/topology";
+
+    StringJoiner localVarQueryStringJoiner = new StringJoiner("&");
+    String localVarQueryParameterBaseName;
+    List<Pair> localVarQueryParams = new ArrayList<Pair>();
+    List<Pair> localVarCollectionQueryParams = new ArrayList<Pair>();
+    Map<String, String> localVarHeaderParams = new HashMap<String, String>();
+    Map<String, String> localVarCookieParams = new HashMap<String, String>();
+    Map<String, Object> localVarFormParams = new HashMap<String, Object>();
+
+    
+    localVarHeaderParams.putAll(additionalHeaders);
+
+    
+    
+    final String[] localVarAccepts = {
+      "application/json"
+    };
+    final String localVarAccept = 
apiClient.selectHeaderAccept(localVarAccepts);
+
+    final String[] localVarContentTypes = {
+      
+    };
+    final String localVarContentType = 
apiClient.selectHeaderContentType(localVarContentTypes);
+
+    String[] localVarAuthNames = new String[] { "basic" };
+
+    TypeReference<TopologyResponse> localVarReturnType = new 
TypeReference<TopologyResponse>() {};
+    return apiClient.invokeAPI(
+        localVarPath,
+        "GET",
+        localVarQueryParams,
+        localVarCollectionQueryParams,
+        localVarQueryStringJoiner.toString(),
+        localVarPostBody,
+        localVarHeaderParams,
+        localVarCookieParams,
+        localVarFormParams,
+        localVarAccept,
+        localVarContentType,
+        localVarAuthNames,
+        localVarReturnType
+    );
+  }
+
   /**
    * 
    * Remove the workers unavailable info from the master.
diff --git 
a/openapi/openapi-client/src/main/java/org/apache/celeborn/rest/v1/model/TopologyInfo.java
 
b/openapi/openapi-client/src/main/java/org/apache/celeborn/rest/v1/model/TopologyInfo.java
new file mode 100644
index 000000000..5e6385ccd
--- /dev/null
+++ 
b/openapi/openapi-client/src/main/java/org/apache/celeborn/rest/v1/model/TopologyInfo.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.celeborn.rest.v1.model;
+
+import java.util.Objects;
+import java.util.Arrays;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+
+/**
+ * TopologyInfo
+ */
+@JsonPropertyOrder({
+  TopologyInfo.JSON_PROPERTY_NETWORK_LOCATION,
+  TopologyInfo.JSON_PROPERTY_WORKERS
+})
[email protected](value = 
"org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator 
version: 7.8.0")
+public class TopologyInfo {
+  public static final String JSON_PROPERTY_NETWORK_LOCATION = 
"networkLocation";
+  private String networkLocation;
+
+  public static final String JSON_PROPERTY_WORKERS = "workers";
+  private List<String> workers = new ArrayList<>();
+
+  public TopologyInfo() {
+  }
+
+  public TopologyInfo networkLocation(String networkLocation) {
+    
+    this.networkLocation = networkLocation;
+    return this;
+  }
+
+  /**
+   * The network location.
+   * @return networkLocation
+   */
+  @javax.annotation.Nullable
+  @JsonProperty(JSON_PROPERTY_NETWORK_LOCATION)
+  @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
+
+  public String getNetworkLocation() {
+    return networkLocation;
+  }
+
+
+  @JsonProperty(JSON_PROPERTY_NETWORK_LOCATION)
+  @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
+  public void setNetworkLocation(String networkLocation) {
+    this.networkLocation = networkLocation;
+  }
+
+  public TopologyInfo workers(List<String> workers) {
+    
+    this.workers = workers;
+    return this;
+  }
+
+  public TopologyInfo addWorkersItem(String workersItem) {
+    if (this.workers == null) {
+      this.workers = new ArrayList<>();
+    }
+    this.workers.add(workersItem);
+    return this;
+  }
+
+  /**
+   * The workers in the network location.
+   * @return workers
+   */
+  @javax.annotation.Nullable
+  @JsonProperty(JSON_PROPERTY_WORKERS)
+  @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
+
+  public List<String> getWorkers() {
+    return workers;
+  }
+
+
+  @JsonProperty(JSON_PROPERTY_WORKERS)
+  @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
+  public void setWorkers(List<String> workers) {
+    this.workers = workers;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    TopologyInfo topologyInfo = (TopologyInfo) o;
+    return Objects.equals(this.networkLocation, topologyInfo.networkLocation) 
&&
+        Objects.equals(this.workers, topologyInfo.workers);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(networkLocation, workers);
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    sb.append("class TopologyInfo {\n");
+    sb.append("    networkLocation: 
").append(toIndentedString(networkLocation)).append("\n");
+    sb.append("    workers: ").append(toIndentedString(workers)).append("\n");
+    sb.append("}");
+    return sb.toString();
+  }
+
+  /**
+   * Convert the given object to string with each line indented by 4 spaces
+   * (except the first line).
+   */
+  private String toIndentedString(Object o) {
+    if (o == null) {
+      return "null";
+    }
+    return o.toString().replace("\n", "\n    ");
+  }
+
+}
+
diff --git 
a/openapi/openapi-client/src/main/java/org/apache/celeborn/rest/v1/model/TopologyResponse.java
 
b/openapi/openapi-client/src/main/java/org/apache/celeborn/rest/v1/model/TopologyResponse.java
new file mode 100644
index 000000000..ab13a5360
--- /dev/null
+++ 
b/openapi/openapi-client/src/main/java/org/apache/celeborn/rest/v1/model/TopologyResponse.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.celeborn.rest.v1.model;
+
+import java.util.Objects;
+import java.util.Arrays;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.apache.celeborn.rest.v1.model.TopologyInfo;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+
+/**
+ * TopologyResponse
+ */
+@JsonPropertyOrder({
+  TopologyResponse.JSON_PROPERTY_TOPOLOGIES
+})
[email protected](value = 
"org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator 
version: 7.8.0")
+public class TopologyResponse {
+  public static final String JSON_PROPERTY_TOPOLOGIES = "topologies";
+  private List<TopologyInfo> topologies = new ArrayList<>();
+
+  public TopologyResponse() {
+  }
+
+  public TopologyResponse topologies(List<TopologyInfo> topologies) {
+    
+    this.topologies = topologies;
+    return this;
+  }
+
+  public TopologyResponse addTopologiesItem(TopologyInfo topologiesItem) {
+    if (this.topologies == null) {
+      this.topologies = new ArrayList<>();
+    }
+    this.topologies.add(topologiesItem);
+    return this;
+  }
+
+  /**
+   * The workers topology information.
+   * @return topologies
+   */
+  @javax.annotation.Nullable
+  @JsonProperty(JSON_PROPERTY_TOPOLOGIES)
+  @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
+
+  public List<TopologyInfo> getTopologies() {
+    return topologies;
+  }
+
+
+  @JsonProperty(JSON_PROPERTY_TOPOLOGIES)
+  @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
+  public void setTopologies(List<TopologyInfo> topologies) {
+    this.topologies = topologies;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    TopologyResponse topologyResponse = (TopologyResponse) o;
+    return Objects.equals(this.topologies, topologyResponse.topologies);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(topologies);
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    sb.append("class TopologyResponse {\n");
+    sb.append("    topologies: 
").append(toIndentedString(topologies)).append("\n");
+    sb.append("}");
+    return sb.toString();
+  }
+
+  /**
+   * Convert the given object to string with each line indented by 4 spaces
+   * (except the first line).
+   */
+  private String toIndentedString(Object o) {
+    if (o == null) {
+      return "null";
+    }
+    return o.toString().replace("\n", "\n    ");
+  }
+
+}
+
diff --git 
a/openapi/openapi-client/src/main/java/org/apache/celeborn/rest/v1/model/WorkerData.java
 
b/openapi/openapi-client/src/main/java/org/apache/celeborn/rest/v1/model/WorkerData.java
index 09908248b..618b25dbc 100644
--- 
a/openapi/openapi-client/src/main/java/org/apache/celeborn/rest/v1/model/WorkerData.java
+++ 
b/openapi/openapi-client/src/main/java/org/apache/celeborn/rest/v1/model/WorkerData.java
@@ -48,7 +48,8 @@ import com.fasterxml.jackson.annotation.JsonTypeName;
   WorkerData.JSON_PROPERTY_RESOURCE_CONSUMPTIONS,
   WorkerData.JSON_PROPERTY_WORKER_REF,
   WorkerData.JSON_PROPERTY_WORKER_STATE,
-  WorkerData.JSON_PROPERTY_WORKER_STATE_START_TIME
+  WorkerData.JSON_PROPERTY_WORKER_STATE_START_TIME,
+  WorkerData.JSON_PROPERTY_NETWORK_LOCATION
 })
 @javax.annotation.Generated(value = 
"org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator 
version: 7.8.0")
 public class WorkerData {
@@ -94,6 +95,9 @@ public class WorkerData {
   public static final String JSON_PROPERTY_WORKER_STATE_START_TIME = 
"workerStateStartTime";
   private Long workerStateStartTime;
 
+  public static final String JSON_PROPERTY_NETWORK_LOCATION = 
"networkLocation";
+  private String networkLocation;
+
   public WorkerData() {
   }
 
@@ -463,6 +467,31 @@ public class WorkerData {
     this.workerStateStartTime = workerStateStartTime;
   }
 
+  public WorkerData networkLocation(String networkLocation) {
+    
+    this.networkLocation = networkLocation;
+    return this;
+  }
+
+  /**
+   * The network location of the worker.
+   * @return networkLocation
+   */
+  @javax.annotation.Nullable
+  @JsonProperty(JSON_PROPERTY_NETWORK_LOCATION)
+  @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
+
+  public String getNetworkLocation() {
+    return networkLocation;
+  }
+
+
+  @JsonProperty(JSON_PROPERTY_NETWORK_LOCATION)
+  @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
+  public void setNetworkLocation(String networkLocation) {
+    this.networkLocation = networkLocation;
+  }
+
   @Override
   public boolean equals(Object o) {
     if (this == o) {
@@ -485,12 +514,13 @@ public class WorkerData {
         Objects.equals(this.resourceConsumptions, 
workerData.resourceConsumptions) &&
         Objects.equals(this.workerRef, workerData.workerRef) &&
         Objects.equals(this.workerState, workerData.workerState) &&
-        Objects.equals(this.workerStateStartTime, 
workerData.workerStateStartTime);
+        Objects.equals(this.workerStateStartTime, 
workerData.workerStateStartTime) &&
+        Objects.equals(this.networkLocation, workerData.networkLocation);
   }
 
   @Override
   public int hashCode() {
-    return Objects.hash(host, rpcPort, pushPort, fetchPort, replicatePort, 
internalPort, slotUsed, lastHeartbeatTimestamp, heartbeatElapsedSeconds, 
diskInfos, resourceConsumptions, workerRef, workerState, workerStateStartTime);
+    return Objects.hash(host, rpcPort, pushPort, fetchPort, replicatePort, 
internalPort, slotUsed, lastHeartbeatTimestamp, heartbeatElapsedSeconds, 
diskInfos, resourceConsumptions, workerRef, workerState, workerStateStartTime, 
networkLocation);
   }
 
   @Override
@@ -511,6 +541,7 @@ public class WorkerData {
     sb.append("    workerRef: 
").append(toIndentedString(workerRef)).append("\n");
     sb.append("    workerState: 
").append(toIndentedString(workerState)).append("\n");
     sb.append("    workerStateStartTime: 
").append(toIndentedString(workerStateStartTime)).append("\n");
+    sb.append("    networkLocation: 
").append(toIndentedString(networkLocation)).append("\n");
     sb.append("}");
     return sb.toString();
   }
diff --git a/openapi/openapi-client/src/main/openapi3/master_rest_v1.yaml 
b/openapi/openapi-client/src/main/openapi3/master_rest_v1.yaml
index f2676d269..6d88e5b1c 100644
--- a/openapi/openapi-client/src/main/openapi3/master_rest_v1.yaml
+++ b/openapi/openapi-client/src/main/openapi3/master_rest_v1.yaml
@@ -226,6 +226,20 @@ paths:
               schema:
                 $ref: '#/components/schemas/HandleResponse'
 
+  /api/v1/workers/topology:
+    get:
+      tags:
+        - Worker
+      operationId: getWorkersTopology
+      description: List all worker topology info of the master.
+      responses:
+        "200":
+          description: The request was successful.
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TopologyResponse'
+
   /api/v1/applications:
     get:
       tags:
@@ -841,6 +855,9 @@ components:
           type: integer
           format: int64
           description: The start time of the worker state.
+        networkLocation:
+          type: string
+          description: The network location of the worker.
       required:
         - host
         - rpcPort
@@ -950,6 +967,27 @@ components:
           items:
             $ref: '#/components/schemas/WorkerEventData'
 
+    TopologyInfo:
+      type: object
+      properties:
+        networkLocation:
+          type: string
+          description: The network location.
+        workers:
+          type: array
+          description: The workers in the network location.
+          items:
+            type: string
+
+    TopologyResponse:
+      type: object
+      properties:
+        topologies:
+          type: array
+          description: The workers topology information.
+          items:
+            $ref: '#/components/schemas/TopologyInfo'
+
     WorkerId:
       type: object
       properties:
diff --git a/openapi/openapi-client/src/main/openapi3/worker_rest_v1.yaml 
b/openapi/openapi-client/src/main/openapi3/worker_rest_v1.yaml
index e0f70a1cc..2e1d5c543 100644
--- a/openapi/openapi-client/src/main/openapi3/worker_rest_v1.yaml
+++ b/openapi/openapi-client/src/main/openapi3/worker_rest_v1.yaml
@@ -552,6 +552,9 @@ components:
           type: integer
           format: int64
           description: The start time of the worker state.
+        networkLocation:
+          type: string
+          description: The network location of the worker.
       required:
         - host
         - rpcPort
diff --git 
a/service/src/main/scala/org/apache/celeborn/server/common/http/api/v1/ApiUtils.scala
 
b/service/src/main/scala/org/apache/celeborn/server/common/http/api/v1/ApiUtils.scala
index c302a4243..a14e5ab12 100644
--- 
a/service/src/main/scala/org/apache/celeborn/server/common/http/api/v1/ApiUtils.scala
+++ 
b/service/src/main/scala/org/apache/celeborn/server/common/http/api/v1/ApiUtils.scala
@@ -57,6 +57,7 @@ object ApiUtils {
       .workerRef(Option(workerInfo.endpoint).map(_.toString).orNull)
       .workerState(workerInfo.workerStatus.getState.toString)
       .workerStateStartTime(workerInfo.workerStatus.getStateStartTime)
+      .networkLocation(workerInfo.networkLocation)
   }
 
   private def workerResourceConsumptions(workerInfo: WorkerInfo)

Reply via email to