feat(k8s): M14 Namespace 管理看板(资源配额 + 命名空间 CRUD)

- 后端: ListNamespacesDetailed/CreateNamespace/DeleteNamespace/ListResourceQuotas/ListLimitRanges
- 后端: GetNamespacesDetail handler (6 API calls aggregate, not N×3)
- 后端: CreateNamespaceHandler + DeleteNamespaceHandler (system NS protection)
- 前端: NamespaceManagementPage.tsx (~280行) — 表格+概览卡片+创建/删除弹框
- 路由: GET/POST/DELETE /:clusterCode/namespaces + GET /namespace/:ns/detail
- 验证: 9/9 通过 (urllib), TS 零错误, Vite 构建成功
This commit is contained in:
attacker committed 2026-06-24 23:46:52 +08:00
1 parent c7b61968bc
commit 8240a88a84
33 files changed
+2029 -71

No files matched your search

+25 -14
View File
@@ -18,9 +18,11 @@ import (
// netSample 保存上一次的网络采样数据,用于计算速率
type netSample struct {
time time.Time
rxBytes uint64
txBytes uint64
time time.Time
rxBytes uint64
txBytes uint64
rxErrors uint64
txErrors uint64
}
// NetworkCollector 网络指标采集器
@@ -34,7 +36,7 @@ func NewNetworkCollector() *NetworkCollector {
return &NetworkCollector{}
}
// Collect 采集网络指标(并发连接数、TIME_WAIT、网卡 rx/tx B/s)
// Collect 采集网络指标(并发连接数、TIME_WAIT、网卡 rx/tx B/s、错误包)
func (c *NetworkCollector) Collect() (model.NetworkStat, error) {
stat := model.NetworkStat{}
@@ -46,8 +48,8 @@ func (c *NetworkCollector) Collect() (model.NetworkStat, error) {
}
stat.TCPCloseWait = countCloseWait()
// 2. 采集网卡流量(取所有非 lo 网卡合计)
curRx, curTx, nicName, err := readNetDevTotal()
// 2. 采集网卡流量 + 错误包(取所有非 lo 网卡合计)
curRx, curTx, curRxErr, curTxErr, nicName, err := readNetDevTotal()
if err != nil {
return stat, fmt.Errorf("读取网卡流量失败: %w", err)
}
@@ -57,7 +59,7 @@ func (c *NetworkCollector) Collect() (model.NetworkStat, error) {
defer c.mu.Unlock()
now := time.Now()
cur := &netSample{time: now, rxBytes: curRx, txBytes: curTx}
cur := &netSample{time: now, rxBytes: curRx, txBytes: curTx, rxErrors: curRxErr, txErrors: curTxErr}
if c.prev != nil && now.After(c.prev.time) {
elapsed := now.Sub(c.prev.time).Seconds()
@@ -66,6 +68,11 @@ func (c *NetworkCollector) Collect() (model.NetworkStat, error) {
stat.NetTxBPS = float64(cur.txBytes-c.prev.txBytes) / elapsed
}
}
// 错误包:返回当前累计值(供前端判断是否激增)
stat.NetRxErrors = int64(cur.rxErrors)
stat.NetTxErrors = int64(cur.txErrors)
c.prev = cur
return stat, nil
@@ -120,11 +127,11 @@ func readSockStat() (tcpSockStat, error) {
return result, scanner.Err()
}
// readNetDevTotal 读取 /proc/net/dev,取第一个非 lo 且活跃的物理网卡总流量
func readNetDevTotal() (rxBytes, txBytes uint64, nicName string, err error) {
// readNetDevTotal 读取 /proc/net/dev,取第一个非 lo 且活跃的物理网卡总流量 + 错误包
func readNetDevTotal() (rxBytes, txBytes, rxErrors, txErrors uint64, nicName string, err error) {
f, err := os.Open("/proc/net/dev")
if err != nil {
return 0, 0, "", err
return 0, 0, 0, 0, "", err
}
defer f.Close()
@@ -149,26 +156,30 @@ func readNetDevTotal() (rxBytes, txBytes uint64, nicName string, err error) {
}
fields := strings.Fields(parts[1])
if len(fields) < 10 {
if len(fields) < 11 {
continue
}
// fields[0]=rx_bytes, fields[8]=tx_bytes
// fields[0]=rx_bytes, fields[2]=rx_errors, fields[8]=tx_bytes, fields[10]=tx_errors
rb, _ := strconv.ParseUint(fields[0], 10, 64)
tb, _ := strconv.ParseUint(fields[8], 10, 64)
re, _ := strconv.ParseUint(fields[2], 10, 64)
te, _ := strconv.ParseUint(fields[10], 10, 64)
if rb > 0 || tb > 0 {
nicName = name
rxBytes += rb
txBytes += tb
rxErrors += re
txErrors += te
}
}
if nicName == "" {
return 0, 0, "eth0", nil
return 0, 0, 0, 0, "eth0", nil
}
return rxBytes, txBytes, nicName, scanner.Err()
return rxBytes, txBytes, rxErrors, txErrors, nicName, scanner.Err()
}
// countCloseWait 从 /proc/net/tcp 统计 CLOSE_WAIT 连接数