github.com/cs3org/reva/v2@v2.27.7/pkg/cbox/storage/eoshomewrapper/eoshomewrapper.go (about) 1 // Copyright 2018-2021 CERN 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 package eoshomewrapper 20 21 import ( 22 "bytes" 23 "context" 24 "text/template" 25 26 "github.com/Masterminds/sprig" 27 provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" 28 ctxpkg "github.com/cs3org/reva/v2/pkg/ctx" 29 "github.com/cs3org/reva/v2/pkg/errtypes" 30 "github.com/cs3org/reva/v2/pkg/events" 31 "github.com/cs3org/reva/v2/pkg/storage" 32 "github.com/cs3org/reva/v2/pkg/storage/fs/registry" 33 "github.com/cs3org/reva/v2/pkg/storage/utils/eosfs" 34 "github.com/mitchellh/mapstructure" 35 "github.com/pkg/errors" 36 "github.com/rs/zerolog" 37 ) 38 39 func init() { 40 registry.Register("eoshomewrapper", New) 41 } 42 43 type wrapper struct { 44 storage.FS 45 mountIDTemplate *template.Template 46 } 47 48 func parseConfig(m map[string]interface{}) (*eosfs.Config, string, error) { 49 c := &eosfs.Config{} 50 if err := mapstructure.Decode(m, c); err != nil { 51 err = errors.Wrap(err, "error decoding conf") 52 return nil, "", err 53 } 54 55 // default to version invariance if not configured 56 if _, ok := m["version_invariant"]; !ok { 57 c.VersionInvariant = true 58 } 59 60 t, ok := m["mount_id_template"].(string) 61 if !ok || t == "" { 62 t = "eoshome-{{substr 0 1 .Username}}" 63 } 64 65 return c, t, nil 66 } 67 68 // New returns an implementation of the storage.FS interface that forms a wrapper 69 // around separate connections to EOS. 70 func New(m map[string]interface{}, _ events.Stream, _ *zerolog.Logger) (storage.FS, error) { 71 c, t, err := parseConfig(m) 72 if err != nil { 73 return nil, err 74 } 75 c.EnableHome = true 76 77 eos, err := eosfs.NewEOSFS(c) 78 if err != nil { 79 return nil, err 80 } 81 82 mountIDTemplate, err := template.New("mountID").Funcs(sprig.TxtFuncMap()).Parse(t) 83 if err != nil { 84 return nil, err 85 } 86 87 return &wrapper{FS: eos, mountIDTemplate: mountIDTemplate}, nil 88 } 89 90 // We need to override the two methods, GetMD and ListFolder to fill the 91 // StorageId in the ResourceInfo objects. 92 93 func (w *wrapper) GetMD(ctx context.Context, ref *provider.Reference, mdKeys []string, fieldMask []string) (*provider.ResourceInfo, error) { 94 res, err := w.FS.GetMD(ctx, ref, mdKeys, fieldMask) 95 if err != nil { 96 return nil, err 97 } 98 99 // We need to extract the mount ID based on the mapping template. 100 // 101 // Take the first letter of the username of the logged-in user, as the home 102 // storage provider restricts requests only to the home namespace. 103 res.Id.StorageId = w.getMountID(ctx, res) 104 return res, nil 105 } 106 107 func (w *wrapper) ListFolder(ctx context.Context, ref *provider.Reference, mdKeys, fieldMask []string) ([]*provider.ResourceInfo, error) { 108 res, err := w.FS.ListFolder(ctx, ref, mdKeys, fieldMask) 109 if err != nil { 110 return nil, err 111 } 112 for _, r := range res { 113 r.Id.StorageId = w.getMountID(ctx, r) 114 } 115 return res, nil 116 } 117 118 func (w *wrapper) DenyGrant(ctx context.Context, ref *provider.Reference, g *provider.Grantee) error { 119 return errtypes.NotSupported("eos: deny grant is only enabled for project spaces") 120 } 121 122 func (w *wrapper) getMountID(ctx context.Context, r *provider.ResourceInfo) string { 123 u := ctxpkg.ContextMustGetUser(ctx) 124 b := bytes.Buffer{} 125 if err := w.mountIDTemplate.Execute(&b, u); err != nil { 126 return "" 127 } 128 return b.String() 129 }