2019-01-24 20:15:10 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
2018-12-07 19:26:39 +00:00
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
2018-12-11 08:46:52 +00:00
|
|
|
package miniogw_test
|
2018-12-07 19:26:39 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2018-12-11 08:46:52 +00:00
|
|
|
"errors"
|
2018-12-07 19:26:39 +00:00
|
|
|
"flag"
|
2019-05-22 14:57:12 +01:00
|
|
|
"io/ioutil"
|
|
|
|
"math/rand"
|
2018-12-07 19:26:39 +00:00
|
|
|
"os"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/minio/cli"
|
|
|
|
minio "github.com/minio/minio/cmd"
|
2019-01-14 21:19:15 +00:00
|
|
|
"github.com/spf13/pflag"
|
2018-12-07 19:26:39 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
2019-05-22 14:57:12 +01:00
|
|
|
"github.com/stretchr/testify/require"
|
2018-12-07 19:26:39 +00:00
|
|
|
"go.uber.org/zap"
|
|
|
|
"go.uber.org/zap/zaptest"
|
|
|
|
|
|
|
|
"storj.io/storj/internal/s3client"
|
|
|
|
"storj.io/storj/internal/testcontext"
|
2019-01-02 17:39:17 +00:00
|
|
|
"storj.io/storj/internal/testidentity"
|
2018-12-07 19:26:39 +00:00
|
|
|
"storj.io/storj/internal/testplanet"
|
2019-04-15 21:13:02 +01:00
|
|
|
libuplink "storj.io/storj/lib/uplink"
|
2018-12-07 19:26:39 +00:00
|
|
|
"storj.io/storj/pkg/cfgstruct"
|
2019-01-30 20:47:21 +00:00
|
|
|
"storj.io/storj/pkg/identity"
|
2019-05-24 17:51:27 +01:00
|
|
|
"storj.io/storj/pkg/macaroon"
|
2018-12-11 08:46:52 +00:00
|
|
|
"storj.io/storj/pkg/miniogw"
|
2019-02-08 12:57:35 +00:00
|
|
|
"storj.io/storj/pkg/storj"
|
2019-02-05 17:22:17 +00:00
|
|
|
"storj.io/storj/satellite/console"
|
2019-02-08 12:57:35 +00:00
|
|
|
"storj.io/storj/uplink"
|
2018-12-07 19:26:39 +00:00
|
|
|
)
|
|
|
|
|
2019-02-08 12:57:35 +00:00
|
|
|
type config struct {
|
|
|
|
Server miniogw.ServerConfig
|
|
|
|
Minio miniogw.MinioConfig
|
|
|
|
}
|
|
|
|
|
2018-12-07 19:26:39 +00:00
|
|
|
func TestUploadDownload(t *testing.T) {
|
2019-04-30 19:18:32 +01:00
|
|
|
t.Skip("disable because, keeps stalling CI intermittently")
|
2018-12-11 14:52:03 +00:00
|
|
|
|
2018-12-07 19:26:39 +00:00
|
|
|
ctx := testcontext.New(t)
|
|
|
|
defer ctx.Cleanup()
|
|
|
|
|
|
|
|
planet, err := testplanet.New(t, 1, 30, 0)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
defer ctx.Check(planet.Shutdown)
|
|
|
|
|
2019-02-05 17:22:17 +00:00
|
|
|
// add project to satisfy constraint
|
|
|
|
project, err := planet.Satellites[0].DB.Console().Projects().Insert(context.Background(), &console.Project{
|
|
|
|
Name: "testProject",
|
|
|
|
})
|
2019-05-24 17:51:27 +01:00
|
|
|
assert.NoError(t, err)
|
2019-02-05 17:22:17 +00:00
|
|
|
|
2019-05-24 17:51:27 +01:00
|
|
|
apiKey, err := macaroon.NewAPIKey([]byte("testSecret"))
|
2019-02-05 17:22:17 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
apiKeyInfo := console.APIKeyInfo{
|
|
|
|
ProjectID: project.ID,
|
|
|
|
Name: "testKey",
|
2019-05-24 17:51:27 +01:00
|
|
|
Secret: []byte("testSecret"),
|
2019-02-05 17:22:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// add api key to db
|
2019-05-24 17:51:27 +01:00
|
|
|
_, err = planet.Satellites[0].DB.Console().APIKeys().Create(context.Background(), apiKey.Head(), apiKeyInfo)
|
2019-02-05 17:22:17 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 19:26:39 +00:00
|
|
|
// bind default values to config
|
2019-02-08 12:57:35 +00:00
|
|
|
var gwCfg config
|
2019-04-19 19:17:30 +01:00
|
|
|
cfgstruct.Bind(&pflag.FlagSet{}, &gwCfg, cfgstruct.UseDevDefaults())
|
2019-02-08 12:57:35 +00:00
|
|
|
var uplinkCfg uplink.Config
|
2019-04-19 19:17:30 +01:00
|
|
|
cfgstruct.Bind(&pflag.FlagSet{}, &uplinkCfg, cfgstruct.UseDevDefaults())
|
2018-12-07 19:26:39 +00:00
|
|
|
|
|
|
|
// minio config directory
|
|
|
|
gwCfg.Minio.Dir = ctx.Dir("minio")
|
|
|
|
|
|
|
|
// addresses
|
2019-01-02 10:23:25 +00:00
|
|
|
gwCfg.Server.Address = "127.0.0.1:7777"
|
2019-03-22 09:01:49 +00:00
|
|
|
uplinkCfg.Client.SatelliteAddr = planet.Satellites[0].Addr()
|
2018-12-07 19:26:39 +00:00
|
|
|
|
|
|
|
// keys
|
2019-02-08 12:57:35 +00:00
|
|
|
uplinkCfg.Client.APIKey = "apiKey"
|
2019-05-22 14:57:12 +01:00
|
|
|
|
|
|
|
// Encryption key
|
|
|
|
passphrase := make([]byte, rand.Intn(100)+1)
|
|
|
|
_, err = rand.Read(passphrase)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
encryptionKey, err := storj.NewKey(passphrase)
|
|
|
|
require.NoError(t, err)
|
|
|
|
filename := ctx.File("encryption.key")
|
|
|
|
err = ioutil.WriteFile(filename, encryptionKey[:], os.FileMode(0400))
|
|
|
|
require.NoError(t, err)
|
|
|
|
uplinkCfg.Enc.KeyFilepath = filename
|
2018-12-07 19:26:39 +00:00
|
|
|
|
|
|
|
// redundancy
|
2019-02-08 12:57:35 +00:00
|
|
|
uplinkCfg.RS.MinThreshold = 7
|
|
|
|
uplinkCfg.RS.RepairThreshold = 8
|
|
|
|
uplinkCfg.RS.SuccessThreshold = 9
|
|
|
|
uplinkCfg.RS.MaxThreshold = 10
|
2018-12-07 19:26:39 +00:00
|
|
|
|
|
|
|
planet.Start(ctx)
|
|
|
|
|
|
|
|
// create identity for gateway
|
|
|
|
ca, err := testidentity.NewTestCA(ctx)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
identity, err := ca.NewIdentity()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// setup and start gateway
|
|
|
|
go func() {
|
|
|
|
// TODO: this leaks the gateway server, however it shouldn't
|
2019-02-08 12:57:35 +00:00
|
|
|
err := runGateway(ctx, gwCfg, uplinkCfg, zaptest.NewLogger(t), identity)
|
2018-12-07 19:26:39 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Log(err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
|
|
|
|
client, err := s3client.NewMinio(s3client.Config{
|
2019-01-02 10:23:25 +00:00
|
|
|
S3Gateway: gwCfg.Server.Address,
|
2018-12-07 19:26:39 +00:00
|
|
|
Satellite: planet.Satellites[0].Addr(),
|
|
|
|
AccessKey: gwCfg.Minio.AccessKey,
|
|
|
|
SecretKey: gwCfg.Minio.SecretKey,
|
2019-02-08 12:57:35 +00:00
|
|
|
APIKey: uplinkCfg.Client.APIKey,
|
2019-05-22 14:57:12 +01:00
|
|
|
EncryptionKey: string(encryptionKey[:]),
|
2018-12-07 19:26:39 +00:00
|
|
|
NoSSL: true,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
bucket := "bucket"
|
|
|
|
|
|
|
|
err = client.MakeBucket(bucket, "")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// generate enough data for a remote segment
|
|
|
|
data := []byte{}
|
|
|
|
for i := 0; i < 5000; i++ {
|
|
|
|
data = append(data, 'a')
|
|
|
|
}
|
|
|
|
|
|
|
|
objectName := "testdata"
|
|
|
|
|
|
|
|
err = client.Upload(bucket, objectName, data)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
buffer := make([]byte, len(data))
|
|
|
|
|
|
|
|
bytes, err := client.Download(bucket, objectName, buffer)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
assert.Equal(t, string(data), string(bytes))
|
|
|
|
}
|
|
|
|
|
|
|
|
// runGateway creates and starts a gateway
|
2019-04-15 21:13:02 +01:00
|
|
|
func runGateway(ctx context.Context, gwCfg config, uplinkCfg uplink.Config, log *zap.Logger, ident *identity.FullIdentity) (err error) {
|
2018-12-07 19:26:39 +00:00
|
|
|
|
|
|
|
// set gateway flags
|
|
|
|
flags := flag.NewFlagSet("gateway", flag.ExitOnError)
|
2019-02-08 12:57:35 +00:00
|
|
|
flags.String("address", gwCfg.Server.Address, "")
|
|
|
|
flags.String("config-dir", gwCfg.Minio.Dir, "")
|
2018-12-07 19:26:39 +00:00
|
|
|
flags.Bool("quiet", true, "")
|
|
|
|
|
|
|
|
// create *cli.Context with gateway flags
|
|
|
|
cliCtx := cli.NewContext(cli.NewApp(), flags, nil)
|
|
|
|
|
|
|
|
// TODO: setting the flag on flagset and cliCtx seems redundant, but output is not quiet otherwise
|
|
|
|
err = cliCtx.Set("quiet", "true")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-02-08 12:57:35 +00:00
|
|
|
err = os.Setenv("MINIO_ACCESS_KEY", gwCfg.Minio.AccessKey)
|
2018-12-07 19:26:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-02-08 12:57:35 +00:00
|
|
|
err = os.Setenv("MINIO_SECRET_KEY", gwCfg.Minio.SecretKey)
|
2018-12-07 19:26:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-04-15 21:13:02 +01:00
|
|
|
cfg := libuplink.Config{}
|
|
|
|
cfg.Volatile.TLS = struct {
|
|
|
|
SkipPeerCAWhitelist bool
|
|
|
|
PeerCAWhitelistPath string
|
|
|
|
}{
|
|
|
|
SkipPeerCAWhitelist: !uplinkCfg.TLS.UsePeerCAWhitelist,
|
|
|
|
PeerCAWhitelistPath: uplinkCfg.TLS.PeerCAWhitelistPath,
|
|
|
|
}
|
|
|
|
cfg.Volatile.MaxInlineSize = uplinkCfg.Client.MaxInlineSize
|
|
|
|
cfg.Volatile.MaxMemory = uplinkCfg.RS.MaxBufferMem
|
|
|
|
|
|
|
|
uplink, err := libuplink.NewUplink(ctx, &cfg)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
apiKey, err := libuplink.ParseAPIKey(uplinkCfg.Client.APIKey)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-06-24 03:06:14 +01:00
|
|
|
project, err := uplink.OpenProject(ctx, uplinkCfg.Client.SatelliteAddr, apiKey)
|
2018-12-07 19:26:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-02-08 12:57:35 +00:00
|
|
|
gw := miniogw.NewStorjGateway(
|
2019-04-15 21:13:02 +01:00
|
|
|
project,
|
2019-06-24 03:06:14 +01:00
|
|
|
&storj.Key{},
|
2019-04-15 21:13:02 +01:00
|
|
|
storj.Cipher(uplinkCfg.Enc.PathType).ToCipherSuite(),
|
|
|
|
uplinkCfg.GetEncryptionScheme().ToEncryptionParameters(),
|
2019-02-08 12:57:35 +00:00
|
|
|
uplinkCfg.GetRedundancyScheme(),
|
2019-04-15 21:13:02 +01:00
|
|
|
uplinkCfg.Client.SegmentSize,
|
2019-02-08 12:57:35 +00:00
|
|
|
)
|
|
|
|
|
2018-12-11 08:46:52 +00:00
|
|
|
minio.StartGateway(cliCtx, miniogw.Logging(gw, log))
|
|
|
|
return errors.New("unexpected minio exit")
|
2018-12-07 19:26:39 +00:00
|
|
|
}
|