mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2024-01-19 02:48:24 +00:00
commit
9a4dda3011
|
@ -139,6 +139,7 @@ message AssignVolumeResponse {
|
||||||
string url = 2;
|
string url = 2;
|
||||||
string public_url = 3;
|
string public_url = 3;
|
||||||
int32 count = 4;
|
int32 count = 4;
|
||||||
|
string auth = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LookupVolumeRequest {
|
message LookupVolumeRequest {
|
||||||
|
|
|
@ -4,6 +4,9 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/server"
|
||||||
|
"github.com/spf13/viper"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
||||||
|
@ -19,8 +22,11 @@ var (
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
weed_server.LoadConfiguration("security", false)
|
||||||
|
grpcDialOption := security.LoadClientTLS(viper.Sub("grpc"), "client")
|
||||||
|
|
||||||
for i := 0; i < *repeat; i++ {
|
for i := 0; i < *repeat; i++ {
|
||||||
assignResult, err := operation.Assign(*master, &operation.VolumeAssignRequest{Count: 1})
|
assignResult, err := operation.Assign(*master, grpcDialOption, &operation.VolumeAssignRequest{Count: 1})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("assign: %v", err)
|
log.Fatalf("assign: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -31,12 +37,12 @@ func main() {
|
||||||
|
|
||||||
targetUrl := fmt.Sprintf("http://%s/%s", assignResult.Url, assignResult.Fid)
|
targetUrl := fmt.Sprintf("http://%s/%s", assignResult.Url, assignResult.Fid)
|
||||||
|
|
||||||
_, err = operation.Upload(targetUrl, fmt.Sprintf("test%d", i), reader, false, "", nil, "")
|
_, err = operation.Upload(targetUrl, fmt.Sprintf("test%d", i), reader, false, "", nil, assignResult.Auth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("upload: %v", err)
|
log.Fatalf("upload: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
util.Delete(targetUrl, "")
|
util.Delete(targetUrl, string(assignResult.Auth))
|
||||||
|
|
||||||
util.Get(fmt.Sprintf("http://%s/vol/vacuum", *master))
|
util.Get(fmt.Sprintf("http://%s/vol/vacuum", *master))
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,9 @@ package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/server"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/operation"
|
"github.com/chrislusf/seaweedfs/weed/operation"
|
||||||
"github.com/chrislusf/seaweedfs/weed/storage"
|
"github.com/chrislusf/seaweedfs/weed/storage"
|
||||||
|
@ -46,6 +49,10 @@ var cmdBackup = &Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
func runBackup(cmd *Command, args []string) bool {
|
func runBackup(cmd *Command, args []string) bool {
|
||||||
|
|
||||||
|
weed_server.LoadConfiguration("security", false)
|
||||||
|
grpcDialOption := security.LoadClientTLS(viper.Sub("grpc"), "client")
|
||||||
|
|
||||||
if *s.volumeId == -1 {
|
if *s.volumeId == -1 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -59,7 +66,7 @@ func runBackup(cmd *Command, args []string) bool {
|
||||||
}
|
}
|
||||||
volumeServer := lookup.Locations[0].Url
|
volumeServer := lookup.Locations[0].Url
|
||||||
|
|
||||||
stats, err := operation.GetVolumeSyncStatus(volumeServer, uint32(vid))
|
stats, err := operation.GetVolumeSyncStatus(volumeServer, grpcDialOption, uint32(vid))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error get volume %d status: %v\n", vid, err)
|
fmt.Printf("Error get volume %d status: %v\n", vid, err)
|
||||||
return true
|
return true
|
||||||
|
@ -81,7 +88,7 @@ func runBackup(cmd *Command, args []string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := v.Synchronize(volumeServer); err != nil {
|
if err := v.Synchronize(volumeServer, grpcDialOption); err != nil {
|
||||||
fmt.Printf("Error synchronizing volume %d: %v\n", vid, err)
|
fmt.Printf("Error synchronizing volume %d: %v\n", vid, err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,9 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/server"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
@ -35,13 +38,14 @@ type BenchmarkOptions struct {
|
||||||
collection *string
|
collection *string
|
||||||
cpuprofile *string
|
cpuprofile *string
|
||||||
maxCpu *int
|
maxCpu *int
|
||||||
secretKey *string
|
grpcDialOption grpc.DialOption
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
b BenchmarkOptions
|
b BenchmarkOptions
|
||||||
sharedBytes []byte
|
sharedBytes []byte
|
||||||
masterClient *wdclient.MasterClient
|
masterClient *wdclient.MasterClient
|
||||||
|
isSecure bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -59,7 +63,6 @@ func init() {
|
||||||
b.collection = cmdBenchmark.Flag.String("collection", "benchmark", "write data to this collection")
|
b.collection = cmdBenchmark.Flag.String("collection", "benchmark", "write data to this collection")
|
||||||
b.cpuprofile = cmdBenchmark.Flag.String("cpuprofile", "", "cpu profile output file")
|
b.cpuprofile = cmdBenchmark.Flag.String("cpuprofile", "", "cpu profile output file")
|
||||||
b.maxCpu = cmdBenchmark.Flag.Int("maxCpu", 0, "maximum number of CPUs. 0 means all available CPUs")
|
b.maxCpu = cmdBenchmark.Flag.Int("maxCpu", 0, "maximum number of CPUs. 0 means all available CPUs")
|
||||||
b.secretKey = cmdBenchmark.Flag.String("secure.secret", "", "secret to encrypt Json Web Token(JWT)")
|
|
||||||
sharedBytes = make([]byte, 1024)
|
sharedBytes = make([]byte, 1024)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +105,10 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func runBenchmark(cmd *Command, args []string) bool {
|
func runBenchmark(cmd *Command, args []string) bool {
|
||||||
|
|
||||||
|
weed_server.LoadConfiguration("security", false)
|
||||||
|
b.grpcDialOption = security.LoadClientTLS(viper.Sub("grpc"), "client")
|
||||||
|
|
||||||
fmt.Printf("This is SeaweedFS version %s %s %s\n", util.VERSION, runtime.GOOS, runtime.GOARCH)
|
fmt.Printf("This is SeaweedFS version %s %s %s\n", util.VERSION, runtime.GOOS, runtime.GOARCH)
|
||||||
if *b.maxCpu < 1 {
|
if *b.maxCpu < 1 {
|
||||||
*b.maxCpu = runtime.NumCPU()
|
*b.maxCpu = runtime.NumCPU()
|
||||||
|
@ -116,7 +123,7 @@ func runBenchmark(cmd *Command, args []string) bool {
|
||||||
defer pprof.StopCPUProfile()
|
defer pprof.StopCPUProfile()
|
||||||
}
|
}
|
||||||
|
|
||||||
masterClient = wdclient.NewMasterClient(context.Background(), "benchmark", strings.Split(*b.masters, ","))
|
masterClient = wdclient.NewMasterClient(context.Background(), b.grpcDialOption, "client", strings.Split(*b.masters, ","))
|
||||||
go masterClient.KeepConnectedToMaster()
|
go masterClient.KeepConnectedToMaster()
|
||||||
masterClient.WaitUntilConnected()
|
masterClient.WaitUntilConnected()
|
||||||
|
|
||||||
|
@ -188,7 +195,6 @@ func writeFiles(idChan chan int, fileIdLineChan chan string, s *stat) {
|
||||||
defer wait.Done()
|
defer wait.Done()
|
||||||
delayedDeleteChan := make(chan *delayedFile, 100)
|
delayedDeleteChan := make(chan *delayedFile, 100)
|
||||||
var waitForDeletions sync.WaitGroup
|
var waitForDeletions sync.WaitGroup
|
||||||
secret := security.Secret(*b.secretKey)
|
|
||||||
|
|
||||||
for i := 0; i < 7; i++ {
|
for i := 0; i < 7; i++ {
|
||||||
waitForDeletions.Add(1)
|
waitForDeletions.Add(1)
|
||||||
|
@ -198,8 +204,11 @@ func writeFiles(idChan chan int, fileIdLineChan chan string, s *stat) {
|
||||||
if df.enterTime.After(time.Now()) {
|
if df.enterTime.After(time.Now()) {
|
||||||
time.Sleep(df.enterTime.Sub(time.Now()))
|
time.Sleep(df.enterTime.Sub(time.Now()))
|
||||||
}
|
}
|
||||||
if e := util.Delete("http://"+df.fp.Server+"/"+df.fp.Fid,
|
var jwtAuthorization security.EncodedJwt
|
||||||
security.GenJwt(secret, df.fp.Fid)); e == nil {
|
if isSecure {
|
||||||
|
jwtAuthorization = operation.LookupJwt(masterClient.GetMaster(), df.fp.Fid)
|
||||||
|
}
|
||||||
|
if e := util.Delete(fmt.Sprintf("http://%s/%s", df.fp.Server, df.fp.Fid), string(jwtAuthorization)); e == nil {
|
||||||
s.completed++
|
s.completed++
|
||||||
} else {
|
} else {
|
||||||
s.failed++
|
s.failed++
|
||||||
|
@ -222,9 +231,12 @@ func writeFiles(idChan chan int, fileIdLineChan chan string, s *stat) {
|
||||||
Count: 1,
|
Count: 1,
|
||||||
Collection: *b.collection,
|
Collection: *b.collection,
|
||||||
}
|
}
|
||||||
if assignResult, err := operation.Assign(masterClient.GetMaster(), ar); err == nil {
|
if assignResult, err := operation.Assign(masterClient.GetMaster(), b.grpcDialOption, ar); err == nil {
|
||||||
fp.Server, fp.Fid, fp.Collection = assignResult.Url, assignResult.Fid, *b.collection
|
fp.Server, fp.Fid, fp.Collection = assignResult.Url, assignResult.Fid, *b.collection
|
||||||
if _, err := fp.Upload(0, masterClient.GetMaster(), secret); err == nil {
|
if !isSecure && assignResult.Auth != "" {
|
||||||
|
isSecure = true
|
||||||
|
}
|
||||||
|
if _, err := fp.Upload(0, masterClient.GetMaster(), assignResult.Auth, b.grpcDialOption); err == nil {
|
||||||
if random.Intn(100) < *b.deletePercentage {
|
if random.Intn(100) < *b.deletePercentage {
|
||||||
s.total++
|
s.total++
|
||||||
delayedDeleteChan <- &delayedFile{time.Now().Add(time.Second), fp}
|
delayedDeleteChan <- &delayedFile{time.Now().Add(time.Second), fp}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
|
"github.com/spf13/viper"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -28,7 +30,6 @@ type FilerOptions struct {
|
||||||
redirectOnRead *bool
|
redirectOnRead *bool
|
||||||
disableDirListing *bool
|
disableDirListing *bool
|
||||||
maxMB *int
|
maxMB *int
|
||||||
secretKey *string
|
|
||||||
dirListingLimit *int
|
dirListingLimit *int
|
||||||
dataCenter *string
|
dataCenter *string
|
||||||
enableNotification *bool
|
enableNotification *bool
|
||||||
|
@ -49,7 +50,6 @@ func init() {
|
||||||
f.redirectOnRead = cmdFiler.Flag.Bool("redirectOnRead", false, "whether proxy or redirect to volume server during file GET request")
|
f.redirectOnRead = cmdFiler.Flag.Bool("redirectOnRead", false, "whether proxy or redirect to volume server during file GET request")
|
||||||
f.disableDirListing = cmdFiler.Flag.Bool("disableDirListing", false, "turn off directory listing")
|
f.disableDirListing = cmdFiler.Flag.Bool("disableDirListing", false, "turn off directory listing")
|
||||||
f.maxMB = cmdFiler.Flag.Int("maxMB", 32, "split files larger than the limit")
|
f.maxMB = cmdFiler.Flag.Int("maxMB", 32, "split files larger than the limit")
|
||||||
f.secretKey = cmdFiler.Flag.String("secure.secret", "", "secret to encrypt Json Web Token(JWT)")
|
|
||||||
f.dirListingLimit = cmdFiler.Flag.Int("dirListLimit", 100000, "limit sub dir listing size")
|
f.dirListingLimit = cmdFiler.Flag.Int("dirListLimit", 100000, "limit sub dir listing size")
|
||||||
f.dataCenter = cmdFiler.Flag.String("dataCenter", "", "prefer to write to volumes in this data center")
|
f.dataCenter = cmdFiler.Flag.String("dataCenter", "", "prefer to write to volumes in this data center")
|
||||||
}
|
}
|
||||||
|
@ -70,13 +70,15 @@ var cmdFiler = &Command{
|
||||||
|
|
||||||
The configuration file "filer.toml" is read from ".", "$HOME/.seaweedfs/", or "/etc/seaweedfs/", in that order.
|
The configuration file "filer.toml" is read from ".", "$HOME/.seaweedfs/", or "/etc/seaweedfs/", in that order.
|
||||||
|
|
||||||
The example filer.toml configuration file can be generated by "weed scaffold filer"
|
The example filer.toml configuration file can be generated by "weed scaffold -config=filer"
|
||||||
|
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
func runFiler(cmd *Command, args []string) bool {
|
func runFiler(cmd *Command, args []string) bool {
|
||||||
|
|
||||||
|
weed_server.LoadConfiguration("security", false)
|
||||||
|
|
||||||
f.startFiler()
|
f.startFiler()
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@ -103,7 +105,6 @@ func (fo *FilerOptions) startFiler() {
|
||||||
RedirectOnRead: *fo.redirectOnRead,
|
RedirectOnRead: *fo.redirectOnRead,
|
||||||
DisableDirListing: *fo.disableDirListing,
|
DisableDirListing: *fo.disableDirListing,
|
||||||
MaxMB: *fo.maxMB,
|
MaxMB: *fo.maxMB,
|
||||||
SecretKey: *fo.secretKey,
|
|
||||||
DirListingLimit: *fo.dirListingLimit,
|
DirListingLimit: *fo.dirListingLimit,
|
||||||
DataCenter: *fo.dataCenter,
|
DataCenter: *fo.dataCenter,
|
||||||
DefaultLevelDbDir: defaultLevelDbDirectory,
|
DefaultLevelDbDir: defaultLevelDbDirectory,
|
||||||
|
@ -144,7 +145,7 @@ func (fo *FilerOptions) startFiler() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("failed to listen on grpc port %d: %v", grpcPort, err)
|
glog.Fatalf("failed to listen on grpc port %d: %v", grpcPort, err)
|
||||||
}
|
}
|
||||||
grpcS := util.NewGrpcServer()
|
grpcS := util.NewGrpcServer(security.LoadServerTLS(viper.Sub("grpc"), "filer"))
|
||||||
filer_pb.RegisterSeaweedFilerServer(grpcS, fs)
|
filer_pb.RegisterSeaweedFilerServer(grpcS, fs)
|
||||||
reflection.Register(grpcS)
|
reflection.Register(grpcS)
|
||||||
go grpcS.Serve(grpcL)
|
go grpcS.Serve(grpcL)
|
||||||
|
|
|
@ -2,6 +2,10 @@ package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/server"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
@ -11,7 +15,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/chrislusf/seaweedfs/weed/operation"
|
"github.com/chrislusf/seaweedfs/weed/operation"
|
||||||
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
||||||
"github.com/chrislusf/seaweedfs/weed/security"
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/util"
|
"github.com/chrislusf/seaweedfs/weed/util"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -31,9 +34,7 @@ type CopyOptions struct {
|
||||||
collection *string
|
collection *string
|
||||||
ttl *string
|
ttl *string
|
||||||
maxMB *int
|
maxMB *int
|
||||||
secretKey *string
|
grpcDialOption grpc.DialOption
|
||||||
|
|
||||||
secret security.Secret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -46,7 +47,6 @@ func init() {
|
||||||
copy.ttl = cmdCopy.Flag.String("ttl", "", "time to live, e.g.: 1m, 1h, 1d, 1M, 1y")
|
copy.ttl = cmdCopy.Flag.String("ttl", "", "time to live, e.g.: 1m, 1h, 1d, 1M, 1y")
|
||||||
copy.maxMB = cmdCopy.Flag.Int("maxMB", 0, "split files larger than the limit")
|
copy.maxMB = cmdCopy.Flag.Int("maxMB", 0, "split files larger than the limit")
|
||||||
copy.filerGrpcPort = cmdCopy.Flag.Int("filer.port.grpc", 0, "filer grpc server listen port, default to filer port + 10000")
|
copy.filerGrpcPort = cmdCopy.Flag.Int("filer.port.grpc", 0, "filer grpc server listen port, default to filer port + 10000")
|
||||||
copy.secretKey = cmdCopy.Flag.String("secure.secret", "", "secret to encrypt Json Web Token(JWT)")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmdCopy = &Command{
|
var cmdCopy = &Command{
|
||||||
|
@ -66,7 +66,9 @@ var cmdCopy = &Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCopy(cmd *Command, args []string) bool {
|
func runCopy(cmd *Command, args []string) bool {
|
||||||
copy.secret = security.Secret(*copy.secretKey)
|
|
||||||
|
weed_server.LoadConfiguration("security", false)
|
||||||
|
|
||||||
if len(args) <= 1 {
|
if len(args) <= 1 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -101,16 +103,17 @@ func runCopy(cmd *Command, args []string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
filerGrpcAddress := fmt.Sprintf("%s:%d", filerUrl.Hostname(), filerGrpcPort)
|
filerGrpcAddress := fmt.Sprintf("%s:%d", filerUrl.Hostname(), filerGrpcPort)
|
||||||
|
copy.grpcDialOption = security.LoadClientTLS(viper.Sub("grpc"), "client")
|
||||||
|
|
||||||
for _, fileOrDir := range fileOrDirs {
|
for _, fileOrDir := range fileOrDirs {
|
||||||
if !doEachCopy(fileOrDir, filerUrl.Host, filerGrpcAddress, urlPath) {
|
if !doEachCopy(fileOrDir, filerUrl.Host, filerGrpcAddress, copy.grpcDialOption, urlPath) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func doEachCopy(fileOrDir string, filerAddress, filerGrpcAddress string, path string) bool {
|
func doEachCopy(fileOrDir string, filerAddress, filerGrpcAddress string, grpcDialOption grpc.DialOption, path string) bool {
|
||||||
f, err := os.Open(fileOrDir)
|
f, err := os.Open(fileOrDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Failed to open file %s: %v\n", fileOrDir, err)
|
fmt.Printf("Failed to open file %s: %v\n", fileOrDir, err)
|
||||||
|
@ -128,7 +131,7 @@ func doEachCopy(fileOrDir string, filerAddress, filerGrpcAddress string, path st
|
||||||
if mode.IsDir() {
|
if mode.IsDir() {
|
||||||
files, _ := ioutil.ReadDir(fileOrDir)
|
files, _ := ioutil.ReadDir(fileOrDir)
|
||||||
for _, subFileOrDir := range files {
|
for _, subFileOrDir := range files {
|
||||||
if !doEachCopy(fileOrDir+"/"+subFileOrDir.Name(), filerAddress, filerGrpcAddress, path+fi.Name()+"/") {
|
if !doEachCopy(fileOrDir+"/"+subFileOrDir.Name(), filerAddress, filerGrpcAddress, grpcDialOption, path+fi.Name()+"/") {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,13 +153,13 @@ func doEachCopy(fileOrDir string, filerAddress, filerGrpcAddress string, path st
|
||||||
}
|
}
|
||||||
|
|
||||||
if chunkCount == 1 {
|
if chunkCount == 1 {
|
||||||
return uploadFileAsOne(filerAddress, filerGrpcAddress, path, f, fi)
|
return uploadFileAsOne(filerAddress, filerGrpcAddress, grpcDialOption, path, f, fi)
|
||||||
}
|
}
|
||||||
|
|
||||||
return uploadFileInChunks(filerAddress, filerGrpcAddress, path, f, fi, chunkCount, chunkSize)
|
return uploadFileInChunks(filerAddress, filerGrpcAddress, grpcDialOption, path, f, fi, chunkCount, chunkSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
func uploadFileAsOne(filerAddress, filerGrpcAddress string, urlFolder string, f *os.File, fi os.FileInfo) bool {
|
func uploadFileAsOne(filerAddress, filerGrpcAddress string, grpcDialOption grpc.DialOption, urlFolder string, f *os.File, fi os.FileInfo) bool {
|
||||||
|
|
||||||
// upload the file content
|
// upload the file content
|
||||||
fileName := filepath.Base(f.Name())
|
fileName := filepath.Base(f.Name())
|
||||||
|
@ -167,7 +170,7 @@ func uploadFileAsOne(filerAddress, filerGrpcAddress string, urlFolder string, f
|
||||||
if fi.Size() > 0 {
|
if fi.Size() > 0 {
|
||||||
|
|
||||||
// assign a volume
|
// assign a volume
|
||||||
assignResult, err := operation.Assign(*copy.master, &operation.VolumeAssignRequest{
|
assignResult, err := operation.Assign(*copy.master, grpcDialOption, &operation.VolumeAssignRequest{
|
||||||
Count: 1,
|
Count: 1,
|
||||||
Replication: *copy.replication,
|
Replication: *copy.replication,
|
||||||
Collection: *copy.collection,
|
Collection: *copy.collection,
|
||||||
|
@ -179,7 +182,7 @@ func uploadFileAsOne(filerAddress, filerGrpcAddress string, urlFolder string, f
|
||||||
|
|
||||||
targetUrl := "http://" + assignResult.Url + "/" + assignResult.Fid
|
targetUrl := "http://" + assignResult.Url + "/" + assignResult.Fid
|
||||||
|
|
||||||
uploadResult, err := operation.Upload(targetUrl, fileName, f, false, mimeType, nil, "")
|
uploadResult, err := operation.Upload(targetUrl, fileName, f, false, mimeType, nil, assignResult.Auth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("upload data %v to %s: %v\n", fileName, targetUrl, err)
|
fmt.Printf("upload data %v to %s: %v\n", fileName, targetUrl, err)
|
||||||
return false
|
return false
|
||||||
|
@ -201,7 +204,7 @@ func uploadFileAsOne(filerAddress, filerGrpcAddress string, urlFolder string, f
|
||||||
fmt.Printf("copied %s => http://%s%s%s\n", fileName, filerAddress, urlFolder, fileName)
|
fmt.Printf("copied %s => http://%s%s%s\n", fileName, filerAddress, urlFolder, fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := withFilerClient(filerGrpcAddress, func(client filer_pb.SeaweedFilerClient) error {
|
if err := withFilerClient(filerGrpcAddress, grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
|
||||||
request := &filer_pb.CreateEntryRequest{
|
request := &filer_pb.CreateEntryRequest{
|
||||||
Directory: urlFolder,
|
Directory: urlFolder,
|
||||||
Entry: &filer_pb.Entry{
|
Entry: &filer_pb.Entry{
|
||||||
|
@ -234,7 +237,7 @@ func uploadFileAsOne(filerAddress, filerGrpcAddress string, urlFolder string, f
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func uploadFileInChunks(filerAddress, filerGrpcAddress string, urlFolder string, f *os.File, fi os.FileInfo, chunkCount int, chunkSize int64) bool {
|
func uploadFileInChunks(filerAddress, filerGrpcAddress string, grpcDialOption grpc.DialOption, urlFolder string, f *os.File, fi os.FileInfo, chunkCount int, chunkSize int64) bool {
|
||||||
|
|
||||||
fileName := filepath.Base(f.Name())
|
fileName := filepath.Base(f.Name())
|
||||||
mimeType := detectMimeType(f)
|
mimeType := detectMimeType(f)
|
||||||
|
@ -244,7 +247,7 @@ func uploadFileInChunks(filerAddress, filerGrpcAddress string, urlFolder string,
|
||||||
for i := int64(0); i < int64(chunkCount); i++ {
|
for i := int64(0); i < int64(chunkCount); i++ {
|
||||||
|
|
||||||
// assign a volume
|
// assign a volume
|
||||||
assignResult, err := operation.Assign(*copy.master, &operation.VolumeAssignRequest{
|
assignResult, err := operation.Assign(*copy.master, grpcDialOption, &operation.VolumeAssignRequest{
|
||||||
Count: 1,
|
Count: 1,
|
||||||
Replication: *copy.replication,
|
Replication: *copy.replication,
|
||||||
Collection: *copy.collection,
|
Collection: *copy.collection,
|
||||||
|
@ -259,7 +262,7 @@ func uploadFileInChunks(filerAddress, filerGrpcAddress string, urlFolder string,
|
||||||
uploadResult, err := operation.Upload(targetUrl,
|
uploadResult, err := operation.Upload(targetUrl,
|
||||||
fileName+"-"+strconv.FormatInt(i+1, 10),
|
fileName+"-"+strconv.FormatInt(i+1, 10),
|
||||||
io.LimitReader(f, chunkSize),
|
io.LimitReader(f, chunkSize),
|
||||||
false, "application/octet-stream", nil, "")
|
false, "application/octet-stream", nil, assignResult.Auth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("upload data %v to %s: %v\n", fileName, targetUrl, err)
|
fmt.Printf("upload data %v to %s: %v\n", fileName, targetUrl, err)
|
||||||
return false
|
return false
|
||||||
|
@ -278,7 +281,7 @@ func uploadFileInChunks(filerAddress, filerGrpcAddress string, urlFolder string,
|
||||||
fmt.Printf("uploaded %s-%d to %s [%d,%d)\n", fileName, i+1, targetUrl, i*chunkSize, i*chunkSize+int64(uploadResult.Size))
|
fmt.Printf("uploaded %s-%d to %s [%d,%d)\n", fileName, i+1, targetUrl, i*chunkSize, i*chunkSize+int64(uploadResult.Size))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := withFilerClient(filerGrpcAddress, func(client filer_pb.SeaweedFilerClient) error {
|
if err := withFilerClient(filerGrpcAddress, grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
|
||||||
request := &filer_pb.CreateEntryRequest{
|
request := &filer_pb.CreateEntryRequest{
|
||||||
Directory: urlFolder,
|
Directory: urlFolder,
|
||||||
Entry: &filer_pb.Entry{
|
Entry: &filer_pb.Entry{
|
||||||
|
@ -329,9 +332,9 @@ func detectMimeType(f *os.File) string {
|
||||||
return mimeType
|
return mimeType
|
||||||
}
|
}
|
||||||
|
|
||||||
func withFilerClient(filerAddress string, fn func(filer_pb.SeaweedFilerClient) error) error {
|
func withFilerClient(filerAddress string, grpcDialOption grpc.DialOption, fn func(filer_pb.SeaweedFilerClient) error) error {
|
||||||
|
|
||||||
grpcConnection, err := util.GrpcDial(filerAddress)
|
grpcConnection, err := util.GrpcDial(filerAddress, grpcDialOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("fail to dial %s: %v", filerAddress, err)
|
return fmt.Errorf("fail to dial %s: %v", filerAddress, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,13 +28,14 @@ var cmdFilerReplicate = &Command{
|
||||||
filer.replicate listens on filer notifications. If any file is updated, it will fetch the updated content,
|
filer.replicate listens on filer notifications. If any file is updated, it will fetch the updated content,
|
||||||
and write to the other destination.
|
and write to the other destination.
|
||||||
|
|
||||||
Run "weed scaffold -config replication" to generate a replication.toml file and customize the parameters.
|
Run "weed scaffold -config=replication" to generate a replication.toml file and customize the parameters.
|
||||||
|
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
func runFilerReplicate(cmd *Command, args []string) bool {
|
func runFilerReplicate(cmd *Command, args []string) bool {
|
||||||
|
|
||||||
|
weed_server.LoadConfiguration("security", false)
|
||||||
weed_server.LoadConfiguration("replication", true)
|
weed_server.LoadConfiguration("replication", true)
|
||||||
weed_server.LoadConfiguration("notification", true)
|
weed_server.LoadConfiguration("notification", true)
|
||||||
config := viper.GetViper()
|
config := viper.GetViper()
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
|
"github.com/spf13/viper"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -23,8 +25,11 @@ func init() {
|
||||||
var cmdMaster = &Command{
|
var cmdMaster = &Command{
|
||||||
UsageLine: "master -port=9333",
|
UsageLine: "master -port=9333",
|
||||||
Short: "start a master server",
|
Short: "start a master server",
|
||||||
Long: `start a master server to provide volume=>location mapping service
|
Long: `start a master server to provide volume=>location mapping service and sequence number of file ids
|
||||||
and sequence number of file ids
|
|
||||||
|
The configuration file "security.toml" is read from ".", "$HOME/.seaweedfs/", or "/etc/seaweedfs/", in that order.
|
||||||
|
|
||||||
|
The example security.toml configuration file can be generated by "weed scaffold -config=security"
|
||||||
|
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
@ -44,7 +49,6 @@ var (
|
||||||
mMaxCpu = cmdMaster.Flag.Int("maxCpu", 0, "maximum number of CPUs. 0 means all available CPUs")
|
mMaxCpu = cmdMaster.Flag.Int("maxCpu", 0, "maximum number of CPUs. 0 means all available CPUs")
|
||||||
garbageThreshold = cmdMaster.Flag.Float64("garbageThreshold", 0.3, "threshold to vacuum and reclaim spaces")
|
garbageThreshold = cmdMaster.Flag.Float64("garbageThreshold", 0.3, "threshold to vacuum and reclaim spaces")
|
||||||
masterWhiteListOption = cmdMaster.Flag.String("whiteList", "", "comma separated Ip addresses having write permission. No limit if empty.")
|
masterWhiteListOption = cmdMaster.Flag.String("whiteList", "", "comma separated Ip addresses having write permission. No limit if empty.")
|
||||||
masterSecureKey = cmdMaster.Flag.String("secure.secret", "", "secret to encrypt Json Web Token(JWT)")
|
|
||||||
masterCpuProfile = cmdMaster.Flag.String("cpuprofile", "", "cpu profile output file")
|
masterCpuProfile = cmdMaster.Flag.String("cpuprofile", "", "cpu profile output file")
|
||||||
masterMemProfile = cmdMaster.Flag.String("memprofile", "", "memory profile output file")
|
masterMemProfile = cmdMaster.Flag.String("memprofile", "", "memory profile output file")
|
||||||
|
|
||||||
|
@ -52,6 +56,9 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func runMaster(cmd *Command, args []string) bool {
|
func runMaster(cmd *Command, args []string) bool {
|
||||||
|
|
||||||
|
weed_server.LoadConfiguration("security", false)
|
||||||
|
|
||||||
if *mMaxCpu < 1 {
|
if *mMaxCpu < 1 {
|
||||||
*mMaxCpu = runtime.NumCPU()
|
*mMaxCpu = runtime.NumCPU()
|
||||||
}
|
}
|
||||||
|
@ -72,7 +79,7 @@ func runMaster(cmd *Command, args []string) bool {
|
||||||
ms := weed_server.NewMasterServer(r, *mport, *metaFolder,
|
ms := weed_server.NewMasterServer(r, *mport, *metaFolder,
|
||||||
*volumeSizeLimitMB, *volumePreallocate,
|
*volumeSizeLimitMB, *volumePreallocate,
|
||||||
*mpulse, *defaultReplicaPlacement, *garbageThreshold,
|
*mpulse, *defaultReplicaPlacement, *garbageThreshold,
|
||||||
masterWhiteList, *masterSecureKey,
|
masterWhiteList,
|
||||||
)
|
)
|
||||||
|
|
||||||
listeningAddress := *masterBindIp + ":" + strconv.Itoa(*mport)
|
listeningAddress := *masterBindIp + ":" + strconv.Itoa(*mport)
|
||||||
|
@ -102,7 +109,7 @@ func runMaster(cmd *Command, args []string) bool {
|
||||||
glog.Fatalf("master failed to listen on grpc port %d: %v", grpcPort, err)
|
glog.Fatalf("master failed to listen on grpc port %d: %v", grpcPort, err)
|
||||||
}
|
}
|
||||||
// Create your protocol servers.
|
// Create your protocol servers.
|
||||||
grpcS := util.NewGrpcServer()
|
grpcS := util.NewGrpcServer(security.LoadServerTLS(viper.Sub("grpc"), "master"))
|
||||||
master_pb.RegisterSeaweedServer(grpcS, ms)
|
master_pb.RegisterSeaweedServer(grpcS, ms)
|
||||||
reflection.Register(grpcS)
|
reflection.Register(grpcS)
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,9 @@ package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/server"
|
||||||
|
"github.com/spf13/viper"
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -19,6 +22,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func runMount(cmd *Command, args []string) bool {
|
func runMount(cmd *Command, args []string) bool {
|
||||||
|
|
||||||
|
weed_server.LoadConfiguration("security", false)
|
||||||
|
|
||||||
fmt.Printf("This is SeaweedFS version %s %s %s\n", util.VERSION, runtime.GOOS, runtime.GOARCH)
|
fmt.Printf("This is SeaweedFS version %s %s %s\n", util.VERSION, runtime.GOOS, runtime.GOARCH)
|
||||||
if *mountOptions.dir == "" {
|
if *mountOptions.dir == "" {
|
||||||
fmt.Printf("Please specify the mount directory via \"-dir\"")
|
fmt.Printf("Please specify the mount directory via \"-dir\"")
|
||||||
|
@ -91,6 +97,7 @@ func runMount(cmd *Command, args []string) bool {
|
||||||
|
|
||||||
err = fs.Serve(c, filesys.NewSeaweedFileSystem(&filesys.Option{
|
err = fs.Serve(c, filesys.NewSeaweedFileSystem(&filesys.Option{
|
||||||
FilerGrpcAddress: filerGrpcAddress,
|
FilerGrpcAddress: filerGrpcAddress,
|
||||||
|
GrpcDialOption: security.LoadClientTLS(viper.Sub("grpc"), "client"),
|
||||||
FilerMountRootPath: mountRoot,
|
FilerMountRootPath: mountRoot,
|
||||||
Collection: *mountOptions.collection,
|
Collection: *mountOptions.collection,
|
||||||
Replication: *mountOptions.replication,
|
Replication: *mountOptions.replication,
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/server"
|
||||||
|
"github.com/spf13/viper"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -46,6 +49,8 @@ var cmdS3 = &Command{
|
||||||
|
|
||||||
func runS3(cmd *Command, args []string) bool {
|
func runS3(cmd *Command, args []string) bool {
|
||||||
|
|
||||||
|
weed_server.LoadConfiguration("security", false)
|
||||||
|
|
||||||
filerGrpcAddress, err := parseFilerGrpcAddress(*s3options.filer, *s3options.filerGrpcPort)
|
filerGrpcAddress, err := parseFilerGrpcAddress(*s3options.filer, *s3options.filerGrpcPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatal(err)
|
glog.Fatal(err)
|
||||||
|
@ -59,6 +64,7 @@ func runS3(cmd *Command, args []string) bool {
|
||||||
FilerGrpcAddress: filerGrpcAddress,
|
FilerGrpcAddress: filerGrpcAddress,
|
||||||
DomainName: *s3options.domainName,
|
DomainName: *s3options.domainName,
|
||||||
BucketsPath: *s3options.filerBucketsPath,
|
BucketsPath: *s3options.filerBucketsPath,
|
||||||
|
GrpcDialOption: security.LoadClientTLS(viper.Sub("grpc"), "client"),
|
||||||
})
|
})
|
||||||
if s3ApiServer_err != nil {
|
if s3ApiServer_err != nil {
|
||||||
glog.Fatalf("S3 API Server startup error: %v", s3ApiServer_err)
|
glog.Fatalf("S3 API Server startup error: %v", s3ApiServer_err)
|
||||||
|
|
|
@ -10,7 +10,7 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmdScaffold = &Command{
|
var cmdScaffold = &Command{
|
||||||
UsageLine: "scaffold [filer]",
|
UsageLine: "scaffold -config=[filer|notification|replication|security]",
|
||||||
Short: "generate basic configuration files",
|
Short: "generate basic configuration files",
|
||||||
Long: `Generate filer.toml with all possible configurations for you to customize.
|
Long: `Generate filer.toml with all possible configurations for you to customize.
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ var cmdScaffold = &Command{
|
||||||
|
|
||||||
var (
|
var (
|
||||||
outputPath = cmdScaffold.Flag.String("output", "", "if not empty, save the configuration file to this directory")
|
outputPath = cmdScaffold.Flag.String("output", "", "if not empty, save the configuration file to this directory")
|
||||||
config = cmdScaffold.Flag.String("config", "filer", "[filer|notification|replication] the configuration file to generate")
|
config = cmdScaffold.Flag.String("config", "filer", "[filer|notification|replication|security] the configuration file to generate")
|
||||||
)
|
)
|
||||||
|
|
||||||
func runScaffold(cmd *Command, args []string) bool {
|
func runScaffold(cmd *Command, args []string) bool {
|
||||||
|
@ -32,6 +32,8 @@ func runScaffold(cmd *Command, args []string) bool {
|
||||||
content = NOTIFICATION_TOML_EXAMPLE
|
content = NOTIFICATION_TOML_EXAMPLE
|
||||||
case "replication":
|
case "replication":
|
||||||
content = REPLICATION_TOML_EXAMPLE
|
content = REPLICATION_TOML_EXAMPLE
|
||||||
|
case "security":
|
||||||
|
content = SECURITY_TOML_EXAMPLE
|
||||||
}
|
}
|
||||||
if content == "" {
|
if content == "" {
|
||||||
println("need a valid -config option")
|
println("need a valid -config option")
|
||||||
|
@ -239,5 +241,43 @@ b2_master_application_key = ""
|
||||||
bucket = "mybucket" # an existing bucket
|
bucket = "mybucket" # an existing bucket
|
||||||
directory = "/" # destination directory
|
directory = "/" # destination directory
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
SECURITY_TOML_EXAMPLE = `
|
||||||
|
# Put this file to one of the location, with descending priority
|
||||||
|
# ./security.toml
|
||||||
|
# $HOME/.seaweedfs/security.toml
|
||||||
|
# /etc/seaweedfs/security.toml
|
||||||
|
# this file is read by master, volume server, and filer
|
||||||
|
|
||||||
|
# the jwt signing key is read by master and volume server
|
||||||
|
# a jwt expires in 10 seconds
|
||||||
|
[jwt.signing]
|
||||||
|
key = ""
|
||||||
|
|
||||||
|
# volume server also uses grpc that should be secured.
|
||||||
|
|
||||||
|
# all grpc tls authentications are mutual
|
||||||
|
[grpc]
|
||||||
|
ca = ""
|
||||||
|
|
||||||
|
[grpc.volume]
|
||||||
|
cert = ""
|
||||||
|
key = ""
|
||||||
|
|
||||||
|
[grpc.master]
|
||||||
|
cert = ""
|
||||||
|
key = ""
|
||||||
|
|
||||||
|
[grpc.filer]
|
||||||
|
cert = ""
|
||||||
|
key = ""
|
||||||
|
|
||||||
|
# use this for any place needs a grpc client
|
||||||
|
# i.e., "weed backup|benchmark|filer.copy|filer.replicate|mount|s3|upload"
|
||||||
|
[grpc.client]
|
||||||
|
cert = ""
|
||||||
|
key = ""
|
||||||
|
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
|
"github.com/spf13/viper"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -58,7 +60,6 @@ var (
|
||||||
serverRack = cmdServer.Flag.String("rack", "", "current volume server's rack name")
|
serverRack = cmdServer.Flag.String("rack", "", "current volume server's rack name")
|
||||||
serverWhiteListOption = cmdServer.Flag.String("whiteList", "", "comma separated Ip addresses having write permission. No limit if empty.")
|
serverWhiteListOption = cmdServer.Flag.String("whiteList", "", "comma separated Ip addresses having write permission. No limit if empty.")
|
||||||
serverPeers = cmdServer.Flag.String("master.peers", "", "all master nodes in comma separated ip:masterPort list")
|
serverPeers = cmdServer.Flag.String("master.peers", "", "all master nodes in comma separated ip:masterPort list")
|
||||||
serverSecureKey = cmdServer.Flag.String("secure.secret", "", "secret to encrypt Json Web Token(JWT)")
|
|
||||||
serverGarbageThreshold = cmdServer.Flag.Float64("garbageThreshold", 0.3, "threshold to vacuum and reclaim spaces")
|
serverGarbageThreshold = cmdServer.Flag.Float64("garbageThreshold", 0.3, "threshold to vacuum and reclaim spaces")
|
||||||
masterPort = cmdServer.Flag.Int("master.port", 9333, "master server http listen port")
|
masterPort = cmdServer.Flag.Int("master.port", 9333, "master server http listen port")
|
||||||
masterGrpcPort = cmdServer.Flag.Int("master.port.grpc", 0, "master grpc server listen port, default to http port + 10000")
|
masterGrpcPort = cmdServer.Flag.Int("master.port.grpc", 0, "master grpc server listen port, default to http port + 10000")
|
||||||
|
@ -96,7 +97,9 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func runServer(cmd *Command, args []string) bool {
|
func runServer(cmd *Command, args []string) bool {
|
||||||
filerOptions.secretKey = serverSecureKey
|
|
||||||
|
weed_server.LoadConfiguration("security", false)
|
||||||
|
|
||||||
if *serverOptions.cpuprofile != "" {
|
if *serverOptions.cpuprofile != "" {
|
||||||
f, err := os.Create(*serverOptions.cpuprofile)
|
f, err := os.Create(*serverOptions.cpuprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -170,7 +173,7 @@ func runServer(cmd *Command, args []string) bool {
|
||||||
ms := weed_server.NewMasterServer(r, *masterPort, *masterMetaFolder,
|
ms := weed_server.NewMasterServer(r, *masterPort, *masterMetaFolder,
|
||||||
*masterVolumeSizeLimitMB, *masterVolumePreallocate,
|
*masterVolumeSizeLimitMB, *masterVolumePreallocate,
|
||||||
*pulseSeconds, *masterDefaultReplicaPlacement, *serverGarbageThreshold,
|
*pulseSeconds, *masterDefaultReplicaPlacement, *serverGarbageThreshold,
|
||||||
serverWhiteList, *serverSecureKey,
|
serverWhiteList,
|
||||||
)
|
)
|
||||||
|
|
||||||
glog.V(0).Infof("Start Seaweed Master %s at %s:%d", util.VERSION, *serverIp, *masterPort)
|
glog.V(0).Infof("Start Seaweed Master %s at %s:%d", util.VERSION, *serverIp, *masterPort)
|
||||||
|
@ -190,7 +193,8 @@ func runServer(cmd *Command, args []string) bool {
|
||||||
glog.Fatalf("master failed to listen on grpc port %d: %v", grpcPort, err)
|
glog.Fatalf("master failed to listen on grpc port %d: %v", grpcPort, err)
|
||||||
}
|
}
|
||||||
// Create your protocol servers.
|
// Create your protocol servers.
|
||||||
grpcS := util.NewGrpcServer()
|
glog.V(0).Infof("grpc config %+v", viper.Sub("grpc"))
|
||||||
|
grpcS := util.NewGrpcServer(security.LoadServerTLS(viper.Sub("grpc"), "master"))
|
||||||
master_pb.RegisterSeaweedServer(grpcS, ms)
|
master_pb.RegisterSeaweedServer(grpcS, ms)
|
||||||
reflection.Register(grpcS)
|
reflection.Register(grpcS)
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,13 @@ package command
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/server"
|
||||||
|
"github.com/spf13/viper"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/operation"
|
"github.com/chrislusf/seaweedfs/weed/operation"
|
||||||
"github.com/chrislusf/seaweedfs/weed/security"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -23,7 +25,6 @@ type UploadOptions struct {
|
||||||
dataCenter *string
|
dataCenter *string
|
||||||
ttl *string
|
ttl *string
|
||||||
maxMB *int
|
maxMB *int
|
||||||
secretKey *string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -37,7 +38,6 @@ func init() {
|
||||||
upload.dataCenter = cmdUpload.Flag.String("dataCenter", "", "optional data center name")
|
upload.dataCenter = cmdUpload.Flag.String("dataCenter", "", "optional data center name")
|
||||||
upload.ttl = cmdUpload.Flag.String("ttl", "", "time to live, e.g.: 1m, 1h, 1d, 1M, 1y")
|
upload.ttl = cmdUpload.Flag.String("ttl", "", "time to live, e.g.: 1m, 1h, 1d, 1M, 1y")
|
||||||
upload.maxMB = cmdUpload.Flag.Int("maxMB", 0, "split files larger than the limit")
|
upload.maxMB = cmdUpload.Flag.Int("maxMB", 0, "split files larger than the limit")
|
||||||
upload.secretKey = cmdUpload.Flag.String("secure.secret", "", "secret to encrypt Json Web Token(JWT)")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmdUpload = &Command{
|
var cmdUpload = &Command{
|
||||||
|
@ -60,7 +60,10 @@ var cmdUpload = &Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
func runUpload(cmd *Command, args []string) bool {
|
func runUpload(cmd *Command, args []string) bool {
|
||||||
secret := security.Secret(*upload.secretKey)
|
|
||||||
|
weed_server.LoadConfiguration("security", false)
|
||||||
|
grpcDialOption := security.LoadClientTLS(viper.Sub("grpc"), "client")
|
||||||
|
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
if *upload.dir == "" {
|
if *upload.dir == "" {
|
||||||
return false
|
return false
|
||||||
|
@ -77,9 +80,9 @@ func runUpload(cmd *Command, args []string) bool {
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
results, e := operation.SubmitFiles(*upload.master, parts,
|
results, e := operation.SubmitFiles(*upload.master, grpcDialOption, parts,
|
||||||
*upload.replication, *upload.collection, *upload.dataCenter,
|
*upload.replication, *upload.collection, *upload.dataCenter,
|
||||||
*upload.ttl, *upload.maxMB, secret)
|
*upload.ttl, *upload.maxMB)
|
||||||
bytes, _ := json.Marshal(results)
|
bytes, _ := json.Marshal(results)
|
||||||
fmt.Println(string(bytes))
|
fmt.Println(string(bytes))
|
||||||
if e != nil {
|
if e != nil {
|
||||||
|
@ -96,9 +99,9 @@ func runUpload(cmd *Command, args []string) bool {
|
||||||
if e != nil {
|
if e != nil {
|
||||||
fmt.Println(e.Error())
|
fmt.Println(e.Error())
|
||||||
}
|
}
|
||||||
results, _ := operation.SubmitFiles(*upload.master, parts,
|
results, _ := operation.SubmitFiles(*upload.master, grpcDialOption, parts,
|
||||||
*upload.replication, *upload.collection, *upload.dataCenter,
|
*upload.replication, *upload.collection, *upload.dataCenter,
|
||||||
*upload.ttl, *upload.maxMB, secret)
|
*upload.ttl, *upload.maxMB)
|
||||||
bytes, _ := json.Marshal(results)
|
bytes, _ := json.Marshal(results)
|
||||||
fmt.Println(string(bytes))
|
fmt.Println(string(bytes))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
|
"github.com/spf13/viper"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -78,6 +80,9 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func runVolume(cmd *Command, args []string) bool {
|
func runVolume(cmd *Command, args []string) bool {
|
||||||
|
|
||||||
|
weed_server.LoadConfiguration("security", false)
|
||||||
|
|
||||||
if *v.maxCpu < 1 {
|
if *v.maxCpu < 1 {
|
||||||
*v.maxCpu = runtime.NumCPU()
|
*v.maxCpu = runtime.NumCPU()
|
||||||
}
|
}
|
||||||
|
@ -185,7 +190,7 @@ func (v VolumeServerOptions) startVolumeServer(volumeFolders, maxVolumeCounts, v
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("failed to listen on grpc port %d: %v", grpcPort, err)
|
glog.Fatalf("failed to listen on grpc port %d: %v", grpcPort, err)
|
||||||
}
|
}
|
||||||
grpcS := util.NewGrpcServer()
|
grpcS := util.NewGrpcServer(security.LoadServerTLS(viper.Sub("grpc"), "volume"))
|
||||||
volume_server_pb.RegisterVolumeServerServer(grpcS, volumeServer)
|
volume_server_pb.RegisterVolumeServerServer(grpcS, volumeServer)
|
||||||
reflection.Register(grpcS)
|
reflection.Register(grpcS)
|
||||||
go grpcS.Serve(grpcL)
|
go grpcS.Serve(grpcL)
|
||||||
|
|
|
@ -3,6 +3,7 @@ package filer2
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -24,13 +25,15 @@ type Filer struct {
|
||||||
directoryCache *ccache.Cache
|
directoryCache *ccache.Cache
|
||||||
MasterClient *wdclient.MasterClient
|
MasterClient *wdclient.MasterClient
|
||||||
fileIdDeletionChan chan string
|
fileIdDeletionChan chan string
|
||||||
|
GrpcDialOption grpc.DialOption
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFiler(masters []string) *Filer {
|
func NewFiler(masters []string, grpcDialOption grpc.DialOption) *Filer {
|
||||||
f := &Filer{
|
f := &Filer{
|
||||||
directoryCache: ccache.New(ccache.Configure().MaxSize(1000).ItemsToPrune(100)),
|
directoryCache: ccache.New(ccache.Configure().MaxSize(1000).ItemsToPrune(100)),
|
||||||
MasterClient: wdclient.NewMasterClient(context.Background(), "filer", masters),
|
MasterClient: wdclient.NewMasterClient(context.Background(), grpcDialOption, "filer", masters),
|
||||||
fileIdDeletionChan: make(chan string, 4096),
|
fileIdDeletionChan: make(chan string, 4096),
|
||||||
|
GrpcDialOption: grpcDialOption,
|
||||||
}
|
}
|
||||||
|
|
||||||
go f.loopProcessingDeletion()
|
go f.loopProcessingDeletion()
|
||||||
|
|
|
@ -38,13 +38,13 @@ func (f *Filer) loopProcessingDeletion() {
|
||||||
fileIds = append(fileIds, fid)
|
fileIds = append(fileIds, fid)
|
||||||
if len(fileIds) >= 4096 {
|
if len(fileIds) >= 4096 {
|
||||||
glog.V(1).Infof("deleting fileIds len=%d", len(fileIds))
|
glog.V(1).Infof("deleting fileIds len=%d", len(fileIds))
|
||||||
operation.DeleteFilesWithLookupVolumeId(fileIds, lookupFunc)
|
operation.DeleteFilesWithLookupVolumeId(f.GrpcDialOption, fileIds, lookupFunc)
|
||||||
fileIds = fileIds[:0]
|
fileIds = fileIds[:0]
|
||||||
}
|
}
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
if len(fileIds) > 0 {
|
if len(fileIds) > 0 {
|
||||||
glog.V(1).Infof("timed deletion fileIds len=%d", len(fileIds))
|
glog.V(1).Infof("timed deletion fileIds len=%d", len(fileIds))
|
||||||
operation.DeleteFilesWithLookupVolumeId(fileIds, lookupFunc)
|
operation.DeleteFilesWithLookupVolumeId(f.GrpcDialOption, fileIds, lookupFunc)
|
||||||
fileIds = fileIds[:0]
|
fileIds = fileIds[:0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCreateAndFind(t *testing.T) {
|
func TestCreateAndFind(t *testing.T) {
|
||||||
filer := filer2.NewFiler(nil)
|
filer := filer2.NewFiler(nil, nil)
|
||||||
dir, _ := ioutil.TempDir("", "seaweedfs_filer_test")
|
dir, _ := ioutil.TempDir("", "seaweedfs_filer_test")
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
store := &LevelDBStore{}
|
store := &LevelDBStore{}
|
||||||
|
@ -61,7 +61,7 @@ func TestCreateAndFind(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEmptyRoot(t *testing.T) {
|
func TestEmptyRoot(t *testing.T) {
|
||||||
filer := filer2.NewFiler(nil)
|
filer := filer2.NewFiler(nil, nil)
|
||||||
dir, _ := ioutil.TempDir("", "seaweedfs_filer_test2")
|
dir, _ := ioutil.TempDir("", "seaweedfs_filer_test2")
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
store := &LevelDBStore{}
|
store := &LevelDBStore{}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCreateAndFind(t *testing.T) {
|
func TestCreateAndFind(t *testing.T) {
|
||||||
filer := filer2.NewFiler(nil)
|
filer := filer2.NewFiler(nil, nil)
|
||||||
store := &MemDbStore{}
|
store := &MemDbStore{}
|
||||||
store.Initialize(nil)
|
store.Initialize(nil)
|
||||||
filer.SetStore(store)
|
filer.SetStore(store)
|
||||||
|
@ -43,7 +43,7 @@ func TestCreateAndFind(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateFileAndList(t *testing.T) {
|
func TestCreateFileAndList(t *testing.T) {
|
||||||
filer := filer2.NewFiler(nil)
|
filer := filer2.NewFiler(nil, nil)
|
||||||
store := &MemDbStore{}
|
store := &MemDbStore{}
|
||||||
store.Initialize(nil)
|
store.Initialize(nil)
|
||||||
filer.SetStore(store)
|
filer.SetStore(store)
|
||||||
|
|
|
@ -4,13 +4,14 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/glog"
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||||
"github.com/chrislusf/seaweedfs/weed/operation"
|
"github.com/chrislusf/seaweedfs/weed/operation"
|
||||||
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
||||||
"sync"
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ContinuousDirtyPages struct {
|
type ContinuousDirtyPages struct {
|
||||||
|
@ -164,6 +165,7 @@ func (pages *ContinuousDirtyPages) saveExistingPagesToStorage(ctx context.Contex
|
||||||
func (pages *ContinuousDirtyPages) saveToStorage(ctx context.Context, buf []byte, offset int64) (*filer_pb.FileChunk, error) {
|
func (pages *ContinuousDirtyPages) saveToStorage(ctx context.Context, buf []byte, offset int64) (*filer_pb.FileChunk, error) {
|
||||||
|
|
||||||
var fileId, host string
|
var fileId, host string
|
||||||
|
var auth security.EncodedJwt
|
||||||
|
|
||||||
if err := pages.f.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
|
if err := pages.f.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
|
||||||
|
|
||||||
|
@ -181,7 +183,7 @@ func (pages *ContinuousDirtyPages) saveToStorage(ctx context.Context, buf []byte
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fileId, host = resp.FileId, resp.Url
|
fileId, host, auth = resp.FileId, resp.Url, security.EncodedJwt(resp.Auth)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
@ -190,7 +192,7 @@ func (pages *ContinuousDirtyPages) saveToStorage(ctx context.Context, buf []byte
|
||||||
|
|
||||||
fileUrl := fmt.Sprintf("http://%s/%s", host, fileId)
|
fileUrl := fmt.Sprintf("http://%s/%s", host, fileId)
|
||||||
bufReader := bytes.NewReader(buf)
|
bufReader := bytes.NewReader(buf)
|
||||||
uploadResult, err := operation.Upload(fileUrl, pages.f.Name, bufReader, false, "application/octet-stream", nil, "")
|
uploadResult, err := operation.Upload(fileUrl, pages.f.Name, bufReader, false, "application/octet-stream", nil, auth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(0).Infof("upload data %v to %s: %v", pages.f.Name, fileUrl, err)
|
glog.V(0).Infof("upload data %v to %s: %v", pages.f.Name, fileUrl, err)
|
||||||
return nil, fmt.Errorf("upload data: %v", err)
|
return nil, fmt.Errorf("upload data: %v", err)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/chrislusf/seaweedfs/weed/util"
|
"github.com/chrislusf/seaweedfs/weed/util"
|
||||||
"github.com/seaweedfs/fuse"
|
"github.com/seaweedfs/fuse"
|
||||||
"github.com/seaweedfs/fuse/fs"
|
"github.com/seaweedfs/fuse/fs"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -230,7 +231,7 @@ func (fh *FileHandle) Flush(ctx context.Context, req *fuse.FlushRequest) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteFileIds(ctx context.Context, client filer_pb.SeaweedFilerClient, fileIds []string) error {
|
func deleteFileIds(ctx context.Context, grpcDialOption grpc.DialOption, client filer_pb.SeaweedFilerClient, fileIds []string) error {
|
||||||
|
|
||||||
var vids []string
|
var vids []string
|
||||||
for _, fileId := range fileIds {
|
for _, fileId := range fileIds {
|
||||||
|
@ -267,7 +268,7 @@ func deleteFileIds(ctx context.Context, client filer_pb.SeaweedFilerClient, file
|
||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := operation.DeleteFilesWithLookupVolumeId(fileIds, lookupFunc)
|
_, err := operation.DeleteFilesWithLookupVolumeId(grpcDialOption, fileIds, lookupFunc)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
|
|
||||||
type Option struct {
|
type Option struct {
|
||||||
FilerGrpcAddress string
|
FilerGrpcAddress string
|
||||||
|
GrpcDialOption grpc.DialOption
|
||||||
FilerMountRootPath string
|
FilerMountRootPath string
|
||||||
Collection string
|
Collection string
|
||||||
Replication string
|
Replication string
|
||||||
|
@ -46,8 +47,6 @@ type WFS struct {
|
||||||
pathToHandleLock sync.Mutex
|
pathToHandleLock sync.Mutex
|
||||||
bufPool sync.Pool
|
bufPool sync.Pool
|
||||||
|
|
||||||
fileIdsDeletionChan chan []string
|
|
||||||
|
|
||||||
stats statsCache
|
stats statsCache
|
||||||
}
|
}
|
||||||
type statsCache struct {
|
type statsCache struct {
|
||||||
|
@ -65,11 +64,8 @@ func NewSeaweedFileSystem(option *Option) *WFS {
|
||||||
return make([]byte, option.ChunkSizeLimit)
|
return make([]byte, option.ChunkSizeLimit)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
fileIdsDeletionChan: make(chan []string, 32),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
go wfs.loopProcessingDeletion()
|
|
||||||
|
|
||||||
return wfs
|
return wfs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +78,7 @@ func (wfs *WFS) withFilerClient(fn func(filer_pb.SeaweedFilerClient) error) erro
|
||||||
return util.WithCachedGrpcClient(func(grpcConnection *grpc.ClientConn) error {
|
return util.WithCachedGrpcClient(func(grpcConnection *grpc.ClientConn) error {
|
||||||
client := filer_pb.NewSeaweedFilerClient(grpcConnection)
|
client := filer_pb.NewSeaweedFilerClient(grpcConnection)
|
||||||
return fn(client)
|
return fn(client)
|
||||||
}, wfs.option.FilerGrpcAddress)
|
}, wfs.option.FilerGrpcAddress, wfs.option.GrpcDialOption)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,39 +2,9 @@ package filesys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/glog"
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (wfs *WFS) loopProcessingDeletion() {
|
|
||||||
|
|
||||||
ticker := time.NewTicker(2 * time.Second)
|
|
||||||
|
|
||||||
wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
|
|
||||||
var fileIds []string
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case fids := <-wfs.fileIdsDeletionChan:
|
|
||||||
fileIds = append(fileIds, fids...)
|
|
||||||
if len(fileIds) >= 1024 {
|
|
||||||
glog.V(1).Infof("deleting fileIds len=%d", len(fileIds))
|
|
||||||
deleteFileIds(context.Background(), client, fileIds)
|
|
||||||
fileIds = fileIds[:0]
|
|
||||||
}
|
|
||||||
case <-ticker.C:
|
|
||||||
if len(fileIds) > 0 {
|
|
||||||
glog.V(1).Infof("timed deletion fileIds len=%d", len(fileIds))
|
|
||||||
deleteFileIds(context.Background(), client, fileIds)
|
|
||||||
fileIds = fileIds[:0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wfs *WFS) deleteFileChunks(chunks []*filer_pb.FileChunk) {
|
func (wfs *WFS) deleteFileChunks(chunks []*filer_pb.FileChunk) {
|
||||||
if len(chunks) == 0 {
|
if len(chunks) == 0 {
|
||||||
return
|
return
|
||||||
|
@ -45,14 +15,8 @@ func (wfs *WFS) deleteFileChunks(chunks []*filer_pb.FileChunk) {
|
||||||
fileIds = append(fileIds, chunk.FileId)
|
fileIds = append(fileIds, chunk.FileId)
|
||||||
}
|
}
|
||||||
|
|
||||||
var async = false
|
|
||||||
if async {
|
|
||||||
wfs.fileIdsDeletionChan <- fileIds
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
|
wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
|
||||||
deleteFileIds(context.Background(), client, fileIds)
|
deleteFileIds(context.Background(), wfs.option.GrpcDialOption, client, fileIds)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,13 @@ package operation
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
|
"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type VolumeAssignRequest struct {
|
type VolumeAssignRequest struct {
|
||||||
|
@ -24,9 +28,10 @@ type AssignResult struct {
|
||||||
PublicUrl string `json:"publicUrl,omitempty"`
|
PublicUrl string `json:"publicUrl,omitempty"`
|
||||||
Count uint64 `json:"count,omitempty"`
|
Count uint64 `json:"count,omitempty"`
|
||||||
Error string `json:"error,omitempty"`
|
Error string `json:"error,omitempty"`
|
||||||
|
Auth security.EncodedJwt `json:"auth,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func Assign(server string, primaryRequest *VolumeAssignRequest, alternativeRequests ...*VolumeAssignRequest) (*AssignResult, error) {
|
func Assign(server string, grpcDialOption grpc.DialOption, primaryRequest *VolumeAssignRequest, alternativeRequests ...*VolumeAssignRequest) (*AssignResult, error) {
|
||||||
|
|
||||||
var requests []*VolumeAssignRequest
|
var requests []*VolumeAssignRequest
|
||||||
requests = append(requests, primaryRequest)
|
requests = append(requests, primaryRequest)
|
||||||
|
@ -40,7 +45,7 @@ func Assign(server string, primaryRequest *VolumeAssignRequest, alternativeReque
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
lastError = withMasterServerClient(server, func(masterClient master_pb.SeaweedClient) error {
|
lastError = withMasterServerClient(server, grpcDialOption, func(masterClient master_pb.SeaweedClient) error {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
@ -63,6 +68,7 @@ func Assign(server string, primaryRequest *VolumeAssignRequest, alternativeReque
|
||||||
ret.Url = resp.Url
|
ret.Url = resp.Url
|
||||||
ret.PublicUrl = resp.PublicUrl
|
ret.PublicUrl = resp.PublicUrl
|
||||||
ret.Error = resp.Error
|
ret.Error = resp.Error
|
||||||
|
ret.Auth = security.EncodedJwt(resp.Auth)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
@ -81,3 +87,17 @@ func Assign(server string, primaryRequest *VolumeAssignRequest, alternativeReque
|
||||||
|
|
||||||
return ret, lastError
|
return ret, lastError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LookupJwt(master string, fileId string) security.EncodedJwt {
|
||||||
|
|
||||||
|
tokenStr := ""
|
||||||
|
|
||||||
|
if h, e := util.Head(fmt.Sprintf("http://%s/dir/lookup?fileId=%s", master, fileId)); e == nil {
|
||||||
|
bearer := h.Get("Authorization")
|
||||||
|
if len(bearer) > 7 && strings.ToUpper(bearer[0:6]) == "BEARER" {
|
||||||
|
tokenStr = bearer[7:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return security.EncodedJwt(tokenStr)
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -69,12 +70,12 @@ func (cm *ChunkManifest) Marshal() ([]byte, error) {
|
||||||
return json.Marshal(cm)
|
return json.Marshal(cm)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cm *ChunkManifest) DeleteChunks(master string) error {
|
func (cm *ChunkManifest) DeleteChunks(master string, grpcDialOption grpc.DialOption) error {
|
||||||
var fileIds []string
|
var fileIds []string
|
||||||
for _, ci := range cm.Chunks {
|
for _, ci := range cm.Chunks {
|
||||||
fileIds = append(fileIds, ci.Fid)
|
fileIds = append(fileIds, ci.Fid)
|
||||||
}
|
}
|
||||||
results, err := DeleteFiles(master, fileIds)
|
results, err := DeleteFiles(master, grpcDialOption, fileIds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(0).Infof("delete %+v: %v", fileIds, err)
|
glog.V(0).Infof("delete %+v: %v", fileIds, err)
|
||||||
return fmt.Errorf("chunk delete: %v", err)
|
return fmt.Errorf("chunk delete: %v", err)
|
||||||
|
|
|
@ -2,6 +2,5 @@ package operation
|
||||||
|
|
||||||
type JoinResult struct {
|
type JoinResult struct {
|
||||||
VolumeSizeLimit uint64 `json:"VolumeSizeLimit,omitempty"`
|
VolumeSizeLimit uint64 `json:"VolumeSizeLimit,omitempty"`
|
||||||
SecretKey string `json:"secretKey,omitempty"`
|
|
||||||
Error string `json:"error,omitempty"`
|
Error string `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -28,17 +29,17 @@ func ParseFileId(fid string) (vid string, key_cookie string, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteFiles batch deletes a list of fileIds
|
// DeleteFiles batch deletes a list of fileIds
|
||||||
func DeleteFiles(master string, fileIds []string) ([]*volume_server_pb.DeleteResult, error) {
|
func DeleteFiles(master string, grpcDialOption grpc.DialOption, fileIds []string) ([]*volume_server_pb.DeleteResult, error) {
|
||||||
|
|
||||||
lookupFunc := func(vids []string) (map[string]LookupResult, error) {
|
lookupFunc := func(vids []string) (map[string]LookupResult, error) {
|
||||||
return LookupVolumeIds(master, vids)
|
return LookupVolumeIds(master, grpcDialOption, vids)
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeleteFilesWithLookupVolumeId(fileIds, lookupFunc)
|
return DeleteFilesWithLookupVolumeId(grpcDialOption, fileIds, lookupFunc)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteFilesWithLookupVolumeId(fileIds []string, lookupFunc func(vid []string) (map[string]LookupResult, error)) ([]*volume_server_pb.DeleteResult, error) {
|
func DeleteFilesWithLookupVolumeId(grpcDialOption grpc.DialOption, fileIds []string, lookupFunc func(vid []string) (map[string]LookupResult, error)) ([]*volume_server_pb.DeleteResult, error) {
|
||||||
|
|
||||||
var ret []*volume_server_pb.DeleteResult
|
var ret []*volume_server_pb.DeleteResult
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ func DeleteFilesWithLookupVolumeId(fileIds []string, lookupFunc func(vid []strin
|
||||||
vid, _, err := ParseFileId(fileId)
|
vid, _, err := ParseFileId(fileId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ret = append(ret, &volume_server_pb.DeleteResult{
|
ret = append(ret, &volume_server_pb.DeleteResult{
|
||||||
FileId: vid,
|
FileId: fileId,
|
||||||
Status: http.StatusBadRequest,
|
Status: http.StatusBadRequest,
|
||||||
Error: err.Error()},
|
Error: err.Error()},
|
||||||
)
|
)
|
||||||
|
@ -92,7 +93,7 @@ func DeleteFilesWithLookupVolumeId(fileIds []string, lookupFunc func(vid []strin
|
||||||
go func(server string, fidList []string) {
|
go func(server string, fidList []string) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
if deleteResults, deleteErr := DeleteFilesAtOneVolumeServer(server, fidList); deleteErr != nil {
|
if deleteResults, deleteErr := DeleteFilesAtOneVolumeServer(server, grpcDialOption, fidList); deleteErr != nil {
|
||||||
err = deleteErr
|
err = deleteErr
|
||||||
} else {
|
} else {
|
||||||
ret = append(ret, deleteResults...)
|
ret = append(ret, deleteResults...)
|
||||||
|
@ -106,9 +107,9 @@ func DeleteFilesWithLookupVolumeId(fileIds []string, lookupFunc func(vid []strin
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteFilesAtOneVolumeServer deletes a list of files that is on one volume server via gRpc
|
// DeleteFilesAtOneVolumeServer deletes a list of files that is on one volume server via gRpc
|
||||||
func DeleteFilesAtOneVolumeServer(volumeServer string, fileIds []string) (ret []*volume_server_pb.DeleteResult, err error) {
|
func DeleteFilesAtOneVolumeServer(volumeServer string, grpcDialOption grpc.DialOption, fileIds []string) (ret []*volume_server_pb.DeleteResult, err error) {
|
||||||
|
|
||||||
err = WithVolumeServerClient(volumeServer, func(volumeServerClient volume_server_pb.VolumeServerClient) error {
|
err = WithVolumeServerClient(volumeServer, grpcDialOption, func(volumeServerClient volume_server_pb.VolumeServerClient) error {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ var (
|
||||||
grpcClientsLock sync.Mutex
|
grpcClientsLock sync.Mutex
|
||||||
)
|
)
|
||||||
|
|
||||||
func WithVolumeServerClient(volumeServer string, fn func(volume_server_pb.VolumeServerClient) error) error {
|
func WithVolumeServerClient(volumeServer string, grpcDialOption grpc.DialOption, fn func(volume_server_pb.VolumeServerClient) error) error {
|
||||||
|
|
||||||
grpcAddress, err := toVolumeServerGrpcAddress(volumeServer)
|
grpcAddress, err := toVolumeServerGrpcAddress(volumeServer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -28,7 +28,7 @@ func WithVolumeServerClient(volumeServer string, fn func(volume_server_pb.Volume
|
||||||
return util.WithCachedGrpcClient(func(grpcConnection *grpc.ClientConn) error {
|
return util.WithCachedGrpcClient(func(grpcConnection *grpc.ClientConn) error {
|
||||||
client := volume_server_pb.NewVolumeServerClient(grpcConnection)
|
client := volume_server_pb.NewVolumeServerClient(grpcConnection)
|
||||||
return fn(client)
|
return fn(client)
|
||||||
}, grpcAddress)
|
}, grpcAddress, grpcDialOption)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ func toVolumeServerGrpcAddress(volumeServer string) (grpcAddress string, err err
|
||||||
return fmt.Sprintf("%s:%d", volumeServer[0:sepIndex], port+10000), nil
|
return fmt.Sprintf("%s:%d", volumeServer[0:sepIndex], port+10000), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func withMasterServerClient(masterServer string, fn func(masterClient master_pb.SeaweedClient) error) error {
|
func withMasterServerClient(masterServer string, grpcDialOption grpc.DialOption, fn func(masterClient master_pb.SeaweedClient) error) error {
|
||||||
|
|
||||||
masterGrpcAddress, parseErr := util.ParseServerToGrpcAddress(masterServer, 0)
|
masterGrpcAddress, parseErr := util.ParseServerToGrpcAddress(masterServer, 0)
|
||||||
if parseErr != nil {
|
if parseErr != nil {
|
||||||
|
@ -52,6 +52,6 @@ func withMasterServerClient(masterServer string, fn func(masterClient master_pb.
|
||||||
return util.WithCachedGrpcClient(func(grpcConnection *grpc.ClientConn) error {
|
return util.WithCachedGrpcClient(func(grpcConnection *grpc.ClientConn) error {
|
||||||
client := master_pb.NewSeaweedClient(grpcConnection)
|
client := master_pb.NewSeaweedClient(grpcConnection)
|
||||||
return fn(client)
|
return fn(client)
|
||||||
}, masterGrpcAddress)
|
}, masterGrpcAddress, grpcDialOption)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -78,7 +79,7 @@ func LookupFileId(server string, fileId string) (fullUrl string, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// LookupVolumeIds find volume locations by cache and actual lookup
|
// LookupVolumeIds find volume locations by cache and actual lookup
|
||||||
func LookupVolumeIds(server string, vids []string) (map[string]LookupResult, error) {
|
func LookupVolumeIds(server string, grpcDialOption grpc.DialOption, vids []string) (map[string]LookupResult, error) {
|
||||||
ret := make(map[string]LookupResult)
|
ret := make(map[string]LookupResult)
|
||||||
var unknown_vids []string
|
var unknown_vids []string
|
||||||
|
|
||||||
|
@ -98,7 +99,7 @@ func LookupVolumeIds(server string, vids []string) (map[string]LookupResult, err
|
||||||
|
|
||||||
//only query unknown_vids
|
//only query unknown_vids
|
||||||
|
|
||||||
err := withMasterServerClient(server, func(masterClient master_pb.SeaweedClient) error {
|
err := withMasterServerClient(server, grpcDialOption, func(masterClient master_pb.SeaweedClient) error {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,15 @@ package operation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
|
"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Statistics(server string, req *master_pb.StatisticsRequest) (resp *master_pb.StatisticsResponse, err error) {
|
func Statistics(server string, grpcDialOption grpc.DialOption, req *master_pb.StatisticsRequest) (resp *master_pb.StatisticsResponse, err error) {
|
||||||
|
|
||||||
err = withMasterServerClient(server, func(masterClient master_pb.SeaweedClient) error {
|
err = withMasterServerClient(server, grpcDialOption, func(masterClient master_pb.SeaweedClient) error {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package operation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"io"
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -36,10 +37,8 @@ type SubmitResult struct {
|
||||||
Error string `json:"error,omitempty"`
|
Error string `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func SubmitFiles(master string, files []FilePart,
|
func SubmitFiles(master string, grpcDialOption grpc.DialOption, files []FilePart,
|
||||||
replication string, collection string, dataCenter string, ttl string, maxMB int,
|
replication string, collection string, dataCenter string, ttl string, maxMB int) ([]SubmitResult, error) {
|
||||||
secret security.Secret,
|
|
||||||
) ([]SubmitResult, error) {
|
|
||||||
results := make([]SubmitResult, len(files))
|
results := make([]SubmitResult, len(files))
|
||||||
for index, file := range files {
|
for index, file := range files {
|
||||||
results[index].FileName = file.FileName
|
results[index].FileName = file.FileName
|
||||||
|
@ -51,7 +50,7 @@ func SubmitFiles(master string, files []FilePart,
|
||||||
DataCenter: dataCenter,
|
DataCenter: dataCenter,
|
||||||
Ttl: ttl,
|
Ttl: ttl,
|
||||||
}
|
}
|
||||||
ret, err := Assign(master, ar)
|
ret, err := Assign(master, grpcDialOption, ar)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
for index, _ := range files {
|
for index, _ := range files {
|
||||||
results[index].Error = err.Error()
|
results[index].Error = err.Error()
|
||||||
|
@ -67,7 +66,7 @@ func SubmitFiles(master string, files []FilePart,
|
||||||
file.Replication = replication
|
file.Replication = replication
|
||||||
file.Collection = collection
|
file.Collection = collection
|
||||||
file.DataCenter = dataCenter
|
file.DataCenter = dataCenter
|
||||||
results[index].Size, err = file.Upload(maxMB, master, secret)
|
results[index].Size, err = file.Upload(maxMB, master, ret.Auth, grpcDialOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
results[index].Error = err.Error()
|
results[index].Error = err.Error()
|
||||||
}
|
}
|
||||||
|
@ -110,8 +109,7 @@ func newFilePart(fullPathFilename string) (ret FilePart, err error) {
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fi FilePart) Upload(maxMB int, master string, secret security.Secret) (retSize uint32, err error) {
|
func (fi FilePart) Upload(maxMB int, master string, jwt security.EncodedJwt, grpcDialOption grpc.DialOption) (retSize uint32, err error) {
|
||||||
jwt := security.GenJwt(secret, fi.Fid)
|
|
||||||
fileUrl := "http://" + fi.Server + "/" + fi.Fid
|
fileUrl := "http://" + fi.Server + "/" + fi.Fid
|
||||||
if fi.ModTime != 0 {
|
if fi.ModTime != 0 {
|
||||||
fileUrl += "?ts=" + strconv.Itoa(int(fi.ModTime))
|
fileUrl += "?ts=" + strconv.Itoa(int(fi.ModTime))
|
||||||
|
@ -139,7 +137,7 @@ func (fi FilePart) Upload(maxMB int, master string, secret security.Secret) (ret
|
||||||
Collection: fi.Collection,
|
Collection: fi.Collection,
|
||||||
Ttl: fi.Ttl,
|
Ttl: fi.Ttl,
|
||||||
}
|
}
|
||||||
ret, err = Assign(master, ar)
|
ret, err = Assign(master, grpcDialOption, ar)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -152,10 +150,10 @@ func (fi FilePart) Upload(maxMB int, master string, secret security.Secret) (ret
|
||||||
Collection: fi.Collection,
|
Collection: fi.Collection,
|
||||||
Ttl: fi.Ttl,
|
Ttl: fi.Ttl,
|
||||||
}
|
}
|
||||||
ret, err = Assign(master, ar)
|
ret, err = Assign(master, grpcDialOption, ar)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// delete all uploaded chunks
|
// delete all uploaded chunks
|
||||||
cm.DeleteChunks(master)
|
cm.DeleteChunks(master, grpcDialOption)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
id = ret.Fid
|
id = ret.Fid
|
||||||
|
@ -170,10 +168,10 @@ func (fi FilePart) Upload(maxMB int, master string, secret security.Secret) (ret
|
||||||
baseName+"-"+strconv.FormatInt(i+1, 10),
|
baseName+"-"+strconv.FormatInt(i+1, 10),
|
||||||
io.LimitReader(fi.Reader, chunkSize),
|
io.LimitReader(fi.Reader, chunkSize),
|
||||||
master, fileUrl,
|
master, fileUrl,
|
||||||
jwt)
|
ret.Auth)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
// delete all uploaded chunks
|
// delete all uploaded chunks
|
||||||
cm.DeleteChunks(master)
|
cm.DeleteChunks(master, grpcDialOption)
|
||||||
return 0, e
|
return 0, e
|
||||||
}
|
}
|
||||||
cm.Chunks = append(cm.Chunks,
|
cm.Chunks = append(cm.Chunks,
|
||||||
|
@ -188,7 +186,7 @@ func (fi FilePart) Upload(maxMB int, master string, secret security.Secret) (ret
|
||||||
err = upload_chunked_file_manifest(fileUrl, &cm, jwt)
|
err = upload_chunked_file_manifest(fileUrl, &cm, jwt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// delete all uploaded chunks
|
// delete all uploaded chunks
|
||||||
cm.DeleteChunks(master)
|
cm.DeleteChunks(master, grpcDialOption)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret, e := Upload(fileUrl, baseName, fi.Reader, false, fi.MimeType, nil, jwt)
|
ret, e := Upload(fileUrl, baseName, fi.Reader, false, fi.MimeType, nil, jwt)
|
||||||
|
|
|
@ -3,6 +3,7 @@ package operation
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -11,9 +12,9 @@ import (
|
||||||
"github.com/chrislusf/seaweedfs/weed/util"
|
"github.com/chrislusf/seaweedfs/weed/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetVolumeSyncStatus(server string, vid uint32) (resp *volume_server_pb.VolumeSyncStatusResponse, err error) {
|
func GetVolumeSyncStatus(server string, grpcDialOption grpc.DialOption, vid uint32) (resp *volume_server_pb.VolumeSyncStatusResponse, err error) {
|
||||||
|
|
||||||
WithVolumeServerClient(server, func(client volume_server_pb.VolumeServerClient) error {
|
WithVolumeServerClient(server, grpcDialOption, func(client volume_server_pb.VolumeServerClient) error {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
@ -26,9 +27,9 @@ func GetVolumeSyncStatus(server string, vid uint32) (resp *volume_server_pb.Volu
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetVolumeIdxEntries(server string, vid uint32, eachEntryFn func(key NeedleId, offset Offset, size uint32)) error {
|
func GetVolumeIdxEntries(server string, grpcDialOption grpc.DialOption, vid uint32, eachEntryFn func(key NeedleId, offset Offset, size uint32)) error {
|
||||||
|
|
||||||
return WithVolumeServerClient(server, func(client volume_server_pb.VolumeServerClient) error {
|
return WithVolumeServerClient(server, grpcDialOption, func(client volume_server_pb.VolumeServerClient) error {
|
||||||
stream, err := client.VolumeSyncIndex(context.Background(), &volume_server_pb.VolumeSyncIndexRequest{
|
stream, err := client.VolumeSyncIndex(context.Background(), &volume_server_pb.VolumeSyncIndexRequest{
|
||||||
VolumdId: vid,
|
VolumdId: vid,
|
||||||
})
|
})
|
||||||
|
|
|
@ -58,9 +58,6 @@ func upload_content(uploadUrl string, fillBufferFunction func(w io.Writer) error
|
||||||
if isGzipped {
|
if isGzipped {
|
||||||
h.Set("Content-Encoding", "gzip")
|
h.Set("Content-Encoding", "gzip")
|
||||||
}
|
}
|
||||||
if jwt != "" {
|
|
||||||
h.Set("Authorization", "BEARER "+string(jwt))
|
|
||||||
}
|
|
||||||
|
|
||||||
file_writer, cp_err := body_writer.CreatePart(h)
|
file_writer, cp_err := body_writer.CreatePart(h)
|
||||||
if cp_err != nil {
|
if cp_err != nil {
|
||||||
|
@ -86,6 +83,9 @@ func upload_content(uploadUrl string, fillBufferFunction func(w io.Writer) error
|
||||||
for k, v := range pairMap {
|
for k, v := range pairMap {
|
||||||
req.Header.Set(k, v)
|
req.Header.Set(k, v)
|
||||||
}
|
}
|
||||||
|
if jwt != "" {
|
||||||
|
req.Header.Set("Authorization", "BEARER "+string(jwt))
|
||||||
|
}
|
||||||
resp, post_err := client.Do(req)
|
resp, post_err := client.Do(req)
|
||||||
if post_err != nil {
|
if post_err != nil {
|
||||||
glog.V(0).Infoln("failing to upload to", uploadUrl, post_err.Error())
|
glog.V(0).Infoln("failing to upload to", uploadUrl, post_err.Error())
|
||||||
|
|
|
@ -139,6 +139,7 @@ message AssignVolumeResponse {
|
||||||
string url = 2;
|
string url = 2;
|
||||||
string public_url = 3;
|
string public_url = 3;
|
||||||
int32 count = 4;
|
int32 count = 4;
|
||||||
|
string auth = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LookupVolumeRequest {
|
message LookupVolumeRequest {
|
||||||
|
|
|
@ -574,6 +574,7 @@ type AssignVolumeResponse struct {
|
||||||
Url string `protobuf:"bytes,2,opt,name=url" json:"url,omitempty"`
|
Url string `protobuf:"bytes,2,opt,name=url" json:"url,omitempty"`
|
||||||
PublicUrl string `protobuf:"bytes,3,opt,name=public_url,json=publicUrl" json:"public_url,omitempty"`
|
PublicUrl string `protobuf:"bytes,3,opt,name=public_url,json=publicUrl" json:"public_url,omitempty"`
|
||||||
Count int32 `protobuf:"varint,4,opt,name=count" json:"count,omitempty"`
|
Count int32 `protobuf:"varint,4,opt,name=count" json:"count,omitempty"`
|
||||||
|
Auth string `protobuf:"bytes,5,opt,name=auth" json:"auth,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *AssignVolumeResponse) Reset() { *m = AssignVolumeResponse{} }
|
func (m *AssignVolumeResponse) Reset() { *m = AssignVolumeResponse{} }
|
||||||
|
@ -609,6 +610,13 @@ func (m *AssignVolumeResponse) GetCount() int32 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *AssignVolumeResponse) GetAuth() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Auth
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
type LookupVolumeRequest struct {
|
type LookupVolumeRequest struct {
|
||||||
VolumeIds []string `protobuf:"bytes,1,rep,name=volume_ids,json=volumeIds" json:"volume_ids,omitempty"`
|
VolumeIds []string `protobuf:"bytes,1,rep,name=volume_ids,json=volumeIds" json:"volume_ids,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -1159,86 +1167,87 @@ var _SeaweedFiler_serviceDesc = grpc.ServiceDesc{
|
||||||
func init() { proto.RegisterFile("filer.proto", fileDescriptor0) }
|
func init() { proto.RegisterFile("filer.proto", fileDescriptor0) }
|
||||||
|
|
||||||
var fileDescriptor0 = []byte{
|
var fileDescriptor0 = []byte{
|
||||||
// 1291 bytes of a gzipped FileDescriptorProto
|
// 1301 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x57, 0x4d, 0x8f, 0xdc, 0x44,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x57, 0x4d, 0x8f, 0xd3, 0xc6,
|
||||||
0x13, 0x8e, 0xe7, 0x2b, 0xe3, 0x9a, 0x99, 0xbc, 0xbb, 0x3d, 0xfb, 0x12, 0x6b, 0xb2, 0x1b, 0x26,
|
0x1b, 0xc7, 0x79, 0x23, 0x7e, 0x92, 0xf0, 0xdf, 0x9d, 0xec, 0xbf, 0x58, 0x61, 0x97, 0x06, 0xb7,
|
||||||
0x86, 0xa0, 0x8d, 0x88, 0x46, 0x51, 0xe0, 0x90, 0x10, 0x21, 0x91, 0x6c, 0x36, 0x52, 0xa4, 0x4d,
|
0x54, 0x8b, 0x8a, 0x22, 0x44, 0x7b, 0x80, 0xa2, 0x4a, 0x85, 0x65, 0x91, 0x90, 0x16, 0xa8, 0xbc,
|
||||||
0x82, 0xbc, 0x09, 0x12, 0xe2, 0x60, 0x79, 0xed, 0x9e, 0xa1, 0xb5, 0x1e, 0x7b, 0x70, 0xb7, 0x37,
|
0x50, 0xa9, 0xea, 0xc1, 0xf2, 0xda, 0x93, 0x30, 0x5a, 0xc7, 0x4e, 0x3d, 0xe3, 0x05, 0xfa, 0x11,
|
||||||
0x09, 0x7f, 0x82, 0x0b, 0x57, 0x0e, 0x9c, 0xf8, 0x17, 0x5c, 0xf8, 0x3f, 0xdc, 0xb9, 0xa1, 0xae,
|
0x7a, 0xe9, 0xa5, 0xd7, 0x1e, 0x7a, 0xea, 0xb7, 0xe8, 0xa5, 0xdf, 0xa7, 0xf7, 0xde, 0xaa, 0x79,
|
||||||
0x6e, 0x7b, 0xda, 0x63, 0xef, 0x06, 0x84, 0x72, 0xeb, 0x7e, 0xaa, 0xba, 0xbe, 0xfa, 0xe9, 0x2a,
|
0x66, 0xec, 0x8c, 0x63, 0x2f, 0xb4, 0xaa, 0xb8, 0xcd, 0xfc, 0x9e, 0xf7, 0x67, 0x9e, 0x17, 0x1b,
|
||||||
0x1b, 0x06, 0x73, 0x16, 0xd3, 0x6c, 0xb6, 0xca, 0x52, 0x91, 0x92, 0x3e, 0x6e, 0xfc, 0xd5, 0x89,
|
0x06, 0x73, 0x16, 0xd3, 0x6c, 0xb6, 0xca, 0x52, 0x91, 0x92, 0x3e, 0x5e, 0xfc, 0xd5, 0x89, 0xfb,
|
||||||
0xfb, 0x02, 0xae, 0x1d, 0xa5, 0xe9, 0x69, 0xbe, 0x7a, 0xcc, 0x32, 0x1a, 0x8a, 0x34, 0x7b, 0x7b,
|
0x0c, 0xae, 0x1c, 0xa5, 0xe9, 0x69, 0xbe, 0x7a, 0xc8, 0x32, 0x1a, 0x8a, 0x34, 0x7b, 0x73, 0x98,
|
||||||
0x98, 0x88, 0xec, 0xad, 0x47, 0x7f, 0xc8, 0x29, 0x17, 0x64, 0x17, 0xec, 0xa8, 0x10, 0x38, 0xd6,
|
0x88, 0xec, 0x8d, 0x47, 0xbf, 0xcf, 0x29, 0x17, 0x64, 0x17, 0xec, 0xa8, 0x20, 0x38, 0xd6, 0xd4,
|
||||||
0xd4, 0xda, 0xb7, 0xbd, 0x35, 0x40, 0x08, 0x74, 0x92, 0x60, 0x49, 0x9d, 0x16, 0x0a, 0x70, 0xed,
|
0xda, 0xb7, 0xbd, 0x35, 0x40, 0x08, 0x74, 0x92, 0x60, 0x49, 0x9d, 0x16, 0x12, 0xf0, 0xec, 0x1e,
|
||||||
0x1e, 0xc2, 0x6e, 0xb3, 0x41, 0xbe, 0x4a, 0x13, 0x4e, 0xc9, 0x4d, 0xe8, 0x52, 0x09, 0xa0, 0xb5,
|
0xc2, 0x6e, 0xb3, 0x42, 0xbe, 0x4a, 0x13, 0x4e, 0xc9, 0x75, 0xe8, 0x52, 0x09, 0xa0, 0xb6, 0xc1,
|
||||||
0xc1, 0xdd, 0xff, 0xcd, 0x8a, 0x50, 0x66, 0x4a, 0x4f, 0x49, 0xdd, 0xdf, 0x2d, 0x20, 0x47, 0x8c,
|
0xed, 0xff, 0xcd, 0x0a, 0x57, 0x66, 0x8a, 0x4f, 0x51, 0xdd, 0xdf, 0x2d, 0x20, 0x47, 0x8c, 0x0b,
|
||||||
0x0b, 0x09, 0x32, 0xca, 0xff, 0x59, 0x3c, 0x1f, 0x40, 0x6f, 0x95, 0xd1, 0x39, 0x7b, 0xa3, 0x23,
|
0x09, 0x32, 0xca, 0xff, 0x99, 0x3f, 0x1f, 0x40, 0x6f, 0x95, 0xd1, 0x39, 0x7b, 0xad, 0x3d, 0xd2,
|
||||||
0xd2, 0x3b, 0x72, 0x1b, 0xb6, 0xb9, 0x08, 0x32, 0xf1, 0x24, 0x4b, 0x97, 0x4f, 0x58, 0x4c, 0x9f,
|
0x37, 0x72, 0x13, 0xb6, 0xb9, 0x08, 0x32, 0xf1, 0x28, 0x4b, 0x97, 0x8f, 0x58, 0x4c, 0x9f, 0x4a,
|
||||||
0xcb, 0xa0, 0xdb, 0xa8, 0x52, 0x17, 0x90, 0x19, 0x10, 0x96, 0x84, 0x71, 0xce, 0xd9, 0x19, 0x3d,
|
0xa7, 0xdb, 0xc8, 0x52, 0x27, 0x90, 0x19, 0x10, 0x96, 0x84, 0x71, 0xce, 0xd9, 0x19, 0x3d, 0x2e,
|
||||||
0x2e, 0xa4, 0x4e, 0x67, 0x6a, 0xed, 0xf7, 0xbd, 0x06, 0x09, 0xd9, 0x81, 0x6e, 0xcc, 0x96, 0x4c,
|
0xa8, 0x4e, 0x67, 0x6a, 0xed, 0xf7, 0xbd, 0x06, 0x0a, 0xd9, 0x81, 0x6e, 0xcc, 0x96, 0x4c, 0x38,
|
||||||
0x38, 0xdd, 0xa9, 0xb5, 0x3f, 0xf2, 0xd4, 0xc6, 0xfd, 0x0a, 0xc6, 0x95, 0xf8, 0x75, 0xfa, 0xb7,
|
0xdd, 0xa9, 0xb5, 0x3f, 0xf2, 0xd4, 0xc5, 0xfd, 0x0a, 0xc6, 0x15, 0xff, 0x75, 0xf8, 0x37, 0xe0,
|
||||||
0xe0, 0x32, 0x55, 0x90, 0x63, 0x4d, 0xdb, 0x4d, 0x05, 0x28, 0xe4, 0xee, 0x2f, 0x2d, 0xe8, 0x22,
|
0x22, 0x55, 0x90, 0x63, 0x4d, 0xdb, 0x4d, 0x09, 0x28, 0xe8, 0xee, 0x2f, 0x2d, 0xe8, 0x22, 0x54,
|
||||||
0x54, 0xd6, 0xd9, 0x5a, 0xd7, 0x99, 0xdc, 0x80, 0x21, 0xe3, 0xfe, 0xba, 0x18, 0x2d, 0x8c, 0x6f,
|
0xe6, 0xd9, 0x5a, 0xe7, 0x99, 0x5c, 0x83, 0x21, 0xe3, 0xfe, 0x3a, 0x19, 0x2d, 0xf4, 0x6f, 0xc0,
|
||||||
0xc0, 0x78, 0x59, 0x77, 0xf2, 0x29, 0xf4, 0xc2, 0xef, 0xf3, 0xe4, 0x94, 0x3b, 0x6d, 0x74, 0x35,
|
0x78, 0x99, 0x77, 0xf2, 0x29, 0xf4, 0xc2, 0x97, 0x79, 0x72, 0xca, 0x9d, 0x36, 0x9a, 0x1a, 0xaf,
|
||||||
0x5e, 0xbb, 0x92, 0xc9, 0x1e, 0x48, 0x99, 0xa7, 0x55, 0xc8, 0x3d, 0x80, 0x40, 0x88, 0x8c, 0x9d,
|
0x4d, 0xc9, 0x60, 0x0f, 0x24, 0xcd, 0xd3, 0x2c, 0xe4, 0x0e, 0x40, 0x20, 0x44, 0xc6, 0x4e, 0x72,
|
||||||
0xe4, 0x82, 0x72, 0xcc, 0x76, 0x70, 0xd7, 0x31, 0x0e, 0xe4, 0x9c, 0x3e, 0x2c, 0xe5, 0x9e, 0xa1,
|
0x41, 0x39, 0x46, 0x3b, 0xb8, 0xed, 0x18, 0x02, 0x39, 0xa7, 0xf7, 0x4b, 0xba, 0x67, 0xf0, 0x92,
|
||||||
0x4b, 0xee, 0x43, 0x9f, 0xbe, 0x11, 0x34, 0x89, 0x68, 0xe4, 0x74, 0xd1, 0xd1, 0xde, 0x46, 0x4e,
|
0xbb, 0xd0, 0xa7, 0xaf, 0x05, 0x4d, 0x22, 0x1a, 0x39, 0x5d, 0x34, 0xb4, 0xb7, 0x11, 0xd3, 0xec,
|
||||||
0xb3, 0x43, 0x2d, 0x57, 0x19, 0x96, 0xea, 0x93, 0x07, 0x30, 0xaa, 0x88, 0xc8, 0x16, 0xb4, 0x4f,
|
0x50, 0xd3, 0x55, 0x84, 0x25, 0xfb, 0xe4, 0x1e, 0x8c, 0x2a, 0x24, 0xb2, 0x05, 0xed, 0x53, 0x5a,
|
||||||
0x69, 0x71, 0xb3, 0x72, 0x29, 0xab, 0x7b, 0x16, 0xc4, 0xb9, 0x22, 0xd9, 0xd0, 0x53, 0x9b, 0x2f,
|
0xbc, 0xac, 0x3c, 0xca, 0xec, 0x9e, 0x05, 0x71, 0xae, 0x8a, 0x6c, 0xe8, 0xa9, 0xcb, 0x17, 0xad,
|
||||||
0x5a, 0xf7, 0x2c, 0xf7, 0x67, 0x0b, 0xb6, 0x0f, 0xcf, 0x68, 0x22, 0x9e, 0xa7, 0x82, 0xcd, 0x59,
|
0x3b, 0x96, 0xfb, 0xb3, 0x05, 0xdb, 0x87, 0x67, 0x34, 0x11, 0x4f, 0x53, 0xc1, 0xe6, 0x2c, 0x0c,
|
||||||
0x18, 0x08, 0x96, 0x26, 0xe4, 0x36, 0xd8, 0x69, 0x1c, 0xf9, 0x17, 0x72, 0xac, 0x9f, 0xc6, 0xda,
|
0x04, 0x4b, 0x13, 0x72, 0x13, 0xec, 0x34, 0x8e, 0xfc, 0xb7, 0xd6, 0x58, 0x3f, 0x8d, 0xb5, 0xbd,
|
||||||
0xdf, 0x6d, 0xb0, 0x13, 0xfa, 0x5a, 0x6b, 0xb7, 0xce, 0xd1, 0x4e, 0xe8, 0x6b, 0xa5, 0xfd, 0x11,
|
0x9b, 0x60, 0x27, 0xf4, 0x95, 0xe6, 0x6e, 0x9d, 0xc3, 0x9d, 0xd0, 0x57, 0x8a, 0xfb, 0x23, 0x18,
|
||||||
0x8c, 0x22, 0x1a, 0x53, 0x41, 0xfd, 0xb2, 0xae, 0xb2, 0xe8, 0x43, 0x05, 0x62, 0x3d, 0xb9, 0xfb,
|
0x45, 0x34, 0xa6, 0x82, 0xfa, 0x65, 0x5e, 0x65, 0xd2, 0x87, 0x0a, 0xc4, 0x7c, 0x72, 0xf7, 0x57,
|
||||||
0xab, 0x05, 0x76, 0x59, 0x5e, 0x72, 0x15, 0x2e, 0x4b, 0x73, 0x3e, 0x8b, 0x74, 0x52, 0x3d, 0xb9,
|
0x0b, 0xec, 0x32, 0xbd, 0xe4, 0x32, 0x5c, 0x94, 0xea, 0x7c, 0x16, 0xe9, 0xa0, 0x7a, 0xf2, 0xfa,
|
||||||
0x7d, 0x1a, 0x49, 0xae, 0xa6, 0xf3, 0x39, 0xa7, 0x02, 0xdd, 0xb6, 0x3d, 0xbd, 0x93, 0x77, 0xcd,
|
0x38, 0x92, 0xb5, 0x9a, 0xce, 0xe7, 0x9c, 0x0a, 0x34, 0xdb, 0xf6, 0xf4, 0x4d, 0xbe, 0x35, 0x67,
|
||||||
0xd9, 0x8f, 0x8a, 0x9e, 0x1d, 0x0f, 0xd7, 0xb2, 0x06, 0x4b, 0xc1, 0x96, 0x14, 0xaf, 0xa5, 0xed,
|
0x3f, 0xa8, 0xf2, 0xec, 0x78, 0x78, 0x96, 0x39, 0x58, 0x0a, 0xb6, 0xa4, 0xf8, 0x2c, 0x6d, 0x4f,
|
||||||
0xa9, 0x0d, 0x19, 0x43, 0x97, 0xfa, 0x22, 0x58, 0x20, 0xef, 0x6c, 0xaf, 0x43, 0x5f, 0x06, 0x0b,
|
0x5d, 0xc8, 0x18, 0xba, 0xd4, 0x17, 0xc1, 0x02, 0xeb, 0xce, 0xf6, 0x3a, 0xf4, 0x79, 0xb0, 0x20,
|
||||||
0xf2, 0x31, 0x5c, 0xe1, 0x69, 0x9e, 0x85, 0xd4, 0x2f, 0xdc, 0xf6, 0x50, 0x3a, 0x54, 0xe8, 0x13,
|
0x1f, 0xc3, 0x25, 0x9e, 0xe6, 0x59, 0x48, 0xfd, 0xc2, 0x6c, 0x0f, 0xa9, 0x43, 0x85, 0x3e, 0x42,
|
||||||
0x74, 0xee, 0xfe, 0xd9, 0x82, 0x2b, 0xd5, 0x1b, 0x25, 0xd7, 0xc0, 0xc6, 0x13, 0xe8, 0xdc, 0x42,
|
0xe3, 0xee, 0x9f, 0x2d, 0xb8, 0x54, 0x7d, 0x51, 0x72, 0x05, 0x6c, 0x94, 0x40, 0xe3, 0x16, 0x1a,
|
||||||
0xe7, 0xd8, 0x25, 0x8e, 0x2b, 0x01, 0xb4, 0xcc, 0x00, 0x8a, 0x23, 0xcb, 0x34, 0x52, 0xf1, 0x8e,
|
0xc7, 0x29, 0x71, 0x5c, 0x71, 0xa0, 0x65, 0x3a, 0x50, 0x88, 0x2c, 0xd3, 0x48, 0xf9, 0x3b, 0x52,
|
||||||
0xd4, 0x91, 0x67, 0x69, 0x44, 0xe5, 0x4d, 0xe6, 0x2c, 0xc2, 0x88, 0x47, 0x9e, 0x5c, 0x4a, 0x64,
|
0x22, 0x4f, 0xd2, 0x88, 0xca, 0x97, 0xcc, 0x59, 0x84, 0x1e, 0x8f, 0x3c, 0x79, 0x94, 0xc8, 0x82,
|
||||||
0xc1, 0x22, 0xfd, 0x4a, 0xe4, 0x52, 0xd6, 0x20, 0xcc, 0xd0, 0x6e, 0x4f, 0xd5, 0x40, 0xed, 0x64,
|
0x45, 0xba, 0x4b, 0xe4, 0x51, 0xe6, 0x20, 0xcc, 0x50, 0x6f, 0x4f, 0xe5, 0x40, 0xdd, 0x64, 0x0e,
|
||||||
0x0d, 0x96, 0x12, 0xbd, 0xac, 0x12, 0x93, 0x6b, 0x32, 0x85, 0x41, 0x46, 0x57, 0xb1, 0xbe, 0x66,
|
0x96, 0x12, 0xbd, 0xa8, 0x02, 0x93, 0x67, 0x32, 0x85, 0x41, 0x46, 0x57, 0xb1, 0x7e, 0x66, 0xa7,
|
||||||
0xa7, 0x8f, 0x22, 0x13, 0x22, 0xd7, 0x01, 0xc2, 0x34, 0x8e, 0x69, 0x88, 0x0a, 0x36, 0x2a, 0x18,
|
0x8f, 0x24, 0x13, 0x22, 0x57, 0x01, 0xc2, 0x34, 0x8e, 0x69, 0x88, 0x0c, 0x36, 0x32, 0x18, 0x88,
|
||||||
0x88, 0xbc, 0x0a, 0x21, 0x62, 0x9f, 0xd3, 0xd0, 0x81, 0xa9, 0xb5, 0xdf, 0xf5, 0x7a, 0x42, 0xc4,
|
0x7c, 0x0a, 0x21, 0x62, 0x9f, 0xd3, 0xd0, 0x81, 0xa9, 0xb5, 0xdf, 0xf5, 0x7a, 0x42, 0xc4, 0xc7,
|
||||||
0xc7, 0x34, 0x94, 0x79, 0xe4, 0x9c, 0x66, 0x3e, 0xbe, 0xb1, 0x01, 0x9e, 0xeb, 0x4b, 0x00, 0xbb,
|
0x34, 0x94, 0x71, 0xe4, 0x9c, 0x66, 0x3e, 0xf6, 0xd8, 0x00, 0xe5, 0xfa, 0x12, 0xc0, 0x69, 0xb0,
|
||||||
0xc1, 0x1e, 0xc0, 0x22, 0x4b, 0xf3, 0x95, 0x92, 0x0e, 0xa7, 0x6d, 0xd9, 0x72, 0x10, 0x41, 0xf1,
|
0x07, 0xb0, 0xc8, 0xd2, 0x7c, 0xa5, 0xa8, 0xc3, 0x69, 0x5b, 0x8e, 0x1c, 0x44, 0x90, 0x7c, 0x1d,
|
||||||
0x4d, 0xb8, 0xc2, 0xdf, 0x2e, 0x63, 0x96, 0x9c, 0xfa, 0x22, 0xc8, 0x16, 0x54, 0x38, 0x23, 0x34,
|
0x2e, 0xf1, 0x37, 0xcb, 0x98, 0x25, 0xa7, 0xbe, 0x08, 0xb2, 0x05, 0x15, 0xce, 0x08, 0x15, 0x8c,
|
||||||
0x30, 0xd2, 0xe8, 0x4b, 0x04, 0xdd, 0x6f, 0x81, 0x1c, 0x64, 0x34, 0x10, 0xf4, 0x5f, 0x74, 0xd7,
|
0x34, 0xfa, 0x1c, 0x41, 0xf7, 0x5b, 0x20, 0x07, 0x19, 0x0d, 0x04, 0xfd, 0x17, 0xd3, 0xb5, 0x9c,
|
||||||
0xb2, 0x53, 0xb6, 0x2e, 0xec, 0x94, 0xff, 0x87, 0x71, 0xc5, 0xb4, 0x6a, 0x34, 0xd2, 0xe3, 0xab,
|
0x94, 0xad, 0xb7, 0x4e, 0xca, 0xff, 0xc3, 0xb8, 0xa2, 0x5a, 0x0d, 0x1a, 0x69, 0xf1, 0xc5, 0x2a,
|
||||||
0x55, 0xf4, 0xbe, 0x3c, 0x56, 0x4c, 0x6b, 0x8f, 0x3f, 0x59, 0x40, 0x1e, 0xe3, 0x4b, 0xf8, 0x6f,
|
0x7a, 0x5f, 0x16, 0x2b, 0xaa, 0xb5, 0xc5, 0x9f, 0x2c, 0x20, 0x0f, 0xb1, 0x13, 0xfe, 0xdb, 0x0a,
|
||||||
0x23, 0x44, 0x72, 0x58, 0xb6, 0x36, 0xf5, 0xd2, 0xa2, 0x40, 0x04, 0xba, 0xf9, 0x0e, 0x19, 0x57,
|
0x91, 0x35, 0x2c, 0x47, 0x9b, 0xea, 0xb4, 0x28, 0x10, 0x81, 0x1e, 0xbe, 0x43, 0xc6, 0x95, 0xfe,
|
||||||
0xf6, 0x1f, 0x07, 0x22, 0xd0, 0x0d, 0x30, 0xa3, 0x61, 0x9e, 0xc9, 0x7e, 0x8c, 0xbc, 0xc2, 0x06,
|
0x87, 0x81, 0x08, 0xf4, 0x00, 0xcc, 0x68, 0x98, 0x67, 0x72, 0x1e, 0x63, 0x5d, 0xe1, 0x00, 0xf4,
|
||||||
0xe8, 0x15, 0x90, 0x0c, 0xb4, 0x12, 0x90, 0x0e, 0xf4, 0x37, 0x0b, 0xc6, 0x0f, 0x39, 0x67, 0x8b,
|
0x0a, 0x48, 0x3a, 0x5a, 0x71, 0x48, 0x3b, 0xfa, 0x9b, 0x05, 0xe3, 0xfb, 0x9c, 0xb3, 0x45, 0xf2,
|
||||||
0xe4, 0x9b, 0x34, 0xce, 0x97, 0xb4, 0x88, 0x74, 0x07, 0xba, 0x61, 0x9a, 0x27, 0x02, 0xa3, 0xec,
|
0x4d, 0x1a, 0xe7, 0x4b, 0x5a, 0x78, 0xba, 0x03, 0xdd, 0x30, 0xcd, 0x13, 0x81, 0x5e, 0x76, 0x3d,
|
||||||
0x7a, 0x6a, 0xb3, 0x41, 0xab, 0x56, 0x8d, 0x56, 0x1b, 0xc4, 0x6c, 0xd7, 0x89, 0x69, 0x10, 0xaf,
|
0x75, 0xd9, 0x28, 0xab, 0x56, 0xad, 0xac, 0x36, 0x0a, 0xb3, 0x5d, 0x2f, 0x4c, 0xa3, 0xf0, 0x3a,
|
||||||
0x53, 0x21, 0xde, 0x87, 0x30, 0x90, 0xe9, 0xf9, 0x21, 0x4d, 0x04, 0xcd, 0xf4, 0x3b, 0x06, 0x09,
|
0x95, 0xc2, 0xfb, 0x10, 0x06, 0x32, 0x3c, 0x3f, 0xa4, 0x89, 0xa0, 0x99, 0xee, 0x63, 0x90, 0xd0,
|
||||||
0x1d, 0x20, 0xe2, 0x9e, 0xc1, 0x4e, 0x35, 0x50, 0x3d, 0x45, 0xce, 0xed, 0x2a, 0xf2, 0xd5, 0x65,
|
0x01, 0x22, 0xee, 0x8f, 0x16, 0xec, 0x54, 0x3d, 0xd5, 0x6b, 0xe4, 0xdc, 0xb1, 0x22, 0xdb, 0x2e,
|
||||||
0xb1, 0x8e, 0x52, 0x2e, 0x25, 0x7f, 0x57, 0xf9, 0x49, 0xcc, 0x42, 0x5f, 0x0a, 0x54, 0x74, 0xb6,
|
0x8b, 0xb5, 0x9b, 0xf2, 0x28, 0x0b, 0x78, 0x95, 0x9f, 0xc4, 0x2c, 0xf4, 0x25, 0x41, 0xb9, 0x67,
|
||||||
0x42, 0x5e, 0x65, 0xf1, 0x3a, 0xe7, 0x8e, 0x91, 0xb3, 0xfb, 0x39, 0x8c, 0xd5, 0x10, 0xaf, 0x16,
|
0x2b, 0xe4, 0x45, 0x16, 0xaf, 0x83, 0xee, 0x98, 0x41, 0x13, 0xe8, 0x04, 0xb9, 0x78, 0x59, 0x8c,
|
||||||
0x68, 0x0f, 0xe0, 0x0c, 0x01, 0x9f, 0x45, 0x6a, 0x7e, 0xd9, 0x9e, 0xad, 0x90, 0xa7, 0x11, 0x77,
|
0x16, 0x79, 0x76, 0x3f, 0x87, 0xb1, 0xda, 0xec, 0xd5, 0xac, 0xed, 0x01, 0x9c, 0x21, 0xe0, 0xb3,
|
||||||
0xbf, 0x04, 0xfb, 0x28, 0x55, 0x39, 0x73, 0x72, 0x07, 0xec, 0xb8, 0xd8, 0xe8, 0x51, 0x47, 0xd6,
|
0x48, 0x2d, 0x35, 0xdb, 0xb3, 0x15, 0xf2, 0x38, 0xe2, 0xee, 0x97, 0x60, 0x1f, 0xa5, 0x2a, 0x11,
|
||||||
0x7c, 0x2a, 0xf4, 0xbc, 0xb5, 0x92, 0xfb, 0x00, 0xfa, 0x05, 0x5c, 0xe4, 0x61, 0x9d, 0x97, 0x47,
|
0x9c, 0xdc, 0x02, 0x3b, 0x2e, 0x2e, 0x7a, 0xff, 0x91, 0x75, 0x91, 0x15, 0x7c, 0xde, 0x9a, 0xc9,
|
||||||
0x6b, 0x23, 0x0f, 0xf7, 0x0f, 0x0b, 0x76, 0xaa, 0x21, 0xeb, 0x52, 0xbd, 0x82, 0x51, 0xe9, 0xc2,
|
0xbd, 0x07, 0xfd, 0x02, 0x2e, 0x62, 0xb3, 0xce, 0x8b, 0xad, 0xb5, 0x11, 0x9b, 0xfb, 0x87, 0x05,
|
||||||
0x5f, 0x06, 0x2b, 0x1d, 0xcb, 0x1d, 0x33, 0x96, 0xfa, 0xb1, 0x32, 0x40, 0xfe, 0x2c, 0x58, 0x29,
|
0x3b, 0x55, 0x97, 0x75, 0xfa, 0x5e, 0xc0, 0xa8, 0x34, 0xe1, 0x2f, 0x83, 0x95, 0xf6, 0xe5, 0x96,
|
||||||
0xf6, 0x0c, 0x63, 0x03, 0x9a, 0xbc, 0x84, 0xed, 0x9a, 0x4a, 0xc3, 0xf4, 0xba, 0x65, 0x4e, 0xaf,
|
0xe9, 0x4b, 0x5d, 0xac, 0x74, 0x90, 0x3f, 0x09, 0x56, 0xaa, 0xa4, 0x86, 0xb1, 0x01, 0x4d, 0x9e,
|
||||||
0xca, 0x04, 0x2e, 0x4f, 0x9b, 0x23, 0xed, 0x3e, 0x5c, 0x55, 0x84, 0x3d, 0x28, 0xf9, 0x55, 0xd4,
|
0xc3, 0x76, 0x8d, 0xa5, 0x61, 0xa5, 0xdd, 0x30, 0x57, 0x5a, 0x65, 0x2d, 0x97, 0xd2, 0xe6, 0x9e,
|
||||||
0xbe, 0x4a, 0x43, 0x6b, 0x93, 0x86, 0xee, 0x04, 0x9c, 0xfa, 0x51, 0x4d, 0xf8, 0x05, 0x6c, 0x1f,
|
0xbb, 0x0b, 0x97, 0x55, 0x15, 0x1f, 0x94, 0x45, 0x57, 0xe4, 0xbe, 0x5a, 0x9b, 0xd6, 0x66, 0x6d,
|
||||||
0x8b, 0x40, 0x30, 0x2e, 0x58, 0x58, 0x7e, 0x4a, 0x6d, 0xf0, 0xd6, 0x7a, 0x57, 0x43, 0xad, 0x33,
|
0xba, 0x13, 0x70, 0xea, 0xa2, 0xba, 0x0b, 0x16, 0xb0, 0x7d, 0x2c, 0x02, 0xc1, 0xb8, 0x60, 0x61,
|
||||||
0x7f, 0x0b, 0xda, 0x42, 0x14, 0x9c, 0x92, 0x4b, 0x79, 0x0b, 0xc4, 0xf4, 0xa4, 0xef, 0xe0, 0x3d,
|
0xf9, 0x7d, 0xb5, 0x51, 0xcc, 0xd6, 0xbb, 0xa6, 0x6c, 0xbd, 0x1d, 0xb6, 0xa0, 0x2d, 0x44, 0x51,
|
||||||
0xb8, 0x92, 0x7c, 0x10, 0xa9, 0x08, 0x62, 0x35, 0xb0, 0x3a, 0x38, 0xb0, 0x6c, 0x44, 0x70, 0x62,
|
0x67, 0xf2, 0x28, 0x5f, 0x81, 0x98, 0x96, 0xf4, 0x1b, 0xbc, 0x07, 0x53, 0xb2, 0x1e, 0x44, 0x2a,
|
||||||
0xa9, 0x9e, 0x1e, 0x29, 0x69, 0x57, 0x8d, 0x33, 0x09, 0xa0, 0x70, 0x0f, 0x00, 0x9f, 0x8f, 0x62,
|
0x82, 0x58, 0x6d, 0xb1, 0x0e, 0x6e, 0x31, 0x1b, 0x11, 0x5c, 0x63, 0x6a, 0xd0, 0x47, 0x8a, 0xda,
|
||||||
0x7e, 0x4f, 0x9d, 0x95, 0xc8, 0x81, 0x04, 0xee, 0xfe, 0xd5, 0x85, 0xe1, 0x31, 0x0d, 0x5e, 0x53,
|
0x55, 0x3b, 0x4e, 0x02, 0x48, 0xdc, 0x03, 0xc0, 0x96, 0x52, 0xdd, 0xd0, 0x53, 0xb2, 0x12, 0x39,
|
||||||
0x1a, 0xc9, 0x79, 0x99, 0x91, 0x45, 0xc1, 0xad, 0xea, 0x37, 0x2d, 0xb9, 0xb9, 0x49, 0xa2, 0xc6,
|
0x90, 0xc0, 0xed, 0xbf, 0xba, 0x30, 0x3c, 0xa6, 0xc1, 0x2b, 0x4a, 0x23, 0xb9, 0x44, 0x33, 0xb2,
|
||||||
0x8f, 0xe8, 0xc9, 0x27, 0xef, 0x52, 0xd3, 0xd7, 0x74, 0x89, 0x1c, 0xc1, 0xc0, 0xf8, 0x68, 0x24,
|
0x28, 0x6a, 0xab, 0xfa, 0xa1, 0x4b, 0xae, 0x6f, 0x16, 0x51, 0xe3, 0x97, 0xf5, 0xe4, 0x93, 0x77,
|
||||||
0xbb, 0xc6, 0xc1, 0xda, 0xb7, 0xf0, 0x64, 0xef, 0x1c, 0xa9, 0x69, 0xcd, 0x98, 0x0c, 0xa6, 0xb5,
|
0xb1, 0xe9, 0x67, 0xba, 0x40, 0x8e, 0x60, 0x60, 0x7c, 0x49, 0x92, 0x5d, 0x43, 0xb0, 0xf6, 0x81,
|
||||||
0xfa, 0x2c, 0x32, 0xad, 0x35, 0x8d, 0x13, 0xb4, 0x66, 0x74, 0x7d, 0xd3, 0x5a, 0x7d, 0xce, 0x98,
|
0x3c, 0xd9, 0x3b, 0x87, 0x6a, 0x6a, 0x33, 0xd6, 0x85, 0xa9, 0xad, 0xbe, 0xa0, 0x4c, 0x6d, 0x4d,
|
||||||
0xd6, 0x9a, 0x46, 0x05, 0x5a, 0x33, 0x5a, 0xb3, 0x69, 0xad, 0x3e, 0x42, 0x4c, 0x6b, 0x4d, 0xfd,
|
0x3b, 0x06, 0xb5, 0x19, 0xab, 0xc0, 0xd4, 0x56, 0x5f, 0x3e, 0xa6, 0xb6, 0xa6, 0xfd, 0x81, 0xda,
|
||||||
0xfc, 0x12, 0x79, 0x01, 0x43, 0xb3, 0x4f, 0x12, 0xe3, 0x40, 0x43, 0xa3, 0x9f, 0x5c, 0x3f, 0x4f,
|
0x8c, 0x79, 0x6d, 0x6a, 0xab, 0xef, 0x15, 0x53, 0x5b, 0xd3, 0x90, 0xbf, 0x40, 0x9e, 0xc1, 0xd0,
|
||||||
0x6c, 0x1a, 0x34, 0xdb, 0x82, 0x69, 0xb0, 0xa1, 0x31, 0x9a, 0x06, 0x9b, 0xba, 0x89, 0x7b, 0x89,
|
0x9c, 0x9d, 0xc4, 0x10, 0x68, 0x98, 0xfe, 0x93, 0xab, 0xe7, 0x91, 0x4d, 0x85, 0xe6, 0x58, 0x30,
|
||||||
0x7c, 0x07, 0x5b, 0x9b, 0xcf, 0x93, 0xdc, 0xd8, 0x4c, 0xab, 0xf6, 0xea, 0x27, 0xee, 0x45, 0x2a,
|
0x15, 0x36, 0x0c, 0x46, 0x53, 0x61, 0xd3, 0x34, 0x71, 0x2f, 0x90, 0xef, 0x60, 0x6b, 0xb3, 0x3d,
|
||||||
0xa5, 0xf1, 0xa7, 0x00, 0xeb, 0x57, 0x47, 0xae, 0xad, 0xcf, 0xd4, 0x5e, 0xfd, 0x64, 0xb7, 0x59,
|
0xc9, 0xb5, 0xcd, 0xb0, 0x6a, 0x5d, 0x3f, 0x71, 0xdf, 0xc6, 0x52, 0x2a, 0x7f, 0x0c, 0xb0, 0xee,
|
||||||
0x58, 0x98, 0x7a, 0x74, 0x1d, 0xb6, 0xb8, 0xa2, 0xfe, 0x9c, 0xcf, 0xc2, 0x98, 0xd1, 0x44, 0x3c,
|
0x3a, 0x72, 0x65, 0x2d, 0x53, 0xeb, 0xfa, 0xc9, 0x6e, 0x33, 0xb1, 0x50, 0xf5, 0xe0, 0x2a, 0x6c,
|
||||||
0x02, 0x7c, 0x05, 0x5f, 0xcb, 0x3f, 0xc7, 0x93, 0x1e, 0xfe, 0x40, 0x7e, 0xf6, 0x77, 0x00, 0x00,
|
0x71, 0x55, 0xfa, 0x73, 0x3e, 0x0b, 0x63, 0x46, 0x13, 0xf1, 0x00, 0xb0, 0x0b, 0xbe, 0x96, 0xbf,
|
||||||
0x00, 0xff, 0xff, 0x8d, 0x38, 0xa9, 0x9f, 0x4f, 0x0e, 0x00, 0x00,
|
0x93, 0x27, 0x3d, 0xfc, 0xab, 0xfc, 0xec, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8c, 0x6d, 0xf7,
|
||||||
|
0x42, 0x64, 0x0e, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,6 @@ message Heartbeat {
|
||||||
|
|
||||||
message HeartbeatResponse {
|
message HeartbeatResponse {
|
||||||
uint64 volumeSizeLimit = 1;
|
uint64 volumeSizeLimit = 1;
|
||||||
string secretKey = 2;
|
|
||||||
string leader = 3;
|
string leader = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +108,7 @@ message AssignResponse {
|
||||||
string public_url = 3;
|
string public_url = 3;
|
||||||
uint64 count = 4;
|
uint64 count = 4;
|
||||||
string error = 5;
|
string error = 5;
|
||||||
|
string auth = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message StatisticsRequest {
|
message StatisticsRequest {
|
||||||
|
|
|
@ -145,7 +145,6 @@ func (m *Heartbeat) GetDeletedVids() []uint32 {
|
||||||
|
|
||||||
type HeartbeatResponse struct {
|
type HeartbeatResponse struct {
|
||||||
VolumeSizeLimit uint64 `protobuf:"varint,1,opt,name=volumeSizeLimit" json:"volumeSizeLimit,omitempty"`
|
VolumeSizeLimit uint64 `protobuf:"varint,1,opt,name=volumeSizeLimit" json:"volumeSizeLimit,omitempty"`
|
||||||
SecretKey string `protobuf:"bytes,2,opt,name=secretKey" json:"secretKey,omitempty"`
|
|
||||||
Leader string `protobuf:"bytes,3,opt,name=leader" json:"leader,omitempty"`
|
Leader string `protobuf:"bytes,3,opt,name=leader" json:"leader,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,13 +160,6 @@ func (m *HeartbeatResponse) GetVolumeSizeLimit() uint64 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *HeartbeatResponse) GetSecretKey() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.SecretKey
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *HeartbeatResponse) GetLeader() string {
|
func (m *HeartbeatResponse) GetLeader() string {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
return m.Leader
|
return m.Leader
|
||||||
|
@ -545,6 +537,7 @@ type AssignResponse struct {
|
||||||
PublicUrl string `protobuf:"bytes,3,opt,name=public_url,json=publicUrl" json:"public_url,omitempty"`
|
PublicUrl string `protobuf:"bytes,3,opt,name=public_url,json=publicUrl" json:"public_url,omitempty"`
|
||||||
Count uint64 `protobuf:"varint,4,opt,name=count" json:"count,omitempty"`
|
Count uint64 `protobuf:"varint,4,opt,name=count" json:"count,omitempty"`
|
||||||
Error string `protobuf:"bytes,5,opt,name=error" json:"error,omitempty"`
|
Error string `protobuf:"bytes,5,opt,name=error" json:"error,omitempty"`
|
||||||
|
Auth string `protobuf:"bytes,6,opt,name=auth" json:"auth,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *AssignResponse) Reset() { *m = AssignResponse{} }
|
func (m *AssignResponse) Reset() { *m = AssignResponse{} }
|
||||||
|
@ -587,6 +580,13 @@ func (m *AssignResponse) GetError() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *AssignResponse) GetAuth() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Auth
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
type StatisticsRequest struct {
|
type StatisticsRequest struct {
|
||||||
Replication string `protobuf:"bytes,1,opt,name=replication" json:"replication,omitempty"`
|
Replication string `protobuf:"bytes,1,opt,name=replication" json:"replication,omitempty"`
|
||||||
Collection string `protobuf:"bytes,2,opt,name=collection" json:"collection,omitempty"`
|
Collection string `protobuf:"bytes,2,opt,name=collection" json:"collection,omitempty"`
|
||||||
|
@ -966,71 +966,71 @@ var _Seaweed_serviceDesc = grpc.ServiceDesc{
|
||||||
func init() { proto.RegisterFile("master.proto", fileDescriptor0) }
|
func init() { proto.RegisterFile("master.proto", fileDescriptor0) }
|
||||||
|
|
||||||
var fileDescriptor0 = []byte{
|
var fileDescriptor0 = []byte{
|
||||||
// 1055 bytes of a gzipped FileDescriptorProto
|
// 1056 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x56, 0x4b, 0x6f, 0xe4, 0x44,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x56, 0xcd, 0x6e, 0xe4, 0x44,
|
||||||
0x10, 0x5e, 0x7b, 0x9e, 0xae, 0xd9, 0xc9, 0x4e, 0x3a, 0x11, 0xf2, 0xce, 0xbe, 0x06, 0x73, 0x19,
|
0x10, 0x8e, 0x3d, 0xbf, 0xae, 0xc9, 0x64, 0x27, 0x9d, 0x08, 0x79, 0x67, 0xd9, 0xdd, 0xc1, 0x5c,
|
||||||
0x04, 0x8a, 0x96, 0x70, 0x44, 0x08, 0xb1, 0xd1, 0x22, 0xa2, 0x04, 0x36, 0x38, 0xb0, 0x07, 0x2e,
|
0x06, 0x81, 0xa2, 0x25, 0x1c, 0x11, 0x42, 0x6c, 0x14, 0x44, 0x94, 0xc0, 0x06, 0x87, 0xdd, 0x03,
|
||||||
0xa6, 0x63, 0x57, 0xa2, 0x56, 0xfc, 0xa2, 0xbb, 0x27, 0x99, 0xd9, 0x0b, 0x47, 0xfe, 0x15, 0x17,
|
0x17, 0xd3, 0xb1, 0x2b, 0xa1, 0x15, 0xff, 0xe1, 0x6e, 0x27, 0x33, 0x7b, 0xe1, 0xc8, 0x03, 0xf0,
|
||||||
0xb8, 0xf1, 0x53, 0xb8, 0xf1, 0x0b, 0x50, 0x3f, 0xec, 0xf1, 0x38, 0x09, 0x91, 0x90, 0xb8, 0xb5,
|
0x3e, 0x5c, 0xe0, 0xc6, 0xa3, 0x70, 0xe3, 0x09, 0x50, 0xff, 0xd8, 0xf1, 0x38, 0x19, 0x22, 0x21,
|
||||||
0xbf, 0xae, 0xee, 0xaa, 0xfe, 0xbe, 0x7a, 0x18, 0x1e, 0x66, 0x54, 0x48, 0xe4, 0x7b, 0x25, 0x2f,
|
0x71, 0xeb, 0xfe, 0xba, 0xba, 0xab, 0xfa, 0xfb, 0xaa, 0xaa, 0x1b, 0x36, 0x13, 0xca, 0x05, 0x16,
|
||||||
0x64, 0x41, 0x3c, 0xf3, 0x15, 0x95, 0x67, 0xc1, 0x5f, 0x2e, 0x78, 0x5f, 0x23, 0xe5, 0xf2, 0x0c,
|
0x7b, 0x79, 0x91, 0x89, 0x8c, 0x38, 0x7a, 0x16, 0xe4, 0xe7, 0xde, 0x5f, 0x36, 0x38, 0x5f, 0x21,
|
||||||
0xa9, 0x24, 0x5b, 0xe0, 0xb2, 0xd2, 0x77, 0x66, 0xce, 0xdc, 0x0b, 0x5d, 0x56, 0x12, 0x02, 0xdd,
|
0x2d, 0xc4, 0x39, 0x52, 0x41, 0xb6, 0xc0, 0x66, 0xb9, 0x6b, 0xcd, 0xac, 0xb9, 0xe3, 0xdb, 0x2c,
|
||||||
0xb2, 0xe0, 0xd2, 0x77, 0x67, 0xce, 0x7c, 0x1c, 0xea, 0x35, 0x79, 0x06, 0x50, 0x2e, 0xce, 0x52,
|
0x27, 0x04, 0xba, 0x79, 0x56, 0x08, 0xd7, 0x9e, 0x59, 0xf3, 0xb1, 0xaf, 0xc6, 0xe4, 0x29, 0x40,
|
||||||
0x16, 0x47, 0x0b, 0x9e, 0xfa, 0x1d, 0x6d, 0xeb, 0x19, 0xe4, 0x07, 0x9e, 0x92, 0x39, 0x4c, 0x32,
|
0x5e, 0x9e, 0xc7, 0x2c, 0x0c, 0xca, 0x22, 0x76, 0x3b, 0xca, 0xd6, 0xd1, 0xc8, 0xeb, 0x22, 0x26,
|
||||||
0xba, 0x8c, 0xae, 0x8a, 0x74, 0x91, 0x61, 0x14, 0x17, 0x8b, 0x5c, 0xfa, 0x5d, 0x7d, 0x7c, 0x2b,
|
0x73, 0x98, 0x24, 0x74, 0x11, 0x5c, 0x67, 0x71, 0x99, 0x60, 0x10, 0x66, 0x65, 0x2a, 0xdc, 0xae,
|
||||||
0xa3, 0xcb, 0xb7, 0x1a, 0x3e, 0x50, 0x28, 0x99, 0xa9, 0xa8, 0x96, 0xd1, 0x39, 0x4b, 0x31, 0xba,
|
0xda, 0xbe, 0x95, 0xd0, 0xc5, 0x1b, 0x05, 0x1f, 0x48, 0x94, 0xcc, 0x64, 0x54, 0x8b, 0xe0, 0x82,
|
||||||
0xc4, 0x95, 0xdf, 0x9b, 0x39, 0xf3, 0x6e, 0x08, 0x19, 0x5d, 0x7e, 0xc5, 0x52, 0x3c, 0xc2, 0x15,
|
0xc5, 0x18, 0x5c, 0xe1, 0xd2, 0xed, 0xcd, 0xac, 0x79, 0xd7, 0x87, 0x84, 0x2e, 0xbe, 0x64, 0x31,
|
||||||
0x79, 0x01, 0xa3, 0x84, 0x4a, 0x1a, 0xc5, 0x98, 0x4b, 0xe4, 0x7e, 0x5f, 0xfb, 0x02, 0x05, 0x1d,
|
0x1e, 0xe3, 0x92, 0x3c, 0x87, 0x51, 0x44, 0x05, 0x0d, 0x42, 0x4c, 0x05, 0x16, 0x6e, 0x5f, 0xf9,
|
||||||
0x68, 0x44, 0xc5, 0xc7, 0x69, 0x7c, 0xe9, 0x0f, 0xf4, 0x8e, 0x5e, 0xab, 0xf8, 0x68, 0x92, 0xb1,
|
0x02, 0x09, 0x1d, 0x28, 0x44, 0xc6, 0x57, 0xd0, 0xf0, 0xca, 0x1d, 0xa8, 0x15, 0x35, 0x96, 0xf1,
|
||||||
0x3c, 0xd2, 0x91, 0x0f, 0xb5, 0x6b, 0x4f, 0x23, 0x27, 0x2a, 0xfc, 0xcf, 0x61, 0x60, 0x62, 0x13,
|
0xd1, 0x28, 0x61, 0x69, 0xa0, 0x22, 0x1f, 0x2a, 0xd7, 0x8e, 0x42, 0x4e, 0x65, 0xf8, 0x9f, 0xc1,
|
||||||
0xbe, 0x37, 0xeb, 0xcc, 0x47, 0xfb, 0x1f, 0xec, 0xd5, 0x6c, 0xec, 0x99, 0xf0, 0x0e, 0xf3, 0xf3,
|
0x40, 0xc7, 0xc6, 0x5d, 0x67, 0xd6, 0x99, 0x8f, 0xf6, 0xdf, 0xdf, 0xab, 0xd9, 0xd8, 0xd3, 0xe1,
|
||||||
0x82, 0x67, 0x54, 0xb2, 0x22, 0xff, 0x06, 0x85, 0xa0, 0x17, 0x18, 0x56, 0x67, 0xc8, 0x63, 0x18,
|
0x1d, 0xa5, 0x17, 0x59, 0x91, 0x50, 0xc1, 0xb2, 0xf4, 0x6b, 0xe4, 0x9c, 0x5e, 0xa2, 0x5f, 0xed,
|
||||||
0xe6, 0x78, 0x1d, 0x5d, 0xb1, 0x44, 0xf8, 0x30, 0xeb, 0xcc, 0xc7, 0xe1, 0x20, 0xc7, 0xeb, 0xb7,
|
0x21, 0x8f, 0x61, 0x98, 0xe2, 0x4d, 0x70, 0xcd, 0x22, 0xee, 0xc2, 0xac, 0x33, 0x1f, 0xfb, 0x83,
|
||||||
0x2c, 0x11, 0xe4, 0x7d, 0x78, 0x98, 0x60, 0x8a, 0x12, 0x13, 0xb3, 0x3d, 0xd2, 0xdb, 0x23, 0x8b,
|
0x14, 0x6f, 0xde, 0xb0, 0x88, 0x93, 0xf7, 0x60, 0x33, 0xc2, 0x18, 0x05, 0x46, 0x7a, 0x79, 0xa4,
|
||||||
0x29, 0x93, 0x40, 0xc0, 0x76, 0x4d, 0x76, 0x88, 0xa2, 0x2c, 0x72, 0x81, 0x64, 0x0e, 0x8f, 0xcc,
|
0x96, 0x47, 0x06, 0x93, 0x26, 0xde, 0x6b, 0xd8, 0xae, 0xc9, 0xf6, 0x91, 0xe7, 0x59, 0xca, 0x91,
|
||||||
0xed, 0xa7, 0xec, 0x1d, 0x1e, 0xb3, 0x8c, 0x49, 0xad, 0x40, 0x37, 0x6c, 0xc3, 0xe4, 0x29, 0x78,
|
0xcc, 0xe1, 0x91, 0x3e, 0xfd, 0x8c, 0xbd, 0xc5, 0x13, 0x96, 0x30, 0xa1, 0x14, 0xe8, 0xfa, 0x6d,
|
||||||
0x02, 0x63, 0x8e, 0xf2, 0x08, 0x57, 0x5a, 0x13, 0x2f, 0x5c, 0x03, 0xe4, 0x3d, 0xe8, 0xa7, 0x48,
|
0x98, 0xbc, 0x03, 0xfd, 0x18, 0x69, 0x84, 0x85, 0xa1, 0xdd, 0xcc, 0xbc, 0x3f, 0x6c, 0x70, 0xd7,
|
||||||
0x13, 0xe4, 0x56, 0x14, 0xfb, 0x15, 0xfc, 0xe1, 0x82, 0x7f, 0xd7, 0xc3, 0xb4, 0xe2, 0x89, 0xf6,
|
0x85, 0xae, 0x34, 0x8d, 0xd4, 0x89, 0x63, 0xdf, 0x66, 0x91, 0xe4, 0x8c, 0xb3, 0xb7, 0xa8, 0x34,
|
||||||
0x37, 0x0e, 0x5d, 0x96, 0x28, 0x46, 0x05, 0x7b, 0x87, 0xfa, 0xf6, 0x6e, 0xa8, 0xd7, 0xe4, 0x39,
|
0xed, 0xfa, 0x6a, 0x4c, 0x9e, 0x01, 0x84, 0x59, 0x1c, 0x63, 0x28, 0x37, 0x9a, 0xc3, 0x1b, 0x88,
|
||||||
0x40, 0x5c, 0xa4, 0x29, 0xc6, 0xea, 0xa0, 0xbd, 0xbc, 0x81, 0x28, 0xc6, 0xb5, 0x88, 0x6b, 0xb1,
|
0xe4, 0x54, 0xc9, 0x74, 0x2b, 0x67, 0xd7, 0x77, 0x24, 0xa2, 0x95, 0xac, 0x6f, 0x6e, 0x0c, 0xb4,
|
||||||
0xbb, 0xa1, 0xa7, 0x10, 0xa3, 0x73, 0xcd, 0x8b, 0x35, 0x30, 0x3a, 0x5b, 0x5e, 0x8c, 0xc9, 0xc7,
|
0x92, 0xe6, 0xe6, 0xda, 0xe4, 0x23, 0x20, 0x15, 0x39, 0xe7, 0xcb, 0xda, 0xb0, 0xaf, 0x0c, 0x27,
|
||||||
0x40, 0x2a, 0xea, 0xce, 0x56, 0xb5, 0x61, 0x5f, 0x1b, 0x4e, 0xec, 0xce, 0xab, 0x55, 0x65, 0xfd,
|
0x66, 0xe5, 0xe5, 0xb2, 0xb2, 0x7e, 0x02, 0x4e, 0x81, 0x34, 0x0a, 0xb2, 0x34, 0x5e, 0x2a, 0x71,
|
||||||
0x04, 0x3c, 0x8e, 0x34, 0x89, 0x8a, 0x3c, 0x5d, 0x69, 0xe9, 0x87, 0xe1, 0x50, 0x01, 0x6f, 0xf2,
|
0x87, 0xfe, 0x50, 0x02, 0xaf, 0xd2, 0x78, 0x49, 0x3e, 0x84, 0xed, 0x02, 0xf3, 0x98, 0x85, 0x34,
|
||||||
0x74, 0x45, 0x3e, 0x82, 0x6d, 0x8e, 0x65, 0xca, 0x62, 0x1a, 0x95, 0x29, 0x8d, 0x31, 0xc3, 0xbc,
|
0xc8, 0x63, 0x1a, 0x62, 0x82, 0x69, 0xa5, 0xf3, 0xc4, 0x2c, 0x9c, 0x56, 0x38, 0x71, 0x61, 0x70,
|
||||||
0xca, 0x82, 0x89, 0xdd, 0x38, 0xa9, 0x70, 0xe2, 0xc3, 0xe0, 0x0a, 0xb9, 0x50, 0xcf, 0xf2, 0xb4,
|
0x8d, 0x05, 0x97, 0xd7, 0x72, 0x94, 0x49, 0x35, 0x25, 0x13, 0xe8, 0x08, 0x11, 0xbb, 0xa0, 0x50,
|
||||||
0x49, 0xf5, 0x49, 0x26, 0xd0, 0x91, 0x32, 0xf5, 0x41, 0xa3, 0x6a, 0x19, 0x0c, 0xa0, 0xf7, 0x3a,
|
0x39, 0xf4, 0x06, 0xd0, 0x3b, 0x4c, 0x72, 0xb1, 0xf4, 0x7e, 0xb3, 0xe0, 0xd1, 0x59, 0x99, 0x63,
|
||||||
0x2b, 0xe5, 0x2a, 0xf8, 0xcd, 0x81, 0x47, 0xa7, 0x8b, 0x12, 0xf9, 0xab, 0xb4, 0x88, 0x2f, 0x5f,
|
0xf1, 0x32, 0xce, 0xc2, 0xab, 0xc3, 0x85, 0x28, 0x28, 0x79, 0x05, 0x5b, 0x58, 0x50, 0x5e, 0x16,
|
||||||
0x2f, 0x25, 0xa7, 0xe4, 0x0d, 0x6c, 0x21, 0xa7, 0x62, 0xc1, 0x55, 0xec, 0x09, 0xcb, 0x2f, 0x34,
|
0x32, 0xf6, 0x88, 0xa5, 0x97, 0x8a, 0xd2, 0xd1, 0xfe, 0xbc, 0x91, 0x3e, 0xad, 0x3d, 0x7b, 0x87,
|
||||||
0xa5, 0xa3, 0xfd, 0x79, 0x23, 0xb9, 0x5a, 0x67, 0xf6, 0x5e, 0x9b, 0x03, 0x07, 0xda, 0x3e, 0x1c,
|
0x7a, 0xc3, 0x81, 0xb2, 0xf7, 0xc7, 0xd8, 0x9c, 0x4e, 0xbf, 0x87, 0xf1, 0xca, 0xba, 0x14, 0x46,
|
||||||
0x63, 0xf3, 0x73, 0xfa, 0x23, 0x8c, 0x37, 0xf6, 0x95, 0x30, 0x2a, 0xf1, 0xad, 0x54, 0x7a, 0xad,
|
0xa6, 0xb6, 0x91, 0x4a, 0x8d, 0xa5, 0xe2, 0x39, 0x2d, 0x98, 0x58, 0x9a, 0x12, 0x34, 0x33, 0x29,
|
||||||
0x14, 0x2f, 0x29, 0x67, 0x72, 0x65, 0x0b, 0xd4, 0x7e, 0x29, 0x41, 0x6c, 0xfd, 0xa9, 0x3c, 0xec,
|
0x88, 0xa9, 0x30, 0x99, 0x69, 0x1d, 0x95, 0x69, 0x8e, 0x46, 0x8e, 0x22, 0xee, 0x7d, 0x00, 0x3b,
|
||||||
0xe8, 0x3c, 0xf4, 0x0c, 0x72, 0x98, 0x88, 0xe0, 0x43, 0xd8, 0x39, 0x48, 0x19, 0xe6, 0xf2, 0x98,
|
0x07, 0x31, 0xc3, 0x54, 0x9c, 0x30, 0x2e, 0x30, 0xf5, 0xf1, 0xa7, 0x12, 0xb9, 0x90, 0x1e, 0x52,
|
||||||
0x09, 0x89, 0x79, 0x88, 0x3f, 0x2f, 0x50, 0x48, 0xe5, 0x21, 0xa7, 0x19, 0xda, 0xf2, 0xd7, 0xeb,
|
0x9a, 0xa0, 0x29, 0x70, 0x35, 0xf6, 0x7e, 0x86, 0x2d, 0x9d, 0x3a, 0x27, 0x59, 0xa8, 0xf2, 0x46,
|
||||||
0xe0, 0x17, 0xd8, 0x32, 0xa9, 0x73, 0x5c, 0xc4, 0x3a, 0x6f, 0x14, 0x31, 0xaa, 0xee, 0x8d, 0x91,
|
0x12, 0x23, 0x2b, 0x5b, 0x1b, 0xc9, 0x61, 0xab, 0xe4, 0xed, 0x76, 0xc9, 0x37, 0x6b, 0xa2, 0xf3,
|
||||||
0x5a, 0xb6, 0x1a, 0x82, 0xdb, 0x6e, 0x08, 0xcd, 0x8a, 0xe9, 0xfc, 0x7b, 0xc5, 0x74, 0x6f, 0x56,
|
0xef, 0x35, 0xd1, 0xbd, 0x5b, 0x13, 0xdf, 0xc1, 0xce, 0x49, 0x96, 0x5d, 0x95, 0xb9, 0x0e, 0xa3,
|
||||||
0xcc, 0xf7, 0xb0, 0x73, 0x5c, 0x14, 0x97, 0x8b, 0xd2, 0x84, 0x51, 0xc5, 0xba, 0xf9, 0x42, 0x67,
|
0x8a, 0x75, 0xf5, 0x86, 0xd6, 0xac, 0x23, 0x7d, 0xd6, 0x37, 0x6c, 0x65, 0xac, 0xdd, 0xce, 0x58,
|
||||||
0xd6, 0x51, 0x3e, 0xeb, 0x17, 0xb6, 0x32, 0xd6, 0x6d, 0x67, 0x6c, 0xf0, 0xb7, 0x03, 0xbb, 0x9b,
|
0xef, 0x6f, 0x0b, 0x76, 0x57, 0x8f, 0x35, 0xd5, 0xf6, 0x03, 0xec, 0xd4, 0xe7, 0x06, 0xb1, 0xb9,
|
||||||
0xd7, 0xda, 0x5a, 0xfc, 0x09, 0x76, 0xea, 0x7b, 0xa3, 0xd4, 0xbe, 0xd9, 0x38, 0x18, 0xed, 0xbf,
|
0xb3, 0x76, 0x30, 0xda, 0x7f, 0xd1, 0x10, 0xf3, 0xbe, 0xdd, 0x55, 0x83, 0x88, 0x2a, 0xb2, 0xfc,
|
||||||
0x6c, 0x88, 0x79, 0xdb, 0xe9, 0xaa, 0x7d, 0x24, 0x15, 0x59, 0xe1, 0xf6, 0x55, 0x0b, 0x11, 0xd3,
|
0xed, 0xeb, 0x16, 0xc2, 0xa7, 0x0b, 0x98, 0xb4, 0xcd, 0x64, 0x42, 0xd7, 0x5e, 0x0d, 0xb3, 0xc3,
|
||||||
0x25, 0x4c, 0xda, 0x66, 0x2a, 0xa1, 0x6b, 0xaf, 0x96, 0xd9, 0x61, 0x75, 0x92, 0x7c, 0x02, 0xde,
|
0x6a, 0x27, 0xf9, 0x18, 0x9c, 0xdb, 0x40, 0x6c, 0x15, 0xc8, 0xce, 0x4a, 0x20, 0xc6, 0xd7, 0xad,
|
||||||
0x3a, 0x10, 0x57, 0x07, 0xb2, 0xb3, 0x11, 0x88, 0xf5, 0xb5, 0xb6, 0x22, 0xbb, 0xd0, 0x43, 0xce,
|
0x15, 0xd9, 0x85, 0x1e, 0x16, 0x45, 0x56, 0x35, 0x02, 0x3d, 0xf1, 0x3e, 0x85, 0xe1, 0x7f, 0x56,
|
||||||
0x8b, 0xaa, 0x11, 0x98, 0x8f, 0xe0, 0x33, 0x18, 0xfe, 0x67, 0x15, 0x83, 0x3f, 0x1d, 0x18, 0x7f,
|
0xd1, 0xfb, 0xd3, 0x82, 0xf1, 0x17, 0x9c, 0xb3, 0xcb, 0x3a, 0x5d, 0x76, 0xa1, 0xa7, 0xcb, 0x54,
|
||||||
0x29, 0x04, 0xbb, 0xa8, 0xd3, 0x65, 0x17, 0x7a, 0xa6, 0x4c, 0x4d, 0xb3, 0x32, 0x1f, 0x64, 0x06,
|
0xb7, 0x23, 0x3d, 0x21, 0x33, 0x18, 0x99, 0x2a, 0x6b, 0x50, 0xdf, 0x84, 0x1e, 0xec, 0x26, 0xa6,
|
||||||
0x23, 0x5b, 0x65, 0x0d, 0xea, 0x9b, 0xd0, 0xbd, 0xdd, 0xc4, 0x56, 0x5e, 0xd7, 0x84, 0x26, 0x65,
|
0xf2, 0xba, 0x3a, 0x34, 0x21, 0xe2, 0x76, 0xa3, 0xef, 0xad, 0x6d, 0xf4, 0xfd, 0x46, 0xa3, 0x7f,
|
||||||
0xda, 0x1e, 0x03, 0xbd, 0x3b, 0xc7, 0x40, 0xbf, 0x31, 0x06, 0x9e, 0x80, 0xa7, 0x0f, 0xe5, 0x45,
|
0x02, 0x8e, 0xda, 0x94, 0x66, 0x11, 0x9a, 0x17, 0x60, 0x28, 0x81, 0x6f, 0xb2, 0x08, 0xbd, 0x5f,
|
||||||
0x82, 0x76, 0x3e, 0x0c, 0x15, 0xf0, 0x6d, 0x91, 0xe8, 0xb4, 0xae, 0x1e, 0x63, 0x85, 0x9f, 0x40,
|
0x2d, 0xd8, 0xaa, 0x6e, 0x63, 0x94, 0x9f, 0x40, 0xe7, 0xa2, 0x66, 0x5f, 0x0e, 0x2b, 0x8e, 0xec,
|
||||||
0xe7, 0xbc, 0x26, 0x5f, 0x2d, 0x2b, 0x8a, 0xdc, 0xbb, 0x28, 0xba, 0x31, 0xf9, 0x6a, 0x42, 0xba,
|
0x75, 0x1c, 0xdd, 0x79, 0xdc, 0x6a, 0x46, 0xba, 0x4d, 0x46, 0x6a, 0x31, 0x7a, 0x0d, 0x31, 0x64,
|
||||||
0x4d, 0x42, 0x6a, 0x2d, 0x7a, 0x4d, 0x2d, 0x2e, 0x60, 0xfb, 0x54, 0x52, 0xc9, 0x84, 0x64, 0xb1,
|
0xc8, 0xb4, 0x14, 0x3f, 0x56, 0x21, 0xcb, 0xb1, 0x77, 0x09, 0xdb, 0x67, 0x82, 0x0a, 0xc6, 0x05,
|
||||||
0xa8, 0x18, 0x6d, 0x71, 0xe7, 0xdc, 0xc7, 0x9d, 0x7b, 0x17, 0x77, 0x9d, 0x9a, 0xbb, 0xe0, 0x77,
|
0x0b, 0x79, 0x45, 0x73, 0x8b, 0x50, 0xeb, 0x21, 0x42, 0xed, 0x75, 0x84, 0x76, 0x6a, 0x42, 0xbd,
|
||||||
0x07, 0x48, 0xd3, 0x93, 0x7d, 0xee, 0xff, 0xe0, 0x4a, 0xd1, 0x23, 0x0b, 0x49, 0xd3, 0x48, 0x0f,
|
0xdf, 0x2d, 0x20, 0x4d, 0x4f, 0x86, 0x82, 0xff, 0xc1, 0x95, 0xa4, 0x4c, 0x64, 0x82, 0xc6, 0x81,
|
||||||
0x10, 0x3b, 0x06, 0x34, 0xa2, 0x26, 0x98, 0x12, 0x64, 0x21, 0x30, 0x31, 0xbb, 0x66, 0x06, 0x0c,
|
0x7a, 0x55, 0xcc, 0xdb, 0xa0, 0x10, 0xf9, 0x70, 0x49, 0x95, 0x4a, 0x8e, 0x91, 0x5e, 0xd5, 0x0f,
|
||||||
0x15, 0xa0, 0x37, 0x37, 0x47, 0x48, 0xbf, 0x35, 0x42, 0xf6, 0x7f, 0xed, 0xc0, 0xe0, 0x14, 0xe9,
|
0xc3, 0x50, 0x02, 0x6a, 0x71, 0xf5, 0x5d, 0xe9, 0xb7, 0xde, 0x95, 0xfd, 0x5f, 0x3a, 0x30, 0x38,
|
||||||
0x35, 0x62, 0x42, 0x0e, 0x61, 0x7c, 0x8a, 0x79, 0xb2, 0xfe, 0x69, 0xd9, 0x6d, 0x54, 0x43, 0x8d,
|
0x43, 0x7a, 0x83, 0x18, 0x91, 0x23, 0x18, 0x9f, 0x61, 0x1a, 0xdd, 0xfe, 0x55, 0x76, 0x1b, 0x25,
|
||||||
0x4e, 0x9f, 0xde, 0x86, 0x56, 0xef, 0x0f, 0x1e, 0xcc, 0x9d, 0x97, 0x0e, 0x39, 0x81, 0xf1, 0x11,
|
0x52, 0xa3, 0xd3, 0x77, 0xef, 0x43, 0xab, 0xfb, 0x7b, 0x1b, 0x73, 0xeb, 0x85, 0x45, 0x4e, 0x61,
|
||||||
0x62, 0x79, 0x50, 0xe4, 0x39, 0xc6, 0x12, 0x13, 0xf2, 0xbc, 0x71, 0xe8, 0x96, 0x16, 0x39, 0x7d,
|
0x7c, 0x8c, 0x98, 0x1f, 0x64, 0x69, 0x8a, 0xa1, 0xc0, 0x88, 0x3c, 0x6b, 0x6c, 0xba, 0xa7, 0x6f,
|
||||||
0x7c, 0xe3, 0x5f, 0xa1, 0xaa, 0x28, 0x7b, 0xe3, 0x77, 0xf0, 0xb0, 0xd9, 0x19, 0x36, 0x2e, 0xbc,
|
0x4e, 0x1f, 0xdf, 0xf9, 0x22, 0x54, 0x65, 0x66, 0x4e, 0xfc, 0x16, 0x36, 0x9b, 0xed, 0x62, 0xe5,
|
||||||
0xa5, 0x8f, 0x4d, 0x5f, 0xdc, 0xd3, 0x52, 0x82, 0x07, 0xe4, 0x0b, 0xe8, 0x9b, 0x5c, 0x25, 0x7e,
|
0xc0, 0x7b, 0x9a, 0xdb, 0xf4, 0xf9, 0x03, 0x7d, 0xc6, 0xdb, 0x20, 0x9f, 0x43, 0x5f, 0xe7, 0x2f,
|
||||||
0xc3, 0x78, 0xa3, 0x16, 0x37, 0xe2, 0xda, 0x4c, 0xec, 0xe0, 0x01, 0x39, 0x02, 0x58, 0x67, 0x00,
|
0x71, 0x1b, 0xc6, 0x2b, 0x05, 0xba, 0x12, 0xd7, 0x6a, 0xb2, 0x7b, 0x1b, 0xe4, 0x18, 0xe0, 0x36,
|
||||||
0x69, 0xf2, 0x72, 0x23, 0x05, 0xa7, 0xcf, 0xee, 0xd8, 0xad, 0x2e, 0x3b, 0xeb, 0xeb, 0x3f, 0xc8,
|
0x03, 0x48, 0x93, 0x97, 0x3b, 0x29, 0x38, 0x7d, 0xba, 0x66, 0xb5, 0x3a, 0xec, 0xbc, 0xaf, 0x3e,
|
||||||
0x4f, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0xc7, 0x9f, 0x0a, 0x25, 0x51, 0x0a, 0x00, 0x00,
|
0x8e, 0x9f, 0xfc, 0x13, 0x00, 0x00, 0xff, 0xff, 0x25, 0xfc, 0xb7, 0x54, 0x48, 0x0a, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/chrislusf/seaweedfs/weed/glog"
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||||
"github.com/chrislusf/seaweedfs/weed/operation"
|
"github.com/chrislusf/seaweedfs/weed/operation"
|
||||||
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
"github.com/chrislusf/seaweedfs/weed/util"
|
"github.com/chrislusf/seaweedfs/weed/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -59,6 +60,7 @@ func (fs *FilerSink) fetchAndWrite(sourceChunk *filer_pb.FileChunk) (fileId stri
|
||||||
defer readCloser.Close()
|
defer readCloser.Close()
|
||||||
|
|
||||||
var host string
|
var host string
|
||||||
|
var auth security.EncodedJwt
|
||||||
|
|
||||||
if err := fs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
|
if err := fs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
|
||||||
|
|
||||||
|
@ -76,7 +78,7 @@ func (fs *FilerSink) fetchAndWrite(sourceChunk *filer_pb.FileChunk) (fileId stri
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fileId, host = resp.FileId, resp.Url
|
fileId, host, auth = resp.FileId, resp.Url, security.EncodedJwt(resp.Auth)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
@ -88,7 +90,7 @@ func (fs *FilerSink) fetchAndWrite(sourceChunk *filer_pb.FileChunk) (fileId stri
|
||||||
glog.V(4).Infof("replicating %s to %s header:%+v", filename, fileUrl, header)
|
glog.V(4).Infof("replicating %s to %s header:%+v", filename, fileUrl, header)
|
||||||
|
|
||||||
uploadResult, err := operation.Upload(fileUrl, filename, readCloser,
|
uploadResult, err := operation.Upload(fileUrl, filename, readCloser,
|
||||||
"gzip" == header.Get("Content-Encoding"), header.Get("Content-Type"), nil, "")
|
"gzip" == header.Get("Content-Encoding"), header.Get("Content-Type"), nil, auth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(0).Infof("upload data %v to %s: %v", filename, fileUrl, err)
|
glog.V(0).Infof("upload data %v to %s: %v", filename, fileUrl, err)
|
||||||
return "", fmt.Errorf("upload data: %v", err)
|
return "", fmt.Errorf("upload data: %v", err)
|
||||||
|
@ -103,7 +105,7 @@ func (fs *FilerSink) fetchAndWrite(sourceChunk *filer_pb.FileChunk) (fileId stri
|
||||||
|
|
||||||
func (fs *FilerSink) withFilerClient(fn func(filer_pb.SeaweedFilerClient) error) error {
|
func (fs *FilerSink) withFilerClient(fn func(filer_pb.SeaweedFilerClient) error) error {
|
||||||
|
|
||||||
grpcConnection, err := util.GrpcDial(fs.grpcAddress)
|
grpcConnection, err := util.GrpcDial(fs.grpcAddress, fs.grpcDialOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("fail to dial %s: %v", fs.grpcAddress, err)
|
return fmt.Errorf("fail to dial %s: %v", fs.grpcAddress, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@ package filersink
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/filer2"
|
"github.com/chrislusf/seaweedfs/weed/filer2"
|
||||||
"github.com/chrislusf/seaweedfs/weed/glog"
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||||
|
@ -20,6 +23,7 @@ type FilerSink struct {
|
||||||
collection string
|
collection string
|
||||||
ttlSec int32
|
ttlSec int32
|
||||||
dataCenter string
|
dataCenter string
|
||||||
|
grpcDialOption grpc.DialOption
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -55,6 +59,7 @@ func (fs *FilerSink) initialize(grpcAddress string, dir string,
|
||||||
fs.replication = replication
|
fs.replication = replication
|
||||||
fs.collection = collection
|
fs.collection = collection
|
||||||
fs.ttlSec = int32(ttlSec)
|
fs.ttlSec = int32(ttlSec)
|
||||||
|
fs.grpcDialOption = security.LoadClientTLS(viper.Sub("grpc"), "client")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,9 @@ package source
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -18,6 +21,7 @@ type ReplicationSource interface {
|
||||||
|
|
||||||
type FilerSource struct {
|
type FilerSource struct {
|
||||||
grpcAddress string
|
grpcAddress string
|
||||||
|
grpcDialOption grpc.DialOption
|
||||||
Dir string
|
Dir string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +35,7 @@ func (fs *FilerSource) Initialize(configuration util.Configuration) error {
|
||||||
func (fs *FilerSource) initialize(grpcAddress string, dir string) (err error) {
|
func (fs *FilerSource) initialize(grpcAddress string, dir string) (err error) {
|
||||||
fs.grpcAddress = grpcAddress
|
fs.grpcAddress = grpcAddress
|
||||||
fs.Dir = dir
|
fs.Dir = dir
|
||||||
|
fs.grpcDialOption = security.LoadClientTLS(viper.Sub("grpc"), "client")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +45,7 @@ func (fs *FilerSource) LookupFileId(part string) (fileUrl string, err error) {
|
||||||
|
|
||||||
vid := volumeId(part)
|
vid := volumeId(part)
|
||||||
|
|
||||||
err = fs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
|
err = fs.withFilerClient(fs.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
|
||||||
|
|
||||||
glog.V(4).Infof("read lookup volume id locations: %v", vid)
|
glog.V(4).Infof("read lookup volume id locations: %v", vid)
|
||||||
resp, err := client.LookupVolume(context.Background(), &filer_pb.LookupVolumeRequest{
|
resp, err := client.LookupVolume(context.Background(), &filer_pb.LookupVolumeRequest{
|
||||||
|
@ -84,9 +89,9 @@ func (fs *FilerSource) ReadPart(part string) (filename string, header http.Heade
|
||||||
return filename, header, readCloser, err
|
return filename, header, readCloser, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FilerSource) withFilerClient(fn func(filer_pb.SeaweedFilerClient) error) error {
|
func (fs *FilerSource) withFilerClient(grpcDialOption grpc.DialOption, fn func(filer_pb.SeaweedFilerClient) error) error {
|
||||||
|
|
||||||
grpcConnection, err := util.GrpcDial(fs.grpcAddress)
|
grpcConnection, err := util.GrpcDial(fs.grpcAddress, grpcDialOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("fail to dial %s: %v", fs.grpcAddress, err)
|
return fmt.Errorf("fail to dial %s: %v", fs.grpcAddress, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ func encodeResponse(response interface{}) []byte {
|
||||||
|
|
||||||
func (s3a *S3ApiServer) withFilerClient(fn func(filer_pb.SeaweedFilerClient) error) error {
|
func (s3a *S3ApiServer) withFilerClient(fn func(filer_pb.SeaweedFilerClient) error) error {
|
||||||
|
|
||||||
grpcConnection, err := util.GrpcDial(s3a.option.FilerGrpcAddress)
|
grpcConnection, err := util.GrpcDial(s3a.option.FilerGrpcAddress, s3a.option.GrpcDialOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("fail to dial %s: %v", s3a.option.FilerGrpcAddress, err)
|
return fmt.Errorf("fail to dial %s: %v", s3a.option.FilerGrpcAddress, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
_ "github.com/chrislusf/seaweedfs/weed/filer2/postgres"
|
_ "github.com/chrislusf/seaweedfs/weed/filer2/postgres"
|
||||||
_ "github.com/chrislusf/seaweedfs/weed/filer2/redis"
|
_ "github.com/chrislusf/seaweedfs/weed/filer2/redis"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,6 +17,7 @@ type S3ApiServerOption struct {
|
||||||
FilerGrpcAddress string
|
FilerGrpcAddress string
|
||||||
DomainName string
|
DomainName string
|
||||||
BucketsPath string
|
BucketsPath string
|
||||||
|
GrpcDialOption grpc.DialOption
|
||||||
}
|
}
|
||||||
|
|
||||||
type S3ApiServer struct {
|
type S3ApiServer struct {
|
||||||
|
|
|
@ -42,20 +42,20 @@ https://github.com/pkieltyka/jwtauth/blob/master/jwtauth.go
|
||||||
*/
|
*/
|
||||||
type Guard struct {
|
type Guard struct {
|
||||||
whiteList []string
|
whiteList []string
|
||||||
SecretKey Secret
|
SigningKey SigningKey
|
||||||
|
|
||||||
isActive bool
|
isActive bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGuard(whiteList []string, secretKey string) *Guard {
|
func NewGuard(whiteList []string, signingKey string) *Guard {
|
||||||
g := &Guard{whiteList: whiteList, SecretKey: Secret(secretKey)}
|
g := &Guard{whiteList: whiteList, SigningKey: SigningKey(signingKey)}
|
||||||
g.isActive = len(g.whiteList) != 0 || len(g.SecretKey) != 0
|
g.isActive = len(g.whiteList) != 0 || len(g.SigningKey) != 0
|
||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Guard) WhiteList(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
|
func (g *Guard) WhiteList(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
|
||||||
if !g.isActive {
|
if !g.isActive {
|
||||||
//if no security needed, just skip all checkings
|
//if no security needed, just skip all checking
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -67,20 +67,6 @@ func (g *Guard) WhiteList(f func(w http.ResponseWriter, r *http.Request)) func(w
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Guard) Secure(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if !g.isActive {
|
|
||||||
//if no security needed, just skip all checkings
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if err := g.checkJwt(w, r); err != nil {
|
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
f(w, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetActualRemoteHost(r *http.Request) (host string, err error) {
|
func GetActualRemoteHost(r *http.Request) (host string, err error) {
|
||||||
host = r.Header.Get("HTTP_X_FORWARDED_FOR")
|
host = r.Header.Get("HTTP_X_FORWARDED_FOR")
|
||||||
if host == "" {
|
if host == "" {
|
||||||
|
@ -130,33 +116,3 @@ func (g *Guard) checkWhiteList(w http.ResponseWriter, r *http.Request) error {
|
||||||
glog.V(0).Infof("Not in whitelist: %s", r.RemoteAddr)
|
glog.V(0).Infof("Not in whitelist: %s", r.RemoteAddr)
|
||||||
return fmt.Errorf("Not in whitelis: %s", r.RemoteAddr)
|
return fmt.Errorf("Not in whitelis: %s", r.RemoteAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Guard) checkJwt(w http.ResponseWriter, r *http.Request) error {
|
|
||||||
if g.checkWhiteList(w, r) == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(g.SecretKey) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenStr := GetJwt(r)
|
|
||||||
|
|
||||||
if tokenStr == "" {
|
|
||||||
return ErrUnauthorized
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify the token
|
|
||||||
token, err := DecodeJwt(g.SecretKey, tokenStr)
|
|
||||||
if err != nil {
|
|
||||||
glog.V(1).Infof("Token verification error from %s: %v", r.RemoteAddr, err)
|
|
||||||
return ErrUnauthorized
|
|
||||||
}
|
|
||||||
if !token.Valid {
|
|
||||||
glog.V(1).Infof("Token invliad from %s: %v", r.RemoteAddr, tokenStr)
|
|
||||||
return ErrUnauthorized
|
|
||||||
}
|
|
||||||
|
|
||||||
glog.V(1).Infof("No permission from %s", r.RemoteAddr)
|
|
||||||
return fmt.Errorf("No write permission from %s", r.RemoteAddr)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package security
|
package security
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/glog"
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||||
|
@ -11,21 +11,28 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type EncodedJwt string
|
type EncodedJwt string
|
||||||
type Secret string
|
type SigningKey []byte
|
||||||
|
|
||||||
func GenJwt(secret Secret, fileId string) EncodedJwt {
|
type SeaweedFileIdClaims struct {
|
||||||
if secret == "" {
|
Fid string `json:"fid"`
|
||||||
|
jwt.StandardClaims
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenJwt(signingKey SigningKey, fileId string) EncodedJwt {
|
||||||
|
if len(signingKey) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
t := jwt.New(jwt.GetSigningMethod("HS256"))
|
claims := SeaweedFileIdClaims{
|
||||||
t.Claims = &jwt.StandardClaims{
|
fileId,
|
||||||
|
jwt.StandardClaims{
|
||||||
ExpiresAt: time.Now().Add(time.Second * 10).Unix(),
|
ExpiresAt: time.Now().Add(time.Second * 10).Unix(),
|
||||||
Subject: fileId,
|
},
|
||||||
}
|
}
|
||||||
encoded, e := t.SignedString(secret)
|
t := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
encoded, e := t.SignedString([]byte(signingKey))
|
||||||
if e != nil {
|
if e != nil {
|
||||||
glog.V(0).Infof("Failed to sign claims: %v", t.Claims)
|
glog.V(0).Infof("Failed to sign claims %+v: %v", t.Claims, e)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return EncodedJwt(encoded)
|
return EncodedJwt(encoded)
|
||||||
|
@ -44,31 +51,15 @@ func GetJwt(r *http.Request) EncodedJwt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get token from cookie
|
|
||||||
if tokenStr == "" {
|
|
||||||
cookie, err := r.Cookie("jwt")
|
|
||||||
if err == nil {
|
|
||||||
tokenStr = cookie.Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return EncodedJwt(tokenStr)
|
return EncodedJwt(tokenStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func EncodeJwt(secret Secret, claims *jwt.StandardClaims) (EncodedJwt, error) {
|
func DecodeJwt(signingKey SigningKey, tokenString EncodedJwt) (token *jwt.Token, err error) {
|
||||||
if secret == "" {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
t := jwt.New(jwt.GetSigningMethod("HS256"))
|
|
||||||
t.Claims = claims
|
|
||||||
encoded, e := t.SignedString(secret)
|
|
||||||
return EncodedJwt(encoded), e
|
|
||||||
}
|
|
||||||
|
|
||||||
func DecodeJwt(secret Secret, tokenString EncodedJwt) (token *jwt.Token, err error) {
|
|
||||||
// check exp, nbf
|
// check exp, nbf
|
||||||
return jwt.Parse(string(tokenString), func(token *jwt.Token) (interface{}, error) {
|
return jwt.ParseWithClaims(string(tokenString), &SeaweedFileIdClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||||
return secret, nil
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
|
return nil, fmt.Errorf("unknown token method")
|
||||||
|
}
|
||||||
|
return []byte(signingKey), nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
66
weed/security/tls.go
Normal file
66
weed/security/tls.go
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
package security
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/credentials"
|
||||||
|
)
|
||||||
|
|
||||||
|
func LoadServerTLS(config *viper.Viper, component string) grpc.ServerOption {
|
||||||
|
if config == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// load cert/key, ca cert
|
||||||
|
cert, err := tls.LoadX509KeyPair(config.GetString(component+".cert"), config.GetString(component+".key"))
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("load cert/key error: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
caCert, err := ioutil.ReadFile(config.GetString("ca"))
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("read ca cert file error: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
caCertPool := x509.NewCertPool()
|
||||||
|
caCertPool.AppendCertsFromPEM(caCert)
|
||||||
|
ta := credentials.NewTLS(&tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
ClientCAs: caCertPool,
|
||||||
|
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||||
|
})
|
||||||
|
|
||||||
|
return grpc.Creds(ta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadClientTLS(config *viper.Viper, component string) grpc.DialOption {
|
||||||
|
if config == nil {
|
||||||
|
return grpc.WithInsecure()
|
||||||
|
}
|
||||||
|
|
||||||
|
// load cert/key, cacert
|
||||||
|
cert, err := tls.LoadX509KeyPair(config.GetString(component+".cert"), config.GetString(component+".key"))
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("load cert/key error: %v", err)
|
||||||
|
return grpc.WithInsecure()
|
||||||
|
}
|
||||||
|
caCert, err := ioutil.ReadFile(config.GetString("ca"))
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("read ca cert file error: %v", err)
|
||||||
|
return grpc.WithInsecure()
|
||||||
|
}
|
||||||
|
caCertPool := x509.NewCertPool()
|
||||||
|
caCertPool.AppendCertsFromPEM(caCert)
|
||||||
|
|
||||||
|
ta := credentials.NewTLS(&tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
RootCAs: caCertPool,
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
})
|
||||||
|
return grpc.WithTransportCredentials(ta)
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -13,7 +14,6 @@ import (
|
||||||
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/glog"
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||||
"github.com/chrislusf/seaweedfs/weed/operation"
|
"github.com/chrislusf/seaweedfs/weed/operation"
|
||||||
"github.com/chrislusf/seaweedfs/weed/security"
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/stats"
|
"github.com/chrislusf/seaweedfs/weed/stats"
|
||||||
"github.com/chrislusf/seaweedfs/weed/storage"
|
"github.com/chrislusf/seaweedfs/weed/storage"
|
||||||
"github.com/chrislusf/seaweedfs/weed/util"
|
"github.com/chrislusf/seaweedfs/weed/util"
|
||||||
|
@ -82,8 +82,7 @@ func debug(params ...interface{}) {
|
||||||
glog.V(4).Infoln(params...)
|
glog.V(4).Infoln(params...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func submitForClientHandler(w http.ResponseWriter, r *http.Request, masterUrl string) {
|
func submitForClientHandler(w http.ResponseWriter, r *http.Request, masterUrl string, grpcDialOption grpc.DialOption) {
|
||||||
jwt := security.GetJwt(r)
|
|
||||||
m := make(map[string]interface{})
|
m := make(map[string]interface{})
|
||||||
if r.Method != "POST" {
|
if r.Method != "POST" {
|
||||||
writeJsonError(w, r, http.StatusMethodNotAllowed, errors.New("Only submit via POST!"))
|
writeJsonError(w, r, http.StatusMethodNotAllowed, errors.New("Only submit via POST!"))
|
||||||
|
@ -113,7 +112,7 @@ func submitForClientHandler(w http.ResponseWriter, r *http.Request, masterUrl st
|
||||||
Collection: r.FormValue("collection"),
|
Collection: r.FormValue("collection"),
|
||||||
Ttl: r.FormValue("ttl"),
|
Ttl: r.FormValue("ttl"),
|
||||||
}
|
}
|
||||||
assignResult, ae := operation.Assign(masterUrl, ar)
|
assignResult, ae := operation.Assign(masterUrl, grpcDialOption, ar)
|
||||||
if ae != nil {
|
if ae != nil {
|
||||||
writeJsonError(w, r, http.StatusInternalServerError, ae)
|
writeJsonError(w, r, http.StatusInternalServerError, ae)
|
||||||
return
|
return
|
||||||
|
@ -125,7 +124,7 @@ func submitForClientHandler(w http.ResponseWriter, r *http.Request, masterUrl st
|
||||||
}
|
}
|
||||||
|
|
||||||
debug("upload file to store", url)
|
debug("upload file to store", url)
|
||||||
uploadResult, err := operation.Upload(url, fname, bytes.NewReader(data), isGzipped, mimeType, pairMap, jwt)
|
uploadResult, err := operation.Upload(url, fname, bytes.NewReader(data), isGzipped, mimeType, pairMap, assignResult.Auth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeJsonError(w, r, http.StatusInternalServerError, err)
|
writeJsonError(w, r, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -220,7 +220,7 @@ func (fs *FilerServer) AssignVolume(ctx context.Context, req *filer_pb.AssignVol
|
||||||
DataCenter: "",
|
DataCenter: "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assignResult, err := operation.Assign(fs.filer.GetMaster(), assignRequest, altRequest)
|
assignResult, err := operation.Assign(fs.filer.GetMaster(), fs.grpcDialOption, assignRequest, altRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("assign volume: %v", err)
|
return nil, fmt.Errorf("assign volume: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -233,6 +233,7 @@ func (fs *FilerServer) AssignVolume(ctx context.Context, req *filer_pb.AssignVol
|
||||||
Count: int32(assignResult.Count),
|
Count: int32(assignResult.Count),
|
||||||
Url: assignResult.Url,
|
Url: assignResult.Url,
|
||||||
PublicUrl: assignResult.PublicUrl,
|
PublicUrl: assignResult.PublicUrl,
|
||||||
|
Auth: string(assignResult.Auth),
|
||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +254,7 @@ func (fs *FilerServer) Statistics(ctx context.Context, req *filer_pb.StatisticsR
|
||||||
Ttl: req.Ttl,
|
Ttl: req.Ttl,
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := operation.Statistics(fs.filer.GetMaster(), input)
|
output, err := operation.Statistics(fs.filer.GetMaster(), fs.grpcDialOption, input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package weed_server
|
package weed_server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"google.golang.org/grpc"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
@ -28,7 +29,6 @@ type FilerOption struct {
|
||||||
RedirectOnRead bool
|
RedirectOnRead bool
|
||||||
DisableDirListing bool
|
DisableDirListing bool
|
||||||
MaxMB int
|
MaxMB int
|
||||||
SecretKey string
|
|
||||||
DirListingLimit int
|
DirListingLimit int
|
||||||
DataCenter string
|
DataCenter string
|
||||||
DefaultLevelDbDir string
|
DefaultLevelDbDir string
|
||||||
|
@ -36,21 +36,23 @@ type FilerOption struct {
|
||||||
|
|
||||||
type FilerServer struct {
|
type FilerServer struct {
|
||||||
option *FilerOption
|
option *FilerOption
|
||||||
secret security.Secret
|
secret security.SigningKey
|
||||||
filer *filer2.Filer
|
filer *filer2.Filer
|
||||||
|
grpcDialOption grpc.DialOption
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFilerServer(defaultMux, readonlyMux *http.ServeMux, option *FilerOption) (fs *FilerServer, err error) {
|
func NewFilerServer(defaultMux, readonlyMux *http.ServeMux, option *FilerOption) (fs *FilerServer, err error) {
|
||||||
|
|
||||||
fs = &FilerServer{
|
fs = &FilerServer{
|
||||||
option: option,
|
option: option,
|
||||||
|
grpcDialOption: security.LoadClientTLS(viper.Sub("grpc"), "filer"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(option.Masters) == 0 {
|
if len(option.Masters) == 0 {
|
||||||
glog.Fatal("master list is required!")
|
glog.Fatal("master list is required!")
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.filer = filer2.NewFiler(option.Masters)
|
fs.filer = filer2.NewFiler(option.Masters, fs.grpcDialOption)
|
||||||
|
|
||||||
go fs.filer.KeepConnectedToMaster()
|
go fs.filer.KeepConnectedToMaster()
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -14,8 +15,8 @@ import (
|
||||||
"github.com/chrislusf/seaweedfs/weed/glog"
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||||
"github.com/chrislusf/seaweedfs/weed/operation"
|
"github.com/chrislusf/seaweedfs/weed/operation"
|
||||||
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
"github.com/chrislusf/seaweedfs/weed/util"
|
"github.com/chrislusf/seaweedfs/weed/util"
|
||||||
"os"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -31,7 +32,7 @@ type FilerPostResult struct {
|
||||||
Url string `json:"url,omitempty"`
|
Url string `json:"url,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FilerServer) assignNewFileInfo(w http.ResponseWriter, r *http.Request, replication, collection string, dataCenter string) (fileId, urlLocation string, err error) {
|
func (fs *FilerServer) assignNewFileInfo(w http.ResponseWriter, r *http.Request, replication, collection string, dataCenter string) (fileId, urlLocation string, auth security.EncodedJwt, err error) {
|
||||||
ar := &operation.VolumeAssignRequest{
|
ar := &operation.VolumeAssignRequest{
|
||||||
Count: 1,
|
Count: 1,
|
||||||
Replication: replication,
|
Replication: replication,
|
||||||
|
@ -50,7 +51,7 @@ func (fs *FilerServer) assignNewFileInfo(w http.ResponseWriter, r *http.Request,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assignResult, ae := operation.Assign(fs.filer.GetMaster(), ar, altRequest)
|
assignResult, ae := operation.Assign(fs.filer.GetMaster(), fs.grpcDialOption, ar, altRequest)
|
||||||
if ae != nil {
|
if ae != nil {
|
||||||
glog.Errorf("failing to assign a file id: %v", ae)
|
glog.Errorf("failing to assign a file id: %v", ae)
|
||||||
writeJsonError(w, r, http.StatusInternalServerError, ae)
|
writeJsonError(w, r, http.StatusInternalServerError, ae)
|
||||||
|
@ -59,6 +60,7 @@ func (fs *FilerServer) assignNewFileInfo(w http.ResponseWriter, r *http.Request,
|
||||||
}
|
}
|
||||||
fileId = assignResult.Fid
|
fileId = assignResult.Fid
|
||||||
urlLocation = "http://" + assignResult.Url + "/" + assignResult.Fid
|
urlLocation = "http://" + assignResult.Url + "/" + assignResult.Fid
|
||||||
|
auth = assignResult.Auth
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +84,7 @@ func (fs *FilerServer) PostHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fileId, urlLocation, err := fs.assignNewFileInfo(w, r, replication, collection, dataCenter)
|
fileId, urlLocation, auth, err := fs.assignNewFileInfo(w, r, replication, collection, dataCenter)
|
||||||
|
|
||||||
if err != nil || fileId == "" || urlLocation == "" {
|
if err != nil || fileId == "" || urlLocation == "" {
|
||||||
glog.V(0).Infof("fail to allocate volume for %s, collection:%s, datacenter:%s", r.URL.Path, collection, dataCenter)
|
glog.V(0).Infof("fail to allocate volume for %s, collection:%s, datacenter:%s", r.URL.Path, collection, dataCenter)
|
||||||
|
@ -115,6 +117,9 @@ func (fs *FilerServer) PostHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
Host: r.Host,
|
Host: r.Host,
|
||||||
ContentLength: r.ContentLength,
|
ContentLength: r.ContentLength,
|
||||||
}
|
}
|
||||||
|
if auth != "" {
|
||||||
|
request.Header.Set("Authorization", "BEARER "+string(auth))
|
||||||
|
}
|
||||||
resp, do_err := util.Do(request)
|
resp, do_err := util.Do(request)
|
||||||
if do_err != nil {
|
if do_err != nil {
|
||||||
glog.Errorf("failing to connect to volume server %s: %v, %+v", r.RequestURI, do_err, r.Method)
|
glog.Errorf("failing to connect to volume server %s: %v, %+v", r.RequestURI, do_err, r.Method)
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/chrislusf/seaweedfs/weed/glog"
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||||
"github.com/chrislusf/seaweedfs/weed/operation"
|
"github.com/chrislusf/seaweedfs/weed/operation"
|
||||||
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
"github.com/chrislusf/seaweedfs/weed/util"
|
"github.com/chrislusf/seaweedfs/weed/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -105,14 +106,14 @@ func (fs *FilerServer) doAutoChunk(w http.ResponseWriter, r *http.Request, conte
|
||||||
|
|
||||||
if chunkBufOffset >= chunkSize || readFully || (chunkBufOffset > 0 && bytesRead == 0) {
|
if chunkBufOffset >= chunkSize || readFully || (chunkBufOffset > 0 && bytesRead == 0) {
|
||||||
writtenChunks = writtenChunks + 1
|
writtenChunks = writtenChunks + 1
|
||||||
fileId, urlLocation, assignErr := fs.assignNewFileInfo(w, r, replication, collection, dataCenter)
|
fileId, urlLocation, auth, assignErr := fs.assignNewFileInfo(w, r, replication, collection, dataCenter)
|
||||||
if assignErr != nil {
|
if assignErr != nil {
|
||||||
return nil, assignErr
|
return nil, assignErr
|
||||||
}
|
}
|
||||||
|
|
||||||
// upload the chunk to the volume server
|
// upload the chunk to the volume server
|
||||||
chunkName := fileName + "_chunk_" + strconv.FormatInt(int64(len(fileChunks)+1), 10)
|
chunkName := fileName + "_chunk_" + strconv.FormatInt(int64(len(fileChunks)+1), 10)
|
||||||
uploadErr := fs.doUpload(urlLocation, w, r, chunkBuf[0:chunkBufOffset], chunkName, "application/octet-stream", fileId)
|
uploadErr := fs.doUpload(urlLocation, w, r, chunkBuf[0:chunkBufOffset], chunkName, "application/octet-stream", fileId, auth)
|
||||||
if uploadErr != nil {
|
if uploadErr != nil {
|
||||||
return nil, uploadErr
|
return nil, uploadErr
|
||||||
}
|
}
|
||||||
|
@ -175,11 +176,11 @@ func (fs *FilerServer) doAutoChunk(w http.ResponseWriter, r *http.Request, conte
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FilerServer) doUpload(urlLocation string, w http.ResponseWriter, r *http.Request, chunkBuf []byte, fileName string, contentType string, fileId string) (err error) {
|
func (fs *FilerServer) doUpload(urlLocation string, w http.ResponseWriter, r *http.Request, chunkBuf []byte, fileName string, contentType string, fileId string, auth security.EncodedJwt) (err error) {
|
||||||
err = nil
|
err = nil
|
||||||
|
|
||||||
ioReader := ioutil.NopCloser(bytes.NewBuffer(chunkBuf))
|
ioReader := ioutil.NopCloser(bytes.NewBuffer(chunkBuf))
|
||||||
uploadResult, uploadError := operation.Upload(urlLocation, fileName, ioReader, false, contentType, nil, fs.jwt(fileId))
|
uploadResult, uploadError := operation.Upload(urlLocation, fileName, ioReader, false, contentType, nil, auth)
|
||||||
if uploadResult != nil {
|
if uploadResult != nil {
|
||||||
glog.V(0).Infoln("Chunk upload result. Name:", uploadResult.Name, "Fid:", fileId, "Size:", uploadResult.Size)
|
glog.V(0).Infoln("Chunk upload result. Name:", uploadResult.Name, "Fid:", fileId, "Size:", uploadResult.Size)
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,6 @@ func (ms *MasterServer) SendHeartbeat(stream master_pb.Seaweed_SendHeartbeatServ
|
||||||
glog.V(0).Infof("added volume server %v:%d", heartbeat.GetIp(), heartbeat.GetPort())
|
glog.V(0).Infof("added volume server %v:%d", heartbeat.GetIp(), heartbeat.GetPort())
|
||||||
if err := stream.Send(&master_pb.HeartbeatResponse{
|
if err := stream.Send(&master_pb.HeartbeatResponse{
|
||||||
VolumeSizeLimit: uint64(ms.volumeSizeLimitMB) * 1024 * 1024,
|
VolumeSizeLimit: uint64(ms.volumeSizeLimitMB) * 1024 * 1024,
|
||||||
SecretKey: string(ms.guard.SecretKey),
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/chrislusf/raft"
|
"github.com/chrislusf/raft"
|
||||||
"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
|
"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
"github.com/chrislusf/seaweedfs/weed/storage"
|
"github.com/chrislusf/seaweedfs/weed/storage"
|
||||||
"github.com/chrislusf/seaweedfs/weed/topology"
|
"github.com/chrislusf/seaweedfs/weed/topology"
|
||||||
)
|
)
|
||||||
|
@ -75,7 +76,7 @@ func (ms *MasterServer) Assign(ctx context.Context, req *master_pb.AssignRequest
|
||||||
}
|
}
|
||||||
ms.vgLock.Lock()
|
ms.vgLock.Lock()
|
||||||
if !ms.Topo.HasWritableVolume(option) {
|
if !ms.Topo.HasWritableVolume(option) {
|
||||||
if _, err = ms.vg.AutomaticGrowByType(option, ms.Topo); err != nil {
|
if _, err = ms.vg.AutomaticGrowByType(option, ms.grpcDialOpiton, ms.Topo); err != nil {
|
||||||
ms.vgLock.Unlock()
|
ms.vgLock.Unlock()
|
||||||
return nil, fmt.Errorf("Cannot grow volume group! %v", err)
|
return nil, fmt.Errorf("Cannot grow volume group! %v", err)
|
||||||
}
|
}
|
||||||
|
@ -92,6 +93,7 @@ func (ms *MasterServer) Assign(ctx context.Context, req *master_pb.AssignRequest
|
||||||
Url: dn.Url(),
|
Url: dn.Url(),
|
||||||
PublicUrl: dn.PublicUrl,
|
PublicUrl: dn.PublicUrl,
|
||||||
Count: count,
|
Count: count,
|
||||||
|
Auth: string(security.GenJwt(ms.guard.SigningKey, fid)),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package weed_server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -15,6 +16,7 @@ import (
|
||||||
"github.com/chrislusf/seaweedfs/weed/topology"
|
"github.com/chrislusf/seaweedfs/weed/topology"
|
||||||
"github.com/chrislusf/seaweedfs/weed/util"
|
"github.com/chrislusf/seaweedfs/weed/util"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MasterServer struct {
|
type MasterServer struct {
|
||||||
|
@ -36,6 +38,8 @@ type MasterServer struct {
|
||||||
// notifying clients
|
// notifying clients
|
||||||
clientChansLock sync.RWMutex
|
clientChansLock sync.RWMutex
|
||||||
clientChans map[string]chan *master_pb.VolumeLocation
|
clientChans map[string]chan *master_pb.VolumeLocation
|
||||||
|
|
||||||
|
grpcDialOpiton grpc.DialOption
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMasterServer(r *mux.Router, port int, metaFolder string,
|
func NewMasterServer(r *mux.Router, port int, metaFolder string,
|
||||||
|
@ -45,9 +49,11 @@ func NewMasterServer(r *mux.Router, port int, metaFolder string,
|
||||||
defaultReplicaPlacement string,
|
defaultReplicaPlacement string,
|
||||||
garbageThreshold float64,
|
garbageThreshold float64,
|
||||||
whiteList []string,
|
whiteList []string,
|
||||||
secureKey string,
|
|
||||||
) *MasterServer {
|
) *MasterServer {
|
||||||
|
|
||||||
|
v := viper.GetViper()
|
||||||
|
signingKey := v.GetString("jwt.signing.key")
|
||||||
|
|
||||||
var preallocateSize int64
|
var preallocateSize int64
|
||||||
if preallocate {
|
if preallocate {
|
||||||
preallocateSize = int64(volumeSizeLimitMB) * (1 << 20)
|
preallocateSize = int64(volumeSizeLimitMB) * (1 << 20)
|
||||||
|
@ -60,6 +66,7 @@ func NewMasterServer(r *mux.Router, port int, metaFolder string,
|
||||||
defaultReplicaPlacement: defaultReplicaPlacement,
|
defaultReplicaPlacement: defaultReplicaPlacement,
|
||||||
garbageThreshold: garbageThreshold,
|
garbageThreshold: garbageThreshold,
|
||||||
clientChans: make(map[string]chan *master_pb.VolumeLocation),
|
clientChans: make(map[string]chan *master_pb.VolumeLocation),
|
||||||
|
grpcDialOpiton: security.LoadClientTLS(v.Sub("grpc"), "master"),
|
||||||
}
|
}
|
||||||
ms.bounedLeaderChan = make(chan int, 16)
|
ms.bounedLeaderChan = make(chan int, 16)
|
||||||
seq := sequence.NewMemorySequencer()
|
seq := sequence.NewMemorySequencer()
|
||||||
|
@ -67,7 +74,7 @@ func NewMasterServer(r *mux.Router, port int, metaFolder string,
|
||||||
ms.vg = topology.NewDefaultVolumeGrowth()
|
ms.vg = topology.NewDefaultVolumeGrowth()
|
||||||
glog.V(0).Infoln("Volume Size Limit is", volumeSizeLimitMB, "MB")
|
glog.V(0).Infoln("Volume Size Limit is", volumeSizeLimitMB, "MB")
|
||||||
|
|
||||||
ms.guard = security.NewGuard(whiteList, secureKey)
|
ms.guard = security.NewGuard(whiteList, signingKey)
|
||||||
|
|
||||||
handleStaticResources2(r)
|
handleStaticResources2(r)
|
||||||
r.HandleFunc("/", ms.uiStatusHandler)
|
r.HandleFunc("/", ms.uiStatusHandler)
|
||||||
|
@ -85,7 +92,7 @@ func NewMasterServer(r *mux.Router, port int, metaFolder string,
|
||||||
r.HandleFunc("/stats/memory", ms.guard.WhiteList(statsMemoryHandler))
|
r.HandleFunc("/stats/memory", ms.guard.WhiteList(statsMemoryHandler))
|
||||||
r.HandleFunc("/{fileId}", ms.proxyToLeader(ms.redirectHandler))
|
r.HandleFunc("/{fileId}", ms.proxyToLeader(ms.redirectHandler))
|
||||||
|
|
||||||
ms.Topo.StartRefreshWritableVolumes(garbageThreshold, ms.preallocate)
|
ms.Topo.StartRefreshWritableVolumes(ms.grpcDialOpiton, garbageThreshold, ms.preallocate)
|
||||||
|
|
||||||
return ms
|
return ms
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/operation"
|
"github.com/chrislusf/seaweedfs/weed/operation"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
"github.com/chrislusf/seaweedfs/weed/stats"
|
"github.com/chrislusf/seaweedfs/weed/stats"
|
||||||
"github.com/chrislusf/seaweedfs/weed/storage"
|
"github.com/chrislusf/seaweedfs/weed/storage"
|
||||||
)
|
)
|
||||||
|
@ -40,13 +41,24 @@ func (ms *MasterServer) lookupVolumeId(vids []string, collection string) (volume
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes one volumeId only, can not do batch lookup
|
// If "fileId" is provided, this returns the fileId location and a JWT to update or delete the file.
|
||||||
|
// If "volumeId" is provided, this only returns the volumeId location
|
||||||
func (ms *MasterServer) dirLookupHandler(w http.ResponseWriter, r *http.Request) {
|
func (ms *MasterServer) dirLookupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
vid := r.FormValue("volumeId")
|
vid := r.FormValue("volumeId")
|
||||||
|
if vid != "" {
|
||||||
|
// backward compatible
|
||||||
commaSep := strings.Index(vid, ",")
|
commaSep := strings.Index(vid, ",")
|
||||||
if commaSep > 0 {
|
if commaSep > 0 {
|
||||||
vid = vid[0:commaSep]
|
vid = vid[0:commaSep]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
fileId := r.FormValue("fileId")
|
||||||
|
if fileId != "" {
|
||||||
|
commaSep := strings.Index(fileId, ",")
|
||||||
|
if commaSep > 0 {
|
||||||
|
vid = fileId[0:commaSep]
|
||||||
|
}
|
||||||
|
}
|
||||||
vids := []string{vid}
|
vids := []string{vid}
|
||||||
collection := r.FormValue("collection") //optional, but can be faster if too many collections
|
collection := r.FormValue("collection") //optional, but can be faster if too many collections
|
||||||
volumeLocations := ms.lookupVolumeId(vids, collection)
|
volumeLocations := ms.lookupVolumeId(vids, collection)
|
||||||
|
@ -54,6 +66,8 @@ func (ms *MasterServer) dirLookupHandler(w http.ResponseWriter, r *http.Request)
|
||||||
httpStatus := http.StatusOK
|
httpStatus := http.StatusOK
|
||||||
if location.Error != "" {
|
if location.Error != "" {
|
||||||
httpStatus = http.StatusNotFound
|
httpStatus = http.StatusNotFound
|
||||||
|
} else {
|
||||||
|
ms.maybeAddJwtAuthorization(w, fileId)
|
||||||
}
|
}
|
||||||
writeJsonQuiet(w, r, httpStatus, location)
|
writeJsonQuiet(w, r, httpStatus, location)
|
||||||
}
|
}
|
||||||
|
@ -79,7 +93,7 @@ func (ms *MasterServer) dirAssignHandler(w http.ResponseWriter, r *http.Request)
|
||||||
ms.vgLock.Lock()
|
ms.vgLock.Lock()
|
||||||
defer ms.vgLock.Unlock()
|
defer ms.vgLock.Unlock()
|
||||||
if !ms.Topo.HasWritableVolume(option) {
|
if !ms.Topo.HasWritableVolume(option) {
|
||||||
if _, err = ms.vg.AutomaticGrowByType(option, ms.Topo); err != nil {
|
if _, err = ms.vg.AutomaticGrowByType(option, ms.grpcDialOpiton, ms.Topo); err != nil {
|
||||||
writeJsonError(w, r, http.StatusInternalServerError,
|
writeJsonError(w, r, http.StatusInternalServerError,
|
||||||
fmt.Errorf("Cannot grow volume group! %v", err))
|
fmt.Errorf("Cannot grow volume group! %v", err))
|
||||||
return
|
return
|
||||||
|
@ -88,8 +102,17 @@ func (ms *MasterServer) dirAssignHandler(w http.ResponseWriter, r *http.Request)
|
||||||
}
|
}
|
||||||
fid, count, dn, err := ms.Topo.PickForWrite(requestedCount, option)
|
fid, count, dn, err := ms.Topo.PickForWrite(requestedCount, option)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
ms.maybeAddJwtAuthorization(w, fid)
|
||||||
writeJsonQuiet(w, r, http.StatusOK, operation.AssignResult{Fid: fid, Url: dn.Url(), PublicUrl: dn.PublicUrl, Count: count})
|
writeJsonQuiet(w, r, http.StatusOK, operation.AssignResult{Fid: fid, Url: dn.Url(), PublicUrl: dn.PublicUrl, Count: count})
|
||||||
} else {
|
} else {
|
||||||
writeJsonQuiet(w, r, http.StatusNotAcceptable, operation.AssignResult{Error: err.Error()})
|
writeJsonQuiet(w, r, http.StatusNotAcceptable, operation.AssignResult{Error: err.Error()})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ms *MasterServer) maybeAddJwtAuthorization(w http.ResponseWriter, fileId string) {
|
||||||
|
encodedJwt := security.GenJwt(ms.guard.SigningKey, fileId)
|
||||||
|
if encodedJwt == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Authorization", "BEARER "+string(encodedJwt))
|
||||||
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ func (ms *MasterServer) collectionDeleteHandler(w http.ResponseWriter, r *http.R
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, server := range collection.ListVolumeServers() {
|
for _, server := range collection.ListVolumeServers() {
|
||||||
err := operation.WithVolumeServerClient(server.Url(), func(client volume_server_pb.VolumeServerClient) error {
|
err := operation.WithVolumeServerClient(server.Url(), ms.grpcDialOpiton, func(client volume_server_pb.VolumeServerClient) error {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ func (ms *MasterServer) volumeVacuumHandler(w http.ResponseWriter, r *http.Reque
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
glog.Infoln("garbageThreshold =", gcThreshold)
|
glog.Infoln("garbageThreshold =", gcThreshold)
|
||||||
ms.Topo.Vacuum(gcThreshold, ms.preallocate)
|
ms.Topo.Vacuum(ms.grpcDialOpiton, gcThreshold, ms.preallocate)
|
||||||
ms.dirStatusHandler(w, r)
|
ms.dirStatusHandler(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ func (ms *MasterServer) volumeGrowHandler(w http.ResponseWriter, r *http.Request
|
||||||
if ms.Topo.FreeSpace() < count*option.ReplicaPlacement.GetCopyCount() {
|
if ms.Topo.FreeSpace() < count*option.ReplicaPlacement.GetCopyCount() {
|
||||||
err = errors.New("Only " + strconv.Itoa(ms.Topo.FreeSpace()) + " volumes left! Not enough for " + strconv.Itoa(count*option.ReplicaPlacement.GetCopyCount()))
|
err = errors.New("Only " + strconv.Itoa(ms.Topo.FreeSpace()) + " volumes left! Not enough for " + strconv.Itoa(count*option.ReplicaPlacement.GetCopyCount()))
|
||||||
} else {
|
} else {
|
||||||
count, err = ms.vg.GrowByCountAndType(count, option, ms.Topo)
|
count, err = ms.vg.GrowByCountAndType(ms.grpcDialOpiton, count, option, ms.Topo)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = errors.New("parameter count is not found")
|
err = errors.New("parameter count is not found")
|
||||||
|
@ -126,13 +126,13 @@ func (ms *MasterServer) selfUrl(r *http.Request) string {
|
||||||
}
|
}
|
||||||
func (ms *MasterServer) submitFromMasterServerHandler(w http.ResponseWriter, r *http.Request) {
|
func (ms *MasterServer) submitFromMasterServerHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if ms.Topo.IsLeader() {
|
if ms.Topo.IsLeader() {
|
||||||
submitForClientHandler(w, r, ms.selfUrl(r))
|
submitForClientHandler(w, r, ms.selfUrl(r), ms.grpcDialOpiton)
|
||||||
} else {
|
} else {
|
||||||
masterUrl, err := ms.Topo.Leader()
|
masterUrl, err := ms.Topo.Leader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeJsonError(w, r, http.StatusInternalServerError, err)
|
writeJsonError(w, r, http.StatusInternalServerError, err)
|
||||||
} else {
|
} else {
|
||||||
submitForClientHandler(w, r, masterUrl)
|
submitForClientHandler(w, r, masterUrl, ms.grpcDialOpiton)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,13 @@ package weed_server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/glog"
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||||
"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
|
"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
|
||||||
"github.com/chrislusf/seaweedfs/weed/security"
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/util"
|
"github.com/chrislusf/seaweedfs/weed/util"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
@ -20,6 +22,8 @@ func (vs *VolumeServer) heartbeat() {
|
||||||
vs.store.SetDataCenter(vs.dataCenter)
|
vs.store.SetDataCenter(vs.dataCenter)
|
||||||
vs.store.SetRack(vs.rack)
|
vs.store.SetRack(vs.rack)
|
||||||
|
|
||||||
|
grpcDialOption := security.LoadClientTLS(viper.Sub("grpc"), "volume")
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
var newLeader string
|
var newLeader string
|
||||||
for {
|
for {
|
||||||
|
@ -32,7 +36,7 @@ func (vs *VolumeServer) heartbeat() {
|
||||||
glog.V(0).Infof("failed to parse master grpc %v", masterGrpcAddress)
|
glog.V(0).Infof("failed to parse master grpc %v", masterGrpcAddress)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
newLeader, err = vs.doHeartbeat(master, masterGrpcAddress, time.Duration(vs.pulseSeconds)*time.Second)
|
newLeader, err = vs.doHeartbeat(master, masterGrpcAddress, grpcDialOption, time.Duration(vs.pulseSeconds)*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(0).Infof("heartbeat error: %v", err)
|
glog.V(0).Infof("heartbeat error: %v", err)
|
||||||
time.Sleep(time.Duration(vs.pulseSeconds) * time.Second)
|
time.Sleep(time.Duration(vs.pulseSeconds) * time.Second)
|
||||||
|
@ -41,9 +45,9 @@ func (vs *VolumeServer) heartbeat() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vs *VolumeServer) doHeartbeat(masterNode, masterGrpcAddress string, sleepInterval time.Duration) (newLeader string, err error) {
|
func (vs *VolumeServer) doHeartbeat(masterNode, masterGrpcAddress string, grpcDialOption grpc.DialOption, sleepInterval time.Duration) (newLeader string, err error) {
|
||||||
|
|
||||||
grpcConection, err := util.GrpcDial(masterGrpcAddress)
|
grpcConection, err := util.GrpcDial(masterGrpcAddress, grpcDialOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("fail to dial %s : %v", masterNode, err)
|
return "", fmt.Errorf("fail to dial %s : %v", masterNode, err)
|
||||||
}
|
}
|
||||||
|
@ -73,9 +77,6 @@ func (vs *VolumeServer) doHeartbeat(masterNode, masterGrpcAddress string, sleepI
|
||||||
if in.GetVolumeSizeLimit() != 0 {
|
if in.GetVolumeSizeLimit() != 0 {
|
||||||
vs.store.VolumeSizeLimit = in.GetVolumeSizeLimit()
|
vs.store.VolumeSizeLimit = in.GetVolumeSizeLimit()
|
||||||
}
|
}
|
||||||
if in.GetSecretKey() != "" {
|
|
||||||
vs.guard.SecretKey = security.Secret(in.GetSecretKey())
|
|
||||||
}
|
|
||||||
if in.GetLeader() != "" && masterNode != in.GetLeader() {
|
if in.GetLeader() != "" && masterNode != in.GetLeader() {
|
||||||
glog.V(0).Infof("Volume Server found a new master newLeader: %v instead of %v", in.GetLeader(), masterNode)
|
glog.V(0).Infof("Volume Server found a new master newLeader: %v instead of %v", in.GetLeader(), masterNode)
|
||||||
newLeader = in.GetLeader()
|
newLeader = in.GetLeader()
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
package weed_server
|
package weed_server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"google.golang.org/grpc"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/glog"
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||||
"github.com/chrislusf/seaweedfs/weed/security"
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
"github.com/chrislusf/seaweedfs/weed/storage"
|
"github.com/chrislusf/seaweedfs/weed/storage"
|
||||||
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
type VolumeServer struct {
|
type VolumeServer struct {
|
||||||
|
@ -16,6 +18,7 @@ type VolumeServer struct {
|
||||||
rack string
|
rack string
|
||||||
store *storage.Store
|
store *storage.Store
|
||||||
guard *security.Guard
|
guard *security.Guard
|
||||||
|
grpcDialOption grpc.DialOption
|
||||||
|
|
||||||
needleMapKind storage.NeedleMapType
|
needleMapKind storage.NeedleMapType
|
||||||
FixJpgOrientation bool
|
FixJpgOrientation bool
|
||||||
|
@ -31,6 +34,11 @@ func NewVolumeServer(adminMux, publicMux *http.ServeMux, ip string,
|
||||||
whiteList []string,
|
whiteList []string,
|
||||||
fixJpgOrientation bool,
|
fixJpgOrientation bool,
|
||||||
readRedirect bool) *VolumeServer {
|
readRedirect bool) *VolumeServer {
|
||||||
|
|
||||||
|
v := viper.GetViper()
|
||||||
|
signingKey := v.GetString("jwt.signing.key")
|
||||||
|
enableUiAccess := v.GetBool("access.ui")
|
||||||
|
|
||||||
vs := &VolumeServer{
|
vs := &VolumeServer{
|
||||||
pulseSeconds: pulseSeconds,
|
pulseSeconds: pulseSeconds,
|
||||||
dataCenter: dataCenter,
|
dataCenter: dataCenter,
|
||||||
|
@ -38,18 +46,22 @@ func NewVolumeServer(adminMux, publicMux *http.ServeMux, ip string,
|
||||||
needleMapKind: needleMapKind,
|
needleMapKind: needleMapKind,
|
||||||
FixJpgOrientation: fixJpgOrientation,
|
FixJpgOrientation: fixJpgOrientation,
|
||||||
ReadRedirect: readRedirect,
|
ReadRedirect: readRedirect,
|
||||||
|
grpcDialOption: security.LoadClientTLS(viper.Sub("grpc"), "volume"),
|
||||||
}
|
}
|
||||||
vs.MasterNodes = masterNodes
|
vs.MasterNodes = masterNodes
|
||||||
vs.store = storage.NewStore(port, ip, publicUrl, folders, maxCounts, vs.needleMapKind)
|
vs.store = storage.NewStore(port, ip, publicUrl, folders, maxCounts, vs.needleMapKind)
|
||||||
|
|
||||||
vs.guard = security.NewGuard(whiteList, "")
|
vs.guard = security.NewGuard(whiteList, signingKey)
|
||||||
|
|
||||||
handleStaticResources(adminMux)
|
handleStaticResources(adminMux)
|
||||||
|
if signingKey == "" || enableUiAccess {
|
||||||
|
// only expose the volume server details for safe environments
|
||||||
adminMux.HandleFunc("/ui/index.html", vs.uiStatusHandler)
|
adminMux.HandleFunc("/ui/index.html", vs.uiStatusHandler)
|
||||||
adminMux.HandleFunc("/status", vs.guard.WhiteList(vs.statusHandler))
|
adminMux.HandleFunc("/status", vs.guard.WhiteList(vs.statusHandler))
|
||||||
adminMux.HandleFunc("/stats/counter", vs.guard.WhiteList(statsCounterHandler))
|
adminMux.HandleFunc("/stats/counter", vs.guard.WhiteList(statsCounterHandler))
|
||||||
adminMux.HandleFunc("/stats/memory", vs.guard.WhiteList(statsMemoryHandler))
|
adminMux.HandleFunc("/stats/memory", vs.guard.WhiteList(statsMemoryHandler))
|
||||||
adminMux.HandleFunc("/stats/disk", vs.guard.WhiteList(vs.statsDiskHandler))
|
adminMux.HandleFunc("/stats/disk", vs.guard.WhiteList(vs.statsDiskHandler))
|
||||||
|
}
|
||||||
adminMux.HandleFunc("/", vs.privateStoreHandler)
|
adminMux.HandleFunc("/", vs.privateStoreHandler)
|
||||||
if publicMux != adminMux {
|
if publicMux != adminMux {
|
||||||
// separated admin and public port
|
// separated admin and public port
|
||||||
|
@ -69,5 +81,5 @@ func (vs *VolumeServer) Shutdown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vs *VolumeServer) jwt(fileId string) security.EncodedJwt {
|
func (vs *VolumeServer) jwt(fileId string) security.EncodedJwt {
|
||||||
return security.GenJwt(vs.guard.SecretKey, fileId)
|
return security.GenJwt(vs.guard.SigningKey, fileId)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ package weed_server
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
"github.com/chrislusf/seaweedfs/weed/stats"
|
"github.com/chrislusf/seaweedfs/weed/stats"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,3 +47,32 @@ func (vs *VolumeServer) publicReadOnlyHandler(w http.ResponseWriter, r *http.Req
|
||||||
vs.GetOrHeadHandler(w, r)
|
vs.GetOrHeadHandler(w, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vs *VolumeServer) maybeCheckJwtAuthorization(r *http.Request, vid, fid string) bool {
|
||||||
|
|
||||||
|
if len(vs.guard.SigningKey) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenStr := security.GetJwt(r)
|
||||||
|
if tokenStr == "" {
|
||||||
|
glog.V(1).Infof("missing jwt from %s", r.RemoteAddr)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := security.DecodeJwt(vs.guard.SigningKey, tokenStr)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(1).Infof("jwt verification error from %s: %v", r.RemoteAddr, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !token.Valid {
|
||||||
|
glog.V(1).Infof("jwt invalid from %s: %v", r.RemoteAddr, tokenStr)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if sc, ok := token.Claims.(*security.SeaweedFileIdClaims); ok {
|
||||||
|
return sc.Fid == vid+","+fid
|
||||||
|
}
|
||||||
|
glog.V(1).Infof("unexpected jwt from %s: %v", r.RemoteAddr, tokenStr)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -20,13 +20,20 @@ func (vs *VolumeServer) PostHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
writeJsonError(w, r, http.StatusBadRequest, e)
|
writeJsonError(w, r, http.StatusBadRequest, e)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
vid, _, _, _, _ := parseURLPath(r.URL.Path)
|
|
||||||
|
vid, fid, _, _, _ := parseURLPath(r.URL.Path)
|
||||||
volumeId, ve := storage.NewVolumeId(vid)
|
volumeId, ve := storage.NewVolumeId(vid)
|
||||||
if ve != nil {
|
if ve != nil {
|
||||||
glog.V(0).Infoln("NewVolumeId error:", ve)
|
glog.V(0).Infoln("NewVolumeId error:", ve)
|
||||||
writeJsonError(w, r, http.StatusBadRequest, ve)
|
writeJsonError(w, r, http.StatusBadRequest, ve)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !vs.maybeCheckJwtAuthorization(r, vid, fid) {
|
||||||
|
writeJsonError(w, r, http.StatusUnauthorized, errors.New("wrong jwt"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
needle, originalSize, ne := storage.CreateNeedleFromRequest(r, vs.FixJpgOrientation)
|
needle, originalSize, ne := storage.CreateNeedleFromRequest(r, vs.FixJpgOrientation)
|
||||||
if ne != nil {
|
if ne != nil {
|
||||||
writeJsonError(w, r, http.StatusBadRequest, ne)
|
writeJsonError(w, r, http.StatusBadRequest, ne)
|
||||||
|
@ -56,6 +63,11 @@ func (vs *VolumeServer) DeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
volumeId, _ := storage.NewVolumeId(vid)
|
volumeId, _ := storage.NewVolumeId(vid)
|
||||||
n.ParsePath(fid)
|
n.ParsePath(fid)
|
||||||
|
|
||||||
|
if !vs.maybeCheckJwtAuthorization(r, vid, fid) {
|
||||||
|
writeJsonError(w, r, http.StatusUnauthorized, errors.New("wrong jwt"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// glog.V(2).Infof("volume %s deleting %s", vid, n)
|
// glog.V(2).Infof("volume %s deleting %s", vid, n)
|
||||||
|
|
||||||
cookie := n.Cookie
|
cookie := n.Cookie
|
||||||
|
@ -83,7 +95,7 @@ func (vs *VolumeServer) DeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// make sure all chunks had deleted before delete manifest
|
// make sure all chunks had deleted before delete manifest
|
||||||
if e := chunkManifest.DeleteChunks(vs.GetMaster()); e != nil {
|
if e := chunkManifest.DeleteChunks(vs.GetMaster(), vs.grpcDialOption); e != nil {
|
||||||
writeJsonError(w, r, http.StatusInternalServerError, fmt.Errorf("Delete chunks error: %v", e))
|
writeJsonError(w, r, http.StatusInternalServerError, fmt.Errorf("Delete chunks error: %v", e))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package storage
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -45,12 +46,12 @@ optimized more later).
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func (v *Volume) Synchronize(volumeServer string) (err error) {
|
func (v *Volume) Synchronize(volumeServer string, grpcDialOption grpc.DialOption) (err error) {
|
||||||
var lastCompactRevision uint16 = 0
|
var lastCompactRevision uint16 = 0
|
||||||
var compactRevision uint16 = 0
|
var compactRevision uint16 = 0
|
||||||
var masterMap *needle.CompactMap
|
var masterMap *needle.CompactMap
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
if masterMap, _, compactRevision, err = fetchVolumeFileEntries(volumeServer, v.Id); err != nil {
|
if masterMap, _, compactRevision, err = fetchVolumeFileEntries(volumeServer, grpcDialOption, v.Id); err != nil {
|
||||||
return fmt.Errorf("Failed to sync volume %d entries with %s: %v", v.Id, volumeServer, err)
|
return fmt.Errorf("Failed to sync volume %d entries with %s: %v", v.Id, volumeServer, err)
|
||||||
}
|
}
|
||||||
if lastCompactRevision != compactRevision && lastCompactRevision != 0 {
|
if lastCompactRevision != compactRevision && lastCompactRevision != 0 {
|
||||||
|
@ -62,7 +63,7 @@ func (v *Volume) Synchronize(volumeServer string) (err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastCompactRevision = compactRevision
|
lastCompactRevision = compactRevision
|
||||||
if err = v.trySynchronizing(volumeServer, masterMap, compactRevision); err == nil {
|
if err = v.trySynchronizing(volumeServer, grpcDialOption, masterMap, compactRevision); err == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +78,7 @@ func (a ByOffset) Less(i, j int) bool { return a[i].Offset < a[j].Offset }
|
||||||
|
|
||||||
// trySynchronizing sync with remote volume server incrementally by
|
// trySynchronizing sync with remote volume server incrementally by
|
||||||
// make up the local and remote delta.
|
// make up the local and remote delta.
|
||||||
func (v *Volume) trySynchronizing(volumeServer string, masterMap *needle.CompactMap, compactRevision uint16) error {
|
func (v *Volume) trySynchronizing(volumeServer string, grpcDialOption grpc.DialOption, masterMap *needle.CompactMap, compactRevision uint16) error {
|
||||||
slaveIdxFile, err := os.Open(v.nm.IndexFileName())
|
slaveIdxFile, err := os.Open(v.nm.IndexFileName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Open volume %d index file: %v", v.Id, err)
|
return fmt.Errorf("Open volume %d index file: %v", v.Id, err)
|
||||||
|
@ -126,7 +127,7 @@ func (v *Volume) trySynchronizing(volumeServer string, masterMap *needle.Compact
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// add master file entry to local data file
|
// add master file entry to local data file
|
||||||
if err := v.fetchNeedle(volumeServer, needleValue, compactRevision); err != nil {
|
if err := v.fetchNeedle(volumeServer, grpcDialOption, needleValue, compactRevision); err != nil {
|
||||||
glog.V(0).Infof("Fetch needle %v from %s: %v", needleValue, volumeServer, err)
|
glog.V(0).Infof("Fetch needle %v from %s: %v", needleValue, volumeServer, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -136,16 +137,16 @@ func (v *Volume) trySynchronizing(volumeServer string, masterMap *needle.Compact
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchVolumeFileEntries(volumeServer string, vid VolumeId) (m *needle.CompactMap, lastOffset uint64, compactRevision uint16, err error) {
|
func fetchVolumeFileEntries(volumeServer string, grpcDialOption grpc.DialOption, vid VolumeId) (m *needle.CompactMap, lastOffset uint64, compactRevision uint16, err error) {
|
||||||
m = needle.NewCompactMap()
|
m = needle.NewCompactMap()
|
||||||
|
|
||||||
syncStatus, err := operation.GetVolumeSyncStatus(volumeServer, uint32(vid))
|
syncStatus, err := operation.GetVolumeSyncStatus(volumeServer, grpcDialOption, uint32(vid))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return m, 0, 0, err
|
return m, 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
total := 0
|
total := 0
|
||||||
err = operation.GetVolumeIdxEntries(volumeServer, uint32(vid), func(key NeedleId, offset Offset, size uint32) {
|
err = operation.GetVolumeIdxEntries(volumeServer, grpcDialOption, uint32(vid), func(key NeedleId, offset Offset, size uint32) {
|
||||||
// println("remote key", key, "offset", offset*NeedlePaddingSize, "size", size)
|
// println("remote key", key, "offset", offset*NeedlePaddingSize, "size", size)
|
||||||
if offset > 0 && size != TombstoneFileSize {
|
if offset > 0 && size != TombstoneFileSize {
|
||||||
m.Set(NeedleId(key), offset, size)
|
m.Set(NeedleId(key), offset, size)
|
||||||
|
@ -187,9 +188,9 @@ func (v *Volume) removeNeedle(key NeedleId) {
|
||||||
// fetchNeedle fetches a remote volume needle by vid, id, offset
|
// fetchNeedle fetches a remote volume needle by vid, id, offset
|
||||||
// The compact revision is checked first in case the remote volume
|
// The compact revision is checked first in case the remote volume
|
||||||
// is compacted and the offset is invalid any more.
|
// is compacted and the offset is invalid any more.
|
||||||
func (v *Volume) fetchNeedle(volumeServer string, needleValue needle.NeedleValue, compactRevision uint16) error {
|
func (v *Volume) fetchNeedle(volumeServer string, grpcDialOption grpc.DialOption, needleValue needle.NeedleValue, compactRevision uint16) error {
|
||||||
|
|
||||||
return operation.WithVolumeServerClient(volumeServer, func(client volume_server_pb.VolumeServerClient) error {
|
return operation.WithVolumeServerClient(volumeServer, grpcDialOption, func(client volume_server_pb.VolumeServerClient) error {
|
||||||
stream, err := client.VolumeSyncData(context.Background(), &volume_server_pb.VolumeSyncDataRequest{
|
stream, err := client.VolumeSyncData(context.Background(), &volume_server_pb.VolumeSyncDataRequest{
|
||||||
VolumdId: uint32(v.Id),
|
VolumdId: uint32(v.Id),
|
||||||
Revision: uint32(compactRevision),
|
Revision: uint32(compactRevision),
|
||||||
|
|
|
@ -2,6 +2,7 @@ package topology
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/operation"
|
"github.com/chrislusf/seaweedfs/weed/operation"
|
||||||
|
@ -13,9 +14,9 @@ type AllocateVolumeResult struct {
|
||||||
Error string
|
Error string
|
||||||
}
|
}
|
||||||
|
|
||||||
func AllocateVolume(dn *DataNode, vid storage.VolumeId, option *VolumeGrowOption) error {
|
func AllocateVolume(dn *DataNode, grpcDialOption grpc.DialOption, vid storage.VolumeId, option *VolumeGrowOption) error {
|
||||||
|
|
||||||
return operation.WithVolumeServerClient(dn.Url(), func(client volume_server_pb.VolumeServerClient) error {
|
return operation.WithVolumeServerClient(dn.Url(), grpcDialOption, func(client volume_server_pb.VolumeServerClient) error {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,7 @@ func ReplicatedDelete(masterNode string, store *storage.Store,
|
||||||
if needToReplicate { //send to other replica locations
|
if needToReplicate { //send to other replica locations
|
||||||
if r.FormValue("type") != "replicate" {
|
if r.FormValue("type") != "replicate" {
|
||||||
if err = distributedOperation(masterNode, store, volumeId, func(location operation.Location) error {
|
if err = distributedOperation(masterNode, store, volumeId, func(location operation.Location) error {
|
||||||
return util.Delete("http://"+location.Url+r.URL.Path+"?type=replicate", jwt)
|
return util.Delete("http://"+location.Url+r.URL.Path+"?type=replicate", string(jwt))
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
ret = 0
|
ret = 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package topology
|
package topology
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"google.golang.org/grpc"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -8,7 +9,7 @@ import (
|
||||||
"github.com/chrislusf/seaweedfs/weed/storage"
|
"github.com/chrislusf/seaweedfs/weed/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t *Topology) StartRefreshWritableVolumes(garbageThreshold float64, preallocate int64) {
|
func (t *Topology) StartRefreshWritableVolumes(grpcDialOption grpc.DialOption, garbageThreshold float64, preallocate int64) {
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
if t.IsLeader() {
|
if t.IsLeader() {
|
||||||
|
@ -22,7 +23,7 @@ func (t *Topology) StartRefreshWritableVolumes(garbageThreshold float64, preallo
|
||||||
c := time.Tick(15 * time.Minute)
|
c := time.Tick(15 * time.Minute)
|
||||||
for _ = range c {
|
for _ = range c {
|
||||||
if t.IsLeader() {
|
if t.IsLeader() {
|
||||||
t.Vacuum(garbageThreshold, preallocate)
|
t.Vacuum(grpcDialOption, garbageThreshold, preallocate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(garbageThreshold)
|
}(garbageThreshold)
|
||||||
|
|
|
@ -2,6 +2,7 @@ package topology
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/glog"
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||||
|
@ -10,11 +11,11 @@ import (
|
||||||
"github.com/chrislusf/seaweedfs/weed/storage"
|
"github.com/chrislusf/seaweedfs/weed/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func batchVacuumVolumeCheck(vl *VolumeLayout, vid storage.VolumeId, locationlist *VolumeLocationList, garbageThreshold float64) bool {
|
func batchVacuumVolumeCheck(grpcDialOption grpc.DialOption, vl *VolumeLayout, vid storage.VolumeId, locationlist *VolumeLocationList, garbageThreshold float64) bool {
|
||||||
ch := make(chan bool, locationlist.Length())
|
ch := make(chan bool, locationlist.Length())
|
||||||
for index, dn := range locationlist.list {
|
for index, dn := range locationlist.list {
|
||||||
go func(index int, url string, vid storage.VolumeId) {
|
go func(index int, url string, vid storage.VolumeId) {
|
||||||
err := operation.WithVolumeServerClient(url, func(volumeServerClient volume_server_pb.VolumeServerClient) error {
|
err := operation.WithVolumeServerClient(url, grpcDialOption, func(volumeServerClient volume_server_pb.VolumeServerClient) error {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
@ -46,13 +47,13 @@ func batchVacuumVolumeCheck(vl *VolumeLayout, vid storage.VolumeId, locationlist
|
||||||
}
|
}
|
||||||
return isCheckSuccess
|
return isCheckSuccess
|
||||||
}
|
}
|
||||||
func batchVacuumVolumeCompact(vl *VolumeLayout, vid storage.VolumeId, locationlist *VolumeLocationList, preallocate int64) bool {
|
func batchVacuumVolumeCompact(grpcDialOption grpc.DialOption, vl *VolumeLayout, vid storage.VolumeId, locationlist *VolumeLocationList, preallocate int64) bool {
|
||||||
vl.removeFromWritable(vid)
|
vl.removeFromWritable(vid)
|
||||||
ch := make(chan bool, locationlist.Length())
|
ch := make(chan bool, locationlist.Length())
|
||||||
for index, dn := range locationlist.list {
|
for index, dn := range locationlist.list {
|
||||||
go func(index int, url string, vid storage.VolumeId) {
|
go func(index int, url string, vid storage.VolumeId) {
|
||||||
glog.V(0).Infoln(index, "Start vacuuming", vid, "on", url)
|
glog.V(0).Infoln(index, "Start vacuuming", vid, "on", url)
|
||||||
err := operation.WithVolumeServerClient(url, func(volumeServerClient volume_server_pb.VolumeServerClient) error {
|
err := operation.WithVolumeServerClient(url, grpcDialOption, func(volumeServerClient volume_server_pb.VolumeServerClient) error {
|
||||||
_, err := volumeServerClient.VacuumVolumeCompact(context.Background(), &volume_server_pb.VacuumVolumeCompactRequest{
|
_, err := volumeServerClient.VacuumVolumeCompact(context.Background(), &volume_server_pb.VacuumVolumeCompactRequest{
|
||||||
VolumdId: uint32(vid),
|
VolumdId: uint32(vid),
|
||||||
})
|
})
|
||||||
|
@ -79,11 +80,11 @@ func batchVacuumVolumeCompact(vl *VolumeLayout, vid storage.VolumeId, locationli
|
||||||
}
|
}
|
||||||
return isVacuumSuccess
|
return isVacuumSuccess
|
||||||
}
|
}
|
||||||
func batchVacuumVolumeCommit(vl *VolumeLayout, vid storage.VolumeId, locationlist *VolumeLocationList) bool {
|
func batchVacuumVolumeCommit(grpcDialOption grpc.DialOption, vl *VolumeLayout, vid storage.VolumeId, locationlist *VolumeLocationList) bool {
|
||||||
isCommitSuccess := true
|
isCommitSuccess := true
|
||||||
for _, dn := range locationlist.list {
|
for _, dn := range locationlist.list {
|
||||||
glog.V(0).Infoln("Start Committing vacuum", vid, "on", dn.Url())
|
glog.V(0).Infoln("Start Committing vacuum", vid, "on", dn.Url())
|
||||||
err := operation.WithVolumeServerClient(dn.Url(), func(volumeServerClient volume_server_pb.VolumeServerClient) error {
|
err := operation.WithVolumeServerClient(dn.Url(), grpcDialOption, func(volumeServerClient volume_server_pb.VolumeServerClient) error {
|
||||||
_, err := volumeServerClient.VacuumVolumeCommit(context.Background(), &volume_server_pb.VacuumVolumeCommitRequest{
|
_, err := volumeServerClient.VacuumVolumeCommit(context.Background(), &volume_server_pb.VacuumVolumeCommitRequest{
|
||||||
VolumdId: uint32(vid),
|
VolumdId: uint32(vid),
|
||||||
})
|
})
|
||||||
|
@ -101,10 +102,10 @@ func batchVacuumVolumeCommit(vl *VolumeLayout, vid storage.VolumeId, locationlis
|
||||||
}
|
}
|
||||||
return isCommitSuccess
|
return isCommitSuccess
|
||||||
}
|
}
|
||||||
func batchVacuumVolumeCleanup(vl *VolumeLayout, vid storage.VolumeId, locationlist *VolumeLocationList) {
|
func batchVacuumVolumeCleanup(grpcDialOption grpc.DialOption, vl *VolumeLayout, vid storage.VolumeId, locationlist *VolumeLocationList) {
|
||||||
for _, dn := range locationlist.list {
|
for _, dn := range locationlist.list {
|
||||||
glog.V(0).Infoln("Start cleaning up", vid, "on", dn.Url())
|
glog.V(0).Infoln("Start cleaning up", vid, "on", dn.Url())
|
||||||
err := operation.WithVolumeServerClient(dn.Url(), func(volumeServerClient volume_server_pb.VolumeServerClient) error {
|
err := operation.WithVolumeServerClient(dn.Url(), grpcDialOption, func(volumeServerClient volume_server_pb.VolumeServerClient) error {
|
||||||
_, err := volumeServerClient.VacuumVolumeCleanup(context.Background(), &volume_server_pb.VacuumVolumeCleanupRequest{
|
_, err := volumeServerClient.VacuumVolumeCleanup(context.Background(), &volume_server_pb.VacuumVolumeCleanupRequest{
|
||||||
VolumdId: uint32(vid),
|
VolumdId: uint32(vid),
|
||||||
})
|
})
|
||||||
|
@ -118,21 +119,21 @@ func batchVacuumVolumeCleanup(vl *VolumeLayout, vid storage.VolumeId, locationli
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Topology) Vacuum(garbageThreshold float64, preallocate int64) int {
|
func (t *Topology) Vacuum(grpcDialOption grpc.DialOption, garbageThreshold float64, preallocate int64) int {
|
||||||
glog.V(1).Infof("Start vacuum on demand with threshold: %f", garbageThreshold)
|
glog.V(1).Infof("Start vacuum on demand with threshold: %f", garbageThreshold)
|
||||||
for _, col := range t.collectionMap.Items() {
|
for _, col := range t.collectionMap.Items() {
|
||||||
c := col.(*Collection)
|
c := col.(*Collection)
|
||||||
for _, vl := range c.storageType2VolumeLayout.Items() {
|
for _, vl := range c.storageType2VolumeLayout.Items() {
|
||||||
if vl != nil {
|
if vl != nil {
|
||||||
volumeLayout := vl.(*VolumeLayout)
|
volumeLayout := vl.(*VolumeLayout)
|
||||||
vacuumOneVolumeLayout(volumeLayout, c, garbageThreshold, preallocate)
|
vacuumOneVolumeLayout(grpcDialOption, volumeLayout, c, garbageThreshold, preallocate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func vacuumOneVolumeLayout(volumeLayout *VolumeLayout, c *Collection, garbageThreshold float64, preallocate int64) {
|
func vacuumOneVolumeLayout(grpcDialOption grpc.DialOption, volumeLayout *VolumeLayout, c *Collection, garbageThreshold float64, preallocate int64) {
|
||||||
|
|
||||||
volumeLayout.accessLock.RLock()
|
volumeLayout.accessLock.RLock()
|
||||||
tmpMap := make(map[storage.VolumeId]*VolumeLocationList)
|
tmpMap := make(map[storage.VolumeId]*VolumeLocationList)
|
||||||
|
@ -152,11 +153,11 @@ func vacuumOneVolumeLayout(volumeLayout *VolumeLayout, c *Collection, garbageThr
|
||||||
}
|
}
|
||||||
|
|
||||||
glog.V(2).Infof("check vacuum on collection:%s volume:%d", c.Name, vid)
|
glog.V(2).Infof("check vacuum on collection:%s volume:%d", c.Name, vid)
|
||||||
if batchVacuumVolumeCheck(volumeLayout, vid, locationList, garbageThreshold) {
|
if batchVacuumVolumeCheck(grpcDialOption, volumeLayout, vid, locationList, garbageThreshold) {
|
||||||
if batchVacuumVolumeCompact(volumeLayout, vid, locationList, preallocate) {
|
if batchVacuumVolumeCompact(grpcDialOption, volumeLayout, vid, locationList, preallocate) {
|
||||||
batchVacuumVolumeCommit(volumeLayout, vid, locationList)
|
batchVacuumVolumeCommit(grpcDialOption, volumeLayout, vid, locationList)
|
||||||
} else {
|
} else {
|
||||||
batchVacuumVolumeCleanup(volumeLayout, vid, locationList)
|
batchVacuumVolumeCleanup(grpcDialOption, volumeLayout, vid, locationList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package topology
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"google.golang.org/grpc"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
@ -55,19 +56,19 @@ func (vg *VolumeGrowth) findVolumeCount(copyCount int) (count int) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vg *VolumeGrowth) AutomaticGrowByType(option *VolumeGrowOption, topo *Topology) (count int, err error) {
|
func (vg *VolumeGrowth) AutomaticGrowByType(option *VolumeGrowOption, grpcDialOption grpc.DialOption, topo *Topology) (count int, err error) {
|
||||||
count, err = vg.GrowByCountAndType(vg.findVolumeCount(option.ReplicaPlacement.GetCopyCount()), option, topo)
|
count, err = vg.GrowByCountAndType(grpcDialOption, vg.findVolumeCount(option.ReplicaPlacement.GetCopyCount()), option, topo)
|
||||||
if count > 0 && count%option.ReplicaPlacement.GetCopyCount() == 0 {
|
if count > 0 && count%option.ReplicaPlacement.GetCopyCount() == 0 {
|
||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
return count, err
|
return count, err
|
||||||
}
|
}
|
||||||
func (vg *VolumeGrowth) GrowByCountAndType(targetCount int, option *VolumeGrowOption, topo *Topology) (counter int, err error) {
|
func (vg *VolumeGrowth) GrowByCountAndType(grpcDialOption grpc.DialOption, targetCount int, option *VolumeGrowOption, topo *Topology) (counter int, err error) {
|
||||||
vg.accessLock.Lock()
|
vg.accessLock.Lock()
|
||||||
defer vg.accessLock.Unlock()
|
defer vg.accessLock.Unlock()
|
||||||
|
|
||||||
for i := 0; i < targetCount; i++ {
|
for i := 0; i < targetCount; i++ {
|
||||||
if c, e := vg.findAndGrow(topo, option); e == nil {
|
if c, e := vg.findAndGrow(grpcDialOption, topo, option); e == nil {
|
||||||
counter += c
|
counter += c
|
||||||
} else {
|
} else {
|
||||||
return counter, e
|
return counter, e
|
||||||
|
@ -76,13 +77,13 @@ func (vg *VolumeGrowth) GrowByCountAndType(targetCount int, option *VolumeGrowOp
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vg *VolumeGrowth) findAndGrow(topo *Topology, option *VolumeGrowOption) (int, error) {
|
func (vg *VolumeGrowth) findAndGrow(grpcDialOption grpc.DialOption, topo *Topology, option *VolumeGrowOption) (int, error) {
|
||||||
servers, e := vg.findEmptySlotsForOneVolume(topo, option)
|
servers, e := vg.findEmptySlotsForOneVolume(topo, option)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return 0, e
|
return 0, e
|
||||||
}
|
}
|
||||||
vid := topo.NextVolumeId()
|
vid := topo.NextVolumeId()
|
||||||
err := vg.grow(topo, vid, option, servers...)
|
err := vg.grow(grpcDialOption, topo, vid, option, servers...)
|
||||||
return len(servers), err
|
return len(servers), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,9 +190,9 @@ func (vg *VolumeGrowth) findEmptySlotsForOneVolume(topo *Topology, option *Volum
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vg *VolumeGrowth) grow(topo *Topology, vid storage.VolumeId, option *VolumeGrowOption, servers ...*DataNode) error {
|
func (vg *VolumeGrowth) grow(grpcDialOption grpc.DialOption, topo *Topology, vid storage.VolumeId, option *VolumeGrowOption, servers ...*DataNode) error {
|
||||||
for _, server := range servers {
|
for _, server := range servers {
|
||||||
if err := AllocateVolume(server, vid, option); err == nil {
|
if err := AllocateVolume(server, grpcDialOption, vid, option); err == nil {
|
||||||
vi := storage.VolumeInfo{
|
vi := storage.VolumeInfo{
|
||||||
Id: vid,
|
Id: vid,
|
||||||
Size: 0,
|
Size: 0,
|
||||||
|
|
|
@ -17,25 +17,38 @@ var (
|
||||||
grpcClientsLock sync.Mutex
|
grpcClientsLock sync.Mutex
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewGrpcServer() *grpc.Server {
|
func NewGrpcServer(opts ...grpc.ServerOption) *grpc.Server {
|
||||||
return grpc.NewServer(grpc.KeepaliveParams(keepalive.ServerParameters{
|
var options []grpc.ServerOption
|
||||||
|
options = append(options, grpc.KeepaliveParams(keepalive.ServerParameters{
|
||||||
Time: 10 * time.Second, // wait time before ping if no activity
|
Time: 10 * time.Second, // wait time before ping if no activity
|
||||||
Timeout: 20 * time.Second, // ping timeout
|
Timeout: 20 * time.Second, // ping timeout
|
||||||
}), grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
|
}), grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
|
||||||
MinTime: 60 * time.Second, // min time a client should wait before sending a ping
|
MinTime: 60 * time.Second, // min time a client should wait before sending a ping
|
||||||
}))
|
}))
|
||||||
|
for _, opt := range opts {
|
||||||
|
if opt != nil {
|
||||||
|
options = append(options, opt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return grpc.NewServer(options...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GrpcDial(address string, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
|
func GrpcDial(address string, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
|
||||||
// opts = append(opts, grpc.WithBlock())
|
// opts = append(opts, grpc.WithBlock())
|
||||||
// opts = append(opts, grpc.WithTimeout(time.Duration(5*time.Second)))
|
// opts = append(opts, grpc.WithTimeout(time.Duration(5*time.Second)))
|
||||||
opts = append(opts, grpc.WithInsecure())
|
var options []grpc.DialOption
|
||||||
opts = append(opts, grpc.WithKeepaliveParams(keepalive.ClientParameters{
|
options = append(options,
|
||||||
|
// grpc.WithInsecure(),
|
||||||
|
grpc.WithKeepaliveParams(keepalive.ClientParameters{
|
||||||
Time: 30 * time.Second, // client ping server if no activity for this long
|
Time: 30 * time.Second, // client ping server if no activity for this long
|
||||||
Timeout: 20 * time.Second,
|
Timeout: 20 * time.Second,
|
||||||
}))
|
}))
|
||||||
|
for _, opt := range opts {
|
||||||
return grpc.Dial(address, opts...)
|
if opt != nil {
|
||||||
|
options = append(options, opt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return grpc.Dial(address, options...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithCachedGrpcClient(fn func(*grpc.ClientConn) error, address string, opts ...grpc.DialOption) error {
|
func WithCachedGrpcClient(fn func(*grpc.ClientConn) error, address string, opts ...grpc.DialOption) error {
|
||||||
|
|
|
@ -12,8 +12,6 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/security"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -97,7 +95,7 @@ func Head(url string) (http.Header, error) {
|
||||||
return r.Header, nil
|
return r.Header, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Delete(url string, jwt security.EncodedJwt) error {
|
func Delete(url string, jwt string) error {
|
||||||
req, err := http.NewRequest("DELETE", url, nil)
|
req, err := http.NewRequest("DELETE", url, nil)
|
||||||
if jwt != "" {
|
if jwt != "" {
|
||||||
req.Header.Set("Authorization", "BEARER "+string(jwt))
|
req.Header.Set("Authorization", "BEARER "+string(jwt))
|
||||||
|
|
|
@ -3,12 +3,13 @@ package wdclient
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/glog"
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||||
"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
|
"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
|
||||||
"github.com/chrislusf/seaweedfs/weed/util"
|
"github.com/chrislusf/seaweedfs/weed/util"
|
||||||
"math/rand"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MasterClient struct {
|
type MasterClient struct {
|
||||||
|
@ -16,15 +17,17 @@ type MasterClient struct {
|
||||||
name string
|
name string
|
||||||
currentMaster string
|
currentMaster string
|
||||||
masters []string
|
masters []string
|
||||||
|
grpcDialOption grpc.DialOption
|
||||||
|
|
||||||
vidMap
|
vidMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMasterClient(ctx context.Context, clientName string, masters []string) *MasterClient {
|
func NewMasterClient(ctx context.Context, grpcDialOption grpc.DialOption, clientName string, masters []string) *MasterClient {
|
||||||
return &MasterClient{
|
return &MasterClient{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
name: clientName,
|
name: clientName,
|
||||||
masters: masters,
|
masters: masters,
|
||||||
|
grpcDialOption: grpcDialOption,
|
||||||
vidMap: newVidMap(),
|
vidMap: newVidMap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +53,7 @@ func (mc *MasterClient) KeepConnectedToMaster() {
|
||||||
func (mc *MasterClient) tryAllMasters() {
|
func (mc *MasterClient) tryAllMasters() {
|
||||||
for _, master := range mc.masters {
|
for _, master := range mc.masters {
|
||||||
glog.V(0).Infof("Connecting to master %v", master)
|
glog.V(0).Infof("Connecting to master %v", master)
|
||||||
gprcErr := withMasterClient(master, func(client master_pb.SeaweedClient) error {
|
gprcErr := withMasterClient(master, mc.grpcDialOption, func(client master_pb.SeaweedClient) error {
|
||||||
|
|
||||||
stream, err := client.KeepConnected(context.Background())
|
stream, err := client.KeepConnected(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -96,14 +99,14 @@ func (mc *MasterClient) tryAllMasters() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func withMasterClient(master string, fn func(client master_pb.SeaweedClient) error) error {
|
func withMasterClient(master string, grpcDialOption grpc.DialOption, fn func(client master_pb.SeaweedClient) error) error {
|
||||||
|
|
||||||
masterGrpcAddress, parseErr := util.ParseServerToGrpcAddress(master, 0)
|
masterGrpcAddress, parseErr := util.ParseServerToGrpcAddress(master, 0)
|
||||||
if parseErr != nil {
|
if parseErr != nil {
|
||||||
return fmt.Errorf("failed to parse master grpc %v", master)
|
return fmt.Errorf("failed to parse master grpc %v", master)
|
||||||
}
|
}
|
||||||
|
|
||||||
grpcConnection, err := util.GrpcDial(masterGrpcAddress)
|
grpcConnection, err := util.GrpcDial(masterGrpcAddress, grpcDialOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("fail to dial %s: %v", master, err)
|
return fmt.Errorf("fail to dial %s: %v", master, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
package wdclient
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SeaweedClient struct {
|
|
||||||
*MasterClient
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewSeaweedClient(ctx context.Context, clientName string, masters []string) *SeaweedClient {
|
|
||||||
return &SeaweedClient{
|
|
||||||
MasterClient: NewMasterClient(ctx, clientName, masters),
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue