Skip to content

Commit

Permalink
chore: add credential settings for agent in enrolling agent (#116)
Browse files Browse the repository at this point in the history
* chore: add collection mode to cluster editing

* chore: add credential settings for agent when enroll agent

* chore: update release notes

---------

Co-authored-by: yaojiping <[email protected]>
  • Loading branch information
yaojp123 and yaojiping authored Feb 11, 2025
1 parent 8762255 commit d2a3ec0
Show file tree
Hide file tree
Showing 21 changed files with 669 additions and 41 deletions.
3 changes: 3 additions & 0 deletions docs/content.en/docs/release-notes/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions docs/content.zh/docs/release-notes/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ title: "版本历史"

### Improvements

- 在注册 Agent 中新增 Agent 凭据设置
- 在集群编辑中新增采集模式

## 1.28.1 (2025-01-24)

### Features
Expand Down
7 changes: 5 additions & 2 deletions web/src/components/Overview/Monitor/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
8 changes: 8 additions & 0 deletions web/src/locales/en-US/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -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":
Expand Down Expand Up @@ -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",
};
2 changes: 2 additions & 0 deletions web/src/locales/en-US/alert.js
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions web/src/locales/en-US/cluster.js
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
7 changes: 7 additions & 0 deletions web/src/locales/zh-CN/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -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":
Expand Down Expand Up @@ -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": "不需要凭据",
};
2 changes: 2 additions & 0 deletions web/src/locales/zh-CN/alert.js
Original file line number Diff line number Diff line change
Expand Up @@ -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": "分类",
Expand Down
1 change: 1 addition & 0 deletions web/src/locales/zh-CN/cluster.js
Original file line number Diff line number Diff line change
Expand Up @@ -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": "节点指标",
Expand Down
117 changes: 117 additions & 0 deletions web/src/pages/Agent/Instance/components/AgentCredential.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<Alert
message={formatMessage({ id: "agent.credential.tip" })}
type="success"
/>
);
}

return (
<Form {...formItemLayout} colon={false}>
<AgentCredentialForm
btnLoading={loading}
needAuth={needAuth}
form={form}
initialValue={{
...record,
username: record.agent_basic_auth?.username,
password: record.agent_basic_auth?.password,
}}
isManual={isManual}
setIsManual={setIsManual}
isEdit={true}
tryConnect={tryConnect}
credentialRequired={false}
/>
<Form.Item label=" " colon={false}>
<div style={{ textAlign: "right" }}>
<Button loading={loading} type="primary" onClick={() => onConfirm()}>
{formatMessage({ id: "cluster.regist.step.confirm.title" })}
</Button>
</div>
</Form.Item>
</Form>
);
});
143 changes: 143 additions & 0 deletions web/src/pages/Agent/Instance/components/AgentCredentialForm.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<Form.Item
label={formatMessage({
id: "cluster.regist.step.connect.label.agent_credential",
})}
>
{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",
}),
},
],
})(
<Select loading={loading} onChange={onCredentialChange} allowClear>
<Select.Option value={MANUAL_VALUE}>
{formatMessage({
id: "cluster.regist.step.connect.credential.manual",
})}
</Select.Option>
{data.map((item) => (
<Select.Option value={item.id}>{item.name}</Select.Option>
))}
</Select>
)}
</Form.Item>
{isManual && (
<>
<Form.Item
label={formatMessage({
id: "cluster.regist.step.connect.label.username",
})}
>
{getFieldDecorator("agent_username", {
initialValue: initialValue?.username || "",
rules: [
{
required: credentialRequired,
message: formatMessage({
id: "cluster.regist.form.verify.required.auth_username",
}),
},
],
})(<Input autoComplete="off" placeholder={formatMessage({id: "agent.form.placeholder.auth.username"})} />)}
</Form.Item>
<Form.Item
label={formatMessage({
id: "cluster.regist.step.connect.label.password",
})}
hasFeedback
>
{getFieldDecorator("agent_password", {
initialValue: initialValue?.password || "",
rules: [
{
required: credentialRequired,
message: formatMessage({
id: "cluster.regist.form.verify.required.auth_password",
}),
},
],
})(
<Input.Password
autoComplete="off"
placeholder={formatMessage({
id: "cluster.regist.form.verify.required.auth_password",
})}
/>
)}
</Form.Item>
{isEdit && (
<>
<Form.Item label={" "}>
<div style={{ lineHeight: "20px" }}>
{formatMessage({
id: "cluster.regist.form.credential.manual.desc",
})}
</div>
</Form.Item>
</>
)}
</>
)}
</>
);
};
Loading

0 comments on commit d2a3ec0

Please sign in to comment.