| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 |
- // agent-mounter:资料库挂载服务(docs/design/21-knowledge-sources.md §4)。
- // 以部署用户运行,把本机目录(以后还有远程存储)只读挂到 knowledge/mnt/<id>,隐藏以 . 开头的文件。
- package main
- import (
- "flag"
- "log"
- "net"
- "os"
- "os/signal"
- "path/filepath"
- "syscall"
- "golang.org/x/sys/unix"
- )
- const version = "1.1.0"
- func main() {
- dir := flag.String("dir", "/srv/agent-server/mounter", "挂载服务目录(socket、密钥、state.json)")
- mnt := flag.String("mnt", "/srv/agent-server/knowledge/mnt", "挂载点所在目录")
- rclone := flag.String("rclone", "/srv/agent-server/app/mounter/rclone", "rclone 程序(远程存储)")
- showVersion := flag.Bool("version", false, "显示版本")
- flag.Parse()
- if *showVersion {
- println(version)
- return
- }
- log.SetFlags(0)
- log.SetOutput(os.Stderr)
- var st unix.Stat_t
- if err := unix.Stat(*dir, &st); err != nil {
- log.Fatalf("挂载服务目录不存在:%s(先执行 deploy/deploy.sh)", *dir)
- }
- gid := int(st.Gid)
- if err := unix.Stat(*mnt, &st); err != nil {
- log.Fatalf("挂载点目录不存在:%s", *mnt)
- }
- unix.Umask(0o027)
- mgr := newManager(realSystem{}, allowedRoots, filepath.Clean(*mnt), filepath.Join(*dir, "state.json"))
- if _, err := os.Stat(*rclone); err == nil {
- remoteDir, cacheDir := filepath.Join(*dir, "remote"), filepath.Join(*dir, "cache")
- for _, d := range []string{remoteDir, cacheDir} {
- if err := os.MkdirAll(d, 0o700); err != nil {
- log.Fatalf("创建 %s 失败:%v", d, err)
- }
- }
- // 空的配置文件:不读取部署用户自己的 rclone.conf,连接参数全部来自环境变量
- conf := filepath.Join(*dir, "rclone.conf")
- if err := os.WriteFile(conf, nil, 0o600); err != nil {
- log.Fatalf("创建 %s 失败:%v", conf, err)
- }
- mgr.withRemote(&rcloneRunner{bin: *rclone, config: conf, home: *dir}, remoteDir, cacheDir)
- } else {
- log.Printf("没有找到 rclone(%s),远程存储不可用", *rclone)
- }
- mgr.cleanupStale()
- if specs := mgr.loadState(); len(specs) > 0 {
- if _, err := mgr.sync(specs, false); err != nil {
- log.Printf("按 state.json 恢复挂载失败:%v", err)
- } else {
- log.Printf("已按 state.json 恢复 %d 个挂载", len(specs))
- }
- }
- stop := make(chan struct{})
- go mgr.watchMountinfo(stop)
- srv := &server{token: newToken(), mgr: mgr, version: version}
- sock := filepath.Join(*dir, "mounter.sock")
- _ = os.Remove(sock)
- l, err := net.Listen("unix", sock)
- if err != nil {
- log.Fatalf("监听 %s 失败:%v", sock, err)
- }
- if err := os.Chown(sock, -1, gid); err != nil {
- log.Fatalf("设置 socket 的组失败:%v", err)
- }
- if err := os.Chmod(sock, 0o660); err != nil {
- log.Fatalf("设置 socket 权限失败:%v", err)
- }
- if err := writeGroupFile(filepath.Join(*dir, "token"), []byte(srv.token+"\n"), 0o640, gid); err != nil {
- log.Fatalf("写入密钥失败:%v", err)
- }
- go srv.serve(l)
- log.Printf("agent-mounter %s 已启动:%s", version, sock)
- sig := make(chan os.Signal, 1)
- signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT)
- <-sig
- close(stop)
- l.Close()
- mgr.unmountAll()
- log.Printf("已停止")
- }
|