Skip to content

Commit

Permalink
add / update fstab entry with --update-fstab
Browse files Browse the repository at this point in the history
closes #2432
  • Loading branch information
timfeirg committed Aug 10, 2022
1 parent eba3200 commit c573f29
Show file tree
Hide file tree
Showing 12 changed files with 187 additions and 25 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ libjfs.h
.DS_Store
docs/node_modules
cmd/cmd
*.dump
*.out
2 changes: 1 addition & 1 deletion cmd/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
)

func TestBench(t *testing.T) {
mountTemp(t, nil, false)
mountTemp(t, nil, []string{"--trash-days=0"}, nil)
defer umountTemp(t)

os.Setenv("SKIP_DROP_CACHES", "true")
Expand Down
2 changes: 1 addition & 1 deletion cmd/fsck_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
)

func TestFsck(t *testing.T) {
mountTemp(t, nil, true)
mountTemp(t, nil, nil, nil)
defer umountTemp(t)

for i := 0; i < 10; i++ {
Expand Down
2 changes: 1 addition & 1 deletion cmd/gc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func getFileCount(dir string) int {

func TestGc(t *testing.T) {
var bucket string
mountTemp(t, &bucket, false)
mountTemp(t, &bucket, []string{"--trash-days=0"}, nil)
defer umountTemp(t)

if err := writeSmallBlocks(testMountPoint); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cmd/info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func TestInfo(t *testing.T) {
patches := gomonkey.ApplyGlobalVar(os.Stdout, *tmpFile)
defer patches.Reset()

mountTemp(t, nil, true)
mountTemp(t, nil, nil, nil)
defer umountTemp(t)

if err = os.MkdirAll(fmt.Sprintf("%s/dir1", testMountPoint), 0777); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cmd/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func startWebdav(t *testing.T) {
}

func TestIntegration(t *testing.T) {
mountTemp(t, nil, true)
mountTemp(t, nil, nil, nil)
defer umountTemp(t)
startGateway(t)
startWebdav(t)
Expand Down
138 changes: 129 additions & 9 deletions cmd/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package cmd

import (
"bufio"
"fmt"
"net"
"net/http"
Expand All @@ -25,6 +26,7 @@ import (
"os/signal"
"path/filepath"
"runtime"
"sort"
"strings"
"syscall"
"time"
Expand Down Expand Up @@ -212,26 +214,33 @@ func daemonRun(c *cli.Context, addr string, vfsConf *vfs.Config, m meta.Meta) {
}
}
}
_ = expandPathForEmbedded(addr)
// The default log to syslog is only in daemon mode.
utils.InitLoggers(!c.Bool("no-syslog"))
err := makeDaemon(c, vfsConf.Format.Name, vfsConf.Meta.MountPoint, m)
if err != nil {
logger.Fatalf("Failed to make daemon: %s", err)
}
}

func expandPathForEmbedded(addr string) string {
embeddedSchemes := []string{"sqlite3://", "badger://"}
for _, es := range embeddedSchemes {
if strings.HasPrefix(addr, es) {
path := addr[len(es):]
path2, err := filepath.Abs(path)
if err == nil && path2 != path {
absPath, err := filepath.Abs(path)
if err == nil && absPath != path {
for i, a := range os.Args {
if a == addr {
os.Args[i] = es + path2
expanded := es + absPath
os.Args[i] = expanded
return expanded
}
}
}
}
}
// The default log to syslog is only in daemon mode.
utils.InitLoggers(!c.Bool("no-syslog"))
err := makeDaemon(c, vfsConf.Format.Name, vfsConf.Meta.MountPoint, m)
if err != nil {
logger.Fatalf("Failed to make daemon: %s", err)
}
return addr
}

func getVfsConf(c *cli.Context, metaConf *meta.Config, format *meta.Format, chunkConf *chunk.Config) *vfs.Config {
Expand Down Expand Up @@ -392,6 +401,110 @@ func NewReloadableStorage(format *meta.Format, reload func() (*meta.Format, erro
return holder, nil
}

func tellFstabOptions(c *cli.Context) string {
opts := []string{""}
seen := make(map[string]bool)
for _, s := range os.Args[2:] {
s = strings.Split(s, "=")[0]
s = strings.TrimLeft(s, "-")
if !c.IsSet(s) {
continue
}
if seen[s] {
continue
} else {
seen[s] = true
}
if s == "o" {
opts = append(opts, c.String(s))
} else if v := c.Bool(s); v {
opts = append(opts, s)
} else {
v := c.Generic(s)
formatted := fmt.Sprintf("%s", v)
if strings.HasPrefix(formatted, "[") && strings.HasSuffix(formatted, "]") {
trimmed := strings.TrimPrefix(formatted, "[")
trimmed = strings.TrimSuffix(trimmed, "]")
vals := strings.Fields(trimmed)
for _, val := range vals {
opts = append(opts, fmt.Sprintf("%s=%s", s, val))
}
} else {
opts = append(opts, fmt.Sprintf("%s=%s", s, v))
}
}
}
sort.Strings(opts)
return strings.Join(opts, ",")

}

var fstab = "/etc/fstab"

func updateFstab(c *cli.Context) error {
if runtime.GOOS != "linux" {
logger.Infof("--update-fstab is ignored in %s", runtime.GOOS)
return nil
}
if _, err := os.Stat("/.dockerenv"); err == nil {
logger.Infoln("--update-fstab is ignored in container")
return nil
}
addr := expandPathForEmbedded(c.Args().Get(0))
mp := c.Args().Get(1)
f, err := os.Open(fstab)
if err != nil {
return err
}
index, entryIndex := -1, -1
var lines []string
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
lines = append(lines, line)
index += 1
fields := strings.Fields(line)
if len(fields) < 6 {
continue
}
if fields[0] == addr && fields[1] == mp {
entryIndex = index
}
}
if err = scanner.Err(); err != nil {
return err
}
f.Close()
opts := tellFstabOptions(c)
entry := fmt.Sprintf("%s %s juicefs _netdev%s 0 0", addr, mp, opts)
if entryIndex >= 0 {
if entry == lines[entryIndex] {
return nil
}
lines[entryIndex] = entry
} else {
lines = append(lines, entry)
}
tempFstab := fstab + ".tmp"
tmpf, err := os.OpenFile(tempFstab, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
datawriter := bufio.NewWriter(tmpf)
for _, line := range lines {
if _, err := datawriter.WriteString(line + "\n"); err != nil {
return err
}
}
datawriter.Flush()
tmpf.Close()
err = os.Rename(tempFstab, fstab)
if err != nil {
return err
}
return nil
}

func mount(c *cli.Context) error {
setup(c, 2)
addr := c.Args().Get(0)
Expand Down Expand Up @@ -421,6 +534,13 @@ func mount(c *cli.Context) error {
}
logger.Infof("Data use %s", blob)

if c.Bool("update-fstab") {
err = updateFstab(c)
if err != nil {
logger.Fatalf("failed to update fstab: %s", err)
}
}

chunkConf := getChunkConf(c, format)
store := chunk.NewCachedStore(blob, *chunkConf, registerer)
registerMetaMsg(metaCli, store, chunkConf)
Expand Down
52 changes: 44 additions & 8 deletions cmd/mount_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ import (
"context"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"reflect"
"runtime"
"testing"
"time"

Expand Down Expand Up @@ -92,25 +94,29 @@ func resetTestMeta() *redis.Client { // using Redis
return rdb
}

func mountTemp(t *testing.T, bucket *string, trash bool) {
func mountTemp(t *testing.T, bucket *string, extraFormatOpts []string, extraMountOpts []string) {
_ = resetTestMeta()
testDir := t.TempDir()
if bucket != nil {
*bucket = testDir
}
args := []string{"", "format", "--bucket", testDir, testMeta, testVolume}
if !trash {
args = append(args, "--trash-days=0")
formatArgs := []string{"", "format", "--bucket", testDir, testMeta, testVolume}
if extraFormatOpts != nil {
formatArgs = append(formatArgs, extraFormatOpts...)
}
if err := Main(args); err != nil {
if err := Main(formatArgs); err != nil {
t.Fatalf("format failed: %s", err)
}

// must do reset, otherwise will panic
ResetHttp()

mountArgs := []string{"", "mount", "--enable-xattr", testMeta, testMountPoint, "--no-usage-report"}
if extraMountOpts != nil {
mountArgs = append(mountArgs, extraMountOpts...)
}
go func() {
if err := Main([]string{"", "mount", "--enable-xattr", testMeta, testMountPoint, "--no-usage-report"}); err != nil {
if err := Main(mountArgs); err != nil {
t.Errorf("mount failed: %s", err)
}
}()
Expand All @@ -124,16 +130,46 @@ func umountTemp(t *testing.T) {
}

func TestMount(t *testing.T) {
mountTemp(t, nil, true)
mountTemp(t, nil, nil, nil)
defer umountTemp(t)

if err := os.WriteFile(fmt.Sprintf("%s/f1.txt", testMountPoint), []byte("test"), 0644); err != nil {
t.Fatalf("write file failed: %s", err)
}
}

func TestUpdateFstab(t *testing.T) {
if runtime.GOOS != "linux" {
t.SkipNow()
}
mockFstab, err := ioutil.TempFile("/tmp", "fstab")
if err != nil {
t.Fatalf("cannot make temp file: %s", err)
}
defer os.Remove(mockFstab.Name())

patches := gomonkey.ApplyGlobalVar(&fstab, mockFstab.Name())
defer patches.Reset()
mountArgs := []string{"juicefs", "mount", "--enable-xattr", testMeta, testMountPoint, "--no-usage-report"}
mountOpts := []string{"--update-fstab", "--writeback", "--entry-cache=2", "--max-uploads", "3", "-o", "max_read=99"}
patches = gomonkey.ApplyGlobalVar(&os.Args, append(mountArgs, mountOpts...))
defer patches.Reset()
mountTemp(t, nil, nil, mountOpts)
defer umountTemp(t)

content, err := ioutil.ReadFile(mockFstab.Name())
if err != nil {
t.Fatalf("error reading mocked fstab: %s", err)
}
rv := "redis://127.0.0.1:6379/11 /tmp/jfs-unit-test juicefs _netdev,enable-xattr,entry-cache=2,max-uploads=3,max_read=99,no-usage-report,update-fstab,writeback 0 0"
lv := string(content)
if lv != rv {
t.Logf("incorrect fstab entry: %s", lv)
}
}

func TestUmount(t *testing.T) {
mountTemp(t, nil, true)
mountTemp(t, nil, nil, nil)
umountTemp(t)

inode, err := utils.GetFileInode(testMountPoint)
Expand Down
4 changes: 4 additions & 0 deletions cmd/mount_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ func mount_flags() []cli.Flag {
Name: "enable-xattr",
Usage: "enable extended attributes (xattr)",
},
&cli.BoolFlag{
Name: "update-fstab",
Usage: "add / update entry in /etc/fstab",
},
}
return append(selfFlags, cacheFlags(1.0)...)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/rmr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
)

func TestRmr(t *testing.T) {
mountTemp(t, nil, true)
mountTemp(t, nil, nil, nil)
defer umountTemp(t)

paths := []string{"/dir1", "/dir2", "/dir3/dir2"}
Expand Down
2 changes: 1 addition & 1 deletion cmd/status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func TestStatus(t *testing.T) {
patches := gomonkey.ApplyGlobalVar(os.Stdout, *tmpFile)
defer patches.Reset()

mountTemp(t, nil, true)
mountTemp(t, nil, nil, nil)
defer umountTemp(t)

if err = Main([]string{"", "status", testMeta}); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cmd/warmup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (
)

func TestWarmup(t *testing.T) {
mountTemp(t, nil, true)
mountTemp(t, nil, nil, nil)
defer umountTemp(t)

if err := os.WriteFile(fmt.Sprintf("%s/f1.txt", testMountPoint), []byte("test"), 0644); err != nil {
Expand Down

0 comments on commit c573f29

Please sign in to comment.