From d2a3ec0e7aef9c67726395e66357b89bb9a340da Mon Sep 17 00:00:00 2001 From: yaojp123 <15989103230@163.com> Date: Tue, 11 Feb 2025 22:44:06 +0800 Subject: [PATCH] chore: add credential settings for agent in enrolling agent (#116) * chore: add collection mode to cluster editing * chore: add credential settings for agent when enroll agent * chore: update release notes --------- Co-authored-by: yaojiping --- docs/content.en/docs/release-notes/_index.md | 3 + docs/content.zh/docs/release-notes/_index.md | 3 + web/src/components/Overview/Monitor/index.jsx | 7 +- web/src/locales/en-US/agent.js | 8 + web/src/locales/en-US/alert.js | 2 + web/src/locales/en-US/cluster.js | 1 + web/src/locales/zh-CN/agent.js | 7 + web/src/locales/zh-CN/alert.js | 2 + web/src/locales/zh-CN/cluster.js | 1 + .../Instance/components/AgentCredential.jsx | 117 ++++++++++++ .../components/AgentCredentialForm.jsx | 143 ++++++++++++++ .../Agent/Instance/components/AutoEnroll.jsx | 41 ++++- .../Agent/Instance/components/RowDetail.jsx | 2 +- .../components/SetAgentCredential.jsx | 174 ++++++++++++++++++ .../components/SetAgentCredential.less | 7 + .../Instance/components/UnknownAssociate.jsx | 42 ++++- .../Instance/components/UnknownAssociate.less | 7 + web/src/pages/System/Cluster/CollectMode.jsx | 48 +++++ web/src/pages/System/Cluster/CollectMode.less | 8 + web/src/pages/System/Cluster/Form.js | 82 ++++++--- .../System/Cluster/MonitorConfigsForm.jsx | 5 +- 21 files changed, 669 insertions(+), 41 deletions(-) create mode 100644 web/src/pages/Agent/Instance/components/AgentCredential.jsx create mode 100644 web/src/pages/Agent/Instance/components/AgentCredentialForm.jsx create mode 100644 web/src/pages/Agent/Instance/components/SetAgentCredential.jsx create mode 100644 web/src/pages/Agent/Instance/components/SetAgentCredential.less create mode 100644 web/src/pages/Agent/Instance/components/UnknownAssociate.less create mode 100644 web/src/pages/System/Cluster/CollectMode.jsx create mode 100644 web/src/pages/System/Cluster/CollectMode.less diff --git a/docs/content.en/docs/release-notes/_index.md b/docs/content.en/docs/release-notes/_index.md index d5564ca5..537ceabe 100644 --- a/docs/content.en/docs/release-notes/_index.md +++ b/docs/content.en/docs/release-notes/_index.md @@ -19,6 +19,9 @@ Information about release notes of INFINI Console is provided here. ## 1.28.1 (2025-01-24) +- add credential settings for agent in enrolling agent +- add collection mode to cluster editing + ### Features - Support function-format parameters in Insight Data API diff --git a/docs/content.zh/docs/release-notes/_index.md b/docs/content.zh/docs/release-notes/_index.md index 001b43f5..8cf2b781 100644 --- a/docs/content.zh/docs/release-notes/_index.md +++ b/docs/content.zh/docs/release-notes/_index.md @@ -17,6 +17,9 @@ title: "版本历史" ### Improvements +- 在注册 Agent 中新增 Agent 凭据设置 +- 在集群编辑中新增采集模式 + ## 1.28.1 (2025-01-24) ### Features diff --git a/web/src/components/Overview/Monitor/index.jsx b/web/src/components/Overview/Monitor/index.jsx index 6aa58222..c34b6af5 100644 --- a/web/src/components/Overview/Monitor/index.jsx +++ b/web/src/components/Overview/Monitor/index.jsx @@ -151,8 +151,11 @@ const Monitor = (props) => { const breadcrumbList = getBreadcrumbList(state); const isAgent = useMemo(() => { - const { monitor_configs = {} } = selectedCluster || {} - return monitor_configs?.node_stats?.enabled === false && monitor_configs?.index_stats?.enabled === false + const { metric_collection_mode, monitor_configs = {} } = selectedCluster || {} + if (typeof metric_collection_mode === 'undefined') { + return monitor_configs?.node_stats?.enabled === false && monitor_configs?.index_stats?.enabled === false + } + return metric_collection_mode === 'agent' }, [JSON.stringify(selectedCluster?.monitor_configs)]) return ( diff --git a/web/src/locales/en-US/agent.js b/web/src/locales/en-US/agent.js index a5d7da42..3f1f9472 100644 --- a/web/src/locales/en-US/agent.js +++ b/web/src/locales/en-US/agent.js @@ -6,7 +6,12 @@ export default { "agent.instance.associate.labels.select_cluster": "Select Cluster", "agent.instance.associate.tips.associate": "Please select cluster(s) to enroll !", + "agent.instance.associate.set_credential": "Set credential for agent", + "agent.instance.associate.set_credential.tips": + "This permission will be used for metrics and log collection. It is recommended to use a user with a reasonable permission range.", "agent.instance.associate.tips.connected": "Connection succeeded!", + "agent.instance.associate.tips.connected.check": "please set a credential for agent", + "agent.instance.associate.auth.error": "The following clusters need to set credentials for the agent:", "agent.instance.associate.tips.metric": "After enroll, the agent will collect metrics for the enrolled cluster", "agent.instance.associate.tips.unregister": @@ -35,4 +40,7 @@ export default { "agent.install.setup.copy.success": "Copied to clipboard successfully!", "agent.instance.auto_associate.title": "Auto Enroll", "agent.instance.install.title": "Install Agent", + + "agent.label.agent_credential": "Agent Credential", + "agent.credential.tip": "No credential required", }; diff --git a/web/src/locales/en-US/alert.js b/web/src/locales/en-US/alert.js index a5fba7c4..95d2e0cf 100644 --- a/web/src/locales/en-US/alert.js +++ b/web/src/locales/en-US/alert.js @@ -207,6 +207,8 @@ export default { "alert.rule.table.columnns.schedule": "Schedule", "alert.rule.table.columnns.expression": "Expression", "alert.rule.table.columnns.status": "Status", + "alert.rule.table.columnns.status.failed": "Connect failed", + "alert.rule.table.columnns.status.succeeded": "Connect succeeded", "alert.rule.table.columnns.enabled": "Enabled", "alert.rule.table.columnns.updated": "Updated time", "alert.rule.table.columnns.category": "Category", diff --git a/web/src/locales/en-US/cluster.js b/web/src/locales/en-US/cluster.js index 41173891..a115bb6e 100644 --- a/web/src/locales/en-US/cluster.js +++ b/web/src/locales/en-US/cluster.js @@ -35,6 +35,7 @@ export default { "cluster.manage.table.column.location": "Location", "cluster.manage.monitored.on": "ON", "cluster.manage.monitored.off": "OFF", + "cluster.manage.metric_collection_mode": "Collect Mode", "cluster.manage.monitor_configs.cluster_health": "Cluster health", "cluster.manage.monitor_configs.cluster_stats": "Cluster stats", "cluster.manage.monitor_configs.node_stats": "Node stats", diff --git a/web/src/locales/zh-CN/agent.js b/web/src/locales/zh-CN/agent.js index 7b66f5d4..a3693b5e 100644 --- a/web/src/locales/zh-CN/agent.js +++ b/web/src/locales/zh-CN/agent.js @@ -5,7 +5,11 @@ export default { "agent.instance.associate.labels.cluster_version": "版本", "agent.instance.associate.labels.select_cluster": "关联到集群", "agent.instance.associate.tips.associate": "请选择要关联的集群!", + "agent.instance.associate.set_credential": "为代理设置凭据", + "agent.instance.associate.set_credential.tips": "此权限将用于度量和日志收集。建议使用具有合理权限范围的用户。", "agent.instance.associate.tips.connected": "连接成功!", + "agent.instance.associate.tips.connected.check": "请设置凭据", + "agent.instance.associate.auth.error": "以下集群需要为 Agent 设置凭据:", "agent.instance.associate.tips.metric": "关联后 Agent 会对关联的集群进行指标采集操作", "agent.instance.associate.tips.unregister": @@ -33,4 +37,7 @@ export default { "agent.install.setup.copy.success": "已成功复制到剪贴板!", "agent.instance.auto_associate.title": "自动关联集群", "agent.instance.install.title": "安装 Agent", + + "agent.label.agent_credential": "代理凭据", + "agent.credential.tip": "不需要凭据", }; diff --git a/web/src/locales/zh-CN/alert.js b/web/src/locales/zh-CN/alert.js index 027c5a7d..dcffd4d5 100644 --- a/web/src/locales/zh-CN/alert.js +++ b/web/src/locales/zh-CN/alert.js @@ -195,6 +195,8 @@ export default { "alert.rule.table.columnns.schedule": "计划周期", "alert.rule.table.columnns.expression": "告警规则", "alert.rule.table.columnns.status": "运行状态", + "alert.rule.table.columnns.status.failed": "连接失败", + "alert.rule.table.columnns.status.succeeded": "连接成功", "alert.rule.table.columnns.enabled": "告警启停", "alert.rule.table.columnns.updated": "更新时间", "alert.rule.table.columnns.category": "分类", diff --git a/web/src/locales/zh-CN/cluster.js b/web/src/locales/zh-CN/cluster.js index 63865abb..a4f4b249 100644 --- a/web/src/locales/zh-CN/cluster.js +++ b/web/src/locales/zh-CN/cluster.js @@ -35,6 +35,7 @@ export default { "cluster.manage.table.column.location": "位置", "cluster.manage.monitored.on": "启用", "cluster.manage.monitored.off": "关闭", + "cluster.manage.metric_collection_mode": "采集模式", "cluster.manage.monitor_configs.cluster_health": "集群健康状态指标", "cluster.manage.monitor_configs.cluster_stats": "集群指标", "cluster.manage.monitor_configs.node_stats": "节点指标", diff --git a/web/src/pages/Agent/Instance/components/AgentCredential.jsx b/web/src/pages/Agent/Instance/components/AgentCredential.jsx new file mode 100644 index 00000000..71ab3b1a --- /dev/null +++ b/web/src/pages/Agent/Instance/components/AgentCredential.jsx @@ -0,0 +1,117 @@ +import { Alert, Button, Form, message } from "antd"; +import { useState } from "react"; +import { formatMessage } from "umi/locale"; + +import request from "@/utils/request"; +import AgentCredentialForm, { MANUAL_VALUE } from "./AgentCredentialForm"; +import { ESPrefix } from "@/services/common"; + +const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 5 }, + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 18 }, + }, +}; + +export default Form.create()((props) => { + const { form, record, loading, tryConnect, onAgentCredentialSave } = props; + + const [isManual, setIsManual] = useState(false); + const [saveLoading, setSaveLoading] = useState(false); + + const needAuth = !!(record.credential_id || record.basic_auth?.username); + + const onConfirm = async () => { + form.validateFields(async (errors, values) => { + if (errors) return; + setSaveLoading(true); + const { credential_id, basic_auth, metric_collection_mode } = record; + const res = await request(`${ESPrefix}/${record.id}`, { + method: "PUT", + body: { + credential_id, + basic_auth, + metric_collection_mode, + agent_credential_id: + values.agent_credential_id !== MANUAL_VALUE + ? values.agent_credential_id + : undefined, + agent_basic_auth: { + username: values.agent_username, + password: values.agent_password, + }, + }, + }); + if (res?.result === "updated") { + message.success( + formatMessage({ + id: "app.message.update.success", + }) + ); + const res = await request(`/elasticsearch/${record.id}`); + if (res?.found) { + onAgentCredentialSave(res._source); + if (res._source?.agent_credential_id) { + setIsManual(false); + } + form.setFieldsValue({ + agent_credential_id: res._source?.agent_credential_id + ? res._source?.agent_credential_id + : res._source?.agent_basic_auth?.username + ? MANUAL_VALUE + : undefined, + agent_username: res._source.agent_basic_auth?.username, + agent_password: res._source.agent_basic_auth?.password, + }); + } + } else { + message.error( + formatMessage({ + id: "app.message.update.failed", + }) + ); + } + setSaveLoading(false); + }); + }; + + if (!needAuth) { + return ( + + ); + } + + return ( +
+ + +
+ +
+
+ + ); +}); diff --git a/web/src/pages/Agent/Instance/components/AgentCredentialForm.jsx b/web/src/pages/Agent/Instance/components/AgentCredentialForm.jsx new file mode 100644 index 00000000..5d5041b1 --- /dev/null +++ b/web/src/pages/Agent/Instance/components/AgentCredentialForm.jsx @@ -0,0 +1,143 @@ +import React, { useEffect, useMemo, useState } from "react"; +import { Button, Divider, Form, Input, Select, Row, Col } from "antd"; +import { formatMessage } from "umi/locale"; + +import useFetch from "@/lib/hooks/use_fetch"; +import { formatESSearchResult } from "@/lib/elasticsearch/util"; + +export const MANUAL_VALUE = "manual"; + +export default (props) => { + const { + btnLoading = false, + needAuth, + form: { getFieldDecorator }, + initialValue, + isEdit, + tryConnect, + credentialRequired = false, + isManual, + setIsManual, + } = props; + + const { loading, error, value, run } = useFetch( + "/credential/_search", + { + queryParams: { + from: 0, + size: 1000, + }, + }, + [] + ); + + const onCredentialChange = (value) => { + if (value === "manual") { + setIsManual(true); + } else { + setIsManual(false); + } + }; + + const { data, total } = useMemo(() => { + return formatESSearchResult(value); + }, [value]); + + if (!needAuth) { + return null; + } + + return ( + <> + + {getFieldDecorator("agent_credential_id", { + initialValue: initialValue?.agent_credential_id + ? initialValue?.agent_credential_id + : initialValue?.username + ? MANUAL_VALUE + : undefined, + rules: [ + { + required: credentialRequired, + message: formatMessage({ + id: "cluster.regist.form.verify.required.agent_credential", + }), + }, + ], + })( + + )} + + {isManual && ( + <> + + {getFieldDecorator("agent_username", { + initialValue: initialValue?.username || "", + rules: [ + { + required: credentialRequired, + message: formatMessage({ + id: "cluster.regist.form.verify.required.auth_username", + }), + }, + ], + })()} + + + {getFieldDecorator("agent_password", { + initialValue: initialValue?.password || "", + rules: [ + { + required: credentialRequired, + message: formatMessage({ + id: "cluster.regist.form.verify.required.auth_password", + }), + }, + ], + })( + + )} + + {isEdit && ( + <> + +
+ {formatMessage({ + id: "cluster.regist.form.credential.manual.desc", + })} +
+
+ + )} + + )} + + ); +}; diff --git a/web/src/pages/Agent/Instance/components/AutoEnroll.jsx b/web/src/pages/Agent/Instance/components/AutoEnroll.jsx index 448a8703..9ffcdf8c 100644 --- a/web/src/pages/Agent/Instance/components/AutoEnroll.jsx +++ b/web/src/pages/Agent/Instance/components/AutoEnroll.jsx @@ -1,22 +1,36 @@ import { useGlobal } from "@/layouts/GlobalContext"; import request from "@/utils/request"; -import { Form, Input, Switch, Icon, Button, Select } from "antd"; -import { useMemo, useRef, useState } from "react"; +import { Form, Input, Switch, Icon, Button, Select, Alert } from "antd"; +import { useEffect, useMemo, useRef, useState } from "react"; import { Link, router } from "umi"; import { formatMessage } from "umi/locale"; import ClusterSelect from "@/components/ClusterSelect"; +import SetAgentCredential from "./SetAgentCredential"; export default ({ onEnroll, loading }) => { const { clusterList = [], clusterStatus } = useGlobal(); const [selectedCluster, setSelectedCluster] = useState([]); + const [auths, setAuths] = useState([]); const onEnrollClick = () => { - if (typeof onEnroll === "function") { + if (selectedCluster.length === 0) return; + const newAuths = [...auths] + selectedCluster.forEach((item) => { + if (item.credential_id && !item.agent_credential_id) { + newAuths.push(item) + } + }) + setAuths(newAuths) + if (newAuths.length === 0 && typeof onEnroll === "function") { onEnroll(selectedCluster.map((item) => item.id)); } }; + useEffect(() => { + setAuths([]) + }, [JSON.stringify(selectedCluster)]) + return (
{ }} />
+ + { + auths.length > 0 && ( + +
+ {formatMessage({ + id: "agent.instance.associate.auth.error", + })} +
+
+ { auths.map((item) => ( +
+ - {item.name} +
+ )) } +
+
+ )}/> + ) + }
diff --git a/web/src/pages/Agent/Instance/components/RowDetail.jsx b/web/src/pages/Agent/Instance/components/RowDetail.jsx index 4da977e7..1ea8347e 100644 --- a/web/src/pages/Agent/Instance/components/RowDetail.jsx +++ b/web/src/pages/Agent/Instance/components/RowDetail.jsx @@ -228,7 +228,7 @@ export const AgentRowDetail = ({ agentID, t }) => { }) } > - diff --git a/web/src/pages/Agent/Instance/components/SetAgentCredential.jsx b/web/src/pages/Agent/Instance/components/SetAgentCredential.jsx new file mode 100644 index 00000000..fa896851 --- /dev/null +++ b/web/src/pages/Agent/Instance/components/SetAgentCredential.jsx @@ -0,0 +1,174 @@ +import request from "@/utils/request"; +import { message, Table, Tooltip, Spin } from "antd"; +import { useState } from "react"; +import { formatMessage } from "umi/locale"; + +import { MANUAL_VALUE } from "./AgentCredentialForm"; +import styles from "./SetAgentCredential.less"; +import AgentCredential from "./AgentCredential"; +import { ESPrefix } from "@/services/common"; +import { cloneDeep } from "lodash"; +import { connect } from "dva"; + +export default connect()((props) => { + const { selectedCluster, setSelectedCluster, dispatch } = props + + const [status, setStatus] = useState({}); + const [testLoading, setTestLoading] = useState(false); + + const onAgentCredentialSave = async (values) => { + const newSelectedCluster = cloneDeep(selectedCluster); + const index = newSelectedCluster.findIndex((item) => item.id === values.id); + if (index !== -1) { + newSelectedCluster[index] = values; + setSelectedCluster(newSelectedCluster); + } + dispatch({ + type: "global/fetchClusterList", + payload: { + size: 200, + name: "", + }, + }); + dispatch({ + type: "global/fetchClusterStatus", + }) + }; + + const expandedRowRender = (record) => { + return ( + onAgentCredentialSave(values)} + /> + ); + }; + + const tryConnect = async (values) => { + setTestLoading(true); + const body = { + basic_auth: { + username: values.agent_basic_auth?.username, + password: values.agent_basic_auth?.password, + }, + host: values.host, + credential_id: + values.agent_credential_id !== MANUAL_VALUE + ? values.agent_credential_id + : undefined, + schema: values.schema || "http", + }; + if ( + values.credential_id && + !body.credential_id && + (!body.basic_auth.username || !body.basic_auth.password) + ) { + message.warning(formatMessage({ id: "agent.instance.associate.tips.connected.check" })); + setTestLoading(false); + return; + } + const res = await request(`${ESPrefix}/try_connect`, { + method: "POST", + body, + showErrorInner: true, + }, false, false); + setStatus({ + ...status, + [values.id]: { + status: res?.status, + error: res?.error, + }, + }); + setTestLoading(false); + }; + + return ( + <> +
+
+ {formatMessage({ id: "agent.instance.associate.set_credential" })} +
+
{formatMessage({ id: "agent.instance.associate.set_credential.tips" })}
+
+ +
+ { + return record.credential_id || record.basic_auth?.username + ? formatMessage({ + id: "cluster.regist.step.complete.tls.yes", + }) + : formatMessage({ + id: "cluster.regist.step.complete.tls.no", + }); + }, + }, + { + title: formatMessage({ id: "agent.label.agent_credential" }), + dataIndex: "agent_credential_id", + key: "agent_credential_id", + render: (text, record) => { + return record.agent_credential_id ? "Set" : "No set"; + }, + }, + { + title: formatMessage({ id: "alert.rule.table.columnns.status" }), + dataIndex: "status", + key: "Status", + render: (text, record) => { + if (!status[record.id]) return "-"; + if (status[record.id].error) { + return ( + + {formatMessage({ id: "alert.rule.table.columnns.status.failed"})} + + ); + } + return ( + {formatMessage({ id: "alert.rule.table.columnns.status.succeeded"})} + ); + }, + }, + { + title: formatMessage({ id: "table.field.actions" }), + dataIndex: "", + key: "", + render: (record) => + testLoading ? ( + + ) : ( + tryConnect(record)}> + {formatMessage({ id: "guide.cluster.test.connection" })} + + ), + }, + ]} + expandedRowRender={expandedRowRender} + /> + + + ); +}); diff --git a/web/src/pages/Agent/Instance/components/SetAgentCredential.less b/web/src/pages/Agent/Instance/components/SetAgentCredential.less new file mode 100644 index 00000000..62b5a937 --- /dev/null +++ b/web/src/pages/Agent/Instance/components/SetAgentCredential.less @@ -0,0 +1,7 @@ +.table { + :global { + tr.ant-table-expanded-row, tr.ant-table-expanded-row:hover { + background: #fff; + } + } +} \ No newline at end of file diff --git a/web/src/pages/Agent/Instance/components/UnknownAssociate.jsx b/web/src/pages/Agent/Instance/components/UnknownAssociate.jsx index 5cad6525..cf512a85 100644 --- a/web/src/pages/Agent/Instance/components/UnknownAssociate.jsx +++ b/web/src/pages/Agent/Instance/components/UnknownAssociate.jsx @@ -1,22 +1,35 @@ import { useGlobal } from "@/layouts/GlobalContext"; import request from "@/utils/request"; -import { Form, Input, Switch, Icon, Button, Select } from "antd"; -import { useMemo, useRef, useState } from "react"; +import { Form, Input, Switch, Icon, Button, Alert } from "antd"; +import { useEffect, useMemo, useRef, useState } from "react"; import { Link, router } from "umi"; import { formatMessage } from "umi/locale"; import ClusterSelect from "@/components/ClusterSelect"; +import SetAgentCredential from "./SetAgentCredential"; export default ({ onBatchEnroll, loading }) => { const { clusterList = [], clusterStatus } = useGlobal(); - const [selectedCluster, setSelectedCluster] = useState([]); + const [auths, setAuths] = useState([]); const onBatchEnrollClick = () => { - if (typeof onBatchEnroll === "function") { + if (selectedCluster.length === 0) return; + const newAuths = [...auths] + selectedCluster.forEach((item) => { + if (item.credential_id && !item.agent_credential_id) { + newAuths.push(item) + } + }) + setAuths(newAuths) + if (newAuths.length === 0 && typeof onBatchEnroll === "function") { onBatchEnroll(selectedCluster.map((item) => item.id)); } }; + useEffect(() => { + setAuths([]) + }, [JSON.stringify(selectedCluster)]) + return (
{ }} />
+ + { + auths.length > 0 && ( + +
+ {formatMessage({ + id: "agent.instance.associate.auth.error", + })} +
+
+ { auths.map((item) => ( +
+ - {item.name} +
+ )) } +
+
+ )}/> + ) + }
diff --git a/web/src/pages/Agent/Instance/components/UnknownAssociate.less b/web/src/pages/Agent/Instance/components/UnknownAssociate.less new file mode 100644 index 00000000..62b5a937 --- /dev/null +++ b/web/src/pages/Agent/Instance/components/UnknownAssociate.less @@ -0,0 +1,7 @@ +.table { + :global { + tr.ant-table-expanded-row, tr.ant-table-expanded-row:hover { + background: #fff; + } + } +} \ No newline at end of file diff --git a/web/src/pages/System/Cluster/CollectMode.jsx b/web/src/pages/System/Cluster/CollectMode.jsx new file mode 100644 index 00000000..54c1d8d5 --- /dev/null +++ b/web/src/pages/System/Cluster/CollectMode.jsx @@ -0,0 +1,48 @@ +import { Form, Radio } from "antd"; +import { useEffect, useState } from "react"; +import { formatMessage } from "umi/locale"; +import styles from "./CollectMode.less"; + +export default (props) => { + const { editValue, form, onChange } = props; + const { getFieldDecorator } = form; + + const [mode, setMode] = useState( + editValue?.metric_collection_mode || "agentless" + ); + + useEffect(() => { + const monitor_configs = form.getFieldValue("monitor_configs"); + if (mode === "agent") { + monitor_configs["node_stats"] = { enabled: false }; + monitor_configs["index_stats"] = { enabled: false }; + } else { + monitor_configs["node_stats"] = { enabled: true }; + monitor_configs["index_stats"] = { enabled: true }; + } + form.setFieldsValue({ monitor_configs }); + }, [mode]); + + return ( + <> + + {getFieldDecorator(`metric_collection_mode`, { + initialValue: mode, + })( + { + setMode(e.target.value) + onChange(e.target.value) + }} + > + Agentless + Agent + + )} + + + ); +}; \ No newline at end of file diff --git a/web/src/pages/System/Cluster/CollectMode.less b/web/src/pages/System/Cluster/CollectMode.less new file mode 100644 index 00000000..65b33169 --- /dev/null +++ b/web/src/pages/System/Cluster/CollectMode.less @@ -0,0 +1,8 @@ +.mode { + :global { + .ant-radio-button-wrapper { + margin-right: 12px; + border-radius: 4px; + } + } +} \ No newline at end of file diff --git a/web/src/pages/System/Cluster/Form.js b/web/src/pages/System/Cluster/Form.js index d735b3ec..dfca1ded 100644 --- a/web/src/pages/System/Cluster/Form.js +++ b/web/src/pages/System/Cluster/Form.js @@ -27,6 +27,7 @@ import { MANUAL_VALUE } from "./steps"; import SearchEngines from "./components/SearchEngines"; import Providers from "./components/Providers"; import TrimSpaceInput from "@/components/TrimSpaceInput"; +import CollectMode from "./CollectMode"; const InputGroup = Input.Group; @Form.create() @@ -51,7 +52,7 @@ class ClusterForm extends React.Component { validateFieldNames = [ "name", - "host", + "hosts", "isTLS", "credential_id", "username", @@ -59,7 +60,7 @@ class ClusterForm extends React.Component { ]; agentValidateFieldNames = [ "name", - "host", + "hosts", "isTLS", "agent_credential_id", "agent_username", @@ -70,6 +71,7 @@ class ClusterForm extends React.Component { //console.log(this.props.clusterConfig.editMode) const { match, dispatch, clusterConfig } = this.props; if (clusterConfig?.editValue) { + this.setState({ monitored: clusterConfig?.editValue.hasOwnProperty("monitored") ? clusterConfig?.editValue?.monitored @@ -98,9 +100,14 @@ class ClusterForm extends React.Component { isManual = true; } } + let collectMode = editValue?.metric_collection_mode || 'agentless' + if (typeof editValue?.metric_collection_mode === 'undefined' && editValue?.monitor_configs?.node_stats?.enabled === false && editValue?.monitor_configs?.index_stats?.enabled === false) { + collectMode = 'agent' + } this.setState({ needAuth, isManual, + collectMode }); } }); @@ -154,6 +161,7 @@ class ClusterForm extends React.Component { } const monitor_configs_new = formatConfigsValues(values.monitor_configs); const metadata_configs_new = formatConfigsValues(values.metadata_configs); + const isAgentMode = values.metric_collection_mode === "agent"; let newVals = { name: values.name, @@ -169,13 +177,14 @@ class ClusterForm extends React.Component { }, agent_credential_id: - values.agent_credential_id !== MANUAL_VALUE + values.agent_credential_id !== MANUAL_VALUE && isAgentMode ? values.agent_credential_id - : undefined, - agent_basic_auth: { + : agent_credential_id, + agent_basic_auth: isAgentMode ? { username: values.agent_username, password: values.agent_password, - }, + } : agent_basic_auth, + metric_collection_mode: values.metric_collection_mode || 'agentless', description: values.description, enabled: values.enabled, @@ -267,9 +276,10 @@ class ClusterForm extends React.Component { if (!values) { return; } + debugger let newVals = { name: values.name, - host: values.host, + hosts: values.hosts, schema: values.isTLS === true ? "https" : "http", }; @@ -417,6 +427,15 @@ class ClusterForm extends React.Component { ], })()} + + {getFieldDecorator("description", { + initialValue: editValue.description, + })()} + - {/* {getFieldDecorator('order', { initialValue: editValue.order || 0, })()} */} - - {getFieldDecorator("description", { - initialValue: editValue.description, - })()} - {/* {getFieldDecorator('enabled', { valuePropName: 'checked', @@ -581,10 +577,36 @@ class ClusterForm extends React.Component { /> )} + { + this.setState({ collectMode: mode }) + }} + /> + { + this.state.collectMode === 'agent' && ( + + ) + } { display: props.visible ? "block" : "none", }} > - {configs.map((item) => { + {configs.filter((item) => { + if (props.collectMode !== "agent") return true; + return !["node_stats", "index_stats"].includes(item.key); + }).map((item) => { return (