Skip to content

Commit

Permalink
Implementation of CS3 Lock API for EOS storage driver (cs3org#2444)
Browse files Browse the repository at this point in the history
  • Loading branch information
gmgigi96 authored and kobergj committed Nov 30, 2022
1 parent 25bbedc commit f4ad966
Show file tree
Hide file tree
Showing 19 changed files with 6,575 additions and 3,087 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ If you see `TestGetManagerWithInvalidUser/Nil_in_user` fail, [try removing](http
To run a single one of them you can do:
```sh
$ go test `go list ./pkg/utils/...`
ok github.com/cs3org/reva/pkg/utils 0.374s
ok github.com/cs3org/reva/v2/pkg/utils 0.374s
```

### Integration tests (GRPC)
Expand Down
4 changes: 4 additions & 0 deletions changelog/unreleased/eos-lock-implementation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Enhancement: Implement the CS3 Lock API in the EOS storage driver

https://github.com/cs3org/cs3apis/pull/160
https://github.com/cs3org/reva/pull/2444
70 changes: 70 additions & 0 deletions cmd/reva/getlock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2018-2021 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

package main

import (
"errors"
"fmt"
"io"

rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/gdexlab/go-render/render"
)

func getlockCommand() *command {
cmd := newCommand("getlock")
cmd.Description = func() string { return "get a lock on a resource" }
cmd.Usage = func() string { return "Usage: getlock <resource_path>" }

cmd.ResetFlags = func() {}

cmd.Action = func(w ...io.Writer) error {
if cmd.NArg() < 1 {
return errors.New("Invalid arguments: " + cmd.Usage())
}

fn := cmd.Args()[0]
client, err := getClient()
if err != nil {
return err
}

ctx := getAuthContext()

ref := &provider.Reference{Path: fn}

res, err := client.GetLock(ctx, &provider.GetLockRequest{
Ref: ref,
})

if err != nil {
return err
}

if res.Status.Code != rpc.Code_CODE_OK {
return formatError(res.Status)
}

fmt.Println(render.Render(res.Lock))

return nil
}
return cmd
}
4 changes: 2 additions & 2 deletions cmd/reva/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"google.golang.org/grpc"
grpcinsecure "google.golang.org/grpc/credentials/insecure"
ins "google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/metadata"
)

Expand All @@ -57,7 +57,7 @@ func getClient() (gateway.GatewayAPIClient, error) {

func getConn() (*grpc.ClientConn, error) {
if insecure {
return grpc.Dial(conf.Host, grpc.WithTransportCredentials(grpcinsecure.NewCredentials()))
return grpc.Dial(conf.Host, grpc.WithTransportCredentials(ins.NewCredentials()))
}

// TODO(labkode): if in the future we want client-side certificate validation,
Expand Down
3 changes: 3 additions & 0 deletions cmd/reva/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ var (
appTokensListCommand(),
appTokensRemoveCommand(),
appTokensCreateCommand(),
setlockCommand(),
getlockCommand(),
unlockCommand(),
helpCommand(),
}
)
Expand Down
171 changes: 171 additions & 0 deletions cmd/reva/setlock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// Copyright 2018-2021 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

package main

import (
"context"
"errors"
"fmt"
"io"
"time"

gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
)

func setlockCommand() *command {
cmd := newCommand("setlock")
cmd.Description = func() string { return "set a lock on a resource" }
cmd.Usage = func() string { return "Usage: setlock [-flags] <resource_path>" }

typeFlag := cmd.String("type", "write", "type of lock")
idFlag := cmd.String("id", "", "id of lock")
userFlag := cmd.String("user", "", "user associated to lock")
appFlag := cmd.String("app", "", "app associated to lock")
expFlag := cmd.String("exp", "", "lock expiration time")
refreshFlag := cmd.Bool("refresh", false, "refresh the lock")

cmd.ResetFlags = func() {
*typeFlag, *idFlag, *userFlag, *appFlag, *expFlag, *refreshFlag = "", "", "", "", "", false
}

cmd.Action = func(w ...io.Writer) error {
if cmd.NArg() < 1 {
return errors.New("Invalid arguments: " + cmd.Usage())
}

fn := cmd.Args()[0]
client, err := getClient()
if err != nil {
return err
}

ctx := getAuthContext()

lock, err := createLock(ctx, client, *typeFlag, *idFlag, *userFlag, *appFlag, *expFlag)
if err != nil {
return err
}

ref := &provider.Reference{Path: fn}

if *refreshFlag {
res, err := client.RefreshLock(ctx, &provider.RefreshLockRequest{
Ref: ref,
Lock: lock,
})
if err != nil {
return err
}

if res.Status.Code != rpc.Code_CODE_OK {
return formatError(res.Status)
}
} else {
res, err := client.SetLock(ctx, &provider.SetLockRequest{
Ref: ref,
Lock: lock,
})
if err != nil {
return err
}

if res.Status.Code != rpc.Code_CODE_OK {
return formatError(res.Status)
}
}

fmt.Println("OK")

return nil
}
return cmd
}

func createLock(ctx context.Context, client gateway.GatewayAPIClient, t, id, u, app, exp string) (*provider.Lock, error) {
lockType, err := getType(t)
if err != nil {
return nil, err
}
var uID *user.UserId
if u != "" {
u, err := getUser(ctx, client, u)
if err != nil {
return nil, err
}
uID = u.GetId()
}
var expiration *types.Timestamp
if exp != "" {
expiration, err = getExpiration(exp)
if err != nil {
return nil, err
}
}

lock := provider.Lock{
LockId: id,
Type: lockType,
User: uID,
AppName: app,
Expiration: expiration,
}

return &lock, nil
}

func getType(t string) (provider.LockType, error) {
switch t {
case "shared":
return provider.LockType_LOCK_TYPE_SHARED, nil
case "write":
return provider.LockType_LOCK_TYPE_WRITE, nil
case "exclusive":
return provider.LockType_LOCK_TYPE_EXCL, nil
default:
return provider.LockType_LOCK_TYPE_INVALID, errors.New("type not recognised")
}
}

func getUser(ctx context.Context, client gateway.GatewayAPIClient, u string) (*user.User, error) {
res, err := client.GetUserByClaim(ctx, &user.GetUserByClaimRequest{
Claim: "username",
Value: u,
})
switch {
case err != nil:
return nil, err
case res.Status.Code != rpc.Code_CODE_OK:
return nil, errors.New(res.Status.Message)
}
return res.User, nil
}

func getExpiration(exp string) (*types.Timestamp, error) {
t, err := time.Parse("2006-01-02", exp)
if err != nil {
return nil, err
}
return &types.Timestamp{
Seconds: uint64(t.Unix()),
}, nil
}
93 changes: 93 additions & 0 deletions cmd/reva/unlock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright 2018-2021 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

package main

import (
"errors"
"fmt"
"io"

rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
)

func unlockCommand() *command {
cmd := newCommand("unlock")
cmd.Description = func() string { return "remove a lock on a resource" }
cmd.Usage = func() string { return "Usage: unlock <resource_path>" }

idFlag := cmd.String("id", "", "lock id")

cmd.ResetFlags = func() {
*idFlag = ""
}

cmd.Action = func(w ...io.Writer) error {
if cmd.NArg() < 1 {
return errors.New("Invalid arguments: " + cmd.Usage())
}

fn := cmd.Args()[0]
client, err := getClient()
if err != nil {
return err
}

ctx := getAuthContext()

ref := &provider.Reference{Path: fn}

// get lock from the id if set
var lock *provider.Lock
if *idFlag == "" {
getLockRes, err := client.GetLock(ctx, &provider.GetLockRequest{
Ref: ref,
})
if err != nil {
return err
}
if getLockRes.Status.Code != rpc.Code_CODE_OK {
return formatError(getLockRes.Status)
}
lock = getLockRes.Lock
} else {
lock = &provider.Lock{
LockId: *idFlag,
}
}

res, err := client.Unlock(ctx, &provider.UnlockRequest{
Ref: ref,
Lock: lock,
})

if err != nil {
return err
}

if res.Status.Code != rpc.Code_CODE_OK {
return formatError(res.Status)
}

fmt.Println("OK")

return nil
}
return cmd
}
Loading

0 comments on commit f4ad966

Please sign in to comment.