GCS: add ACL support
This commit is contained in:
parent
52f3a98cc8
commit
24b0352eb6
9 changed files with 40 additions and 3 deletions
|
@ -2637,6 +2637,7 @@ func TestUserHiddenFields(t *testing.T) {
|
||||||
u2.FsConfig.Provider = sdk.GCSFilesystemProvider
|
u2.FsConfig.Provider = sdk.GCSFilesystemProvider
|
||||||
u2.FsConfig.GCSConfig.Bucket = "test"
|
u2.FsConfig.GCSConfig.Bucket = "test"
|
||||||
u2.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret("fake credentials")
|
u2.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret("fake credentials")
|
||||||
|
u2.FsConfig.GCSConfig.ACL = "bucketOwnerRead"
|
||||||
user2, _, err := httpdtest.AddUser(u2, http.StatusCreated)
|
user2, _, err := httpdtest.AddUser(u2, http.StatusCreated)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
@ -2804,6 +2805,7 @@ func TestUserHiddenFields(t *testing.T) {
|
||||||
|
|
||||||
// update the GCS user and check that the credentials are preserved
|
// update the GCS user and check that the credentials are preserved
|
||||||
user2.FsConfig.GCSConfig.Credentials = kms.NewEmptySecret()
|
user2.FsConfig.GCSConfig.Credentials = kms.NewEmptySecret()
|
||||||
|
user2.FsConfig.GCSConfig.ACL = "private"
|
||||||
_, _, err = httpdtest.UpdateUser(user2, http.StatusOK, "")
|
_, _, err = httpdtest.UpdateUser(user2, http.StatusOK, "")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
@ -13385,6 +13387,7 @@ func TestWebUserGCSMock(t *testing.T) {
|
||||||
user.FsConfig.GCSConfig.Bucket = "test"
|
user.FsConfig.GCSConfig.Bucket = "test"
|
||||||
user.FsConfig.GCSConfig.KeyPrefix = "somedir/subdir/"
|
user.FsConfig.GCSConfig.KeyPrefix = "somedir/subdir/"
|
||||||
user.FsConfig.GCSConfig.StorageClass = "standard"
|
user.FsConfig.GCSConfig.StorageClass = "standard"
|
||||||
|
user.FsConfig.GCSConfig.ACL = "publicReadWrite"
|
||||||
form := make(url.Values)
|
form := make(url.Values)
|
||||||
form.Set(csrfFormToken, csrfToken)
|
form.Set(csrfFormToken, csrfToken)
|
||||||
form.Set("username", user.Username)
|
form.Set("username", user.Username)
|
||||||
|
@ -13405,6 +13408,7 @@ func TestWebUserGCSMock(t *testing.T) {
|
||||||
form.Set("fs_provider", "2")
|
form.Set("fs_provider", "2")
|
||||||
form.Set("gcs_bucket", user.FsConfig.GCSConfig.Bucket)
|
form.Set("gcs_bucket", user.FsConfig.GCSConfig.Bucket)
|
||||||
form.Set("gcs_storage_class", user.FsConfig.GCSConfig.StorageClass)
|
form.Set("gcs_storage_class", user.FsConfig.GCSConfig.StorageClass)
|
||||||
|
form.Set("gcs_acl", user.FsConfig.GCSConfig.ACL)
|
||||||
form.Set("gcs_key_prefix", user.FsConfig.GCSConfig.KeyPrefix)
|
form.Set("gcs_key_prefix", user.FsConfig.GCSConfig.KeyPrefix)
|
||||||
form.Set("pattern_path0", "/dir1")
|
form.Set("pattern_path0", "/dir1")
|
||||||
form.Set("patterns0", "*.jpg,*.png")
|
form.Set("patterns0", "*.jpg,*.png")
|
||||||
|
@ -13441,6 +13445,7 @@ func TestWebUserGCSMock(t *testing.T) {
|
||||||
assert.Equal(t, user.FsConfig.Provider, updateUser.FsConfig.Provider)
|
assert.Equal(t, user.FsConfig.Provider, updateUser.FsConfig.Provider)
|
||||||
assert.Equal(t, user.FsConfig.GCSConfig.Bucket, updateUser.FsConfig.GCSConfig.Bucket)
|
assert.Equal(t, user.FsConfig.GCSConfig.Bucket, updateUser.FsConfig.GCSConfig.Bucket)
|
||||||
assert.Equal(t, user.FsConfig.GCSConfig.StorageClass, updateUser.FsConfig.GCSConfig.StorageClass)
|
assert.Equal(t, user.FsConfig.GCSConfig.StorageClass, updateUser.FsConfig.GCSConfig.StorageClass)
|
||||||
|
assert.Equal(t, user.FsConfig.GCSConfig.ACL, updateUser.FsConfig.GCSConfig.ACL)
|
||||||
assert.Equal(t, user.FsConfig.GCSConfig.KeyPrefix, updateUser.FsConfig.GCSConfig.KeyPrefix)
|
assert.Equal(t, user.FsConfig.GCSConfig.KeyPrefix, updateUser.FsConfig.GCSConfig.KeyPrefix)
|
||||||
if assert.Len(t, updateUser.Filters.FilePatterns, 1) {
|
if assert.Len(t, updateUser.Filters.FilePatterns, 1) {
|
||||||
assert.Equal(t, "/dir1", updateUser.Filters.FilePatterns[0].Path)
|
assert.Equal(t, "/dir1", updateUser.Filters.FilePatterns[0].Path)
|
||||||
|
|
|
@ -4234,6 +4234,9 @@ components:
|
||||||
* `1` - enabled, we try to use the Application Default Credentials (ADC) strategy to find your application's credentials
|
* `1` - enabled, we try to use the Application Default Credentials (ADC) strategy to find your application's credentials
|
||||||
storage_class:
|
storage_class:
|
||||||
type: string
|
type: string
|
||||||
|
acl:
|
||||||
|
type: string
|
||||||
|
description: 'The ACL to apply to uploaded objects. Leave empty to use the default ACL. For more information and available ACLs, refer to the JSON API here: https://cloud.google.com/storage/docs/access-control/lists#predefined-acl'
|
||||||
key_prefix:
|
key_prefix:
|
||||||
type: string
|
type: string
|
||||||
description: 'key_prefix is similar to a chroot directory for a local filesystem. If specified the user will only see contents that starts with this prefix and so you can restrict access to a specific virtual folder. The prefix, if not empty, must not start with "/" and must end with "/". If empty the whole bucket contents will be available'
|
description: 'key_prefix is similar to a chroot directory for a local filesystem. If specified the user will only see contents that starts with this prefix and so you can restrict access to a specific virtual folder. The prefix, if not empty, must not start with "/" and must end with "/". If empty the whole bucket contents will be available'
|
||||||
|
|
|
@ -859,6 +859,7 @@ func getGCSConfig(r *http.Request) (vfs.GCSFsConfig, error) {
|
||||||
|
|
||||||
config.Bucket = r.Form.Get("gcs_bucket")
|
config.Bucket = r.Form.Get("gcs_bucket")
|
||||||
config.StorageClass = r.Form.Get("gcs_storage_class")
|
config.StorageClass = r.Form.Get("gcs_storage_class")
|
||||||
|
config.ACL = r.Form.Get("gcs_acl")
|
||||||
config.KeyPrefix = r.Form.Get("gcs_key_prefix")
|
config.KeyPrefix = r.Form.Get("gcs_key_prefix")
|
||||||
autoCredentials := r.Form.Get("gcs_auto_credentials")
|
autoCredentials := r.Form.Get("gcs_auto_credentials")
|
||||||
if autoCredentials != "" {
|
if autoCredentials != "" {
|
||||||
|
|
|
@ -1299,6 +1299,9 @@ func compareGCSConfig(expected *vfs.Filesystem, actual *vfs.Filesystem) error {
|
||||||
if expected.GCSConfig.StorageClass != actual.GCSConfig.StorageClass {
|
if expected.GCSConfig.StorageClass != actual.GCSConfig.StorageClass {
|
||||||
return errors.New("GCS storage class mismatch")
|
return errors.New("GCS storage class mismatch")
|
||||||
}
|
}
|
||||||
|
if expected.GCSConfig.ACL != actual.GCSConfig.ACL {
|
||||||
|
return errors.New("GCS ACL mismatch")
|
||||||
|
}
|
||||||
if expected.GCSConfig.KeyPrefix != actual.GCSConfig.KeyPrefix &&
|
if expected.GCSConfig.KeyPrefix != actual.GCSConfig.KeyPrefix &&
|
||||||
expected.GCSConfig.KeyPrefix+"/" != actual.GCSConfig.KeyPrefix {
|
expected.GCSConfig.KeyPrefix+"/" != actual.GCSConfig.KeyPrefix {
|
||||||
return errors.New("GCS key prefix mismatch")
|
return errors.New("GCS key prefix mismatch")
|
||||||
|
|
|
@ -144,6 +144,10 @@ type GCSFsConfig struct {
|
||||||
// 0 explicit, 1 automatic
|
// 0 explicit, 1 automatic
|
||||||
AutomaticCredentials int `json:"automatic_credentials,omitempty"`
|
AutomaticCredentials int `json:"automatic_credentials,omitempty"`
|
||||||
StorageClass string `json:"storage_class,omitempty"`
|
StorageClass string `json:"storage_class,omitempty"`
|
||||||
|
// The ACL to apply to uploaded objects. Leave empty to use the default ACL.
|
||||||
|
// For more information and available ACLs, refer to the JSON API here:
|
||||||
|
// https://cloud.google.com/storage/docs/access-control/lists#predefined-acl
|
||||||
|
ACL string `json:"acl,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AzBlobFsConfig defines the configuration for Azure Blob Storage based filesystem
|
// AzBlobFsConfig defines the configuration for Azure Blob Storage based filesystem
|
||||||
|
|
|
@ -109,7 +109,7 @@
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-2"></div>
|
<div class="col-sm-2"></div>
|
||||||
<label for="idS3KeyPrefix" class="col-sm-2 col-form-label">ACL</label>
|
<label for="idS3ACL" class="col-sm-2 col-form-label">ACL</label>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
<input type="text" class="form-control" id="idS3ACL" name="s3_acl" placeholder=""
|
<input type="text" class="form-control" id="idS3ACL" name="s3_acl" placeholder=""
|
||||||
value="{{.S3Config.ACL}}" maxlength="255" aria-describedby="S3ACLHelpBlock">
|
value="{{.S3Config.ACL}}" maxlength="255" aria-describedby="S3ACLHelpBlock">
|
||||||
|
@ -174,13 +174,22 @@
|
||||||
|
|
||||||
<div class="form-group row fsconfig fsconfig-gcsfs">
|
<div class="form-group row fsconfig fsconfig-gcsfs">
|
||||||
<label for="idGCSKeyPrefix" class="col-sm-2 col-form-label">Key Prefix</label>
|
<label for="idGCSKeyPrefix" class="col-sm-2 col-form-label">Key Prefix</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-3">
|
||||||
<input type="text" class="form-control" id="idGCSKeyPrefix" name="gcs_key_prefix" placeholder=""
|
<input type="text" class="form-control" id="idGCSKeyPrefix" name="gcs_key_prefix" placeholder=""
|
||||||
value="{{.GCSConfig.KeyPrefix}}" maxlength="255" aria-describedby="GCSKeyPrefixHelpBlock">
|
value="{{.GCSConfig.KeyPrefix}}" maxlength="255" aria-describedby="GCSKeyPrefixHelpBlock">
|
||||||
<small id="GCSKeyPrefixHelpBlock" class="form-text text-muted">
|
<small id="GCSKeyPrefixHelpBlock" class="form-text text-muted">
|
||||||
Similar to a chroot for local filesystem. Cannot start with "/". Example: "somedir/subdir/".
|
Similar to a chroot for local filesystem. Cannot start with "/". Example: "somedir/subdir/".
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-sm-2"></div>
|
||||||
|
<label for="idGCSACL" class="col-sm-2 col-form-label">ACL</label>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<input type="text" class="form-control" id="idGCSACL" name="gcs_acl" placeholder=""
|
||||||
|
value="{{.GCSConfig.ACL}}" maxlength="255" aria-describedby="GCSACLHelpBlock">
|
||||||
|
<small id="GCSACLHelpBlock" class="form-text text-muted">
|
||||||
|
ACL for uploaded objects. For more info refer to the JSON API <a href="https://cloud.google.com/storage/docs/access-control/lists#predefined-acl" target="_blank">here</a>
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group row fsconfig fsconfig-azblobfs">
|
<div class="form-group row fsconfig fsconfig-azblobfs">
|
||||||
|
|
|
@ -252,6 +252,7 @@ func (f *Filesystem) GetACopy() Filesystem {
|
||||||
Credentials: f.GCSConfig.Credentials.Clone(),
|
Credentials: f.GCSConfig.Credentials.Clone(),
|
||||||
AutomaticCredentials: f.GCSConfig.AutomaticCredentials,
|
AutomaticCredentials: f.GCSConfig.AutomaticCredentials,
|
||||||
StorageClass: f.GCSConfig.StorageClass,
|
StorageClass: f.GCSConfig.StorageClass,
|
||||||
|
ACL: f.GCSConfig.ACL,
|
||||||
KeyPrefix: f.GCSConfig.KeyPrefix,
|
KeyPrefix: f.GCSConfig.KeyPrefix,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -185,6 +185,9 @@ func (fs *GCSFs) Create(name string, flag int) (File, *PipeWriter, func(), error
|
||||||
if fs.config.StorageClass != "" {
|
if fs.config.StorageClass != "" {
|
||||||
objectWriter.ObjectAttrs.StorageClass = fs.config.StorageClass
|
objectWriter.ObjectAttrs.StorageClass = fs.config.StorageClass
|
||||||
}
|
}
|
||||||
|
if fs.config.ACL != "" {
|
||||||
|
objectWriter.PredefinedACL = fs.config.ACL
|
||||||
|
}
|
||||||
go func() {
|
go func() {
|
||||||
defer cancelFn()
|
defer cancelFn()
|
||||||
|
|
||||||
|
@ -195,7 +198,8 @@ func (fs *GCSFs) Create(name string, flag int) (File, *PipeWriter, func(), error
|
||||||
}
|
}
|
||||||
r.CloseWithError(err) //nolint:errcheck
|
r.CloseWithError(err) //nolint:errcheck
|
||||||
p.Done(err)
|
p.Done(err)
|
||||||
fsLog(fs, logger.LevelDebug, "upload completed, path: %#v, readed bytes: %v, err: %v", name, n, err)
|
fsLog(fs, logger.LevelDebug, "upload completed, path: %#v, acl: %#v, readed bytes: %v, err: %v",
|
||||||
|
name, fs.config.ACL, n, err)
|
||||||
metric.GCSTransferCompleted(n, 0, err)
|
metric.GCSTransferCompleted(n, 0, err)
|
||||||
}()
|
}()
|
||||||
return nil, p, cancelFn, nil
|
return nil, p, cancelFn, nil
|
||||||
|
@ -234,6 +238,9 @@ func (fs *GCSFs) Rename(source, target string) error {
|
||||||
if fs.config.StorageClass != "" {
|
if fs.config.StorageClass != "" {
|
||||||
copier.StorageClass = fs.config.StorageClass
|
copier.StorageClass = fs.config.StorageClass
|
||||||
}
|
}
|
||||||
|
if fs.config.ACL != "" {
|
||||||
|
copier.PredefinedACL = fs.config.ACL
|
||||||
|
}
|
||||||
var contentType string
|
var contentType string
|
||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
contentType = dirMimeType
|
contentType = dirMimeType
|
||||||
|
|
|
@ -300,6 +300,9 @@ func (c *GCSFsConfig) isEqual(other *GCSFsConfig) bool {
|
||||||
if c.StorageClass != other.StorageClass {
|
if c.StorageClass != other.StorageClass {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if c.ACL != other.ACL {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if c.Credentials == nil {
|
if c.Credentials == nil {
|
||||||
c.Credentials = kms.NewEmptySecret()
|
c.Credentials = kms.NewEmptySecret()
|
||||||
}
|
}
|
||||||
|
@ -339,6 +342,7 @@ func (c *GCSFsConfig) Validate(credentialsFilePath string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.StorageClass = strings.TrimSpace(c.StorageClass)
|
c.StorageClass = strings.TrimSpace(c.StorageClass)
|
||||||
|
c.ACL = strings.TrimSpace(c.ACL)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue