2019-01-24 20:15:10 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
2018-11-06 13:19:43 +00:00
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
2018-12-03 19:50:05 +00:00
|
|
|
package s3client
|
2018-11-06 13:19:43 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2019-05-24 21:25:53 +01:00
|
|
|
"fmt"
|
2018-11-06 13:19:43 +00:00
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/zeebo/errs"
|
2019-05-24 21:25:53 +01:00
|
|
|
|
2019-11-14 19:46:15 +00:00
|
|
|
"storj.io/storj/private/fpath"
|
2018-11-06 13:19:43 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// UplinkError is class for minio errors
|
|
|
|
var UplinkError = errs.Class("uplink error")
|
|
|
|
|
|
|
|
// Uplink implements basic S3 Client with uplink
|
|
|
|
type Uplink struct {
|
|
|
|
conf Config
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewUplink creates new Client
|
|
|
|
func NewUplink(conf Config) (Client, error) {
|
|
|
|
client := &Uplink{conf}
|
|
|
|
|
2019-05-28 19:46:58 +01:00
|
|
|
if client.conf.ConfigDir != "" {
|
|
|
|
fmt.Printf("Using existing uplink config at %s\n", client.conf.ConfigDir)
|
|
|
|
return client, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
client.conf.ConfigDir = fpath.ApplicationDir("storj", "s3-client", "uplink")
|
|
|
|
|
|
|
|
// remove existing s3client uplink config so that
|
|
|
|
// we can create a new one with up-to-date settings
|
|
|
|
err := os.RemoveAll(client.conf.ConfigDir)
|
2018-11-06 13:19:43 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, UplinkError.Wrap(fullExitError(err))
|
|
|
|
}
|
2019-05-28 19:46:58 +01:00
|
|
|
|
|
|
|
cmd := client.cmd("--config-dir", client.conf.ConfigDir,
|
|
|
|
"setup",
|
|
|
|
"--non-interactive", "true",
|
|
|
|
"--api-key", client.conf.APIKey,
|
|
|
|
"--enc.encryption-key", client.conf.EncryptionKey,
|
|
|
|
"--satellite-addr", client.conf.Satellite,
|
|
|
|
)
|
|
|
|
|
|
|
|
_, err = cmd.Output()
|
|
|
|
if err != nil {
|
|
|
|
return nil, UplinkError.Wrap(fullExitError(err))
|
2019-05-24 21:25:53 +01:00
|
|
|
}
|
2018-11-06 13:19:43 +00:00
|
|
|
|
|
|
|
return client, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (client *Uplink) cmd(subargs ...string) *exec.Cmd {
|
|
|
|
args := []string{}
|
|
|
|
|
2019-05-28 19:46:58 +01:00
|
|
|
configArgs := []string{"--config-dir", client.conf.ConfigDir}
|
|
|
|
args = append(args, configArgs...)
|
2018-11-06 13:19:43 +00:00
|
|
|
args = append(args, subargs...)
|
|
|
|
|
|
|
|
cmd := exec.Command("uplink", args...)
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
|
|
|
// MakeBucket makes a new bucket
|
|
|
|
func (client *Uplink) MakeBucket(bucket, location string) error {
|
|
|
|
cmd := client.cmd("mb", "s3://"+bucket)
|
|
|
|
_, err := cmd.Output()
|
|
|
|
if err != nil {
|
|
|
|
return UplinkError.Wrap(fullExitError(err))
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemoveBucket removes a bucket
|
|
|
|
func (client *Uplink) RemoveBucket(bucket string) error {
|
|
|
|
cmd := client.cmd("rb", "s3://"+bucket)
|
|
|
|
_, err := cmd.Output()
|
|
|
|
if err != nil {
|
|
|
|
return UplinkError.Wrap(fullExitError(err))
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ListBuckets lists all buckets
|
|
|
|
func (client *Uplink) ListBuckets() ([]string, error) {
|
|
|
|
cmd := client.cmd("ls")
|
|
|
|
data, err := cmd.Output()
|
|
|
|
if err != nil {
|
|
|
|
return nil, UplinkError.Wrap(fullExitError(err))
|
|
|
|
}
|
|
|
|
|
|
|
|
names := strings.Split(strings.TrimRight(string(data), "\n"), "\n")
|
|
|
|
return names, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Upload uploads object data to the specified path
|
|
|
|
func (client *Uplink) Upload(bucket, objectName string, data []byte) error {
|
|
|
|
// TODO: add upload threshold
|
|
|
|
cmd := client.cmd("put", "s3://"+bucket+"/"+objectName)
|
|
|
|
cmd.Stdin = bytes.NewReader(data)
|
|
|
|
_, err := cmd.Output()
|
|
|
|
if err != nil {
|
|
|
|
return UplinkError.Wrap(fullExitError(err))
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Download downloads object data
|
|
|
|
func (client *Uplink) Download(bucket, objectName string, buffer []byte) ([]byte, error) {
|
|
|
|
cmd := client.cmd("cat", "s3://"+bucket+"/"+objectName)
|
2019-05-28 19:46:58 +01:00
|
|
|
out, err := cmd.Output()
|
2018-11-06 13:19:43 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, UplinkError.Wrap(fullExitError(err))
|
|
|
|
}
|
2019-05-28 19:46:58 +01:00
|
|
|
return out, nil
|
2018-11-06 13:19:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Delete deletes object
|
|
|
|
func (client *Uplink) Delete(bucket, objectName string) error {
|
|
|
|
cmd := client.cmd("rm", "s3://"+bucket+"/"+objectName)
|
|
|
|
_, err := cmd.Output()
|
|
|
|
if err != nil {
|
|
|
|
return UplinkError.Wrap(fullExitError(err))
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ListObjects lists objects
|
|
|
|
func (client *Uplink) ListObjects(bucket, prefix string) ([]string, error) {
|
|
|
|
cmd := client.cmd("ls", "s3://"+bucket+"/"+prefix)
|
|
|
|
data, err := cmd.Output()
|
|
|
|
if err != nil {
|
|
|
|
return nil, UplinkError.Wrap(fullExitError(err))
|
|
|
|
}
|
|
|
|
|
|
|
|
names := strings.Split(strings.TrimRight(string(data), "\n"), "\n")
|
|
|
|
return names, nil
|
|
|
|
}
|