diff options
author | Joey Hess <joey@kitenet.net> | 2012-11-20 16:43:58 -0400 |
---|---|---|
committer | Joey Hess <joey@kitenet.net> | 2012-11-20 16:43:58 -0400 |
commit | 0d378285e709833f87547fd6fedc4e8b2f4884c4 (patch) | |
tree | 6caa2c4ba7710c917751d26c5bf58cce2a1163e2 | |
parent | cba848b472a4ac323693b44fcef9ddbbe535c929 (diff) |
Amazon Glacier special remote; 100% working
-rw-r--r-- | Creds.hs | 20 | ||||
-rw-r--r-- | GitAnnex.hs | 1 | ||||
-rw-r--r-- | Remote/Glacier.hs | 235 | ||||
-rw-r--r-- | Remote/Helper/AWS.hs | 21 | ||||
-rw-r--r-- | Remote/List.hs | 2 | ||||
-rw-r--r-- | Remote/S3.hs | 24 | ||||
-rw-r--r-- | Remote/WebDAV.hs | 8 | ||||
-rw-r--r-- | debian/changelog | 2 | ||||
-rw-r--r-- | doc/design/assistant/cloud.mdwn | 2 | ||||
-rw-r--r-- | doc/git-annex.mdwn | 16 | ||||
-rw-r--r-- | doc/special_remotes.mdwn | 1 | ||||
-rw-r--r-- | doc/special_remotes/glacier.mdwn | 51 | ||||
-rw-r--r-- | doc/tips/using_Amazon_Glacier.mdwn | 69 | ||||
-rw-r--r-- | doc/tips/using_Amazon_S3.mdwn | 2 | ||||
-rw-r--r-- | doc/todo/special_remote_for_amazon_glacier.mdwn | 5 |
15 files changed, 427 insertions, 32 deletions
@@ -34,7 +34,7 @@ data CredPairStorage = CredPairStorage {- Stores creds in a remote's configuration, if the remote allows - that. Otherwise, caches them locally. -} setRemoteCredPair :: RemoteConfig -> CredPairStorage -> Annex RemoteConfig -setRemoteCredPair c storage = go =<< getRemoteCredPair c storage +setRemoteCredPair c storage = go =<< getRemoteCredPair' c storage where go (Just creds) | embedCreds c = case credPairRemoteKey storage of @@ -58,8 +58,20 @@ setRemoteCredPair c storage = go =<< getRemoteCredPair c storage {- Gets a remote's credpair, from the environment if set, otherwise - from the cache in gitAnnexCredsDir, or failing that, from the - value in RemoteConfig. -} -getRemoteCredPair :: RemoteConfig -> CredPairStorage -> Annex (Maybe CredPair) -getRemoteCredPair c storage = maybe fromcache (return . Just) =<< fromenv +getRemoteCredPair :: String -> RemoteConfig -> CredPairStorage -> Annex (Maybe CredPair) +getRemoteCredPair this c storage = maybe missing (return . Just) =<< getRemoteCredPair' c storage + where + (loginvar, passwordvar) = credPairEnvironment storage + missing = do + warning $ unwords + [ "Set both", loginvar + , "and", passwordvar + , "to use", this + ] + return Nothing + +getRemoteCredPair' :: RemoteConfig -> CredPairStorage -> Annex (Maybe CredPair) +getRemoteCredPair' c storage = maybe fromcache (return . Just) =<< fromenv where fromenv = liftIO $ getEnvCredPair storage fromcache = maybe fromconfig (return . Just) =<< readCacheCredPair storage @@ -91,6 +103,8 @@ getEnvCredPair storage = liftM2 (,) (uenv, penv) = credPairEnvironment storage get = catchMaybeIO . getEnv + + {- Stores a CredPair in the environment. -} setEnvCredPair :: CredPair -> CredPairStorage -> IO () setEnvCredPair (l, p) storage = do diff --git a/GitAnnex.hs b/GitAnnex.hs index 81667ee76..57f3b9898 100644 --- a/GitAnnex.hs +++ b/GitAnnex.hs @@ -163,6 +163,7 @@ options = Option.common ++ "skip files smaller than a size" , Option ['T'] ["time-limit"] (ReqArg Limit.addTimeLimit paramTime) "stop after the specified amount of time" + , Option [] ["trust-glacier"] (NoArg (Annex.setFlag "trustglacier")) "Trust Amazon Glacier inventory" ] ++ Option.matcher where setnumcopies v = Annex.changeState $ diff --git a/Remote/Glacier.hs b/Remote/Glacier.hs new file mode 100644 index 000000000..fb5ff8e6a --- /dev/null +++ b/Remote/Glacier.hs @@ -0,0 +1,235 @@ +{- Amazon Glacier remotes. + - + - Copyright 2012 Joey Hess <joey@kitenet.net> + - + - Licensed under the GNU GPL version 3 or higher. + -} + +module Remote.Glacier (remote) where + +import qualified Data.ByteString.Lazy.Char8 as L +import qualified Data.Map as M +import System.Environment + +import Common.Annex +import Types.Remote +import Types.Key +import qualified Git +import Config +import Remote.Helper.Special +import Remote.Helper.Encryptable +import qualified Remote.Helper.AWS as AWS +import Crypto +import Creds +import Annex.Content +import qualified Annex + +type Vault = String +type Archive = FilePath + +remote :: RemoteType +remote = RemoteType { + typename = "glacier", + enumerate = findSpecialRemotes "glacier", + generate = gen, + setup = glacierSetup +} + +gen :: Git.Repo -> UUID -> Maybe RemoteConfig -> Annex Remote +gen r u c = do + cst <- remoteCost r expensiveRemoteCost + return $ gen' r u c cst +gen' :: Git.Repo -> UUID -> Maybe RemoteConfig -> Int -> Remote +gen' r u c cst = + encryptableRemote c + (storeEncrypted this) + (retrieveEncrypted this) + this + where + this = Remote { + uuid = u, + cost = cst, + name = Git.repoDescribe r, + storeKey = store this, + retrieveKeyFile = retrieve this, + retrieveKeyFileCheap = retrieveCheap this, + removeKey = remove this, + hasKey = checkPresent this, + hasKeyCheap = False, + whereisKey = Nothing, + config = c, + repo = r, + localpath = Nothing, + readonly = False, + remotetype = remote + } + +glacierSetup :: UUID -> RemoteConfig -> Annex RemoteConfig +glacierSetup u c = do + c' <- encryptionSetup c + let fullconfig = c' `M.union` defaults + genVault fullconfig u + gitConfigSpecialRemote u fullconfig "glacier" "true" + setRemoteCredPair fullconfig (AWS.creds u) + where + remotename = fromJust (M.lookup "name" c) + defvault = remotename ++ "-" ++ fromUUID u + defaults = M.fromList + [ ("datacenter", "us-east-1") + , ("vault", defvault) + ] + +store :: Remote -> Key -> AssociatedFile -> MeterUpdate -> Annex Bool +store r k _f _p + | keySize k == Just 0 = do + warning "Cannot store empty files in Glacier." + return False + | otherwise = do + src <- inRepo $ gitAnnexLocation k + storeHelper r k src + +storeEncrypted :: Remote -> (Cipher, Key) -> Key -> MeterUpdate -> Annex Bool +storeEncrypted r (cipher, enck) k _p = + -- With current glacier-cli UI, have to encrypt to a temp file. + withTmp enck $ \tmp -> do + f <- inRepo $ gitAnnexLocation k + liftIO $ encrypt cipher (feedFile f) $ + readBytes $ L.writeFile tmp + storeHelper r enck tmp + +{- Glacier cannot store empty files. So empty keys are handled by + - doing nothing on storage, and re-creating the empty file on retrieve. -} +storeHelper :: Remote -> Key -> FilePath -> Annex Bool +storeHelper r k file = do + showOutput + glacierAction r + [ Param "archive" + , Param "upload" + , Param "--name", Param $ archive r k + , Param $ remoteVault r + , File file + ] + +retrieve :: Remote -> Key -> AssociatedFile -> FilePath -> Annex Bool +retrieve r k _f d = retrieveHelper r k d + +retrieveCheap :: Remote -> Key -> FilePath -> Annex Bool +retrieveCheap _ _ _ = return False + +retrieveEncrypted :: Remote -> (Cipher, Key) -> Key -> FilePath -> Annex Bool +retrieveEncrypted r (cipher, enck) _k d = do + withTmp enck $ \tmp -> do + ok <- retrieveHelper r enck tmp + if ok + then liftIO $ decrypt cipher (feedFile tmp) $ + readBytes $ \content -> do + L.writeFile d content + return True + else return False + +retrieveHelper :: Remote -> Key -> FilePath -> Annex Bool +retrieveHelper r k file = do + showOutput + ok <- glacierAction r + [ Param "archive" + , Param "retrieve" + , Param "-o", File file + , Param $ remoteVault r + , Param $ archive r k + ] + unless ok $ + showLongNote "Recommend you wait up to 4 hours, and then run this command again." + return ok + +remove :: Remote -> Key -> Annex Bool +remove r k = glacierAction r + [ Param "archive" + , Param "delete" + , Param $ remoteVault r + , Param $ archive r k + ] + +checkPresent :: Remote -> Key -> Annex (Either String Bool) +checkPresent r k = do + showAction $ "checking " ++ name r + go =<< glacierEnv (fromJust $ config r) (uuid r) + where + go Nothing = return $ Left "cannot check glacier" + go (Just env) = do + {- glacier checkpresent outputs the archive name to stdout if + - it's present. -} + v <- liftIO $ catchMsgIO $ + readProcessEnv "glacier" (toCommand params) (Just env) + case v of + Right s -> do + let probablypresent = key2file k `elem` lines s + if probablypresent + then ifM (Annex.getFlag "trustglacier") + ( return $ Right True, untrusted ) + else return $ Right False + Left e -> return $ Left e + + params = + [ Param "archive" + , Param "checkpresent" + , Param $ remoteVault r + , Param $ archive r k + ] + + untrusted = do + showLongNote $ unlines + [ "Glacier's inventory says it has a copy." + , "However, the inventory could be out of date, if it was recently removed." + , "(Use --trust-glacier if you're sure it's still in Glacier.)" + , "" + ] + return $ Right False + +glacierAction :: Remote -> [CommandParam] -> Annex Bool +glacierAction r params = do + when (isNothing $ config r) $ + error $ "Missing configuration for special remote " ++ name r + runGlacier (fromJust $ config r) (uuid r) params + +runGlacier :: RemoteConfig -> UUID -> [CommandParam] -> Annex Bool +runGlacier c u params = go =<< glacierEnv c u + where + go Nothing = return False + go (Just env) = liftIO $ + boolSystemEnv "glacier" (datacenter:params) (Just env) + + datacenter = Param $ "--region=" ++ + (fromJust $ M.lookup "datacenter" c) + +glacierEnv :: RemoteConfig -> UUID -> Annex (Maybe [(String, String)]) +glacierEnv c u = go =<< getRemoteCredPair "glacier" c creds + where + go Nothing = return Nothing + go (Just (user, pass)) = do + env <- liftIO getEnvironment + return $ Just $ (uk, user):(pk, pass):env + + creds = AWS.creds u + (uk, pk) = credPairEnvironment creds + +remoteVault :: Remote -> Vault +remoteVault = vault . fromJust . config + +vault :: RemoteConfig -> Vault +vault = fromJust . M.lookup "vault" + +archive :: Remote -> Key -> Archive +archive r k = fileprefix ++ key2file k + where + fileprefix = M.findWithDefault "" "fileprefix" $ fromJust $ config r + +-- glacier vault create will succeed even if the vault already exists. +genVault :: RemoteConfig -> UUID -> Annex () +genVault c u = unlessM (runGlacier c u params) $ + error "Failed creating glacier vault." + where + params = + [ Param "vault" + , Param "create" + , Param $ vault c + ] diff --git a/Remote/Helper/AWS.hs b/Remote/Helper/AWS.hs new file mode 100644 index 000000000..a988a0b15 --- /dev/null +++ b/Remote/Helper/AWS.hs @@ -0,0 +1,21 @@ +{- Amazon Web Services common infrastructure. + - + - Copyright 2011,2012 Joey Hess <joey@kitenet.net> + - + - Licensed under the GNU GPL version 3 or higher. + -} + +module Remote.Helper.AWS where + +import Common.Annex +import Creds + +creds :: UUID -> CredPairStorage +creds u = CredPairStorage + { credPairFile = fromUUID u + , credPairEnvironment = ("AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY") + , credPairRemoteKey = Just "s3creds" + } + +setCredsEnv :: CredPair -> IO () +setCredsEnv p = setEnvCredPair p $ creds undefined diff --git a/Remote/List.hs b/Remote/List.hs index a25533bb1..3179456eb 100644 --- a/Remote/List.hs +++ b/Remote/List.hs @@ -32,6 +32,7 @@ import qualified Remote.Web #ifdef WITH_WEBDAV import qualified Remote.WebDAV #endif +import qualified Remote.Glacier import qualified Remote.Hook remoteTypes :: [RemoteType] @@ -47,6 +48,7 @@ remoteTypes = #ifdef WITH_WEBDAV , Remote.WebDAV.remote #endif + , Remote.Glacier.remote , Remote.Hook.remote ] diff --git a/Remote/S3.hs b/Remote/S3.hs index ca4161c15..400f3e027 100644 --- a/Remote/S3.hs +++ b/Remote/S3.hs @@ -5,7 +5,7 @@ - Licensed under the GNU GPL version 3 or higher. -} -module Remote.S3 (remote, setCredsEnv) where +module Remote.S3 (remote) where import Network.AWS.AWSConnection import Network.AWS.S3Object @@ -22,6 +22,7 @@ import qualified Git import Config import Remote.Helper.Special import Remote.Helper.Encryptable +import qualified Remote.Helper.AWS as AWS import Crypto import Creds import Meters @@ -84,7 +85,7 @@ s3Setup u c = handlehost $ M.lookup "host" c use fullconfig = do gitConfigSpecialRemote u fullconfig "s3" "true" - setRemoteCredPair fullconfig (s3Creds u) + setRemoteCredPair fullconfig (AWS.creds u) defaulthost = do c' <- encryptionSetup c @@ -261,28 +262,13 @@ s3ConnectionRequired c u = maybe (error "Cannot connect to S3") return =<< s3Connection c u s3Connection :: RemoteConfig -> UUID -> Annex (Maybe AWSConnection) -s3Connection c u = go =<< getRemoteCredPair c creds +s3Connection c u = go =<< getRemoteCredPair "S3" c (AWS.creds u) where - go Nothing = do - warning $ "Set both " ++ s3AccessKey ++ " and " ++ s3SecretKey ++ " to use S3" - return Nothing + go Nothing = return Nothing go (Just (ak, sk)) = return $ Just $ AWSConnection host port ak sk - creds = s3Creds u - (s3AccessKey, s3SecretKey) = credPairEnvironment creds - host = fromJust $ M.lookup "host" c port = let s = fromJust $ M.lookup "port" c in case reads s of [(p, _)] -> p _ -> error $ "bad S3 port value: " ++ s - -s3Creds :: UUID -> CredPairStorage -s3Creds u = CredPairStorage - { credPairFile = fromUUID u - , credPairEnvironment = ("AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY") - , credPairRemoteKey = Just "s3creds" - } - -setCredsEnv :: (String, String) -> IO () -setCredsEnv creds = setEnvCredPair creds $ s3Creds undefined diff --git a/Remote/WebDAV.hs b/Remote/WebDAV.hs index 84f675bbd..b303dbe59 100644 --- a/Remote/WebDAV.hs +++ b/Remote/WebDAV.hs @@ -321,13 +321,7 @@ noProps :: XML.Document noProps = XML.parseText_ XML.def $ LT.pack "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<propertyupdate/>" getCreds :: RemoteConfig -> UUID -> Annex (Maybe CredPair) -getCreds c u = maybe missing (return . Just) =<< getRemoteCredPair c creds - where - creds = davCreds u - (loginvar, passwordvar) = credPairEnvironment creds - missing = do - warning $ "Set both " ++ loginvar ++ " and " ++ passwordvar ++ " to use webdav" - return Nothing +getCreds c u = getRemoteCredPair "webdav" c (davCreds u) davCreds :: UUID -> CredPairStorage davCreds u = CredPairStorage diff --git a/debian/changelog b/debian/changelog index ba8556767..44fd9cf16 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,6 @@ git-annex (3.20121113) UNRELEASED; urgency=low - * New webdav special remotes. + * New webdav and Amazon glacier special remotes. * Show error message to user when testing XMPP creds. * Fix build of assistant without yesod. * webapp: The list of repositiories refreshes when new repositories are diff --git a/doc/design/assistant/cloud.mdwn b/doc/design/assistant/cloud.mdwn index 8df7ac753..3f5524cb1 100644 --- a/doc/design/assistant/cloud.mdwn +++ b/doc/design/assistant/cloud.mdwn @@ -15,7 +15,7 @@ More should be added, such as: * Box.com (it's free, and current method is hard to set up and a sorta shakey; a better method would be to use its API) **done** * Dropbox? That would be ironic.. Via its API, presumably. -* [[Amazon Glacier|todo/special_remote_for_amazon_glacier]] +* [[Amazon Glacier|todo/special_remote_for_amazon_glacier]] **done** * [nimbus.io](https://nimbus.io/) Fairly low prices ($0.06/GB); REST API; free software diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn index c4ba9917b..7646e4392 100644 --- a/doc/git-annex.mdwn +++ b/doc/git-annex.mdwn @@ -568,6 +568,17 @@ subdirectories). The repository should be specified using the name of a configured remote, or the UUID or description of a repository. +* --trust-glacier-inventory + + Amazon Glacier inventories take hours to retrieve, and may not represent + the current state of a repository. So git-annex does not trust that + files that the inventory claims are in Glacier are really there. + This switch can be used to allow it to trust the inventory. + + Be careful using this, especially if you or someone else might have recently + removed a file from Glacier. If you try to drop the only other copy of the + file, and this switch is enabled, you could lose data! + * --backend=name Specifies which key-value backend to use. This can be used when @@ -885,6 +896,11 @@ Here are all the supported configuration settings. Used to identify Amazon S3 special remotes. Normally this is automatically set up by `git annex initremote`. +* `remote.<name>.glacier` + + Used to identify Amazon Glacier special remotes. + Normally this is automatically set up by `git annex initremote`. + * `remote.<name>.webdav` Used to identify webdav special remotes. diff --git a/doc/special_remotes.mdwn b/doc/special_remotes.mdwn index 65fcb8768..b6d6be5bb 100644 --- a/doc/special_remotes.mdwn +++ b/doc/special_remotes.mdwn @@ -19,6 +19,7 @@ into many cloud services. Here are specific instructions for various cloud things: * [[tips/using_Amazon_S3]] +* [[tips/using_Amazon_Glacier]] * [[tips/Internet_Archive_via_S3]] * [[tahoe-lafs|forum/tips:_special__95__remotes__47__hook_with_tahoe-lafs]] * [[tips/using_box.com_as_a_special_remote]] diff --git a/doc/special_remotes/glacier.mdwn b/doc/special_remotes/glacier.mdwn new file mode 100644 index 000000000..f02f36694 --- /dev/null +++ b/doc/special_remotes/glacier.mdwn @@ -0,0 +1,51 @@ +This special remote type stores file contents in Amazon Glacier. + +To use it, you need to have [glacier-cli](http://github.com/basak/glacier-cli) +installed. + +The unusual thing about Amazon Glacier is the multiple-hour delay it takes +to retrieve information out of Glacier. To deal with this, commands like +"git-annex get" request Glacier start the retrieval process, and will fail +due to the data not yet being available. You can then wait appriximately +four hours, re-run the same command, and this time, it will actually +download the data. + +## configuration + +The standard environment variables `AWS_ACCESS_KEY_ID` and +`AWS_SECRET_ACCESS_KEY` are used to supply login credentials +for Amazon. You need to set these only when running +`git annex initremote`, as they will be cached in a file only you +can read inside the local git repository. + +A number of parameters can be passed to `git annex initremote` to configure +the Glacier remote. + +* `encryption` - Required. Either "none" to disable encryption (not recommended), + or a value that can be looked up (using gpg -k) to find a gpg encryption + key that will be given access to the remote, or "shared" which allows + every clone of the repository to access the encrypted data (use with caution). + + Note that additional gpg keys can be given access to a remote by + rerunning initremote with the new key id. See [[encryption]]. + +* `embedcreds` - Optional. Set to "yes" embed the login credentials inside + the git repository, which allows other clones to also access them. This is + the default when gpg encryption is enabled; the credentials are stored + encrypted and only those with the repository's keys can access them. + + It is not the default when using shared encryption, or no encryption. + Think carefully about who can access your repository before using + embedcreds without gpg encryption. + +* `datacenter` - Defaults to "us-east-1". + +* `vault` - Glacier requires that vaults have a globally unique name, + so by default, a vault name is chosen based on the remote name + and UUID. This can be specified to pick a valult name. + +* `fileprefix` - By default, git-annex places files in a tree rooted at the + top of the Glacier vault. When this is set, it's prefixed to the filenames + used. For example, you could set it to "foo/" in one special remote, + and to "bar/" in another special remote, and both special remotes could + then use the same vault. diff --git a/doc/tips/using_Amazon_Glacier.mdwn b/doc/tips/using_Amazon_Glacier.mdwn new file mode 100644 index 000000000..73c248e63 --- /dev/null +++ b/doc/tips/using_Amazon_Glacier.mdwn @@ -0,0 +1,69 @@ +Amazon Glacier provides low-cost storage, well suited for archiving and +backup. But it takes around 4 hours to get content out of Glacier. + +Recent versions of git-annex support Glacier. To use it, you need to have +[glacier-cli](http://github.com/basak/glacier-cli) installed. + +First, export your Amazon AWS credentials: + + # export AWS_ACCESS_KEY_ID="08TJMT99S3511WOZEP91" + # export AWS_SECRET_ACCESS_KEY="s3kr1t" + +Now, create a gpg key, if you don't already have one. This will be used +to encrypt everything stored in Glacier, for your privacy. Once you have +a gpg key, run `gpg --list-secret-keys` to look up its key id, something +like "2512E3C7" + +Next, create the Glacier remote. + + # git annex initremote glacier type=glacier encryption=2512E3C7 + initremote glacier (encryption setup with gpg key C910D9222512E3C7) (gpg) ok + +The configuration for the Glacier remote is stored in git. So to make another +repository use the same Glacier remote is easy: + + # cd /media/usb/annex + # git pull laptop + # git annex initremote glacier + initremote glacier (gpg) ok + +Now the remote can be used like any other remote. + + # git annex move my_cool_big_file --to glacier + copy my_cool_big_file (gpg) (checking glacier...) (to glacier...) ok + +But, when you try to get a file out of Glacier, it'll queue a retrieval +job: + + # git annex get my_cool_big_file + get my_cool_big_file (from glacier...) (gpg) + glacier: queued retrieval job for archive 'GPGHMACSHA1--862afd4e67e3946587a9ef7fa5beb4e8f1aeb6b8' + Recommend you wait up to 4 hours, and then run this command again. + failed + +Like it says, you'll need to run the command again later. Let's remember to +do that: + + # at now + 4 hours + at> git annex get my_cool_big_file + +Another oddity of Glacier is that git-annex is never entirely sure +if a file is still in Glacier. Glacier inventories take hours to retrieve, +and even when retrieved do not necessarily represent the current state. + +So, git-annex plays it safe, and avoids trusting the inventory: + + # git annex copy important_file --to glacier + copy important_file (gpg) (checking glacier...) (to glacier...) ok + # git annex drop important_file + drop important_file (gpg) (checking glacier...) + However, the inventory could be out of date, if it was recently removed. + (Use --trust-glacier-inventory if you're sure it's still in Glacier.) + + (unsafe) + Could only verify the existence of 0 out of 1 necessary copies + +Like it says, you can use `--trust-glacier-inventory` if you're sure +Glacier's inventory is correct and up-to-date. + +See [[special_remotes/Glacier]] for details. diff --git a/doc/tips/using_Amazon_S3.mdwn b/doc/tips/using_Amazon_S3.mdwn index 128819fcb..19997d026 100644 --- a/doc/tips/using_Amazon_S3.mdwn +++ b/doc/tips/using_Amazon_S3.mdwn @@ -2,7 +2,7 @@ git-annex extends git's usual remotes with some [[special_remotes]], that are not git repositories. This way you can set up a remote using say, Amazon S3, and use git-annex to transfer files into the cloud. -First, export your S3 credentials: +First, export your Amazon AWS credentials: # export AWS_ACCESS_KEY_ID="08TJMT99S3511WOZEP91" # export AWS_SECRET_ACCESS_KEY="s3kr1t" diff --git a/doc/todo/special_remote_for_amazon_glacier.mdwn b/doc/todo/special_remote_for_amazon_glacier.mdwn index a6e524cdd..0fa77b527 100644 --- a/doc/todo/special_remote_for_amazon_glacier.mdwn +++ b/doc/todo/special_remote_for_amazon_glacier.mdwn @@ -18,8 +18,13 @@ run, or files to transfer, at that point. --[[Joey]] +> [[done]]! --[[Joey]] + ----- > In the coming months, Amazon S3 will introduce an option that will allow customers to seamlessly move data between Amazon S3 and Amazon Glacier based on data lifecycle policies. -- <http://aws.amazon.com/glacier/faqs/#How_should_I_choose_between_Amazon_Glacier_and_Amazon_S3> + +>> They did, but it's IMHO not very useful for git-annex. It's rather +>> intended to allow aging S3 storage out to Glacier. --[[Joey]] |