Skip to content
This repository has been archived by the owner on Aug 13, 2019. It is now read-only.

add-go-fuse-to-inject-filesystem-error #583

Open
wants to merge 84 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 80 commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
b97c06f
add-go-fuse-to-inject-filesystem-error
qiffang Apr 16, 2019
29b7209
add-go-fuse-to-inject-filesystem-error
qiffang Apr 16, 2019
394b39a
add-go-fuse-to-inject-filesystem-error
qiffang Apr 16, 2019
2472c78
add-go-fuse-to-inject-filesystem-error
qiffang Apr 17, 2019
ec0a5e0
add-go-fuse-to-inject-filesystem-error
qiffang Apr 17, 2019
75d7e04
add-go-fuse-to-inject-filesystem-error
qiffang Apr 17, 2019
c44cf44
add-go-fuse-to-inject-filesystem-error
qiffang Apr 17, 2019
a9ed232
Merge branch 'add-go-fuse-to-inject-filesystem-error' of https://gith…
qiffang Apr 17, 2019
81f7dd5
add-go-fuse-to-inject-filesystem-error
qiffang Apr 17, 2019
8ce9574
add-go-fuse-to-inject-filesystem-error
qiffang Apr 17, 2019
13374dd
Merge branch 'add-go-fuse-to-inject-filesystem-error' of https://gith…
qiffang Apr 18, 2019
62ae86f
Merge branch 'add-go-fuse-to-inject-filesystem-error' of https://gith…
qiffang Apr 18, 2019
5037567
Merge branch 'add-go-fuse-to-inject-filesystem-error' of https://gith…
qiffang Apr 18, 2019
406adcc
add-go-fuse-to-inject-filesystem-error
qiffang Apr 25, 2019
37157e9
add-go-fuse-to-inject-filesystem-error
qiffang May 14, 2019
b8478d4
add-go-fuse-to-inject-filesystem-error
qiffang May 14, 2019
d469dbf
add-go-fuse-to-inject-filesystem-error
qiffang May 15, 2019
261d9c5
add-go-fuse-to-inject-filesystem-error
qiffang May 16, 2019
f3808fe
add-go-fuse-to-inject-filesystem-error
qiffang May 16, 2019
b00d5bd
add-go-fuse-to-inject-filesystem-error
qiffang May 16, 2019
c1a3061
add-go-fuse-to-inject-filesystem-error
qiffang May 24, 2019
e11678e
add-go-fuse-to-inject-filesystem-error
qiffang May 24, 2019
4ac7384
add-go-fuse-to-inject-filesystem-error
qiffang May 24, 2019
bb5f22d
add-go-fuse-to-inject-filesystem-error
qiffang May 24, 2019
c8b6c6f
add-go-fuse-to-inject-filesystem-error
qiffang May 24, 2019
097610a
add-go-fuse-to-inject-filesystem-error
qiffang May 24, 2019
b634c3e
add-go-fuse-to-inject-filesystem-error
qiffang May 24, 2019
ccf974d
add-go-fuse-to-inject-filesystem-error
qiffang May 24, 2019
6aa7043
add-go-fuse-to-inject-filesystem-error
qiffang May 24, 2019
7ba8847
Merge branch 'master' into add-go-fuse-to-inject-filesystem-error
qiffang May 24, 2019
0795eb8
Merge branch 'master' into add-go-fuse-to-inject-filesystem-error
qiffang May 25, 2019
5de9085
add-go-fuse-to-inject-filesystem-error
qiffang May 25, 2019
ca04b2b
add-go-fuse-to-inject-filesystem-error
qiffang May 25, 2019
c607310
add-go-fuse-to-inject-filesystem-error
qiffang May 31, 2019
ddcc50d
add-go-fuse-to-inject-filesystem-error
qiffang May 31, 2019
9753d96
add-go-fuse-to-inject-filesystem-error
qiffang May 31, 2019
54774f1
add-go-fuse-to-inject-filesystem-error
qiffang May 31, 2019
5f15701
add-go-fuse-to-inject-filesystem-error
qiffang May 31, 2019
0417ed6
add-go-fuse-to-inject-filesystem-error
qiffang May 31, 2019
f3f984d
add-go-fuse-to-inject-filesystem-error
qiffang May 31, 2019
4bda5c0
add-go-fuse-to-inject-filesystem-error
qiffang Jun 1, 2019
8d09cc0
add-go-fuse-to-inject-filesystem-error
qiffang Jun 1, 2019
ac9068f
add-go-fuse-to-inject-filesystem-error
qiffang Jun 3, 2019
8c485d6
add-go-fuse-to-inject-filesystem-error
qiffang Jun 6, 2019
d9c5506
add-go-fuse-to-inject-filesystem-error
qiffang Jun 6, 2019
90f8077
Merge branch 'master' into add-go-fuse-to-inject-filesystem-error
qiffang Jun 6, 2019
80edb85
add-go-fuse-to-inject-filesystem-error
qiffang Jun 6, 2019
797257b
add-go-fuse-to-inject-filesystem-error
qiffang Jun 6, 2019
de99273
add-go-fuse-to-inject-filesystem-error
qiffang Jun 6, 2019
26b3fb8
add-go-fuse-to-inject-filesystem-error
qiffang Jun 7, 2019
0c0a19d
add-go-fuse-to-inject-filesystem-error
qiffang Jun 7, 2019
e16e3a7
add-go-fuse-to-inject-filesystem-error
qiffang Jun 7, 2019
ad6151f
add-go-fuse-to-inject-filesystem-error
qiffang Jun 8, 2019
59c387b
add-go-fuse-to-inject-filesystem-error
qiffang Jun 10, 2019
687fd7f
add-go-fuse-to-inject-filesystem-error
qiffang Jun 11, 2019
20534be
add-go-fuse-to-inject-filesystem-error
qiffang Jun 11, 2019
42b7859
add-go-fuse-to-inject-filesystem-error
qiffang Jun 11, 2019
9f79aa9
add-go-fuse-to-inject-filesystem-error
qiffang Jun 12, 2019
6d56002
add-go-fuse-to-inject-filesystem-error
qiffang Jun 12, 2019
9b0e24f
add-go-fuse-to-inject-filesystem-error
qiffang Jun 12, 2019
0e390ac
add-go-fuse-to-inject-filesystem-error
qiffang Jun 12, 2019
33e8785
add-go-fuse-to-inject-filesystem-error
qiffang Jun 13, 2019
0ac1b40
add-go-fuse-to-inject-filesystem-error
qiffang Jun 13, 2019
a545d05
add-go-fuse-to-inject-filesystem-error
qiffang Jun 13, 2019
43c2c03
add-go-fuse-to-inject-filesystem-error
qiffang Jun 13, 2019
f1cf68f
add-go-fuse-to-inject-filesystem-error
qiffang Jun 18, 2019
5859805
add-go-fuse-to-inject-filesystem-error
qiffang Jun 18, 2019
f7be8b1
add-go-fuse-to-inject-filesystem-error
qiffang Jun 18, 2019
0ebd0a7
add-go-fuse-to-inject-filesystem-error
qiffang Jun 18, 2019
9408f0d
add-go-fuse-to-inject-filesystem-error
qiffang Jun 18, 2019
8833d11
add-go-fuse-to-inject-filesystem-error
qiffang Jun 18, 2019
f9af261
add-go-fuse-to-inject-filesystem-error
qiffang Jun 18, 2019
0e6f527
add-go-fuse-to-inject-filesystem-error
qiffang Jun 18, 2019
e670888
add-go-fuse-to-inject-filesystem-error
qiffang Jun 19, 2019
f7c0590
add-go-fuse-to-inject-filesystem-error
qiffang Jun 20, 2019
719257b
add-go-fuse-to-inject-filesystem-error
qiffang Jun 20, 2019
213d516
add-go-fuse-to-inject-filesystem-error
qiffang Jun 23, 2019
bbc3ee7
add-go-fuse-to-inject-filesystem-error
qiffang Jun 25, 2019
33b31b8
Merge branch 'master' into add-go-fuse-to-inject-filesystem-error
qiffang Jun 25, 2019
6320020
add-go-fuse-to-inject-filesystem-error
qiffang Jun 25, 2019
0680777
Table-Partition-Issue-AS-MYSQL-BUG/42849
qiffang Jun 25, 2019
e59acfa
Table-Partition-Issue-AS-MYSQL-BUG/42849
qiffang Jun 25, 2019
998ef76
Merge branch 'master' into add-go-fuse-to-inject-filesystem-error
qiffang Jul 25, 2019
429f7b0
add-go-fuse-to-inject-filesystem-error
qiffang Jul 26, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 33 additions & 16 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,37 @@
dist: trusty
language: go
os:
- windows
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry maybe I wasn't clear. We still need to run all but the file system tests for Windows.

