Kaynağa Gözat

feat(odin): added grist container, first iteration

Zander Hawke 5 ay önce
ebeveyn
işleme
abe4ed4d19

+ 5 - 0
flake.nix

@@ -116,6 +116,11 @@
           system = "x86_64-linux";
           modules = [ ./hosts/odin ];
         };
+
+        grist = lib.mkSystem {
+          system = "x86_64-linux";
+          modules = [ ./hosts/odin/containers/grist.nix ];
+        };
       };
 
       darwinConfigurations = {

+ 75 - 0
hosts/odin/containers/grist.nix

@@ -0,0 +1,75 @@
+{ lib
+, pkgs
+, outputs
+, ...
+}:
+let
+  dataDir = "/var/lib/grist";
+in
+{
+  imports = [
+    # TODO: auto-import via `outputs.modules.nixos`
+    outputs.modules.global.nix-config
+  ];
+
+  systemd.services.grist = {
+    description = "Grist Core Spreadsheet Server";
+    wantedBy = [ "multi-user.target" ];
+    after = [ "network.target" ];
+
+    environment = {
+      APP_HOME_URL = "https://grist.odin.t5.st";
+      GRIST_ORG_IN_PATH = "true";
+      GRIST_HOST = "0.0.0.0";
+      GRIST_SINGLE_PORT = "true";
+      GRIST_SERVE_SAME_ORIGIN = "true";
+      GRIST_INST_DIR = "${dataDir}";
+      GRIST_DATA_DIR = "${dataDir}/docs";
+      GRIST_SANDBOX_FLAVOR = "unsandboxed";
+      GRIST_SESSION_COOKIE = "grist_core";
+      GRIST_DEFAULT_EMAIL = "[email protected]";
+      GRIST_TELEMETRY_LEVEL = "off";
+      GRIST_ALLOW_AUTOMATIC_VERSION_CHECKING = "false";
+      NODE_OPTIONS = "--no-deprecation";
+      NODE_ENV = "production";
+      TYPEORM_DATABASE = "${dataDir}/home.sqlite3";
+    };
+
+    serviceConfig = {
+      ExecStart = "${lib.getExe pkgs.grist-core}";
+      DynamicUser = true;
+      StateDirectory = "grist";
+      StateDirectoryMode = "0700";
+      WorkingDirectory = dataDir;
+      Restart = "always";
+      ReadWritePaths = [ dataDir ];
+      ProtectSystem = "strict";
+      ProtectHome = true;
+      PrivateTmp = true;
+      NoNewPrivileges = true;
+      RestrictSUIDSGID = true;
+    };
+
+    preStart = ''
+      mkdir -p ${dataDir}/docs
+    '';
+  };
+
+  networking = {
+    firewall.allowedTCPPorts = [ 8484 ];
+    interfaces.eth0 = {
+      ipv4.addresses = [
+        {
+          address = "192.168.1.2";
+          prefixLength = 24;
+        }
+      ];
+    };
+    defaultGateway = "192.168.1.1";
+    nameservers = [ "8.8.8.8" ];
+    useDHCP = false;
+  };
+
+  boot.isContainer = true;
+  system.stateVersion = "25.05";
+}

+ 24 - 6
hosts/odin/default.nix

@@ -1,9 +1,8 @@
-{
-  config,
-  lib,
-  pkgs,
-  outputs,
-  ...
+{ config
+, lib
+, pkgs
+, outputs
+, ...
 }:
 {
   imports = [
@@ -57,6 +56,23 @@
   #   };
   # };
 
+  containers.grist-latest = {
+    autoStart = false;
+    privateNetwork = true;
+    hostAddress = "192.168.1.1";
+    localAddress = "192.168.1.2";
+    specialArgs = { inherit outputs; };
+    config = import ./containers/grist.nix;
+  };
+
+  services.caddy.virtualHosts.grist = {
+    hostName = "grist.{$DOMAIN}";
+    extraConfig = ''
+      encode gzip zstd
+      reverse_proxy 192.168.1.2:8484
+    '';
+  };
+
   programs.fish = {
     enable = true;
     vendor = {
@@ -71,6 +87,8 @@
   ];
 
   # System packages
+  # nixos-container create grist --flake .#grist --host-address "192.168.1.1" --local-address
+
   environment.systemPackages = with pkgs; [
     # System utilities
     git

+ 5 - 5
hosts/odin/system/default.nix

@@ -1,8 +1,7 @@
-{
-  config,
-  inputs,
-  pkgs,
-  ...
+{ config
+, inputs
+, pkgs
+, ...
 }:
 {
   imports = [
@@ -44,6 +43,7 @@
       "net.core.default_qdisc" = "cake";
     };
 
+    enableContainers = true;
   };
 
   hardware.fancontrol = {

+ 1 - 1
packages/default.nix

@@ -14,7 +14,7 @@
 {
   aerospace-tmux-focus = pkgs.callPackage ./aerospace-tmux-focus.nix { };
   default = pkgs.callPackage ./quick-setup.nix { };
-  grist-core = pkgs.callPackage ./grist-core.nix { };
+  grist-core = pkgs.callPackage ./grist-core { };
   go-avahi-cname = pkgs.callPackage ./go-avahi-cname.nix { };
   hello = pkgs.callPackage ./hello.nix { };
   nct6775-pwm-udev-package = pkgs.callPackage ./nct6775-pwm-udev-package.nix { };

+ 57 - 14
packages/grist-core.nix → packages/grist-core/default.nix

@@ -14,9 +14,33 @@
 , apple-sdk
 , cctools
 , cacert
-, gvisor
-,
+, fetchPypi
+, python3Packages
 }:
+
+let
+  friendly-traceback = python3Packages.buildPythonPackage rec {
+    pname = "friendly-traceback";
+    version = "0.7.48";
+
+    format = "setuptools";
+
+    src = fetchPypi {
+      inherit pname version;
+      hash = "sha256-A4TEnu4W30GzNWvzBxsDHqqFzaW0tBQgy74J2f+CcKA=";
+    };
+
+    propagatedBuildInputs = with python3.pkgs; [
+      asttokens
+      executing
+      pure-eval
+      stack-data
+    ];
+
+    doCheck = false;
+  };
+in
+
 stdenv.mkDerivation rec {
   pname = "grist-core";
   version = "1.7.8";
@@ -33,9 +57,23 @@ stdenv.mkDerivation rec {
     hash = "sha256-7zyuBxheftgCXGjjJ+rdwSslIro9IEd/uvmo4xp6I+Q=";
   };
 
+  gristPython = python3.withPackages (pkgs: with pkgs; [
+    friendly-traceback
+    openpyxl
+    astroid
+    roman
+    chardet
+    iso8601
+    phonenumberslite
+    python-dateutil
+    sortedcontainers
+    unittest-xml-reporting
+  ]);
+
   nativeBuildInputs = [
     yarn
     nodejs
+    nodejs.pkgs.node-pre-gyp
     prefetch-yarn-deps
     fixup-yarn-lock
     makeWrapper
@@ -49,8 +87,6 @@ stdenv.mkDerivation rec {
     sqlite
   ] ++ lib.optionals stdenv.hostPlatform.isDarwin [
     apple-sdk
-  ] ++ lib.optionals stdenv.hostPlatform.isLinux [
-    gvisor
   ];
 
   passthru = {
@@ -62,12 +98,8 @@ stdenv.mkDerivation rec {
     runHook preConfigure
 
     export HOME=$(mktemp -d)
-
     rm .yarnrc
 
-    yarn config --offline set yarn-offline-mirror ${offlineCache}
-    fixup-yarn-lock yarn.lock
-
     mkdir -p "$HOME/.node-gyp/${nodejs.version}"
     echo 9 >"$HOME/.node-gyp/${nodejs.version}/installVersion"
     ln -sfv "${nodejs}/include" "$HOME/.node-gyp/${nodejs.version}"
@@ -82,8 +114,10 @@ stdenv.mkDerivation rec {
       export PATH="${cctools}/bin:$PATH"
     ''}
 
-    yarn --offline --frozen-lockfile --ignore-platform --ignore-engines --ignore-optional --no-progress --non-interactive install
-    yarn install:python
+    fixup-yarn-lock yarn.lock
+
+    yarn config --offline set yarn-offline-mirror ${offlineCache}
+    yarn --offline --frozen-lockfile --ignore-platform --ignore-engines --no-progress --non-interactive install
 
     patchShebangs node_modules
     patchShebangs buildtools
@@ -93,9 +127,7 @@ stdenv.mkDerivation rec {
 
   buildPhase = ''
     runHook preBuild
-
     yarn --offline run build:prod
-
     runHook postBuild
   '';
 
@@ -104,13 +136,15 @@ stdenv.mkDerivation rec {
 
     mkdir -p "$out/libexec" "$out/bin"
 
-    # Copy runtime files + the sandbox venv
-    cp -r _build node_modules plugins sandbox static bower_components package.json sandbox_venv3 $out/libexec/
+    cp -r _build node_modules plugins sandbox static bower_components package.json $out/libexec/
+    cp -r ${gristPython} $out/libexec/sandbox_venv3
 
     makeWrapper ${lib.getExe nodejs} $out/bin/grist-core \
       --add-flags "$out/libexec/_build/stubs/app/server/server.js" \
       --set "GRIST_PYTHON_VIRTUALENV" "$out/libexec/sandbox_venv3" \
       --set "NODE_PATH" "$out/libexec/_build:$out/libexec/_build/stubs:$out/libexec/_build/ext" \
+      --set "LD_LIBRARY_PATH" "$out/libexec/sandbox_venv3/lib" \
+      --prefix PATH : ${gristPython}/bin \
       --chdir "$out/libexec"
 
     runHook postInstall
@@ -127,6 +161,15 @@ stdenv.mkDerivation rec {
     
     # Remove problematic .bin directories
     find $out/libexec/node_modules -name '.bin' -type d -print0 | xargs -0 rm -rf 2>/dev/null || true
+    
+    # Fix ELF binaries in Python virtual environment using autoPatchelf
+    if [ -d "$out/libexec/sandbox_venv3" ]; then
+      find "$out/libexec/sandbox_venv3" -type f -executable \
+        -exec sh -c "file -i '{}' | grep -qE 'x-(.*); charset=binary'" \; -print |
+        while read file; do
+          autoPatchelf "$file" || true
+        done
+    fi
   '';
 
   meta = {