fix handling of ERROR in response to REMOVE

This allows an error message from a proxied special remote to be
displayed to the client.

In the case where removal from several nodes of a cluster fails,
there can be several errors. What to do? I decided to only show
the first error to the user. Probably in this case the user is not in a
position to do anything about an error message, so best keep it simple.
If the problem with the first node is fixed, they'll see the error from
the next node.
This commit is contained in:
Joey Hess 2024-06-28 14:07:23 -04:00
parent a6ea057f6b
commit 158d7bc933
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
5 changed files with 31 additions and 23 deletions

View file

@ -76,7 +76,6 @@ proxySpecialRemote
proxySpecialRemote protoversion r ihdl ohdl endv = go proxySpecialRemote protoversion r ihdl ohdl endv = go
where where
go = receivemessage >>= \case go = receivemessage >>= \case
Just (BYPASS _) -> go
Just (CHECKPRESENT k) -> do Just (CHECKPRESENT k) -> do
tryNonAsync (Remote.checkPresent r k) >>= \case tryNonAsync (Remote.checkPresent r k) >>= \case
Right True -> sendmessage SUCCESS Right True -> sendmessage SUCCESS
@ -90,10 +89,11 @@ proxySpecialRemote protoversion r ihdl ohdl endv = go
Just (REMOVE k) -> do Just (REMOVE k) -> do
tryNonAsync (Remote.removeKey r k) >>= \case tryNonAsync (Remote.removeKey r k) >>= \case
Right () -> sendmessage SUCCESS Right () -> sendmessage SUCCESS
Left _ -> sendmessage FAILURE Left err -> propagateerror err
go go
Just (PUT af k) -> giveup "TODO PUT" -- XXX Just (PUT af k) -> giveup "TODO PUT" -- XXX
Just (GET offset af k) -> giveup "TODO GET" -- XXX Just (GET offset af k) -> giveup "TODO GET" -- XXX
Just (BYPASS _) -> go
Just (CONNECT _) -> Just (CONNECT _) ->
-- Not supported and the protocol ends here. -- Not supported and the protocol ends here.
sendmessage $ CONNECTDONE (ExitFailure 1) sendmessage $ CONNECTDONE (ExitFailure 1)

View file

@ -378,7 +378,7 @@ lockContentWhile runproto key a = bracket setup cleanup a
cleanup True = runproto () $ net $ sendMessage UNLOCKCONTENT cleanup True = runproto () $ net $ sendMessage UNLOCKCONTENT
cleanup False = return () cleanup False = return ()
remove :: Key -> Proto (Bool, Maybe [UUID]) remove :: Key -> Proto (Either String Bool, Maybe [UUID])
remove key = do remove key = do
net $ sendMessage (REMOVE key) net $ sendMessage (REMOVE key)
checkSuccessFailurePlus checkSuccessFailurePlus
@ -644,28 +644,30 @@ checkSuccess' = do
checkSuccessPlus :: Proto (Maybe [UUID]) checkSuccessPlus :: Proto (Maybe [UUID])
checkSuccessPlus = checkSuccessPlus =
checkSuccessFailurePlus >>= return . \case checkSuccessFailurePlus >>= return . \case
(True, v) -> v (Right True, v) -> v
(False, _) -> Nothing (Right False, _) -> Nothing
(Left _, _) -> Nothing
checkSuccessFailurePlus :: Proto (Bool, Maybe [UUID]) checkSuccessFailurePlus :: Proto (Either String Bool, Maybe [UUID])
checkSuccessFailurePlus = do checkSuccessFailurePlus = do
ver <- net getProtocolVersion ver <- net getProtocolVersion
if ver >= ProtocolVersion 2 if ver >= ProtocolVersion 2
then do then do
ack <- net receiveMessage ack <- net receiveMessage
case ack of case ack of
Just SUCCESS -> return (True, Just []) Just SUCCESS -> return (Right True, Just [])
Just (SUCCESS_PLUS l) -> return (True, Just l) Just (SUCCESS_PLUS l) -> return (Right True, Just l)
Just FAILURE -> return (False, Nothing) Just FAILURE -> return (Right False, Nothing)
Just (FAILURE_PLUS l) -> return (False, Just l) Just (FAILURE_PLUS l) -> return (Right False, Just l)
Just (ERROR err) -> return (Left err, Nothing)
_ -> do _ -> do
net $ sendMessage (ERROR "expected SUCCESS or SUCCESS-PLUS or FAILURE or FAILURE-PLUS") net $ sendMessage (ERROR "expected SUCCESS or SUCCESS-PLUS or FAILURE or FAILURE-PLUS")
return (False, Nothing) return (Right False, Nothing)
else do else do
ok <- checkSuccess ok <- checkSuccess
if ok if ok
then return (True, Just []) then return (Right True, Just [])
else return (False, Nothing) else return (Right False, Nothing)
sendSuccess :: Bool -> Proto () sendSuccess :: Bool -> Proto ()
sendSuccess True = net $ sendMessage SUCCESS sendSuccess True = net $ sendMessage SUCCESS

