Commit b1396355 authored by wenmo's avatar wenmo

集群配置管理

parent db2a929c
package com.dlink.controller;
import com.dlink.common.result.ProTableResult;
import com.dlink.common.result.Result;
import com.dlink.model.ClusterConfiguration;
import com.dlink.service.ClusterConfigurationService;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
* ClusterConfigController
*
* @author wenmo
* @since 2021/11/6 21:16
*/
@Slf4j
@RestController
@RequestMapping("/api/clusterConfiguration")
public class ClusterConfigurationController {
@Autowired
private ClusterConfigurationService clusterConfigurationService;
/**
* 新增或者更新
*/
@PutMapping
public Result saveOrUpdate(@RequestBody ClusterConfiguration clusterConfiguration) {
if(clusterConfigurationService.saveOrUpdate(clusterConfiguration)){
return Result.succeed("新增成功");
}else {
return Result.failed("新增失败");
}
}
/**
* 动态查询列表
*/
@PostMapping
public ProTableResult<ClusterConfiguration> listClusterConfigs(@RequestBody JsonNode para) {
return clusterConfigurationService.selectForProTable(para);
}
/**
* 批量删除
*/
@DeleteMapping
public Result deleteMul(@RequestBody JsonNode para) {
if (para.size()>0){
List<Integer> error = new ArrayList<>();
for (final JsonNode item : para){
Integer id = item.asInt();
if(!clusterConfigurationService.removeById(id)){
error.add(id);
}
}
if(error.size()==0) {
return Result.succeed("删除成功");
}else {
return Result.succeed("删除部分成功,但"+error.toString()+"删除失败,共"+error.size()+"次失败。");
}
}else{
return Result.failed("请选择要删除的记录");
}
}
/**
* 获取指定ID的信息
*/
@PostMapping("/getOneById")
public Result getOneById(@RequestBody ClusterConfiguration clusterConfiguration) {
clusterConfiguration = clusterConfigurationService.getById(clusterConfiguration.getId());
return Result.succeed(clusterConfiguration,"获取成功");
}
}
package com.dlink.mapper;
import com.dlink.db.mapper.SuperMapper;
import com.dlink.model.ClusterConfiguration;
import org.apache.ibatis.annotations.Mapper;
/**
* ClusterMapper
*
* @author wenmo
* @since 2021/5/28 13:56
**/
@Mapper
public interface ClusterConfigurationMapper extends SuperMapper<ClusterConfiguration> {
}
package com.dlink.model;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.dlink.assertion.Asserts;
import com.dlink.db.model.SuperEntity;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.HashMap;
import java.util.Map;
/**
* ClusterConfig
*
* @author wenmo
* @since 2021/11/6
**/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("dlink_cluster_config")
public class ClusterConfiguration extends SuperEntity {
private static final long serialVersionUID = 5830130188542066241L;
@TableField(fill = FieldFill.INSERT)
private String alias;
private String type;
private String configJson;
private boolean isAvailable;
private String note;
@TableField(exist = false)
private Map<String,String> config = new HashMap<>();
public Map<String,String> parseConfig(){
ObjectMapper objectMapper = new ObjectMapper();
try {
if(Asserts.isNotNullString(configJson)) {
config = objectMapper.readValue(configJson, HashMap.class);
}
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return config;
}
}
package com.dlink.service;
import com.dlink.db.service.ISuperService;
import com.dlink.model.ClusterConfiguration;
/**
* ClusterConfigService
*
* @author wenmo
* @since 2021/11/6 20:52
*/
public interface ClusterConfigurationService extends ISuperService<ClusterConfiguration> {
ClusterConfiguration getClusterConfigById(Integer id);
}
package com.dlink.service.impl;
import com.dlink.db.service.impl.SuperServiceImpl;
import com.dlink.mapper.ClusterConfigurationMapper;
import com.dlink.model.ClusterConfiguration;
import com.dlink.service.ClusterConfigurationService;
import org.springframework.stereotype.Service;
/**
* ClusterConfigServiceImpl
*
* @author wenmo
* @since 2021/11/6 20:54
*/
@Service
public class ClusterConfigurationServiceImpl extends SuperServiceImpl<ClusterConfigurationMapper,ClusterConfiguration> implements ClusterConfigurationService {
@Override
public ClusterConfiguration getClusterConfigById(Integer id) {
ClusterConfiguration clusterConfiguration = baseMapper.selectById(id);
clusterConfiguration.parseConfig();
return clusterConfiguration;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dlink.mapper.ClusterConfigurationMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.dlink.model.ClusterConfiguration">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="alias" property="alias" />
<result column="type" property="type" />
<result column="config_json" property="configJson" />
<result column="is_available" property="isAvailable" />
<result column="note" property="note" />
<result column="enabled" property="enabled" />
<result column="create_time" property="createTime" />
<result column="update_time" property="updateTime" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, name, alias, type,config_json,is_available,note, enabled, create_time, update_time
</sql>
<select id="selectForProTable" resultType="com.dlink.model.ClusterConfiguration">
select
a.*
from
dlink_cluster_configuration a
<where>
1=1
<if test='param.name!=null and param.name!=""'>
and a.name like "%${param.name}%"
</if>
<if test='param.alias!=null and param.alias!=""'>
and a.alias like "%${param.alias}%"
</if>
<if test='param.createTime!=null and param.createTime!=""'>
and a.create_time <![CDATA[>=]]> str_to_date( #{param.createTime},'%Y-%m-%d %H:%i:%s')
</if>
<if test='param.updateTime!=null and param.updateTime!=""'>
and a.update_time <![CDATA[>=]]> str_to_date( #{param.updateTime},'%Y-%m-%d %H:%i:%s')
</if>
<if test='ew.sqlSegment!=null and ew.sqlSegment!="" and !ew.sqlSegment.startsWith(" ORDER BY")'>
and
</if>
<if test='ew.sqlSegment!=null and ew.sqlSegment!=""'>
${ew.sqlSegment}
</if>
</where>
</select>
</mapper>
......@@ -60,7 +60,7 @@
</plugins>
</build>
<properties>
<flink.version>1.12.5</flink.version>
<flink.version>1.13.3</flink.version>
<java.version>1.8</java.version>
<clickhouse-jdbc.version>0.2.6</clickhouse-jdbc.version>
<mariadb-java-client.version>2.5.4</mariadb-java-client.version>
......
......@@ -26,6 +26,7 @@ import org.apache.hadoop.yarn.api.records.ApplicationId;
import org.apache.hadoop.yarn.client.api.YarnClient;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
......@@ -69,7 +70,9 @@ public abstract class YarnGateway extends AbstractGateway {
private void initYarnClient(){
yarnConfiguration = new YarnConfiguration();
yarnConfiguration.addResource( new Path( config.getClusterConfig().getYarnConfigPath() ) );
yarnConfiguration.addResource( new Path( URI.create(config.getClusterConfig().getYarnConfigPath()+"/yarn-site.xml") ) );
yarnConfiguration.addResource( new Path( URI.create(config.getClusterConfig().getYarnConfigPath()+"/core-site.xml") ) );
yarnConfiguration.addResource( new Path( URI.create(config.getClusterConfig().getYarnConfigPath()+"/hdfs-site.xml") ) );
yarnClient = YarnClient.createYarnClient();
yarnClient.init(yarnConfiguration);
yarnClient.start();
......
export type ClusterConfigerationTableListItem = {
id: number,
name: string,
alias: string,
type: string,
config: any,
isAvailable: boolean,
note: string,
enabled: boolean,
createTime: Date,
updateTime: Date,
};
import React, {useRef, useState} from "react";
import {DownOutlined, HeartOutlined, PlusOutlined, UserOutlined} from '@ant-design/icons';
import {ClusterConfigerationTableListItem} from "@/pages/Cluster/data";
import {ActionType, ProColumns} from "@ant-design/pro-table";
import {Button, message, Input, Drawer, Modal, Dropdown, Menu} from 'antd';
import {PageContainer, FooterToolbar} from '@ant-design/pro-layout';
import type {ProColumns, ActionType} from '@ant-design/pro-table';
import ProTable from '@ant-design/pro-table';
import ProDescriptions from '@ant-design/pro-descriptions';
import {ClusterConfigerationTableListItem} from "@/pages/ClusterConfiguration/data";
import {handleAddOrUpdate, handleRemove, queryData, updateEnabled} from "@/components/Common/crud";
import {showCluster} from "@/components/Studio/StudioEvent/DDL";
const url = '/api/clusterConfigeration';
const ClusterConfigurationTableList: React.FC<{}> = (props: any) => {
const {dispatch} = props;
const [row, setRow] = useState<ClusterConfigerationTableListItem>();
const [createModalVisible, handleModalVisible] = useState<boolean>(false);
const [updateModalVisible, handleUpdateModalVisible] = useState<boolean>(false);
const [formValues, setFormValues] = useState({});
const actionRef = useRef<ActionType>();
const [selectedRowsState, setSelectedRows] = useState<ClusterConfigerationTableListItem[]>([]);
const editAndDelete = (key: string | number, currentItem: ClusterConfigerationTableListItem) => {
if (key === 'edit') {
handleUpdateModalVisible(true);
setFormValues(currentItem);
} else if (key === 'delete') {
Modal.confirm({
title: '删除集群配置',
content: '确定删除该集群配置吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await handleRemove(url, [currentItem]);
actionRef.current?.reloadAndRest?.();
}
});
}
};
const MoreBtn: React.FC<{
item: ClusterConfigerationTableListItem;
}> = ({item}) => (
<Dropdown
overlay={
<Menu onClick={({key}) => editAndDelete(key, item)}>
<Menu.Item key="edit">编辑</Menu.Item>
<Menu.Item key="delete">删除</Menu.Item>
</Menu>
}
>
<a>
更多 <DownOutlined/>
</a>
</Dropdown>
);
const columns: ProColumns<ClusterConfigerationTableListItem>[] = [
{
title: '名称',
dataIndex: 'name',
tip: '名称是唯一的',
sorter: true,
formItemProps: {
rules: [
{
required: true,
message: '名称为必填项',
},
],
},
render: (dom, entity) => {
return <a onClick={() => setRow(entity)}>{dom}</a>;
},
},
{
title: '集群配置ID',
dataIndex: 'id',
hideInTable: true,
hideInForm: true,
hideInSearch: true,
},
{
title: '别名',
sorter: true,
dataIndex: 'alias',
hideInTable: false,
},
{
title: '类型',
sorter: true,
dataIndex: 'type',
hideInForm: false,
hideInSearch: true,
hideInTable: false,
filters: [
{
text: 'Yarn',
value: 'Yarn',
},
{
text: 'Standalone',
value: 'Standalone',
},
{
text: 'Others',
value: 'Others',
},
],
filterMultiple: false,
valueEnum: {
'Yarn': {text: 'Yarn'},
'Standalone': {text: 'Standalone'},
'Others': {text: 'Others'},
},
},
{
title: '是否可用',
dataIndex: 'enabled',
hideInForm: true,
hideInSearch: true,
hideInTable: false,
filters: [
{
text: '可用',
value: 1,
},
{
text: '不可用',
value: 0,
},
],
filterMultiple: false,
valueEnum: {
true: {text: '可用', status: 'Success'},
false: {text: '不可用', status: 'Error'},
},
},
{
title: '注释',
sorter: true,
valueType: 'textarea',
dataIndex: 'note',
hideInForm: false,
hideInSearch: true,
hideInTable: true,
},
{
title: '是否启用',
dataIndex: 'enabled',
hideInForm: true,
hideInSearch: true,
hideInTable: false,
filters: [
{
text: '已启用',
value: 1,
},
{
text: '已禁用',
value: 0,
},
],
filterMultiple: false,
valueEnum: {
true: {text: '已启用', status: 'Success'},
false: {text: '已禁用', status: 'Error'},
},
},
{
title: '创建时间',
dataIndex: 'createTime',
sorter: true,
valueType: 'dateTime',
hideInForm: true,
hideInTable: true,
renderFormItem: (item, {defaultRender, ...rest}, form) => {
const status = form.getFieldValue('status');
if (`${status}` === '0') {
return false;
}
if (`${status}` === '3') {
return <Input {...rest} placeholder="请输入异常原因!"/>;
}
return defaultRender(item);
},
},
{
title: '最近更新时间',
dataIndex: 'updateTime',
sorter: true,
valueType: 'dateTime',
hideInForm: true,
renderFormItem: (item, {defaultRender, ...rest}, form) => {
const status = form.getFieldValue('status');
if (`${status}` === '0') {
return false;
}
if (`${status}` === '3') {
return <Input {...rest} placeholder="请输入异常原因!"/>;
}
return defaultRender(item);
},
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => [
<a
onClick={() => {
handleUpdateModalVisible(true);
setFormValues(record);
}}
>
配置
</a>,
<MoreBtn key="more" item={record}/>,
],
},
];
return (
<PageContainer>
<ProTable<ClusterConfigerationTableListItem>
headerTitle="集群配置管理"
actionRef={actionRef}
rowKey="id"
search={{
labelWidth: 120,
}}
toolBarRender={() => [
<Button type="primary" onClick={() => handleModalVisible(true)}>
<PlusOutlined/> 新建
</Button>,
]}
request={(params, sorter, filter) => queryData(url, {...params, sorter, filter})}
columns={columns}
rowSelection={{
onChange: (_, selectedRows) => setSelectedRows(selectedRows),
}}
/>
{selectedRowsState?.length > 0 && (
<FooterToolbar
extra={
<div>
已选择 <a style={{fontWeight: 600}}>{selectedRowsState.length}</a>&nbsp;&nbsp;
<span>
被禁用的集群配置共 {selectedRowsState.length - selectedRowsState.reduce((pre, item) => pre + (item.enabled ? 1 : 0), 0)}
</span>
</div>
}
>
<Button type="primary" danger
onClick={() => {
Modal.confirm({
title: '删除集群配置',
content: '确定删除选中的集群配置吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await handleRemove(url, selectedRowsState);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>
批量删除
</Button>
<Button type="primary"
onClick={() => {
Modal.confirm({
title: '启用集群配置',
content: '确定启用选中的集群配置吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await updateEnabled(url, selectedRowsState, true);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>批量启用</Button>
<Button danger
onClick={() => {
Modal.confirm({
title: '禁用集群配置',
content: '确定禁用选中的集群配置吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await updateEnabled(url, selectedRowsState, false);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>批量禁用</Button>
</FooterToolbar>
)}
<Drawer
width={600}
visible={!!row}
onClose={() => {
setRow(undefined);
}}
closable={false}
>
{row?.name && (
<ProDescriptions<ClusterConfigerationTableListItem>
column={2}
title={row?.name}
request={async () => ({
data: row || {},
})}
params={{
id: row?.name,
}}
columns={columns}
/>
)}
</Drawer>
</PageContainer>
);
};
export default ClusterConfigerationTableList;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment