2018-07-16 20:27:45 +00:00
|
|
|
package s3
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"net/url"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"path"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"gopkg.in/ini.v1"
|
|
|
|
)
|
|
|
|
|
2018-07-21 11:35:31 +00:00
|
|
|
// Implements Mounter
|
|
|
|
type s3qlMounter struct {
|
2018-07-27 10:56:28 +00:00
|
|
|
bucket *bucket
|
2018-07-16 20:27:45 +00:00
|
|
|
url string
|
|
|
|
bucketURL string
|
|
|
|
login string
|
|
|
|
password string
|
|
|
|
passphrase string
|
|
|
|
options []string
|
|
|
|
ssl bool
|
|
|
|
targetPath string
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
2018-07-21 13:23:11 +00:00
|
|
|
s3qlCmdMkfs = "mkfs.s3ql"
|
|
|
|
s3qlCmdMount = "mount.s3ql"
|
|
|
|
s3qlCmdUnmount = "umount.s3ql"
|
2018-07-16 20:27:45 +00:00
|
|
|
)
|
|
|
|
|
2018-07-27 10:56:28 +00:00
|
|
|
func newS3qlMounter(b *bucket, cfg *Config) (Mounter, error) {
|
2018-07-16 20:27:45 +00:00
|
|
|
url, err := url.Parse(cfg.Endpoint)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
ssl := url.Scheme != "http"
|
|
|
|
if strings.Contains(url.Scheme, "http") {
|
|
|
|
url.Scheme = "s3c"
|
|
|
|
}
|
2018-07-21 11:35:31 +00:00
|
|
|
s3ql := &s3qlMounter{
|
2018-07-27 10:56:28 +00:00
|
|
|
bucket: b,
|
2018-07-16 20:27:45 +00:00
|
|
|
url: url.String(),
|
|
|
|
login: cfg.AccessKeyID,
|
|
|
|
password: cfg.SecretAccessKey,
|
|
|
|
passphrase: cfg.EncryptionKey,
|
|
|
|
ssl: ssl,
|
|
|
|
}
|
|
|
|
|
2018-07-27 19:37:32 +00:00
|
|
|
// s3ql requires a trailing slash or it will just
|
|
|
|
// prepend the fspath to the s3ql files
|
|
|
|
url.Path = path.Join(url.Path, b.Name, b.FSPath) + "/"
|
2018-07-16 20:27:45 +00:00
|
|
|
s3ql.bucketURL = url.String()
|
|
|
|
|
|
|
|
if !ssl {
|
|
|
|
s3ql.options = []string{"--backend-options", "no-ssl"}
|
|
|
|
}
|
|
|
|
|
|
|
|
return s3ql, s3ql.writeConfig()
|
|
|
|
}
|
|
|
|
|
2018-07-26 20:43:51 +00:00
|
|
|
func (s3ql *s3qlMounter) Stage(stagePath string) error {
|
2018-07-21 11:35:31 +00:00
|
|
|
// force creation to ignore existing data
|
|
|
|
args := []string{
|
|
|
|
s3ql.bucketURL,
|
|
|
|
"--force",
|
2018-07-16 20:27:45 +00:00
|
|
|
}
|
2018-07-21 11:35:31 +00:00
|
|
|
|
|
|
|
p := fmt.Sprintf("%s\n%s\n", s3ql.passphrase, s3ql.passphrase)
|
|
|
|
reader := bytes.NewReader([]byte(p))
|
2018-07-22 20:08:48 +00:00
|
|
|
cmd := exec.Command(s3qlCmdMkfs, append(args, s3ql.options...)...)
|
|
|
|
cmd.Stdin = reader
|
|
|
|
|
|
|
|
out, err := cmd.CombinedOutput()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error running s3ql command: %s", out)
|
|
|
|
}
|
|
|
|
return nil
|
2018-07-16 20:27:45 +00:00
|
|
|
}
|
|
|
|
|
2018-07-26 20:43:51 +00:00
|
|
|
func (s3ql *s3qlMounter) Unstage(stagePath string) error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s3ql *s3qlMounter) Mount(source string, target string) error {
|
2018-07-21 11:35:31 +00:00
|
|
|
args := []string{
|
|
|
|
s3ql.bucketURL,
|
2018-07-26 20:43:51 +00:00
|
|
|
target,
|
2018-07-21 11:35:31 +00:00
|
|
|
"--allow-other",
|
2018-07-16 20:27:45 +00:00
|
|
|
}
|
2018-07-26 20:43:51 +00:00
|
|
|
return fuseMount(target, s3qlCmdMount, append(args, s3ql.options...))
|
2018-07-16 20:27:45 +00:00
|
|
|
}
|
|
|
|
|
2018-07-26 20:43:51 +00:00
|
|
|
func (s3ql *s3qlMounter) Unmount(target string) error {
|
|
|
|
return fuseUnmount(target, s3qlCmdMount)
|
2018-07-16 20:27:45 +00:00
|
|
|
}
|
|
|
|
|
2018-07-21 11:35:31 +00:00
|
|
|
func (s3ql *s3qlMounter) writeConfig() error {
|
2018-07-16 20:27:45 +00:00
|
|
|
s3qlIni := ini.Empty()
|
|
|
|
section, err := s3qlIni.NewSection("s3ql")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-07-21 11:35:31 +00:00
|
|
|
section.NewKey("storage-url", s3ql.url)
|
|
|
|
section.NewKey("backend-login", s3ql.login)
|
|
|
|
section.NewKey("backend-password", s3ql.password)
|
|
|
|
section.NewKey("fs-passphrase", s3ql.passphrase)
|
2018-07-16 20:27:45 +00:00
|
|
|
|
|
|
|
authDir := os.Getenv("HOME") + "/.s3ql"
|
|
|
|
authFile := authDir + "/authinfo2"
|
|
|
|
os.Mkdir(authDir, 0700)
|
|
|
|
s3qlIni.SaveTo(authFile)
|
|
|
|
os.Chmod(authFile, 0600)
|
|
|
|
return nil
|
|
|
|
}
|