From 9d5d84ebfb83991cae38c5a93ae81d16eed95834 Mon Sep 17 00:00:00 2001 From: Cyrill Troxler Date: Sat, 21 Jul 2018 13:35:31 +0200 Subject: [PATCH] Refactor all mounters to use the mounter interface --- pkg/s3/controllerserver.go | 19 +++++---- pkg/s3/goofys.go | 37 ---------------- pkg/s3/mounter.go | 34 +++++++++++++++ pkg/s3/mounter_goofys.go | 63 ++++++++++++++++++++++++++++ pkg/s3/mounter_s3fs.go | 64 ++++++++++++++++++++++++++++ pkg/s3/{s3ql.go => mounter_s3ql.go} | 65 +++++++++++------------------ pkg/s3/nodeserver.go | 36 ++++------------ pkg/s3/s3fs.go | 43 ------------------- 8 files changed, 204 insertions(+), 157 deletions(-) delete mode 100644 pkg/s3/goofys.go create mode 100644 pkg/s3/mounter.go create mode 100644 pkg/s3/mounter_goofys.go create mode 100644 pkg/s3/mounter_s3fs.go rename pkg/s3/{s3ql.go => mounter_s3ql.go} (59%) delete mode 100644 pkg/s3/s3fs.go diff --git a/pkg/s3/controllerserver.go b/pkg/s3/controllerserver.go index 8b2f4bc..1d3b859 100644 --- a/pkg/s3/controllerserver.go +++ b/pkg/s3/controllerserver.go @@ -55,20 +55,21 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol return nil, err } if !exists { - if err := cs.s3.client.createBucket(volumeID); err != nil { + if err = cs.s3.client.createBucket(volumeID); err != nil { glog.V(3).Infof("failed to create volume: %v", err) return nil, err } } - mounter := cs.s3.cfg.Mounter - if mounter == "" { - mounter = req.GetParameters()[mounterKey] + mounterType := cs.s3.cfg.Mounter + if mounterType == "" { + mounterType = req.GetParameters()[mounterKey] } - switch mounter { - case s3qlMounter: - if err := s3qlCreate(volumeID, cs.s3.cfg); err != nil { - return nil, err - } + mounter, err := newMounter(mounterType, volumeID, cs.s3.cfg) + if err != nil { + return nil, err + } + if err := mounter.Format(); err != nil { + return nil, err } glog.V(4).Infof("create volume %s", volumeID) diff --git a/pkg/s3/goofys.go b/pkg/s3/goofys.go deleted file mode 100644 index d28ff7c..0000000 --- a/pkg/s3/goofys.go +++ /dev/null @@ -1,37 +0,0 @@ -package s3 - -import ( - "fmt" - "os" - - "context" - - goofys "github.com/kahing/goofys/api" -) - -const defaultRegion = "us-east-1" - -func goofysMount(bucket string, cfg *Config, targetPath string) error { - goofysCfg := &goofys.Config{ - MountPoint: targetPath, - Endpoint: cfg.Endpoint, - Region: cfg.Region, - DirMode: 0755, - FileMode: 0644, - MountOptions: map[string]string{ - "allow_other": "", - }, - } - if cfg.Endpoint != "" { - cfg.Region = defaultRegion - } - os.Setenv("AWS_ACCESS_KEY_ID", cfg.AccessKeyID) - os.Setenv("AWS_SECRET_ACCESS_KEY", cfg.SecretAccessKey) - - _, _, err := goofys.Mount(context.Background(), bucket, goofysCfg) - - if err != nil { - return fmt.Errorf("Error mounting via goofys: %s", err) - } - return nil -} diff --git a/pkg/s3/mounter.go b/pkg/s3/mounter.go new file mode 100644 index 0000000..55d148a --- /dev/null +++ b/pkg/s3/mounter.go @@ -0,0 +1,34 @@ +package s3 + +import "fmt" + +// Mounter interface which can be implemented +// by the different mounter types +type Mounter interface { + Format() error + Mount(targetPath string) error +} + +const ( + mounterKey = "mounter" + s3fsMounterType = "s3fs" + goofysMounterType = "goofys" + s3qlMounterType = "s3ql" +) + +// newMounter returns a new mounter depending on the mounterType parameter +func newMounter(mounterType string, bucket string, cfg *Config) (Mounter, error) { + switch mounterType { + case "": + case s3fsMounterType: + return newS3fsMounter(bucket, cfg) + + case goofysMounterType: + return newGoofysMounter(bucket, cfg) + + case s3qlMounterType: + return newS3qlMounter(bucket, cfg) + + } + return nil, fmt.Errorf("Error mounting bucket %s, invalid mounter specified: %s", bucket, mounterType) +} diff --git a/pkg/s3/mounter_goofys.go b/pkg/s3/mounter_goofys.go new file mode 100644 index 0000000..2a1b8c2 --- /dev/null +++ b/pkg/s3/mounter_goofys.go @@ -0,0 +1,63 @@ +package s3 + +import ( + "fmt" + "os" + + "context" + + goofysApi "github.com/kahing/goofys/api" +) + +const defaultRegion = "us-east-1" + +// Implements Mounter +type goofysMounter struct { + bucket string + endpoint string + region string + accessKeyID string + secretAccessKey string +} + +func newGoofysMounter(bucket string, cfg *Config) (Mounter, error) { + region := cfg.Region + // if endpoint is set we need a default region + if region == "" && cfg.Endpoint != "" { + region = defaultRegion + } + return &goofysMounter{ + bucket: bucket, + endpoint: cfg.Endpoint, + region: region, + accessKeyID: cfg.AccessKeyID, + secretAccessKey: cfg.SecretAccessKey, + }, nil +} + +func (goofys *goofysMounter) Format() error { + return nil +} + +func (goofys *goofysMounter) Mount(targetPath string) error { + goofysCfg := &goofysApi.Config{ + MountPoint: targetPath, + Endpoint: goofys.endpoint, + Region: goofys.region, + DirMode: 0755, + FileMode: 0644, + MountOptions: map[string]string{ + "allow_other": "", + }, + } + + os.Setenv("AWS_ACCESS_KEY_ID", goofys.accessKeyID) + os.Setenv("AWS_SECRET_ACCESS_KEY", goofys.secretAccessKey) + + _, _, err := goofysApi.Mount(context.Background(), goofys.bucket, goofysCfg) + + if err != nil { + return fmt.Errorf("Error mounting via goofys: %s", err) + } + return nil +} diff --git a/pkg/s3/mounter_s3fs.go b/pkg/s3/mounter_s3fs.go new file mode 100644 index 0000000..812f644 --- /dev/null +++ b/pkg/s3/mounter_s3fs.go @@ -0,0 +1,64 @@ +package s3 + +import ( + "fmt" + "os" + "os/exec" +) + +// Implements Mounter +type s3fsMounter struct { + bucket string + url string + region string + pwFileContent string +} + +func newS3fsMounter(bucket string, cfg *Config) (Mounter, error) { + return &s3fsMounter{ + bucket: bucket, + url: cfg.Endpoint, + region: cfg.Region, + pwFileContent: cfg.AccessKeyID + ":" + cfg.SecretAccessKey, + }, nil +} + +func (s3fs *s3fsMounter) Format() error { + return nil +} + +func (s3fs *s3fsMounter) Mount(targetPath string) error { + if err := writes3fsPass(s3fs.pwFileContent); err != nil { + return err + } + args := []string{ + fmt.Sprintf("%s", s3fs.bucket), + fmt.Sprintf("%s", targetPath), + "-o", "sigv2", + "-o", "use_path_request_style", + "-o", fmt.Sprintf("url=%s", s3fs.url), + "-o", fmt.Sprintf("endpoint=%s", s3fs.region), + "-o", "allow_other", + "-o", "mp_umask=000", + } + cmd := exec.Command("s3fs", args...) + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("Error mounting using s3fs, output: %s", out) + } + return nil +} + +func writes3fsPass(pwFileContent string) error { + pwFileName := fmt.Sprintf("%s/.passwd-s3fs", os.Getenv("HOME")) + pwFile, err := os.OpenFile(pwFileName, os.O_RDWR|os.O_CREATE, 0600) + if err != nil { + return err + } + _, err = pwFile.WriteString(pwFileContent) + if err != nil { + return err + } + pwFile.Close() + return nil +} diff --git a/pkg/s3/s3ql.go b/pkg/s3/mounter_s3ql.go similarity index 59% rename from pkg/s3/s3ql.go rename to pkg/s3/mounter_s3ql.go index 3e1a7b8..4995478 100644 --- a/pkg/s3/s3ql.go +++ b/pkg/s3/mounter_s3ql.go @@ -13,7 +13,8 @@ import ( "gopkg.in/ini.v1" ) -type s3fsConfig struct { +// Implements Mounter +type s3qlMounter struct { url string bucketURL string login string @@ -29,7 +30,7 @@ const ( s3qlCmdMount = "mount.s3ql" ) -func newS3ql(bucket string, targetPath string, cfg *Config) (*s3fsConfig, error) { +func newS3qlMounter(bucket string, cfg *Config) (Mounter, error) { url, err := url.Parse(cfg.Endpoint) if err != nil { return nil, err @@ -38,13 +39,12 @@ func newS3ql(bucket string, targetPath string, cfg *Config) (*s3fsConfig, error) if strings.Contains(url.Scheme, "http") { url.Scheme = "s3c" } - s3ql := &s3fsConfig{ + s3ql := &s3qlMounter{ url: url.String(), login: cfg.AccessKeyID, password: cfg.SecretAccessKey, passphrase: cfg.EncryptionKey, ssl: ssl, - targetPath: targetPath, } url.Path = path.Join(url.Path, bucket) @@ -57,21 +57,25 @@ func newS3ql(bucket string, targetPath string, cfg *Config) (*s3fsConfig, error) return s3ql, s3ql.writeConfig() } -func s3qlCreate(bucket string, cfg *Config) error { - s3ql, err := newS3ql(bucket, "unknown", cfg) - if err != nil { - return err +func (s3ql *s3qlMounter) Format() error { + // force creation to ignore existing data + args := []string{ + s3ql.bucketURL, + "--force", } - return s3ql.create() + + p := fmt.Sprintf("%s\n%s\n", s3ql.passphrase, s3ql.passphrase) + reader := bytes.NewReader([]byte(p)) + return s3qlCmd(s3qlCmdMkfs, append(args, s3ql.options...), reader) } -func s3qlMount(bucket string, cfg *Config, targetPath string) error { - s3ql, err := newS3ql(bucket, targetPath, cfg) - if err != nil { - return err +func (s3ql *s3qlMounter) Mount(targetPath string) error { + args := []string{ + s3ql.bucketURL, + targetPath, + "--allow-other", } - - return s3ql.mount() + return s3qlCmd(s3qlCmdMount, append(args, s3ql.options...), nil) } func s3qlCmd(s3qlCmd string, args []string, stdin io.Reader) error { @@ -87,38 +91,17 @@ func s3qlCmd(s3qlCmd string, args []string, stdin io.Reader) error { return nil } -func (cfg *s3fsConfig) create() error { - // force creation to ignore existing data - args := []string{ - cfg.bucketURL, - "--force", - } - - p := fmt.Sprintf("%s\n%s\n", cfg.passphrase, cfg.passphrase) - reader := bytes.NewReader([]byte(p)) - return s3qlCmd(s3qlCmdMkfs, append(args, cfg.options...), reader) -} - -func (cfg *s3fsConfig) mount() error { - args := []string{ - cfg.bucketURL, - cfg.targetPath, - "--allow-other", - } - return s3qlCmd(s3qlCmdMount, append(args, cfg.options...), nil) -} - -func (cfg *s3fsConfig) writeConfig() error { +func (s3ql *s3qlMounter) writeConfig() error { s3qlIni := ini.Empty() section, err := s3qlIni.NewSection("s3ql") if err != nil { return err } - section.NewKey("storage-url", cfg.url) - section.NewKey("backend-login", cfg.login) - section.NewKey("backend-password", cfg.password) - section.NewKey("fs-passphrase", cfg.passphrase) + section.NewKey("storage-url", s3ql.url) + section.NewKey("backend-login", s3ql.login) + section.NewKey("backend-password", s3ql.password) + section.NewKey("fs-passphrase", s3ql.passphrase) authDir := os.Getenv("HOME") + "/.s3ql" authFile := authDir + "/authinfo2" diff --git a/pkg/s3/nodeserver.go b/pkg/s3/nodeserver.go index 9fd88f5..446190a 100644 --- a/pkg/s3/nodeserver.go +++ b/pkg/s3/nodeserver.go @@ -17,7 +17,6 @@ limitations under the License. package s3 import ( - "fmt" "os" "github.com/golang/glog" @@ -31,13 +30,6 @@ import ( "github.com/kubernetes-csi/drivers/pkg/csi-common" ) -const ( - mounterKey = "mounter" - s3fsMounter = "s3fs" - goofysMounter = "goofys" - s3qlMounter = "s3ql" -) - type nodeServer struct { *csicommon.DefaultNodeServer *s3 @@ -86,26 +78,16 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis glog.V(4).Infof("target %v\ndevice %v\nreadonly %v\nvolumeId %v\nattributes %v\nmountflags %v\n", targetPath, deviceID, readOnly, volumeID, attrib, mountFlags) - mounter := ns.s3.cfg.Mounter - if mounter == "" { - mounter = attrib[mounterKey] + mounterType := ns.s3.cfg.Mounter + if mounterType == "" { + mounterType = attrib[mounterKey] } - switch mounter { - case "": - case s3fsMounter: - if err := s3fsMount(volumeID, ns.s3.cfg, targetPath); err != nil { - return nil, err - } - case goofysMounter: - if err := goofysMount(volumeID, ns.s3.cfg, targetPath); err != nil { - return nil, err - } - case s3qlMounter: - if err := s3qlMount(volumeID, ns.s3.cfg, targetPath); err != nil { - return nil, err - } - default: - return nil, fmt.Errorf("Error mounting bucket %s, invalid mounter specified: %s", volumeID, ns.s3.cfg.Mounter) + mounter, err := newMounter(mounterType, volumeID, ns.s3.cfg) + if err != nil { + return nil, err + } + if err := mounter.Mount(targetPath); err != nil { + return nil, err } glog.V(4).Infof("s3: bucket %s successfuly mounted to %s", volumeID, targetPath) diff --git a/pkg/s3/s3fs.go b/pkg/s3/s3fs.go deleted file mode 100644 index 1f48cb7..0000000 --- a/pkg/s3/s3fs.go +++ /dev/null @@ -1,43 +0,0 @@ -package s3 - -import ( - "fmt" - "os" - "os/exec" -) - -func s3fsMount(bucket string, cfg *Config, targetPath string) error { - if err := writes3fsPass(cfg); err != nil { - return err - } - args := []string{ - fmt.Sprintf("%s", bucket), - fmt.Sprintf("%s", targetPath), - "-o", "sigv2", - "-o", "use_path_request_style", - "-o", fmt.Sprintf("url=%s", cfg.Endpoint), - "-o", fmt.Sprintf("endpoint=%s", cfg.Region), - "-o", "allow_other", - "-o", "mp_umask=000", - } - cmd := exec.Command("s3fs", args...) - out, err := cmd.CombinedOutput() - if err != nil { - return fmt.Errorf("Error mounting using s3fs, output: %s", out) - } - return nil -} - -func writes3fsPass(cfg *Config) error { - pwFileName := fmt.Sprintf("%s/.passwd-s3fs", os.Getenv("HOME")) - pwFile, err := os.OpenFile(pwFileName, os.O_RDWR|os.O_CREATE, 0600) - if err != nil { - return err - } - _, err = pwFile.WriteString(cfg.AccessKeyID + ":" + cfg.SecretAccessKey) - if err != nil { - return err - } - pwFile.Close() - return nil -}