2018-03-07 19:15:23 +00:00
|
|
|
{- git-annex command
|
|
|
|
-
|
2024-06-10 22:01:36 +00:00
|
|
|
- Copyright 2018-2024 Joey Hess <id@joeyh.name>
|
2018-03-07 19:15:23 +00:00
|
|
|
-
|
2019-03-13 19:48:14 +00:00
|
|
|
- Licensed under the GNU AGPL version 3 or higher.
|
2018-03-07 19:15:23 +00:00
|
|
|
-}
|
|
|
|
|
|
|
|
module Command.P2PStdIO where
|
|
|
|
|
|
|
|
import Command
|
|
|
|
import P2P.IO
|
|
|
|
import P2P.Annex
|
2024-06-10 22:01:36 +00:00
|
|
|
import P2P.Proxy
|
2018-03-07 19:15:23 +00:00
|
|
|
import qualified P2P.Protocol as P2P
|
|
|
|
import qualified Annex
|
2024-06-18 14:51:37 +00:00
|
|
|
import Annex.Proxy
|
2018-03-07 19:15:23 +00:00
|
|
|
import Annex.UUID
|
|
|
|
import qualified CmdLine.GitAnnexShell.Checks as Checks
|
2024-06-12 15:37:14 +00:00
|
|
|
import Logs.Location
|
2024-06-17 19:00:11 +00:00
|
|
|
import Logs.Cluster
|
2024-06-18 14:36:04 +00:00
|
|
|
import Annex.Cluster
|
2024-06-12 15:37:14 +00:00
|
|
|
import qualified Remote
|
2018-03-07 19:15:23 +00:00
|
|
|
|
2018-09-25 20:49:59 +00:00
|
|
|
import System.IO.Error
|
|
|
|
|
2018-03-07 19:15:23 +00:00
|
|
|
cmd :: Command
|
|
|
|
cmd = noMessages $ command "p2pstdio" SectionPlumbing
|
|
|
|
"communicate in P2P protocol over stdio"
|
2018-03-08 20:21:16 +00:00
|
|
|
paramUUID (withParams seek)
|
2018-03-07 19:15:23 +00:00
|
|
|
|
|
|
|
seek :: CmdParams -> CommandSeek
|
2018-03-08 20:21:16 +00:00
|
|
|
seek [u] = commandAction $ start $ toUUID u
|
|
|
|
seek _ = giveup "missing UUID parameter"
|
2018-03-07 19:15:23 +00:00
|
|
|
|
2018-03-08 20:21:16 +00:00
|
|
|
start :: UUID -> CommandStart
|
finish CommandStart transition
The hoped for optimisation of CommandStart with -J did not materialize.
In fact, not runnign CommandStart in parallel is slower than -J3.
So, CommandStart are still run in parallel.
(The actual bad performance I've been seeing with -J in my big repo
has to do with building the remoteList.)
But, this is still progress toward making -J faster, because it gets rid
of the onlyActionOn roadblock in the way of making CommandCleanup jobs
run separate from CommandPerform jobs.
Added OnlyActionOn constructor for ActionItem which fixes the
onlyActionOn breakage in the last commit.
Made CustomOutput include an ActionItem, so even things using it can
specify OnlyActionOn.
In Command.Move and Command.Sync, there were CommandStarts that used
includeCommandAction, so output messages, which is no longer allowed.
Fixed by using startingCustomOutput, but that's still not quite right,
since it prevents message display for the includeCommandAction run
inside it too.
2019-06-12 13:23:26 +00:00
|
|
|
start theiruuid = startingCustomOutput (ActionItemOther Nothing) $ do
|
2018-05-25 17:17:56 +00:00
|
|
|
servermode <- liftIO $ do
|
|
|
|
ro <- Checks.checkEnvSet Checks.readOnlyEnv
|
|
|
|
ao <- Checks.checkEnvSet Checks.appendOnlyEnv
|
|
|
|
return $ case (ro, ao) of
|
|
|
|
(True, _) -> P2P.ServeReadOnly
|
|
|
|
(False, True) -> P2P.ServeAppendOnly
|
|
|
|
(False, False) -> P2P.ServeReadWrite
|
2024-06-10 22:01:36 +00:00
|
|
|
Annex.getState Annex.proxyremote >>= \case
|
2024-06-17 19:00:11 +00:00
|
|
|
Nothing ->
|
|
|
|
performLocal theiruuid servermode
|
|
|
|
Just (Right r) ->
|
|
|
|
performProxy theiruuid servermode r
|
|
|
|
Just (Left clusteruuid) ->
|
|
|
|
performProxyCluster theiruuid clusteruuid servermode
|
2024-06-10 22:01:36 +00:00
|
|
|
|
|
|
|
performLocal :: UUID -> P2P.ServerMode -> CommandPerform
|
|
|
|
performLocal theiruuid servermode = do
|
2018-03-07 19:15:23 +00:00
|
|
|
myuuid <- getUUID
|
git-annex-shell: block relay requests
connRepo is only used when relaying git upload-pack and receive-pack.
That's only supposed to be used when git-annex-remotedaemon is serving
git-remote-tor-annex connections over tor. But, it was always set, and
so could be used in other places possibly.
Fixed by making connRepo optional in the P2P protocol interface.
In Command.EnableTor, it's not needed, because it only speaks the
protocol in order to check that it's able to connect back to itself via
the hidden service. So changed that to pass Nothing rather than the git
repo.
In Remote.Helper.Ssh, it's connecting to git-annex-shell p2pstdio,
so is making the requests, so will never need connRepo.
In git-annex-shell p2pstdio, it was accepting git upload-pack and
receive-pack requests over the P2P protocol, even though nothing sent
them. This is arguably a security hole, particularly if the user has
set environment variables like GIT_ANNEX_SHELL_LIMITED to prevent
git push/pull via git-annex-shell.
2024-06-10 17:53:28 +00:00
|
|
|
let conn = stdioP2PConnection Nothing
|
2018-03-08 18:02:18 +00:00
|
|
|
let server = do
|
|
|
|
P2P.net $ P2P.sendMessage (P2P.AUTH_SUCCESS myuuid)
|
|
|
|
P2P.serveAuthed servermode myuuid
|
2018-03-12 17:43:19 +00:00
|
|
|
runst <- liftIO $ mkRunState $ Serving theiruuid Nothing
|
2024-06-28 17:19:57 +00:00
|
|
|
p2pErrHandler noop (const p2pDone) (runFullProto runst conn server)
|
2024-06-10 22:01:36 +00:00
|
|
|
|
|
|
|
performProxy :: UUID -> P2P.ServerMode -> Remote -> CommandPerform
|
2024-06-27 18:36:55 +00:00
|
|
|
performProxy clientuuid servermode r = do
|
2024-06-17 19:00:11 +00:00
|
|
|
clientside <- proxyClientSide clientuuid
|
2024-06-27 18:36:55 +00:00
|
|
|
getClientProtocolVersion (Remote.uuid r) clientside
|
2024-06-11 14:20:11 +00:00
|
|
|
(withclientversion clientside)
|
2024-06-28 17:19:57 +00:00
|
|
|
(p2pErrHandler noop)
|
2024-06-10 22:01:36 +00:00
|
|
|
where
|
2024-06-17 18:14:08 +00:00
|
|
|
withclientversion clientside (Just (clientmaxversion, othermsg)) = do
|
2024-06-28 15:22:29 +00:00
|
|
|
remoteside <- proxyRemoteSide clientmaxversion mempty r
|
2024-06-17 19:51:10 +00:00
|
|
|
protocolversion <- either (const (min P2P.maxProtocolVersion clientmaxversion)) id
|
|
|
|
<$> runRemoteSide remoteside
|
|
|
|
(P2P.net P2P.getProtocolVersion)
|
2024-06-28 17:19:57 +00:00
|
|
|
concurrencyconfig <- noConcurrencyConfig
|
2024-06-17 19:51:10 +00:00
|
|
|
let closer = do
|
|
|
|
closeRemoteSide remoteside
|
|
|
|
p2pDone
|
2024-06-28 17:19:57 +00:00
|
|
|
let errhandler = p2pErrHandler (closeRemoteSide remoteside)
|
REMOVE-BEFORE and GETTIMESTAMP proxying
For clusters, the timestamps have to be translated, since each node can
have its own idea about what time it is. To translate a timestamp, the
proxy remembers what time it asked the node for a timestamp in
GETTIMESTAMP, and applies the delta as an offset in REMOVE-BEFORE.
This does mean that a remove from a cluster has to call GETTIMESTAMP on
every node before dropping from nodes. Not very efficient. Although
currently it tries to drop from every single node anyway, which is also
not very efficient.
I thought about caching the GETTIMESTAMP from the nodes on the first
call. That would improve efficiency. But, since monotonic clocks on
!Linux don't advance when the computer is suspended, consider what might
happen if one node was suspended for a while, then came back. Its
monotonic timestamp would end up behind where the proxying expects it to
be. Would that result in removing when it shouldn't, or refusing to
remove when it should? Have not thought it through. Either way, a
cluster behaving strangly for an extended period of time because one
of its nodes was briefly asleep doesn't seem like good behavior.
2024-07-04 19:08:33 +00:00
|
|
|
proxystate <- liftIO mkProxyState
|
|
|
|
let runproxy othermsg' = proxy closer
|
|
|
|
proxymethods proxystate
|
2024-06-27 16:20:22 +00:00
|
|
|
servermode clientside
|
2024-06-27 18:36:55 +00:00
|
|
|
(Remote.uuid r)
|
2024-06-17 23:19:15 +00:00
|
|
|
(singleProxySelector remoteside)
|
2024-06-25 18:52:47 +00:00
|
|
|
concurrencyconfig
|
2024-06-28 17:19:57 +00:00
|
|
|
protocolversion othermsg' errhandler
|
2024-06-27 16:20:22 +00:00
|
|
|
sendClientProtocolVersion clientside othermsg protocolversion
|
2024-06-28 17:19:57 +00:00
|
|
|
runproxy errhandler
|
2024-06-17 19:00:11 +00:00
|
|
|
withclientversion _ Nothing = p2pDone
|
2024-06-18 14:36:04 +00:00
|
|
|
|
|
|
|
proxymethods = ProxyMethods
|
|
|
|
{ removedContent = \u k -> logChange k u InfoMissing
|
|
|
|
, addedContent = \u k -> logChange k u InfoPresent
|
|
|
|
}
|
2024-06-12 15:37:14 +00:00
|
|
|
|
2024-06-17 19:00:11 +00:00
|
|
|
performProxyCluster :: UUID -> ClusterUUID -> P2P.ServerMode -> CommandPerform
|
|
|
|
performProxyCluster clientuuid clusteruuid servermode = do
|
|
|
|
clientside <- proxyClientSide clientuuid
|
2024-06-18 14:36:04 +00:00
|
|
|
proxyCluster clusteruuid p2pDone servermode clientside p2pErrHandler
|
2024-06-17 19:51:10 +00:00
|
|
|
|
2024-06-17 19:00:11 +00:00
|
|
|
proxyClientSide :: UUID -> Annex ClientSide
|
|
|
|
proxyClientSide clientuuid = do
|
|
|
|
clientrunst <- liftIO (mkRunState $ Serving clientuuid Nothing)
|
2024-07-01 14:04:45 +00:00
|
|
|
ClientSide clientrunst <$> liftIO (stdioP2PConnectionDupped Nothing)
|
2024-06-10 22:01:36 +00:00
|
|
|
|
2024-06-28 17:19:57 +00:00
|
|
|
p2pErrHandler :: Annex () -> (a -> CommandPerform) -> Annex (Either ProtoFailure a) -> CommandPerform
|
|
|
|
p2pErrHandler closeconn cont a = a >>= \case
|
2024-06-17 19:00:11 +00:00
|
|
|
-- Avoid displaying an error when the client hung up on us.
|
2024-06-28 17:19:57 +00:00
|
|
|
Left (ProtoFailureIOError e) | isEOFError e -> do
|
|
|
|
closeconn
|
|
|
|
p2pDone
|
|
|
|
Left e -> do
|
|
|
|
closeconn
|
|
|
|
giveup (describeProtoFailure e)
|
2024-06-17 19:00:11 +00:00
|
|
|
Right v -> cont v
|
|
|
|
|
|
|
|
p2pDone :: CommandPerform
|
|
|
|
p2pDone = next $ return True
|