集群信息
This commit is contained in:
83
src/main/java/com/xuxd/kafka/console/beans/BrokerNode.java
Normal file
83
src/main/java/com/xuxd/kafka/console/beans/BrokerNode.java
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package com.xuxd.kafka.console.beans;
|
||||||
|
|
||||||
|
import org.apache.kafka.common.Node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* kafka-console-ui.
|
||||||
|
*
|
||||||
|
* @author xuxd
|
||||||
|
* @date 2021-10-08 14:03:21
|
||||||
|
**/
|
||||||
|
public class BrokerNode {
|
||||||
|
|
||||||
|
private int id;
|
||||||
|
|
||||||
|
private String idString;
|
||||||
|
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
private String rack;
|
||||||
|
|
||||||
|
private boolean isController;
|
||||||
|
|
||||||
|
public static BrokerNode fromNode(Node node) {
|
||||||
|
BrokerNode brokerNode = new BrokerNode();
|
||||||
|
brokerNode.setId(node.id());
|
||||||
|
brokerNode.setIdString(node.idString());
|
||||||
|
brokerNode.setHost(node.host());
|
||||||
|
brokerNode.setPort(node.port());
|
||||||
|
brokerNode.setRack(node.rack());
|
||||||
|
|
||||||
|
return brokerNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIdString() {
|
||||||
|
return idString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIdString(String idString) {
|
||||||
|
this.idString = idString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHost(String host) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPort(int port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRack() {
|
||||||
|
return rack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRack(String rack) {
|
||||||
|
this.rack = rack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isController() {
|
||||||
|
return isController;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setController(boolean controller) {
|
||||||
|
isController = controller;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/main/java/com/xuxd/kafka/console/beans/ClusterInfo.java
Normal file
42
src/main/java/com/xuxd/kafka/console/beans/ClusterInfo.java
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package com.xuxd.kafka.console.beans;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* kafka-console-ui.
|
||||||
|
*
|
||||||
|
* @author xuxd
|
||||||
|
* @date 2021-10-08 13:57:48
|
||||||
|
**/
|
||||||
|
public class ClusterInfo {
|
||||||
|
|
||||||
|
private Set<BrokerNode> nodes;
|
||||||
|
|
||||||
|
private Set<String> authorizedOperations;
|
||||||
|
|
||||||
|
private String clusterId;
|
||||||
|
|
||||||
|
public Set<BrokerNode> getNodes() {
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNodes(Set<BrokerNode> nodes) {
|
||||||
|
this.nodes = nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getAuthorizedOperations() {
|
||||||
|
return authorizedOperations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthorizedOperations(Set<String> authorizedOperations) {
|
||||||
|
this.authorizedOperations = authorizedOperations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClusterId() {
|
||||||
|
return clusterId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClusterId(String clusterId) {
|
||||||
|
this.clusterId = clusterId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.xuxd.kafka.console.config;
|
package com.xuxd.kafka.console.config;
|
||||||
|
|
||||||
|
import kafka.console.ClusterConsole;
|
||||||
import kafka.console.ConsumerConsole;
|
import kafka.console.ConsumerConsole;
|
||||||
import kafka.console.KafkaAclConsole;
|
import kafka.console.KafkaAclConsole;
|
||||||
import kafka.console.KafkaConfigConsole;
|
import kafka.console.KafkaConfigConsole;
|
||||||
@@ -35,4 +36,9 @@ public class KafkaConfiguration {
|
|||||||
public ConsumerConsole consumerConsole(KafkaConfig config) {
|
public ConsumerConsole consumerConsole(KafkaConfig config) {
|
||||||
return new ConsumerConsole(config);
|
return new ConsumerConsole(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ClusterConsole clusterConsole(KafkaConfig config) {
|
||||||
|
return new ClusterConsole(config);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.xuxd.kafka.console.controller;
|
||||||
|
|
||||||
|
import com.xuxd.kafka.console.service.ClusterService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* kafka-console-ui.
|
||||||
|
*
|
||||||
|
* @author xuxd
|
||||||
|
* @date 2021-10-08 14:26:11
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/cluster")
|
||||||
|
public class ClusterController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ClusterService clusterService;
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public Object getClusterInfo() {
|
||||||
|
return clusterService.getClusterInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.xuxd.kafka.console.service;
|
||||||
|
|
||||||
|
import com.xuxd.kafka.console.beans.ResponseData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* kafka-console-ui.
|
||||||
|
*
|
||||||
|
* @author xuxd
|
||||||
|
* @date 2021-10-08 14:22:30
|
||||||
|
**/
|
||||||
|
public interface ClusterService {
|
||||||
|
ResponseData getClusterInfo();
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.xuxd.kafka.console.service.impl;
|
||||||
|
|
||||||
|
import com.xuxd.kafka.console.beans.ResponseData;
|
||||||
|
import com.xuxd.kafka.console.service.ClusterService;
|
||||||
|
import kafka.console.ClusterConsole;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* kafka-console-ui.
|
||||||
|
*
|
||||||
|
* @author xuxd
|
||||||
|
* @date 2021-10-08 14:23:09
|
||||||
|
**/
|
||||||
|
@Service
|
||||||
|
public class ClusterServiceImpl implements ClusterService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ClusterConsole clusterConsole;
|
||||||
|
|
||||||
|
@Override public ResponseData getClusterInfo() {
|
||||||
|
return ResponseData.create().data(clusterConsole.clusterInfo()).success();
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/main/scala/kafka/console/ClusterConsole.scala
Normal file
44
src/main/scala/kafka/console/ClusterConsole.scala
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package kafka.console
|
||||||
|
|
||||||
|
import java.util.Collections
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
import com.xuxd.kafka.console.beans.{BrokerNode, ClusterInfo}
|
||||||
|
import com.xuxd.kafka.console.config.KafkaConfig
|
||||||
|
import org.apache.kafka.clients.admin.DescribeClusterResult
|
||||||
|
|
||||||
|
import scala.jdk.CollectionConverters.{CollectionHasAsScala, SetHasAsJava, SetHasAsScala}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* kafka-console-ui. cluster console.
|
||||||
|
*
|
||||||
|
* @author xuxd
|
||||||
|
* @date 2021-10-08 10:55:56
|
||||||
|
* */
|
||||||
|
class ClusterConsole(config: KafkaConfig) extends KafkaConsole(config: KafkaConfig) with Logging {
|
||||||
|
|
||||||
|
def clusterInfo(): ClusterInfo = {
|
||||||
|
withAdminClientAndCatchError(admin => {
|
||||||
|
val clusterResult: DescribeClusterResult = admin.describeCluster()
|
||||||
|
val clusterInfo = new ClusterInfo
|
||||||
|
clusterInfo.setClusterId(clusterResult.clusterId().get(3000, TimeUnit.MILLISECONDS))
|
||||||
|
val acls = clusterResult.authorizedOperations().get(3000, TimeUnit.MILLISECONDS)
|
||||||
|
if (acls != null) {
|
||||||
|
clusterInfo.setAuthorizedOperations(acls.asScala.map(_.toString).toSet[String].asJava)
|
||||||
|
} else {
|
||||||
|
clusterInfo.setAuthorizedOperations(Collections.emptySet())
|
||||||
|
}
|
||||||
|
clusterInfo.setNodes(clusterResult.nodes().get(3000, TimeUnit.MILLISECONDS).asScala.map(BrokerNode.fromNode(_)).toSet[BrokerNode].asJava)
|
||||||
|
val id = clusterResult.controller().get(3000, TimeUnit.MILLISECONDS).id()
|
||||||
|
clusterInfo.getNodes.asScala.foreach(n => {
|
||||||
|
if (n.getId == id) {
|
||||||
|
n.setController(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
clusterInfo
|
||||||
|
}, eh => {
|
||||||
|
log.error("get clusterInfo error.", eh)
|
||||||
|
new ClusterInfo
|
||||||
|
}).asInstanceOf[ClusterInfo]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,8 @@
|
|||||||
><router-link to="/acl-page" class="pad-l-r" v-show="config.enableAcl"
|
><router-link to="/acl-page" class="pad-l-r" v-show="config.enableAcl"
|
||||||
>Acl</router-link
|
>Acl</router-link
|
||||||
>
|
>
|
||||||
<span>|</span><router-link to="/op-page" class="pad-l-r">运维</router-link>
|
<span>|</span
|
||||||
|
><router-link to="/op-page" class="pad-l-r">运维</router-link>
|
||||||
</div>
|
</div>
|
||||||
<router-view class="content" />
|
<router-view class="content" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -37,6 +37,12 @@ const routes = [
|
|||||||
component: () =>
|
component: () =>
|
||||||
import(/* webpackChunkName: "op" */ "../views/op/Operation.vue"),
|
import(/* webpackChunkName: "op" */ "../views/op/Operation.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/cluster-page",
|
||||||
|
name: "Cluster",
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "cluster" */ "../views/cluster/Cluster.vue"),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const router = new VueRouter({
|
const router = new VueRouter({
|
||||||
|
|||||||
@@ -85,3 +85,10 @@ export const KafkaConsumerApi = {
|
|||||||
method: "get",
|
method: "get",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const KafkaClusterApi = {
|
||||||
|
getClusterInfo: {
|
||||||
|
url: "/cluster",
|
||||||
|
method: "get",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
92
ui/src/views/cluster/Cluster.vue
Normal file
92
ui/src/views/cluster/Cluster.vue
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<template>
|
||||||
|
<div class="content">
|
||||||
|
<a-spin :spinning="loading">
|
||||||
|
<div class="body-c">
|
||||||
|
<div class="cluster-id">
|
||||||
|
<h3>集群ID:{{ clusterId }}</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-table :columns="columns" :data-source="data" bordered row-key="name">
|
||||||
|
<div slot="addr" slot-scope="text, record">
|
||||||
|
{{ record.host }}:{{ record.port }}
|
||||||
|
</div>
|
||||||
|
<div slot="controller" slot-scope="text">
|
||||||
|
<span v-if="text" style="color: red">是</span><span v-else>否</span>
|
||||||
|
</div>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
</a-spin>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import request from "@/utils/request";
|
||||||
|
import { KafkaClusterApi } from "@/utils/api";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Topic",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
data: [],
|
||||||
|
columns,
|
||||||
|
loading: false,
|
||||||
|
clusterId: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getClusterInfo() {
|
||||||
|
this.loading = true;
|
||||||
|
request({
|
||||||
|
url: KafkaClusterApi.getClusterInfo.url,
|
||||||
|
method: KafkaClusterApi.getClusterInfo.method,
|
||||||
|
}).then((res) => {
|
||||||
|
this.loading = false;
|
||||||
|
this.data = res.data.nodes;
|
||||||
|
this.clusterId = res.data.clusterId;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getClusterInfo();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: "id",
|
||||||
|
dataIndex: "id",
|
||||||
|
key: "id",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "地址",
|
||||||
|
key: "addr",
|
||||||
|
scopedSlots: { customRender: "addr" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "控制器",
|
||||||
|
key: "controller",
|
||||||
|
dataIndex: "controller",
|
||||||
|
scopedSlots: { customRender: "controller" },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.body-c {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cluster-id {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operation-row-button {
|
||||||
|
height: 4%;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operation-btn {
|
||||||
|
margin-right: 3%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user