diff options
| author | Ben Sima <ben@bensima.com> | 2025-12-16 08:06:09 -0500 |
|---|---|---|
| committer | Ben Sima <ben@bensima.com> | 2025-12-16 08:06:09 -0500 |
| commit | a7dcb30c7a465d9fce72b7fc3e605470b2b59814 (patch) | |
| tree | 57a6436de34062773483dbd0cb745ac103c6bb48 /Omni/Bild.hs | |
| parent | 4caefe45756fdc21df990b8d6e826c40db1b9c78 (diff) | |
feat(deploy): Complete mini-PaaS deployment system (t-266)
- Add Omni/Deploy/ with Manifest, Deployer, Systemd, Caddy modules
- Manifest CLI: show, update, add-service, list, rollback commands
- Deployer: polls S3 manifest, pulls closures, manages systemd units
- Caddy integration for dynamic reverse proxy routes
- bild: auto-cache to S3, outputs STORE_PATH for push.sh
- push.sh: supports both NixOS and service deploys
- Biz.nix: simplified to base OS + deployer only
- Services (podcastitlater-web/worker) now deployer-managed
- Documentation: README.md with operations guide
Diffstat (limited to 'Omni/Bild.hs')
| -rw-r--r-- | Omni/Bild.hs | 60 |
1 files changed, 49 insertions, 11 deletions
diff --git a/Omni/Bild.hs b/Omni/Bild.hs index e1f5c46..1ebeb05 100644 --- a/Omni/Bild.hs +++ b/Omni/Bild.hs @@ -249,7 +249,7 @@ move args = do forM_ skippedNamespaces <| \ns -> LogC.updateLineState ns LogC.Skipped action runWithManager <| do - pipelineBuild isTest isLoud 8 jobs (cpus nproc) namespaces analyzeOne + pipelineBuild isTest isLoud (not noCache) 8 jobs (cpus nproc) namespaces analyzeOne |> Timeout.timeout (toMillis minutes) +> \case Nothing -> @@ -285,6 +285,7 @@ move args = do Just n -> n isTest = args `Cli.has` Cli.longOption "test" isLoud = args `Cli.has` Cli.longOption "loud" + noCache = args `Cli.has` Cli.longOption "no-cache" putJSON = Aeson.encode .> ByteString.Lazy.toStrict .> Char8.putStrLn -- | Don't try to build stuff that isn't part of the git repo. @@ -363,6 +364,7 @@ Options: --test, -t Run tests on a target after building --loud, -l Show all output from compiler --plan, -p Print the build plan as JSON, don't build + --no-cache Skip signing and pushing to S3 binary cache --time N Set timeout to N minutes, 0 means never timeout [default: 10] --jobs N, -j N Build up to N jobs at once [default: 6] --cpus N, -c N Allocate up to N cpu cores per job (default: (nproc-4)/jobs) @@ -1297,8 +1299,8 @@ pipelineAnalysisWorker coord@Coordinator {..} analyzeFn = loop else modifyTVar' coStates (Map.insert ns (TSWaitingForDeps target pendingDeps)) loop -pipelineBuildWorker :: Bool -> Bool -> Int -> Int -> Coordinator -> IO () -pipelineBuildWorker andTest loud jobs cpus coord@Coordinator {..} = loop +pipelineBuildWorker :: Bool -> Bool -> Bool -> Int -> Int -> Coordinator -> IO () +pipelineBuildWorker andTest loud andCache jobs cpus coord@Coordinator {..} = loop where loop = do remaining <- readTVarIO coRemaining @@ -1319,7 +1321,7 @@ pipelineBuildWorker andTest loud jobs cpus coord@Coordinator {..} = loop Nothing -> loop Just target -> do LogC.updateLineState ns LogC.Building - exitCode <- pipelineBuildOne andTest loud jobs cpus target + exitCode <- pipelineBuildOne andTest loud andCache jobs cpus target atomically <| do modifyTVar' coStates (Map.insert ns (TSComplete target exitCode)) modifyTVar' coResults (exitCode :) @@ -1342,8 +1344,8 @@ promoteWaiters Coordinator {..} completedNs = do else modifyTVar' coStates (Map.insert ns (TSWaitingForDeps target deps')) _ -> pure () -pipelineBuildOne :: Bool -> Bool -> Int -> Int -> Target -> IO Exit.ExitCode -pipelineBuildOne andTest loud jobs cpus target@Target {..} = do +pipelineBuildOne :: Bool -> Bool -> Bool -> Int -> Int -> Target -> IO Exit.ExitCode +pipelineBuildOne andTest loud andCache jobs cpus target@Target {..} = do root <- getCoderoot result <- case compiler of CPython -> case out of @@ -1392,14 +1394,50 @@ pipelineBuildOne andTest loud jobs cpus target@Target {..} = do nixBuild loud jobs cpus target Sbcl -> proc loud namespace (toNixFlag compiler) compilerFlags - pure (fst result) - -pipelineBuild :: Bool -> Bool -> Int -> Int -> Int -> [Namespace] -> (Namespace -> IO (Maybe Target)) -> IO [Exit.ExitCode] -pipelineBuild andTest loud analysisWorkers buildWorkers cpus namespaces analyzeFn = do + let exitCode = fst result + when (andCache && isSuccess exitCode) <| do + storePath <- Dir.canonicalizePath (nixdir </> outname out) + cacheStorePath loud namespace storePath + pure exitCode + +cacheStorePath :: Bool -> Namespace -> FilePath -> IO () +cacheStorePath loud ns storePath = do + mKeyPath <- Env.lookupEnv "NIX_CACHE_KEY" + case mKeyPath of + Nothing -> Log.warn ["cache", "NIX_CACHE_KEY not set, skipping"] + Just keyPath -> do + let s3Url = "s3://omni-nix-cache?profile=digitalocean&scheme=https&endpoint=nyc3.digitaloceanspaces.com" + LogC.updateLine ns "signing..." + (signExit, _, signErr) <- + Process.readProcessWithExitCode + "nix" + ["store", "sign", "--key-file", keyPath, storePath] + "" + case signExit of + Exit.ExitSuccess -> do + LogC.updateLine ns "pushing to cache..." + (pushExit, _, pushErr) <- + Process.readProcessWithExitCode + "nix" + ["copy", "--to", s3Url, storePath] + "" + case pushExit of + Exit.ExitSuccess -> do + loud ?| Log.good ["cache", "pushed", Text.pack storePath] + Text.IO.putStrLn <| "STORE_PATH=" <> Text.pack storePath + Exit.ExitFailure _ -> do + Log.fail ["cache", "push failed", Text.pack storePath] + loud ?| putStrLn pushErr + Exit.ExitFailure _ -> do + Log.fail ["cache", "sign failed", Text.pack storePath] + loud ?| putStrLn signErr + +pipelineBuild :: Bool -> Bool -> Bool -> Int -> Int -> Int -> [Namespace] -> (Namespace -> IO (Maybe Target)) -> IO [Exit.ExitCode] +pipelineBuild andTest loud andCache analysisWorkers buildWorkers cpus namespaces analyzeFn = do root <- getCoderoot coord <- initCoordinator root namespaces let spawnAnalysis = replicateM analysisWorkers (Async.async (pipelineAnalysisWorker coord analyzeFn)) - let spawnBuild = replicateM buildWorkers (Async.async (pipelineBuildWorker andTest loud buildWorkers cpus coord)) + let spawnBuild = replicateM buildWorkers (Async.async (pipelineBuildWorker andTest loud andCache buildWorkers cpus coord)) threads <- (<>) </ spawnAnalysis <*> spawnBuild let waitLoop = do remaining <- readTVarIO (coRemaining coord) |
