proxying to local git remotes works

This just happened to work correctly. Rather surprisingly. It turns out
that openP2PSshConnection actually also supports local git remotes,
by just running git-annex-shell with the path to the remote.

Renamed "P2PSsh" to "P2PShell" to make this clear.
This commit is contained in:
Joey Hess 2024-06-12 10:10:11 -04:00
parent 178da0dc99
commit c6e0710281
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
4 changed files with 62 additions and 56 deletions

View file

@ -15,7 +15,7 @@ import qualified P2P.Protocol as P2P
import qualified Annex import qualified Annex
import Annex.UUID import Annex.UUID
import qualified CmdLine.GitAnnexShell.Checks as Checks import qualified CmdLine.GitAnnexShell.Checks as Checks
import Remote.Helper.Ssh (openP2PSshConnection', closeP2PSshConnection) import Remote.Helper.Ssh (openP2PShellConnection', closeP2PShellConnection)
import System.IO.Error import System.IO.Error
@ -72,12 +72,12 @@ performProxy clientuuid servermode remote = do
othermsg protoerrhandler othermsg protoerrhandler
withclientversion _ Nothing = done withclientversion _ Nothing = done
-- FIXME: Support special remotes and non-ssh git remotes. -- FIXME: Support special remotes.
connectremote clientmaxversion cont = connectremote clientmaxversion cont =
openP2PSshConnection' remote clientmaxversion >>= \case openP2PShellConnection' remote clientmaxversion >>= \case
Just conn@(P2P.IO.OpenConnection (remoterunst, remoteconn, _)) -> Just conn@(P2P.IO.OpenConnection (remoterunst, remoteconn, _)) ->
cont (RemoteSide remoterunst remoteconn) cont (RemoteSide remoterunst remoteconn)
`finally` liftIO (closeP2PSshConnection conn) `finally` liftIO (closeP2PShellConnection conn)
_ -> giveup "Unable to connect to remote." _ -> giveup "Unable to connect to remote."
protoerrhandler cont a = a >>= \case protoerrhandler cont a = a >>= \case

View file

@ -472,7 +472,7 @@ lockKey' repo r st@(State connpool duc _ _ _) key callback
) )
| Git.repoIsSsh repo = do | Git.repoIsSsh repo = do
showLocking r showLocking r
let withconn = Ssh.withP2PSshConnection r connpool failedlock let withconn = Ssh.withP2PShellConnection r connpool failedlock
P2PHelper.lock withconn Ssh.runProtoConn (uuid r) key callback P2PHelper.lock withconn Ssh.runProtoConn (uuid r) key callback
| otherwise = failedlock | otherwise = failedlock
where where
@ -733,7 +733,7 @@ mkFileCopier remotewanthardlink (State _ _ copycowtried _ _) = do
- This returns False when the repository UUID is not as expected. -} - This returns False when the repository UUID is not as expected. -}
type DeferredUUIDCheck = Annex Bool type DeferredUUIDCheck = Annex Bool
data State = State Ssh.P2PSshConnectionPool DeferredUUIDCheck CopyCoWTried (Annex (Git.Repo, GitConfig)) LocalRemoteAnnex data State = State Ssh.P2PShellConnectionPool DeferredUUIDCheck CopyCoWTried (Annex (Git.Repo, GitConfig)) LocalRemoteAnnex
getRepoFromState :: State -> Annex Git.Repo getRepoFromState :: State -> Annex Git.Repo
getRepoFromState (State _ _ _ a _) = fst <$> a getRepoFromState (State _ _ _ a _) = fst <$> a
@ -746,7 +746,7 @@ getGitConfigFromState (State _ _ _ a _) = snd <$> a
mkState :: Git.Repo -> UUID -> RemoteGitConfig -> Annex State mkState :: Git.Repo -> UUID -> RemoteGitConfig -> Annex State
mkState r u gc = do mkState r u gc = do
pool <- Ssh.mkP2PSshConnectionPool pool <- Ssh.mkP2PShellConnectionPool
copycowtried <- liftIO newCopyCoWTried copycowtried <- liftIO newCopyCoWTried
lra <- mkLocalRemoteAnnex r lra <- mkLocalRemoteAnnex r
(duc, getrepo) <- go (duc, getrepo) <- go

View file

