From 947b0bfa048ac5a2cedc92df61b5378c224397a9 Mon Sep 17 00:00:00 2001 From: liugq Date: Fri, 8 Oct 2021 14:53:47 +0800 Subject: [PATCH] modify cluster overview and alerting --- api/index_management/elasticsearch.go | 87 ++++++++++ api/init.go | 2 + service/alerting/monitor.go | 4 +- web/config/router.config.js | 6 +- .../console/components/ConsoleInput.tsx | 4 +- .../kibana/console/services/settings.ts | 2 +- web/src/lib/format.js | 19 +++ web/src/locales/en-US/alert.js | 1 + web/src/locales/zh-CN/alert.js | 3 +- .../components/Flyout/flyouts/message.js | 5 +- .../Flyout/flyouts/triggerCondition.js | 12 +- web/src/pages/Alerting/destination.js | 5 +- web/src/pages/Alerting/index.js | 21 ++- .../Dashboard/containers/AlertOverview.tsx | 77 ++++----- .../pages/Dashboard/containers/Dashboard.js | 61 +++++-- .../pages/Dashboard/utils/tableUtils.js | 2 +- .../containers/Triggers/Triggers.js | 17 +- web/src/pages/Cluster/Overview.js | 154 ++++++++++++++++-- web/src/pages/Cluster/models/overview.js | 48 ++++++ web/src/services/overview.js | 8 + 20 files changed, 439 insertions(+), 99 deletions(-) create mode 100644 api/index_management/elasticsearch.go create mode 100644 web/src/lib/format.js create mode 100644 web/src/pages/Cluster/models/overview.js create mode 100644 web/src/services/overview.js diff --git a/api/index_management/elasticsearch.go b/api/index_management/elasticsearch.go new file mode 100644 index 00000000..ece9809e --- /dev/null +++ b/api/index_management/elasticsearch.go @@ -0,0 +1,87 @@ +package index_management + +import ( + "fmt" + httprouter "infini.sh/framework/core/api/router" + "infini.sh/framework/core/elastic" + "infini.sh/framework/core/orm" + "infini.sh/framework/core/util" + "infini.sh/framework/modules/elastic/common" + "net/http" + log "github.com/cihub/seelog" +) + +func (handler APIHandler) ElasticsearchOverviewAction(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + var ( + totalNode int + totalStoreSize int + hosts = map[string]struct{}{} + ) + elastic.WalkConfigs(func(key, value interface{})bool{ + if handler.Config.Elasticsearch == key { + return true + } + data, err := handler.getLatestClusterMonitorData(key) + if err != nil{ + log.Error(err) + } + val, err := data.GetValue("cluster_stats.nodes.count.total") + if err != nil { + log.Warn(err) + } + if num, ok := val.(float64); ok { + totalNode += int(num) + } + val, err = data.GetValue("index_stats._all.total.store.size_in_bytes") + if err != nil { + log.Warn(err) + } + if num, ok := val.(float64); ok { + totalStoreSize += int(num) + } + + val, err = data.GetValue("agent.ip") + if err != nil { + log.Warn(err) + } + if ip, ok := val.(string); ok { + hosts[ip] = struct{}{} + } + return true + }) + resBody := util.MapStr{ + "total_node": totalNode, + "total_store_size_in_bytes": totalStoreSize, + "total_host": len(hosts), + //"hosts": hosts, + } + handler.WriteJSON(w, resBody, http.StatusOK) +} + +func (handler APIHandler) getLatestClusterMonitorData(clusterID interface{}) (util.MapStr, error){ + client := elastic.GetClient(handler.Config.Elasticsearch) + queryDSLTpl := `{ + "size": 1, + "query": { + "match": { + "elasticsearch": "%s" + } + }, + "sort": [ + { + "cluster_stats.timestamp": { + "order": "desc" + } + } + ] +}` + queryDSL := fmt.Sprintf(queryDSLTpl, clusterID) + searchRes, err := client.SearchWithRawQueryDSL(orm.GetIndexName(common.MonitoringItem{}), []byte(queryDSL)) + if err != nil { + return nil, err + } + if len(searchRes.Hits.Hits) == 0 { + return nil, nil + } + return searchRes.Hits.Hits[0].Source, nil +} diff --git a/api/init.go b/api/init.go index dfc444b2..8183eeb7 100644 --- a/api/init.go +++ b/api/init.go @@ -17,6 +17,8 @@ func Init(cfg *config.AppConfig) { } var pathPrefix = "/_search-center/" //ui.HandleUIMethod(api.POST, "/api/get_indices",index_management.API1) + ui.HandleUIMethod(api.GET, path.Join(pathPrefix, "elasticsearch/overview"), handler.ElasticsearchOverviewAction) + ui.HandleUIMethod(api.GET, path.Join(pathPrefix, "dict/_search"), handler.GetDictListAction) ui.HandleUIMethod(api.POST, path.Join(pathPrefix, "dict/*id"), handler.CreateDictItemAction) //ui.HandleUIMethod(api.GET, "/api/dict/:id",handler.GetDictItemAction) diff --git a/service/alerting/monitor.go b/service/alerting/monitor.go index 13ec49cc..5da1e0b9 100644 --- a/service/alerting/monitor.go +++ b/service/alerting/monitor.go @@ -679,14 +679,14 @@ func ExecuteMonitor(w http.ResponseWriter, req *http.Request, ps httprouter.Para } monitorCtx, err := createMonitorContext(&trigger, resBody, &sm, IfaceMap{}) if err != nil { - triggerResult["error"] = err + triggerResult["error"] = err.Error() triggerResults[trigger.ID] = triggerResult continue } isTrigger, err := resolveTriggerResult(&trigger, monitorCtx) triggerResult["triggered"] = isTrigger if err != nil { - triggerResult["error"] = err + triggerResult["error"] = err.Error() } if trigger.ID == "" { trigger.ID = util.GetUUID() diff --git a/web/config/router.config.js b/web/config/router.config.js index 41da0947..0a975c31 100644 --- a/web/config/router.config.js +++ b/web/config/router.config.js @@ -214,9 +214,9 @@ export default [ }, ] }, - // - // - // //search + + + //search // { // path: '/search', // name: 'search', diff --git a/web/src/components/kibana/console/components/ConsoleInput.tsx b/web/src/components/kibana/console/components/ConsoleInput.tsx index f1b6f577..663a70bc 100644 --- a/web/src/components/kibana/console/components/ConsoleInput.tsx +++ b/web/src/components/kibana/console/components/ConsoleInput.tsx @@ -65,7 +65,7 @@ const SendRequestButton = (props: any) => { interface ConsoleInputProps { clusterID: string, - initialText: string, + initialText: string | undefined, } const DEFAULT_INPUT_VALUE = `GET _search @@ -198,7 +198,7 @@ const ConsoleInputUI = ({clusterID, initialText}:ConsoleInputProps) => { ); }; -const ConsoleInput = ({clusterID}:ConsoleInputProps)=>{ +const ConsoleInput = ({clusterID}:{clusterID:string})=>{ const { done, error, retry } = useDataInit(); const { currentTextObject } = useEditorReadContext(); return done ? : <> diff --git a/web/src/components/kibana/console/services/settings.ts b/web/src/components/kibana/console/services/settings.ts index 434b82ab..564f0347 100644 --- a/web/src/components/kibana/console/services/settings.ts +++ b/web/src/components/kibana/console/services/settings.ts @@ -35,7 +35,7 @@ export class Settings { constructor(private readonly storage: Storage) {} getFontSize() { - return this.storage.get('font_size', 14); + return this.storage.get('font_size', 12); } setFontSize(size: any) { diff --git a/web/src/lib/format.js b/web/src/lib/format.js new file mode 100644 index 00000000..c4d8257a --- /dev/null +++ b/web/src/lib/format.js @@ -0,0 +1,19 @@ +const unitArr = Array("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"); + +export const formatter = { + bytes: (value) => { + if (isNaN(value) || null == value || value === ''||value==0) { + return "0B"; + } + var index = 0; + var srcsize = parseFloat(value); + index = Math.floor(Math.log(srcsize) / Math.log(1024)); + var size = srcsize / Math.pow(1024, index); + size = size.toFixed(1); + return { + size, + unit: unitArr[index], + }; + }, +} + diff --git a/web/src/locales/en-US/alert.js b/web/src/locales/en-US/alert.js index 7f4e7bb3..1ccfb728 100644 --- a/web/src/locales/en-US/alert.js +++ b/web/src/locales/en-US/alert.js @@ -145,6 +145,7 @@ export default { 'alert.trigger.edit.action.field.name': 'Action name', 'alert.trigger.edit.action.field.destination': 'Destination', 'alert.trigger.edit.action.field.message': 'Message', + 'alert.trigger.edit.action.field.message.info.paragraph1': 'You have access to a "_ctx" variable in your yaml scripts and action templates.', 'alert.trigger.edit.action.field.message_subject': 'Message subject', 'alert.trigger.edit.action.field.message_preview': 'Message preview', 'alert.trigger.edit.action.send_test_message': 'Send test message', diff --git a/web/src/locales/zh-CN/alert.js b/web/src/locales/zh-CN/alert.js index 135868e0..f0e27965 100644 --- a/web/src/locales/zh-CN/alert.js +++ b/web/src/locales/zh-CN/alert.js @@ -143,7 +143,8 @@ export default { 'alert.trigger.edit.action.button.add_action': '添加通知', 'alert.trigger.edit.action.field.name': '通知名称', 'alert.trigger.edit.action.field.destination': '渠道选择', - 'alert.trigger.edit.action.field.message': '消息配置', + 'alert.trigger.edit.action.field.message': '消息', + 'alert.trigger.edit.action.field.message.info.paragraph1': '您可以在 yaml 脚本中和通知模版中访问 "_ctx" 变量', 'alert.trigger.edit.action.field.message_subject': '消息标题', 'alert.trigger.edit.action.field.message_preview': '消息预览', 'alert.trigger.edit.action.send_test_message': '发送测试消息', diff --git a/web/src/pages/Alerting/components/Flyout/flyouts/message.js b/web/src/pages/Alerting/components/Flyout/flyouts/message.js index ded35adc..520f5ebf 100644 --- a/web/src/pages/Alerting/components/Flyout/flyouts/message.js +++ b/web/src/pages/Alerting/components/Flyout/flyouts/message.js @@ -16,6 +16,7 @@ import React from 'react'; import { EuiLink, EuiText, EuiTitle } from '@elastic/eui'; import { URL } from '../../../utils/constants'; +import {formatMessage} from 'umi/locale'; const message = () => ({ flyoutProps: { @@ -27,14 +28,14 @@ const message = () => ({ header: (

- Message + {formatMessage({id:"alert.trigger.edit.action.field.message"})}

), body: (

- {`You have access to a "_ctx" variable in your yaml scripts and action quicktemplate templates.`} + {formatMessage({id:"alert.trigger.edit.action.field.message.info.paragraph1"})}

{/*

Learn More

    diff --git a/web/src/pages/Alerting/components/Flyout/flyouts/triggerCondition.js b/web/src/pages/Alerting/components/Flyout/flyouts/triggerCondition.js index 581e030d..ebfe3f86 100644 --- a/web/src/pages/Alerting/components/Flyout/flyouts/triggerCondition.js +++ b/web/src/pages/Alerting/components/Flyout/flyouts/triggerCondition.js @@ -34,7 +34,7 @@ const CONTEXT_VARIABLES = JSON.stringify( const triggerCondition = context => ({ flyoutProps: { 'aria-labelledby': 'triggerConditionFlyout', - maxWidth: 500, + maxWidth: 540, size: 'm', }, headerProps: { hasBorder: true }, @@ -50,6 +50,16 @@ const triggerCondition = context => ({

    {formatMessage({id:'alert.trigger.edit.define.field.condition.info.paragraph1'})}

    + 逻辑判断操作包括 or, and, not, in, range, equals, contains, regexp。其中 or, and, not 支持嵌套,如 + + {`and: + - range: + _ctx.results.[0].hits.total.value.gt: 0 + - contains: + _ctx.results.[0].hits.hits.[0]._source.field: value`} + +

    +

    {formatMessage({id:'alert.trigger.edit.define.field.condition.info.paragraph2'})}

    diff --git a/web/src/pages/Alerting/destination.js b/web/src/pages/Alerting/destination.js index ae4bedfd..e2fb94b7 100644 --- a/web/src/pages/Alerting/destination.js +++ b/web/src/pages/Alerting/destination.js @@ -5,6 +5,7 @@ import DestinationsList from './pages/Destinations/containers/DestinationsList'; import {Fetch} from '../../components/kibana/core/public/http/fetch'; import {ScopedHistory} from '../../components/kibana/core/public/application/scoped_history'; import {notification} from 'antd'; +import PageHeaderWrapper from '@/components/PageHeaderWrapper'; const Destination = ({httpClient, notifications, history})=> { return ( @@ -85,6 +86,8 @@ export default (props)=>{ }, [props.history]) return ( - + + + ) } \ No newline at end of file diff --git a/web/src/pages/Alerting/index.js b/web/src/pages/Alerting/index.js index 27b9a9cc..cad400b3 100644 --- a/web/src/pages/Alerting/index.js +++ b/web/src/pages/Alerting/index.js @@ -6,6 +6,7 @@ import {useMemo} from 'react'; import {ScopedHistory} from '../../components/kibana/core/public/application/scoped_history'; import {notification} from 'antd'; import {connect} from 'dva' +import PageHeaderWrapper from '@/components/PageHeaderWrapper'; const httpClient = new Fetch({ basePath:{ @@ -49,15 +50,17 @@ const AlertingUI = (props)=>{ }, [props.history]) return ( - - -
    -
    -
    -
    -
    + + + +
    +
    +
    +
    +
    +
    ) } diff --git a/web/src/pages/Alerting/pages/Dashboard/containers/AlertOverview.tsx b/web/src/pages/Alerting/pages/Dashboard/containers/AlertOverview.tsx index 79f64142..28145c63 100644 --- a/web/src/pages/Alerting/pages/Dashboard/containers/AlertOverview.tsx +++ b/web/src/pages/Alerting/pages/Dashboard/containers/AlertOverview.tsx @@ -4,6 +4,7 @@ import {useState, useEffect} from 'react'; import './alertoverview.scss'; import { formatMessage } from 'umi/locale'; + export const AlertOverview = (props: any)=>{ const {httpClient, history} = props; const [data, setData] = useState({ @@ -16,8 +17,7 @@ export const AlertOverview = (props: any)=>{ totalAlerts: 0, }); - const getAlerts = _.debounce( - (from, size, search, sortField, sortDirection, severityLevel, alertState, monitorIds, type) => { + const getAlerts = (from, size, search, sortField, sortDirection, severityLevel, alertState, monitorIds, type) => { let params = { from, size, @@ -31,41 +31,42 @@ export const AlertOverview = (props: any)=>{ if(monitorIds){ params["monitorIds"]= monitorIds; } - httpClient.get('/alerting/alerts', { query: params }).then((resp:any) => { - if (resp.ok) { + return httpClient.get('/alerting/alerts', { query: params }) + } + + const useData = (pageSize: number, page: number, type: string):[any,any] => { + const [size, setSize] = useState(pageSize || 10); + const [pageIndex, setPageIndex] = useState(page || 1); + const [alertData, setAlertData] = useState({ + data: [], + total: 0, + }); + useEffect(()=>{ + const from = (pageIndex - 1) * size; + const fetchAlerts = async (from: number, size: number)=>{ + const resp = await getAlerts(from, size,"", "start_time", "desc", "ALL", "ALL","", type); + if(resp.ok){ const { alerts, totalAlerts } = resp; - if(type == 'ALERT_HISTORY'){ - setHistoryData({ - alerts, - totalAlerts, - }); - return; - } - setData({ - alerts, - totalAlerts, - }); - } else { - console.log('error getting alerts:', resp); + setAlertData({ + ...alertData, + data: alerts, + total: totalAlerts, + }) } - }); - }, - 500, - { leading: true } - ); + } + fetchAlerts(from,size); + }, [pageIndex, size, type]); + const changePage = (pageIndex: number) => { + setPageIndex(pageIndex); + } + + return [alertData, changePage]; + } const pageSize = 10; - useEffect(()=>{ - getAlerts(0, pageSize, "", "start_time", "desc", "ALL", "ALL","", "ALERT"); - getAlerts(0, pageSize, "", "start_time", "desc", "ALL", "ALL","", "ALERT_HISTORY") - },[]) + const [alerts, onAlertPageChange] = useData(pageSize, 1, "ALERT"); + const [historyAlerts, onAlertHistoryPageChange] = useData(pageSize, 1, "ALERT_HISTORY"); - const onPageChangeGen = (type:string) => { - return (pageIndex: number)=>{ - const from = (pageIndex - 1) * pageSize; - getAlerts(from, pageSize, "", "start_time", "desc", "ALL", "ALL","", type) - } - } const onItemClick = (item: any)=>{ @@ -75,21 +76,21 @@ export const AlertOverview = (props: any)=>{ return (
    - -
    {/*
    diff --git a/web/src/pages/Alerting/pages/Dashboard/containers/Dashboard.js b/web/src/pages/Alerting/pages/Dashboard/containers/Dashboard.js index ca000e2c..7d40c9ed 100644 --- a/web/src/pages/Alerting/pages/Dashboard/containers/Dashboard.js +++ b/web/src/pages/Alerting/pages/Dashboard/containers/Dashboard.js @@ -16,7 +16,7 @@ import React, { Component } from 'react'; import _ from 'lodash'; import queryString from 'query-string'; -import { EuiBasicTable, EuiButton, EuiHorizontalRule, EuiIcon,RIGHT_ALIGNMENT,EuiButtonIcon } from '@elastic/eui'; +import { EuiBasicTable, EuiButton, EuiHorizontalRule, EuiIcon,RIGHT_ALIGNMENT,EuiButtonIcon,EuiDescriptionList } from '@elastic/eui'; import ContentPanel from '../../../components/ContentPanel'; import DashboardEmptyPrompt from '../components/DashboardEmptyPrompt'; @@ -55,20 +55,6 @@ export default class Dashboard extends Component { sortField, } = this.getURLQueryParams(); - const tableColumns = [...columns, { - align: RIGHT_ALIGNMENT, - width: '40px', - isExpander: true, - render: (item) => { - const {itemIdToExpandedRowMap} = this.state; - ( - toggleDetails(item)} - aria-label={itemIdToExpandedRowMap[item.id] ? 'Collapse' : 'Expand'} - iconType={itemIdToExpandedRowMap[item.id] ? 'arrowUp' : 'arrowDown'} - /> - )}, - }] this.state = { alerts: [], @@ -83,7 +69,7 @@ export default class Dashboard extends Component { sortField, totalAlerts: 0, itemIdToExpandedRowMap:{}, - columns: tableColumns, + columns: columns, }; } @@ -305,6 +291,27 @@ export default class Dashboard extends Component { this.setState({ page }); }; + toggleDetails = (item)=>{ + const id = `${item.id}-${item.version}`; + const itemIdToExpandedRowMapValues = { ...this.state.itemIdToExpandedRowMap }; + if (itemIdToExpandedRowMapValues[id]) { + delete itemIdToExpandedRowMapValues[id]; + } else { + const listItems = [ + { + title: 'error', + description: `${item.error_message}`, + } + ] + itemIdToExpandedRowMapValues[id] = ( + + ); + } + this.setState({ + itemIdToExpandedRowMap:itemIdToExpandedRowMapValues, + }); + } + render() { const { alerts, @@ -316,9 +323,28 @@ export default class Dashboard extends Component { sortDirection, sortField, totalAlerts, + columns, + itemIdToExpandedRowMap, } = this.state; const { monitorIds, detectorIds, onCreateTrigger } = this.props; + const tableColumns = [...columns, { + align: RIGHT_ALIGNMENT, + width: '40px', + isExpander: true, + render: (item) => { + if(item.state != 'ERROR'){ + return null; + } + return ( + this.toggleDetails(item)} + aria-label={itemIdToExpandedRowMap[item.id] ? 'Collapse' : 'Expand'} + iconType={itemIdToExpandedRowMap[item.id] ? 'arrowUp' : 'arrowDown'} + /> + )}, + }] + const pagination = { pageIndex: page, pageSize: size, @@ -376,6 +402,7 @@ export default class Dashboard extends Component { `${item.id}-${item.version}`} - columns={this.state.columns} + columns={tableColumns} pagination={pagination} sorting={sorting} isSelectable={true} diff --git a/web/src/pages/Alerting/pages/Dashboard/utils/tableUtils.js b/web/src/pages/Alerting/pages/Dashboard/utils/tableUtils.js index f6a64f68..5068c2c2 100644 --- a/web/src/pages/Alerting/pages/Dashboard/utils/tableUtils.js +++ b/web/src/pages/Alerting/pages/Dashboard/utils/tableUtils.js @@ -85,7 +85,7 @@ export const columns = [ render: (state, alert) => { const stateText = typeof state !== 'string' ? DEFAULT_EMPTY_DATA : _.capitalize(state.toLowerCase()); - return state === ALERT_STATE.ERROR ? `${stateText}: ${alert.error_message}` : (stateOptions[state] || stateText); + return (stateOptions[state] || stateText); // state === ALERT_STATE.ERROR ? `${stateText}: ${alert.error_message}` : }, }, { diff --git a/web/src/pages/Alerting/pages/MonitorDetails/containers/Triggers/Triggers.js b/web/src/pages/Alerting/pages/MonitorDetails/containers/Triggers/Triggers.js index f30c5f80..b0bc2bf2 100644 --- a/web/src/pages/Alerting/pages/MonitorDetails/containers/Triggers/Triggers.js +++ b/web/src/pages/Alerting/pages/MonitorDetails/containers/Triggers/Triggers.js @@ -98,6 +98,17 @@ export default class Triggers extends Component { sortable: true, truncateText: false, }, + { + actions: [{ + name: 'Edit', + icon: 'documentEdit', + type: 'icon', + description: formatMessage({ id: 'form.button.edit' }), + onClick: (item)=>{ + this.props.onEditTrigger(item); + }, + }], + }, ]; const sorting = { sort: { field, direction } }; @@ -110,9 +121,9 @@ export default class Triggers extends Component { titleSize="s" bodyStyles={{ padding: 'initial' }} actions={[ - - {formatMessage({ id: 'form.button.edit' })} - , + // + // {formatMessage({ id: 'form.button.edit' })} + // , {formatMessage({ id: 'form.button.delete' })} , diff --git a/web/src/pages/Cluster/Overview.js b/web/src/pages/Cluster/Overview.js index 4be8b364..5754e7b6 100644 --- a/web/src/pages/Cluster/Overview.js +++ b/web/src/pages/Cluster/Overview.js @@ -1,8 +1,11 @@ import React from 'react'; -import {List,Card,Row,Icon,Col} from "antd"; +import {List,Card,Row,Icon,Col, Table} from "antd"; import styles from "./Overview.less"; import {connect} from "dva"; import {formatGigNumber} from "@/utils/utils"; +import {HealthStatusCircle} from '@/components/infini/health_status_circle'; +import {formatter} from '@/lib/format'; +import Link from 'umi/link'; const tabList = [ @@ -10,19 +13,21 @@ const tabList = [ key: 'tabCluster', tab: '集群', }, - { - key: 'tabHost', - tab: '主机', - }, - { - key: 'tabNode', - tab: '节点', - }, + // { + // key: 'tabHost', + // tab: '主机', + // }, + // { + // key: 'tabNode', + // tab: '节点', + // }, ]; -@connect(({global}) => ({ - +@connect(({clusterOverview, global}) => ({ + clusterList: clusterOverview.clusterList, + clusterStatus: global.clusterStatus, + overview: clusterOverview.overview, })) @@ -30,22 +35,134 @@ class Overview extends React.Component { state = { tabkey: 'tabCluster', }; + clusterColumns = [{ + title: '集群名称', + dataIndex: 'name', + key: 'name', + render:(val, item)=>{ + return {val}; + } + },{ + title: '健康状态', + dataIndex: 'id', + key: 'health_status', + render: (val)=>{ + const {clusterStatus} = this.props; + if(!clusterStatus || !clusterStatus[val]){ + return + } + const isAvailable = clusterStatus[val].available; + if(!isAvailable){ + return + } + const status = clusterStatus[val].health?.status; + return + + } + },{ + title: '所属业务', + dataIndex: 'business', + key: 'business', + render: ()=>{ + return 'eu-de-1' + } + }, + { + title: '所属部门', + dataIndex: 'business_department', + key: 'business_department', + render: ()=>{ + return '部门X' + } + }, { + title: '部署环境', + dataIndex: 'deploy_env', + key: 'deploy_env', + render: ()=>{ + return 'PROD' + } + },{ + title: '程序版本', + dataIndex: 'version', + key: 'elasticsearch_version', + // render: (data)=>{ + // return + // } + },{ + title: '节点数', + dataIndex: 'id', + key: 'number_of_nodes', + render: (val)=>{ + const {clusterStatus} = this.props; + if(!clusterStatus || !clusterStatus[val]){ + return + } + return clusterStatus[val].health?.number_of_nodes; + } + },{ + title: '集群地址', + dataIndex: 'host', + key: 'host', + }, + { + title: '监控启用状态', + dataIndex: 'monitored', + key: 'monitored', + render: (val) => { + return val? '启用': '关闭'; + } + }] onOperationTabChange = key => { this.setState({ tabkey: key }); }; + getClusterList = (params)=>{ + const {dispatch} = this.props; + dispatch({ + type: 'clusterOverview/fetchClusterList', + payload: params, + }) + } + getOverviewData = (params)=>{ + const {dispatch} = this.props; + dispatch({ + type: 'clusterOverview/fetchOverview', + }) + } + componentDidMount() { + this.getClusterList({size:20}) + this.getOverviewData(); + } + render() { const { tabkey } = this.state; + const {clusterList, overview} = this.props; const contentList = { tabCluster: ( - -
    + + {/*
    暂无数据 -
    +
    */} + { + this.getClusterList({ + size: pageSize, + from: (page - 1)*pageSize, + }) + } + }} + /> ), tabHost: ( @@ -65,6 +182,7 @@ class Overview extends React.Component { ), }; + const totalStoreSize = formatter.bytes(overview?.total_store_size_in_bytes || 0); return (
    @@ -76,7 +194,7 @@ class Overview extends React.Component { >
    - 1 + {clusterList?.total?.value}
    @@ -87,7 +205,7 @@ class Overview extends React.Component { >
    - 1 + {overview?.total_host}
    @@ -98,7 +216,7 @@ class Overview extends React.Component { >
    - 1 + {overview?.total_node}
    @@ -109,7 +227,7 @@ class Overview extends React.Component { >
    - 100GB + {totalStoreSize.size}{totalStoreSize.unit}
    diff --git a/web/src/pages/Cluster/models/overview.js b/web/src/pages/Cluster/models/overview.js new file mode 100644 index 00000000..fc89791a --- /dev/null +++ b/web/src/pages/Cluster/models/overview.js @@ -0,0 +1,48 @@ +import {searchClusterConfig} from "@/services/cluster"; +import {getOverview} from "@/services/overview"; +import {message} from "antd"; +import {formatESSearchResult} from '@/lib/elasticsearch/util'; + +export default { + namespace: 'clusterOverview', + state: { + + }, + effects:{ + *fetchClusterList({payload}, {call, put, select}){ + let res = yield call(searchClusterConfig, payload); + if(res.error){ + message.error(res.error) + return false; + } + res = formatESSearchResult(res); + yield put({ + type: 'saveData', + payload: { + clusterList: res, + } + }) + }, + *fetchOverview({}, {call, put}){ + let res = yield call(getOverview); + if(res.error){ + message.error(res.error) + return false; + } + yield put({ + type: 'saveData', + payload: { + overview: res, + } + }) + } + }, + reducers:{ + saveData(state, {payload}){ + return { + ...state, + ...payload + }; + }, + } +}; diff --git a/web/src/services/overview.js b/web/src/services/overview.js new file mode 100644 index 00000000..f83536dd --- /dev/null +++ b/web/src/services/overview.js @@ -0,0 +1,8 @@ +import request from '@/utils/request'; +import {pathPrefix} from './common'; + +export async function getOverview(params) { + return request(`${pathPrefix}/elasticsearch/overview`, { + method: 'GET' + }); +}