@@ -1,13 +1,20 @@
1+{-# LANGUAGE Arrows #-}
1module Network.Azure.ServiceManagement
2module Network.Azure.ServiceManagement
2− ( -- * Submitting requests
3+ ( -- * Setup
3− azureRequest
9+ , azureRequest
4− -- * Re-export functionality from TLS
10+ , azureRawRequest
13+import Prelude hiding (id)
14+import Control.Category (id, (>>>))
9import Data.ByteString.Lazy (ByteString)
15import Data.ByteString.Lazy (ByteString)
10import Data.ByteString.Char8 as BSC (pack)
16import Data.ByteString.Char8 as BSC (pack)
17+import Data.ByteString.Lazy.Char8 as BSLC (unpack)
11import Network.TLS (PrivateKey)
18import Network.TLS (PrivateKey)
12import Network.TLS.Extra (fileReadCertificate, fileReadPrivateKey)
19import Network.TLS.Extra (fileReadCertificate, fileReadPrivateKey)
13import Data.Certificate.X509 (X509)
20import Data.Certificate.X509 (X509)
@@ -20,22 +27,93 @@ import Network.HTTP.Conduit
22import Data.CaseInsensitive as CI (mk)
29import Data.CaseInsensitive as CI (mk)
30+import Text.XML.HXT.Core
44+--------------------------------------------------------------------------------
46+--------------------------------------------------------------------------------
49+data AzureSetup = AzureSetup
50+ { subscriptionId :: String
51+ , certificate :: X509
52+ , privateKey :: PrivateKey
57+azureSetup :: String -- ^ Subscription ID
58+ -> String -- ^ Path to certificate
59+ -> String -- ^ Path to private key
61+azureSetup sid certPath pkeyPath = do
62+ cert <- fileReadCertificate certPath
63+ pkey <- fileReadPrivateKey pkeyPath
68+ , baseURL = "https://management.core.windows.net"
71+--------------------------------------------------------------------------------
73+--------------------------------------------------------------------------------
75+hostedServices :: AzureSetup -> IO [(String, String)]
76+hostedServices setup =
77+ azureRequest setup "/services/hostedservices" "2012-03-01" $ proc xml -> do
78+ hostedService <- deep (hasName "HostedService") -< xml
79+ url <- getTextNode "Url" -< hostedService
80+ serviceName <- getTextNode "ServiceName" -< hostedService
81+ id -< (url, serviceName)
83+--------------------------------------------------------------------------------
85+--------------------------------------------------------------------------------
24−-- ^ Execute an Azure request
87+-- | Execute an Azure request and parse the XML data
25−azureRequest :: String -- ^ Subscription ID
88+azureRequest :: AzureSetup
26− -> X509 -- ^ X509 certificate
89+ -> String
27− -> PrivateKey -- ^ Private key
90+ -> String
91+ -> IOSArrow XmlTree c
93+azureRequest setup subURL version f = do
94+ raw <- azureRawRequest setup subURL version
95+ runX $ readString [withValidate no] (BSLC.unpack raw) >>> f
97+-- | Execute an Azure request and return the raw data
98+azureRawRequest :: AzureSetup
28− -> String -- ^ Relative path
99+ -> String -- ^ Relative path
29− -> String -- ^ Version
100+ -> String -- ^ Version
30− -> IO ByteString
101+ -> IO ByteString
31−azureRequest sid cert pkey subURL version = do
102+azureRawRequest setup subURL version = do
32− req <- parseUrl $ "https://management.core.windows.net/" ++ sid++ subURL
103+ req <- parseUrl $ baseURL setup ++ "/" ++ subscriptionId setup ++ "/" ++ subURL
33 withManager $ \manager -> do
104 withManager $ \manager -> do
34 let req' = req {
105 let req' = req {
35− clientCertificates = [ (cert, Just pkey) ]
106+ clientCertificates = [ (certificate setup, Just $ privateKey setup) ]
36 , requestHeaders = [ (CI.mk $ BSC.pack "x-ms-version", BSC.pack version)
107 , requestHeaders = [ (CI.mk $ BSC.pack "x-ms-version", BSC.pack version)
37 , (CI.mk $ BSC.pack "content-type", BSC.pack "application/xml")
108 , (CI.mk $ BSC.pack "content-type", BSC.pack "application/xml")
40 Response _ _ _ lbs <- httpLbs req' manager
111 Response _ _ _ lbs <- httpLbs req' manager
41 return lbs
112 return lbs
114+--------------------------------------------------------------------------------
115+-- XML convenience functions --
116+--------------------------------------------------------------------------------
118+getTextNode :: ArrowXml a => String -> a XmlTree String
119+getTextNode node = deep (hasName node) >>> deep getText