2module Control.Distributed.Process.Backend.Azure.GenericMain
7import Prelude hiding (catch)
8import System.Exit (exitSuccess, exitFailure)
17import Data.Binary (decode)
18import qualified Data.ByteString.Lazy as BSL (getContents, length)
19import Control.Monad (unless, forM, forM_, join, void)
20import Control.Exception (throwIO, SomeException, evaluate)
21import Control.Applicative ((<$>), (<*>), (<|>))
22import Control.Monad.IO.Class (liftIO)
25import System.Posix.Process (forkProcess, createSession)
28import qualified Network.SSH.Client.LibSSH2.Foreign as SSH
33-- Command line options
34import Options.Applicative
53import Control.Distributed.Process
61import Control.Distributed.Process.Node (newLocalNode, runProcess, initRemoteTable)
62import Control.Distributed.Process.Serializable (Serializable)
63import Control.Distributed.Process.Closure (SerializableDict)
64import Network.Transport.TCP (createTransport, defaultTCPParameters)
65import Control.Distributed.Process.Backend.Azure
66 ( AzureParameters(azureSshUserName)
67 , defaultAzureParameters
70 , CloudService(cloudServiceName, cloudServiceVMs)
71 , VirtualMachine(vmName)
72 , Backend(copyToVM, checkMD5, callOnVM, spawnOnVM)
74import qualified Control.Distributed.Process.Backend.Azure as Azure (remoteTable)
76--------------------------------------------------------------------------------
78--------------------------------------------------------------------------------
80data ProcessPair b = forall a. Serializable a => ProcessPair {
81 ppairRemote :: Closure (Process a)
82 , ppairLocal :: a -> IO b
83 , ppairDict :: Static (SerializableDict a)
86genericMain :: (RemoteTable -> RemoteTable) -- ^ Standard CH remote table
87 -> (String -> IO (ProcessPair ())) -- ^ Closures to support in 'run'
88 -> (String -> IO (Closure (Process ()))) -- ^ Closures to support in @run --background@
90genericMain remoteTable callable spawnable = do
91 _ <- SSH.initialize True
92 cmd <- execParser opts
95 params <- azureParameters (azureOptions cmd) Nothing
96 backend <- initializeBackend params
97 css <- cloudServices backend
100 params <- azureParameters (azureOptions cmd) (Just (sshOptions cmd))
101 backend <- initializeBackend params
102 css <- cloudServices backend
103 forM_ (findTarget (target cmd) css) $ \vm -> do
104 putStr (vmName vm ++ ": ") >> hFlush stdout
108 params <- azureParameters (azureOptions cmd) (Just (sshOptions cmd))
109 backend <- initializeBackend params
110 css <- cloudServices backend
111 matches <- forM (findTarget (target cmd) css) $ \vm -> do
112 unless (status cmd) $ putStr (vmName vm ++ ": ") >> hFlush stdout
113 match <- checkMD5 backend vm
114 unless (status cmd) $ putStrLn $ if match then "OK" else "FAILED"
119 RunOn {} | background cmd -> do
120 rProc <- spawnable (closureId cmd)
121 params <- azureParameters (azureOptions cmd) (Just (sshOptions cmd))
122 backend <- initializeBackend params
123 css <- cloudServices backend
124 forM_ (findTarget (target cmd) css) $ \vm -> do
125 putStr (vmName vm ++ ": ") >> hFlush stdout
126 spawnOnVM backend vm (remotePort cmd) rProc
128 RunOn {} {- not (background cmd) -} -> do
129 procPair <- callable (closureId cmd)
130 params <- azureParameters (azureOptions cmd) (Just (sshOptions cmd))
131 backend <- initializeBackend params
132 css <- cloudServices backend
133 forM_ (findTarget (target cmd) css) $ \vm -> do
134 putStr (vmName vm ++ ": ") >> hFlush stdout
136 ProcessPair rProc lProc dict -> do
137 result <- callOnVM backend dict vm (remotePort cmd) rProc
139 OnVmCommand (vmCmd@OnVmRun {}) ->
140 onVmRun (remoteTable . Azure.remoteTable $ initRemoteTable)
143 (onVmBackground vmCmd)
146 opts = info (helper <*> commandParser)
148 & header "Cloud Haskell backend for Azure"
151findTarget :: Target -> [CloudService] -> [VirtualMachine]
152findTarget (CloudService cs) css =
153 concatMap cloudServiceVMs . filter ((== cs) . cloudServiceName) $ css
154findTarget (VirtualMachine virtualMachine) css =
155 [ vm | vm <- concatMap cloudServiceVMs css
156 , vmName vm == virtualMachine
159azureParameters :: AzureOptions -> Maybe SshOptions -> IO AzureParameters
160azureParameters opts Nothing =
161 defaultAzureParameters (subscriptionId opts)
164azureParameters opts (Just sshOpts) = do
165 params <- defaultAzureParameters (subscriptionId opts)
169 azureSshUserName = remoteUser sshOpts
172onVmRun :: RemoteTable -> String -> String -> Bool -> IO ()
173onVmRun rtable host port bg = do
174 hSetBinaryMode stdin True
175 hSetBinaryMode stdout True
176 procEnc <- BSL.getContents
177 -- Force evaluation (so that we can safely close stdin)
178 _length <- evaluate (BSL.length procEnc)
179 let proc = decode procEnc
185 void . forkProcess $ do
191 startCH :: Closure (Process ()) -> IO ()
193 mTransport <- createTransport host port defaultTCPParameters
195 Left err -> throwIO err
196 Right transport -> do
197 node <- newLocalNode transport rtable
199 catch (join . unClosure $ proc)
200 (\e -> liftIO (print (e :: SomeException) >> throwIO e))
202--------------------------------------------------------------------------------
203-- Command line options --
204--------------------------------------------------------------------------------
206data AzureOptions = AzureOptions {
207 subscriptionId :: String
208 , pathToCert :: FilePath
209 , pathToKey :: FilePath
213data SshOptions = SshOptions {
219 VirtualMachine String
220 | CloudService String
225 azureOptions :: AzureOptions
228 azureOptions :: AzureOptions
229 , sshOptions :: SshOptions
233 azureOptions :: AzureOptions
234 , sshOptions :: SshOptions
239 azureOptions :: AzureOptions
240 , sshOptions :: SshOptions
242 , remotePort :: String
243 , closureId :: String
247 onVmCommand :: OnVmCommand
255 , onVmBackground :: Bool
259azureOptionsParser :: Parser AzureOptions
260azureOptionsParser = AzureOptions
261 <$> strOption ( long "subscription-id"
263 & help "Azure subscription ID"
265 <*> strOption ( long "certificate"
267 & help "X509 certificate"
269 <*> strOption ( long "private"
271 & help "Private key in PKCS#1 format"
274sshOptionsParser :: Parser SshOptions
275sshOptionsParser = SshOptions
276 <$> strOption ( long "user"
278 & help "Remove SSH username"
281listParser :: Parser Command
282listParser = List <$> azureOptionsParser
284copyToParser :: Parser Command
286 <$> azureOptionsParser
290targetParser :: Parser Target
292 ( VirtualMachine <$> strOption ( long "virtual-machine"
294 & help "Virtual machine name"
298 ( CloudService <$> strOption ( long "cloud-service"
300 & help "Cloud service name"
304checkMD5Parser :: Parser Command
305checkMD5Parser = CheckMD5
306 <$> azureOptionsParser
309 <*> switch ( long "status"
310 & help "Don't output anything, status code shows success"
313commandParser :: Parser Command
314commandParser = subparser
315 ( command "list" (info listParser
316 (progDesc "List Azure cloud services"))
317 & command "install" (info copyToParser
318 (progDesc "Install the executable"))
319 & command "md5" (info checkMD5Parser
320 (progDesc "Check if the remote and local MD5 hash match"))
321 & command "run" (info runOnParser
322 (progDesc "Run the executable"))
323 & command "onvm" (info onVmCommandParser
324 (progDesc "Commands used when running ON the vm (usually used internally only)"))
327runOnParser :: Parser Command
329 <$> azureOptionsParser
332 <*> strOption ( long "port"
334 & help "Port number of the CH instance"
336 <*> strOption ( long "closure"
338 & help "Process to run on the CH instance"
340 <*> switch ( long "background"
341 & help "Run the process in the background"
344onVmRunParser :: Parser OnVmCommand
345onVmRunParser = OnVmRun
346 <$> strOption ( long "host"
350 <*> strOption ( long "port"
354 <*> switch ( long "background"
355 & help "Run the process in the background"
358onVmCommandParser :: Parser Command
359onVmCommandParser = OnVmCommand <$> subparser
360 ( command "run" (info onVmRunParser
361 (progDesc "Run the executable"))
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list