webapp automatic grouping
webapp: Adds newly created repositories to one of these groups: clients, drives, servers This is heuristic, but it's a pretty good heuristic, and can always be configured.
This commit is contained in:
parent
8eb1ba4cfe
commit
a5781fd9ba
7 changed files with 73 additions and 43 deletions
|
@ -28,11 +28,12 @@ import qualified Data.Map as M
|
||||||
import Data.Char
|
import Data.Char
|
||||||
|
|
||||||
{- Sets up and begins syncing with a new ssh or rsync remote. -}
|
{- Sets up and begins syncing with a new ssh or rsync remote. -}
|
||||||
makeSshRemote :: ThreadState -> DaemonStatusHandle -> ScanRemoteMap -> Bool -> SshData -> IO ()
|
makeSshRemote :: ThreadState -> DaemonStatusHandle -> ScanRemoteMap -> Bool -> SshData -> IO Remote
|
||||||
makeSshRemote st dstatus scanremotes forcersync sshdata = do
|
makeSshRemote st dstatus scanremotes forcersync sshdata = do
|
||||||
r <- runThreadState st $
|
r <- runThreadState st $
|
||||||
addRemote $ maker (sshRepoName sshdata) sshurl
|
addRemote $ maker (sshRepoName sshdata) sshurl
|
||||||
syncNewRemote st dstatus scanremotes r
|
syncNewRemote st dstatus scanremotes r
|
||||||
|
return r
|
||||||
where
|
where
|
||||||
rsync = forcersync || rsyncOnly sshdata
|
rsync = forcersync || rsyncOnly sshdata
|
||||||
maker
|
maker
|
||||||
|
|
|
@ -46,7 +46,7 @@ finishedPairing st dstatus scanremotes msg keypair = do
|
||||||
, "git-annex-shell -c configlist " ++ T.unpack (sshDirectory sshdata)
|
, "git-annex-shell -c configlist " ++ T.unpack (sshDirectory sshdata)
|
||||||
]
|
]
|
||||||
""
|
""
|
||||||
makeSshRemote st dstatus scanremotes False sshdata
|
void $ makeSshRemote st dstatus scanremotes False sshdata
|
||||||
|
|
||||||
{- Mostly a straightforward conversion. Except:
|
{- Mostly a straightforward conversion. Except:
|
||||||
- * Determine the best hostname to use to contact the host.
|
- * Determine the best hostname to use to contact the host.
|
||||||
|
|
|
@ -28,10 +28,13 @@ import Utility.DiskFree
|
||||||
import Utility.DataUnits
|
import Utility.DataUnits
|
||||||
import Utility.Network
|
import Utility.Network
|
||||||
import Remote (prettyListUUIDs)
|
import Remote (prettyListUUIDs)
|
||||||
|
import Logs.Group
|
||||||
|
import Annex.UUID
|
||||||
|
|
||||||
import Yesod
|
import Yesod
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
|
import qualified Data.Set as S
|
||||||
import Data.Char
|
import Data.Char
|
||||||
import System.Posix.Directory
|
import System.Posix.Directory
|
||||||
import qualified Control.Exception as E
|
import qualified Control.Exception as E
|
||||||
|
@ -142,10 +145,10 @@ getNewRepositoryR = bootstrap (Just Config) $ do
|
||||||
case res of
|
case res of
|
||||||
FormSuccess (RepositoryPath p) -> lift $ do
|
FormSuccess (RepositoryPath p) -> lift $ do
|
||||||
let path = T.unpack p
|
let path = T.unpack p
|
||||||
liftIO $ do
|
liftIO $ makeRepo path False
|
||||||
makeRepo path False
|
u <- liftIO $ initRepo path Nothing
|
||||||
initRepo path Nothing
|
runAnnex () $ groupSet u (S.singleton "clients")
|
||||||
addAutoStart path
|
liftIO $ addAutoStart path
|
||||||
redirect $ SwitchToRepositoryR path
|
redirect $ SwitchToRepositoryR path
|
||||||
_ -> $(widgetFile "configurators/newrepository")
|
_ -> $(widgetFile "configurators/newrepository")
|
||||||
|
|
||||||
|
@ -191,8 +194,9 @@ getAddDriveR = bootstrap (Just Config) $ do
|
||||||
where
|
where
|
||||||
go mountpoint = do
|
go mountpoint = do
|
||||||
liftIO $ makerepo dir
|
liftIO $ makerepo dir
|
||||||
liftIO $ initRepo dir $ Just remotename
|
u <- liftIO $ initRepo dir $ Just remotename
|
||||||
r <- addremote dir remotename
|
r <- addremote dir remotename
|
||||||
|
runAnnex () $ groupSet u (S.singleton "drives")
|
||||||
syncRemote r
|
syncRemote r
|
||||||
where
|
where
|
||||||
dir = mountpoint </> gitAnnexAssistantDefaultDir
|
dir = mountpoint </> gitAnnexAssistantDefaultDir
|
||||||
|
@ -260,9 +264,10 @@ driveList = mapM (gen . mnt_dir) =<< filter sane <$> getMounts
|
||||||
startFullAssistant :: FilePath -> Handler ()
|
startFullAssistant :: FilePath -> Handler ()
|
||||||
startFullAssistant path = do
|
startFullAssistant path = do
|
||||||
webapp <- getYesod
|
webapp <- getYesod
|
||||||
|
liftIO $ makeRepo path False
|
||||||
|
u <- liftIO $ initRepo path Nothing
|
||||||
|
runAnnex () $ groupSet u (S.singleton "clients")
|
||||||
url <- liftIO $ do
|
url <- liftIO $ do
|
||||||
makeRepo path False
|
|
||||||
initRepo path Nothing
|
|
||||||
addAutoStart path
|
addAutoStart path
|
||||||
changeWorkingDirectory path
|
changeWorkingDirectory path
|
||||||
fromJust $ postFirstRun webapp
|
fromJust $ postFirstRun webapp
|
||||||
|
@ -286,10 +291,11 @@ inDir dir a = do
|
||||||
Annex.eval state a
|
Annex.eval state a
|
||||||
|
|
||||||
{- Initializes a git-annex repository in a directory with a description. -}
|
{- Initializes a git-annex repository in a directory with a description. -}
|
||||||
initRepo :: FilePath -> Maybe String -> IO ()
|
initRepo :: FilePath -> Maybe String -> IO UUID
|
||||||
initRepo dir desc = inDir dir $
|
initRepo dir desc = inDir dir $ do
|
||||||
unlessM isInitialized $
|
unlessM isInitialized $
|
||||||
initialize desc
|
initialize desc
|
||||||
|
getUUID
|
||||||
|
|
||||||
{- Adds a directory to the autostart file. -}
|
{- Adds a directory to the autostart file. -}
|
||||||
addAutoStart :: FilePath -> IO ()
|
addAutoStart :: FilePath -> IO ()
|
||||||
|
|
|
@ -19,12 +19,14 @@ import Assistant.ThreadedMonad
|
||||||
import Utility.Yesod
|
import Utility.Yesod
|
||||||
import qualified Remote.S3 as S3
|
import qualified Remote.S3 as S3
|
||||||
import Logs.Remote
|
import Logs.Remote
|
||||||
import Remote (prettyListUUIDs)
|
import qualified Remote
|
||||||
import Types.Remote (RemoteConfig)
|
import Types.Remote (RemoteConfig)
|
||||||
|
import Logs.Group
|
||||||
|
|
||||||
import Yesod
|
import Yesod
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
|
import qualified Data.Set as S
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
|
|
||||||
s3Configurator :: Widget -> Handler RepHtml
|
s3Configurator :: Widget -> Handler RepHtml
|
||||||
|
@ -80,7 +82,7 @@ getAddS3R = s3Configurator $ do
|
||||||
case result of
|
case result of
|
||||||
FormSuccess s3input -> lift $ do
|
FormSuccess s3input -> lift $ do
|
||||||
let name = T.unpack $ repoName s3input
|
let name = T.unpack $ repoName s3input
|
||||||
makeS3Remote (extractCreds s3input) name $ M.fromList
|
makeS3Remote (extractCreds s3input) name setgroup $ M.fromList
|
||||||
[ ("encryption", "shared")
|
[ ("encryption", "shared")
|
||||||
, ("type", "S3")
|
, ("type", "S3")
|
||||||
, ("datacenter", T.unpack $ datacenter s3input)
|
, ("datacenter", T.unpack $ datacenter s3input)
|
||||||
|
@ -91,6 +93,8 @@ getAddS3R = s3Configurator $ do
|
||||||
showform form enctype = do
|
showform form enctype = do
|
||||||
let authtoken = webAppFormAuthToken
|
let authtoken = webAppFormAuthToken
|
||||||
$(widgetFile "configurators/adds3")
|
$(widgetFile "configurators/adds3")
|
||||||
|
setgroup r = runAnnex () $
|
||||||
|
groupSet (Remote.uuid r) (S.singleton "servers")
|
||||||
|
|
||||||
getEnableS3R :: UUID -> Handler RepHtml
|
getEnableS3R :: UUID -> Handler RepHtml
|
||||||
getEnableS3R uuid = s3Configurator $ do
|
getEnableS3R uuid = s3Configurator $ do
|
||||||
|
@ -101,24 +105,24 @@ getEnableS3R uuid = s3Configurator $ do
|
||||||
m <- runAnnex M.empty readRemoteLog
|
m <- runAnnex M.empty readRemoteLog
|
||||||
let name = fromJust $ M.lookup "name" $
|
let name = fromJust $ M.lookup "name" $
|
||||||
fromJust $ M.lookup uuid m
|
fromJust $ M.lookup uuid m
|
||||||
makeS3Remote s3creds name M.empty
|
makeS3Remote s3creds name (const noop) M.empty
|
||||||
_ -> showform form enctype
|
_ -> showform form enctype
|
||||||
where
|
where
|
||||||
showform form enctype = do
|
showform form enctype = do
|
||||||
let authtoken = webAppFormAuthToken
|
let authtoken = webAppFormAuthToken
|
||||||
description <- lift $ runAnnex "" $
|
description <- lift $ runAnnex "" $
|
||||||
T.pack . concat <$> prettyListUUIDs [uuid]
|
T.pack . concat <$> Remote.prettyListUUIDs [uuid]
|
||||||
$(widgetFile "configurators/enables3")
|
$(widgetFile "configurators/enables3")
|
||||||
|
|
||||||
makeS3Remote :: S3Creds -> String -> RemoteConfig -> Handler ()
|
makeS3Remote :: S3Creds -> String -> (Remote -> Handler ()) -> RemoteConfig -> Handler ()
|
||||||
makeS3Remote (S3Creds ak sk) name config = do
|
makeS3Remote (S3Creds ak sk) name setup config = do
|
||||||
webapp <- getYesod
|
webapp <- getYesod
|
||||||
let st = fromJust $ threadState webapp
|
let st = fromJust $ threadState webapp
|
||||||
remotename <- runAnnex name $ fromRepo $ uniqueRemoteName name 0
|
remotename <- runAnnex name $ fromRepo $ uniqueRemoteName name 0
|
||||||
liftIO $ do
|
liftIO $ S3.s3SetCredsEnv ( T.unpack ak, T.unpack sk)
|
||||||
S3.s3SetCredsEnv ( T.unpack ak, T.unpack sk)
|
r <- liftIO $ runThreadState st $ addRemote $ do
|
||||||
r <- runThreadState st $ addRemote $ do
|
makeSpecialRemote name S3.remote config
|
||||||
makeSpecialRemote name S3.remote config
|
return remotename
|
||||||
return remotename
|
setup r
|
||||||
syncNewRemote st (daemonStatus webapp) (scanRemotes webapp) r
|
liftIO $ syncNewRemote st (daemonStatus webapp) (scanRemotes webapp) r
|
||||||
redirect RepositoriesR
|
redirect RepositoriesR
|
||||||
|
|
|
@ -19,11 +19,13 @@ import Utility.Yesod
|
||||||
import Utility.Rsync (rsyncUrlIsShell)
|
import Utility.Rsync (rsyncUrlIsShell)
|
||||||
import Logs.Remote
|
import Logs.Remote
|
||||||
import Remote
|
import Remote
|
||||||
|
import Logs.Group
|
||||||
|
|
||||||
import Yesod
|
import Yesod
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
|
import qualified Data.Set as S
|
||||||
import Network.Socket
|
import Network.Socket
|
||||||
import System.Posix.User
|
import System.Posix.User
|
||||||
|
|
||||||
|
@ -130,7 +132,7 @@ getEnableRsyncR u = do
|
||||||
case result of
|
case result of
|
||||||
FormSuccess sshinput'
|
FormSuccess sshinput'
|
||||||
| isRsyncNet (hostname sshinput') ->
|
| isRsyncNet (hostname sshinput') ->
|
||||||
void $ lift $ makeRsyncNet sshinput'
|
void $ lift $ makeRsyncNet sshinput' (const noop)
|
||||||
| otherwise -> do
|
| otherwise -> do
|
||||||
s <- liftIO $ testServer sshinput'
|
s <- liftIO $ testServer sshinput'
|
||||||
case s of
|
case s of
|
||||||
|
@ -250,23 +252,23 @@ getConfirmSshR sshdata = sshConfigurator $ do
|
||||||
$(widgetFile "configurators/ssh/confirm")
|
$(widgetFile "configurators/ssh/confirm")
|
||||||
|
|
||||||
getMakeSshGitR :: SshData -> Handler RepHtml
|
getMakeSshGitR :: SshData -> Handler RepHtml
|
||||||
getMakeSshGitR = makeSsh False
|
getMakeSshGitR = makeSsh False setupGroup
|
||||||
|
|
||||||
getMakeSshRsyncR :: SshData -> Handler RepHtml
|
getMakeSshRsyncR :: SshData -> Handler RepHtml
|
||||||
getMakeSshRsyncR = makeSsh True
|
getMakeSshRsyncR = makeSsh True setupGroup
|
||||||
|
|
||||||
makeSsh :: Bool -> SshData -> Handler RepHtml
|
makeSsh :: Bool -> (Remote -> Handler ()) -> SshData -> Handler RepHtml
|
||||||
makeSsh rsync sshdata
|
makeSsh rsync setup sshdata
|
||||||
| needsPubKey sshdata = do
|
| needsPubKey sshdata = do
|
||||||
keypair <- liftIO genSshKeyPair
|
keypair <- liftIO genSshKeyPair
|
||||||
sshdata' <- liftIO $ setupSshKeyPair keypair sshdata
|
sshdata' <- liftIO $ setupSshKeyPair keypair sshdata
|
||||||
makeSsh' rsync sshdata' (Just keypair)
|
makeSsh' rsync setup sshdata' (Just keypair)
|
||||||
| otherwise = makeSsh' rsync sshdata Nothing
|
| otherwise = makeSsh' rsync setup sshdata Nothing
|
||||||
|
|
||||||
makeSsh' :: Bool -> SshData -> Maybe SshKeyPair -> Handler RepHtml
|
makeSsh' :: Bool -> (Remote -> Handler ()) -> SshData -> Maybe SshKeyPair -> Handler RepHtml
|
||||||
makeSsh' rsync sshdata keypair =
|
makeSsh' rsync setup sshdata keypair =
|
||||||
sshSetup [sshhost, remoteCommand] "" $
|
sshSetup [sshhost, remoteCommand] "" $
|
||||||
makeSshRepo rsync sshdata
|
makeSshRepo rsync setup sshdata
|
||||||
where
|
where
|
||||||
sshhost = genSshHost (sshHostName sshdata) (sshUserName sshdata)
|
sshhost = genSshHost (sshHostName sshdata) (sshUserName sshdata)
|
||||||
remotedir = T.unpack $ sshDirectory sshdata
|
remotedir = T.unpack $ sshDirectory sshdata
|
||||||
|
@ -280,14 +282,15 @@ makeSsh' rsync sshdata keypair =
|
||||||
else Nothing
|
else Nothing
|
||||||
]
|
]
|
||||||
|
|
||||||
makeSshRepo :: Bool -> SshData -> Handler RepHtml
|
makeSshRepo :: Bool -> (Remote -> Handler ()) -> SshData -> Handler RepHtml
|
||||||
makeSshRepo forcersync sshdata = do
|
makeSshRepo forcersync setup sshdata = do
|
||||||
webapp <- getYesod
|
webapp <- getYesod
|
||||||
liftIO $ makeSshRemote
|
r <- liftIO $ makeSshRemote
|
||||||
(fromJust $ threadState webapp)
|
(fromJust $ threadState webapp)
|
||||||
(daemonStatus webapp)
|
(daemonStatus webapp)
|
||||||
(scanRemotes webapp)
|
(scanRemotes webapp)
|
||||||
forcersync sshdata
|
forcersync sshdata
|
||||||
|
setup r
|
||||||
redirect RepositoriesR
|
redirect RepositoriesR
|
||||||
|
|
||||||
getAddRsyncNetR :: Handler RepHtml
|
getAddRsyncNetR :: Handler RepHtml
|
||||||
|
@ -303,14 +306,14 @@ getAddRsyncNetR = do
|
||||||
case result of
|
case result of
|
||||||
FormSuccess sshinput
|
FormSuccess sshinput
|
||||||
| isRsyncNet (hostname sshinput) ->
|
| isRsyncNet (hostname sshinput) ->
|
||||||
makeRsyncNet sshinput
|
makeRsyncNet sshinput setupGroup
|
||||||
| otherwise ->
|
| otherwise ->
|
||||||
showform $ UnusableServer
|
showform $ UnusableServer
|
||||||
"That is not a rsync.net host name."
|
"That is not a rsync.net host name."
|
||||||
_ -> showform UntestedServer
|
_ -> showform UntestedServer
|
||||||
|
|
||||||
makeRsyncNet :: SshInput -> Handler RepHtml
|
makeRsyncNet :: SshInput -> (Remote -> Handler ()) -> Handler RepHtml
|
||||||
makeRsyncNet sshinput = do
|
makeRsyncNet sshinput setup = do
|
||||||
knownhost <- liftIO $ maybe (return False) knownHost (hostname sshinput)
|
knownhost <- liftIO $ maybe (return False) knownHost (hostname sshinput)
|
||||||
keypair <- liftIO $ genSshKeyPair
|
keypair <- liftIO $ genSshKeyPair
|
||||||
sshdata <- liftIO $ setupSshKeyPair keypair $
|
sshdata <- liftIO $ setupSshKeyPair keypair $
|
||||||
|
@ -338,8 +341,11 @@ makeRsyncNet sshinput = do
|
||||||
, remotecommand
|
, remotecommand
|
||||||
]
|
]
|
||||||
sshSetup sshopts (sshPubKey keypair) $
|
sshSetup sshopts (sshPubKey keypair) $
|
||||||
makeSshRepo True sshdata
|
makeSshRepo True setup sshdata
|
||||||
|
|
||||||
isRsyncNet :: Maybe Text -> Bool
|
isRsyncNet :: Maybe Text -> Bool
|
||||||
isRsyncNet Nothing = False
|
isRsyncNet Nothing = False
|
||||||
isRsyncNet (Just host) = ".rsync.net" `T.isSuffixOf` T.toLower host
|
isRsyncNet (Just host) = ".rsync.net" `T.isSuffixOf` T.toLower host
|
||||||
|
|
||||||
|
setupGroup :: Remote -> Handler ()
|
||||||
|
setupGroup r = runAnnex () $ groupSet (Remote.uuid r) (S.singleton "server")
|
||||||
|
|
4
debian/changelog
vendored
4
debian/changelog
vendored
|
@ -1,10 +1,12 @@
|
||||||
git-annex (3.20121002) UNRELEASED; urgency=low
|
git-annex (3.20121002) UNRELEASED; urgency=low
|
||||||
|
|
||||||
* group, ungroup: New commands to indicate groups of repositories.
|
|
||||||
* watch, assistant: It's now safe to git annex unlock files while
|
* watch, assistant: It's now safe to git annex unlock files while
|
||||||
the watcher is running, as well as modify files checked into git
|
the watcher is running, as well as modify files checked into git
|
||||||
as normal files. Additionally, .gitignore settings are now honored.
|
as normal files. Additionally, .gitignore settings are now honored.
|
||||||
Closes: #689979
|
Closes: #689979
|
||||||
|
* group, ungroup: New commands to indicate groups of repositories.
|
||||||
|
* webapp: Adds newly created repositories to one of these groups:
|
||||||
|
clients, drives, servers
|
||||||
* vicfg: New command, allows editing (or simply viewing) most
|
* vicfg: New command, allows editing (or simply viewing) most
|
||||||
of the repository configuration settings stored in the git-annex branch.
|
of the repository configuration settings stored in the git-annex branch.
|
||||||
* Added preferred content expressions, configurable using vicfg.
|
* Added preferred content expressions, configurable using vicfg.
|
||||||
|
|
|
@ -6,8 +6,19 @@ it doesn't currently have, is covered by the [[partial_content]] page.
|
||||||
|
|
||||||
But often the remote is just a removable drive or a cloud remote,
|
But often the remote is just a removable drive or a cloud remote,
|
||||||
that has a limited size. This page is about making the assistant do
|
that has a limited size. This page is about making the assistant do
|
||||||
something smart with such remotes. (Which it now does.. **done** except for
|
something smart with such remotes.
|
||||||
an easy way to configure this.)
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
* easy configuration of preferred content
|
||||||
|
* Drop no longer preferred content.
|
||||||
|
- When a file is renamed, it might stop being preferred, so
|
||||||
|
could be checked and dropped. (If there's multiple links to
|
||||||
|
the same content, this gets tricky.)
|
||||||
|
- When a file is sent or received, the sender's preferred content
|
||||||
|
settings may change, causing it to be dropped from the sender.
|
||||||
|
- May also want to check for things to drop, from both local and remotes,
|
||||||
|
when doing the expensive trasfer scan.
|
||||||
|
|
||||||
## specifying what data a remote prefers to contain **done**
|
## specifying what data a remote prefers to contain **done**
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue