Skip to content

Commit 413388a

Browse files
committed
feat: track and react to realtime changes of config.yaml and rclone.conf
1 parent 74065bc commit 413388a

File tree

14 files changed

+559
-143
lines changed

14 files changed

+559
-143
lines changed

src/cmd/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ func main() {
1515
sigs := make(chan os.Signal, 1)
1616
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
1717

18-
conf := rclone_manager.InitializeRCD(logger)
18+
rclone_manager.InitializeRCD(logger)
1919

2020
for {
2121
select {
2222
case sig := <-sigs:
2323
logger.Warn().Msgf("Received signal %v, shutting down...", sig)
24-
rclone_manager.StopRcloneRemoteDaemon(conf, logger)
24+
rclone_manager.StopRcloneRemoteDaemon(logger)
2525
os.Exit(0)
2626
default:
2727
time.Sleep(1 * time.Second)

src/go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ module rclone-manager
33
go 1.23
44

55
require (
6+
github.com/fsnotify/fsnotify v1.8.0
67
github.com/rs/zerolog v1.33.0
78
gopkg.in/yaml.v3 v3.0.1
89
)
910

1011
require (
1112
github.com/mattn/go-colorable v0.1.13 // indirect
1213
github.com/mattn/go-isatty v0.0.19 // indirect
13-
golang.org/x/sys v0.12.0 // indirect
14+
golang.org/x/sys v0.13.0 // indirect
1415
)

src/go.sum

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
2+
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
3+
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
24
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
35
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
46
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
@@ -11,8 +13,9 @@ github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
1113
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
1214
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1315
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
14-
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
1516
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
17+
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
18+
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1619
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
1720
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1821
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

src/internal/config/config.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ package config
33
import (
44
"gopkg.in/yaml.v3"
55
"os"
6+
"rclone-manager/internal/constants"
67
)
78

8-
const YAMLPath = "/data/config.yaml"
9-
109
type Config struct {
1110
Serves []struct {
1211
BackendName string `yaml:"backendName"`
@@ -21,7 +20,7 @@ type Config struct {
2120
}
2221

2322
func LoadConfig() (*Config, error) {
24-
data, err := os.ReadFile(YAMLPath)
23+
data, err := os.ReadFile(constants.YAMLPath)
2524
if err != nil {
2625
return nil, err
2726
}
@@ -33,3 +32,21 @@ func LoadConfig() (*Config, error) {
3332
}
3433
return &config, nil
3534
}
35+
36+
func IsMountInConfig(mountPoint string, conf *Config) bool {
37+
for _, mount := range conf.Mounts {
38+
if mount.MountPoint == mountPoint {
39+
return true
40+
}
41+
}
42+
return false
43+
}
44+
45+
func IsServeInConfig(backend string, conf *Config) bool {
46+
for _, mount := range conf.Serves {
47+
if mount.BackendName == backend {
48+
return true
49+
}
50+
}
51+
return false
52+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package constants
2+
3+
// Constants for rclone
4+
const (
5+
Rclone = "rclone"
6+
Serve = "serve"
7+
Rcd = "rcd"
8+
Rc = "rc"
9+
Mount = "mount/mount"
10+
UnmountAll = "mount/unmountall"
11+
Unmount = "mount/unmount"
12+
MountPoint = "mountPoint="
13+
Fs = "fs="
14+
Addr = "--addr"
15+
)
16+
17+
// Constants for fusermount
18+
const (
19+
Fusermount = "fusermount"
20+
FuseUnmount = "-u"
21+
)
22+
23+
// Log constants
24+
const (
25+
LogBackend = "backend"
26+
LogMountPoint = "mountPoint"
27+
LogAddr = "addr"
28+
LogProtocol = "protocol"
29+
LogError = "error"
30+
LogPid = "pid"
31+
LogFile = "file"
32+
)
33+
34+
// Constants data files
35+
const (
36+
YAMLPath = "/data/config.yaml"
37+
RcloneConf = "/data/rclone.conf"
38+
)
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package mount_manager
2+
3+
import (
4+
"fmt"
5+
"github.com/rs/zerolog"
6+
"os"
7+
"os/exec"
8+
"rclone-manager/internal/config"
9+
"rclone-manager/internal/constants"
10+
"syscall"
11+
)
12+
13+
func trackEndpoint(instance *MountedEndpoint) {
14+
instanceMap.Store(instance.BackendName, instance)
15+
}
16+
17+
func untrackEndpoint(instance *MountedEndpoint) {
18+
instanceMap.Delete(instance.BackendName)
19+
}
20+
21+
func getMountedEndpoint(key interface{}) (*MountedEndpoint, bool) {
22+
if val, ok := instanceMap.Load(key); ok {
23+
instance, valid := val.(*MountedEndpoint)
24+
return instance, valid
25+
}
26+
return nil, false
27+
}
28+
29+
func createMountCommand(instance *MountedEndpoint) *exec.Cmd {
30+
fsArg := fmt.Sprintf("%s%s:", constants.Fs, instance.BackendName)
31+
mountPointArg := fmt.Sprintf("%s%s", constants.MountPoint, instance.MountPoint)
32+
33+
cmd := exec.Command(constants.Rclone, constants.Rc, constants.Mount, fsArg, mountPointArg)
34+
cmd.Stdout = os.Stdout
35+
cmd.Stderr = os.Stderr
36+
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
37+
return cmd
38+
}
39+
40+
func createUnmountCommand(instance *MountedEndpoint) *exec.Cmd {
41+
mountPointArg := fmt.Sprintf("%s%s", constants.MountPoint, instance.MountPoint)
42+
43+
cmd := exec.Command(constants.Rclone, constants.Rc, constants.Unmount, mountPointArg)
44+
cmd.Stdout = os.Stdout
45+
cmd.Stderr = os.Stderr
46+
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
47+
return cmd
48+
}
49+
50+
func createUnmountAllCommand() *exec.Cmd {
51+
cmd := exec.Command(constants.Rclone, constants.Rc, constants.UnmountAll)
52+
cmd.Stdout = os.Stdout
53+
cmd.Stderr = os.Stderr
54+
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
55+
return cmd
56+
}
57+
58+
func createFuseUnmountCommand(instance *MountedEndpoint) *exec.Cmd {
59+
cmd := exec.Command(constants.Fusermount, constants.FuseUnmount, instance.MountPoint)
60+
cmd.Stdout = os.Stdout
61+
cmd.Stderr = os.Stderr
62+
return cmd
63+
}
64+
65+
func ensureMountPointExists(mountPoint string, logger zerolog.Logger) {
66+
if _, err := os.Stat(mountPoint); os.IsNotExist(err) {
67+
logger.Info().Str(constants.LogMountPoint, mountPoint).Msg("Creating mount point...")
68+
err := os.MkdirAll(mountPoint, 0777)
69+
if err != nil {
70+
logger.Error().Err(err).Str(constants.LogMountPoint, mountPoint).
71+
Msg("Failed to create mount point")
72+
} else {
73+
logger.Info().Str(constants.LogMountPoint, mountPoint).
74+
Msg("Mount point created successfully.")
75+
}
76+
}
77+
}
78+
79+
func setupMountsFromConfig(conf *config.Config, logger zerolog.Logger) {
80+
for _, mount := range conf.Mounts {
81+
instance := &MountedEndpoint{
82+
BackendName: mount.BackendName,
83+
MountPoint: mount.MountPoint,
84+
}
85+
if existing, ok := getMountedEndpoint(mount.BackendName); ok {
86+
if existing.MountPoint != instance.MountPoint {
87+
logger.Warn().
88+
Str(constants.LogMountPoint, mount.MountPoint).
89+
Msg("Mount config changed, remounting...")
90+
91+
if UnmountInstanceViaRcdWithFuseFallback(existing, logger) {
92+
untrackEndpoint(existing)
93+
StartMountWithRetries(instance, logger)
94+
}
95+
}
96+
} else {
97+
logger.Info().
98+
Str(constants.LogMountPoint, mount.MountPoint).
99+
Msg("New mount detected, mounting...")
100+
StartMountWithRetries(instance, logger)
101+
}
102+
}
103+
}
104+
105+
func removeStaleMounts(conf *config.Config, logger zerolog.Logger) {
106+
instanceMap.Range(func(key, value interface{}) bool {
107+
instance := value.(*MountedEndpoint)
108+
if !config.IsMountInConfig(instance.MountPoint, conf) {
109+
logger.Warn().
110+
Str(constants.LogBackend, instance.BackendName).
111+
Msg("Mount removed from config, unmounting...")
112+
if UnmountInstanceViaRcdWithFuseFallback(instance, logger) {
113+
untrackEndpoint(instance)
114+
}
115+
}
116+
return true
117+
})
118+
}

0 commit comments

Comments
 (0)