diff --git a/changelog/unreleased/improve-ocmd-error-logs.md b/changelog/unreleased/improve-ocmd-error-logs.md new file mode 100644 index 0000000000..a08284db04 --- /dev/null +++ b/changelog/unreleased/improve-ocmd-error-logs.md @@ -0,0 +1,6 @@ +Enhancement: Improve error logging in ocmd flow + +https://github.com/cs3org/reva/pull/3526 +https://github.com/cs3org/reva/pull/3419 +https://github.com/cs3org/reva/issues/3365 +https://github.com/cs3org/reva/pull/3369 diff --git a/internal/grpc/services/ocminvitemanager/ocminvitemanager.go b/internal/grpc/services/ocminvitemanager/ocminvitemanager.go index 696220e65d..cb12c6b6c2 100644 --- a/internal/grpc/services/ocminvitemanager/ocminvitemanager.go +++ b/internal/grpc/services/ocminvitemanager/ocminvitemanager.go @@ -118,7 +118,7 @@ func (s *service) ForwardInvite(ctx context.Context, req *invitepb.ForwardInvite err := s.im.ForwardInvite(ctx, req.InviteToken, req.OriginSystemProvider) if err != nil { return &invitepb.ForwardInviteResponse{ - Status: status.NewInternal(ctx, err, "error forwarding invite"), + Status: status.NewInternal(ctx, err, "error forwarding invite:"+err.Error()), }, nil } @@ -158,7 +158,7 @@ func (s *service) FindAcceptedUsers(ctx context.Context, req *invitepb.FindAccep acceptedUsers, err := s.im.FindAcceptedUsers(ctx, req.Filter) if err != nil { return &invitepb.FindAcceptedUsersResponse{ - Status: status.NewInternal(ctx, err, "error finding remote users"), + Status: status.NewInternal(ctx, err, "error finding remote users: "+err.Error()), }, nil } diff --git a/internal/grpc/services/ocmshareprovider/ocmshareprovider.go b/internal/grpc/services/ocmshareprovider/ocmshareprovider.go index 11d6ac4257..3aa85858c6 100644 --- a/internal/grpc/services/ocmshareprovider/ocmshareprovider.go +++ b/internal/grpc/services/ocmshareprovider/ocmshareprovider.go @@ -177,7 +177,7 @@ func (s *service) CreateOCMShare(ctx context.Context, req *ocm.CreateOCMShareReq if err != nil { return &ocm.CreateOCMShareResponse{ - Status: status.NewInternal(ctx, err, "error creating share"), + Status: status.NewInternal(ctx, err, "error creating share: "+err.Error()), }, nil } diff --git a/internal/http/services/ocmd/invites.go b/internal/http/services/ocmd/invites.go index b94b768845..2f101d87dc 100644 --- a/internal/http/services/ocmd/invites.go +++ b/internal/http/services/ocmd/invites.go @@ -190,7 +190,7 @@ func (h *invitesHandler) forwardInvite(w http.ResponseWriter, r *http.Request) { return } - _, err = w.Write([]byte("Accepted invite from: " + html.EscapeString(providerDomain))) + _, err = w.Write([]byte("{\"message\": \"Success\", \"providerDomain\":\"" + html.EscapeString(providerDomain) + "\"}")) if err != nil { WriteError(w, r, APIErrorServerError, "error writing token data", err) return @@ -313,6 +313,7 @@ func (h *invitesHandler) findAcceptedUsers(w http.ResponseWriter, r *http.Reques indentedResponse, _ := json.MarshalIndent(response, "", " ") w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) + log.Debug().Msg("findAcceptedUsers json response: " + string(indentedResponse)) if _, err := w.Write(indentedResponse); err != nil { log.Err(err).Msg("Error writing to ResponseWriter") } diff --git a/internal/http/services/ocmd/ocmd.go b/internal/http/services/ocmd/ocmd.go index 3b0eae7fd9..f6669b8726 100644 --- a/internal/http/services/ocmd/ocmd.go +++ b/internal/http/services/ocmd/ocmd.go @@ -125,9 +125,10 @@ func (s *svc) Handler() http.Handler { return case "send": s.SendHandler.Handler().ServeHTTP(w, r) + return } - log.Warn().Msg("request not handled") + log.Warn().Msgf("request not handled. Try e.g. 'ocm-provider', 'shares', 'notifications', 'invites', or 'send' instead of '%s'", head) w.WriteHeader(http.StatusNotFound) }) } diff --git a/internal/http/services/ocmd/send.go b/internal/http/services/ocmd/send.go index dc632185aa..b1615f6c66 100644 --- a/internal/http/services/ocmd/send.go +++ b/internal/http/services/ocmd/send.go @@ -36,6 +36,7 @@ import ( "github.com/cs3org/reva/pkg/appctx" ctxpkg "github.com/cs3org/reva/pkg/ctx" "github.com/cs3org/reva/pkg/rgrpc/todo/pool" + "github.com/cs3org/reva/pkg/utils" "google.golang.org/grpc/metadata" ) @@ -109,13 +110,13 @@ func (h *sendHandler) Handler() http.Handler { req := &provider.StatRequest{Ref: ref} res2, err := gatewayClient.Stat(authCtx, req) if err != nil { - log.Error().Msg("error sending: stat file/folder to share") + log.Error().Msg("gatewayClient.Stat operation failed; is the storage backend reachable?") w.WriteHeader(http.StatusInternalServerError) return } if res2.Status.Code != rpc.Code_CODE_OK { - log.Error().Msg("error returned: stat file/folder to share") + log.Error().Msgf("sourcePath %s does not exist on the storage backend", sourcePath) w.WriteHeader(http.StatusInternalServerError) return } @@ -183,17 +184,27 @@ func (h *sendHandler) Handler() http.Handler { shareRes, err := gatewayClient.CreateOCMShare(authCtx, shareRequest) if err != nil { - log.Error().Msg("error sending: CreateShare") + log.Error().Msg("error sending: CreateShare: " + err.Error()) w.WriteHeader(http.StatusInternalServerError) return } if shareRes.Status.Code != rpc.Code_CODE_OK { - log.Error().Msg("error returned: CreateShare") + log.Error().Msg("error returned: CreateShare: " + err.Error()) w.WriteHeader(http.StatusInternalServerError) return } + responseBody, err := utils.MarshalProtoV1ToJSON(shareRes) + if err != nil { + log.Error().Msg("error encoding response: " + err.Error()) + w.WriteHeader(http.StatusInternalServerError) + return + } w.WriteHeader(http.StatusOK) + _, err = w.Write(responseBody) + if err != nil { + log.Error().Msg("error writing response body:" + err.Error()) + } }) } diff --git a/internal/http/services/ocmd/shares.go b/internal/http/services/ocmd/shares.go index ce3090895b..d82c4f17af 100644 --- a/internal/http/services/ocmd/shares.go +++ b/internal/http/services/ocmd/shares.go @@ -100,11 +100,13 @@ func (h *sharesHandler) createShare(w http.ResponseWriter, r *http.Request) { } if resource == "" || providerID == "" || owner == "" { - WriteError(w, r, APIErrorInvalidParameter, "missing details about resource to be shared", nil) + msg := fmt.Sprintf("missing details about resource to be shared (resource='%s', providerID='%s', owner='%s", resource, providerID, owner) + WriteError(w, r, APIErrorInvalidParameter, msg, nil) return } if shareWith == "" || protocol["name"] == "" || meshProvider == "" { - WriteError(w, r, APIErrorInvalidParameter, "missing request parameters", nil) + msg := fmt.Sprintf("missing request parameters (shareWith='%s', protocol.name='%s', meshProvider='%s'", shareWith, protocol["name"], meshProvider) + WriteError(w, r, APIErrorInvalidParameter, msg, nil) return } @@ -188,9 +190,13 @@ func (h *sharesHandler) createShare(w http.ResponseWriter, r *http.Request) { return } + ownerParts := strings.Split(owner, "@") + if len(ownerParts) != 2 { + WriteError(w, r, APIErrorInvalidParameter, "owner should be opaqueId@webDAVHost", nil) + } ownerID := &userpb.UserId{ - OpaqueId: owner, - Idp: meshProvider, + OpaqueId: ownerParts[0], + Idp: ownerParts[1], Type: userpb.UserType_USER_TYPE_PRIMARY, } createShareReq := &ocmcore.CreateOCMCoreShareRequest{ diff --git a/pkg/auth/manager/nextcloud/nextcloud.go b/pkg/auth/manager/nextcloud/nextcloud.go index 4f07845882..45895ae10e 100644 --- a/pkg/auth/manager/nextcloud/nextcloud.go +++ b/pkg/auth/manager/nextcloud/nextcloud.go @@ -22,8 +22,10 @@ package nextcloud import ( "context" "encoding/json" + "fmt" "io" "net/http" + "strconv" "strings" authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1" @@ -141,6 +143,9 @@ func (am *Manager) do(ctx context.Context, a Action) (int, []byte, error) { } log.Info().Msgf("am.do response %d %s", resp.StatusCode, body) + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + return 0, nil, fmt.Errorf("Unexpected response code from EFSS API: " + strconv.Itoa(resp.StatusCode)) + } return resp.StatusCode, body, nil } diff --git a/pkg/ocm/invite/manager/json/json.go b/pkg/ocm/invite/manager/json/json.go index 38de89828f..67c3086ab5 100644 --- a/pkg/ocm/invite/manager/json/json.go +++ b/pkg/ocm/invite/manager/json/json.go @@ -34,6 +34,7 @@ import ( userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1" ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1" + "github.com/cs3org/reva/pkg/appctx" ctxpkg "github.com/cs3org/reva/pkg/ctx" "github.com/cs3org/reva/pkg/errtypes" "github.com/cs3org/reva/pkg/ocm/invite" @@ -235,7 +236,7 @@ func (m *manager) ForwardInvite(ctx context.Context, invite *invitepb.InviteToke if e != nil { return errors.Wrap(e, "json: error reading request body") } - return errors.Wrap(fmt.Errorf("%s: %s", resp.Status, string(respBody)), "json: error sending accept post request") + return errors.Wrap(fmt.Errorf("%s: %s", resp.Status, string(respBody)), fmt.Sprintf("json: error sending accept post request to %s", recipientURL)) } return nil @@ -272,7 +273,14 @@ func (m *manager) AcceptInvite(ctx context.Context, invite *invitepb.InviteToken func (m *manager) GetAcceptedUser(ctx context.Context, remoteUserID *userpb.UserId) (*userpb.User, error) { userKey := ctxpkg.ContextMustGetUser(ctx).GetId().GetOpaqueId() + log := appctx.GetLogger(ctx) for _, acceptedUser := range m.model.AcceptedUsers[userKey] { + log.Info().Msgf("looking for '%s' at '%s' - considering '%s' at '%s'", + remoteUserID.OpaqueId, + remoteUserID.Idp, + acceptedUser.Id.GetOpaqueId(), + acceptedUser.Id.GetIdp(), + ) if (acceptedUser.Id.GetOpaqueId() == remoteUserID.OpaqueId) && (remoteUserID.Idp == "" || acceptedUser.Id.GetIdp() == remoteUserID.Idp) { return acceptedUser, nil } diff --git a/pkg/ocm/share/manager/json/json.go b/pkg/ocm/share/manager/json/json.go index 8434b1b30d..ee241a3fad 100644 --- a/pkg/ocm/share/manager/json/json.go +++ b/pkg/ocm/share/manager/json/json.go @@ -32,6 +32,7 @@ import ( ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" + "github.com/cs3org/reva/pkg/appctx" ctxpkg "github.com/cs3org/reva/pkg/ctx" "github.com/cs3org/reva/pkg/errtypes" "github.com/cs3org/reva/pkg/ocm/share" @@ -264,6 +265,15 @@ func (m *mgr) Share(ctx context.Context, md *provider.ResourceId, g *ocm.ShareGr protocol["name"] = "datatx" } + log := appctx.GetLogger(ctx) + log.Info().Msg("pkg/ocm/share/manager/json calls sender.Send") + log.Info().Msgf("pkg/ocm/share/manager/json shareWith: %s", g.Grantee.GetUserId().OpaqueId) + log.Info().Msgf("pkg/ocm/share/manager/json name: %s", name) + log.Info().Msgf("pkg/ocm/share/manager/json providerId: %s", fmt.Sprintf("%s:%s", md.StorageId, md.OpaqueId)) + log.Info().Msgf("pkg/ocm/share/manager/json owner: %s", userID.OpaqueId) + log.Info().Msgf("pkg/ocm/share/manager/json protocol: %s", protocol) + log.Info().Msgf("pkg/ocm/share/manager/json meshProvider: %s", userID.Idp) + requestBodyMap := map[string]interface{}{ "shareWith": g.Grantee.GetUserId().OpaqueId, "name": name, @@ -272,7 +282,7 @@ func (m *mgr) Share(ctx context.Context, md *provider.ResourceId, g *ocm.ShareGr "protocol": protocol, "meshProvider": userID.Idp, // FIXME: move this into the 'owner' string? } - err = sender.Send(requestBodyMap, pi) + err = sender.Send(ctx, requestBodyMap, pi) if err != nil { err = errors.Wrap(err, "error sending OCM POST") return nil, err diff --git a/pkg/ocm/share/manager/nextcloud/nextcloud.go b/pkg/ocm/share/manager/nextcloud/nextcloud.go index d4222073db..03f80bfd0e 100644 --- a/pkg/ocm/share/manager/nextcloud/nextcloud.go +++ b/pkg/ocm/share/manager/nextcloud/nextcloud.go @@ -22,19 +22,22 @@ package nextcloud import ( "context" "encoding/json" + "fmt" "io" "math/rand" "net/http" + "strconv" "strings" "time" userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" + ctxpkg "github.com/cs3org/reva/pkg/ctx" + ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1" ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" "github.com/cs3org/reva/pkg/appctx" - ctxpkg "github.com/cs3org/reva/pkg/ctx" "github.com/cs3org/reva/pkg/errtypes" "github.com/cs3org/reva/pkg/ocm/share" "github.com/cs3org/reva/pkg/ocm/share/manager/registry" @@ -65,6 +68,7 @@ func init() { type Manager struct { client *http.Client sharedSecret string + webDAVHost string endPoint string } @@ -72,6 +76,7 @@ type Manager struct { type ShareManagerConfig struct { EndPoint string `mapstructure:"endpoint" docs:";The Nextcloud backend endpoint for user check"` SharedSecret string `mapstructure:"shared_secret"` + WebDAVHost string `mapstructure:"webdav_host"` MockHTTP bool `mapstructure:"mock_http"` } @@ -159,6 +164,7 @@ func NewShareManager(c *ShareManagerConfig) (*Manager, error) { endPoint: c.EndPoint, // e.g. "http://nc/apps/sciencemesh/" sharedSecret: c.SharedSecret, client: client, + webDAVHost: c.WebDAVHost, }, nil } @@ -208,6 +214,10 @@ func (sm *Manager) do(ctx context.Context, a Action, username string) (int, []by // curl -i -H 'application/json' -H 'X-Reva-Secret: shared-secret-1' -d '{"md":{"opaque_id":"fileid-/other/q/as"},"g":{"grantee":{"type":1,"Id":{"UserId":{"idp":"revanc2.docker","opaque_id":"marie"}}},"permissions":{"permissions":{"get_path":true,"initiate_file_download":true,"list_container":true,"list_file_versions":true,"stat":true}}},"provider_domain":"cern.ch","resource_type":"file","provider_id":2,"owner_opaque_id":"einstein","owner_display_name":"Albert Einstein","protocol":{"name":"webdav","options":{"sharedSecret":"secret","permissions":"webdav-property"}}}' https://nc1.docker/index.php/apps/sciencemesh/~/api/ocm/addSentShare log.Info().Msgf("am.do response %d %s", resp.StatusCode, body) + + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + return 0, nil, fmt.Errorf("Unexpected response code from EFSS API: " + strconv.Itoa(resp.StatusCode)) + } return resp.StatusCode, body, nil } @@ -230,7 +240,7 @@ func (sm *Manager) Share(ctx context.Context, md *provider.ResourceId, g *ocm.Sh isOwnersMeshProvider = true apiMethod = "addSentShare" username = getUsername(ctx) - token = randSeq(10) + token = randSeq(10) // FIXME: is this used for datatx? } else { apiMethod = "addReceivedShare" username = g.Grantee.GetUserId().OpaqueId @@ -252,13 +262,24 @@ func (sm *Manager) Share(ctx context.Context, md *provider.ResourceId, g *ocm.Sh return nil, errors.New("nextcloud: user and grantee are the same") } + now := time.Now().UnixNano() + ts := &typespb.Timestamp{ + Seconds: uint64(now / 1000000000), + Nanos: uint32(now % 1000000000), + } + s := &ocm.Share{ + Id: &ocm.ShareId{ + OpaqueId: "will-be-filled-in-by-the-backend", + }, Name: name, ResourceId: md, Permissions: g.Permissions, Grantee: g.Grantee, Owner: userID, Creator: userID, + Ctime: ts, + Mtime: ts, ShareType: st, } @@ -309,15 +330,9 @@ func (sm *Manager) Share(ctx context.Context, md *provider.ResourceId, g *ocm.Sh } _, body, err := sm.do(ctx, Action{apiMethod, string(encShare)}, username) - s.Id = &ocm.ShareId{ OpaqueId: string(body), } - now := time.Now().UnixNano() - s.Ctime = &typespb.Timestamp{ - Seconds: uint64(now / 1000000000), - Nanos: uint32(now % 1000000000), - } if err != nil { return nil, err } @@ -342,18 +357,45 @@ func (sm *Manager) Share(ctx context.Context, md *provider.ResourceId, g *ocm.Sh "options": map[string]string{ "permissions": pm, "sharedSecret": token, + "remote": sm.webDAVHost, }, } } + + log := appctx.GetLogger(ctx) + log.Info().Msg("pkg/ocm/share/manager/nextcloud calls sender.Send") + log.Info().Msgf("pkg/ocm/share/manager/nextcloud shareWith: %s", g.Grantee.GetUserId().OpaqueId) + log.Info().Msgf("pkg/ocm/share/manager/nextcloud name: %s", name) + log.Info().Msgf("pkg/ocm/share/manager/nextcloud providerId: %s", s.Id.OpaqueId) + log.Info().Msgf("pkg/ocm/share/manager/nextcloud owner: %s", userID.OpaqueId) + log.Info().Msgf("pkg/ocm/share/manager/nextcloud protocol: %s", protocol) + log.Info().Msgf("pkg/ocm/share/manager/nextcloud meshProvider: %s", userID.Idp) + log.Info().Msgf("Truncating name from %s to %s", name, name[5:]) + + // required: + // shareWith string Consumer specific identifier of the user or group the provider wants to share the resource with. This is known in advance. Please note that the consumer service endpoint is known in advance as well, so this is no part of the request body. + // name string Name of the resource (file or folder). + // providerId string Identifier to identify the resource at the provider side. This is unique per provider + // owner string Provider specific identifier of the user who owns the resource. + // shareType string Share type (user or group share) + // resourceType string Resource type (file, calendar, contact,...) + // protocol object The protocol which is used to establish synchronisation. At the moment only webdav is supported, but other (custom) protocols might be added in the future. + // + // optional: + // description string Optional description of the resource (file or folder). + // sender string Provider specific identifier of the user that wants to share the resource. Please note that the requesting provider is being identified on a higher level, so the former remote property is no part of the request body. + // ownerDisplayName string Display name of the owner of the resource + // senderDisplayName string Display name of the owner of the resource + requestBodyMap := map[string]interface{}{ "shareWith": g.Grantee.GetUserId().OpaqueId, - "name": name, + "name": name, // e.g. /home/welcome.txt becomes /welcome.txt "providerId": s.Id.OpaqueId, - "owner": userID.OpaqueId, + "owner": fmt.Sprintf("%s@%s", userID.OpaqueId, sm.webDAVHost), "protocol": protocol, - "meshProvider": userID.Idp, // FIXME: move this into the 'owner' string? + "meshProvider": userID.Idp, } - err = sender.Send(requestBodyMap, pi) + err = sender.Send(ctx, requestBodyMap, pi) if err != nil { err = errors.Wrap(err, "error sending OCM POST") return nil, err @@ -487,7 +529,10 @@ func (sm *Manager) ListShares(ctx context.Context, filters []*ocm.ListOCMSharesR // ListReceivedShares as defined in the ocm.share.Manager interface // https://github.com/cs3org/reva/blob/v1.13.0/pkg/ocm/share/share.go#L30-L57 +// returns a list of these: +// https://github.com/cs3org/go-cs3apis/blob/d297419/cs3/sharing/ocm/v1beta1/resources.pb.go#L290-L302 func (sm *Manager) ListReceivedShares(ctx context.Context) ([]*ocm.ReceivedShare, error) { + log := appctx.GetLogger(ctx) _, respBody, err := sm.do(ctx, Action{"ListReceivedShares", string("")}, getUsername(ctx)) if err != nil { return nil, err @@ -498,33 +543,32 @@ func (sm *Manager) ListReceivedShares(ctx context.Context) ([]*ocm.ReceivedShare if err != nil { return nil, err } - var pointers = make([]*ocm.ReceivedShare, len(respArr)) + var pointersBaseShare = make([]*ocm.Share, len(respArr)) + var pointersReceivedShare = make([]*ocm.ReceivedShare, len(respArr)) for i := 0; i < len(respArr); i++ { + log.Info().Msgf("Unpacking share object %+v\n", respArr[i].Share) altResultShare := respArr[i].Share if altResultShare == nil { - pointers[i] = &ocm.ReceivedShare{ - Share: nil, - State: respArr[i].State, - } - } else { - pointers[i] = &ocm.ReceivedShare{ - Share: &ocm.Share{ - Id: altResultShare.ID, - ResourceId: altResultShare.ResourceID, - Permissions: altResultShare.Permissions, - Grantee: &provider.Grantee{ - Id: altResultShare.Grantee.ID, - }, - Owner: altResultShare.Owner, - Creator: altResultShare.Creator, - Ctime: altResultShare.Ctime, - Mtime: altResultShare.Mtime, - }, - State: respArr[i].State, - } + return nil, errors.New("received an unreadable share object from the EFSS backend") + } + pointersBaseShare[i] = &ocm.Share{ + Id: altResultShare.ID, + ResourceId: altResultShare.ResourceID, + Permissions: altResultShare.Permissions, + Grantee: &provider.Grantee{ + Id: altResultShare.Grantee.ID, + }, + Owner: altResultShare.Owner, + Creator: altResultShare.Creator, + Ctime: altResultShare.Ctime, + Mtime: altResultShare.Mtime, + } + pointersReceivedShare[i] = &ocm.ReceivedShare{ + Share: pointersBaseShare[i], + State: respArr[i].State, } } - return pointers, err + return pointersReceivedShare, err } // GetReceivedShare as defined in the ocm.share.Manager interface diff --git a/pkg/ocm/share/sender/sender.go b/pkg/ocm/share/sender/sender.go index c5e2ddf103..2df13cbfb0 100644 --- a/pkg/ocm/share/sender/sender.go +++ b/pkg/ocm/share/sender/sender.go @@ -19,6 +19,7 @@ package sender import ( + "context" "encoding/json" "fmt" "io" @@ -29,6 +30,7 @@ import ( "time" ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1" + "github.com/cs3org/reva/pkg/appctx" "github.com/cs3org/reva/pkg/rhttp" "github.com/pkg/errors" ) @@ -46,7 +48,7 @@ func getOCMEndpoint(originProvider *ocmprovider.ProviderInfo) (string, error) { // Send executes the POST to the OCM shares endpoint to create the share at the // remote site. -func Send(requestBodyMap map[string]interface{}, pi *ocmprovider.ProviderInfo) error { +func Send(ctx context.Context, requestBodyMap map[string]interface{}, pi *ocmprovider.ProviderInfo) error { requestBody, err := json.Marshal(requestBodyMap) if err != nil { err = errors.Wrap(err, "error marshalling request body") @@ -63,6 +65,9 @@ func Send(requestBodyMap map[string]interface{}, pi *ocmprovider.ProviderInfo) e u.Path = path.Join(u.Path, createOCMCoreShareEndpoint) recipientURL := u.String() + log := appctx.GetLogger(ctx) + log.Info().Msgf("in OCM Send! %s %s", recipientURL, requestBody) + req, err := http.NewRequest(http.MethodPost, recipientURL, strings.NewReader(string(requestBody))) if err != nil { return errors.Wrap(err, "sender: error framing post request") @@ -85,7 +90,7 @@ func Send(requestBodyMap map[string]interface{}, pi *ocmprovider.ProviderInfo) e e = errors.Wrap(e, "sender: error reading request body") return e } - err = errors.Wrap(fmt.Errorf("%s: %s", resp.Status, string(respBody)), "sender: error sending create ocm core share post request") + err = errors.Wrap(fmt.Errorf("%s: %s", resp.Status, string(respBody)), "sender: error from "+ocmEndpoint) return err } return nil diff --git a/pkg/storage/fs/nextcloud/nextcloud.go b/pkg/storage/fs/nextcloud/nextcloud.go index 90406042b7..14ca0abeac 100644 --- a/pkg/storage/fs/nextcloud/nextcloud.go +++ b/pkg/storage/fs/nextcloud/nextcloud.go @@ -25,6 +25,7 @@ import ( "io" "net/http" "net/url" + "strconv" "strings" user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" @@ -126,15 +127,21 @@ func (nc *StorageDriver) SetHTTPClient(c *http.Client) { func (nc *StorageDriver) doUpload(ctx context.Context, filePath string, r io.ReadCloser) error { // log := appctx.GetLogger(ctx) + // log.Error().Msgf("in doUpload! %s", filePath) user, err := getUser(ctx) if err != nil { + // log.Error().Msg("error getting user!") return err } + // log.Error().Msgf("got user! %+v", user) + // See https://github.com/pondersource/nc-sciencemesh/issues/5 // url := nc.endPoint + "~" + user.Username + "/files/" + filePath - url := nc.endPoint + "~" + user.Username + "/api/storage/Upload/" + filePath + url := nc.endPoint + "~" + user.Id.OpaqueId + "/api/storage/Upload/home" + filePath + // log.Error().Msgf("sending PUT to NC/OC! %s", url) req, err := http.NewRequest(http.MethodPut, url, r) if err != nil { + // log.Error().Msgf("error! %s", err.Error()) panic(err) } @@ -142,8 +149,10 @@ func (nc *StorageDriver) doUpload(ctx context.Context, filePath string, r io.Rea // set the request header Content-Type for the upload // FIXME: get the actual content type from somewhere req.Header.Set("Content-Type", "text/plain") + // log.Error().Msg("client req") resp, err := nc.client.Do(req) if err != nil { + // log.Error().Msgf("error! %s", err.Error()) panic(err) } @@ -229,7 +238,9 @@ func (nc *StorageDriver) do(ctx context.Context, a Action) (int, []byte, error) return 0, nil, err } log.Info().Msgf("nc.do res %s %s", url, string(body)) - + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusNotFound { + return 0, nil, fmt.Errorf("Unexpected response code from EFSS API: " + strconv.Itoa(resp.StatusCode) + ":" + string(body)) + } return resp.StatusCode, body, nil } diff --git a/pkg/storage/fs/nextcloud/nextcloud_server_mock.go b/pkg/storage/fs/nextcloud/nextcloud_server_mock.go index 4ad9832f4b..094a47202b 100644 --- a/pkg/storage/fs/nextcloud/nextcloud_server_mock.go +++ b/pkg/storage/fs/nextcloud/nextcloud_server_mock.go @@ -124,6 +124,8 @@ var responses = map[string]Response{ `POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/Move {"oldRef":{"path":"/subdir"},"newRef":{"path":"/new_subdir"}}`: {200, ``, serverStateEmpty}, + `POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/RemoveGrant {"ref":{"path":"/subdir"},"g":{"grantee":{"type":1,"Id":{"UserId":{"idp":"some-idp","opaque_id":"some-opaque-id","type":1}}},"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true}}} EMPTY`: {200, ``, serverStateGrantRemoved}, + `POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/RemoveGrant {"ref":{"path":"/subdir"},"g":{"grantee":{"type":1,"Id":{"UserId":{"idp":"some-idp","opaque_id":"some-opaque-id","type":1}}},"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true}}} GRANT-ADDED`: {200, ``, serverStateGrantRemoved}, `POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/RemoveGrant {"path":"/subdir"} GRANT-ADDED`: {200, ``, serverStateGrantRemoved}, `POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/RestoreRecycleItem null`: {200, ``, serverStateSubdir}, @@ -147,7 +149,7 @@ var responses = map[string]Response{ `POST /apps/sciencemesh/~tester/api/storage/ListFolder {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"/some"},"mdKeys":["val1","val2","val3"]}`: {200, `[{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/some/path","permission_set":{},"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}]`, serverStateEmpty}, // `POST /apps/sciencemesh/~tester/api/storage/ListFolder {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"/some"},"mdKeys":["val1","val2","val3"]}`: {200, `[{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/path","permission_set":{},"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}]`, serverStateEmpty}, `POST /apps/sciencemesh/~tester/api/storage/InitiateUpload {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"/some/path"},"uploadLength":12345,"metadata":{"key1":"val1","key2":"val2","key3":"val3"}}`: {200, `{ "not":"sure", "what": "should be", "returned": "here" }`, serverStateEmpty}, - `PUT /apps/sciencemesh/~tester/api/storage/Upload/some/file/path.txt shiny!`: {200, ``, serverStateEmpty}, + `PUT /apps/sciencemesh/~tester/api/storage/Upload/home/some/file/path.txt shiny!`: {200, ``, serverStateEmpty}, `GET /apps/sciencemesh/~tester/api/storage/Download/some/file/path.txt `: {200, `the contents of the file`, serverStateEmpty}, `POST /apps/sciencemesh/~tester/api/storage/ListRevisions {"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"/some/path"}`: {200, `[{"opaque":{"map":{"some":{"value":"ZGF0YQ=="}}},"key":"version-12","size":12345,"mtime":1234567890,"etag":"deadb00f"},{"opaque":{"map":{"different":{"value":"c3R1ZmY="}}},"key":"asdf","size":12345,"mtime":1234567890,"etag":"deadbeef"}]`, serverStateEmpty}, `GET /apps/sciencemesh/~tester/api/storage/DownloadRevision/some%2Frevision/some/file/path.txt `: {200, `the contents of that revision`, serverStateEmpty}, @@ -180,6 +182,7 @@ func GetNextcloudServerMock(called *[]string) http.Handler { panic("Error reading response into buffer") } var key = fmt.Sprintf("%s %s %s", r.Method, r.URL, buf.String()) + fmt.Printf("Server mock is asked for '%s'\n", key) *called = append(*called, key) response := responses[key] if (response == Response{}) { @@ -187,7 +190,7 @@ func GetNextcloudServerMock(called *[]string) http.Handler { response = responses[key] } if (response == Response{}) { - fmt.Printf("%s %s %s %s\n", r.Method, r.URL, buf.String(), serverState) + fmt.Printf("server mock cannot serve '%s %s %s %s'\n", r.Method, r.URL, buf.String(), serverState) response = Response{500, fmt.Sprintf("response not defined! %s", key), serverStateEmpty} } serverState = responses[key].newServerState diff --git a/pkg/storage/fs/nextcloud/nextcloud_test.go b/pkg/storage/fs/nextcloud/nextcloud_test.go index b70529a6ac..335d74e816 100644 --- a/pkg/storage/fs/nextcloud/nextcloud_test.go +++ b/pkg/storage/fs/nextcloud/nextcloud_test.go @@ -440,13 +440,13 @@ var _ = Describe("Nextcloud", func() { StorageId: "storage-id", OpaqueId: "opaque-id", }, - Path: "some/file/path.txt", + Path: "/some/file/path.txt", } stringReader := strings.NewReader("shiny!") stringReadCloser := io.NopCloser(stringReader) err := nc.Upload(ctx, ref, stringReadCloser) Expect(err).ToNot(HaveOccurred()) - checkCalled(called, `PUT /apps/sciencemesh/~tester/api/storage/Upload/some/file/path.txt shiny!`) + checkCalled(called, `PUT /apps/sciencemesh/~tester/api/storage/Upload/home/some/file/path.txt shiny!`) }) }) // Download(ctx context.Context, ref *provider.Reference) (io.ReadCloser, error) diff --git a/pkg/user/manager/nextcloud/nextcloud.go b/pkg/user/manager/nextcloud/nextcloud.go index 4542abacd1..ab18e41f6f 100644 --- a/pkg/user/manager/nextcloud/nextcloud.go +++ b/pkg/user/manager/nextcloud/nextcloud.go @@ -24,6 +24,7 @@ import ( "fmt" "io" "net/http" + "strconv" "strings" userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" @@ -139,6 +140,9 @@ func (um *Manager) do(ctx context.Context, a Action, username string) (int, []by defer resp.Body.Close() body, err := io.ReadAll(resp.Body) + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + return 0, nil, fmt.Errorf("Unexpected response code from EFSS API: " + strconv.Itoa(resp.StatusCode)) + } return resp.StatusCode, body, err } diff --git a/tests/helpers/helpers.go b/tests/helpers/helpers.go index d4b8dafa93..f281648efe 100644 --- a/tests/helpers/helpers.go +++ b/tests/helpers/helpers.go @@ -46,7 +46,7 @@ func TempDir(name string) (string, error) { if err != nil { return "nil", err } - tmpRoot, err := os.MkdirTemp(tmpDir, "reva-unit-tests-*-root") + tmpRoot, err := os.MkdirTemp(tmpDir, "reva-tests-*-root") if err != nil { return "nil", err } diff --git a/tests/integration/grpc/grpc_suite_test.go b/tests/integration/grpc/grpc_suite_test.go index bc504e3b76..ef59d13f92 100644 --- a/tests/integration/grpc/grpc_suite_test.go +++ b/tests/integration/grpc/grpc_suite_test.go @@ -29,6 +29,7 @@ import ( "testing" "time" + "github.com/cs3org/reva/tests/helpers" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/pkg/errors" @@ -89,7 +90,7 @@ func startRevads(configs map[string]string, variables map[string]string) (map[st ownAddress := addresses[name] // Create a temporary root for this revad - tmpRoot, err := os.MkdirTemp("", "reva-grpc-integration-tests-*-root") + tmpRoot, err := helpers.TempDir("") if err != nil { return nil, errors.Wrapf(err, "Could not create tmpdir") }