From f31ae6ae8df2b29fef769f116d5a10474173c353 Mon Sep 17 00:00:00 2001 From: yangon <2689991790@qq.com> Date: Tue, 18 Jun 2024 10:35:08 +0800 Subject: [PATCH] Add monitoring to obproxy (#455) --- ui/.prettierrc | 1 + ui/package.json | 2 +- ui/src/components/MonitorDetail/index.tsx | 28 ++++------ ui/src/constants/index.ts | 15 ++++++ ui/src/i18n/strings/en-US.json | 42 +++++++++++++++ ui/src/i18n/strings/zh-CN.json | 8 ++- ui/src/pages/Alert/AlarmFilter/index.tsx | 36 ++++++------- ui/src/pages/Cluster/Detail/Monitor/index.tsx | 7 ++- ui/src/pages/Cluster/Detail/Tenant/index.tsx | 9 +--- ui/src/pages/Cluster/index.tsx | 22 +++----- ui/src/pages/OBProxy/ClusterList.tsx | 19 ++++++- ui/src/pages/OBProxy/Detail/Monitor/index.tsx | 41 +++++++++++++- .../OBProxy/Detail/Overview/BasicInfo.tsx | 13 +++-- .../OBProxy/Detail/Overview/ConfigDrawer.tsx | 53 +++++++++++++++---- .../OBProxy/Detail/Overview/DetailConfig.tsx | 1 + .../pages/OBProxy/Detail/Overview/index.tsx | 30 +++++++++-- ui/src/pages/OBProxy/New/BasicConfig.tsx | 19 +++++-- ui/src/pages/OBProxy/New/index.tsx | 4 +- ui/src/pages/OBProxy/index.tsx | 34 ++++++++++-- ui/src/pages/Tenant/index.tsx | 8 +-- ui/src/services/index.ts | 2 +- ui/src/type/monitor.d.ts | 3 +- ui/src/type/obproxy.d.ts | 4 +- ui/src/type/typings.d.ts | 12 +++-- 24 files changed, 307 insertions(+), 106 deletions(-) diff --git a/ui/.prettierrc b/ui/.prettierrc index 70767cdf7..9e640d4a9 100644 --- a/ui/.prettierrc +++ b/ui/.prettierrc @@ -2,6 +2,7 @@ "printWidth": 80, "singleQuote": true, "trailingComma": "all", + "tabWidth": 2, "proseWrap": "never", "overrides": [{ "files": ".prettierrc", "options": { "parser": "json" } }], "plugins": ["prettier-plugin-organize-imports", "prettier-plugin-packagejson"] diff --git a/ui/package.json b/ui/package.json index fe264d39c..8df4b679d 100644 --- a/ui/package.json +++ b/ui/package.json @@ -9,7 +9,7 @@ "postinstall": "max setup", "lint": "eslint src", "oic:clear": "oic --configPath ./must.cjs --clear", - "oic:extract": "oic --configPath ./must.cjs --extract --translate", + "oic:extract": "oic --configPath ./must.cjs --extract", "prepare": "cd .. && husky ui/.husky", "setup": "max setup", "start": "npm run dev" diff --git a/ui/src/components/MonitorDetail/index.tsx b/ui/src/components/MonitorDetail/index.tsx index ffe5557b3..442b110ad 100644 --- a/ui/src/components/MonitorDetail/index.tsx +++ b/ui/src/components/MonitorDetail/index.tsx @@ -3,17 +3,17 @@ import dayjs from 'dayjs'; import { useEffect, useRef, useState } from 'react'; import MonitorComp from '@/components/MonitorComp'; -import { REFRESH_FREQUENCY } from '@/constants'; +import { DEFAULT_QUERY_RANGE, REFRESH_FREQUENCY } from '@/constants'; import DataFilter from './DataFilter'; interface MonitorDetailProps { filterData: Monitor.FilterDataType; - setFilterData:React.Dispatch>; - basicInfo:JSX.Element | null | undefined; - filterLabel:Monitor.LabelType[]; - setFilterLabel:React.Dispatch>; - groupLabels:API.LableKeys[]; - queryScope:API.EventObjectType; + setFilterData: React.Dispatch>; + basicInfo: JSX.Element | null | undefined; + filterLabel: Monitor.LabelType[]; + setFilterLabel: React.Dispatch>; + groupLabels: API.LableKeys[]; + queryScope: API.EventObjectType; } const getDate = () => { @@ -22,12 +22,6 @@ const getDate = () => { .format('YYYY-MM-DD HH:mm:ss'); }; -const defaultQueryRange = { - step: 20, - endTimestamp: Math.floor(new Date().valueOf() / 1000), - startTimestamp: Math.floor(new Date().valueOf() / 1000) - 60 * 30, -}; - //Query is somewhat similar to sql statement, label is equivalent to filter condition,for example: where label1=xxx and label2 = xxx export default function MonitorDetail({ filterData, @@ -36,14 +30,14 @@ export default function MonitorDetail({ setFilterLabel, basicInfo, groupLabels, - queryScope -}:MonitorDetailProps) { + queryScope, +}: MonitorDetailProps) { const [isRefresh, setIsRefresh] = useState(false); const [realTime, setRealTime] = useState(getDate()); const timerRef = useRef(); const updateTimer = useRef(); const [queryRange, setQueryRange] = - useState(defaultQueryRange); + useState(DEFAULT_QUERY_RANGE); const newQueryRangeRef = useRef(); //Only used to solve the problem of not getting the latest value in interval useUpdateEffect(() => { @@ -84,7 +78,7 @@ export default function MonitorDetail({ return (
- { basicInfo } + {basicInfo} {visibleConfig.objectType && ( - + + {({ getFieldValue }) => { return ( + + + + ({ @@ -19,7 +18,7 @@ export default function Monitor() { const [filterLabel, setFilterLabel] = useState([ { key: 'ob_cluster_name', - value: clusterName, + value: clusterName!, }, ]); const { data: clusterDetail, run: getClusterDetail } = useRequest( @@ -35,7 +34,7 @@ export default function Monitor() { ); useEffect(() => { - getClusterDetail({ ns, name }); + getClusterDetail({ ns: ns!, name: name! }); }, []); return ( diff --git a/ui/src/pages/Cluster/Detail/Tenant/index.tsx b/ui/src/pages/Cluster/Detail/Tenant/index.tsx index e5b567e05..d280ef293 100644 --- a/ui/src/pages/Cluster/Detail/Tenant/index.tsx +++ b/ui/src/pages/Cluster/Detail/Tenant/index.tsx @@ -1,5 +1,6 @@ import EventsTable from '@/components/EventsTable'; import MonitorComp from '@/components/MonitorComp'; +import { DEFAULT_QUERY_RANGE } from '@/constants'; import TenantsList from '@/pages/Tenant/TenantsList'; import { getClusterDetailReq } from '@/services'; import { getAllTenants } from '@/services/tenant'; @@ -9,12 +10,6 @@ import { useRequest } from 'ahooks'; import { Col, Row } from 'antd'; import BasicInfo from '../Overview/BasicInfo'; -const defaultQueryRange = { - step: 20, - endTimestamp: Math.floor(new Date().valueOf() / 1000), - startTimestamp: Math.floor(new Date().valueOf() / 1000) - 60 * 30, -}; - export default function Tenant() { const { ns, name, clusterName } = useParams(); const navigate = useNavigate(); @@ -48,7 +43,7 @@ export default function Tenant() { {tenantsList && ( { const navigate = useNavigate(); @@ -44,15 +39,14 @@ const ClusterPage: React.FC = () => { /> - - + /> ); }; diff --git a/ui/src/pages/OBProxy/ClusterList.tsx b/ui/src/pages/OBProxy/ClusterList.tsx index 5174dda7b..f7cfbf057 100644 --- a/ui/src/pages/OBProxy/ClusterList.tsx +++ b/ui/src/pages/OBProxy/ClusterList.tsx @@ -1,8 +1,10 @@ import type { ObproxyOBProxyOverview } from '@/api/generated'; +import { OBPROXY_COLOR_MAP } from '@/constants'; import { intl } from '@/utils/intl'; import { Link } from '@umijs/max'; -import { Button, Card, Col, Table, Typography } from 'antd'; +import { Button, Card, Col, Table, Tag, Typography } from 'antd'; import type { ColumnsType } from 'antd/es/table'; +import dayjs from 'dayjs'; interface ClusterListProps { handleAddCluster: () => void; @@ -33,6 +35,7 @@ const columns: ColumnsType = [ }), dataIndex: 'proxyClusterName', key: 'proxyClusterName', + render: (value) => {value || '-'}, }, { title: intl.formatMessage({ @@ -41,7 +44,7 @@ const columns: ColumnsType = [ }), dataIndex: 'obCluster', key: 'obCluster', - render: (value) => {value.name}, + render: (value) => {value.name || '-'}, }, { title: intl.formatMessage({ @@ -49,7 +52,11 @@ const columns: ColumnsType = [ defaultMessage: '版本', }), dataIndex: 'image', + width: '20%', key: 'image', + render: (value) => ( + {value || '-'} + ), }, { title: intl.formatMessage({ @@ -58,6 +65,7 @@ const columns: ColumnsType = [ }), dataIndex: 'replicas', key: 'replicas', + render: (value) => {value.name || '-'}, }, { title: intl.formatMessage({ @@ -66,6 +74,7 @@ const columns: ColumnsType = [ }), dataIndex: 'serviceIp', key: 'serviceIp', + render: (value) => {value || '-'}, }, { title: intl.formatMessage({ @@ -73,7 +82,11 @@ const columns: ColumnsType = [ defaultMessage: '创建时间', }), dataIndex: 'creationTime', + width: 178, key: 'creationTime', + render: (value) => ( + {dayjs.unix(value).format('YYYY-MM-DD HH:mm:ss') || '-'} + ), }, { title: intl.formatMessage({ @@ -82,6 +95,7 @@ const columns: ColumnsType = [ }), dataIndex: 'status', key: 'status', + render: (value) => {value}, }, ]; @@ -116,6 +130,7 @@ export default function ClusterList({ dataSource={obproxies} pagination={{ simple: true }} rowKey="name" + scroll={{ x: 1200 }} bordered sticky /> diff --git a/ui/src/pages/OBProxy/Detail/Monitor/index.tsx b/ui/src/pages/OBProxy/Detail/Monitor/index.tsx index 61f4358b4..6cbd305c3 100644 --- a/ui/src/pages/OBProxy/Detail/Monitor/index.tsx +++ b/ui/src/pages/OBProxy/Detail/Monitor/index.tsx @@ -1,3 +1,42 @@ +import { obproxy } from '@/api'; +import MonitorComp from '@/components/MonitorComp'; +import { PageContainer } from '@ant-design/pro-components'; +import { useParams } from '@umijs/max'; +import { useRequest } from 'ahooks'; +import { useEffect } from 'react'; +import BasicInfo from '../Overview/BasicInfo'; +import { DEFAULT_QUERY_RANGE } from '@/constants'; + export default function Monitor() { - return <>; + const { ns, name } = useParams(); + const { data: obproxyDetailRes, run: getOBProxy } = useRequest( + obproxy.getOBProxy, + { + manual: true, + }, + ); + const obproxyDetail = obproxyDetailRes?.data; + + useEffect(() => { + getOBProxy(ns!, name!); + }, []); + return ( + + + + + ); } diff --git a/ui/src/pages/OBProxy/Detail/Overview/BasicInfo.tsx b/ui/src/pages/OBProxy/Detail/Overview/BasicInfo.tsx index e2bcb3f9e..6049417f1 100644 --- a/ui/src/pages/OBProxy/Detail/Overview/BasicInfo.tsx +++ b/ui/src/pages/OBProxy/Detail/Overview/BasicInfo.tsx @@ -1,6 +1,7 @@ import IconTip from '@/components/IconTip'; +import { OBPROXY_COLOR_MAP } from '@/constants'; import { intl } from '@/utils/intl'; -import { Card, Descriptions } from 'antd'; +import { Card, Descriptions, Tag } from 'antd'; interface BasicInfoProps { name?: string; @@ -30,8 +31,8 @@ export default function BasicInfo({ title={

{intl.formatMessage({ - id: 'src.pages.OBProxy.Detail.Overview.6E321376', - defaultMessage: '基本设置', + id: 'src.pages.OBProxy.Detail.Overview.4AB0B6DC', + defaultMessage: '基本信息', })}

} @@ -91,7 +92,11 @@ export default function BasicInfo({ defaultMessage: '状态', })} > - {status || '-'} + {status ? ( + {status} + ) : ( + '-' + )} diff --git a/ui/src/pages/OBProxy/Detail/Overview/ConfigDrawer.tsx b/ui/src/pages/OBProxy/Detail/Overview/ConfigDrawer.tsx index 7af01190b..5beedfa2a 100644 --- a/ui/src/pages/OBProxy/Detail/Overview/ConfigDrawer.tsx +++ b/ui/src/pages/OBProxy/Detail/Overview/ConfigDrawer.tsx @@ -3,6 +3,7 @@ import type { CommonKVPair } from '@/api/generated'; import { ObproxyPatchOBProxyParam } from '@/api/generated'; import AlertDrawer from '@/components/AlertDrawer'; import { CustomFormItem } from '@/components/CustomFormItem'; +import IconTip from '@/components/IconTip'; import { SERVICE_TYPE, SUFFIX_UNIT } from '@/constants'; import { MIRROR_OBPROXY } from '@/constants/doc'; import { OBProxy } from '@/type/obproxy'; @@ -19,12 +20,14 @@ import { Row, Select, Typography, + message, } from 'antd'; import { useEffect, useRef } from 'react'; import { isDifferentParams } from '../../helper'; type ConfigDrawerProps = { onClose: () => void; + submitCallback?: () => void; } & OBProxy.CommonProxyDetail & DrawerProps; @@ -38,14 +41,16 @@ export default function ConfigDrawer({ onClose, name, namespace, + submitCallback, ...props }: ConfigDrawerProps) { const [form] = Form.useForm(); + const preParameters = useRef(); const { data: listParametersRes } = useRequest( obproxy.listOBProxyParameters, { - defaultParams: [namespace, name], + defaultParams: [namespace!, name!], }, ); const listParametersOptions = listParametersRes?.data.map((item) => ({ @@ -54,12 +59,23 @@ export default function ConfigDrawer({ info: item.info, })); - const submit = (values: FormValue) => { + const submit = async (values: FormValue) => { if ( !isDifferentParams(values.parameters || [], preParameters.current || []) ) { delete values.parameters; } + const res = await obproxy.patchOBProxy(namespace!, name!, values); + if (res.successful) { + message.success( + intl.formatMessage({ + id: 'src.pages.OBProxy.Detail.Overview.A9BB34D6', + defaultMessage: '操作成功!', + }), + ); + submitCallback && submitCallback(); + onClose(); + } }; const titleStyle = { fontSize: 14, fontWeight: 600 }; @@ -67,11 +83,14 @@ export default function ConfigDrawer({ const value = listParametersRes?.data?.find( (parameter) => parameter.name === label, )?.value; - value && form.setFieldValue(['parameters', name, 'value'], value); + if (typeof value !== 'undefined') { + form.setFieldValue(['parameters', name, 'value'], value); + } }; useEffect(() => { preParameters.current = props.parameters; }, [props.parameters]); + return ( form.submit()} destroyOnClose={true} - onClose={() => onClose()} + onClose={() => { + form.resetFields(); + onClose(); + }} {...props} >

@@ -186,10 +207,17 @@ export default function ConfigDrawer({ />

- {intl.formatMessage({ - id: 'src.pages.OBProxy.Detail.Overview.D537DD35', - defaultMessage: '参数设置', - })} +

{(fields, { add, remove }) => ( @@ -230,7 +258,12 @@ export default function ConfigDrawer({ - + void; } export default function DetailConfig({ style, ...props }: DetailConfigProps) { diff --git a/ui/src/pages/OBProxy/Detail/Overview/index.tsx b/ui/src/pages/OBProxy/Detail/Overview/index.tsx index b02daef12..fa7f396ed 100644 --- a/ui/src/pages/OBProxy/Detail/Overview/index.tsx +++ b/ui/src/pages/OBProxy/Detail/Overview/index.tsx @@ -1,20 +1,37 @@ import { obproxy } from '@/api'; import EventsTable from '@/components/EventsTable'; +import { REFRESH_OBPROXY_TIME } from '@/constants'; import { intl } from '@/utils/intl'; import { PageContainer } from '@ant-design/pro-components'; import { useParams } from '@umijs/max'; import { useRequest } from 'ahooks'; import { Col, Row } from 'antd'; -import { useEffect } from 'react'; +import { useEffect, useRef } from 'react'; import BasicInfo from './BasicInfo'; import DetailConfig from './DetailConfig'; import NodeInfo from './NodeInfo'; export default function Overview() { const { ns, name } = useParams(); - const { data: obproxyDetailRes, run: getOBProxy } = useRequest( - obproxy.getOBProxy, - ); + const timer = useRef(); + const { + data: obproxyDetailRes, + run: getOBProxy, + refresh, + } = useRequest(obproxy.getOBProxy, { + manual: true, + onSuccess: ({ successful, data }) => { + if (successful) { + if (data.status === 'Pending') { + timer.current = setTimeout(() => { + refresh(); + }, REFRESH_OBPROXY_TIME); + } else { + clearTimeout(timer.current); + } + } + }, + }); const obproxyDetail = obproxyDetailRes?.data; useEffect(() => { getOBProxy(ns!, name!); @@ -47,13 +64,16 @@ export default function Overview() { resource={obproxyDetail?.resource} replicas={obproxyDetail?.replicas} serviceType={obproxyDetail?.service.type} + submitCallback={refresh} /> - + {obproxyDetail?.name && ( + + )} diff --git a/ui/src/pages/OBProxy/New/BasicConfig.tsx b/ui/src/pages/OBProxy/New/BasicConfig.tsx index d1d8f51d5..18e3f44d1 100644 --- a/ui/src/pages/OBProxy/New/BasicConfig.tsx +++ b/ui/src/pages/OBProxy/New/BasicConfig.tsx @@ -23,14 +23,19 @@ export default function BasicConfig({ form }: BasicConfigProps) { useEffect(() => { if (selectCluster && !form.getFieldValue('namespace')) { - form.setFieldValue('namespace', selectCluster.split('+')?.[1]); + try { + form.setFieldValue('namespace', JSON.parse(selectCluster).namespace); + form.validateFields(['namespace']); + } catch (err) { + console.error('err:', err); + } } }, [selectCluster]); return ( @@ -117,7 +122,13 @@ export default function BasicConfig({ form }: BasicConfigProps) { }, ]} > - diff --git a/ui/src/pages/OBProxy/New/index.tsx b/ui/src/pages/OBProxy/New/index.tsx index 7fc1f6c99..5064e95a8 100644 --- a/ui/src/pages/OBProxy/New/index.tsx +++ b/ui/src/pages/OBProxy/New/index.tsx @@ -63,9 +63,9 @@ export default function New() { style={{ paddingBottom: 50 }} > - + - + diff --git a/ui/src/pages/OBProxy/index.tsx b/ui/src/pages/OBProxy/index.tsx index 661d13cf1..bbc78abe6 100644 --- a/ui/src/pages/OBProxy/index.tsx +++ b/ui/src/pages/OBProxy/index.tsx @@ -1,14 +1,35 @@ +import { obproxy } from '@/api'; import EventsTable from '@/components/EventsTable'; +import MonitorComp from '@/components/MonitorComp'; +import { DEFAULT_QUERY_RANGE, REFRESH_OBPROXY_TIME } from '@/constants'; import { PageContainer } from '@ant-design/pro-components'; import { useNavigate } from '@umijs/max'; +import { useRequest } from 'ahooks'; import { Row } from 'antd'; +import { useRef } from 'react'; import ClusterList from './ClusterList'; -import { useRequest } from 'ahooks'; -import { obproxy } from '@/api'; + export default function OBProxy() { const navigate = useNavigate(); const handleAddCluster = () => navigate('new'); - const { data: obproxiesRes, loading} = useRequest(obproxy.listOBProxies); + const timer = useRef(); + const { + data: obproxiesRes, + loading, + refresh, + } = useRequest(obproxy.listOBProxies, { + onSuccess({ data, successful }) { + if (successful) { + if (data.some((obcluster) => obcluster.status === 'Pending')) { + timer.current = setTimeout(() => { + refresh(); + }, REFRESH_OBPROXY_TIME); + } else if (timer.current) { + clearTimeout(timer.current); + } + } + }, + }); const obproxies = obproxiesRes?.data; return ( @@ -20,6 +41,13 @@ export default function OBProxy() { /> + ); } diff --git a/ui/src/pages/Tenant/index.tsx b/ui/src/pages/Tenant/index.tsx index e173497a6..eed4e89b9 100644 --- a/ui/src/pages/Tenant/index.tsx +++ b/ui/src/pages/Tenant/index.tsx @@ -9,12 +9,8 @@ import MonitorComp from '@/components/MonitorComp'; import { REFRESH_TENANT_TIME, RESULT_STATUS } from '@/constants'; import { getAllTenants } from '@/services/tenant'; import TenantsList from './TenantsList'; +import { DEFAULT_QUERY_RANGE } from '@/constants'; -const defaultQueryRange: Monitor.QueryRangeType = { - step: 20, - endTimestamp: Math.floor(new Date().valueOf() / 1000), - startTimestamp: Math.floor(new Date().valueOf() / 1000) - 60 * 30, -}; // tenant overview page export default function TenantPage() { const [filterLabel, setFilterLabel] = useState([]); @@ -72,7 +68,7 @@ export default function TenantPage() { type="OVERVIEW" useFor='tenant' groupLabels={['tenant_name','ob_cluster_name']} - queryRange={defaultQueryRange} + queryRange={DEFAULT_QUERY_RANGE} filterData={tenantsList} /> diff --git a/ui/src/services/index.ts b/ui/src/services/index.ts index 268cd0531..0c93384f8 100644 --- a/ui/src/services/index.ts +++ b/ui/src/services/index.ts @@ -435,7 +435,7 @@ export async function queryMetricsReq({ } else { item.name = metric.metric.labels.find( - (label) => label.key === 'ob_cluster_name', + (label) => label.key === 'ob_cluster_name' || label.key === 'cluster', ).value || ''; } } else { diff --git a/ui/src/type/monitor.d.ts b/ui/src/type/monitor.d.ts index 1fc47a4ae..3878bdd77 100644 --- a/ui/src/type/monitor.d.ts +++ b/ui/src/type/monitor.d.ts @@ -5,7 +5,8 @@ declare namespace Monitor { | 'tenant_name' | 'tenant_id' | 'svr_ip' - | 'obzone'; + | 'obzone' + | 'cluster'; type LabelType = { key: Label; diff --git a/ui/src/type/obproxy.d.ts b/ui/src/type/obproxy.d.ts index ec8355e1c..05a5086f4 100644 --- a/ui/src/type/obproxy.d.ts +++ b/ui/src/type/obproxy.d.ts @@ -1,7 +1,7 @@ declare namespace OBProxy { interface CommonProxyDetail { - name: string; - namespace: string; + name?: string; + namespace?: string; image?: string; parameters?: CommonKVPair[]; resource?: CommonResourceSpec; diff --git a/ui/src/type/typings.d.ts b/ui/src/type/typings.d.ts index 9f39b0d3c..8d6514d15 100644 --- a/ui/src/type/typings.d.ts +++ b/ui/src/type/typings.d.ts @@ -260,7 +260,12 @@ declare namespace API { memoryPercent: number; }; - type MetricScope = 'OBCLUSTER' | 'OBTENANT' | 'OBCLUSTER_OVERVIEW'; + type MetricScope = + | 'OBCLUSTER' + | 'OBTENANT' + | 'OBCLUSTER_OVERVIEW' + | 'OBPROXY_OVERVIEW' + | 'OBPROXY'; type NodeSelector = { key: string; @@ -438,7 +443,9 @@ declare namespace API { | 'tenant_name' | 'tenant_id' | 'svr_ip' - | 'obzone'; + | 'obzone' + | 'cluster'; + type BackupType = 'Full' | 'Incremental'; type ScheduleType = 'Weekly' | 'Monthly'; @@ -849,5 +856,4 @@ declare namespace API { setVisible: (prop: boolean) => void; successCallback?: (val?: any) => void; }; - }