* Implemented AmazonS3PathPrefix

* Remove unecessary method

* fix for test

* fix for test which are failing

* fix for test which are failing

* fix for test

Co-authored-by: Dusan Panic <dusan@salestrekker.com>
Этот коммит содержится в:
Dušan Panić
2020-07-07 00:20:13 +02:00
коммит произвёл GitHub
родитель 70084f107c
Коммит 83a80a2422
6 изменённых файлов: 52 добавлений и 18 удалений

Просмотреть файл

@@ -404,6 +404,7 @@ func TestS3TestConnection(t *testing.T) {
AmazonS3Bucket: model.NewString(""), AmazonS3Bucket: model.NewString(""),
AmazonS3Endpoint: model.NewString(s3Endpoint), AmazonS3Endpoint: model.NewString(s3Endpoint),
AmazonS3Region: model.NewString(""), AmazonS3Region: model.NewString(""),
AmazonS3PathPrefix: model.NewString(""),
AmazonS3SSL: model.NewBool(false), AmazonS3SSL: model.NewBool(false),
}, },
} }
@@ -420,6 +421,7 @@ func TestS3TestConnection(t *testing.T) {
// If this fails, check the test configuration to ensure minio is setup with the // If this fails, check the test configuration to ensure minio is setup with the
// `mattermost-test` bucket defined by model.MINIO_BUCKET. // `mattermost-test` bucket defined by model.MINIO_BUCKET.
*config.FileSettings.AmazonS3Bucket = model.MINIO_BUCKET *config.FileSettings.AmazonS3Bucket = model.MINIO_BUCKET
config.FileSettings.AmazonS3PathPrefix = model.NewString("")
*config.FileSettings.AmazonS3Region = "us-east-1" *config.FileSettings.AmazonS3Region = "us-east-1"
_, resp = th.SystemAdminClient.TestS3Connection(&config) _, resp = th.SystemAdminClient.TestS3Connection(&config)
CheckOKStatus(t, resp) CheckOKStatus(t, resp)

Просмотреть файл

@@ -498,6 +498,7 @@ func TestPluginSync(t *testing.T) {
cfg.FileSettings.AmazonS3AccessKeyId = model.NewString(model.MINIO_ACCESS_KEY) cfg.FileSettings.AmazonS3AccessKeyId = model.NewString(model.MINIO_ACCESS_KEY)
cfg.FileSettings.AmazonS3SecretAccessKey = model.NewString(model.MINIO_SECRET_KEY) cfg.FileSettings.AmazonS3SecretAccessKey = model.NewString(model.MINIO_SECRET_KEY)
cfg.FileSettings.AmazonS3Bucket = model.NewString(model.MINIO_BUCKET) cfg.FileSettings.AmazonS3Bucket = model.NewString(model.MINIO_BUCKET)
cfg.FileSettings.AmazonS3PathPrefix = model.NewString("")
cfg.FileSettings.AmazonS3Endpoint = model.NewString(s3Endpoint) cfg.FileSettings.AmazonS3Endpoint = model.NewString(s3Endpoint)
cfg.FileSettings.AmazonS3Region = model.NewString("") cfg.FileSettings.AmazonS3Region = model.NewString("")
cfg.FileSettings.AmazonS3SSL = model.NewBool(false) cfg.FileSettings.AmazonS3SSL = model.NewBool(false)

Просмотреть файл

@@ -1265,6 +1265,7 @@ type FileSettings struct {
AmazonS3AccessKeyId *string `restricted:"true"` AmazonS3AccessKeyId *string `restricted:"true"`
AmazonS3SecretAccessKey *string `restricted:"true"` AmazonS3SecretAccessKey *string `restricted:"true"`
AmazonS3Bucket *string `restricted:"true"` AmazonS3Bucket *string `restricted:"true"`
AmazonS3PathPrefix *string `restricted:"true"`
AmazonS3Region *string `restricted:"true"` AmazonS3Region *string `restricted:"true"`
AmazonS3Endpoint *string `restricted:"true"` AmazonS3Endpoint *string `restricted:"true"`
AmazonS3SSL *bool `restricted:"true"` AmazonS3SSL *bool `restricted:"true"`
@@ -1329,6 +1330,10 @@ func (s *FileSettings) SetDefaults(isUpdate bool) {
s.AmazonS3Bucket = NewString("") s.AmazonS3Bucket = NewString("")
} }
if s.AmazonS3PathPrefix == nil {
s.AmazonS3PathPrefix = NewString("")
}
if s.AmazonS3Region == nil { if s.AmazonS3Region == nil {
s.AmazonS3Region = NewString("") s.AmazonS3Region = NewString("")
} }

Просмотреть файл

@@ -41,6 +41,7 @@ func NewFileBackend(settings *model.FileSettings, enableComplianceFeatures bool)
signV2: settings.AmazonS3SignV2 != nil && *settings.AmazonS3SignV2, signV2: settings.AmazonS3SignV2 != nil && *settings.AmazonS3SignV2,
region: *settings.AmazonS3Region, region: *settings.AmazonS3Region,
bucket: *settings.AmazonS3Bucket, bucket: *settings.AmazonS3Bucket,
pathPrefix: *settings.AmazonS3PathPrefix,
encrypt: settings.AmazonS3SSE != nil && *settings.AmazonS3SSE && enableComplianceFeatures, encrypt: settings.AmazonS3SSE != nil && *settings.AmazonS3SSE && enableComplianceFeatures,
trace: settings.AmazonS3Trace != nil && *settings.AmazonS3Trace, trace: settings.AmazonS3Trace != nil && *settings.AmazonS3Trace,
}, nil }, nil

