This is an automated email from the ASF dual-hosted git repository.
roryqi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-uniffle.git
The following commit(s) were added to refs/heads/master by this push:
new c25807604 [#960][part-1] feat(dashboard): Add some dashboard
interfaces. (#1053)
c25807604 is described below
commit c25807604fec4b683c8b105843897a9b54a8d860
Author: yl09099 <[email protected]>
AuthorDate: Thu Nov 9 18:56:24 2023 +0800
[#960][part-1] feat(dashboard): Add some dashboard interfaces. (#1053)
### What changes were proposed in this pull request?
Add a web dashboard for uniffle, providing some dashboard apis
### Why are the changes needed?
Provide data support for dashboard
Fix: #960
### Does this PR introduce _any_ user-facing change?
Users can obtain relevant metrics information through the new API
### How was this patch tested?
Existing UT.
---
.../org/apache/uniffle/common/config/RssConf.java | 4 +
.../uniffle/coordinator/CoordinatorServer.java | 1 +
.../apache/uniffle/coordinator/web/Response.java | 12 +--
.../coordinator/web/resource/APIResource.java | 10 ++
.../web/resource/ApplicationResource.java | 104 +++++++++++++++++++++
.../web/resource/CoordinatorServerResource.java | 87 +++++++++++++++++
.../coordinator/web/resource/ServerResource.java | 20 ++++
.../uniffle/coordinator/web/vo/AppInfoVO.java | 80 ++++++++++++++++
.../APIResource.java => vo/CoordinatorConfVO.java} | 34 ++++---
.../uniffle/coordinator/web/vo/UserAppNumVO.java | 69 ++++++++++++++
10 files changed, 402 insertions(+), 19 deletions(-)
diff --git a/common/src/main/java/org/apache/uniffle/common/config/RssConf.java
b/common/src/main/java/org/apache/uniffle/common/config/RssConf.java
index 805dc30a8..78c56f96e 100644
--- a/common/src/main/java/org/apache/uniffle/common/config/RssConf.java
+++ b/common/src/main/java/org/apache/uniffle/common/config/RssConf.java
@@ -663,6 +663,10 @@ public class RssConf implements Cloneable {
return this.settings.toString();
}
+ public Set<Map.Entry<String, Object>> getAll() {
+ return this.settings.entrySet();
+ }
+
public String getEnv(String key) {
return System.getenv(key);
}
diff --git
a/coordinator/src/main/java/org/apache/uniffle/coordinator/CoordinatorServer.java
b/coordinator/src/main/java/org/apache/uniffle/coordinator/CoordinatorServer.java
index 2c22d7cf6..befbb550b 100644
---
a/coordinator/src/main/java/org/apache/uniffle/coordinator/CoordinatorServer.java
+++
b/coordinator/src/main/java/org/apache/uniffle/coordinator/CoordinatorServer.java
@@ -190,6 +190,7 @@ public class CoordinatorServer extends ReconfigurableBase {
// register packages and instances for jersey
jettyServer.addResourcePackages(
"org.apache.uniffle.coordinator.web.resource",
"org.apache.uniffle.common.web.resource");
+ jettyServer.registerInstance(CoordinatorServer.class, this);
jettyServer.registerInstance(ClusterManager.class, clusterManager);
jettyServer.registerInstance(AccessManager.class, accessManager);
jettyServer.registerInstance(ApplicationManager.class, applicationManager);
diff --git
a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/Response.java
b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/Response.java
index 3b58d0db3..3313459af 100644
--- a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/Response.java
+++ b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/Response.java
@@ -22,18 +22,18 @@ public class Response<T> {
private static final int ERROR_CODE = -1;
private int code;
private T data;
- private String errMsg;
+ private String msg;
public Response() {}
- public Response(int code, T data, String errMsg) {
+ public Response(int code, T data, String msg) {
this.code = code;
this.data = data;
- this.errMsg = errMsg;
+ this.msg = msg;
}
public static <T> Response<T> success(T data) {
- return new Response<>(SUCCESS_CODE, data, null);
+ return new Response<>(SUCCESS_CODE, data, "success");
}
public static <T> Response<T> fail(String msg) {
@@ -61,10 +61,10 @@ public class Response<T> {
}
public String getErrMsg() {
- return errMsg;
+ return msg;
}
public void setErrMsg(String errMsg) {
- this.errMsg = errMsg;
+ this.msg = errMsg;
}
}
diff --git
a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/APIResource.java
b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/APIResource.java
index b01eb0d64..324820e65 100644
---
a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/APIResource.java
+++
b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/APIResource.java
@@ -33,4 +33,14 @@ public class APIResource {
public Class<AdminResource> getAdminResource() {
return AdminResource.class;
}
+
+ @Path("coordinator")
+ public Class<CoordinatorServerResource> getCoordinatorServerResource() {
+ return CoordinatorServerResource.class;
+ }
+
+ @Path("app")
+ public Class<ApplicationResource> getApplicationResource() {
+ return ApplicationResource.class;
+ }
}
diff --git
a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/ApplicationResource.java
b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/ApplicationResource.java
new file mode 100644
index 000000000..f2e120522
--- /dev/null
+++
b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/ApplicationResource.java
@@ -0,0 +1,104 @@
+/*
+ * 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.uniffle.coordinator.web.resource;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.servlet.ServletContext;
+
+import org.apache.hbase.thirdparty.javax.ws.rs.GET;
+import org.apache.hbase.thirdparty.javax.ws.rs.Path;
+import org.apache.hbase.thirdparty.javax.ws.rs.Produces;
+import org.apache.hbase.thirdparty.javax.ws.rs.core.Context;
+import org.apache.hbase.thirdparty.javax.ws.rs.core.MediaType;
+
+import org.apache.uniffle.coordinator.ApplicationManager;
+import org.apache.uniffle.coordinator.web.Response;
+import org.apache.uniffle.coordinator.web.vo.AppInfoVO;
+import org.apache.uniffle.coordinator.web.vo.UserAppNumVO;
+
+@Produces({MediaType.APPLICATION_JSON})
+public class ApplicationResource extends BaseResource {
+
+ @Context protected ServletContext servletContext;
+
+ @GET
+ @Path("/total")
+ public Response<Map<String, Integer>> getAppTotality() {
+ return execute(
+ () -> {
+ Set<String> appIds = getApplicationManager().getAppIds();
+ Map<String, Integer> appTotalityMap = new HashMap<>();
+ appTotalityMap.put("appTotality", appIds.size());
+ return appTotalityMap;
+ });
+ }
+
+ @GET
+ @Path("/userTotal")
+ public Response<List<UserAppNumVO>> getUserApps() {
+ return execute(
+ () -> {
+ Map<String, Map<String, Long>> currentUserAndApp =
+ getApplicationManager().getQuotaManager().getCurrentUserAndApp();
+ List<UserAppNumVO> usercnt = new ArrayList<>();
+ for (Map.Entry<String, Map<String, Long>> stringMapEntry :
currentUserAndApp.entrySet()) {
+ String userName = stringMapEntry.getKey();
+ usercnt.add(new UserAppNumVO(userName,
stringMapEntry.getValue().size()));
+ }
+ // Display inverted by the number of user applications.
+ usercnt.sort(Comparator.reverseOrder());
+ return usercnt;
+ });
+ }
+
+ @GET
+ @Path("/appInfos")
+ public Response<List<AppInfoVO>> getAppInfoList() {
+ return execute(
+ () -> {
+ List<AppInfoVO> userToAppList = new ArrayList<>();
+ Map<String, Map<String, Long>> currentUserAndApp = new HashMap<>();
+ if (getApplicationManager().getQuotaManager() != null) {
+ currentUserAndApp =
getApplicationManager().getQuotaManager().getCurrentUserAndApp();
+ }
+ for (Map.Entry<String, Map<String, Long>> userAppIdTimestampMap :
+ currentUserAndApp.entrySet()) {
+ String userName = userAppIdTimestampMap.getKey();
+ for (Map.Entry<String, Long> appIdTimestampMap :
+ userAppIdTimestampMap.getValue().entrySet()) {
+ userToAppList.add(
+ new AppInfoVO(
+ userName, appIdTimestampMap.getKey(),
appIdTimestampMap.getValue()));
+ }
+ }
+ // Display is inverted by the submission time of the application.
+ userToAppList.sort(Comparator.reverseOrder());
+ return userToAppList;
+ });
+ }
+
+ private ApplicationManager getApplicationManager() {
+ return (ApplicationManager)
+
servletContext.getAttribute(ApplicationManager.class.getCanonicalName());
+ }
+}
diff --git
a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/CoordinatorServerResource.java
b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/CoordinatorServerResource.java
new file mode 100644
index 000000000..f6822366c
--- /dev/null
+++
b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/CoordinatorServerResource.java
@@ -0,0 +1,87 @@
+/*
+ * 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.uniffle.coordinator.web.resource;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.servlet.ServletContext;
+
+import org.apache.hbase.thirdparty.javax.ws.rs.GET;
+import org.apache.hbase.thirdparty.javax.ws.rs.Path;
+import org.apache.hbase.thirdparty.javax.ws.rs.Produces;
+import org.apache.hbase.thirdparty.javax.ws.rs.core.Context;
+import org.apache.hbase.thirdparty.javax.ws.rs.core.MediaType;
+
+import org.apache.uniffle.common.util.RssUtils;
+import org.apache.uniffle.coordinator.CoordinatorConf;
+import org.apache.uniffle.coordinator.CoordinatorServer;
+import org.apache.uniffle.coordinator.util.CoordinatorUtils;
+import org.apache.uniffle.coordinator.web.Response;
+import org.apache.uniffle.coordinator.web.vo.CoordinatorConfVO;
+
+import static org.apache.uniffle.common.config.RssBaseConf.JETTY_HTTP_PORT;
+
+@Produces({MediaType.APPLICATION_JSON})
+public class CoordinatorServerResource extends BaseResource {
+
+ @Context protected ServletContext servletContext;
+
+ @GET
+ @Path("/conf")
+ public Response<List<CoordinatorConfVO>> getCoordinatorConf() {
+ return execute(
+ () -> {
+ CoordinatorConf coordinatorConf =
getCoordinatorServer().getCoordinatorConf();
+ Set<Map.Entry<String, Object>> allEntry = coordinatorConf.getAll();
+ List<CoordinatorConfVO> coordinatorConfVOs = new ArrayList<>();
+ for (Map.Entry<String, Object> stringObjectEntry : allEntry) {
+ CoordinatorConfVO result =
+ new CoordinatorConfVO(
+ stringObjectEntry.getKey(),
String.valueOf(stringObjectEntry.getValue()));
+ coordinatorConfVOs.add(result);
+ }
+ return coordinatorConfVOs;
+ });
+ }
+
+ @GET
+ @Path("/info")
+ public Response<Map<String, String>> getCoordinatorInfo() {
+ return execute(
+ () -> {
+ final CoordinatorConf coordinatorConf =
getCoordinatorServer().getCoordinatorConf();
+ Map<String, String> coordinatorServerInfo = new HashMap<>();
+ coordinatorServerInfo.put(
+ "coordinatorId",
coordinatorConf.getString(CoordinatorUtils.COORDINATOR_ID, "none"));
+ coordinatorServerInfo.put("serverIp", RssUtils.getHostIp());
+ coordinatorServerInfo.put(
+ "serverPort",
String.valueOf(coordinatorConf.getInteger("rss.rpc.server.port", 0)));
+ coordinatorServerInfo.put(
+ "serverWebPort",
String.valueOf(coordinatorConf.get(JETTY_HTTP_PORT)));
+ return coordinatorServerInfo;
+ });
+ }
+
+ private CoordinatorServer getCoordinatorServer() {
+ return (CoordinatorServer)
+
servletContext.getAttribute(CoordinatorServer.class.getCanonicalName());
+ }
+}
diff --git
a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/ServerResource.java
b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/ServerResource.java
index f4d193fe5..b6cd5b855 100644
---
a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/ServerResource.java
+++
b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/ServerResource.java
@@ -17,11 +17,14 @@
package org.apache.uniffle.coordinator.web.resource;
+import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import javax.servlet.ServletContext;
import org.apache.commons.collections.CollectionUtils;
@@ -162,6 +165,23 @@ public class ServerResource extends BaseResource {
}
}
+ @GET
+ @Path("/nodes/summary")
+ public Response<Map<String, Integer>> getNodeStatusTotal() {
+ return execute(
+ () -> {
+ ClusterManager clusterManager = getClusterManager();
+ Map<String, Integer> stringIntegerHash =
+ Stream.concat(
+
clusterManager.getServerList(Collections.emptySet()).stream(),
+ clusterManager.getLostServerList().stream())
+ .collect(
+ Collectors.groupingBy(
+ n -> n.getStatus().name(), Collectors.reducing(0, n
-> 1, Integer::sum)));
+ return stringIntegerHash;
+ });
+ }
+
private ClusterManager getClusterManager() {
return (ClusterManager)
servletContext.getAttribute(ClusterManager.class.getCanonicalName());
}
diff --git
a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/vo/AppInfoVO.java
b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/vo/AppInfoVO.java
new file mode 100644
index 000000000..87ee82683
--- /dev/null
+++
b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/vo/AppInfoVO.java
@@ -0,0 +1,80 @@
+/*
+ * 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.uniffle.coordinator.web.vo;
+
+import java.util.Objects;
+
+public class AppInfoVO implements Comparable<AppInfoVO> {
+ private String userName;
+ private String appId;
+ private long updateTime;
+
+ public AppInfoVO(String userName, String appId, long updateTime) {
+ this.userName = userName;
+ this.appId = appId;
+ this.updateTime = updateTime;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public void setAppId(String appId) {
+ this.appId = appId;
+ }
+
+ public long getUpdateTime() {
+ return updateTime;
+ }
+
+ public void setUpdateTime(long updateTime) {
+ this.updateTime = updateTime;
+ }
+
+ @Override
+ public int compareTo(AppInfoVO appInfoVO) {
+ return Long.compare(updateTime, appInfoVO.getUpdateTime());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof AppInfoVO)) {
+ return false;
+ }
+ AppInfoVO appInfoVO = (AppInfoVO) o;
+ return updateTime == appInfoVO.updateTime
+ && userName.equals(appInfoVO.userName)
+ && appId.equals(appInfoVO.appId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(userName, appId, updateTime);
+ }
+}
diff --git
a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/APIResource.java
b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/vo/CoordinatorConfVO.java
similarity index 57%
copy from
coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/APIResource.java
copy to
coordinator/src/main/java/org/apache/uniffle/coordinator/web/vo/CoordinatorConfVO.java
index b01eb0d64..b3137ca8a 100644
---
a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/APIResource.java
+++
b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/vo/CoordinatorConfVO.java
@@ -15,22 +15,30 @@
* limitations under the License.
*/
-package org.apache.uniffle.coordinator.web.resource;
+package org.apache.uniffle.coordinator.web.vo;
-import org.apache.hbase.thirdparty.javax.ws.rs.Path;
-import org.apache.hbase.thirdparty.javax.ws.rs.Produces;
-import org.apache.hbase.thirdparty.javax.ws.rs.core.MediaType;
+public class CoordinatorConfVO {
+ private String argumentKey;
+ private String argumentValue;
-@Path("api")
-@Produces({MediaType.APPLICATION_JSON})
-public class APIResource {
- @Path("server")
- public Class<ServerResource> getServerResource() {
- return ServerResource.class;
+ public CoordinatorConfVO(String argumentKey, String argumentValue) {
+ this.argumentKey = argumentKey;
+ this.argumentValue = argumentValue;
}
- @Path("admin")
- public Class<AdminResource> getAdminResource() {
- return AdminResource.class;
+ public String getArgumentKey() {
+ return argumentKey;
+ }
+
+ public void setArgumentKey(String argumentKey) {
+ this.argumentKey = argumentKey;
+ }
+
+ public String getArgumentValue() {
+ return argumentValue;
+ }
+
+ public void setArgumentValue(String argumentValue) {
+ this.argumentValue = argumentValue;
}
}
diff --git
a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/vo/UserAppNumVO.java
b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/vo/UserAppNumVO.java
new file mode 100644
index 000000000..6d5b56bb2
--- /dev/null
+++
b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/vo/UserAppNumVO.java
@@ -0,0 +1,69 @@
+/*
+ * 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.uniffle.coordinator.web.vo;
+
+import java.util.Objects;
+
+public class UserAppNumVO implements Comparable<UserAppNumVO> {
+
+ private String userName;
+ private Integer appNum;
+
+ public UserAppNumVO(String userName, Integer appNum) {
+ this.userName = userName;
+ this.appNum = appNum;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public Integer getAppNum() {
+ return appNum;
+ }
+
+ public void setAppNum(Integer appNum) {
+ this.appNum = appNum;
+ }
+
+ @Override
+ public int compareTo(UserAppNumVO userAppNumVO) {
+ return Integer.compare(appNum, userAppNumVO.getAppNum());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof UserAppNumVO)) {
+ return false;
+ }
+ UserAppNumVO that = (UserAppNumVO) o;
+ return userName.equals(that.userName) && appNum.equals(that.appNum);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(userName, appNum);
+ }
+}