From 3786bca00dd1fd9ebaf83ef82295eaadac89e517 Mon Sep 17 00:00:00 2001 From: JinnyYi <82445294+JinnyYi@users.noreply.github.com> Date: Tue, 1 Jun 2021 10:28:44 +0800 Subject: [PATCH] Implement GSP-87 Feature Gates (#31) --- generated.go | 373 ++++++++++++++++++++++++++++++++++++--------------- go.mod | 2 +- go.sum | 6 +- service.toml | 12 +- utils.go | 10 +- 5 files changed, 284 insertions(+), 119 deletions(-) diff --git a/generated.go b/generated.go index ae6172c..c393620 100644 --- a/generated.go +++ b/generated.go @@ -35,8 +35,12 @@ const ( pairKmsKeyName = "gcs_kms_key_name" // ProjectID pairProjectID = "gcs_project_id" + // ServiceFeatures set service features + pairServiceFeatures = "gcs_service_features" // StorageClass pairStorageClass = "gcs_storage_class" + // StorageFeatures set storage features + pairStorageFeatures = "gcs_storage_features" ) // ObjectMetadata stores service metadata for object. @@ -118,6 +122,16 @@ func WithProjectID(v string) Pair { } } +// WithServiceFeatures will apply service_features value to Options. +// +// ServiceFeatures set service features +func WithServiceFeatures(v ServiceFeatures) Pair { + return Pair{ + Key: pairServiceFeatures, + Value: v, + } +} + // WithStorageClass will apply storage_class value to Options. // // StorageClass @@ -128,10 +142,32 @@ func WithStorageClass(v string) Pair { } } +// WithStorageFeatures will apply storage_features value to Options. +// +// StorageFeatures set storage features +func WithStorageFeatures(v StorageFeatures) Pair { + return Pair{ + Key: pairStorageFeatures, + Value: v, + } +} + var ( _ Servicer = &Service{} ) +type ServiceFeatures struct { + LooseOperationAll bool + LooseOperationCreate bool + LooseOperationDelete bool + LooseOperationGet bool + LooseOperationList bool + + VirtualOperationAll bool + + VirtualPairAll bool +} + // pairServiceNew is the parsed struct type pairServiceNew struct { pairs []Pair @@ -146,7 +182,8 @@ type pairServiceNew struct { DefaultServicePairs DefaultServicePairs HasHTTPClientOptions bool HTTPClientOptions *httpclient.Options - // Generated pairs + HasServiceFeatures bool + ServiceFeatures ServiceFeatures } // parsePairServiceNew will parse Pair slice into *pairServiceNew @@ -183,7 +220,12 @@ func parsePairServiceNew(opts []Pair) (pairServiceNew, error) { } result.HasHTTPClientOptions = true result.HTTPClientOptions = v.Value.(*httpclient.Options) - // Generated pairs + case pairServiceFeatures: + if result.HasServiceFeatures { + continue + } + result.HasServiceFeatures = true + result.ServiceFeatures = v.Value.(ServiceFeatures) } } if !result.HasCredential { @@ -207,10 +249,6 @@ type DefaultServicePairs struct { // pairServiceCreate is the parsed struct type pairServiceCreate struct { pairs []Pair - - // Required pairs - // Optional pairs - // Generated pairs } // parsePairServiceCreate will parse Pair slice into *pairServiceCreate @@ -220,27 +258,33 @@ func (s *Service) parsePairServiceCreate(opts []Pair) (pairServiceCreate, error) } for _, v := range opts { + // isUnsupportedPair records whether current pair is unsupported. + isUnsupportedPair := false + switch v.Key { - // Required pairs - // Optional pairs - // Generated pairs default: + isUnsupportedPair = true + } + if !isUnsupportedPair { continue + } + // If user enables the loose operation feature, we will ignore PairUnsupportedError. + if s.features.LooseOperationAll || s.features.LooseOperationCreate { + continue } + return pairServiceCreate{}, services.PairUnsupportedError{Pair: v} } + // Check required pairs. + return result, nil } // pairServiceDelete is the parsed struct type pairServiceDelete struct { pairs []Pair - - // Required pairs - // Optional pairs - // Generated pairs } // parsePairServiceDelete will parse Pair slice into *pairServiceDelete @@ -250,27 +294,33 @@ func (s *Service) parsePairServiceDelete(opts []Pair) (pairServiceDelete, error) } for _, v := range opts { + // isUnsupportedPair records whether current pair is unsupported. + isUnsupportedPair := false + switch v.Key { - // Required pairs - // Optional pairs - // Generated pairs default: + isUnsupportedPair = true + } + if !isUnsupportedPair { continue + } + // If user enables the loose operation feature, we will ignore PairUnsupportedError. + if s.features.LooseOperationAll || s.features.LooseOperationDelete { + continue } + return pairServiceDelete{}, services.PairUnsupportedError{Pair: v} } + // Check required pairs. + return result, nil } // pairServiceGet is the parsed struct type pairServiceGet struct { pairs []Pair - - // Required pairs - // Optional pairs - // Generated pairs } // parsePairServiceGet will parse Pair slice into *pairServiceGet @@ -280,27 +330,33 @@ func (s *Service) parsePairServiceGet(opts []Pair) (pairServiceGet, error) { } for _, v := range opts { + // isUnsupportedPair records whether current pair is unsupported. + isUnsupportedPair := false + switch v.Key { - // Required pairs - // Optional pairs - // Generated pairs default: + isUnsupportedPair = true + } + if !isUnsupportedPair { continue + } + // If user enables the loose operation feature, we will ignore PairUnsupportedError. + if s.features.LooseOperationAll || s.features.LooseOperationGet { + continue } + return pairServiceGet{}, services.PairUnsupportedError{Pair: v} } + // Check required pairs. + return result, nil } // pairServiceList is the parsed struct type pairServiceList struct { pairs []Pair - - // Required pairs - // Optional pairs - // Generated pairs } // parsePairServiceList will parse Pair slice into *pairServiceList @@ -310,17 +366,27 @@ func (s *Service) parsePairServiceList(opts []Pair) (pairServiceList, error) { } for _, v := range opts { + // isUnsupportedPair records whether current pair is unsupported. + isUnsupportedPair := false + switch v.Key { - // Required pairs - // Optional pairs - // Generated pairs default: + isUnsupportedPair = true + } + if !isUnsupportedPair { continue + } + // If user enables the loose operation feature, we will ignore PairUnsupportedError. + if s.features.LooseOperationAll || s.features.LooseOperationList { + continue } + return pairServiceList{}, services.PairUnsupportedError{Pair: v} } + // Check required pairs. + return result, nil } @@ -429,6 +495,21 @@ var ( _ Storager = &Storage{} ) +type StorageFeatures struct { + LooseOperationAll bool + LooseOperationCreate bool + LooseOperationDelete bool + LooseOperationList bool + LooseOperationMetadata bool + LooseOperationRead bool + LooseOperationStat bool + LooseOperationWrite bool + + VirtualOperationAll bool + + VirtualPairAll bool +} + // pairStorageNew is the parsed struct type pairStorageNew struct { pairs []Pair @@ -439,11 +520,10 @@ type pairStorageNew struct { // Optional pairs HasDefaultStoragePairs bool DefaultStoragePairs DefaultStoragePairs - HasPairPolicy bool - PairPolicy PairPolicy + HasStorageFeatures bool + StorageFeatures StorageFeatures HasWorkDir bool WorkDir string - // Generated pairs } // parsePairStorageNew will parse Pair slice into *pairStorageNew @@ -468,19 +548,18 @@ func parsePairStorageNew(opts []Pair) (pairStorageNew, error) { } result.HasDefaultStoragePairs = true result.DefaultStoragePairs = v.Value.(DefaultStoragePairs) - case "pair_policy": - if result.HasPairPolicy { + case pairStorageFeatures: + if result.HasStorageFeatures { continue } - result.HasPairPolicy = true - result.PairPolicy = v.Value.(PairPolicy) + result.HasStorageFeatures = true + result.StorageFeatures = v.Value.(StorageFeatures) case "work_dir": if result.HasWorkDir { continue } result.HasWorkDir = true result.WorkDir = v.Value.(string) - // Generated pairs } } if !result.HasName { @@ -504,10 +583,6 @@ type DefaultStoragePairs struct { // pairStorageCreate is the parsed struct type pairStorageCreate struct { pairs []Pair - - // Required pairs - // Optional pairs - // Generated pairs } // parsePairStorageCreate will parse Pair slice into *pairStorageCreate @@ -517,29 +592,33 @@ func (s *Storage) parsePairStorageCreate(opts []Pair) (pairStorageCreate, error) } for _, v := range opts { + // isUnsupportedPair records whether current pair is unsupported. + isUnsupportedPair := false + switch v.Key { - // Required pairs - // Optional pairs - // Generated pairs default: + isUnsupportedPair = true + } - if s.pairPolicy.All || s.pairPolicy.Create { - return pairStorageCreate{}, services.PairUnsupportedError{Pair: v} - } + if !isUnsupportedPair { + continue + } + // If user enables the loose operation feature, we will ignore PairUnsupportedError. + if s.features.LooseOperationAll || s.features.LooseOperationCreate { + continue } + return pairStorageCreate{}, services.PairUnsupportedError{Pair: v} } + // Check required pairs. + return result, nil } // pairStorageDelete is the parsed struct type pairStorageDelete struct { pairs []Pair - - // Required pairs - // Optional pairs - // Generated pairs } // parsePairStorageDelete will parse Pair slice into *pairStorageDelete @@ -549,31 +628,35 @@ func (s *Storage) parsePairStorageDelete(opts []Pair) (pairStorageDelete, error) } for _, v := range opts { + // isUnsupportedPair records whether current pair is unsupported. + isUnsupportedPair := false + switch v.Key { - // Required pairs - // Optional pairs - // Generated pairs default: + isUnsupportedPair = true + } - if s.pairPolicy.All || s.pairPolicy.Delete { - return pairStorageDelete{}, services.PairUnsupportedError{Pair: v} - } + if !isUnsupportedPair { + continue + } + // If user enables the loose operation feature, we will ignore PairUnsupportedError. + if s.features.LooseOperationAll || s.features.LooseOperationDelete { + continue } + return pairStorageDelete{}, services.PairUnsupportedError{Pair: v} } + // Check required pairs. + return result, nil } // pairStorageList is the parsed struct type pairStorageList struct { - pairs []Pair - - // Required pairs - // Optional pairs + pairs []Pair HasListMode bool ListMode ListMode - // Generated pairs } // parsePairStorageList will parse Pair slice into *pairStorageList @@ -583,32 +666,40 @@ func (s *Storage) parsePairStorageList(opts []Pair) (pairStorageList, error) { } for _, v := range opts { + // isUnsupportedPair records whether current pair is unsupported. + isUnsupportedPair := false + switch v.Key { - // Required pairs - // Optional pairs case "list_mode": + if result.HasListMode { + continue + } result.HasListMode = true result.ListMode = v.Value.(ListMode) - // Generated pairs + continue default: + isUnsupportedPair = true + } - if s.pairPolicy.All || s.pairPolicy.List { - return pairStorageList{}, services.PairUnsupportedError{Pair: v} - } + if !isUnsupportedPair { + continue + } + // If user enables the loose operation feature, we will ignore PairUnsupportedError. + if s.features.LooseOperationAll || s.features.LooseOperationList { + continue } + return pairStorageList{}, services.PairUnsupportedError{Pair: v} } + // Check required pairs. + return result, nil } // pairStorageMetadata is the parsed struct type pairStorageMetadata struct { pairs []Pair - - // Required pairs - // Optional pairs - // Generated pairs } // parsePairStorageMetadata will parse Pair slice into *pairStorageMetadata @@ -618,28 +709,33 @@ func (s *Storage) parsePairStorageMetadata(opts []Pair) (pairStorageMetadata, er } for _, v := range opts { + // isUnsupportedPair records whether current pair is unsupported. + isUnsupportedPair := false + switch v.Key { - // Required pairs - // Optional pairs - // Generated pairs default: + isUnsupportedPair = true + } - if s.pairPolicy.All || s.pairPolicy.Metadata { - return pairStorageMetadata{}, services.PairUnsupportedError{Pair: v} - } + if !isUnsupportedPair { + continue + } + // If user enables the loose operation feature, we will ignore PairUnsupportedError. + if s.features.LooseOperationAll || s.features.LooseOperationMetadata { + continue } + return pairStorageMetadata{}, services.PairUnsupportedError{Pair: v} } + // Check required pairs. + return result, nil } // pairStorageRead is the parsed struct type pairStorageRead struct { - pairs []Pair - - // Required pairs - // Optional pairs + pairs []Pair HasEncryptionKey bool EncryptionKey []byte HasIoCallback bool @@ -648,7 +744,6 @@ type pairStorageRead struct { Offset int64 HasSize bool Size int64 - // Generated pairs } // parsePairStorageRead will parse Pair slice into *pairStorageRead @@ -658,41 +753,61 @@ func (s *Storage) parsePairStorageRead(opts []Pair) (pairStorageRead, error) { } for _, v := range opts { + // isUnsupportedPair records whether current pair is unsupported. + isUnsupportedPair := false + switch v.Key { - // Required pairs - // Optional pairs case pairEncryptionKey: + if result.HasEncryptionKey { + continue + } result.HasEncryptionKey = true result.EncryptionKey = v.Value.([]byte) + continue case "io_callback": + if result.HasIoCallback { + continue + } result.HasIoCallback = true result.IoCallback = v.Value.(func([]byte)) + continue case "offset": + if result.HasOffset { + continue + } result.HasOffset = true result.Offset = v.Value.(int64) + continue case "size": + if result.HasSize { + continue + } result.HasSize = true result.Size = v.Value.(int64) - // Generated pairs + continue default: + isUnsupportedPair = true + } - if s.pairPolicy.All || s.pairPolicy.Read { - return pairStorageRead{}, services.PairUnsupportedError{Pair: v} - } + if !isUnsupportedPair { + continue + } + // If user enables the loose operation feature, we will ignore PairUnsupportedError. + if s.features.LooseOperationAll || s.features.LooseOperationRead { + continue } + return pairStorageRead{}, services.PairUnsupportedError{Pair: v} } + // Check required pairs. + return result, nil } // pairStorageStat is the parsed struct type pairStorageStat struct { pairs []Pair - - // Required pairs - // Optional pairs - // Generated pairs } // parsePairStorageStat will parse Pair slice into *pairStorageStat @@ -702,28 +817,33 @@ func (s *Storage) parsePairStorageStat(opts []Pair) (pairStorageStat, error) { } for _, v := range opts { + // isUnsupportedPair records whether current pair is unsupported. + isUnsupportedPair := false + switch v.Key { - // Required pairs - // Optional pairs - // Generated pairs default: + isUnsupportedPair = true + } - if s.pairPolicy.All || s.pairPolicy.Stat { - return pairStorageStat{}, services.PairUnsupportedError{Pair: v} - } + if !isUnsupportedPair { + continue + } + // If user enables the loose operation feature, we will ignore PairUnsupportedError. + if s.features.LooseOperationAll || s.features.LooseOperationStat { + continue } + return pairStorageStat{}, services.PairUnsupportedError{Pair: v} } + // Check required pairs. + return result, nil } // pairStorageWrite is the parsed struct type pairStorageWrite struct { - pairs []Pair - - // Required pairs - // Optional pairs + pairs []Pair HasContentMd5 bool ContentMd5 string HasContentType bool @@ -736,7 +856,6 @@ type pairStorageWrite struct { KmsKeyName string HasStorageClass bool StorageClass string - // Generated pairs } // parsePairStorageWrite will parse Pair slice into *pairStorageWrite @@ -746,37 +865,69 @@ func (s *Storage) parsePairStorageWrite(opts []Pair) (pairStorageWrite, error) { } for _, v := range opts { + // isUnsupportedPair records whether current pair is unsupported. + isUnsupportedPair := false + switch v.Key { - // Required pairs - // Optional pairs case "content_md5": + if result.HasContentMd5 { + continue + } result.HasContentMd5 = true result.ContentMd5 = v.Value.(string) + continue case "content_type": + if result.HasContentType { + continue + } result.HasContentType = true result.ContentType = v.Value.(string) + continue case pairEncryptionKey: + if result.HasEncryptionKey { + continue + } result.HasEncryptionKey = true result.EncryptionKey = v.Value.([]byte) + continue case "io_callback": + if result.HasIoCallback { + continue + } result.HasIoCallback = true result.IoCallback = v.Value.(func([]byte)) + continue case pairKmsKeyName: + if result.HasKmsKeyName { + continue + } result.HasKmsKeyName = true result.KmsKeyName = v.Value.(string) + continue case pairStorageClass: + if result.HasStorageClass { + continue + } result.HasStorageClass = true result.StorageClass = v.Value.(string) - // Generated pairs + continue default: + isUnsupportedPair = true + } - if s.pairPolicy.All || s.pairPolicy.Write { - return pairStorageWrite{}, services.PairUnsupportedError{Pair: v} - } + if !isUnsupportedPair { + continue + } + // If user enables the loose operation feature, we will ignore PairUnsupportedError. + if s.features.LooseOperationAll || s.features.LooseOperationWrite { + continue } + return pairStorageWrite{}, services.PairUnsupportedError{Pair: v} } + // Check required pairs. + return result, nil } diff --git a/go.mod b/go.mod index 847c346..52039c9 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.15 require ( cloud.google.com/go/storage v1.15.0 github.com/beyondstorage/go-integration-test/v4 v4.0.0 - github.com/beyondstorage/go-storage/v4 v4.0.0 + github.com/beyondstorage/go-storage/v4 v4.0.1-0.20210530044854-1c928ddbe52d github.com/google/uuid v1.2.0 golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c google.golang.org/api v0.47.0 diff --git a/go.sum b/go.sum index d370e58..bbee822 100644 --- a/go.sum +++ b/go.sum @@ -45,10 +45,12 @@ github.com/Xuanwo/templateutils v0.1.0 h1:WpkWOqQtIQ2vAIpJLa727DdN8WtxhUkkbDGa6U github.com/Xuanwo/templateutils v0.1.0/go.mod h1:OdE0DJ+CJxDBq6psX5DPV+gOZi8bhuHuVUpPCG++Wb8= github.com/beyondstorage/go-integration-test/v4 v4.0.0 h1:tdXQV9yxQ3Q6p9xfyQKzK3MEo9r9j9g3uT5+3sbVtnQ= github.com/beyondstorage/go-integration-test/v4 v4.0.0/go.mod h1:26/JF4b0XxRN0pL4kihpnVNhbbw+QWvmmvgxfnFJDfA= -github.com/beyondstorage/go-storage/v4 v4.0.0 h1:yg3/XFEIuf207Y/kb/Gh1E46imphE2EtsKk+x7wrxIM= github.com/beyondstorage/go-storage/v4 v4.0.0/go.mod h1:oa2dYco+xplPj99WSBnYVw/xXvRkIKWSSVDQKNZ5Kz8= -github.com/beyondstorage/specs/go v0.0.0-20210521044836-3d41c1d9c97f h1:KMXKB/LACUmnOfLfjND8222qtzWT9lWRUdsPOlM4FqE= +github.com/beyondstorage/go-storage/v4 v4.0.1-0.20210530044854-1c928ddbe52d h1:s9t6VNNRDqmg+PXyXtVEsxIM7xZQIJOYlma28IpkbNQ= +github.com/beyondstorage/go-storage/v4 v4.0.1-0.20210530044854-1c928ddbe52d/go.mod h1:kXMu07IDZaKtxbqI1ufuhqo0FjYe0nH7zPCbBanln/Y= github.com/beyondstorage/specs/go v0.0.0-20210521044836-3d41c1d9c97f/go.mod h1:f5VvmLHc/dNJwl+/yAv/TOHdev3phvuEswx8DIXiSQQ= +github.com/beyondstorage/specs/go v0.0.0-20210530044123-3ff75e192bc9 h1:YSiF27cAHlDZk9q+oaEHQbA8dH8XTvYxeTOoPzNCwOQ= +github.com/beyondstorage/specs/go v0.0.0-20210530044123-3ff75e192bc9/go.mod h1:f5VvmLHc/dNJwl+/yAv/TOHdev3phvuEswx8DIXiSQQ= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= diff --git a/service.toml b/service.toml index 60f4207..91f6bf1 100644 --- a/service.toml +++ b/service.toml @@ -2,11 +2,11 @@ name = "gcs" [namespace.service.new] required = ["credential", "project_id"] -optional = ["default_service_pairs", "http_client_options"] +optional = ["service_features", "default_service_pairs", "http_client_options"] [namespace.storage.new] required = ["name"] -optional = ["default_storage_pairs", "pair_policy", "work_dir"] +optional = ["storage_features", "default_storage_pairs", "work_dir"] [namespace.storage.op.list] optional = ["list_mode"] @@ -17,6 +17,14 @@ optional = ["offset", "io_callback", "size", "encryption_key"] [namespace.storage.op.write] optional = ["content_md5", "content_type", "io_callback", "storage_class", "encryption_key", "kms_key_name"] +[pairs.service_features] +type = "ServiceFeatures" +description = "set service features" + +[pairs.storage_features] +type = "StorageFeatures" +description = "set storage features" + [pairs.encryption_key] type = "byte_array" description = "is the customer's 32-byte AES-256 key" diff --git a/utils.go b/utils.go index 700e3f1..bc9275a 100644 --- a/utils.go +++ b/utils.go @@ -29,6 +29,7 @@ type Service struct { projectID string defaultPairs DefaultServicePairs + features ServiceFeatures typ.UnimplementedServicer } @@ -46,7 +47,7 @@ type Storage struct { workDir string defaultPairs DefaultStoragePairs - pairPolicy typ.PairPolicy + features StorageFeatures typ.UnimplementedStorager } @@ -135,6 +136,9 @@ func newServicer(pairs ...typ.Pair) (srv *Service, err error) { if opt.HasDefaultServicePairs { srv.defaultPairs = opt.DefaultServicePairs } + if opt.HasServiceFeatures { + srv.features = opt.ServiceFeatures + } return } @@ -206,8 +210,8 @@ func (s *Service) newStorage(pairs ...typ.Pair) (st *Storage, err error) { if opt.HasDefaultStoragePairs { store.defaultPairs = opt.DefaultStoragePairs } - if opt.HasPairPolicy { - store.pairPolicy = opt.PairPolicy + if opt.HasStorageFeatures { + store.features = opt.StorageFeatures } if opt.HasWorkDir { store.workDir = opt.WorkDir