Skip to content

Commit

Permalink
added meta-fuse-csi-plugin code and made dockerfile
Browse files Browse the repository at this point in the history
  • Loading branch information
Mathis Marcotte committed Jul 9, 2024
1 parent be896e8 commit 9db676b
Show file tree
Hide file tree
Showing 13 changed files with 980 additions and 0 deletions.
Empty file added .github/workflows/build.yaml
Empty file.
35 changes: 35 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
FROM golang:1.20.7 as fusermount3-proxy-builder

WORKDIR /meta-fuse-csi-plugin
ADD . .
# Builds the meta-fuse-csi-plugin app
RUN make fusermount3-proxy BINDIR=/bin
# Builds the goofys app
RUN CGO_ENABLED=0 GOOS=linux go build -o goofys

FROM ubuntu:22.04

RUN apt update && apt upgrade -y
RUN apt install -y ca-certificates wget libfuse2 fuse3

# prepare for MinIO
RUN wget https://dl.min.io/client/mc/release/linux-amd64/mc -O /usr/bin/mc && chmod +x /usr/bin/mc

COPY <<EOF /test.txt
This is a test file for minio
EOF

COPY <<EOF /configure_minio.sh
#!/bin/bash
set -eux
/usr/bin/mc alias set k8s-minio-dev http://localhost:9000 minioadmin minioadmin
/usr/bin/mc mb k8s-minio-dev/test-bucket
/usr/bin/mc cp /test.txt k8s-minio-dev/test-bucket
EOF
RUN chmod +x /configure_minio.sh

#Get goofys build from first step
COPY --from=fusermount3-proxy-builder /meta-fuse-csi-plugin/goofys .

COPY --from=fusermount3-proxy-builder /bin/fusermount3-proxy /bin/fusermount3
RUN ln -sf /bin/fusermount3 /bin/fusermount
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
export CGO_ENABLED=0

export STAGINGVERSION ?= $(shell git describe --long --tags --match='v*' --dirty 2>/dev/null || git rev-list -n1 HEAD)
export BUILD_DATE ?= $(shell date --iso-8601=minutes)
BINDIR ?= bin
LDFLAGS ?= -s -w -X main.version=${STAGINGVERSION} -X main.builddate=${BUILD_DATE} -extldflags '-static'
FUSERMOUNT3PROXY_BINARY = fusermount3-proxy

run-test: s3proxy.jar
./test/run-tests.sh

Expand All @@ -14,3 +20,8 @@ build:

install:
go install -ldflags "-X main.Version=`git rev-parse HEAD`"

fusermount3-proxy:
mkdir -p ${BINDIR}
CGO_ENABLED=0 GOOS=linux GOARCH=$(shell dpkg --print-architecture) go build -ldflags "${LDFLAGS}" -o ${BINDIR}/${FUSERMOUNT3PROXY_BINARY} meta-fuse-csi-plugin/cmd/fusermount3-proxy/main.go

6 changes: 6 additions & 0 deletions go.work
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
go 1.20

use (
.
./meta-fuse-csi-plugin
)
63 changes: 63 additions & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM=
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY=
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/apimachinery v0.28.1 h1:EJD40og3GizBSV3mkIoXQBsws32okPOy+MkRyzh6nPY=
k8s.io/apimachinery v0.28.1/go.mod h1:X0xh/chESs2hP9koe+SdIAcXWcQ+RM5hy0ZynB+yEvw=
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
141 changes: 141 additions & 0 deletions meta-fuse-csi-plugin/cmd/fusermount3-proxy/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
Copyright 2023 Preferred Networks, Inc.
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
https://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 fusermount3proxy

import (
"fmt"
"os"
"strconv"
"syscall"

starter "github.com/StatCan/goofys/meta-fuse-csi-plugin/pkg/fuse_starter"
"github.com/StatCan/goofys/meta-fuse-csi-plugin/pkg/util"
flag "github.com/spf13/pflag"

"k8s.io/klog/v2"
)

