main.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // agent-mounter:资料库挂载服务(docs/design/21-knowledge-sources.md §4)。
  2. // 以部署用户运行,把本机目录(以后还有远程存储)只读挂到 knowledge/mnt/<id>,隐藏以 . 开头的文件。
  3. package main
  4. import (
  5. "flag"
  6. "log"
  7. "net"
  8. "os"
  9. "os/signal"
  10. "path/filepath"
  11. "syscall"
  12. "golang.org/x/sys/unix"
  13. )
  14. const version = "1.1.0"
  15. func main() {
  16. dir := flag.String("dir", "/srv/agent-server/mounter", "挂载服务目录(socket、密钥、state.json)")
  17. mnt := flag.String("mnt", "/srv/agent-server/knowledge/mnt", "挂载点所在目录")
  18. rclone := flag.String("rclone", "/srv/agent-server/app/mounter/rclone", "rclone 程序(远程存储)")
  19. showVersion := flag.Bool("version", false, "显示版本")
  20. flag.Parse()
  21. if *showVersion {
  22. println(version)
  23. return
  24. }
  25. log.SetFlags(0)
  26. log.SetOutput(os.Stderr)
  27. var st unix.Stat_t
  28. if err := unix.Stat(*dir, &st); err != nil {
  29. log.Fatalf("挂载服务目录不存在:%s(先执行 deploy/deploy.sh)", *dir)
  30. }
  31. gid := int(st.Gid)
  32. if err := unix.Stat(*mnt, &st); err != nil {
  33. log.Fatalf("挂载点目录不存在:%s", *mnt)
  34. }
  35. unix.Umask(0o027)
  36. mgr := newManager(realSystem{}, allowedRoots, filepath.Clean(*mnt), filepath.Join(*dir, "state.json"))
  37. if _, err := os.Stat(*rclone); err == nil {
  38. remoteDir, cacheDir := filepath.Join(*dir, "remote"), filepath.Join(*dir, "cache")
  39. for _, d := range []string{remoteDir, cacheDir} {
  40. if err := os.MkdirAll(d, 0o700); err != nil {
  41. log.Fatalf("创建 %s 失败:%v", d, err)
  42. }
  43. }
  44. // 空的配置文件:不读取部署用户自己的 rclone.conf,连接参数全部来自环境变量
  45. conf := filepath.Join(*dir, "rclone.conf")
  46. if err := os.WriteFile(conf, nil, 0o600); err != nil {
  47. log.Fatalf("创建 %s 失败:%v", conf, err)
  48. }
  49. mgr.withRemote(&rcloneRunner{bin: *rclone, config: conf, home: *dir}, remoteDir, cacheDir)
  50. } else {
  51. log.Printf("没有找到 rclone(%s),远程存储不可用", *rclone)
  52. }
  53. mgr.cleanupStale()
  54. if specs := mgr.loadState(); len(specs) > 0 {
  55. if _, err := mgr.sync(specs, false); err != nil {
  56. log.Printf("按 state.json 恢复挂载失败:%v", err)
  57. } else {
  58. log.Printf("已按 state.json 恢复 %d 个挂载", len(specs))
  59. }
  60. }
  61. stop := make(chan struct{})
  62. go mgr.watchMountinfo(stop)
  63. srv := &server{token: newToken(), mgr: mgr, version: version}
  64. sock := filepath.Join(*dir, "mounter.sock")
  65. _ = os.Remove(sock)
  66. l, err := net.Listen("unix", sock)
  67. if err != nil {
  68. log.Fatalf("监听 %s 失败:%v", sock, err)
  69. }
  70. if err := os.Chown(sock, -1, gid); err != nil {
  71. log.Fatalf("设置 socket 的组失败:%v", err)
  72. }
  73. if err := os.Chmod(sock, 0o660); err != nil {
  74. log.Fatalf("设置 socket 权限失败:%v", err)
  75. }
  76. if err := writeGroupFile(filepath.Join(*dir, "token"), []byte(srv.token+"\n"), 0o640, gid); err != nil {
  77. log.Fatalf("写入密钥失败:%v", err)
  78. }
  79. go srv.serve(l)
  80. log.Printf("agent-mounter %s 已启动:%s", version, sock)
  81. sig := make(chan os.Signal, 1)
  82. signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT)
  83. <-sig
  84. close(stop)
  85. l.Close()
  86. mgr.unmountAll()
  87. log.Printf("已停止")
  88. }