@@ -1,10 +1,19 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+import Prelude hiding (catch)
1import System.Environment (getArgs)
3import System.Environment (getArgs)
2import System.Exit (exitSuccess, exitFailure)
4import System.Exit (exitSuccess, exitFailure)
3−import System.IO (hFlush, stdout)
5+import System.IO
11+import Data.Binary (decode)
12+import qualified Data.ByteString.Lazy as BSL (ByteString, length, getContents)
4−import Control.Monad (unless, forM, forM_)
13+import Control.Monad (unless, forM, forM_, join)
5import Control.Monad.IO.Class (liftIO)
14import Control.Monad.IO.Class (liftIO)
6import Control.Arrow (returnA)
15import Control.Arrow (returnA)
7−import Control.Exception (throwIO)
16+import Control.Exception (throwIO, SomeException)
8import Control.Distributed.Process.Backend.Azure
17import Control.Distributed.Process.Backend.Azure
9 ( AzureParameters(azureSshUserName)
18 ( AzureParameters(azureSshUserName)
10 , defaultAzureParameters
19 , defaultAzureParameters
@@ -37,10 +46,109 @@ import Options.Applicative
39import Options.Applicative.Arrows (runA, asA)
48import Options.Applicative.Arrows (runA, asA)
40−import Control.Distributed.Process (getSelfPid, RemoteTable)
49+import Control.Distributed.Process
57+import Control.Distributed.Process.Closure (remotable, mkClosure)
41import Control.Distributed.Process.Node (newLocalNode, runProcess, initRemoteTable)
58import Control.Distributed.Process.Node (newLocalNode, runProcess, initRemoteTable)
42import Network.Transport.TCP (createTransport, defaultTCPParameters)
59import Network.Transport.TCP (createTransport, defaultTCPParameters)
61+cprint :: String -> Process ()
62+cprint = liftIO . putStrLn
66+--------------------------------------------------------------------------------
68+--------------------------------------------------------------------------------
72+ _ <- SSH.initialize True
73+ cmd <- execParser opts
76+ params <- azureParameters (azureOptions cmd) Nothing
77+ backend <- initializeBackend params
78+ css <- cloudServices backend
81+ params <- azureParameters (azureOptions cmd) (Just (sshOptions cmd))
82+ backend <- initializeBackend params
83+ css <- cloudServices backend
84+ forM_ (findTarget (target cmd) css) $ \vm -> do
85+ putStr (vmName vm ++ ": ") >> hFlush stdout
89+ params <- azureParameters (azureOptions cmd) (Just (sshOptions cmd))
90+ backend <- initializeBackend params
91+ css <- cloudServices backend
92+ matches <- forM (findTarget (target cmd) css) $ \vm -> do
93+ unless (status cmd) $ putStr (vmName vm ++ ": ") >> hFlush stdout
94+ match <- checkMD5 backend vm
95+ unless (status cmd) $ putStrLn $ if match then "OK" else "FAILED"
101+ params <- azureParameters (azureOptions cmd) (Just (sshOptions cmd))
102+ backend <- initializeBackend params
103+ css <- cloudServices backend
104+ forM_ (findTarget (target cmd) css) $ \vm -> do
105+ putStr (vmName vm ++ ": ") >> hFlush stdout
106+ runOnVM backend vm (port cmd) ($(mkClosure 'cprint) "Hello world")
107+ OnVmCommand (vmCmd@OnVmRun {}) -> do
108+ let rtable = __remoteTable initRemoteTable
109+ onVmRun rtable (onVmIP vmCmd) (onVmPort vmCmd)
112+ opts = info (helper <*> commandParser)
114+ & header "Cloud Haskell backend for Azure"
117+findTarget :: Target -> [CloudService] -> [VirtualMachine]
118+findTarget (CloudService cs) css =
119+ concatMap cloudServiceVMs . filter ((== cs) . cloudServiceName) $ css
120+findTarget (VirtualMachine virtualMachine) css =
121+ [ vm | vm <- concatMap cloudServiceVMs css
122+ , vmName vm == virtualMachine
125+azureParameters :: AzureOptions -> Maybe SshOptions -> IO AzureParameters
126+azureParameters opts Nothing =
127+ defaultAzureParameters (subscriptionId opts)
130+azureParameters opts (Just sshOpts) = do
131+ params <- defaultAzureParameters (subscriptionId opts)
135+ azureSshUserName = remoteUser sshOpts
138+onVmRun :: RemoteTable -> String -> String -> IO ()
139+onVmRun rtable host port = do
140+ hSetBinaryMode stdin True
141+ proc <- BSL.getContents :: IO BSL.ByteString
142+ putStrLn $ "Got closure encoding of length " ++ show (BSL.length proc)
143+ mTransport <- createTransport host port defaultTCPParameters
145+ Left err -> throwIO err
146+ Right transport -> do
147+ node <- newLocalNode transport rtable
148+ runProcess node $ do
149+ liftIO $ putStrLn "Starting remote node"
150+ catch (join . unClosure . decode $ proc) (\e -> liftIO $ print (e :: SomeException))
44--------------------------------------------------------------------------------
152--------------------------------------------------------------------------------
45-- Command line options --
153-- Command line options --
46--------------------------------------------------------------------------------
154--------------------------------------------------------------------------------
@@ -81,6 +189,7 @@ data Command =
81 azureOptions :: AzureOptions
189 azureOptions :: AzureOptions
82 , sshOptions :: SshOptions
190 , sshOptions :: SshOptions
83 , target :: Target
191 , target :: Target
85 | OnVmCommand {
194 | OnVmCommand {
86 onVmCommand :: OnVmCommand
195 onVmCommand :: OnVmCommand
@@ -167,6 +276,10 @@ runOnParser = RunOn
167 <$> azureOptionsParser
276 <$> azureOptionsParser
168 <*> sshOptionsParser
277 <*> sshOptionsParser
169 <*> targetParser
278 <*> targetParser
279+ <*> strOption ( long "port"
281+ & help "Port number of the CH instance"
171onVmRunParser :: Parser OnVmCommand
284onVmRunParser :: Parser OnVmCommand
172onVmRunParser = OnVmRun
285onVmRunParser = OnVmRun
@@ -185,88 +298,3 @@ onVmCommandParser = OnVmCommand <$> subparser
185 (progDesc "Run the executable"))
298 (progDesc "Run the executable"))
188−--------------------------------------------------------------------------------
190−--------------------------------------------------------------------------------
194− _ <- SSH.initialize True
195− cmd <- execParser opts
198− params <- azureParameters (azureOptions cmd) Nothing
199− backend <- initializeBackend params
200− css <- cloudServices backend
203− params <- azureParameters (azureOptions cmd) (Just (sshOptions cmd))
204− backend <- initializeBackend params
205− css <- cloudServices backend
206− forM_ (findTarget (target cmd) css) $ \vm -> do
207− putStr (vmName vm ++ ": ") >> hFlush stdout
211− params <- azureParameters (azureOptions cmd) (Just (sshOptions cmd))
212− backend <- initializeBackend params
213− css <- cloudServices backend
214− matches <- forM (findTarget (target cmd) css) $ \vm -> do
215− unless (status cmd) $ putStr (vmName vm ++ ": ") >> hFlush stdout
216− match <- checkMD5 backend vm
217− unless (status cmd) $ putStrLn $ if match then "OK" else "FAILED"
223− params <- azureParameters (azureOptions cmd) (Just (sshOptions cmd))
224− backend <- initializeBackend params
225− css <- cloudServices backend
226− forM_ (findTarget (target cmd) css) $ \vm -> do
227− putStr (vmName vm ++ ": ") >> hFlush stdout
230− OnVmCommand (vmCmd@OnVmRun {}) -> do
231− let rtable = initRemoteTable
232− onVmRun rtable (onVmIP vmCmd) (onVmPort vmCmd)
235− opts = info (helper <*> commandParser)
237− & header "Cloud Haskell backend for Azure"
240−findTarget :: Target -> [CloudService] -> [VirtualMachine]
241−findTarget (CloudService cs) css =
242− concatMap cloudServiceVMs . filter ((== cs) . cloudServiceName) $ css
243−findTarget (VirtualMachine virtualMachine) css =
244− [ vm | vm <- concatMap cloudServiceVMs css
245− , vmName vm == virtualMachine
248−azureParameters :: AzureOptions -> Maybe SshOptions -> IO AzureParameters
249−azureParameters opts Nothing =
250− defaultAzureParameters (subscriptionId opts)
253−azureParameters opts (Just sshOpts) = do
254− params <- defaultAzureParameters (subscriptionId opts)
258− azureSshUserName = remoteUser sshOpts
261−onVmRun :: RemoteTable -> String -> String -> IO ()
262−onVmRun rtable host port = do
263− mTransport <- createTransport host port defaultTCPParameters
265− Left err -> throwIO err
266− Right transport -> do
267− node <- newLocalNode transport rtable
268− runProcess node $ do
270− liftIO . putStrLn $ "Azure controller has pid " ++ show pid