@@ -1,5 +1,7 @@
11{-# LANGUAGE Arrows #-}
22import System.Environment (getArgs)
3+import System.Exit (exitSuccess, exitFailure)
4+import Control.Monad (unless)
35import Control.Distributed.Process.Backend.Azure
46 ( AzureParameters(azureSshUserName)
57 , defaultAzureParameters
@@ -7,7 +9,7 @@ import Control.Distributed.Process.Backend.Azure
79 , cloudServices
810 , CloudService(cloudServiceVMs)
911 , VirtualMachine(vmName)
10− , startOnVM
12+ , Backend(copyToVM, checkMD5)
1113 )
1214import Control.Arrow (returnA)
1315import Control.Applicative ((<$>), (<*>))
@@ -26,6 +28,7 @@ import Options.Applicative
2628 , helper
2729 , fullDesc
2830 , header
31+ , switch
2932 )
3033import Options.Applicative.Arrows (runA, asA)
3134
@@ -46,8 +49,20 @@ data SshOptions = SshOptions {
4649 deriving Show
4750
4851data Command =
49− List AzureOptions
50− | Start AzureOptions SshOptions String
52+ List {
53+ azureOptions :: AzureOptions
54+ }
55+ | CopyTo {
56+ azureOptions :: AzureOptions
57+ , sshOptions :: SshOptions
58+ , virtualMachine :: String
59+ }
60+ | CheckMD5 {
61+ azureOptions :: AzureOptions
62+ , sshOptions :: SshOptions
63+ , virtualMachine :: String
64+ , status :: Bool
65+ }
5166 deriving Show
5267
5368azureOptionsParser :: Parser AzureOptions
@@ -75,8 +90,8 @@ sshOptionsParser = SshOptions
7590listParser :: Parser Command
7691listParser = List <$> azureOptionsParser
7792
78−startParser :: Parser Command
79−startParser = Start
93+copyToParser :: Parser Command
94+copyToParser = CopyTo
8095 <$> azureOptionsParser
8196 <*> sshOptionsParser
8297 <*> strOption ( long "vm"
@@ -84,12 +99,26 @@ startParser = Start
8499 & help "Virtual machine name"
85100 )
86101
102+checkMD5Parser :: Parser Command
103+checkMD5Parser = CheckMD5
104+ <$> azureOptionsParser
105+ <*> sshOptionsParser
106+ <*> strOption ( long "vm"
107+ & metavar "VM"
108+ & help "Virtual machine name"
109+ )
110+ <*> switch ( long "status"
111+ & help "Don't output anything, status code shows success"
112+ )
113+
87114commandParser :: Parser Command
88115commandParser = subparser
89116 ( command "list" (info listParser
90117 (progDesc "List Azure cloud services"))
91− & command "start" (info startParser
92− (progDesc "Start a new Cloud Haskell node"))
118+ & command "install" (info copyToParser
119+ (progDesc "Install the executable on a virtual machine"))
120+ & command "md5" (info checkMD5Parser
121+ (progDesc "Check if the remote and local MD5 hash match"))
93122 )
94123
95124--------------------------------------------------------------------------------
@@ -100,20 +129,37 @@ main :: IO ()
100129main = do
101130 cmd <- execParser opts
102131 case cmd of
103− List azureOpts -> do
104− params <- azureParameters azureOpts Nothing
132+ List {} -> do
133+ params <- azureParameters (azureOptions cmd) Nothing
105134 backend <- initializeBackend params
106135 css <- cloudServices backend
107136 mapM_ print css
108− Start azureOpts sshOpts name -> do
109− params <- azureParameters azureOpts (Just sshOpts)
137+ CopyTo {} -> do
138+ params <- azureParameters (azureOptions cmd) (Just (sshOptions cmd))
110139 backend <- initializeBackend params
111140 css <- cloudServices backend
112141 let ch = head [ vm | vm <- concatMap cloudServiceVMs css
113− , vmName vm == name
142+ , vmName vm == virtualMachine cmd
114143 ]
115144 print ch
116− startOnVM backend ch
145+ copyToVM backend ch
146+ CheckMD5 {} -> do
147+ params <- azureParameters (azureOptions cmd) (Just (sshOptions cmd))
148+ backend <- initializeBackend params
149+ css <- cloudServices backend
150+ let ch = head [ vm | vm <- concatMap cloudServiceVMs css
151+ , vmName vm == virtualMachine cmd
152+ ]
153+ match <- checkMD5 backend ch
154+ if match
155+ then do
156+ unless (status cmd) $
157+ putStrLn "Local and remote MD5 hash match"
158+ exitSuccess
159+ else do
160+ unless (status cmd) $
161+ putStrLn "Local and remote MD5 hash do NOT match"
162+ exitFailure
117163 where
118164 opts = info (helper <*> commandParser)
119165 ( fullDesc