@ -178,61 +178,62 @@ rsyncParams r direction = do
| otherwise = remoteAnnexRsyncUploadOptions gc | otherwise = remoteAnnexRsyncUploadOptions gc
gc = gitconfig r gc = gitconfig r
-- A connection over ssh to git-annex shell speaking the P2P protocol. -- A connection over ssh or locally to git-annex shell,
type P2PSshConnection = P2P.ClosableConnection -- speaking the P2P protocol.
type P2PShellConnection = P2P.ClosableConnection
(P2P.RunState, P2P.P2PConnection, ProcessHandle) (P2P.RunState, P2P.P2PConnection, ProcessHandle)
closeP2PSshConnection :: P2PSshConnection -> IO (P2PSshConnection, Maybe ExitCode) closeP2PShellConnection :: P2PShellConnection -> IO (P2PShellConnection, Maybe ExitCode)
closeP2PSshConnection P2P.ClosedConnection = return (P2P.ClosedConnection, Nothing) closeP2PShellConnection P2P.ClosedConnection = return (P2P.ClosedConnection, Nothing)
closeP2PSshConnection (P2P.OpenConnection (_st, conn, pid)) = closeP2PShellConnection (P2P.OpenConnection (_st, conn, pid)) =
-- mask async exceptions, avoid cleanup being interrupted -- mask async exceptions, avoid cleanup being interrupted
uninterruptibleMask_ $ do uninterruptibleMask_ $ do
P2P.closeConnection conn P2P.closeConnection conn
exitcode <- waitForProcess pid exitcode <- waitForProcess pid
return (P2P.ClosedConnection, Just exitcode) return (P2P.ClosedConnection, Just exitcode)
-- Pool of connections over ssh to git-annex-shell p2pstdio. -- Pool of connections to git-annex-shell p2pstdio.
type P2PSshConnectionPool = TVar (Maybe P2PSshConnectionPoolState) type P2PShellConnectionPool = TVar (Maybe P2PShellConnectionPoolState)
data P2PSshConnectionPoolState data P2PShellConnectionPoolState
= P2PSshConnections [P2PSshConnection] = P2PShellConnections [P2PShellConnection]
-- Remotes using an old version of git-annex-shell don't support P2P -- Remotes using an old version of git-annex-shell don't support P2P
| P2PSshUnsupported | P2PShellUnsupported
mkP2PSshConnectionPool :: Annex P2PSshConnectionPool mkP2PShellConnectionPool :: Annex P2PShellConnectionPool
mkP2PSshConnectionPool = liftIO $ newTVarIO Nothing mkP2PShellConnectionPool = liftIO $ newTVarIO Nothing
-- Takes a connection from the pool, if any are available, otherwise -- Takes a connection from the pool, if any are available, otherwise
-- tries to open a new one. -- tries to open a new one.
getP2PSshConnection :: Remote -> P2PSshConnectionPool -> Annex (Maybe P2PSshConnection) getP2PShellConnection :: Remote -> P2PShellConnectionPool -> Annex (Maybe P2PShellConnection)
getP2PSshConnection r connpool = getexistingconn >>= \case getP2PShellConnection r connpool = getexistingconn >>= \case
Nothing -> return Nothing Nothing -> return Nothing
Just Nothing -> openP2PSshConnection r connpool Just Nothing -> openP2PShellConnection r connpool
Just (Just c) -> return (Just c) Just (Just c) -> return (Just c)
where where
getexistingconn = liftIO $ atomically $ readTVar connpool >>= \case getexistingconn = liftIO $ atomically $ readTVar connpool >>= \case
Just P2PSshUnsupported -> return Nothing Just P2PShellUnsupported -> return Nothing
Just (P2PSshConnections (c:cs)) -> do Just (P2PShellConnections (c:cs)) -> do
writeTVar connpool (Just (P2PSshConnections cs)) writeTVar connpool (Just (P2PShellConnections cs))
return (Just (Just c)) return (Just (Just c))
Just (P2PSshConnections []) -> return (Just Nothing) Just (P2PShellConnections []) -> return (Just Nothing)
Nothing -> return (Just Nothing) Nothing -> return (Just Nothing)
-- Add a connection to the pool, unless it's closed. -- Add a connection to the pool, unless it's closed.
storeP2PSshConnection :: P2PSshConnectionPool -> P2PSshConnection -> IO () storeP2PShellConnection :: P2PShellConnectionPool -> P2PShellConnection -> IO ()
storeP2PSshConnection _ P2P.ClosedConnection = return () storeP2PShellConnection _ P2P.ClosedConnection = return ()
storeP2PSshConnection connpool conn = atomically $ modifyTVar' connpool $ \case storeP2PShellConnection connpool conn = atomically $ modifyTVar' connpool $ \case
Just (P2PSshConnections cs) -> Just (P2PSshConnections (conn:cs)) Just (P2PShellConnections cs) -> Just (P2PShellConnections (conn:cs))
_ -> Just (P2PSshConnections [conn]) _ -> Just (P2PShellConnections [conn])
-- Try to open a P2PSshConnection. -- Try to open a P2PShellConnection.
-- The new connection is not added to the pool, so it's available -- The new connection is not added to the pool, so it's available
-- for the caller to use. -- for the caller to use.
-- If the remote does not support the P2P protocol, that's remembered in -- If the remote does not support the P2P protocol, that's remembered in
-- the connection pool. -- the connection pool.
openP2PSshConnection :: Remote -> P2PSshConnectionPool -> Annex (Maybe P2PSshConnection) openP2PShellConnection :: Remote -> P2PShellConnectionPool -> Annex (Maybe P2PShellConnection)
openP2PSshConnection r connpool = openP2PShellConnection r connpool =
openP2PSshConnection' r P2P.maxProtocolVersion >>= \case openP2PShellConnection' r P2P.maxProtocolVersion >>= \case
Just conn -> return (Just conn) Just conn -> return (Just conn)
Nothing -> do Nothing -> do
liftIO $ rememberunsupported liftIO $ rememberunsupported
@ -240,10 +241,10 @@ openP2PSshConnection r connpool =
where where
rememberunsupported = atomically $ rememberunsupported = atomically $
modifyTVar' connpool $ modifyTVar' connpool $
maybe (Just P2PSshUnsupported) Just maybe (Just P2PShellUnsupported) Just
openP2PSshConnection' :: Remote -> P2P.ProtocolVersion -> Annex (Maybe P2PSshConnection) openP2PShellConnection' :: Remote -> P2P.ProtocolVersion -> Annex (Maybe P2PShellConnection)
openP2PSshConnection' r maxprotoversion = do openP2PShellConnection' r maxprotoversion = do
u <- getUUID u <- getUUID
let ps = [Param (fromUUID u)] let ps = [Param (fromUUID u)]
repo <- getRepo r repo <- getRepo r
@ -264,7 +265,7 @@ openP2PSshConnection' r maxprotoversion = do
, P2P.connIhdl = to , P2P.connIhdl = to
, P2P.connOhdl = from , P2P.connOhdl = from
, P2P.connIdent = P2P.ConnIdent $ , P2P.connIdent = P2P.ConnIdent $
Just $ "ssh connection " ++ show pidnum Just $ "git-annex-shell connection " ++ show pidnum
} }
runst <- P2P.mkRunState P2P.Client runst <- P2P.mkRunState P2P.Client
let c = P2P.OpenConnection (runst, conn, pid) let c = P2P.OpenConnection (runst, conn, pid)
@ -276,7 +277,7 @@ openP2PSshConnection' r maxprotoversion = do
Right (Right (Just theiruuid)) | theiruuid == uuid r -> Right (Right (Just theiruuid)) | theiruuid == uuid r ->
return $ Just c return $ Just c
_ -> do _ -> do
(cclosed, exitcode) <- closeP2PSshConnection c (cclosed, exitcode) <- closeP2PShellConnection c
-- ssh exits 255 when unable to connect to -- ssh exits 255 when unable to connect to
-- server. -- server.
if exitcode == Just (ExitFailure 255) if exitcode == Just (ExitFailure 255)
@ -285,19 +286,19 @@ openP2PSshConnection' r maxprotoversion = do
-- Runs a P2P Proto action on a remote when it supports that, -- Runs a P2P Proto action on a remote when it supports that,
-- otherwise the fallback action. -- otherwise the fallback action.
runProto :: Remote -> P2PSshConnectionPool -> Annex a -> P2P.Proto a -> Annex (Maybe a) runProto :: Remote -> P2PShellConnectionPool -> Annex a -> P2P.Proto a -> Annex (Maybe a)
runProto r connpool onerr proto = Just <$> runProto r connpool onerr proto = Just <$>
(getP2PSshConnection r connpool >>= maybe onerr go) (getP2PShellConnection r connpool >>= maybe onerr go)
where where
go c = do go c = do
(c', v) <- runProtoConn proto c (c', v) <- runProtoConn proto c
case v of case v of
Just res -> do Just res -> do
liftIO $ storeP2PSshConnection connpool c' liftIO $ storeP2PShellConnection connpool c'
return res return res
Nothing -> onerr Nothing -> onerr
runProtoConn :: P2P.Proto a -> P2PSshConnection -> Annex (P2PSshConnection, Maybe a) runProtoConn :: P2P.Proto a -> P2PShellConnection -> Annex (P2PShellConnection, Maybe a)
runProtoConn _ P2P.ClosedConnection = return (P2P.ClosedConnection, Nothing) runProtoConn _ P2P.ClosedConnection = return (P2P.ClosedConnection, Nothing)
runProtoConn a conn@(P2P.OpenConnection (runst, c, _)) = do runProtoConn a conn@(P2P.OpenConnection (runst, c, _)) = do
P2P.runFullProto runst c a >>= \case P2P.runFullProto runst c a >>= \case
@ -306,24 +307,24 @@ runProtoConn a conn@(P2P.OpenConnection (runst, c, _)) = do
-- usable, so close it. -- usable, so close it.
Left e -> do Left e -> do
warning $ UnquotedString $ "Lost connection (" ++ P2P.describeProtoFailure e ++ ")" warning $ UnquotedString $ "Lost connection (" ++ P2P.describeProtoFailure e ++ ")"
conn' <- fst <$> liftIO (closeP2PSshConnection conn) conn' <- fst <$> liftIO (closeP2PShellConnection conn)
return (conn', Nothing) return (conn', Nothing)
-- Allocates a P2P ssh connection from the pool, and runs the action with it, -- Allocates a P2P shell connection from the pool, and runs the action with
-- returning the connection to the pool once the action is done. -- it, returning the connection to the pool once the action is done.
-- --
-- If the remote does not support the P2P protocol, runs the fallback -- If the remote does not support the P2P protocol, runs the fallback
-- action instead. -- action instead.
withP2PSshConnection withP2PShellConnection
:: Remote :: Remote
-> P2PSshConnectionPool -> P2PShellConnectionPool
-> Annex a -> Annex a
-> (P2PSshConnection -> Annex (P2PSshConnection, a)) -> (P2PShellConnection -> Annex (P2PShellConnection, a))
-> Annex a -> Annex a
withP2PSshConnection r connpool fallback a = bracketOnError get cache go withP2PShellConnection r connpool fallback a = bracketOnError get cache go
where where
get = getP2PSshConnection r connpool get = getP2PShellConnection r connpool
cache (Just conn) = liftIO $ storeP2PSshConnection connpool conn cache (Just conn) = liftIO $ storeP2PShellConnection connpool conn
cache Nothing = return () cache Nothing = return ()
go (Just conn) = do go (Just conn) = do
(conn', res) <- a conn (conn', res) <- a conn

View file

@ -36,13 +36,18 @@ For June's work on [[design/passthrough_proxy]], implementation plan:
2. Remote instantiation for proxies. (done) 2. Remote instantiation for proxies. (done)
4. Prevent listProxied from listing anything when the proxy remote's
url is a local directory. Proxying does not work in that situation,
because the proxied remotes have the same url, and so git-annex-shell
is not run when accessing them, instead the proxy remote is accessed
directly.
3. Implement git-annex-shell proxying for CONNECT and NOTIFYCHANGES. 3. Implement git-annex-shell proxying for CONNECT and NOTIFYCHANGES.
(For completeness, they will only be used when using tor-annex (For completeness, they will only be used when using tor-annex
to access a proxy.) to access a proxy.)
4. Either implement proxying for local path remotes, or prevent 3. Proxy should update location tracking information for proxied remotes,
listProxied from operating on them. Currently it seems to work, so it is available to other users who sync with it.
but doesn't work right.
4. Either implement proxying for tor-annex remotes, or prevent 4. Either implement proxying for tor-annex remotes, or prevent
listProxied from operating on them. listProxied from operating on them.