For example maybe put all unix OS specific tests in block_unix_test.go

Copy link
Author

@qiffang qiffang Jun 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry maybe I wasn't clear. We still need to run all but the file system tests for Windows.

For example maybe put all unix OS specific tests in block_unix_test.go

@krasi-georgiev
Currently, go fuse library do not support windows platform, so there is a compile error in windows platform

..\..\..\..\pkg\mod\github.com\hanwen\[email protected]\fuse\types.go:511:2: undefined: Attr

I am trying to solve it and do you have any suggestions?
Thanks

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you think the library is loaded when running the tests under windows?
When you have something like block_unix_test.go the file should be loaded only on unix OS-es

Copy link
Contributor

@krasi-georgiev krasi-georgiev Jun 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should rename all fuse utils files to fuse_..._unix.go

Copy link
Author

@qiffang qiffang Jun 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fuse_..._unix.go

For linux and macos, i add the build flag in golang files

// +build linux darwin

Then if the platform is linux or osx, these go files will be automatic applied.
And for windows platform, the fuse_utils_windows.go will be automatic applied.

The advantage is that other developers can write fuse cases in everywhere and do not need to put fuse cases in a special directory.

From the build flag, i see that there is only linux、darwin、windows、freebsd suffix to support. I am not sure the file which suffix is unix can work.

