Last active
October 3, 2016 19:06
-
-
Save drewr/c38632ef4ac51778b82dd2bb9901f6d9 to your computer and use it in GitHub Desktop.
Haskell is a better Python. Continuously run arg, snapping working dir (minus .git) on failures. Optionally upload failures to S3.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| PATH=/usr/local/bin:$PATH | |
| [[ -z $1 ]] && echo run-zing NUM && exit 99 | |
| run_number=$1 | |
| if [[ $(facter os.name) == 'CentOS' ]]; then | |
| ZING_HOME=/opt/zing/zing-jdk1.8.0-16.01.9.0-1-x86_64 | |
| else | |
| ZING_HOME=/opt/zing/zing-jdk1.8.0-16.01.9.0-1 | |
| fi | |
| ulimit -c unlimited | |
| ulimit -l 1000000 | |
| ulimit -n 1000000 | |
| chpst -u drewr -U drewr \ | |
| env \ | |
| HOME=/home/drewr \ | |
| PATH=../gradle-2.13/bin:$PATH \ | |
| JAVA_HOME=$ZING_HOME \ | |
| ../runsnap 'git clean -fd >OUT-git-clean.log 2>&1 && \ | |
| ( git checkout -f 770abd7af8c23773b0a1d5d4153298e69d0151d5 && git log -1 ) >OUT-git-checkout.log 2>&1 && \ | |
| gradle --stacktrace clean >OUT-clean.log 2>&1 && \ | |
| gradle --info check >OUT-check.log 2>&1' $run_number |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env stack | |
| {- stack --resolver lts-6.13 --install-ghc runghc | |
| --package text | |
| -} | |
| -- Continuously run arg (using System.Process.callCommand), snapping | |
| -- working directory on failure. The snap uses rsync to create a | |
| -- sibling directory with timestamp and git sha. The .git directory | |
| -- is not copied. | |
| -- | |
| -- If arg hangs, runsnap's child PID can accept a SIGUSR1 (10) which | |
| -- will terminate the iteration, snap the working dir, and start the | |
| -- next one. | |
| -- | |
| -- Try it! | |
| -- | |
| -- runsnap "sleep 2; echo run a thing; exit 0" | |
| -- runsnap "sleep 2; echo run a thing; exit 99" | |
| -- | |
| -- Really wrote it for running test suites in an ad hoc infinite loop: | |
| -- | |
| -- % cd elasticsearch | |
| -- % env \ | |
| -- PATH=../gradle-2.13/bin:$PATH \ | |
| -- JAVA_HOME=/opt/zing/zing-jdk1.8.0-16.01.7.0-6 \ | |
| -- ../runsnap 'git clean -fd >OUT-git-clean.log 2>&1 && \ | |
| -- git fetch >OUT-git-fetch.log 2>&1 && \ | |
| -- git checkout -f origin/master >OUT-git-checkout.log 2>&1 && \ | |
| -- gradle --stacktrace clean >OUT-clean.log 2>&1 && \ | |
| -- gradle --info check >OUT-check.log 2>&1' | |
| -- | |
| {-# LANGUAGE OverloadedStrings #-} | |
| import Control.Exception (finally) | |
| import Control.Monad (liftM) | |
| import Data.Time.Clock as T | |
| import Data.Time.Format as TF | |
| import Data.Text (pack, unpack, strip) | |
| import System.Directory (canonicalizePath, getCurrentDirectory, setCurrentDirectory) | |
| import System.Environment (getArgs) | |
| import System.Exit | |
| import System.FilePath.Posix (takeFileName, (</>)) | |
| import System.Posix.Signals (installHandler, sigUSR1, Handler(..)) | |
| import System.Process | |
| (spawnCommand, waitForProcess, callCommand, readProcessWithExitCode, | |
| terminateProcess) | |
| import Text.Printf (printf) | |
| type ShellCommand = String | |
| main :: IO () | |
| main = do | |
| args <- getArgs | |
| case args of | |
| ["setup"] -> putStrLn "setup complete" | |
| [cmd] -> runAndCount cmd 1 | |
| [cmd,offset] -> runAndCount cmd (read offset :: Int) | |
| [] -> do | |
| snapped <- snapCurrDir "" | |
| putStrLn $ "snapped to " ++ snapped | |
| _ -> error $ "unknown: \"" ++ show args ++ "\"" | |
| stripStr :: String -> String | |
| stripStr = unpack . strip . pack | |
| gitHead :: FilePath -> IO (Maybe String) | |
| gitHead dir = do | |
| withCurrentDirectory dir $ do | |
| (c, out, _) <- readProcessWithExitCode "git" ["rev-parse", "HEAD"] "" | |
| pure $ case c of | |
| ExitSuccess -> Just (stripStr out) | |
| _ -> Nothing | |
| nowString :: IO String | |
| nowString = do | |
| t <- T.getCurrentTime | |
| pure $ TF.formatTime TF.defaultTimeLocale "%Y%m%d%H%M%S" t | |
| resolveDirName :: FilePath -> IO FilePath | |
| resolveDirName dir = liftM takeFileName (canonicalizePath dir) | |
| snapCurrDir :: String -> IO String | |
| snapCurrDir i = snapDir i "." | |
| snapDir :: String -> String -> IO String | |
| snapDir iterStr dir = do | |
| now <- nowString | |
| gitRev <- gitHead dir | |
| baseName <- resolveDirName dir | |
| destParent <- canonicalizePath (dir </> "..") | |
| let gitRev' = case gitRev of | |
| (Just rev) -> rev | |
| Nothing -> "" | |
| dest = destParent </> baseName ++ "-" ++ now ++ "-" ++ | |
| gitRev' ++ (if (null iterStr) then "" else ("-" ++ iterStr)) | |
| cmd = "rsync -a --exclude .git " ++ dir ++ " " ++ dest | |
| callCommand cmd | |
| pure dest | |
| runAndCount :: ShellCommand -> Int -> IO () | |
| runAndCount cmd n = do | |
| tStart <- T.getCurrentTime | |
| proc <- spawnCommand cmd | |
| installHandler sigUSR1 (CatchOnce $ terminateProcess proc) Nothing | |
| res <- waitForProcess proc | |
| tEnd <- T.getCurrentTime | |
| let dur = show $ T.diffUTCTime tEnd tStart | |
| case res of | |
| ExitSuccess -> logMe "success" dur >> putStrLn "" | |
| (ExitFailure code) -> do | |
| logMe "fail" dur | |
| putStr $ " (" ++ (show code) ++ "): " | |
| dest <- snapCurrDir iterStr | |
| putStrLn dest | |
| runAndCount cmd (n + 1) | |
| where logMe status dur = putStr $ "== runsnap ==> " ++ (show n) ++ " " ++ status ++ " " ++ dur | |
| iterStr = printf "%06i" n :: String | |
| withCurrentDirectory :: FilePath -> IO a -> IO a | |
| withCurrentDirectory path f = do | |
| cur <- getCurrentDirectory | |
| setCurrentDirectory path | |
| finally f (setCurrentDirectory cur) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env stack | |
| {- stack --resolver lts-6.13 --install-ghc | |
| runghc | |
| --package amazonka | |
| --package amazonka-s3 | |
| --package cond | |
| --package filepath | |
| --package network | |
| --package text | |
| -} | |
| -- Save a directory as .tar.xz and .zip, then upload those to S3 at | |
| -- BUCKET/PREFIX/FILENAME. | |
| -- | |
| -- Example: | |
| -- | |
| -- savesnap mybucket.example.com $(date -u +%s) somedir/ | |
| -- | |
| {-# LANGUAGE OverloadedStrings #-} | |
| import Prelude hiding (unwords, takeWhile) | |
| import Control.Exception | |
| import Control.Lens (set, view, (<&>), (.~)) | |
| import Control.Monad | |
| import Control.Monad.IO.Class (MonadIO, liftIO) | |
| import Control.Monad.Trans.AWS | |
| import Data.Monoid | |
| import Data.Text (Text, pack, unpack, strip, dropAround, unwords, takeWhile) | |
| import Data.Text.IO as T | |
| import Network.AWS.Data (toText, fromText) | |
| import Network.AWS.S3 | |
| (BucketName(..), ObjectKey(..), putObject, poACL, | |
| ObjectCannedACL(OPublicRead)) | |
| import Network.BSD (getHostName) | |
| import System.Directory | |
| import System.Environment (getArgs) | |
| import System.FilePath.Posix as Path hiding ((</>)) | |
| import System.IO (stdout) | |
| import System.Process (callCommand) | |
| data DirToSave = DirToSave | |
| { _path :: Text | |
| , _parent :: Text | |
| , _basename :: Text | |
| , _xzFile :: Text -- xz file path | |
| , _zipFile :: Text -- zip file path | |
| , _xzName :: Text -- xz file without dir | |
| , _zipName :: Text -- zip file without dir | |
| } | |
| chunksize = 16384 | |
| main = do | |
| args <- getArgs | |
| host <- getHostName | |
| let shortHost = takeWhile (\c -> not (c == '.')) . pack $ host | |
| case args of | |
| [bucket, prefix, dirToSync] -> | |
| saveToS3 (pack bucket) (pack prefix) (mkDirToSave (pack dirToSync) shortHost) | |
| _ -> error $ "unknown: \"" ++ show args ++ "\"" | |
| mkDirToSave :: Text -> Text -> DirToSave | |
| mkDirToSave path suffix = DirToSave | |
| { _path = path | |
| , _parent = pack . Path.takeDirectory . unpack $ path | |
| , _basename = baseName | |
| , _xzFile = path <> xzExt | |
| , _xzName = baseName <> xzExt | |
| , _zipFile = path <> zipExt | |
| , _zipName = baseName <> zipExt | |
| } | |
| where | |
| xzExt = "." <> suffix <> ".tar.xz" | |
| zipExt = "." <> suffix <> ".zip" | |
| baseName = pack . Path.takeFileName . unpack $ path | |
| mkArchive :: DirToSave -> (DirToSave -> Text) -> Text -> IO () | |
| mkArchive dir accessor archiveCmd = do | |
| fileExists <- doesFileExist (unpack . accessor $ dir) | |
| when (not fileExists) $ do | |
| withCurrentDirectory (unpack . _parent $ dir) $ do | |
| callCommand . unpack $ cmd | |
| say $ "create " <> (accessor dir) | |
| where cmd = unwords [archiveCmd, (accessor dir), (_basename dir)] | |
| (</>) :: Text -> Text -> Text | |
| (</>) x y = (dropAround (== '/') x) <> "/" <> (dropAround (== '/') y) | |
| saveToS3 :: Text -> Text -> DirToSave -> IO () | |
| saveToS3 b pre dir = do | |
| mkArchive dir _zipFile "zip -qr9" | |
| mkArchive dir _xzFile "tar cfJ" | |
| putChunkedFile | |
| NorthVirginia (BucketName b) | |
| (ObjectKey (pre </> _xzName dir)) chunksize (unpack . _xzFile $ dir) | |
| putChunkedFile | |
| NorthVirginia (BucketName b) | |
| (ObjectKey (pre </> _zipName dir)) chunksize (unpack . _zipFile $ dir) | |
| putChunkedFile :: Region | |
| -> BucketName | |
| -> ObjectKey | |
| -> ChunkSize | |
| -> FilePath | |
| -> IO () | |
| putChunkedFile r b k c f = do | |
| lgr <- newLogger Debug stdout | |
| env <- newEnv r Discover <&> envLogger .~ lgr | |
| runResourceT . runAWST env $ | |
| do bdy <- chunkedFile c f | |
| let po = set poACL (Just OPublicRead) $ putObject b k bdy | |
| void . send $ po | |
| say $ | |
| "Successfully Uploaded: " <> toText f <> " to " <> toText b <> | |
| " - " <> | |
| toText k | |
| say :: MonadIO m => Text -> m () | |
| say = liftIO . T.putStrLn | |
| withCurrentDirectory :: FilePath -> IO a -> IO a | |
| withCurrentDirectory path f = do | |
| cur <- getCurrentDirectory | |
| setCurrentDirectory path | |
| finally f (setCurrentDirectory cur) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment