github.com/cs3org/reva/v2@v2.27.7/pkg/storage/fs/cephfs/connections.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 //go:build ceph 20 // +build ceph 21 22 package cephfs 23 24 import ( 25 "context" 26 "fmt" 27 "time" 28 29 "github.com/ceph/go-ceph/cephfs/admin" 30 rados2 "github.com/ceph/go-ceph/rados" 31 grouppb "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1" 32 userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" 33 rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" 34 "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" 35 "github.com/pkg/errors" 36 37 cephfs2 "github.com/ceph/go-ceph/cephfs" 38 "github.com/dgraph-io/ristretto" 39 "golang.org/x/sync/semaphore" 40 ) 41 42 type cacheVal struct { 43 perm *cephfs2.UserPerm 44 mount *cephfs2.MountInfo 45 } 46 47 //TODO: Add to cephfs obj 48 49 type connections struct { 50 cache *ristretto.Cache 51 lock *semaphore.Weighted 52 ctx context.Context 53 userCache *ristretto.Cache 54 groupCache *ristretto.Cache 55 } 56 57 // TODO: make configurable/add to options 58 var usrLimit int64 = 1e4 59 60 func newCache() (c *connections, err error) { 61 cache, err := ristretto.NewCache(&ristretto.Config{ 62 NumCounters: 1e7, 63 MaxCost: usrLimit, 64 BufferItems: 64, 65 OnEvict: func(item *ristretto.Item) { 66 v := item.Value.(cacheVal) 67 v.perm.Destroy() 68 _ = v.mount.Unmount() 69 _ = v.mount.Release() 70 }, 71 }) 72 if err != nil { 73 return 74 } 75 76 ucache, err := ristretto.NewCache(&ristretto.Config{ 77 NumCounters: 1e7, 78 MaxCost: 10 * usrLimit, 79 BufferItems: 64, 80 }) 81 if err != nil { 82 return 83 } 84 85 gcache, err := ristretto.NewCache(&ristretto.Config{ 86 NumCounters: 1e7, 87 MaxCost: 10 * usrLimit, 88 BufferItems: 64, 89 }) 90 if err != nil { 91 return 92 } 93 94 c = &connections{ 95 cache: cache, 96 lock: semaphore.NewWeighted(usrLimit), 97 ctx: context.Background(), 98 userCache: ucache, 99 groupCache: gcache, 100 } 101 102 return 103 } 104 105 func (c *connections) clearCache() { 106 c.cache.Clear() 107 c.cache.Close() 108 } 109 110 type adminConn struct { 111 indexPoolName string 112 subvolAdmin *admin.FSAdmin 113 adminMount Mount 114 radosConn *rados2.Conn 115 radosIO *rados2.IOContext 116 } 117 118 func newAdminConn(poolName string) *adminConn { 119 rados, err := rados2.NewConn() 120 if err != nil { 121 return nil 122 } 123 if err = rados.ReadDefaultConfigFile(); err != nil { 124 return nil 125 } 126 127 if err = rados.Connect(); err != nil { 128 return nil 129 } 130 131 pools, err := rados.ListPools() 132 if err != nil { 133 rados.Shutdown() 134 return nil 135 } 136 137 var radosIO *rados2.IOContext 138 if in(poolName, pools) { 139 radosIO, err = rados.OpenIOContext(poolName) 140 if err != nil { 141 rados.Shutdown() 142 return nil 143 } 144 } else { 145 err = rados.MakePool(poolName) 146 if err != nil { 147 rados.Shutdown() 148 return nil 149 } 150 radosIO, err = rados.OpenIOContext(poolName) 151 if err != nil { 152 rados.Shutdown() 153 return nil 154 } 155 } 156 157 mount, err := cephfs2.CreateFromRados(rados) 158 if err != nil { 159 rados.Shutdown() 160 return nil 161 } 162 163 if err = mount.Mount(); err != nil { 164 rados.Shutdown() 165 destroyCephConn(mount, nil) 166 return nil 167 } 168 169 return &adminConn{ 170 poolName, 171 admin.NewFromConn(rados), 172 mount, 173 rados, 174 radosIO, 175 } 176 } 177 178 func newConn(user *User) *cacheVal { 179 var perm *cephfs2.UserPerm 180 mount, err := cephfs2.CreateMount() 181 if err != nil { 182 return destroyCephConn(mount, perm) 183 } 184 if err = mount.ReadDefaultConfigFile(); err != nil { 185 return destroyCephConn(mount, perm) 186 } 187 if err = mount.Init(); err != nil { 188 return destroyCephConn(mount, perm) 189 } 190 191 if user != nil { //nil creates admin conn 192 perm = cephfs2.NewUserPerm(int(user.UidNumber), int(user.GidNumber), []int{}) 193 if err = mount.SetMountPerms(perm); err != nil { 194 return destroyCephConn(mount, perm) 195 } 196 } 197 198 if err = mount.MountWithRoot("/"); err != nil { 199 return destroyCephConn(mount, perm) 200 } 201 202 if user != nil { 203 if err = mount.ChangeDir(user.fs.conf.Root); err != nil { 204 return destroyCephConn(mount, perm) 205 } 206 } 207 208 return &cacheVal{ 209 perm: perm, 210 mount: mount, 211 } 212 } 213 214 func (fs *cephfs) getUserByID(ctx context.Context, uid string) (*userpb.User, error) { 215 if entity, found := fs.conn.userCache.Get(uid); found { 216 return entity.(*userpb.User), nil 217 } 218 219 client, err := pool.GetGatewayServiceClient(fs.conf.GatewaySvc) 220 if err != nil { 221 return nil, errors.Wrap(err, "cephfs: error getting gateway grpc client") 222 } 223 getUserResp, err := client.GetUserByClaim(ctx, &userpb.GetUserByClaimRequest{ 224 Claim: "uid", 225 Value: uid, 226 }) 227 228 if err != nil { 229 return nil, errors.Wrap(err, "cephfs: error getting user") 230 } 231 if getUserResp.Status.Code != rpc.Code_CODE_OK { 232 return nil, errors.Wrap(err, "cephfs: grpc get user failed") 233 } 234 fs.conn.userCache.SetWithTTL(uid, getUserResp.User, 1, 24*time.Hour) 235 fs.conn.userCache.SetWithTTL(getUserResp.User.Id.OpaqueId, getUserResp.User, 1, 24*time.Hour) 236 237 return getUserResp.User, nil 238 } 239 240 func (fs *cephfs) getUserByOpaqueID(ctx context.Context, oid string) (*userpb.User, error) { 241 if entity, found := fs.conn.userCache.Get(oid); found { 242 return entity.(*userpb.User), nil 243 } 244 client, err := pool.GetGatewayServiceClient(fs.conf.GatewaySvc) 245 if err != nil { 246 return nil, errors.Wrap(err, "cephfs: error getting gateway grpc client") 247 } 248 getUserResp, err := client.GetUser(ctx, &userpb.GetUserRequest{ 249 UserId: &userpb.UserId{ 250 OpaqueId: oid, 251 }, 252 }) 253 254 if err != nil { 255 return nil, errors.Wrap(err, "cephfs: error getting user") 256 } 257 if getUserResp.Status.Code != rpc.Code_CODE_OK { 258 return nil, errors.Wrap(err, "cephfs: grpc get user failed") 259 } 260 fs.conn.userCache.SetWithTTL(fmt.Sprint(getUserResp.User.UidNumber), getUserResp.User, 1, 24*time.Hour) 261 fs.conn.userCache.SetWithTTL(oid, getUserResp.User, 1, 24*time.Hour) 262 263 return getUserResp.User, nil 264 } 265 266 func (fs *cephfs) getGroupByID(ctx context.Context, gid string) (*grouppb.Group, error) { 267 if entity, found := fs.conn.groupCache.Get(gid); found { 268 return entity.(*grouppb.Group), nil 269 } 270 271 client, err := pool.GetGatewayServiceClient(fs.conf.GatewaySvc) 272 if err != nil { 273 return nil, errors.Wrap(err, "cephfs: error getting gateway grpc client") 274 } 275 getGroupResp, err := client.GetGroupByClaim(ctx, &grouppb.GetGroupByClaimRequest{ 276 Claim: "gid", 277 Value: gid, 278 }) 279 if err != nil { 280 return nil, errors.Wrap(err, "cephfs: error getting group") 281 } 282 if getGroupResp.Status.Code != rpc.Code_CODE_OK { 283 return nil, errors.Wrap(err, "cephfs: grpc get group failed") 284 } 285 fs.conn.groupCache.SetWithTTL(gid, getGroupResp.Group, 1, 24*time.Hour) 286 fs.conn.groupCache.SetWithTTL(getGroupResp.Group.Id.OpaqueId, getGroupResp.Group, 1, 24*time.Hour) 287 288 return getGroupResp.Group, nil 289 } 290 291 func (fs *cephfs) getGroupByOpaqueID(ctx context.Context, oid string) (*grouppb.Group, error) { 292 if entity, found := fs.conn.groupCache.Get(oid); found { 293 return entity.(*grouppb.Group), nil 294 } 295 client, err := pool.GetGatewayServiceClient(fs.conf.GatewaySvc) 296 if err != nil { 297 return nil, errors.Wrap(err, "cephfs: error getting gateway grpc client") 298 } 299 getGroupResp, err := client.GetGroup(ctx, &grouppb.GetGroupRequest{ 300 GroupId: &grouppb.GroupId{ 301 OpaqueId: oid, 302 }, 303 }) 304 305 if err != nil { 306 return nil, errors.Wrap(err, "cephfs: error getting group") 307 } 308 if getGroupResp.Status.Code != rpc.Code_CODE_OK { 309 return nil, errors.Wrap(err, "cephfs: grpc get group failed") 310 } 311 fs.conn.userCache.SetWithTTL(fmt.Sprint(getGroupResp.Group.GidNumber), getGroupResp.Group, 1, 24*time.Hour) 312 fs.conn.userCache.SetWithTTL(oid, getGroupResp.Group, 1, 24*time.Hour) 313 314 return getGroupResp.Group, nil 315 }