summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2012-11-20 16:43:58 -0400
committerGravatar Joey Hess <joey@kitenet.net>2012-11-20 16:43:58 -0400
commit0d378285e709833f87547fd6fedc4e8b2f4884c4 (patch)
tree6caa2c4ba7710c917751d26c5bf58cce2a1163e2
parentcba848b472a4ac323693b44fcef9ddbbe535c929 (diff)
Amazon Glacier special remote; 100% working
-rw-r--r--Creds.hs20
-rw-r--r--GitAnnex.hs1
-rw-r--r--Remote/Glacier.hs235
-rw-r--r--Remote/Helper/AWS.hs21
-rw-r--r--Remote/List.hs2
-rw-r--r--Remote/S3.hs24
-rw-r--r--Remote/WebDAV.hs8
-rw-r--r--debian/changelog2
-rw-r--r--doc/design/assistant/cloud.mdwn2
-rw-r--r--doc/git-annex.mdwn16
-rw-r--r--doc/special_remotes.mdwn1
-rw-r--r--doc/special_remotes/glacier.mdwn51
-rw-r--r--doc/tips/using_Amazon_Glacier.mdwn69
-rw-r--r--doc/tips/using_Amazon_S3.mdwn2
-rw-r--r--doc/todo/special_remote_for_amazon_glacier.mdwn5
15 files changed, 427 insertions, 32 deletions
diff --git a/Creds.hs b/Creds.hs
index dbd05e3ef..f5ea55000 100644
--- a/Creds.hs
+++ b/Creds.hs
@@ -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]]