Copy link
Contributor

@krasi-georgiev krasi-georgiev Jun 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, but looking at the code seems that these tests will fail under windows anyway as they will not use the fuse server mounts so can't inject errors and when the tests expects an error, no error will be returned.

From the build flag, i see that there is only linux、darwin、windows、freebsd suffix to support. I am not sure the file which suffix is unix can work.

yes inside you can put: // +build !windows

Copy link
Author

@qiffang qiffang Jun 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@krasi-georgiev
They do not fail under windows platform because fuse related cases will automatic skipped in windows platform(Other developer who want to inject file system error do not care it because it is automatic skipped in windows platform). In windows platform, it only run other cases which do not include fuse related cases.

For linux and macosx platform, it will run all cases. They works well.

I think the tests which need to inject filesystem errors only run in linux and macosx platform.

And in windows platform, it only run other cases, the fuse related cases will automatic skipped in windows platform. Because windows platform do not support fuse.

Every thing looks well, do you think it is ok?

image

- linux
- osx

go:
- 1.12.x

go_import_path: github.com/prometheus/tsdb
matrix:
include:
- os: linux
dist: trusty
sudo: required
go: 1.12.x
install:
- make deps
script:
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install fuse
- sudo modprobe fuse
- sudo chmod a+rw /etc/fuse.conf
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need these?

- sudo chmod 666 /dev/fuse
- sudo chown root:$USER /etc/fuse.conf
- sudo chmod a+rw /etc/fuse.conf

I think just - sudo addgroup $USER fuse should be enough , no?

Copy link
Author

@qiffang qiffang Jun 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to write user_allow_other to fuse.conf to allow other users which is not root to execute fuse

I remove following lines, but the sudo chmod a+rw /etc/fuse.conf need to add user_allow_other to the conf file

     - sudo chmod 666 /dev/fuse
      - sudo chown root:$USER /etc/fuse.conf

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you sure that sudo echo user_allow_other >> /etc/fuse.conf doesn't work without sudo chmod a+rw /etc/fuse.conf ?

Copy link
Contributor

@krasi-georgiev krasi-georgiev Jun 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you sure that sudo echo user_allow_other >> /etc/fuse.conf doesn't work without sudo chmod a+rw /etc/fuse.conf ?

- sudo echo user_allow_other >> /etc/fuse.conf
- make all
- os: osx
go: 1.12.x
sudo: required
osx_image: xcode8.3
script:
- brew update
- brew tap homebrew/cask
- brew cask install osxfuse
- sudo /Library/Filesystems/osxfuse.fs/Contents/Resources/load_osxfuse
- sudo sysctl -w vfs.generic.osxfuse.tunables.allow_other=1
- make all
- os: windows
go: 1.12.x
before_install:
- choco install make
install:
- make deps
script:
- make test

before_install:
- if [[ "$TRAVIS_OS_NAME" == "windows" ]]; then choco install make; fi

install:
- make deps

script:
- if [[ "$TRAVIS_OS_NAME" == "windows" ]]; then make test; else make all; fi
38 changes: 38 additions & 0 deletions block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"context"
"encoding/binary"
"errors"
"github.com/prometheus/tsdb/testutil/fuse"
"io/ioutil"
"math/rand"
"os"
Expand Down Expand Up @@ -292,3 +293,40 @@ func populateSeries(lbls []map[string]string, mint, maxt int64) []Series {
}
return series
}

// TestFailedDelete ensures that the block is in its original state when a delete fails.
func TestFailedDelete(t *testing.T) {
original, err := ioutil.TempDir("", "original")
testutil.Ok(t, err)
mountpoint, err := ioutil.TempDir("", "mountpoint")
testutil.Ok(t, err)

defer func() {
testutil.Ok(t, os.RemoveAll(mountpoint))
testutil.Ok(t, os.RemoveAll(original))
}()

_, file := filepath.Split(createBlock(t, original, genSeries(1, 1, 1, 100)))
server, err := fuse.NewServer(original, mountpoint, fuse.FailingRenameHook{})
if err != nil {
t.Skip(err) // Skip the test for any error. These tests are optional.
}
defer func() {
testutil.Ok(t, server.Close())
}()

expHash, err := testutil.DirHash(original)
testutil.Ok(t, err)
pb, err := OpenBlock(nil, filepath.Join(mountpoint, file), nil)
testutil.Ok(t, err)
defer func() {
testutil.Ok(t, pb.Close())
}()

testutil.NotOk(t, pb.Delete(1, 10, labels.NewMustRegexpMatcher("", ".*")))

actHash, err := testutil.DirHash(original)
testutil.Ok(t, err)

testutil.Equals(t, expHash, actHash, "the block dir hash has changed after a failed delete")
}
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ require (
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954
github.com/go-kit/kit v0.8.0
github.com/golang/snappy v0.0.1
github.com/hanwen/go-fuse v1.0.0
github.com/oklog/ulid v1.3.1
github.com/pkg/errors v0.8.0
github.com/prometheus/client_golang v1.0.0
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5
golang.org/x/sys v0.0.0-20190422165155-953cdadca894
gopkg.in/alecthomas/kingpin.v2 v2.2.6
)
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/hanwen/go-fuse v1.0.0 h1:GxS9Zrn6c35/BnfiVsZVWmsG803xwE7eVRDvcf/BEVc=
github.com/hanwen/go-fuse v1.0.0/go.mod h1:unqXarDXqzAk0rt98O2tVndEPIpUgLD9+rwFisZH3Ok=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
Expand Down Expand Up @@ -74,9 +76,12 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTm
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5 h1:mzjBh+S5frKOsOBobWIMAbXavqjmgO17k/2puhcFR94=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
38 changes: 38 additions & 0 deletions testutil/directory.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@
package testutil

import (
"crypto/md5"
"io"
"io/ioutil"
"os"
"path/filepath"
"strconv"
)

const (
Expand Down Expand Up @@ -143,3 +146,38 @@ func DirSize(path string) (int64, error) {
})
return size, err
}

// DirHash returns a hash of all files attributes and their content within a directory.
func DirHash(path string) ([]byte, error) {
hash := md5.New()
err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()

if _, err := io.Copy(hash, f); err != nil {
return err
}

if _, err := io.WriteString(hash, strconv.Itoa(int(info.Size()))); err != nil {
return err
}
if _, err := io.WriteString(hash, info.Name()); err != nil {
return err
}

if _, err := io.WriteString(hash, string(info.ModTime().Unix())); err != nil {
return err
}

}
return err
})
return hash.Sum(nil), err
}
160 changes: 160 additions & 0 deletions testutil/fuse/fuse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// +build linux darwin

// Copyright 2019 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fuse

import (
"fmt"
"path/filepath"
"runtime"
"syscall"
"time"

"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/nodefs"
"github.com/hanwen/go-fuse/fuse/pathfs"
)

type loopBackFs struct {
pathfs.FileSystem
}

// hookFs implements the fuse FileSystem interface and allows injecting hooks for different operations.
// Its main purpose is to provide a way to inject file system errors.
type hookFs struct {
qiffang marked this conversation as resolved.
Show resolved Hide resolved
original string
mountpoint string
fsName string
loopBackFs
hook Hook
}

// String returns the string representation of the mounted points.
func (h *hookFs) String() string {
return fmt.Sprintf("HookFs{Original=%s, Mountpoint=%s, FsName=%s, Underlying fs=%s, hook=%s}",
h.original, h.mountpoint, h.fsName, h.loopBackFs.String(), h.hook)
}

// Rename calls the injected rename hooks if those exist or the underlying loopback fs Rename api.
func (h *hookFs) Rename(oldName string, newName string, context *fuse.Context) fuse.Status {
preHooked, err := h.hook.PreRename(oldName, newName)
if preHooked {
if err != nil {
return fuse.ToStatus(err)
}
}

status := h.loopBackFs.Rename(oldName, newName, context)

postHooked, err := h.hook.PostRename(oldName, newName)
if postHooked {
if err != nil {
return fuse.ToStatus(err)
}
}
return status
}

func (h *hookFs) newServer() (*fuse.Server, error) {
opts := &nodefs.Options{
NegativeTimeout: time.Second,
AttrTimeout: time.Second,
EntryTimeout: time.Second,
}
pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true}
pathFs := pathfs.NewPathNodeFs(h, pathFsOpts)
conn := nodefs.NewFileSystemConnector(pathFs.Root(), opts)
originalAbs, _ := filepath.Abs(h.original)
qiffang marked this conversation as resolved.
Show resolved Hide resolved
mOpts := &fuse.MountOptions{
AllowOther: true,
Name: h.fsName,
FsName: originalAbs,
}
return fuse.NewServer(conn.RawFS(), h.mountpoint, mOpts)
}

// Server is a fuse server proxy.
type Server struct {
server *fuse.Server
original string
mountpoint string
}

// NewServer creates a fuse server and attaches it to the given `mountpoint` directory.
// The caller should not forget to close the server to release the mountpoints.
func NewServer(original, mountpoint string, hook Hook) (*Server, error) {
fs := &hookFs{
original: original,
mountpoint: mountpoint,
fsName: "hookfs",
loopBackFs: loopBackFs{pathfs.NewLoopbackFileSystem(original)},
hook: hook,
}

server, err := fs.newServer()
if err != nil {
return nil, err
}

// Async start fuse server, and it will be stopped when calling `fuse.Unmount()` method.
go func() {
server.Serve()
}()

return &Server{
server: server,
mountpoint: mountpoint,
original: original,
}, server.WaitMount()
}

// Close releases the mountpoints and return false if the unmount fails.
// When the mountpoint has open files it tries to force unmount.
func (s *Server) Close() error {
err := s.server.Unmount()
if err != nil {
return s.forceUnmount()
}

return nil
}

// forceUnmount forces to unmount even when there are still open files.
func (s *Server) forceUnmount() (err error) {
delay := time.Duration(0)
for try := 0; try < 5; try++ {
err = syscall.Unmount(s.mountpoint, unmountFlag())
if err == nil {
break
}

// Sleep for a bit. This is not pretty, but there is
// no way we can be certain that the kernel thinks all
// open files have already been closed.
delay = 2*delay + 10*time.Millisecond
time.Sleep(delay)
}

return err
}

// unmountFlag returns platform dependent force unmount flag.
func unmountFlag() int {
if runtime.GOOS == "darwin" {
return -1
}

return 0x1
}
30 changes: 30 additions & 0 deletions testutil/fuse/fuse_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2019 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
krasi-georgiev marked this conversation as resolved.
Show resolved Hide resolved
package fuse

import "errors"

// Server implements a mock server to allow skipping tests for windows platform
// which doesn't support fuse.
type Server struct {
}

// NewServer always returns an error because fuse does not support Windows platform.
func NewServer(original, mountpoint string, hook Hook) (*Server, error) {
return nil, errors.New("fuse not supported under Windows")
}

// Close is a noop method.
func (s *Server) Close() error {
return nil
}
Loading