Compare commits

...

4 Commits

Author SHA1 Message Date
Akizon77
b1c863bacd fix: https://github.com/komari-monitor/komari/issues/446 去重同一物理设备的挂载点 2026-03-10 17:56:03 +08:00
Akizon77
bb1e01459b fix: https://github.com/komari-monitor/komari/issues/402 2026-03-10 15:55:04 +08:00
Akizon
c829958d59 Merge pull request #72 from Yuuuuu0/main
feat: 所有出站连接支持 HTTP 代理
2026-02-21 11:21:10 +08:00
Yuuuuu0
3be21757f6 feat: 所有出站连接支持 HTTP 代理
在无法直接访问外网的环境下(如内网服务器需要通过代理访问互联网),
agent 的 websocket 上报、IP 地址获取、autodiscovery 注册等请求
无法走代理导致连接失败。

现在统一添加 http.ProxyFromEnvironment,
配置 http_proxy/https_proxy 环境变量即可生效,未配置时行为不变。

systemd 配置示例:

[Service]
Environment="http_proxy=http://your-proxy-ip:port"
Environment="https_proxy=http://your-proxy-ip:port"
Environment="HTTP_PROXY=http://your-proxy-ip:port"
Environment="HTTPS_PROXY=http://your-proxy-ip:port"
Environment="no_proxy=localhost,127.0.0.1,::1,172.16.0.0/12"
Environment="NO_PROXY=localhost,127.0.0.1,::1,172.16.0.0/12"
2026-02-10 19:59:54 +08:00
4 changed files with 36 additions and 10 deletions

View File

@@ -10,7 +10,9 @@ import (
"net/url" "net/url"
"os" "os"
"path/filepath" "path/filepath"
"time"
"github.com/komari-monitor/komari-agent/dnsresolver"
"github.com/komari-monitor/komari-agent/utils" "github.com/komari-monitor/komari-agent/utils"
) )
@@ -136,7 +138,7 @@ func registerWithAutoDiscovery() error {
} }
// 发送请求 // 发送请求
client := &http.Client{} client := dnsresolver.GetHTTPClient(30 * time.Second)
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
return fmt.Errorf("failed to send register request: %v", err) return fmt.Errorf("failed to send register request: %v", err)

View File

@@ -83,26 +83,21 @@ func isPhysicalDisk(part disk.PartitionStat) bool {
} }
mountpoint := strings.ToLower(part.Mountpoint) mountpoint := strings.ToLower(part.Mountpoint)
// 排除挂载点 // 排除挂载点
var mountpointsToExclude = []string{ var mountpointsToExcludePerfix = []string{
"/tmp", "/tmp",
"/var/tmp", "/var/tmp",
"/dev/shm", "/dev",
"/run", "/run",
"/run/lock",
"/run/user",
"/var/lib/containers", "/var/lib/containers",
"/var/lib/docker", "/var/lib/docker",
"/proc", "/proc",
"/dev/pts",
"/sys", "/sys",
"/sys/fs/cgroup", "/sys/fs/cgroup",
"/dev/mqueue",
"/etc/resolv.conf", "/etc/resolv.conf",
"/etc/host", // /etc/hosts,/etc/hostname "/etc/host", // /etc/hosts,/etc/hostname
"/dev/hugepages",
"/nix/store", "/nix/store",
} }
for _, mp := range mountpointsToExclude { for _, mp := range mountpointsToExcludePerfix {
if mountpoint == mp || strings.HasPrefix(mountpoint, mp) { if mountpoint == mp || strings.HasPrefix(mountpoint, mp) {
return false return false
} }
@@ -123,6 +118,7 @@ func isPhysicalDisk(part disk.PartitionStat) bool {
var fstypeToExclude = []string{ var fstypeToExclude = []string{
"tmpfs", "tmpfs",
"devtmpfs", "devtmpfs",
"udev",
"nfs", "nfs",
"cifs", "cifs",
"smb", "smb",
@@ -136,6 +132,9 @@ func isPhysicalDisk(part disk.PartitionStat) bool {
"cgroup", "cgroup",
"mqueue", "mqueue",
"hugetlbfs", "hugetlbfs",
"debugfs",
"binfmt_misc",
"securityfs",
} }
for _, fs := range fstypeToExclude { for _, fs := range fstypeToExclude {
if fstype == fs || strings.HasPrefix(fstype, fs) { if fstype == fs || strings.HasPrefix(fstype, fs) {
@@ -172,11 +171,33 @@ func DiskList() ([]string, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
// 同一物理设备只保留路径最短的根挂载点
deviceMap := make(map[string]disk.PartitionStat)
for _, part := range usage { for _, part := range usage {
if isPhysicalDisk(part) { if isPhysicalDisk(part) {
diskList = append(diskList, fmt.Sprintf("%s (%s)", part.Mountpoint, part.Fstype)) deviceID := part.Device
// ZFS去重: 基于 pool 名称
if strings.ToLower(part.Fstype) == "zfs" {
if idx := strings.Index(deviceID, "/"); idx != -1 {
deviceID = deviceID[:idx]
}
}
if existing, ok := deviceMap[deviceID]; ok {
// 优先保留路径更短的挂载点 (e.g., /volume1 优于 /volume1/@appdata/...)
if len(part.Mountpoint) < len(existing.Mountpoint) {
deviceMap[deviceID] = part
}
} else {
deviceMap[deviceID] = part
}
} }
} }
for _, part := range deviceMap {
diskList = append(diskList, fmt.Sprintf("%s (%s)", part.Mountpoint, part.Fstype))
}
} }
return diskList, nil return diskList, nil
} }

View File

@@ -16,6 +16,7 @@ var (
// 创建适用于IPv4和IPv6的HTTP客户端 // 创建适用于IPv4和IPv6的HTTP客户端
ipv4HTTPClient = &http.Client{ ipv4HTTPClient = &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
dialer := dnsresolver.GetNetDialer(15 * time.Second) dialer := dnsresolver.GetNetDialer(15 * time.Second)
return dialer.DialContext(ctx, "tcp4", addr) // 锁v4防止出现问题 return dialer.DialContext(ctx, "tcp4", addr) // 锁v4防止出现问题
@@ -29,6 +30,7 @@ var (
} }
ipv6HTTPClient = &http.Client{ ipv6HTTPClient = &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
dialer := dnsresolver.GetNetDialer(15 * time.Second) dialer := dnsresolver.GetNetDialer(15 * time.Second)
return dialer.DialContext(ctx, "tcp6", addr) // 锁v6防止出现问题 return dialer.DialContext(ctx, "tcp6", addr) // 锁v6防止出现问题

View File

@@ -192,6 +192,7 @@ func newWSDialer() *websocket.Dialer {
d := &websocket.Dialer{ d := &websocket.Dialer{
HandshakeTimeout: 15 * time.Second, HandshakeTimeout: 15 * time.Second,
NetDialContext: dnsresolver.GetDialContext(15 * time.Second), NetDialContext: dnsresolver.GetDialContext(15 * time.Second),
Proxy: http.ProxyFromEnvironment,
} }
if flags.IgnoreUnsafeCert { if flags.IgnoreUnsafeCert {
d.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} d.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}