View file

@ -329,13 +329,15 @@ proxy proxydone proxymethods servermode (ClientSide clientrunst clientconn) remo
net $ sendMessage message net $ sendMessage message
net receiveMessage >>= return . \case net receiveMessage >>= return . \case
Just SUCCESS -> Just SUCCESS ->
Just (True, [Remote.uuid (remote r)]) Just ((True, Nothing), [Remote.uuid (remote r)])
Just (SUCCESS_PLUS us) -> Just (SUCCESS_PLUS us) ->
Just (True, Remote.uuid (remote r):us) Just ((True, Nothing), Remote.uuid (remote r):us)
Just FAILURE -> Just FAILURE ->
Just (False, []) Just ((False, Nothing), [])
Just (FAILURE_PLUS us) -> Just (FAILURE_PLUS us) ->
Just (False, us) Just ((False, Nothing), us)
Just (ERROR err) ->
Just ((False, Just err), [])
_ -> Nothing _ -> Nothing
let v' = map join v let v' = map join v
let us = concatMap snd $ catMaybes v' let us = concatMap snd $ catMaybes v'
@ -344,12 +346,14 @@ proxy proxydone proxymethods servermode (ClientSide clientrunst clientconn) remo
client $ net $ sendMessage $ client $ net $ sendMessage $
let nonplussed = all (== remoteuuid) us let nonplussed = all (== remoteuuid) us
|| protocolversion < 2 || protocolversion < 2
in if all (maybe False fst) v' in if all (maybe False (fst . fst)) v'
then if nonplussed then if nonplussed
then SUCCESS then SUCCESS
else SUCCESS_PLUS us else SUCCESS_PLUS us
else if nonplussed else if nonplussed
then FAILURE then case mapMaybe (snd . fst) (catMaybes v') of
[] -> FAILURE
(err:_) -> ERROR err
else FAILURE_PLUS us else FAILURE_PLUS us
handleGET remoteside message = getresponse (runRemoteSide remoteside) message $ handleGET remoteside message = getresponse (runRemoteSide remoteside) message $

View file

@ -456,7 +456,7 @@ dropKey' repo r st@(State connpool duc _ _ _) key
) )
| Git.repoIsHttp repo = giveup "dropping from http remote not supported" | Git.repoIsHttp repo = giveup "dropping from http remote not supported"
| otherwise = P2PHelper.remove (uuid r) | otherwise = P2PHelper.remove (uuid r)
(Ssh.runProto r connpool (return (False, Nothing))) key (Ssh.runProto r connpool (return (Right False, Nothing))) key
lockKey :: Remote -> State -> Key -> (VerifiedCopy -> Annex r) -> Annex r lockKey :: Remote -> State -> Key -> (VerifiedCopy -> Annex r) -> Annex r
lockKey r st key callback = do lockKey r st key callback = do

View file

@ -60,12 +60,14 @@ retrieve gc runner k af dest p verifyconfig = do
Just (False, _) -> giveup "Transfer failed" Just (False, _) -> giveup "Transfer failed"
Nothing -> remoteUnavail Nothing -> remoteUnavail
remove :: UUID -> ProtoRunner (Bool, Maybe [UUID]) -> Key -> Annex () remove :: UUID -> ProtoRunner (Either String Bool, Maybe [UUID]) -> Key -> Annex ()
remove remoteuuid runner k = runner (P2P.remove k) >>= \case remove remoteuuid runner k = runner (P2P.remove k) >>= \case
Just (True, alsoremoveduuids) -> note alsoremoveduuids Just (Right True, alsoremoveduuids) -> note alsoremoveduuids
Just (False, alsoremoveduuids) -> do Just (Right False, alsoremoveduuids) -> do
note alsoremoveduuids note alsoremoveduuids
giveup "removing content from remote failed" giveup "removing content from remote failed"
Just (Left err, _) -> do
giveup (safeOutput err)
Nothing -> remoteUnavail Nothing -> remoteUnavail
where where
-- The remote reports removal from other UUIDs than its own, -- The remote reports removal from other UUIDs than its own,