Improve initializing ConnectInfo (#101)
- Remove ConnectInfo's Default instance - Add support for reading from well-known credential files and environment variables
This commit is contained in:
parent
8273910084
commit
44bbd66719
@ -57,11 +57,12 @@ library
|
|||||||
, containers >= 0.5
|
, containers >= 0.5
|
||||||
, cryptonite >= 0.25
|
, cryptonite >= 0.25
|
||||||
, cryptonite-conduit >= 0.2
|
, cryptonite-conduit >= 0.2
|
||||||
, data-default >= 0.7
|
, directory
|
||||||
, filepath >= 1.4
|
, filepath >= 1.4
|
||||||
, http-client >= 0.5
|
, http-client >= 0.5
|
||||||
, http-conduit >= 2.3
|
, http-conduit >= 2.3
|
||||||
, http-types >= 0.12
|
, http-types >= 0.12
|
||||||
|
, ini
|
||||||
, memory >= 0.14
|
, memory >= 0.14
|
||||||
, resourcet >= 1.2
|
, resourcet >= 1.2
|
||||||
, text >= 1.2
|
, text >= 1.2
|
||||||
@ -142,12 +143,12 @@ test-suite minio-hs-live-server-test
|
|||||||
, containers
|
, containers
|
||||||
, cryptonite
|
, cryptonite
|
||||||
, cryptonite-conduit
|
, cryptonite-conduit
|
||||||
, data-default
|
|
||||||
, directory
|
, directory
|
||||||
, filepath
|
, filepath
|
||||||
, http-client
|
, http-client
|
||||||
, http-conduit
|
, http-conduit
|
||||||
, http-types
|
, http-types
|
||||||
|
, ini
|
||||||
, memory
|
, memory
|
||||||
, QuickCheck
|
, QuickCheck
|
||||||
, resourcet
|
, resourcet
|
||||||
@ -181,11 +182,12 @@ test-suite minio-hs-test
|
|||||||
, containers
|
, containers
|
||||||
, cryptonite
|
, cryptonite
|
||||||
, cryptonite-conduit
|
, cryptonite-conduit
|
||||||
, data-default
|
, filepath
|
||||||
, directory
|
, directory
|
||||||
, http-client
|
, http-client
|
||||||
, http-conduit
|
, http-conduit
|
||||||
, http-types
|
, http-types
|
||||||
|
, ini
|
||||||
, memory
|
, memory
|
||||||
, QuickCheck
|
, QuickCheck
|
||||||
, resourcet
|
, resourcet
|
||||||
|
|||||||
@ -18,18 +18,27 @@
|
|||||||
|
|
||||||
module Network.Minio
|
module Network.Minio
|
||||||
(
|
(
|
||||||
|
-- * Credentials
|
||||||
|
Credentials (..)
|
||||||
|
, fromAWSConfigFile
|
||||||
|
, fromAWSEnv
|
||||||
|
, fromMinioEnv
|
||||||
|
|
||||||
-- * Connecting to object storage
|
-- * Connecting to object storage
|
||||||
---------------------------------
|
---------------------------------
|
||||||
ConnectInfo(..)
|
, ConnectInfo
|
||||||
, awsCI
|
, setRegion
|
||||||
, gcsCI
|
, setCreds
|
||||||
|
, setCredsFrom
|
||||||
|
, MinioConn
|
||||||
|
, mkMinioConn
|
||||||
|
|
||||||
-- ** Connection helpers
|
-- ** Connection helpers
|
||||||
------------------------
|
------------------------
|
||||||
, awsWithRegionCI
|
|
||||||
, minioPlayCI
|
, minioPlayCI
|
||||||
, minioCI
|
, awsCI
|
||||||
|
, gcsCI
|
||||||
|
|
||||||
|
|
||||||
-- * Minio Monad
|
-- * Minio Monad
|
||||||
----------------
|
----------------
|
||||||
@ -39,8 +48,9 @@ module Network.Minio
|
|||||||
-- this Monad.
|
-- this Monad.
|
||||||
|
|
||||||
, Minio
|
, Minio
|
||||||
|
, runMinioWith
|
||||||
, runMinio
|
, runMinio
|
||||||
, def
|
|
||||||
|
|
||||||
-- * Bucket Operations
|
-- * Bucket Operations
|
||||||
----------------------
|
----------------------
|
||||||
@ -76,12 +86,16 @@ module Network.Minio
|
|||||||
|
|
||||||
-- ** Bucket Notifications
|
-- ** Bucket Notifications
|
||||||
, Notification(..)
|
, Notification(..)
|
||||||
|
, defaultNotification
|
||||||
, NotificationConfig(..)
|
, NotificationConfig(..)
|
||||||
, Arn
|
, Arn
|
||||||
, Event(..)
|
, Event(..)
|
||||||
, Filter(..)
|
, Filter(..)
|
||||||
|
, defaultFilter
|
||||||
, FilterKey(..)
|
, FilterKey(..)
|
||||||
|
, defaultFilterKey
|
||||||
, FilterRules(..)
|
, FilterRules(..)
|
||||||
|
, defaultFilterRules
|
||||||
, FilterRule(..)
|
, FilterRule(..)
|
||||||
, getBucketNotification
|
, getBucketNotification
|
||||||
, putBucketNotification
|
, putBucketNotification
|
||||||
@ -99,6 +113,7 @@ module Network.Minio
|
|||||||
, putObject
|
, putObject
|
||||||
-- | Input data type represents PutObject options.
|
-- | Input data type represents PutObject options.
|
||||||
, PutObjectOptions
|
, PutObjectOptions
|
||||||
|
, defaultPutObjectOptions
|
||||||
, pooContentType
|
, pooContentType
|
||||||
, pooContentEncoding
|
, pooContentEncoding
|
||||||
, pooContentDisposition
|
, pooContentDisposition
|
||||||
@ -111,6 +126,7 @@ module Network.Minio
|
|||||||
, getObject
|
, getObject
|
||||||
-- | Input data type represents GetObject options.
|
-- | Input data type represents GetObject options.
|
||||||
, GetObjectOptions
|
, GetObjectOptions
|
||||||
|
, defaultGetObjectOptions
|
||||||
, gooRange
|
, gooRange
|
||||||
, gooIfMatch
|
, gooIfMatch
|
||||||
, gooIfNoneMatch
|
, gooIfNoneMatch
|
||||||
@ -120,6 +136,7 @@ module Network.Minio
|
|||||||
-- ** Server-side copying
|
-- ** Server-side copying
|
||||||
, copyObject
|
, copyObject
|
||||||
, SourceInfo
|
, SourceInfo
|
||||||
|
, defaultSourceInfo
|
||||||
, srcBucket
|
, srcBucket
|
||||||
, srcObject
|
, srcObject
|
||||||
, srcRange
|
, srcRange
|
||||||
@ -128,6 +145,7 @@ module Network.Minio
|
|||||||
, srcIfModifiedSince
|
, srcIfModifiedSince
|
||||||
, srcIfUnmodifiedSince
|
, srcIfUnmodifiedSince
|
||||||
, DestinationInfo
|
, DestinationInfo
|
||||||
|
, defaultDestinationInfo
|
||||||
, dstBucket
|
, dstBucket
|
||||||
, dstObject
|
, dstObject
|
||||||
|
|
||||||
@ -178,7 +196,6 @@ This module exports the high-level Minio API for object storage.
|
|||||||
import qualified Data.Conduit as C
|
import qualified Data.Conduit as C
|
||||||
import qualified Data.Conduit.Binary as CB
|
import qualified Data.Conduit.Binary as CB
|
||||||
import qualified Data.Conduit.Combinators as CC
|
import qualified Data.Conduit.Combinators as CC
|
||||||
import Data.Default (def)
|
|
||||||
|
|
||||||
import Lib.Prelude
|
import Lib.Prelude
|
||||||
|
|
||||||
|
|||||||
@ -31,7 +31,6 @@ module Network.Minio.API
|
|||||||
import qualified Data.ByteString as B
|
import qualified Data.ByteString as B
|
||||||
import qualified Data.Char as C
|
import qualified Data.Char as C
|
||||||
import qualified Data.Conduit as C
|
import qualified Data.Conduit as C
|
||||||
import Data.Default (def)
|
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Time.Clock as Time
|
import qualified Data.Time.Clock as Time
|
||||||
@ -53,7 +52,7 @@ import Network.Minio.XmlParser
|
|||||||
-- | Fetch bucket location (region)
|
-- | Fetch bucket location (region)
|
||||||
getLocation :: Bucket -> Minio Region
|
getLocation :: Bucket -> Minio Region
|
||||||
getLocation bucket = do
|
getLocation bucket = do
|
||||||
resp <- executeRequest $ def {
|
resp <- executeRequest $ defaultS3ReqInfo {
|
||||||
riBucket = Just bucket
|
riBucket = Just bucket
|
||||||
, riQueryParams = [("location", Nothing)]
|
, riQueryParams = [("location", Nothing)]
|
||||||
, riNeedsLocation = False
|
, riNeedsLocation = False
|
||||||
|
|||||||
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
module Network.Minio.CopyObject where
|
module Network.Minio.CopyObject where
|
||||||
|
|
||||||
import Data.Default (def)
|
|
||||||
import qualified Data.List as List
|
import qualified Data.List as List
|
||||||
|
|
||||||
import Lib.Prelude
|
import Lib.Prelude
|
||||||
@ -81,7 +80,7 @@ multiPartCopyObject b o cps srcSize = do
|
|||||||
partRanges = selectCopyRanges byteRange
|
partRanges = selectCopyRanges byteRange
|
||||||
partSources = map (\(x, (start, end)) -> (x, cps {srcRange = Just (start, end) }))
|
partSources = map (\(x, (start, end)) -> (x, cps {srcRange = Just (start, end) }))
|
||||||
partRanges
|
partRanges
|
||||||
dstInfo = def { dstBucket = b, dstObject = o}
|
dstInfo = defaultDestinationInfo { dstBucket = b, dstObject = o}
|
||||||
|
|
||||||
copiedParts <- limitedMapConcurrently 10
|
copiedParts <- limitedMapConcurrently 10
|
||||||
(\(pn, cps') -> do
|
(\(pn, cps') -> do
|
||||||
|
|||||||
@ -25,9 +25,11 @@ import Control.Monad.IO.Unlift (MonadUnliftIO, UnliftIO (..),
|
|||||||
import Control.Monad.Trans.Resource
|
import Control.Monad.Trans.Resource
|
||||||
import qualified Data.ByteString as B
|
import qualified Data.ByteString as B
|
||||||
import Data.CaseInsensitive (mk)
|
import Data.CaseInsensitive (mk)
|
||||||
import Data.Default (Default (..))
|
import qualified Data.Ini as Ini
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
import Data.String (IsString (..))
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
|
import qualified Data.Text.Encoding as TE
|
||||||
import Data.Time (defaultTimeLocale, formatTime)
|
import Data.Time (defaultTimeLocale, formatTime)
|
||||||
import GHC.Show (Show (show))
|
import GHC.Show (Show (show))
|
||||||
import Network.HTTP.Client (defaultManagerSettings)
|
import Network.HTTP.Client (defaultManagerSettings)
|
||||||
@ -36,6 +38,9 @@ import Network.HTTP.Types (ByteRange, Header, Method, Query,
|
|||||||
hRange)
|
hRange)
|
||||||
import qualified Network.HTTP.Types as HT
|
import qualified Network.HTTP.Types as HT
|
||||||
import Network.Minio.Errors
|
import Network.Minio.Errors
|
||||||
|
import System.Directory (doesFileExist, getHomeDirectory)
|
||||||
|
import qualified System.Environment as Env
|
||||||
|
import System.FilePath.Posix (combine)
|
||||||
import Text.XML
|
import Text.XML
|
||||||
import qualified UnliftIO as U
|
import qualified UnliftIO as U
|
||||||
|
|
||||||
@ -92,11 +97,73 @@ data ConnectInfo = ConnectInfo {
|
|||||||
} deriving (Eq, Show)
|
} deriving (Eq, Show)
|
||||||
|
|
||||||
|
|
||||||
-- | Connects to a Minio server located at @localhost:9000@ with access
|
instance IsString ConnectInfo where
|
||||||
-- key /minio/ and secret key /minio123/. It is over __HTTP__ by
|
fromString str = let req = NC.parseRequest_ str
|
||||||
-- default.
|
in ConnectInfo
|
||||||
instance Default ConnectInfo where
|
{ connectHost = TE.decodeUtf8 $ NC.host req
|
||||||
def = ConnectInfo "localhost" 9000 "minio" "minio123" False "us-east-1" True
|
, connectPort = NC.port req
|
||||||
|
, connectAccessKey = ""
|
||||||
|
, connectSecretKey = ""
|
||||||
|
, connectIsSecure = NC.secure req
|
||||||
|
, connectRegion = ""
|
||||||
|
, connectAutoDiscoverRegion = True
|
||||||
|
}
|
||||||
|
|
||||||
|
data Credentials = Credentials { cAccessKey :: Text
|
||||||
|
, cSecretKey :: Text
|
||||||
|
} deriving (Eq, Show)
|
||||||
|
|
||||||
|
type Provider = IO (Maybe Credentials)
|
||||||
|
|
||||||
|
findFirst :: [Provider] -> Provider
|
||||||
|
findFirst [] = return Nothing
|
||||||
|
findFirst (f:fs) = do c <- f
|
||||||
|
maybe (findFirst fs) (return . Just) c
|
||||||
|
|
||||||
|
fromAWSConfigFile :: Provider
|
||||||
|
fromAWSConfigFile = do
|
||||||
|
credsE <- runExceptT $ do
|
||||||
|
homeDir <- lift $ getHomeDirectory
|
||||||
|
let awsCredsFile = homeDir `combine` ".aws" `combine` "credentials"
|
||||||
|
fileExists <- lift $ doesFileExist awsCredsFile
|
||||||
|
bool (throwE "FileNotFound") (return ()) fileExists
|
||||||
|
ini <- ExceptT $ Ini.readIniFile awsCredsFile
|
||||||
|
akey <- ExceptT $ return
|
||||||
|
$ Ini.lookupValue "default" "aws_access_key_id" ini
|
||||||
|
skey <- ExceptT $ return
|
||||||
|
$ Ini.lookupValue "default" "aws_secret_access_key" ini
|
||||||
|
return $ Credentials akey skey
|
||||||
|
return $ hush credsE
|
||||||
|
|
||||||
|
fromAWSEnv :: Provider
|
||||||
|
fromAWSEnv = runMaybeT $ do
|
||||||
|
akey <- MaybeT $ Env.lookupEnv "AWS_ACCESS_KEY_ID"
|
||||||
|
skey <- MaybeT $ Env.lookupEnv "AWS_SECRET_ACCESS_KEY"
|
||||||
|
return $ Credentials (T.pack akey) (T.pack skey)
|
||||||
|
|
||||||
|
fromMinioEnv :: Provider
|
||||||
|
fromMinioEnv = runMaybeT $ do
|
||||||
|
akey <- MaybeT $ Env.lookupEnv "MINIO_ACCESS_KEY"
|
||||||
|
skey <- MaybeT $ Env.lookupEnv "MINIO_SECRET_KEY"
|
||||||
|
return $ Credentials (T.pack akey) (T.pack skey)
|
||||||
|
|
||||||
|
setCredsFrom :: [Provider] -> ConnectInfo -> IO ConnectInfo
|
||||||
|
setCredsFrom ps ci = do pMay <- findFirst ps
|
||||||
|
maybe
|
||||||
|
(throwIO MErrVMissingCredentials)
|
||||||
|
(return . (flip setCreds ci))
|
||||||
|
pMay
|
||||||
|
|
||||||
|
setCreds :: Credentials -> ConnectInfo -> ConnectInfo
|
||||||
|
setCreds (Credentials accessKey secretKey) connInfo =
|
||||||
|
connInfo { connectAccessKey = accessKey
|
||||||
|
, connectSecretKey = secretKey
|
||||||
|
}
|
||||||
|
|
||||||
|
setRegion :: Region -> ConnectInfo -> ConnectInfo
|
||||||
|
setRegion r connInfo = connInfo { connectRegion = r
|
||||||
|
, connectAutoDiscoverRegion = False
|
||||||
|
}
|
||||||
|
|
||||||
getHostAddr :: ConnectInfo -> ByteString
|
getHostAddr :: ConnectInfo -> ByteString
|
||||||
getHostAddr ci = if | port == 80 || port == 443 -> toS host
|
getHostAddr ci = if | port == 80 || port == 443 -> toS host
|
||||||
@ -110,92 +177,25 @@ getHostAddr ci = if | port == 80 || port == 443 -> toS host
|
|||||||
-- | Default GCS ConnectInfo. Works only for "Simple Migration"
|
-- | Default GCS ConnectInfo. Works only for "Simple Migration"
|
||||||
-- use-case with interoperability mode enabled on GCP console. For
|
-- use-case with interoperability mode enabled on GCP console. For
|
||||||
-- more information - https://cloud.google.com/storage/docs/migrating
|
-- more information - https://cloud.google.com/storage/docs/migrating
|
||||||
-- Credentials should be supplied before use, for e.g.:
|
-- Credentials should be supplied before use.
|
||||||
--
|
|
||||||
-- > gcsCI {
|
|
||||||
-- > connectAccessKey = "my-access-key"
|
|
||||||
-- > , connectSecretKey = "my-secret-key"
|
|
||||||
-- > }
|
|
||||||
|
|
||||||
gcsCI :: ConnectInfo
|
gcsCI :: ConnectInfo
|
||||||
gcsCI = def {
|
gcsCI = setRegion "us"
|
||||||
connectHost = "storage.googleapis.com"
|
"https://storage.googleapis.com"
|
||||||
, connectPort = 443
|
|
||||||
, connectRegion = "us" -- picking region with Multi-Regional support
|
|
||||||
, connectAccessKey = ""
|
|
||||||
, connectSecretKey = ""
|
|
||||||
, connectIsSecure = True
|
|
||||||
, connectAutoDiscoverRegion = True
|
|
||||||
}
|
|
||||||
|
|
||||||
-- | Default AWS ConnectInfo. Connects to "us-east-1". Credentials
|
-- | Default AWS ConnectInfo. Connects to "us-east-1". Credentials
|
||||||
-- should be supplied before use, for e.g.:
|
-- should be supplied before use.
|
||||||
--
|
|
||||||
-- > awsCI {
|
|
||||||
-- > connectAccessKey = "my-access-key"
|
|
||||||
-- > , connectSecretKey = "my-secret-key"
|
|
||||||
-- > }
|
|
||||||
awsCI :: ConnectInfo
|
awsCI :: ConnectInfo
|
||||||
awsCI = def {
|
awsCI = "https://s3.amazonaws.com"
|
||||||
connectHost = "s3.amazonaws.com"
|
|
||||||
, connectPort = 443
|
|
||||||
, connectAccessKey = ""
|
|
||||||
, connectSecretKey = ""
|
|
||||||
, connectIsSecure = True
|
|
||||||
}
|
|
||||||
|
|
||||||
-- | AWS ConnectInfo with a specified region. It can optionally
|
|
||||||
-- disable the automatic discovery of a bucket's region via the
|
|
||||||
-- Boolean argument.
|
|
||||||
--
|
|
||||||
-- > awsWithRegionCI "us-west-1" False {
|
|
||||||
-- > connectAccessKey = "my-access-key"
|
|
||||||
-- > , connectSecretKey = "my-secret-key"
|
|
||||||
-- > }
|
|
||||||
--
|
|
||||||
-- This restricts all operations to the "us-west-1" region and does
|
|
||||||
-- not perform any bucket location requests.
|
|
||||||
awsWithRegionCI :: Region -> Bool -> ConnectInfo
|
|
||||||
awsWithRegionCI region autoDiscoverRegion =
|
|
||||||
let host = maybe "s3.amazonaws.com" identity $
|
|
||||||
Map.lookup region awsRegionMap
|
|
||||||
in awsCI {
|
|
||||||
connectHost = host
|
|
||||||
, connectRegion = region
|
|
||||||
, connectAutoDiscoverRegion = autoDiscoverRegion
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
-- | <https://play.minio.io:9000 Minio Play Server>
|
-- | <https://play.minio.io:9000 Minio Play Server>
|
||||||
-- ConnectInfo. Credentials are already filled in.
|
-- ConnectInfo. Credentials are already filled in.
|
||||||
minioPlayCI :: ConnectInfo
|
minioPlayCI :: ConnectInfo
|
||||||
minioPlayCI = def {
|
minioPlayCI = let playCreds = Credentials "Q3AM3UQ867SPQQA43P2F" "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"
|
||||||
connectHost = "play.minio.io"
|
in setCreds playCreds
|
||||||
, connectPort = 9000
|
$ setRegion "us-east-1"
|
||||||
, connectAccessKey = "Q3AM3UQ867SPQQA43P2F"
|
"https://play.minio.io:9000"
|
||||||
, connectSecretKey = "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"
|
|
||||||
, connectIsSecure = True
|
|
||||||
, connectAutoDiscoverRegion = False
|
|
||||||
}
|
|
||||||
|
|
||||||
-- | ConnectInfo for Minio server. Takes hostname, port and a Boolean
|
|
||||||
-- to enable TLS.
|
|
||||||
--
|
|
||||||
-- > minioCI "minio.example.com" 9000 True {
|
|
||||||
-- > connectAccessKey = "my-access-key"
|
|
||||||
-- > , connectSecretKey = "my-secret-key"
|
|
||||||
-- > }
|
|
||||||
--
|
|
||||||
-- This connects to a Minio server at the given hostname and port over
|
|
||||||
-- HTTPS.
|
|
||||||
minioCI :: Text -> Int -> Bool -> ConnectInfo
|
|
||||||
minioCI host port isSecure = def {
|
|
||||||
connectHost = host
|
|
||||||
, connectPort = port
|
|
||||||
, connectRegion = "us-east-1"
|
|
||||||
, connectIsSecure = isSecure
|
|
||||||
, connectAutoDiscoverRegion = False
|
|
||||||
}
|
|
||||||
|
|
||||||
-- |
|
-- |
|
||||||
-- Represents a bucket in the object store
|
-- Represents a bucket in the object store
|
||||||
@ -241,8 +241,8 @@ data PutObjectOptions = PutObjectOptions {
|
|||||||
} deriving (Show, Eq)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
-- Provide a default instance
|
-- Provide a default instance
|
||||||
instance Default PutObjectOptions where
|
defaultPutObjectOptions :: PutObjectOptions
|
||||||
def = PutObjectOptions def def def def def def [] def
|
defaultPutObjectOptions = PutObjectOptions Nothing Nothing Nothing Nothing Nothing Nothing [] Nothing
|
||||||
|
|
||||||
addXAmzMetaPrefix :: Text -> Text
|
addXAmzMetaPrefix :: Text -> Text
|
||||||
addXAmzMetaPrefix s = do
|
addXAmzMetaPrefix s = do
|
||||||
@ -361,17 +361,17 @@ data SourceInfo = SourceInfo {
|
|||||||
, srcIfUnmodifiedSince :: Maybe UTCTime
|
, srcIfUnmodifiedSince :: Maybe UTCTime
|
||||||
} deriving (Show, Eq)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
instance Default SourceInfo where
|
defaultSourceInfo :: SourceInfo
|
||||||
def = SourceInfo "" "" def def def def def
|
defaultSourceInfo = SourceInfo "" "" Nothing Nothing Nothing Nothing Nothing
|
||||||
|
|
||||||
-- | Represents destination object in server-side copy object
|
-- | Represents destination object in server-side copy object
|
||||||
data DestinationInfo = DestinationInfo {
|
data DestinationInfo = DestinationInfo
|
||||||
dstBucket :: Text
|
{ dstBucket :: Text
|
||||||
, dstObject :: Text
|
, dstObject :: Text
|
||||||
} deriving (Show, Eq)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
instance Default DestinationInfo where
|
defaultDestinationInfo :: DestinationInfo
|
||||||
def = DestinationInfo "" ""
|
defaultDestinationInfo = DestinationInfo "" ""
|
||||||
|
|
||||||
data GetObjectOptions = GetObjectOptions {
|
data GetObjectOptions = GetObjectOptions {
|
||||||
-- | Set object's data of given offset begin and end,
|
-- | Set object's data of given offset begin and end,
|
||||||
@ -389,8 +389,8 @@ data GetObjectOptions = GetObjectOptions {
|
|||||||
, gooIfModifiedSince :: Maybe UTCTime
|
, gooIfModifiedSince :: Maybe UTCTime
|
||||||
} deriving (Show, Eq)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
instance Default GetObjectOptions where
|
defaultGetObjectOptions :: GetObjectOptions
|
||||||
def = GetObjectOptions def def def def def
|
defaultGetObjectOptions = GetObjectOptions Nothing Nothing Nothing Nothing Nothing
|
||||||
|
|
||||||
gooToHeaders :: GetObjectOptions -> [HT.Header]
|
gooToHeaders :: GetObjectOptions -> [HT.Header]
|
||||||
gooToHeaders goo = rangeHdr ++ zip names values
|
gooToHeaders goo = rangeHdr ++ zip names values
|
||||||
@ -450,22 +450,23 @@ data Filter = Filter
|
|||||||
{ fFilter :: FilterKey
|
{ fFilter :: FilterKey
|
||||||
} deriving (Show, Eq)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
instance Default Filter where
|
defaultFilter :: Filter
|
||||||
def = Filter def
|
defaultFilter = Filter defaultFilterKey
|
||||||
|
|
||||||
data FilterKey = FilterKey
|
data FilterKey = FilterKey
|
||||||
{ fkKey :: FilterRules
|
{ fkKey :: FilterRules
|
||||||
} deriving (Show, Eq)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
instance Default FilterKey where
|
defaultFilterKey :: FilterKey
|
||||||
def = FilterKey def
|
defaultFilterKey = FilterKey defaultFilterRules
|
||||||
|
|
||||||
data FilterRules = FilterRules
|
data FilterRules = FilterRules
|
||||||
{ frFilterRules :: [FilterRule]
|
{ frFilterRules :: [FilterRule]
|
||||||
} deriving (Show, Eq)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
instance Default FilterRules where
|
defaultFilterRules :: FilterRules
|
||||||
def = FilterRules []
|
defaultFilterRules = FilterRules []
|
||||||
|
|
||||||
|
|
||||||
-- | A filter rule that can act based on the suffix or prefix of an
|
-- | A filter rule that can act based on the suffix or prefix of an
|
||||||
-- object. As an example, let's create two filter rules:
|
-- object. As an example, let's create two filter rules:
|
||||||
@ -504,8 +505,8 @@ data Notification = Notification
|
|||||||
, nCloudFunctionConfigurations :: [NotificationConfig]
|
, nCloudFunctionConfigurations :: [NotificationConfig]
|
||||||
} deriving (Eq, Show)
|
} deriving (Eq, Show)
|
||||||
|
|
||||||
instance Default Notification where
|
defaultNotification :: Notification
|
||||||
def = Notification [] [] []
|
defaultNotification = Notification [] [] []
|
||||||
|
|
||||||
-- | Represents different kinds of payload that are used with S3 API
|
-- | Represents different kinds of payload that are used with S3 API
|
||||||
-- requests.
|
-- requests.
|
||||||
@ -514,8 +515,8 @@ data Payload = PayloadBS ByteString
|
|||||||
Int64 -- offset
|
Int64 -- offset
|
||||||
Int64 -- size
|
Int64 -- size
|
||||||
|
|
||||||
instance Default Payload where
|
defaultPayload :: Payload
|
||||||
def = PayloadBS ""
|
defaultPayload = PayloadBS ""
|
||||||
|
|
||||||
data AdminReqInfo = AdminReqInfo {
|
data AdminReqInfo = AdminReqInfo {
|
||||||
ariMethod :: Method
|
ariMethod :: Method
|
||||||
@ -538,8 +539,9 @@ data S3ReqInfo = S3ReqInfo {
|
|||||||
, riNeedsLocation :: Bool
|
, riNeedsLocation :: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
instance Default S3ReqInfo where
|
defaultS3ReqInfo :: S3ReqInfo
|
||||||
def = S3ReqInfo HT.methodGet def def def def def Nothing def True
|
defaultS3ReqInfo = S3ReqInfo HT.methodGet Nothing Nothing
|
||||||
|
[] [] defaultPayload Nothing Nothing True
|
||||||
|
|
||||||
getS3Path :: Maybe Bucket -> Maybe Object -> ByteString
|
getS3Path :: Maybe Bucket -> Maybe Object -> ByteString
|
||||||
getS3Path b o =
|
getS3Path b o =
|
||||||
@ -594,14 +596,11 @@ connect ci = do
|
|||||||
let settings | connectIsSecure ci = NC.tlsManagerSettings
|
let settings | connectIsSecure ci = NC.tlsManagerSettings
|
||||||
| otherwise = defaultManagerSettings
|
| otherwise = defaultManagerSettings
|
||||||
mgr <- NC.newManager settings
|
mgr <- NC.newManager settings
|
||||||
rMapMVar <- M.newMVar Map.empty
|
mkMinioConn ci mgr
|
||||||
return $ MinioConn ci mgr rMapMVar
|
|
||||||
|
|
||||||
-- | Run the Minio action and return the result or an error.
|
|
||||||
runMinio :: ConnectInfo -> Minio a -> IO (Either MinioErr a)
|
runMinioWith :: MinioConn -> Minio a -> IO (Either MinioErr a)
|
||||||
runMinio ci m = do
|
runMinioWith conn m = runResourceT . flip runReaderT conn . unMinio $
|
||||||
conn <- liftIO $ connect ci
|
|
||||||
runResourceT . flip runReaderT conn . unMinio $
|
|
||||||
fmap Right m `U.catches`
|
fmap Right m `U.catches`
|
||||||
[ U.Handler handlerServiceErr
|
[ U.Handler handlerServiceErr
|
||||||
, U.Handler handlerHE
|
, U.Handler handlerHE
|
||||||
@ -614,6 +613,17 @@ runMinio ci m = do
|
|||||||
handlerFE = return . Left . MErrIO
|
handlerFE = return . Left . MErrIO
|
||||||
handlerValidation = return . Left . MErrValidation
|
handlerValidation = return . Left . MErrValidation
|
||||||
|
|
||||||
|
mkMinioConn :: ConnectInfo -> NC.Manager -> IO MinioConn
|
||||||
|
mkMinioConn ci mgr = do
|
||||||
|
rMapMVar <- M.newMVar Map.empty
|
||||||
|
return $ MinioConn ci mgr rMapMVar
|
||||||
|
|
||||||
|
-- | Run the Minio action and return the result or an error.
|
||||||
|
runMinio :: ConnectInfo -> Minio a -> IO (Either MinioErr a)
|
||||||
|
runMinio ci m = do
|
||||||
|
conn <- connect ci
|
||||||
|
runMinioWith conn m
|
||||||
|
|
||||||
s3Name :: Text -> Text -> Name
|
s3Name :: Text -> Text -> Name
|
||||||
s3Name ns s = Name s (Just ns) Nothing
|
s3Name ns s = Name s (Just ns) Nothing
|
||||||
|
|
||||||
|
|||||||
@ -40,6 +40,7 @@ data MErrV = MErrVSinglePUTSizeExceeded Int64
|
|||||||
| MErrVInvalidUrlExpiry Int
|
| MErrVInvalidUrlExpiry Int
|
||||||
| MErrVJsonParse Text
|
| MErrVJsonParse Text
|
||||||
| MErrVInvalidHealPath
|
| MErrVInvalidHealPath
|
||||||
|
| MErrVMissingCredentials
|
||||||
deriving (Show, Eq)
|
deriving (Show, Eq)
|
||||||
|
|
||||||
instance Exception MErrV
|
instance Exception MErrV
|
||||||
|
|||||||
@ -92,7 +92,6 @@ module Network.Minio.S3API
|
|||||||
|
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import qualified Data.Conduit as C
|
import qualified Data.Conduit as C
|
||||||
import Data.Default (def)
|
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Network.HTTP.Conduit as NC
|
import qualified Network.HTTP.Conduit as NC
|
||||||
import qualified Network.HTTP.Types as HT
|
import qualified Network.HTTP.Types as HT
|
||||||
@ -112,7 +111,7 @@ import Network.Minio.XmlParser
|
|||||||
-- | Fetch all buckets from the service.
|
-- | Fetch all buckets from the service.
|
||||||
getService :: Minio [BucketInfo]
|
getService :: Minio [BucketInfo]
|
||||||
getService = do
|
getService = do
|
||||||
resp <- executeRequest $ def {
|
resp <- executeRequest $ defaultS3ReqInfo {
|
||||||
riNeedsLocation = False
|
riNeedsLocation = False
|
||||||
}
|
}
|
||||||
parseListBuckets $ NC.responseBody resp
|
parseListBuckets $ NC.responseBody resp
|
||||||
@ -125,7 +124,7 @@ getObject' bucket object queryParams headers = do
|
|||||||
resp <- mkStreamRequest reqInfo
|
resp <- mkStreamRequest reqInfo
|
||||||
return (NC.responseHeaders resp, NC.responseBody resp)
|
return (NC.responseHeaders resp, NC.responseBody resp)
|
||||||
where
|
where
|
||||||
reqInfo = def { riBucket = Just bucket
|
reqInfo = defaultS3ReqInfo { riBucket = Just bucket
|
||||||
, riObject = Just object
|
, riObject = Just object
|
||||||
, riQueryParams = queryParams
|
, riQueryParams = queryParams
|
||||||
, riHeaders = headers
|
, riHeaders = headers
|
||||||
@ -136,7 +135,7 @@ putBucket :: Bucket -> Region -> Minio ()
|
|||||||
putBucket bucket location = do
|
putBucket bucket location = do
|
||||||
ns <- asks getSvcNamespace
|
ns <- asks getSvcNamespace
|
||||||
void $ executeRequest $
|
void $ executeRequest $
|
||||||
def { riMethod = HT.methodPut
|
defaultS3ReqInfo { riMethod = HT.methodPut
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riPayload = PayloadBS $ mkCreateBucketConfig ns location
|
, riPayload = PayloadBS $ mkCreateBucketConfig ns location
|
||||||
, riNeedsLocation = False
|
, riNeedsLocation = False
|
||||||
@ -155,7 +154,7 @@ putObjectSingle' bucket object headers bs = do
|
|||||||
|
|
||||||
-- content-length header is automatically set by library.
|
-- content-length header is automatically set by library.
|
||||||
resp <- executeRequest $
|
resp <- executeRequest $
|
||||||
def { riMethod = HT.methodPut
|
defaultS3ReqInfo { riMethod = HT.methodPut
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riObject = Just object
|
, riObject = Just object
|
||||||
, riHeaders = headers
|
, riHeaders = headers
|
||||||
@ -179,7 +178,7 @@ putObjectSingle bucket object headers h offset size = do
|
|||||||
|
|
||||||
-- content-length header is automatically set by library.
|
-- content-length header is automatically set by library.
|
||||||
resp <- executeRequest $
|
resp <- executeRequest $
|
||||||
def { riMethod = HT.methodPut
|
defaultS3ReqInfo { riMethod = HT.methodPut
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riObject = Just object
|
, riObject = Just object
|
||||||
, riHeaders = headers
|
, riHeaders = headers
|
||||||
@ -197,7 +196,7 @@ putObjectSingle bucket object headers h offset size = do
|
|||||||
listObjectsV1' :: Bucket -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Int
|
listObjectsV1' :: Bucket -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Int
|
||||||
-> Minio ListObjectsV1Result
|
-> Minio ListObjectsV1Result
|
||||||
listObjectsV1' bucket prefix nextMarker delimiter maxKeys = do
|
listObjectsV1' bucket prefix nextMarker delimiter maxKeys = do
|
||||||
resp <- executeRequest $ def { riMethod = HT.methodGet
|
resp <- executeRequest $ defaultS3ReqInfo { riMethod = HT.methodGet
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riQueryParams = mkOptionalParams params
|
, riQueryParams = mkOptionalParams params
|
||||||
}
|
}
|
||||||
@ -215,7 +214,7 @@ listObjectsV1' bucket prefix nextMarker delimiter maxKeys = do
|
|||||||
listObjects' :: Bucket -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Int
|
listObjects' :: Bucket -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Int
|
||||||
-> Minio ListObjectsResult
|
-> Minio ListObjectsResult
|
||||||
listObjects' bucket prefix nextToken delimiter maxKeys = do
|
listObjects' bucket prefix nextToken delimiter maxKeys = do
|
||||||
resp <- executeRequest $ def { riMethod = HT.methodGet
|
resp <- executeRequest $ defaultS3ReqInfo { riMethod = HT.methodGet
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riQueryParams = mkOptionalParams params
|
, riQueryParams = mkOptionalParams params
|
||||||
}
|
}
|
||||||
@ -233,7 +232,7 @@ listObjects' bucket prefix nextToken delimiter maxKeys = do
|
|||||||
deleteBucket :: Bucket -> Minio ()
|
deleteBucket :: Bucket -> Minio ()
|
||||||
deleteBucket bucket = void $
|
deleteBucket bucket = void $
|
||||||
executeRequest $
|
executeRequest $
|
||||||
def { riMethod = HT.methodDelete
|
defaultS3ReqInfo { riMethod = HT.methodDelete
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +240,7 @@ deleteBucket bucket = void $
|
|||||||
deleteObject :: Bucket -> Object -> Minio ()
|
deleteObject :: Bucket -> Object -> Minio ()
|
||||||
deleteObject bucket object = void $
|
deleteObject bucket object = void $
|
||||||
executeRequest $
|
executeRequest $
|
||||||
def { riMethod = HT.methodDelete
|
defaultS3ReqInfo { riMethod = HT.methodDelete
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riObject = Just object
|
, riObject = Just object
|
||||||
}
|
}
|
||||||
@ -249,7 +248,7 @@ deleteObject bucket object = void $
|
|||||||
-- | Create a new multipart upload.
|
-- | Create a new multipart upload.
|
||||||
newMultipartUpload :: Bucket -> Object -> [HT.Header] -> Minio UploadId
|
newMultipartUpload :: Bucket -> Object -> [HT.Header] -> Minio UploadId
|
||||||
newMultipartUpload bucket object headers = do
|
newMultipartUpload bucket object headers = do
|
||||||
resp <- executeRequest $ def { riMethod = HT.methodPost
|
resp <- executeRequest $ defaultS3ReqInfo { riMethod = HT.methodPost
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riObject = Just object
|
, riObject = Just object
|
||||||
, riQueryParams = [("uploads", Nothing)]
|
, riQueryParams = [("uploads", Nothing)]
|
||||||
@ -262,7 +261,7 @@ putObjectPart :: Bucket -> Object -> UploadId -> PartNumber -> [HT.Header]
|
|||||||
-> Payload -> Minio PartTuple
|
-> Payload -> Minio PartTuple
|
||||||
putObjectPart bucket object uploadId partNumber headers payload = do
|
putObjectPart bucket object uploadId partNumber headers payload = do
|
||||||
resp <- executeRequest $
|
resp <- executeRequest $
|
||||||
def { riMethod = HT.methodPut
|
defaultS3ReqInfo { riMethod = HT.methodPut
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riObject = Just object
|
, riObject = Just object
|
||||||
, riQueryParams = mkOptionalParams params
|
, riQueryParams = mkOptionalParams params
|
||||||
@ -304,7 +303,7 @@ copyObjectPart :: DestinationInfo -> SourceInfo -> UploadId
|
|||||||
-> PartNumber -> [HT.Header] -> Minio (ETag, UTCTime)
|
-> PartNumber -> [HT.Header] -> Minio (ETag, UTCTime)
|
||||||
copyObjectPart dstInfo srcInfo uploadId partNumber headers = do
|
copyObjectPart dstInfo srcInfo uploadId partNumber headers = do
|
||||||
resp <- executeRequest $
|
resp <- executeRequest $
|
||||||
def { riMethod = HT.methodPut
|
defaultS3ReqInfo { riMethod = HT.methodPut
|
||||||
, riBucket = Just $ dstBucket dstInfo
|
, riBucket = Just $ dstBucket dstInfo
|
||||||
, riObject = Just $ dstObject dstInfo
|
, riObject = Just $ dstObject dstInfo
|
||||||
, riQueryParams = mkOptionalParams params
|
, riQueryParams = mkOptionalParams params
|
||||||
@ -328,7 +327,7 @@ copyObjectSingle bucket object srcInfo headers = do
|
|||||||
when (isJust $ srcRange srcInfo) $
|
when (isJust $ srcRange srcInfo) $
|
||||||
throwIO MErrVCopyObjSingleNoRangeAccepted
|
throwIO MErrVCopyObjSingleNoRangeAccepted
|
||||||
resp <- executeRequest $
|
resp <- executeRequest $
|
||||||
def { riMethod = HT.methodPut
|
defaultS3ReqInfo { riMethod = HT.methodPut
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riObject = Just object
|
, riObject = Just object
|
||||||
, riHeaders = headers ++ srcInfoToHeaders srcInfo
|
, riHeaders = headers ++ srcInfoToHeaders srcInfo
|
||||||
@ -340,7 +339,7 @@ completeMultipartUpload :: Bucket -> Object -> UploadId -> [PartTuple]
|
|||||||
-> Minio ETag
|
-> Minio ETag
|
||||||
completeMultipartUpload bucket object uploadId partTuple = do
|
completeMultipartUpload bucket object uploadId partTuple = do
|
||||||
resp <- executeRequest $
|
resp <- executeRequest $
|
||||||
def { riMethod = HT.methodPost
|
defaultS3ReqInfo { riMethod = HT.methodPost
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riObject = Just object
|
, riObject = Just object
|
||||||
, riQueryParams = mkOptionalParams params
|
, riQueryParams = mkOptionalParams params
|
||||||
@ -354,7 +353,7 @@ completeMultipartUpload bucket object uploadId partTuple = do
|
|||||||
-- | Abort a multipart upload.
|
-- | Abort a multipart upload.
|
||||||
abortMultipartUpload :: Bucket -> Object -> UploadId -> Minio ()
|
abortMultipartUpload :: Bucket -> Object -> UploadId -> Minio ()
|
||||||
abortMultipartUpload bucket object uploadId = void $
|
abortMultipartUpload bucket object uploadId = void $
|
||||||
executeRequest $ def { riMethod = HT.methodDelete
|
executeRequest $ defaultS3ReqInfo { riMethod = HT.methodDelete
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riObject = Just object
|
, riObject = Just object
|
||||||
, riQueryParams = mkOptionalParams params
|
, riQueryParams = mkOptionalParams params
|
||||||
@ -366,7 +365,7 @@ abortMultipartUpload bucket object uploadId = void $
|
|||||||
listIncompleteUploads' :: Bucket -> Maybe Text -> Maybe Text -> Maybe Text
|
listIncompleteUploads' :: Bucket -> Maybe Text -> Maybe Text -> Maybe Text
|
||||||
-> Maybe Text -> Maybe Int -> Minio ListUploadsResult
|
-> Maybe Text -> Maybe Int -> Minio ListUploadsResult
|
||||||
listIncompleteUploads' bucket prefix delimiter keyMarker uploadIdMarker maxKeys = do
|
listIncompleteUploads' bucket prefix delimiter keyMarker uploadIdMarker maxKeys = do
|
||||||
resp <- executeRequest $ def { riMethod = HT.methodGet
|
resp <- executeRequest $ defaultS3ReqInfo { riMethod = HT.methodGet
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riQueryParams = params
|
, riQueryParams = params
|
||||||
}
|
}
|
||||||
@ -386,7 +385,7 @@ listIncompleteUploads' bucket prefix delimiter keyMarker uploadIdMarker maxKeys
|
|||||||
listIncompleteParts' :: Bucket -> Object -> UploadId -> Maybe Text
|
listIncompleteParts' :: Bucket -> Object -> UploadId -> Maybe Text
|
||||||
-> Maybe Text -> Minio ListPartsResult
|
-> Maybe Text -> Minio ListPartsResult
|
||||||
listIncompleteParts' bucket object uploadId maxParts partNumMarker = do
|
listIncompleteParts' bucket object uploadId maxParts partNumMarker = do
|
||||||
resp <- executeRequest $ def { riMethod = HT.methodGet
|
resp <- executeRequest $ defaultS3ReqInfo { riMethod = HT.methodGet
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riObject = Just object
|
, riObject = Just object
|
||||||
, riQueryParams = mkOptionalParams params
|
, riQueryParams = mkOptionalParams params
|
||||||
@ -403,7 +402,7 @@ listIncompleteParts' bucket object uploadId maxParts partNumMarker = do
|
|||||||
-- | Get metadata of an object.
|
-- | Get metadata of an object.
|
||||||
headObject :: Bucket -> Object -> Minio ObjectInfo
|
headObject :: Bucket -> Object -> Minio ObjectInfo
|
||||||
headObject bucket object = do
|
headObject bucket object = do
|
||||||
resp <- executeRequest $ def { riMethod = HT.methodHead
|
resp <- executeRequest $ defaultS3ReqInfo { riMethod = HT.methodHead
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riObject = Just object
|
, riObject = Just object
|
||||||
}
|
}
|
||||||
@ -439,7 +438,7 @@ headBucket bucket = headBucketEx `catches`
|
|||||||
handleStatus404 e = throwIO e
|
handleStatus404 e = throwIO e
|
||||||
|
|
||||||
headBucketEx = do
|
headBucketEx = do
|
||||||
resp <- executeRequest $ def { riMethod = HT.methodHead
|
resp <- executeRequest $ defaultS3ReqInfo { riMethod = HT.methodHead
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
}
|
}
|
||||||
return $ NC.responseStatus resp == HT.ok200
|
return $ NC.responseStatus resp == HT.ok200
|
||||||
@ -448,7 +447,7 @@ headBucket bucket = headBucketEx `catches`
|
|||||||
putBucketNotification :: Bucket -> Notification -> Minio ()
|
putBucketNotification :: Bucket -> Notification -> Minio ()
|
||||||
putBucketNotification bucket ncfg = do
|
putBucketNotification bucket ncfg = do
|
||||||
ns <- asks getSvcNamespace
|
ns <- asks getSvcNamespace
|
||||||
void $ executeRequest $ def { riMethod = HT.methodPut
|
void $ executeRequest $ defaultS3ReqInfo { riMethod = HT.methodPut
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riQueryParams = [("notification", Nothing)]
|
, riQueryParams = [("notification", Nothing)]
|
||||||
, riPayload = PayloadBS $
|
, riPayload = PayloadBS $
|
||||||
@ -458,7 +457,7 @@ putBucketNotification bucket ncfg = do
|
|||||||
-- | Retrieve the notification configuration on a bucket.
|
-- | Retrieve the notification configuration on a bucket.
|
||||||
getBucketNotification :: Bucket -> Minio Notification
|
getBucketNotification :: Bucket -> Minio Notification
|
||||||
getBucketNotification bucket = do
|
getBucketNotification bucket = do
|
||||||
resp <- executeRequest $ def { riMethod = HT.methodGet
|
resp <- executeRequest $ defaultS3ReqInfo { riMethod = HT.methodGet
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riQueryParams = [("notification", Nothing)]
|
, riQueryParams = [("notification", Nothing)]
|
||||||
}
|
}
|
||||||
@ -466,12 +465,12 @@ getBucketNotification bucket = do
|
|||||||
|
|
||||||
-- | Remove all notifications configured on a bucket.
|
-- | Remove all notifications configured on a bucket.
|
||||||
removeAllBucketNotification :: Bucket -> Minio ()
|
removeAllBucketNotification :: Bucket -> Minio ()
|
||||||
removeAllBucketNotification = flip putBucketNotification def
|
removeAllBucketNotification = flip putBucketNotification defaultNotification
|
||||||
|
|
||||||
-- | Fetch the policy if any on a bucket.
|
-- | Fetch the policy if any on a bucket.
|
||||||
getBucketPolicy :: Bucket -> Minio Text
|
getBucketPolicy :: Bucket -> Minio Text
|
||||||
getBucketPolicy bucket = do
|
getBucketPolicy bucket = do
|
||||||
resp <- executeRequest $ def { riMethod = HT.methodGet
|
resp <- executeRequest $ defaultS3ReqInfo { riMethod = HT.methodGet
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riQueryParams = [("policy", Nothing)]
|
, riQueryParams = [("policy", Nothing)]
|
||||||
}
|
}
|
||||||
@ -489,7 +488,7 @@ setBucketPolicy bucket policy = do
|
|||||||
-- | Save a new policy on a bucket.
|
-- | Save a new policy on a bucket.
|
||||||
putBucketPolicy :: Bucket -> Text -> Minio()
|
putBucketPolicy :: Bucket -> Text -> Minio()
|
||||||
putBucketPolicy bucket policy = do
|
putBucketPolicy bucket policy = do
|
||||||
void $ executeRequest $ def { riMethod = HT.methodPut
|
void $ executeRequest $ defaultS3ReqInfo { riMethod = HT.methodPut
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riQueryParams = [("policy", Nothing)]
|
, riQueryParams = [("policy", Nothing)]
|
||||||
, riPayload = PayloadBS $ encodeUtf8 policy
|
, riPayload = PayloadBS $ encodeUtf8 policy
|
||||||
@ -498,7 +497,7 @@ putBucketPolicy bucket policy = do
|
|||||||
-- | Delete any policy set on a bucket.
|
-- | Delete any policy set on a bucket.
|
||||||
deleteBucketPolicy :: Bucket -> Minio()
|
deleteBucketPolicy :: Bucket -> Minio()
|
||||||
deleteBucketPolicy bucket = do
|
deleteBucketPolicy bucket = do
|
||||||
void $ executeRequest $ def { riMethod = HT.methodDelete
|
void $ executeRequest $ defaultS3ReqInfo { riMethod = HT.methodDelete
|
||||||
, riBucket = Just bucket
|
, riBucket = Just bucket
|
||||||
, riQueryParams = [("policy", Nothing)]
|
, riQueryParams = [("policy", Nothing)]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,6 @@ import qualified Network.HTTP.Types.Header as H
|
|||||||
|
|
||||||
import Lib.Prelude
|
import Lib.Prelude
|
||||||
|
|
||||||
import Network.Minio.Data
|
|
||||||
import Network.Minio.Data.ByteString
|
import Network.Minio.Data.ByteString
|
||||||
import Network.Minio.Data.Crypto
|
import Network.Minio.Data.Crypto
|
||||||
import Network.Minio.Data.Time
|
import Network.Minio.Data.Time
|
||||||
@ -72,7 +71,7 @@ data SignParams = SignParams {
|
|||||||
spAccessKey :: Text
|
spAccessKey :: Text
|
||||||
, spSecretKey :: Text
|
, spSecretKey :: Text
|
||||||
, spTimeStamp :: UTCTime
|
, spTimeStamp :: UTCTime
|
||||||
, spRegion :: Maybe Region
|
, spRegion :: Maybe Text
|
||||||
, spExpirySecs :: Maybe Int
|
, spExpirySecs :: Maybe Int
|
||||||
, spPayloadHash :: Maybe ByteString
|
, spPayloadHash :: Maybe ByteString
|
||||||
} deriving (Show)
|
} deriving (Show)
|
||||||
@ -174,7 +173,7 @@ signV4 !sp !req =
|
|||||||
in output
|
in output
|
||||||
|
|
||||||
|
|
||||||
mkScope :: UTCTime -> Region -> ByteString
|
mkScope :: UTCTime -> Text -> ByteString
|
||||||
mkScope ts region = B.intercalate "/"
|
mkScope ts region = B.intercalate "/"
|
||||||
[ toS $ Time.formatTime Time.defaultTimeLocale "%Y%m%d" ts
|
[ toS $ Time.formatTime Time.defaultTimeLocale "%Y%m%d" ts
|
||||||
, toS region
|
, toS region
|
||||||
@ -222,7 +221,7 @@ mkStringToSign ts !scope !canonicalRequest = B.intercalate "\n"
|
|||||||
, hashSHA256 canonicalRequest
|
, hashSHA256 canonicalRequest
|
||||||
]
|
]
|
||||||
|
|
||||||
mkSigningKey :: UTCTime -> Region -> ByteString -> ByteString
|
mkSigningKey :: UTCTime -> Text -> ByteString -> ByteString
|
||||||
mkSigningKey ts region !secretKey = hmacSHA256RawBS "aws4_request"
|
mkSigningKey ts region !secretKey = hmacSHA256RawBS "aws4_request"
|
||||||
. hmacSHA256RawBS "s3"
|
. hmacSHA256RawBS "s3"
|
||||||
. hmacSHA256RawBS (toS region)
|
. hmacSHA256RawBS (toS region)
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
--
|
--
|
||||||
-- Minio Haskell SDK, (C) 2017, 2018 Minio, Inc.
|
-- Minio Haskell SDK, (C) 2017, 2018 Minio, Inc.
|
||||||
--
|
--
|
||||||
@ -26,7 +27,6 @@ import Data.Conduit (yield)
|
|||||||
import qualified Data.Conduit as C
|
import qualified Data.Conduit as C
|
||||||
import qualified Data.Conduit.Binary as CB
|
import qualified Data.Conduit.Binary as CB
|
||||||
import Data.Conduit.Combinators (sinkList)
|
import Data.Conduit.Combinators (sinkList)
|
||||||
import Data.Default (Default (..))
|
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Data.Time (fromGregorian)
|
import Data.Time (fromGregorian)
|
||||||
@ -83,12 +83,15 @@ funTestWithBucket t minioTest = testCaseSteps t $ \step -> do
|
|||||||
bktSuffix <- liftIO $ generate $ Q.vectorOf 10 (Q.choose ('a', 'z'))
|
bktSuffix <- liftIO $ generate $ Q.vectorOf 10 (Q.choose ('a', 'z'))
|
||||||
let b = T.concat [funTestBucketPrefix, T.pack bktSuffix]
|
let b = T.concat [funTestBucketPrefix, T.pack bktSuffix]
|
||||||
liftStep = liftIO . step
|
liftStep = liftIO . step
|
||||||
connInfo <- maybe minioPlayCI (const def) <$> lookupEnv "MINIO_LOCAL"
|
connInfo <- ( bool minioPlayCI
|
||||||
|
( setCreds (Credentials "minio" "minio123") "http://localhost:9000" )
|
||||||
|
. isJust
|
||||||
|
) <$> lookupEnv "MINIO_LOCAL"
|
||||||
ret <- runMinio connInfo $ do
|
ret <- runMinio connInfo $ do
|
||||||
liftStep $ "Creating bucket for test - " ++ t
|
liftStep $ "Creating bucket for test - " ++ t
|
||||||
foundBucket <- bucketExists b
|
foundBucket <- bucketExists b
|
||||||
liftIO $ foundBucket @?= False
|
liftIO $ foundBucket @?= False
|
||||||
makeBucket b def
|
makeBucket b Nothing
|
||||||
minioTest liftStep b
|
minioTest liftStep b
|
||||||
deleteBucket b
|
deleteBucket b
|
||||||
isRight ret @? ("Functional test " ++ t ++ " failed => " ++ show ret)
|
isRight ret @? ("Functional test " ++ t ++ " failed => " ++ show ret)
|
||||||
@ -116,7 +119,7 @@ lowLevelMultipartTest = funTestWithBucket "Low-level Multipart Test" $
|
|||||||
|
|
||||||
destFile <- mkRandFile 0
|
destFile <- mkRandFile 0
|
||||||
step "Retrieve the created object and check size"
|
step "Retrieve the created object and check size"
|
||||||
fGetObject bucket object destFile def
|
fGetObject bucket object destFile defaultGetObjectOptions
|
||||||
gotSize <- withNewHandle destFile getFileSize
|
gotSize <- withNewHandle destFile getFileSize
|
||||||
liftIO $ gotSize == Right (Just mb15) @?
|
liftIO $ gotSize == Right (Just mb15) @?
|
||||||
"Wrong file size of put file after getting"
|
"Wrong file size of put file after getting"
|
||||||
@ -135,11 +138,11 @@ putObjectSizeTest = funTestWithBucket "PutObject of conduit source with size" $
|
|||||||
rFile <- mkRandFile mb1
|
rFile <- mkRandFile mb1
|
||||||
|
|
||||||
step "Upload single file."
|
step "Upload single file."
|
||||||
putObject bucket obj (CB.sourceFile rFile) (Just mb1) def
|
putObject bucket obj (CB.sourceFile rFile) (Just mb1) defaultPutObjectOptions
|
||||||
|
|
||||||
step "Retrieve and verify file size"
|
step "Retrieve and verify file size"
|
||||||
destFile <- mkRandFile 0
|
destFile <- mkRandFile 0
|
||||||
fGetObject bucket obj destFile def
|
fGetObject bucket obj destFile defaultGetObjectOptions
|
||||||
gotSize <- withNewHandle destFile getFileSize
|
gotSize <- withNewHandle destFile getFileSize
|
||||||
liftIO $ gotSize == Right (Just mb1) @?
|
liftIO $ gotSize == Right (Just mb1) @?
|
||||||
"Wrong file size of put file after getting"
|
"Wrong file size of put file after getting"
|
||||||
@ -158,11 +161,11 @@ putObjectNoSizeTest = funTestWithBucket "PutObject of conduit source with no siz
|
|||||||
rFile <- mkRandFile mb70
|
rFile <- mkRandFile mb70
|
||||||
|
|
||||||
step "Upload multipart file."
|
step "Upload multipart file."
|
||||||
putObject bucket obj (CB.sourceFile rFile) Nothing def
|
putObject bucket obj (CB.sourceFile rFile) Nothing defaultPutObjectOptions
|
||||||
|
|
||||||
step "Retrieve and verify file size"
|
step "Retrieve and verify file size"
|
||||||
destFile <- mkRandFile 0
|
destFile <- mkRandFile 0
|
||||||
fGetObject bucket obj destFile def
|
fGetObject bucket obj destFile defaultGetObjectOptions
|
||||||
gotSize <- withNewHandle destFile getFileSize
|
gotSize <- withNewHandle destFile getFileSize
|
||||||
liftIO $ gotSize == Right (Just mb70) @?
|
liftIO $ gotSize == Right (Just mb70) @?
|
||||||
"Wrong file size of put file after getting"
|
"Wrong file size of put file after getting"
|
||||||
@ -177,7 +180,7 @@ highLevelListingTest = funTestWithBucket "High-level listObjects Test" $
|
|||||||
step "put 3 objects"
|
step "put 3 objects"
|
||||||
let expectedObjects = ["dir/o1", "dir/dir1/o2", "dir/dir2/o3"]
|
let expectedObjects = ["dir/o1", "dir/dir1/o2", "dir/dir2/o3"]
|
||||||
forM_ expectedObjects $
|
forM_ expectedObjects $
|
||||||
\obj -> fPutObject bucket obj "/etc/lsb-release" def
|
\obj -> fPutObject bucket obj "/etc/lsb-release" defaultPutObjectOptions
|
||||||
|
|
||||||
step "High-level listing of objects"
|
step "High-level listing of objects"
|
||||||
objects <- C.runConduit $ listObjects bucket Nothing True C..| sinkList
|
objects <- C.runConduit $ listObjects bucket Nothing True C..| sinkList
|
||||||
@ -241,7 +244,7 @@ listingTest = funTestWithBucket "Listing Test" $ \step bucket -> do
|
|||||||
let objects = (\s ->T.concat ["lsb-release", T.pack (show s)]) <$> [1..10::Int]
|
let objects = (\s ->T.concat ["lsb-release", T.pack (show s)]) <$> [1..10::Int]
|
||||||
|
|
||||||
forM_ [1..10::Int] $ \s ->
|
forM_ [1..10::Int] $ \s ->
|
||||||
fPutObject bucket (T.concat ["lsb-release", T.pack (show s)]) "/etc/lsb-release" def
|
fPutObject bucket (T.concat ["lsb-release", T.pack (show s)]) "/etc/lsb-release" defaultPutObjectOptions
|
||||||
|
|
||||||
step "Simple list"
|
step "Simple list"
|
||||||
res <- listObjects' bucket Nothing Nothing Nothing Nothing
|
res <- listObjects' bucket Nothing Nothing Nothing Nothing
|
||||||
@ -312,11 +315,11 @@ liveServerUnitTests = testGroup "Unit tests against a live server"
|
|||||||
let mb80 = 80 * 1024 * 1024
|
let mb80 = 80 * 1024 * 1024
|
||||||
obj = "mpart"
|
obj = "mpart"
|
||||||
|
|
||||||
void $ putObjectInternal bucket obj def $ ODFile "/dev/zero" (Just mb80)
|
void $ putObjectInternal bucket obj defaultPutObjectOptions $ ODFile "/dev/zero" (Just mb80)
|
||||||
|
|
||||||
step "Retrieve and verify file size"
|
step "Retrieve and verify file size"
|
||||||
destFile <- mkRandFile 0
|
destFile <- mkRandFile 0
|
||||||
fGetObject bucket obj destFile def
|
fGetObject bucket obj destFile defaultGetObjectOptions
|
||||||
gotSize <- withNewHandle destFile getFileSize
|
gotSize <- withNewHandle destFile getFileSize
|
||||||
liftIO $ gotSize == Right (Just mb80) @?
|
liftIO $ gotSize == Right (Just mb80) @?
|
||||||
"Wrong file size of put file after getting"
|
"Wrong file size of put file after getting"
|
||||||
@ -356,7 +359,7 @@ liveServerUnitTests = testGroup "Unit tests against a live server"
|
|||||||
|
|
||||||
step "create server object with content-type"
|
step "create server object with content-type"
|
||||||
inputFile <- mkRandFile size1
|
inputFile <- mkRandFile size1
|
||||||
fPutObject bucket object inputFile def{
|
fPutObject bucket object inputFile defaultPutObjectOptions {
|
||||||
pooContentType = Just "application/javascript"
|
pooContentType = Just "application/javascript"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,7 +371,7 @@ liveServerUnitTests = testGroup "Unit tests against a live server"
|
|||||||
liftIO $ assertEqual "Content-Type did not match" (Just "application/javascript") (Map.lookup "Content-Type" m)
|
liftIO $ assertEqual "Content-Type did not match" (Just "application/javascript") (Map.lookup "Content-Type" m)
|
||||||
|
|
||||||
step "upload object with content-encoding set to identity"
|
step "upload object with content-encoding set to identity"
|
||||||
fPutObject bucket object inputFile def {
|
fPutObject bucket object inputFile defaultPutObjectOptions {
|
||||||
pooContentEncoding = Just "identity"
|
pooContentEncoding = Just "identity"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,7 +393,7 @@ liveServerUnitTests = testGroup "Unit tests against a live server"
|
|||||||
|
|
||||||
step "create server object with content-language"
|
step "create server object with content-language"
|
||||||
inputFile <- mkRandFile size1
|
inputFile <- mkRandFile size1
|
||||||
fPutObject bucket object inputFile def{
|
fPutObject bucket object inputFile defaultPutObjectOptions {
|
||||||
pooContentLanguage = Just "en-US"
|
pooContentLanguage = Just "en-US"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -418,11 +421,11 @@ liveServerUnitTests = testGroup "Unit tests against a live server"
|
|||||||
inputFile' <- mkRandFile size1
|
inputFile' <- mkRandFile size1
|
||||||
inputFile'' <- mkRandFile size0
|
inputFile'' <- mkRandFile size0
|
||||||
|
|
||||||
fPutObject bucket object inputFile def{
|
fPutObject bucket object inputFile defaultPutObjectOptions {
|
||||||
pooStorageClass = Just "STANDARD"
|
pooStorageClass = Just "STANDARD"
|
||||||
}
|
}
|
||||||
|
|
||||||
fPutObject bucket object' inputFile' def{
|
fPutObject bucket object' inputFile' defaultPutObjectOptions {
|
||||||
pooStorageClass = Just "REDUCED_REDUNDANCY"
|
pooStorageClass = Just "REDUCED_REDUNDANCY"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,7 +439,7 @@ liveServerUnitTests = testGroup "Unit tests against a live server"
|
|||||||
liftIO $ assertEqual "storageClass did not match" (Just "REDUCED_REDUNDANCY")
|
liftIO $ assertEqual "storageClass did not match" (Just "REDUCED_REDUNDANCY")
|
||||||
(Map.lookup "X-Amz-Storage-Class" m')
|
(Map.lookup "X-Amz-Storage-Class" m')
|
||||||
|
|
||||||
fpE <- try $ fPutObject bucket object'' inputFile'' def{
|
fpE <- try $ fPutObject bucket object'' inputFile'' defaultPutObjectOptions {
|
||||||
pooStorageClass = Just "INVALID_STORAGE_CLASS"
|
pooStorageClass = Just "INVALID_STORAGE_CLASS"
|
||||||
}
|
}
|
||||||
case fpE of
|
case fpE of
|
||||||
@ -455,10 +458,10 @@ liveServerUnitTests = testGroup "Unit tests against a live server"
|
|||||||
|
|
||||||
step "create server object to copy"
|
step "create server object to copy"
|
||||||
inputFile <- mkRandFile size1
|
inputFile <- mkRandFile size1
|
||||||
fPutObject bucket object inputFile def
|
fPutObject bucket object inputFile defaultPutObjectOptions
|
||||||
|
|
||||||
step "copy object"
|
step "copy object"
|
||||||
let srcInfo = def { srcBucket = bucket, srcObject = object}
|
let srcInfo = defaultSourceInfo { srcBucket = bucket, srcObject = object}
|
||||||
(etag, modTime) <- copyObjectSingle bucket objCopy srcInfo []
|
(etag, modTime) <- copyObjectSingle bucket objCopy srcInfo []
|
||||||
|
|
||||||
-- retrieve obj info to check
|
-- retrieve obj info to check
|
||||||
@ -484,15 +487,15 @@ liveServerUnitTests = testGroup "Unit tests against a live server"
|
|||||||
let mb15 = 15 * 1024 * 1024
|
let mb15 = 15 * 1024 * 1024
|
||||||
mb5 = 5 * 1024 * 1024
|
mb5 = 5 * 1024 * 1024
|
||||||
randFile <- mkRandFile mb15
|
randFile <- mkRandFile mb15
|
||||||
fPutObject bucket srcObj randFile def
|
fPutObject bucket srcObj randFile defaultPutObjectOptions
|
||||||
|
|
||||||
step "create new multipart upload"
|
step "create new multipart upload"
|
||||||
uid <- newMultipartUpload bucket copyObj []
|
uid <- newMultipartUpload bucket copyObj []
|
||||||
liftIO $ (T.length uid > 0) @? "Got an empty multipartUpload Id."
|
liftIO $ (T.length uid > 0) @? "Got an empty multipartUpload Id."
|
||||||
|
|
||||||
step "put object parts 1-3"
|
step "put object parts 1-3"
|
||||||
let srcInfo' = def { srcBucket = bucket, srcObject = srcObj }
|
let srcInfo' = defaultSourceInfo { srcBucket = bucket, srcObject = srcObj }
|
||||||
dstInfo' = def { dstBucket = bucket, dstObject = copyObj }
|
dstInfo' = defaultDestinationInfo { dstBucket = bucket, dstObject = copyObj }
|
||||||
parts <- forM [1..3] $ \p -> do
|
parts <- forM [1..3] $ \p -> do
|
||||||
(etag', _) <- copyObjectPart dstInfo' srcInfo'{
|
(etag', _) <- copyObjectPart dstInfo' srcInfo'{
|
||||||
srcRange = Just $ (,) ((p-1)*mb5) ((p-1)*mb5 + (mb5 - 1))
|
srcRange = Just $ (,) ((p-1)*mb5) ((p-1)*mb5 + (mb5 - 1))
|
||||||
@ -520,11 +523,11 @@ liveServerUnitTests = testGroup "Unit tests against a live server"
|
|||||||
step "Prepare"
|
step "Prepare"
|
||||||
forM_ (zip srcs sizes) $ \(src, size) -> do
|
forM_ (zip srcs sizes) $ \(src, size) -> do
|
||||||
inputFile' <- mkRandFile size
|
inputFile' <- mkRandFile size
|
||||||
fPutObject bucket src inputFile' def
|
fPutObject bucket src inputFile' defaultPutObjectOptions
|
||||||
|
|
||||||
step "make small and large object copy"
|
step "make small and large object copy"
|
||||||
forM_ (zip copyObjs srcs) $ \(cp, src) ->
|
forM_ (zip copyObjs srcs) $ \(cp, src) ->
|
||||||
copyObject def {dstBucket = bucket, dstObject = cp} def{srcBucket = bucket, srcObject = src}
|
copyObject defaultDestinationInfo {dstBucket = bucket, dstObject = cp} defaultSourceInfo {srcBucket = bucket, srcObject = src}
|
||||||
|
|
||||||
step "verify uploaded objects"
|
step "verify uploaded objects"
|
||||||
uploadedSizes <- fmap oiSize <$> forM copyObjs (headObject bucket)
|
uploadedSizes <- fmap oiSize <$> forM copyObjs (headObject bucket)
|
||||||
@ -539,10 +542,10 @@ liveServerUnitTests = testGroup "Unit tests against a live server"
|
|||||||
|
|
||||||
step "Prepare"
|
step "Prepare"
|
||||||
inputFile' <- mkRandFile size
|
inputFile' <- mkRandFile size
|
||||||
fPutObject bucket src inputFile' def
|
fPutObject bucket src inputFile' defaultPutObjectOptions
|
||||||
|
|
||||||
step "copy last 10MiB of object"
|
step "copy last 10MiB of object"
|
||||||
copyObject def { dstBucket = bucket, dstObject = copyObj } def{
|
copyObject defaultDestinationInfo { dstBucket = bucket, dstObject = copyObj } defaultSourceInfo {
|
||||||
srcBucket = bucket
|
srcBucket = bucket
|
||||||
, srcObject = src
|
, srcObject = src
|
||||||
, srcRange = Just $ (,) (5 * 1024 * 1024) (size - 1)
|
, srcRange = Just $ (,) (5 * 1024 * 1024) (size - 1)
|
||||||
@ -586,21 +589,21 @@ basicTests = funTestWithBucket "Basic tests" $ \step bucket -> do
|
|||||||
liftIO $ region == "us-east-1" @? ("Got unexpected region => " ++ show region)
|
liftIO $ region == "us-east-1" @? ("Got unexpected region => " ++ show region)
|
||||||
|
|
||||||
step "singlepart putObject works"
|
step "singlepart putObject works"
|
||||||
fPutObject bucket "lsb-release" "/etc/lsb-release" def
|
fPutObject bucket "lsb-release" "/etc/lsb-release" defaultPutObjectOptions
|
||||||
|
|
||||||
step "fPutObject onto a non-existent bucket and check for NoSuchBucket exception"
|
step "fPutObject onto a non-existent bucket and check for NoSuchBucket exception"
|
||||||
fpE <- try $ fPutObject "nosuchbucket" "lsb-release" "/etc/lsb-release" def
|
fpE <- try $ fPutObject "nosuchbucket" "lsb-release" "/etc/lsb-release" defaultPutObjectOptions
|
||||||
case fpE of
|
case fpE of
|
||||||
Left exn -> liftIO $ exn @?= NoSuchBucket
|
Left exn -> liftIO $ exn @?= NoSuchBucket
|
||||||
_ -> return ()
|
_ -> return ()
|
||||||
|
|
||||||
outFile <- mkRandFile 0
|
outFile <- mkRandFile 0
|
||||||
step "simple fGetObject works"
|
step "simple fGetObject works"
|
||||||
fGetObject bucket "lsb-release" outFile def
|
fGetObject bucket "lsb-release" outFile defaultGetObjectOptions
|
||||||
|
|
||||||
let unmodifiedTime = UTCTime (fromGregorian 2010 11 26) 69857
|
let unmodifiedTime = UTCTime (fromGregorian 2010 11 26) 69857
|
||||||
step "fGetObject an object which is modified now but requesting as un-modified in past, check for exception"
|
step "fGetObject an object which is modified now but requesting as un-modified in past, check for exception"
|
||||||
resE <- try $ fGetObject bucket "lsb-release" outFile def{
|
resE <- try $ fGetObject bucket "lsb-release" outFile defaultGetObjectOptions {
|
||||||
gooIfUnmodifiedSince = (Just unmodifiedTime)
|
gooIfUnmodifiedSince = (Just unmodifiedTime)
|
||||||
}
|
}
|
||||||
case resE of
|
case resE of
|
||||||
@ -608,7 +611,7 @@ basicTests = funTestWithBucket "Basic tests" $ \step bucket -> do
|
|||||||
_ -> return ()
|
_ -> return ()
|
||||||
|
|
||||||
step "fGetObject an object with no matching etag, check for exception"
|
step "fGetObject an object with no matching etag, check for exception"
|
||||||
resE1 <- try $ fGetObject bucket "lsb-release" outFile def{
|
resE1 <- try $ fGetObject bucket "lsb-release" outFile defaultGetObjectOptions {
|
||||||
gooIfMatch = (Just "invalid-etag")
|
gooIfMatch = (Just "invalid-etag")
|
||||||
}
|
}
|
||||||
case resE1 of
|
case resE1 of
|
||||||
@ -616,7 +619,7 @@ basicTests = funTestWithBucket "Basic tests" $ \step bucket -> do
|
|||||||
_ -> return ()
|
_ -> return ()
|
||||||
|
|
||||||
step "fGetObject an object with no valid range, check for exception"
|
step "fGetObject an object with no valid range, check for exception"
|
||||||
resE2 <- try $ fGetObject bucket "lsb-release" outFile def{
|
resE2 <- try $ fGetObject bucket "lsb-release" outFile defaultGetObjectOptions {
|
||||||
gooRange = (Just $ HT.ByteRangeFromTo 100 200)
|
gooRange = (Just $ HT.ByteRangeFromTo 100 200)
|
||||||
}
|
}
|
||||||
case resE2 of
|
case resE2 of
|
||||||
@ -624,12 +627,12 @@ basicTests = funTestWithBucket "Basic tests" $ \step bucket -> do
|
|||||||
_ -> return ()
|
_ -> return ()
|
||||||
|
|
||||||
step "fGetObject on object with a valid range"
|
step "fGetObject on object with a valid range"
|
||||||
fGetObject bucket "lsb-release" outFile def{
|
fGetObject bucket "lsb-release" outFile defaultGetObjectOptions {
|
||||||
gooRange = (Just $ HT.ByteRangeFrom 1)
|
gooRange = (Just $ HT.ByteRangeFrom 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
step "fGetObject a non-existent object and check for NoSuchKey exception"
|
step "fGetObject a non-existent object and check for NoSuchKey exception"
|
||||||
resE3 <- try $ fGetObject bucket "noSuchKey" outFile def
|
resE3 <- try $ fGetObject bucket "noSuchKey" outFile defaultGetObjectOptions
|
||||||
case resE3 of
|
case resE3 of
|
||||||
Left exn -> liftIO $ exn @?= NoSuchKey
|
Left exn -> liftIO $ exn @?= NoSuchKey
|
||||||
_ -> return ()
|
_ -> return ()
|
||||||
@ -648,7 +651,7 @@ basicTests = funTestWithBucket "Basic tests" $ \step bucket -> do
|
|||||||
let object = "sample"
|
let object = "sample"
|
||||||
step "create an object"
|
step "create an object"
|
||||||
inputFile <- mkRandFile 0
|
inputFile <- mkRandFile 0
|
||||||
fPutObject bucket object inputFile def
|
fPutObject bucket object inputFile defaultPutObjectOptions
|
||||||
|
|
||||||
step "get metadata of the object"
|
step "get metadata of the object"
|
||||||
res <- statObject bucket object
|
res <- statObject bucket object
|
||||||
@ -814,7 +817,7 @@ bucketPolicyFunTest = funTestWithBucket "Bucket Policy tests" $
|
|||||||
let obj = "myobject"
|
let obj = "myobject"
|
||||||
|
|
||||||
step "verify bucket policy: (1) create `myobject`"
|
step "verify bucket policy: (1) create `myobject`"
|
||||||
putObject bucket obj (replicateC 100 "c") Nothing def
|
putObject bucket obj (replicateC 100 "c") Nothing defaultPutObjectOptions
|
||||||
|
|
||||||
step "verify bucket policy: (2) get `myobject` anonymously"
|
step "verify bucket policy: (2) get `myobject` anonymously"
|
||||||
connInfo <- asks mcConnInfo
|
connInfo <- asks mcConnInfo
|
||||||
|
|||||||
@ -23,8 +23,6 @@ import Test.Tasty.HUnit
|
|||||||
|
|
||||||
import Lib.Prelude
|
import Lib.Prelude
|
||||||
|
|
||||||
import Data.Default (def)
|
|
||||||
|
|
||||||
import Network.Minio.Data
|
import Network.Minio.Data
|
||||||
import Network.Minio.TestHelpers
|
import Network.Minio.TestHelpers
|
||||||
import Network.Minio.XmlGenerator
|
import Network.Minio.XmlGenerator
|
||||||
@ -74,7 +72,7 @@ testMkPutNotificationRequest =
|
|||||||
[ NotificationConfig
|
[ NotificationConfig
|
||||||
"YjVkM2Y0YmUtNGI3NC00ZjQyLWEwNGItNDIyYWUxY2I0N2M4"
|
"YjVkM2Y0YmUtNGI3NC00ZjQyLWEwNGItNDIyYWUxY2I0N2M4"
|
||||||
"arn:aws:sns:us-east-1:account-id:s3notificationtopic2"
|
"arn:aws:sns:us-east-1:account-id:s3notificationtopic2"
|
||||||
[ReducedRedundancyLostObject, ObjectCreated] def
|
[ReducedRedundancyLostObject, ObjectCreated] defaultFilter
|
||||||
]
|
]
|
||||||
[]
|
[]
|
||||||
, Notification
|
, Notification
|
||||||
@ -86,14 +84,14 @@ testMkPutNotificationRequest =
|
|||||||
, FilterRule "suffix" ".jpg"])
|
, FilterRule "suffix" ".jpg"])
|
||||||
, NotificationConfig
|
, NotificationConfig
|
||||||
"" "arn:aws:sqs:us-east-1:356671443308:s3notificationqueue"
|
"" "arn:aws:sqs:us-east-1:356671443308:s3notificationqueue"
|
||||||
[ObjectCreated] def
|
[ObjectCreated] defaultFilter
|
||||||
]
|
]
|
||||||
[ NotificationConfig
|
[ NotificationConfig
|
||||||
"" "arn:aws:sns:us-east-1:356671443308:s3notificationtopic2"
|
"" "arn:aws:sns:us-east-1:356671443308:s3notificationtopic2"
|
||||||
[ReducedRedundancyLostObject] def
|
[ReducedRedundancyLostObject] defaultFilter
|
||||||
]
|
]
|
||||||
[ NotificationConfig
|
[ NotificationConfig
|
||||||
"ObjectCreatedEvents" "arn:aws:lambda:us-west-2:35667example:function:CreateThumbnail"
|
"ObjectCreatedEvents" "arn:aws:lambda:us-west-2:35667example:function:CreateThumbnail"
|
||||||
[ObjectCreated] def
|
[ObjectCreated] defaultFilter
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@ -19,7 +19,6 @@ module Network.Minio.XmlParser.Test
|
|||||||
xmlParserTests
|
xmlParserTests
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.Default (def)
|
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import Data.Time (fromGregorian)
|
import Data.Time (fromGregorian)
|
||||||
import Test.Tasty
|
import Test.Tasty
|
||||||
@ -299,7 +298,7 @@ testParseNotification = do
|
|||||||
[ NotificationConfig
|
[ NotificationConfig
|
||||||
"YjVkM2Y0YmUtNGI3NC00ZjQyLWEwNGItNDIyYWUxY2I0N2M4"
|
"YjVkM2Y0YmUtNGI3NC00ZjQyLWEwNGItNDIyYWUxY2I0N2M4"
|
||||||
"arn:aws:sns:us-east-1:account-id:s3notificationtopic2"
|
"arn:aws:sns:us-east-1:account-id:s3notificationtopic2"
|
||||||
[ReducedRedundancyLostObject, ObjectCreated] def
|
[ReducedRedundancyLostObject, ObjectCreated] defaultFilter
|
||||||
]
|
]
|
||||||
[])
|
[])
|
||||||
, ("<NotificationConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">\
|
, ("<NotificationConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">\
|
||||||
@ -342,15 +341,15 @@ testParseNotification = do
|
|||||||
FilterRule "suffix" ".jpg"])
|
FilterRule "suffix" ".jpg"])
|
||||||
, NotificationConfig
|
, NotificationConfig
|
||||||
"" "arn:aws:sqs:us-east-1:356671443308:s3notificationqueue"
|
"" "arn:aws:sqs:us-east-1:356671443308:s3notificationqueue"
|
||||||
[ObjectCreated] def
|
[ObjectCreated] defaultFilter
|
||||||
]
|
]
|
||||||
[ NotificationConfig
|
[ NotificationConfig
|
||||||
"" "arn:aws:sns:us-east-1:356671443308:s3notificationtopic2"
|
"" "arn:aws:sns:us-east-1:356671443308:s3notificationtopic2"
|
||||||
[ReducedRedundancyLostObject] def
|
[ReducedRedundancyLostObject] defaultFilter
|
||||||
]
|
]
|
||||||
[ NotificationConfig
|
[ NotificationConfig
|
||||||
"ObjectCreatedEvents" "arn:aws:lambda:us-west-2:35667example:function:CreateThumbnail"
|
"ObjectCreatedEvents" "arn:aws:lambda:us-west-2:35667example:function:CreateThumbnail"
|
||||||
[ObjectCreated] def
|
[ObjectCreated] defaultFilter
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user