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:
1 parent
c7b61968bc
commit
8240a88a84
33 files changed
+2029
-71
No files matched your search
@@ -1,5 +1,5 @@
|
||||
// Package collector — 磁盘 IO 指标采集器
|
||||
// 通过读取 /proc/diskstats 获取磁盘读写 BPS 和 IOPS。
|
||||
// 通过读取 /proc/diskstats 获取磁盘读写 BPS、IOPS 和 util(磁盘繁忙程度)。
|
||||
//
|
||||
// 署名 Hermes
|
||||
package collector
|
||||
@@ -23,6 +23,7 @@ type diskIOSample struct {
|
||||
writeSects uint64
|
||||
readOps uint64
|
||||
writeOps uint64
|
||||
ioTicks uint64 // io_ticks (field 12) — 磁盘忙碌的毫秒累计
|
||||
}
|
||||
|
||||
// DiskIOCollector 磁盘 IO 采集器
|
||||
@@ -40,7 +41,7 @@ func NewDiskIOCollector() *DiskIOCollector {
|
||||
func (c *DiskIOCollector) Collect() (model.DiskIOStat, error) {
|
||||
stat := model.DiskIOStat{}
|
||||
|
||||
rSects, wSects, rOps, wOps, err := readDiskStats()
|
||||
rSects, wSects, rOps, wOps, ioTicks, err := readDiskStats()
|
||||
if err != nil {
|
||||
return stat, fmt.Errorf("读取磁盘 IO 失败: %w", err)
|
||||
}
|
||||
@@ -55,6 +56,7 @@ func (c *DiskIOCollector) Collect() (model.DiskIOStat, error) {
|
||||
writeSects: wSects,
|
||||
readOps: rOps,
|
||||
writeOps: wOps,
|
||||
ioTicks: ioTicks,
|
||||
}
|
||||
|
||||
if c.prev != nil && now.After(c.prev.time) {
|
||||
@@ -65,6 +67,15 @@ func (c *DiskIOCollector) Collect() (model.DiskIOStat, error) {
|
||||
stat.WriteBPS = float64((cur.writeSects-c.prev.writeSects)*sectorSize) / elapsed
|
||||
stat.ReadIOPS = float64(cur.readOps-c.prev.readOps) / elapsed
|
||||
stat.WriteIOPS = float64(cur.writeOps-c.prev.writeOps) / elapsed
|
||||
// util% = io_ticks_delta_ms / (elapsed_ms) * 100
|
||||
ioDelta := cur.ioTicks - c.prev.ioTicks
|
||||
stat.Util = float64(ioDelta) / (elapsed * 1000.0) * 100.0
|
||||
if stat.Util > 100 {
|
||||
stat.Util = 100
|
||||
}
|
||||
if stat.Util < 0 {
|
||||
stat.Util = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
c.prev = cur
|
||||
@@ -73,11 +84,11 @@ func (c *DiskIOCollector) Collect() (model.DiskIOStat, error) {
|
||||
}
|
||||
|
||||
// readDiskStats 读取 /proc/diskstats,汇总所有物理磁盘的读写数据
|
||||
// fields[2]=设备名, fields[3]=读完成次数, fields[5]=读扇区数, fields[7]=写完成次数, fields[9]=写扇区数
|
||||
func readDiskStats() (rSects, wSects, rOps, wOps uint64, err error) {
|
||||
// fields[2]=设备名, fields[3]=读完成次数, fields[5]=读扇区数, fields[7]=写完成次数, fields[9]=写扇区数, fields[12]=io_ticks
|
||||
func readDiskStats() (rSects, wSects, rOps, wOps, ioTicks uint64, err error) {
|
||||
f, err := os.Open("/proc/diskstats")
|
||||
if err != nil {
|
||||
return 0, 0, 0, 0, err
|
||||
return 0, 0, 0, 0, 0, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
@@ -103,6 +114,7 @@ func readDiskStats() (rSects, wSects, rOps, wOps uint64, err error) {
|
||||
// field 5 = 读扇区数 (rd_sectors)
|
||||
// field 7 = 写完成次数 (wr_ios)
|
||||
// field 9 = 写扇区数 (wr_sectors)
|
||||
// field 12 = io_ticks (milliseconds spent doing I/O)
|
||||
if v, e := strconv.ParseUint(fields[3], 10, 64); e == nil {
|
||||
rOps += v
|
||||
}
|
||||
@@ -115,7 +127,10 @@ func readDiskStats() (rSects, wSects, rOps, wOps uint64, err error) {
|
||||
if v, e := strconv.ParseUint(fields[9], 10, 64); e == nil {
|
||||
wSects += v
|
||||
}
|
||||
if v, e := strconv.ParseUint(fields[12], 10, 64); e == nil {
|
||||
ioTicks += v
|
||||
}
|
||||
}
|
||||
|
||||
return rSects, wSects, rOps, wOps, scanner.Err()
|
||||
return rSects, wSects, rOps, wOps, ioTicks, scanner.Err()
|
||||
}
|
||||
Reference in new issue
Block a user