Просмотреть файл

@@ -76,6 +76,7 @@ func runBackendTest(t *testing.T, encrypt bool) {
AmazonS3Bucket: model.NewString(model.MINIO_BUCKET), AmazonS3Bucket: model.NewString(model.MINIO_BUCKET),
AmazonS3Region: model.NewString(""), AmazonS3Region: model.NewString(""),
AmazonS3Endpoint: model.NewString(s3Endpoint), AmazonS3Endpoint: model.NewString(s3Endpoint),
AmazonS3PathPrefix: model.NewString(""),
AmazonS3SSL: model.NewBool(false), AmazonS3SSL: model.NewBool(false),
AmazonS3SSE: model.NewBool(encrypt), AmazonS3SSE: model.NewBool(encrypt),
}, },

Просмотреть файл

@@ -28,6 +28,7 @@ type S3FileBackend struct {
signV2 bool signV2 bool
region string region string
bucket string bucket string
pathPrefix string
encrypt bool encrypt bool
trace bool trace bool
} }
@@ -89,10 +90,13 @@ func (b *S3FileBackend) Reader(path string) (ReadCloseSeeker, *model.AppError) {
if err != nil { if err != nil {
return nil, model.NewAppError("Reader", "api.file.reader.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, model.NewAppError("Reader", "api.file.reader.s3.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
path = filepath.Join(b.pathPrefix, path)
minioObject, err := s3Clnt.GetObject(b.bucket, path, s3.GetObjectOptions{}) minioObject, err := s3Clnt.GetObject(b.bucket, path, s3.GetObjectOptions{})
if err != nil { if err != nil {
return nil, model.NewAppError("Reader", "api.file.reader.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, model.NewAppError("Reader", "api.file.reader.s3.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
return minioObject, nil return minioObject, nil
} }
@@ -101,10 +105,13 @@ func (b *S3FileBackend) ReadFile(path string) ([]byte, *model.AppError) {
if err != nil { if err != nil {
return nil, model.NewAppError("ReadFile", "api.file.read_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, model.NewAppError("ReadFile", "api.file.read_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
path = filepath.Join(b.pathPrefix, path)
minioObject, err := s3Clnt.GetObject(b.bucket, path, s3.GetObjectOptions{}) minioObject, err := s3Clnt.GetObject(b.bucket, path, s3.GetObjectOptions{})
if err != nil { if err != nil {
return nil, model.NewAppError("ReadFile", "api.file.read_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, model.NewAppError("ReadFile", "api.file.read_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
defer minioObject.Close() defer minioObject.Close()
if f, err := ioutil.ReadAll(minioObject); err != nil { if f, err := ioutil.ReadAll(minioObject); err != nil {
return nil, model.NewAppError("ReadFile", "api.file.read_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, model.NewAppError("ReadFile", "api.file.read_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError)
@@ -119,6 +126,8 @@ func (b *S3FileBackend) FileExists(path string) (bool, *model.AppError) {
if err != nil { if err != nil {
return false, model.NewAppError("FileExists", "api.file.file_exists.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return false, model.NewAppError("FileExists", "api.file.file_exists.s3.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
path = filepath.Join(b.pathPrefix, path)
_, err = s3Clnt.StatObject(b.bucket, path, s3.StatObjectOptions{}) _, err = s3Clnt.StatObject(b.bucket, path, s3.StatObjectOptions{})
if err == nil { if err == nil {
@@ -138,11 +147,15 @@ func (b *S3FileBackend) CopyFile(oldPath, newPath string) *model.AppError {
return model.NewAppError("copyFile", "api.file.write_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return model.NewAppError("copyFile", "api.file.write_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
oldPath = filepath.Join(b.pathPrefix, oldPath)
newPath = filepath.Join(b.pathPrefix, newPath)
source := s3.NewSourceInfo(b.bucket, oldPath, nil) source := s3.NewSourceInfo(b.bucket, oldPath, nil)
destination, err := s3.NewDestinationInfo(b.bucket, newPath, encrypt.NewSSE(), nil) destination, err := s3.NewDestinationInfo(b.bucket, newPath, encrypt.NewSSE(), nil)
if err != nil { if err != nil {
return model.NewAppError("copyFile", "api.file.write_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return model.NewAppError("copyFile", "api.file.write_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
if err = s3Clnt.CopyObject(destination, source); err != nil { if err = s3Clnt.CopyObject(destination, source); err != nil {
return model.NewAppError("copyFile", "api.file.move_file.copy_within_s3.app_error", nil, err.Error(), http.StatusInternalServerError) return model.NewAppError("copyFile", "api.file.move_file.copy_within_s3.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
@@ -155,17 +168,23 @@ func (b *S3FileBackend) MoveFile(oldPath, newPath string) *model.AppError {
return model.NewAppError("moveFile", "api.file.write_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return model.NewAppError("moveFile", "api.file.write_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
oldPath = filepath.Join(b.pathPrefix, oldPath)
newPath = filepath.Join(b.pathPrefix, newPath)
source := s3.NewSourceInfo(b.bucket, oldPath, nil) source := s3.NewSourceInfo(b.bucket, oldPath, nil)
destination, err := s3.NewDestinationInfo(b.bucket, newPath, encrypt.NewSSE(), nil) destination, err := s3.NewDestinationInfo(b.bucket, newPath, encrypt.NewSSE(), nil)
if err != nil { if err != nil {
return model.NewAppError("moveFile", "api.file.write_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return model.NewAppError("moveFile", "api.file.write_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
if err = s3Clnt.CopyObject(destination, source); err != nil { if err = s3Clnt.CopyObject(destination, source); err != nil {
return model.NewAppError("moveFile", "api.file.move_file.copy_within_s3.app_error", nil, err.Error(), http.StatusInternalServerError) return model.NewAppError("moveFile", "api.file.move_file.copy_within_s3.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
if err = s3Clnt.RemoveObject(b.bucket, oldPath); err != nil { if err = s3Clnt.RemoveObject(b.bucket, oldPath); err != nil {
return model.NewAppError("moveFile", "api.file.move_file.delete_from_s3.app_error", nil, err.Error(), http.StatusInternalServerError) return model.NewAppError("moveFile", "api.file.move_file.delete_from_s3.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
return nil return nil
} }
@@ -176,6 +195,7 @@ func (b *S3FileBackend) WriteFile(fr io.Reader, path string) (int64, *model.AppE
} }
var contentType string var contentType string
path = filepath.Join(b.pathPrefix, path)
if ext := filepath.Ext(path); model.IsFileExtImage(ext) { if ext := filepath.Ext(path); model.IsFileExtImage(ext) {
contentType = model.GetImageMimeType(ext) contentType = model.GetImageMimeType(ext)
} else { } else {
@@ -202,6 +222,7 @@ func (b *S3FileBackend) RemoveFile(path string) *model.AppError {
return model.NewAppError("RemoveFile", "utils.file.remove_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return model.NewAppError("RemoveFile", "utils.file.remove_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
path = filepath.Join(b.pathPrefix, path)
if err := s3Clnt.RemoveObject(b.bucket, path); err != nil { if err := s3Clnt.RemoveObject(b.bucket, path); err != nil {
return model.NewAppError("RemoveFile", "utils.file.remove_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return model.NewAppError("RemoveFile", "utils.file.remove_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
@@ -240,11 +261,13 @@ func (b *S3FileBackend) ListDirectory(path string) (*[]string, *model.AppError)
doneCh := make(chan struct{}) doneCh := make(chan struct{})
defer close(doneCh) defer close(doneCh)
path = filepath.Join(b.pathPrefix, path)
if !strings.HasSuffix(path, "/") && len(path) > 0 { if !strings.HasSuffix(path, "/") && len(path) > 0 {
// s3Clnt returns only the path itself when "/" is not present // s3Clnt returns only the path itself when "/" is not present
// appending "/" to make it consistent across all filesstores // appending "/" to make it consistent across all filesstores
path = path + "/" path = path + "/"
} }
for object := range s3Clnt.ListObjects(b.bucket, path, false, doneCh) { for object := range s3Clnt.ListObjects(b.bucket, path, false, doneCh) {
if object.Err != nil { if object.Err != nil {
return nil, model.NewAppError("ListDirectory", "utils.file.list_directory.s3.app_error", nil, object.Err.Error(), http.StatusInternalServerError) return nil, model.NewAppError("ListDirectory", "utils.file.list_directory.s3.app_error", nil, object.Err.Error(), http.StatusInternalServerError)
@@ -263,6 +286,7 @@ func (b *S3FileBackend) RemoveDirectory(path string) *model.AppError {
doneCh := make(chan struct{}) doneCh := make(chan struct{})
path = filepath.Join(b.pathPrefix, path)
for err := range s3Clnt.RemoveObjects(b.bucket, getPathsFromObjectInfos(s3Clnt.ListObjects(b.bucket, path, true, doneCh))) { for err := range s3Clnt.RemoveObjects(b.bucket, getPathsFromObjectInfos(s3Clnt.ListObjects(b.bucket, path, true, doneCh))) {
if err.Err != nil { if err.Err != nil {
doneCh <- struct{}{} doneCh <- struct{}{}