var (
optUnmount = flag.BoolP("unmount", "u", false, "unmount (NOT SUPPORTED)")
optAutoUnmount = flag.BoolP("auto-unmount", "U", false, "auto-unmount (NOT SUPPORTED)")
optLazy = flag.BoolP("lazy", "z", false, "lazy umount (NOT SUPPORTED)")
optQuiet = flag.BoolP("quiet", "q", false, "quiet (NOT SUPPORTED)")
optHelp = flag.BoolP("help", "h", false, "print help")
optVersion = flag.BoolP("version", "V", false, "print version")
optOptions = flag.StringP("options", "o", "", "mount options")
// This is set at compile time.
version = "unknown"
builddate = "unknown"
)

var ignoredOptions = map[string]*bool{
"unmount": optUnmount,
"auto-unmount": optAutoUnmount,
"lazy": optLazy,
"optQuiet": optQuiet,
}

const (
ENV_FUSE_COMMFD = "_FUSE_COMMFD"
ENV_FUSERMOUNT3PROXY_FDPASSING_SOCKPATH = "FUSERMOUNT3PROXY_FDPASSING_SOCKPATH"
)

func main() {
klog.InitFlags(nil)
flag.Parse()

if *optHelp {
flag.PrintDefaults()
os.Exit(0)
}

if *optVersion {
fmt.Printf("fusermount3-dummy version %v (BuildDate %v)\n", version, builddate)
os.Exit(0)
}

klog.Infof("Running meta-fuse-csi-plugin fusermount3-dummy version %v (BuildDate %v)", version, builddate)

if *optUnmount {
klog.Warning("'unmount' is not supported.")
os.Exit(0)
}

if len(flag.Args()) == 0 {
klog.Error("mountpoint is not specified.")
os.Exit(1)
}

if *optOptions == "" {
klog.Error("options is not specified.")
os.Exit(1)
}

// fd-passing socket between fusermount3-dummy and csi-driver is passed as env var
fdPassingSocketPath := os.Getenv(ENV_FUSERMOUNT3PROXY_FDPASSING_SOCKPATH)
if fdPassingSocketPath == "" {
klog.Errorf("environment variable %q is not specified.", ENV_FUSERMOUNT3PROXY_FDPASSING_SOCKPATH)
os.Exit(1)
}
klog.Infof("fd-passing socket path is %q", fdPassingSocketPath)

mntPoint := flag.Args()[0]
klog.Infof("mountpoint is %q, but ignored.", mntPoint)

for k, v := range ignoredOptions {
if *v {
klog.Warningf("opiton %q is true, but ignored.", k)
}
}

// TODO: send options to csi-driver and use them?
klog.Infof("options=%q", *optOptions)

// get unix domain socket from caller
commFdStr := os.Getenv(ENV_FUSE_COMMFD)
commFd, err := strconv.Atoi(commFdStr)
if err != nil {
klog.Errorf("failed to get commFd _FUSE_COMMFD=%q", commFdStr)
os.Exit(1)
}
klog.Infof("commFd from %q is %d", ENV_FUSE_COMMFD, commFd)

commConn, err := util.GetNetConnFromRawUnixSocketFd(commFd)
if err != nil {
klog.Errorf("failed to convert commFd to net.Conn: %w", err)
os.Exit(1)
}
klog.Infof("net.Conn is acquired from fd %d", commFd)

// get fd for /dev/fuse from csi-driver
mc, err := starter.PrepareMountConfig(fdPassingSocketPath)
if err != nil {
klog.Errorf("failed to prepare mount config: socket path %q: %w", fdPassingSocketPath, err)
os.Exit(1)
}
defer syscall.Close(mc.FileDescriptor)
klog.Infof("received fd for /dev/fuse from csi-driver via socket %q", fdPassingSocketPath)

// now already FUSE-fs mounted and fd is ready.
err = util.SendMsg(commConn, mc.FileDescriptor, []byte{0})
if err != nil {
klog.Errorf("failed to send fd via commFd: %w", err)
os.Exit(1)
}
klog.Infof("sent fd for /dev/fuse via commFd %d", commFd)
klog.Info("exiting fusermount3-dummy...")
}
11 changes: 11 additions & 0 deletions meta-fuse-csi-plugin/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module github.com/StatCan/goofys/meta-fuse-csi-plugin

go 1.20

require (
github.com/spf13/pflag v1.0.5
k8s.io/apimachinery v0.28.1
k8s.io/klog/v2 v2.130.1
)

require github.com/go-logr/logr v1.4.1 // indirect
8 changes: 8 additions & 0 deletions meta-fuse-csi-plugin/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
k8s.io/apimachinery v0.28.1 h1:EJD40og3GizBSV3mkIoXQBsws32okPOy+MkRyzh6nPY=
k8s.io/apimachinery v0.28.1/go.mod h1:X0xh/chESs2hP9koe+SdIAcXWcQ+RM5hy0ZynB+yEvw=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
105 changes: 105 additions & 0 deletions meta-fuse-csi-plugin/pkg/fuse_starter/fuse_starter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
Copyright 2018 The Kubernetes Authors.
Copyright 2022 Google LLC
Copyright 2023 Preferred Networks, Inc.
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
https://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 fusestarter

import (
"encoding/json"
"fmt"
"net"
"os"
"os/exec"
"syscall"

"github.com/StatCan/goofys/meta-fuse-csi-plugin/pkg/util"
"k8s.io/klog/v2"
)

// FuseStarter will be used in the sidecar container to invoke fuse impl.
type FuseStarter struct {
mounterPath string
mounterArgs []string
Cmd *exec.Cmd
}

// New returns a FuseStarter for the current system.
// It provides an option to specify the path to fuse binary.
func New(mounterPath string, mounterArgs []string) *FuseStarter {
return &FuseStarter{
mounterPath: mounterPath,
mounterArgs: mounterArgs,
Cmd: nil,
}
}

type MountConfig struct {
FileDescriptor int `json:"-"`
VolumeName string `json:"volumeName,omitempty"`
}

func (m *FuseStarter) Mount(mc *MountConfig) (*exec.Cmd, error) {
klog.Infof("start to invoke fuse impl for volume %q", mc.VolumeName)

klog.Infof("%s mounting with args %v...", m.mounterPath, m.mounterArgs)
cmd := exec.Cmd{
Path: m.mounterPath,
Args: append([]string{m.mounterPath}, m.mounterArgs...),
ExtraFiles: []*os.File{os.NewFile(uintptr(mc.FileDescriptor), "/dev/fuse")},
Stdout: os.Stdout,
Stderr: os.Stderr,
}

m.Cmd = &cmd

return &cmd, nil
}

// Fetch the following information from a given socket path:
// 1. Pod volume name
// 2. The file descriptor
// 3. Mount options passing to mounter (passed by the csi mounter).
func PrepareMountConfig(sp string) (*MountConfig, error) {
mc := MountConfig{}

klog.Infof("connecting to socket %q", sp)
c, err := net.Dial("unix", sp)
if err != nil {
return nil, fmt.Errorf("failed to connect to the socket %q: %w", sp, err)
}
defer func() {
// as we got all the information from the socket, closing the connection and deleting the socket
c.Close()
if err = syscall.Unlink(sp); err != nil {
// csi driver may already removed the socket.
klog.Warningf("failed to close socket %q: %v", sp, err)
}
}()

fd, msg, err := util.RecvMsg(c)
if err != nil {
return nil, fmt.Errorf("failed to receive mount options from the socket %q: %w", sp, err)
}

mc.FileDescriptor = fd

if err := json.Unmarshal(msg, &mc); err != nil {
return nil, fmt.Errorf("failed to unmarshal the mount config: %w", err)
}

return &mc, nil
}
Loading

0 comments on commit 9db676b

Please sign in to comment.