@@ -1,297 +1,16 @@
1{-# LANGUAGE TemplateHaskell #-}
1{-# LANGUAGE TemplateHaskell #-}
2−import Prelude hiding (catch)
2+
3−import System.Environment (getArgs)
4−import System.Exit (exitSuccess, exitFailure)
11−import Data.Binary (decode)
12−import qualified Data.ByteString.Lazy as BSL (ByteString, length, getContents)
13−import Control.Monad (unless, forM, forM_, join)
14import Control.Monad.IO.Class (liftIO)
3import Control.Monad.IO.Class (liftIO)
15−import Control.Arrow (returnA)
16−import Control.Exception (throwIO, SomeException)
17−import Control.Distributed.Process.Backend.Azure
4+import Control.Distributed.Process (Process)
18− ( AzureParameters(azureSshUserName)
19− , defaultAzureParameters
22− , CloudService(cloudServiceName, cloudServiceVMs)
23− , VirtualMachine(vmName)
24− , Backend(copyToVM, checkMD5, runOnVM)
26−import qualified Network.SSH.Client.LibSSH2.Foreign as SSH
30−import Control.Applicative ((<$>), (<*>), (<|>), pure)
31−import Options.Applicative
48−import Options.Applicative.Arrows (runA, asA)
49−import Control.Distributed.Process
57import Control.Distributed.Process.Closure (remotable, mkClosure)
5import Control.Distributed.Process.Closure (remotable, mkClosure)
58−import Control.Distributed.Process.Node (newLocalNode, runProcess, initRemoteTable)
6+import Control.Distributed.Process.Backend.Azure.GenericMain (genericMain)
59−import Network.Transport.TCP (createTransport, defaultTCPParameters)
61cprint :: String -> Process ()
8cprint :: String -> Process ()
62cprint = liftIO . putStrLn
9cprint = liftIO . putStrLn
64remotable ['cprint]
11remotable ['cprint]
66−--------------------------------------------------------------------------------
13+main = genericMain __remoteTable $ \cmd ->
68−--------------------------------------------------------------------------------
72− _ <- SSH.initialize True
73− cmd <- execParser opts
74− case cmd of
14+ case cmd of
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")
15+ "hello" -> return $ $(mkClosure 'cprint) "Hi world!"
107− OnVmCommand (vmCmd@OnVmRun {}) -> do
16+ _ -> error "unknown command"
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− mTransport <- createTransport host port defaultTCPParameters
144− Left err -> throwIO err
145− Right transport -> do
146− node <- newLocalNode transport rtable
147− runProcess node $ join . unClosure . decode $ proc
149−--------------------------------------------------------------------------------
150−-- Command line options --
151−--------------------------------------------------------------------------------
153−data AzureOptions = AzureOptions {
154− subscriptionId :: String
155− , pathToCert :: FilePath
156− , pathToKey :: FilePath
160−data SshOptions = SshOptions {
161− remoteUser :: String
166− VirtualMachine String
167− | CloudService String
172− azureOptions :: AzureOptions
175− azureOptions :: AzureOptions
176− , sshOptions :: SshOptions
180− azureOptions :: AzureOptions
181− , sshOptions :: SshOptions
186− azureOptions :: AzureOptions
187− , sshOptions :: SshOptions
192− onVmCommand :: OnVmCommand
199− , onVmPort :: String
203−azureOptionsParser :: Parser AzureOptions
204−azureOptionsParser = AzureOptions
205− <$> strOption ( long "subscription-id"
207− & help "Azure subscription ID"
209− <*> strOption ( long "certificate"
211− & help "X509 certificate"
213− <*> strOption ( long "private"
215− & help "Private key in PKCS#1 format"
218−sshOptionsParser :: Parser SshOptions
219−sshOptionsParser = SshOptions
220− <$> strOption ( long "user"
222− & help "Remove SSH username"
225−listParser :: Parser Command
226−listParser = List <$> azureOptionsParser
228−copyToParser :: Parser Command
229−copyToParser = CopyTo
230− <$> azureOptionsParser
231− <*> sshOptionsParser
234−targetParser :: Parser Target
236− ( VirtualMachine <$> strOption ( long "virtual-machine"
238− & help "Virtual machine name"
242− ( CloudService <$> strOption ( long "cloud-service"
244− & help "Cloud service name"
248−checkMD5Parser :: Parser Command
249−checkMD5Parser = CheckMD5
250− <$> azureOptionsParser
251− <*> sshOptionsParser
253− <*> switch ( long "status"
254− & help "Don't output anything, status code shows success"
257−commandParser :: Parser Command
258−commandParser = subparser
259− ( command "list" (info listParser
260− (progDesc "List Azure cloud services"))
261− & command "install" (info copyToParser
262− (progDesc "Install the executable"))
263− & command "md5" (info checkMD5Parser
264− (progDesc "Check if the remote and local MD5 hash match"))
265− & command "run" (info runOnParser
266− (progDesc "Run the executable"))
267− & command "onvm" (info onVmCommandParser
268− (progDesc "Commands used when running ON the vm (usually used internally only)"))
271−runOnParser :: Parser Command
273− <$> azureOptionsParser
274− <*> sshOptionsParser
276− <*> strOption ( long "port"
278− & help "Port number of the CH instance"
281−onVmRunParser :: Parser OnVmCommand
282−onVmRunParser = OnVmRun
283− <$> strOption ( long "host"
287− <*> strOption ( long "port"
289− & help "port number"
292−onVmCommandParser :: Parser Command
293−onVmCommandParser = OnVmCommand <$> subparser
294− ( command "run" (info onVmRunParser
295− (progDesc "Run the executable"))