From 32d31ae8d1ef5d5aeb03a7fe7e6a294e14905505 Mon Sep 17 00:00:00 2001 From: Ben Sima Date: Fri, 20 Dec 2024 13:21:43 -0500 Subject: Build and deploy storybook I put the storybook into a new Biz.nix deploy target. The idea here is that any Biz/* targets should be hosted by this one VM for simplicity. Over time I can grow this as need be, but this should work to host a few services. --- Biz.nix | 25 ++++++++++++++++++ Biz/Storybook.nix | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ Biz/Storybook.py | 15 ++++++----- Omni/Bild.hs | 3 ++- 4 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 Biz.nix create mode 100644 Biz/Storybook.nix diff --git a/Biz.nix b/Biz.nix new file mode 100644 index 0000000..c87f91a --- /dev/null +++ b/Biz.nix @@ -0,0 +1,25 @@ +# nunya +{ bild, ... }: + +# This is the biz hosting service. Currently it defines a base OS similar to +# Omni/Cloud.nix et al and starts each Biz/* thing as a systemd service. A +# better solution might be to define each Biz/* thing as a container, and then +# wire them together as necessary here, but I don't know how that works so I'll +# just stick to this method for now. + +bild.os { + imports = [ + ./Omni/Cloud/Hardware.nix + ./Omni/Os/Base.nix + ./Omni/Packages.nix + ./Omni/Users.nix + ./Biz/Storybook.nix + ]; + networking.hostName = "biz"; + networking.domain = "storybook.bensima.com"; + time.timeZone = "America/New_York"; + services.storybook = { + enable = true; + package = bild.run ./Biz/Storybook.py; + }; +} diff --git a/Biz/Storybook.nix b/Biz/Storybook.nix new file mode 100644 index 0000000..692b4e9 --- /dev/null +++ b/Biz/Storybook.nix @@ -0,0 +1,78 @@ +{ options, lib, config, pkgs, ... }: + +let + cfg = config.services.storybook; + rootDomain = "bensima.com"; + ports = import ../Omni/Cloud/Ports.nix; +in { + options.services.storybook = { + enable = lib.mkEnableOption "Enable the storybook service"; + port = lib.mkOption { + type = lib.types.int; + default = 3000; + description = '' + The port on which storybook will listen for + incoming HTTP traffic. + ''; + }; + dataDir = lib.mkOption { + type = lib.types.path; + default = "/var/storybook/"; + description = "Data dir location"; + }; + package = lib.mkOption { + type = lib.types.package; + description = "storybook package to use"; + }; + }; + config = lib.mkIf cfg.enable { + systemd.services.storybook = { + path = [ cfg.package pkgs.git ]; + wantedBy = [ "multi-user.target" ]; + preStart = '' + # these must be manually created + test -d /run/storybook + test -f /run/storybook/env + # this can be generated + mkdir -p ${cfg.dataDir} + ''; + script = '' + ${cfg.package}/bin/storybook + ''; + description = '' + Storybook + ''; + serviceConfig = { + Environment = + [ "PORT=${toString cfg.port}" "AREA=Live" "DATA_DIR=${cfg.dataDir}" ]; + EnvironmentFile = "/run/storybook/env"; + KillSignal = "INT"; + Type = "simple"; + Restart = "on-abort"; + RestartSec = "1"; + }; + }; + + # TODO: nginx web stuff + services.nginx = { + enable = true; + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; + statusPage = true; + + user = "nginx"; + group = "nginx"; + + virtualHosts."storybook.${rootDomain}" = { + forceSSL = true; + enableACME = true; + locations."/".proxyPass = "http://localhost:${toString cfg.port}"; + # useACMEHost = rootDomain; + }; + }; + + networking.firewall.allowedTCPPorts = [ ports.ssh ports.http ports.https ]; + }; +} diff --git a/Biz/Storybook.py b/Biz/Storybook.py index 80f746a..c29d9f5 100644 --- a/Biz/Storybook.py +++ b/Biz/Storybook.py @@ -45,9 +45,11 @@ import unittest import uuid import uvicorn -VPN = True CODEROOT = pathlib.Path(os.getenv("CODEROOT", ".")) -DATA_DIR = pathlib.Path(CODEROOT / "_/var/storybook/") +DATA_DIR = pathlib.Path( + os.environ.get("DATA_DIR", CODEROOT / "_/var/storybook/"), +) +PORT = int(os.environ.get("PORT", "3000")) class Area(enum.Enum): @@ -89,15 +91,16 @@ def main() -> None: def move(area: Area) -> None: """Run the application.""" - Log.setup(logging.DEBUG if area.Test else logging.ERROR) + Log.setup(logging.DEBUG if area == Area.Test else logging.ERROR) logging.info("area: %s", area) - host = "100.127.197.132" if VPN else "127.0.0.1" - uvicorn.run(app, host=host) + # during test, bind to beryllium's VPN address, else localhost + host = "100.127.197.132" if area == Area.Test else "127.0.0.1" + uvicorn.run(app, host=host, port=PORT) def test(area: Area = Area.Test) -> None: """Run the unittest suite manually.""" - Log.setup(logging.DEBUG if area.Test else logging.ERROR) + Log.setup(logging.DEBUG if area == Area.Test else logging.ERROR) suite = unittest.TestSuite() tests = [IndexTest, StoryTest] suite.addTests([ diff --git a/Omni/Bild.hs b/Omni/Bild.hs index 2d3d729..648bfcb 100644 --- a/Omni/Bild.hs +++ b/Omni/Bild.hs @@ -465,7 +465,8 @@ isBuildableNs = \case ["Omni", "Dev", "Lithium"], ["Omni", "Dev", "Beryllium"], ["Omni", "Os", "Boot"], - ["Biz", "Dragons", "Analysis"] + ["Biz", "Dragons", "Analysis"], + ["Biz"] ] -- | The default output directory. This is not IO because I don't want to -- cgit v1.2.3