forgot to commit for a while

feature/csv-import
Sam Hatfield 2022-02-15 21:59:01 -06:00
parent a8477a818d
commit db966f0329
7 changed files with 190 additions and 186 deletions

2
.envrc
View File

@ -1 +1,3 @@
use flake
dotenv .env

View File

@ -1,3 +1,16 @@
.PHONY: clean
clean:
if [ -L "result" ] then rm result fi
${MAKE} -C tests clean
.PHONY: api
api:
nix build .#api
.PHONY: app
app:
nix build .#app
.PHONY: test-build
test-build:
${MAKE} -C tests build

View File

@ -1,22 +1,21 @@
let
urlDefaults = {
scheme = "http";
domain = "localhost";
subdir = "/";
};
attrsToUrl = { scheme, domain, subdir }:
"${if builtins.isString scheme then "${scheme}://" else ""}${domain}${subdir}";
in { pkgs ? import <nixpkgs> { }, webUrl ? { }, apiUrl ? "http://localhost", ...
}:
let web = urlDefaults // webUrl;
in pkgs.yarn2nix-moretea.mkYarnPackage {
attrsToUrl = { scheme ? null, domain ? null, subdir ? "" }:
with builtins;
let
protocol = if isNull scheme then "" else "${scheme}://";
maybeLocalhost = if isNull domain then "" else domain;
in "${protocol}${maybeLocalhost}${subdir}";
in { pkgs ? import <nixpkgs> { }, webAttrs ? { }, apiAttrs ? { }, ... }:
pkgs.yarn2nix-moretea.mkYarnPackage {
pname = "pea-app";
version = "0.1.0";
src = ./.;
buildPhase = ''
export PUBLIC_URL=${attrsToUrl web}
export REACT_APP_API_URL=${apiUrl}
export REACT_APP_SUBDIR=${web.subdir}
export PUBLIC_URL=${attrsToUrl webAttrs}
export REACT_APP_API_URL=${attrsToUrl apiAttrs}
export REACT_APP_SUBDIR=${
if (webAttrs ? subdir) then webAttrs.subdir else "/"
}
yarn --offline run build
'';
installPhase = ''

263
flake.nix
View File

@ -12,6 +12,24 @@
let
pkgs = nixpkgs.legacyPackages.${system};
apiPkg = buildPythonPackage { src = [ ./api ]; };
urlMod = lib:
with lib; {
options.scheme = mkOption {
type = with types; enum [ "http" "https" null ];
default = "http";
example = "https";
};
options.domain = mkOption {
type = with types; nullOr str;
default = null;
example = "pea.example.com";
};
options.subdir = mkOption {
type = types.str;
default = "/";
example = "/pea";
};
};
in {
packages = {
api = mkPython [ apiPkg ];
@ -22,30 +40,13 @@
api = mkPythonShell [ apiPkg ];
app = pkgs.callPackage ./app/shell.nix { };
};
devShell = with pkgs; mkShell { packages = [ gnumake ]; };
overlays = { api = mkOverlay [ apiPkg ]; };
nixosModules = let
nginxOpts = lib:
with lib; {
webUrl = mkOption {
type = with types;
submodule {
options.scheme = mkOption {
type = with types; enum [ "http" "https" null ];
default = "http";
example = "https";
};
options.domain = mkOption {
type = with types; nullOr str;
default = null;
example = "pea.example.com";
};
options.subdir = mkOption {
type = types.str;
default = "/";
example = "/pea";
};
};
};
webAttrs =
mkOption { type = with types; submodule (urlMod lib); };
acmeEmail = mkOption {
type = with types; nullOr str;
default = null;
@ -53,8 +54,8 @@
description = "The email to use for Let's Encrypt certificates";
};
};
newPkgs = mkNixpkgs [ apiPkg ];
maybeLocalhost = domain: if builtins.isNull domain then "localhost" else domain;
maybeLocalhost = domain:
if builtins.isNull domain then "localhost" else domain;
in {
api = { config, lib, pkgs, ... }:
with lib;
@ -90,88 +91,88 @@
};
} // nginxOpts lib;
config = mkIf cfg.enable (let
domain = maybeLocalhost cfg.webUrl.domain;
in mkMerge [
{
# basics
environment.systemPackages = [ cfg.package ];
# NGINX config
services.nginx = {
enable = true;
recommendedProxySettings = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedTlsSettings = true;
config = mkIf cfg.enable
(let domain = maybeLocalhost cfg.webAttrs.domain;
in mkMerge [
{
# basics
environment.systemPackages = [ cfg.package ];
# NGINX config
services.nginx = {
enable = true;
recommendedProxySettings = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedTlsSettings = true;
virtualHosts.${domain} = {
locations.${cfg.webUrl.subdir}.proxyPass =
"http://unix:${cfg.socketFile}";
};
};
# PostgreSQL config
services.postgresql = let db = "pea-db";
in {
enable = true;
package = pkgs.postgresql_14;
ensureDatabases = [ db ];
ensureUsers = [{
name = "pea-user";
ensurePermissions = {
"DATABASE \"${db}\"" = "ALL PRIVILEGES";
virtualHosts.${domain} = {
locations.${cfg.webAttrs.subdir}.proxyPass =
"http://unix:${cfg.socketFile}";
};
}];
identMap = ''
pea-map pea-api pea-user
'';
};
services.postgresqlBackup = {
enable = true;
backupAll = true;
};
# PEA API config
systemd.services.pea-api = {
description = "PEA API Uvicorn service";
after = [ "network.target" "postgresql.service" ];
requires = [ "pea-api.socket" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
WorkingDirectory =
"${cfg.package}/lib/python3.9/site-packages/pea_api/";
EnvironmentFile = cfg.dotEnvFile;
};
script = ''
${cfg.package}/bin/uvicorn main:app --uds ${cfg.socketFile}
'';
reload = ''
/bin/kill -s HUP $MAINPID
'';
};
systemd.sockets.pea-api = {
description = "PEA API Uvicorn socket";
wantedBy = [ "sockets.target" ];
socketConfig = { ListenStream = cfg.socketFile; };
};
# system user config
users.extraGroups.${cfg.group} = { };
users.extraUsers.${cfg.user} = {
isSystemUser = true;
group = cfg.group;
description = "PEA API user";
};
}
# PostgreSQL config
services.postgresql = let db = "pea-db";
in {
enable = true;
package = pkgs.postgresql_14;
ensureDatabases = [ db ];
ensureUsers = [{
name = "pea-user";
ensurePermissions = {
"DATABASE \"${db}\"" = "ALL PRIVILEGES";
};
}];
identMap = ''
pea-map pea-api pea-user
'';
};
services.postgresqlBackup = {
enable = true;
backupAll = true;
};
# PEA API config
systemd.services.pea-api = {
description = "PEA API Uvicorn service";
after = [ "network.target" "postgresql.service" ];
requires = [ "pea-api.socket" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
WorkingDirectory =
"${cfg.package}/lib/python3.9/site-packages/pea_api/";
EnvironmentFile = cfg.dotEnvFile;
};
script = ''
${cfg.package}/bin/uvicorn main:app --uds ${cfg.socketFile}
'';
reload = ''
/bin/kill -s HUP $MAINPID
'';
};
systemd.sockets.pea-api = {
description = "PEA API Uvicorn socket";
wantedBy = [ "sockets.target" ];
socketConfig = { ListenStream = cfg.socketFile; };
};
# system user config
users.extraGroups.${cfg.group} = { };
users.extraUsers.${cfg.user} = {
isSystemUser = true;
group = cfg.group;
description = "PEA API user";
};
}
(mkIf (isString cfg.acmeEmail) {
security.acme = {
acceptTerms = true;
certs.${domain}.email = cfg.acmeEmail;
};
services.nginx.virtualHosts.${domain} = {
enableACME = true;
forceSSL = true;
};
})
]);
(mkIf (isString cfg.acmeEmail) {
security.acme = {
acceptTerms = true;
certs.${domain}.email = cfg.acmeEmail;
};
services.nginx.virtualHosts.${domain} = {
enableACME = true;
forceSSL = true;
};
})
]);
};
app = { config, pkgs, lib, ... }:
with lib;
@ -182,41 +183,41 @@
mkEnableOption "Personal Effectivity Application UI service";
package = mkOption {
type = types.package;
default = self.outputs.packages.${system}.app;
default = self.outputs.packages.${system}.app.override {
inherit (cfg) webAttrs apiAttrs;
};
description = "The package to use for the service.";
};
apiUrl = mkOption {
type = types.str;
example = "http://example.com/api";
description = "The API URL to configure the app to use";
};
apiAttrs =
mkOption { type = with types; submodule (urlMod lib); };
} // nginxOpts lib;
config = mkIf cfg.enable (let
domain = maybeLocalhost cfg.webUrl.domain;
in mkMerge [
{
services.nginx = {
enable = true;
recommendedProxySettings = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedTlsSettings = true;
virtualHosts.${domain} = {
locations.${cfg.webUrl.subdir}.alias = "${cfg.package}/";
config = mkIf cfg.enable
(let domain = maybeLocalhost cfg.webAttrs.domain;
in mkMerge [
{
services.nginx = {
enable = true;
recommendedProxySettings = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedTlsSettings = true;
virtualHosts.${domain} = {
locations.${cfg.webAttrs.subdir}.alias =
"${cfg.package}/";
};
};
};
}
(mkIf (isString cfg.acmeEmail) {
security.acme = {
acceptTerms = true;
certs.${domain}.email = cfg.acmeEmail;
};
services.nginx.virtualHosts.${domain} = {
enableACME = true;
forceSSL = true;
};
})
]);
}
(mkIf (isString cfg.acmeEmail) {
security.acme = {
acceptTerms = true;
certs.${domain}.email = cfg.acmeEmail;
};
services.nginx.virtualHosts.${domain} = {
enableACME = true;
forceSSL = true;
};
})
]);
};
};
});

View File

@ -1,7 +1,3 @@
.PHONY: update
update:
nix flake update
.PHONY: build
build: update
nix build .#nixosConfigurations.container.config.system.build.toplevel
@ -9,3 +5,11 @@ build: update
.PHONY: deploy
deploy: update
sudo nixos-container update pea-test --flake .
.PHONY: update
update:
nix flake update
.PHONY: clean
clean:
rm result

View File

@ -33,7 +33,7 @@
"mach-nix": {
"inputs": {
"flake-utils": "flake-utils_2",
"nixpkgs": "nixpkgs_2",
"nixpkgs": "nixpkgs",
"pypi-deps-db": "pypi-deps-db"
},
"locked": {
@ -51,20 +51,6 @@
}
},
"nixpkgs": {
"locked": {
"lastModified": 1644486793,
"narHash": "sha256-EeijR4guVHgVv+JpOX3cQO+1XdrkJfGmiJ9XVsVU530=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1882c6b7368fd284ad01b0a5b5601ef136321292",
"type": "github"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1643805626,
"narHash": "sha256-AXLDVMG+UaAGsGSpOtQHPIKB+IZ0KSd9WS77aanGzgc=",
@ -79,7 +65,7 @@
"type": "indirect"
}
},
"nixpkgs_3": {
"nixpkgs_2": {
"locked": {
"lastModified": 1644600908,
"narHash": "sha256-TLWxMZAgn4o+y4DgCwzbzhI0vrZ45CmQo4EbhzhH1Ko=",
@ -98,10 +84,10 @@
"inputs": {
"flake-utils": "flake-utils",
"mach-nix": "mach-nix",
"nixpkgs": "nixpkgs_3"
"nixpkgs": "nixpkgs_2"
},
"locked": {
"narHash": "sha256-kLZkryNYiGkzLrslgz+SvjLORLT8XptpPBBwOofp+ZE=",
"narHash": "sha256-qj2Yv0A28Ek4uOEQFoknfthZmpsjEH+0Ny3+432gliE=",
"path": "..",
"type": "path"
},
@ -128,7 +114,6 @@
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs",
"pea": "pea"
}
}

View File

@ -1,12 +1,13 @@
{
description = "NixOS container flake configuration, for testing purposes";
description = "NixOS container flake configuration, for testing PEA";
inputs = { pea.url = "path:.."; };
outputs = { self, nixpkgs, pea }:
outputs = { self, pea, ... }:
let
nixpkgs = pea.inputs.nixpkgs;
system = "x86_64-linux";
pkgs = pea.inputs.nixpkgs.legacyPackages.${system};
pkgs = nixpkgs.legacyPackages.${system};
in {
devShell.${system} =
pkgs.mkShell { buildInputs = with pkgs; [ gnumake ]; };
@ -22,25 +23,24 @@
})
pea.nixosModules.${system}.api
pea.nixosModules.${system}.app
({ config, ... }: {
services.pea.api = {
enable = true;
dotEnvFile = "/run/keys/pea.env";
webUrl.subdir = "/api";
};
services.pea.app = {
enable = true;
package = pea.outputs.packages.${system}.app.override {
inherit (config.services.pea.app) webUrl apiUrl;
({ config, ... }:
let apiSubdir = "/api";
in {
services.pea.api = {
enable = true;
dotEnvFile = "/run/keys/pea.env";
webAttrs.subdir = apiSubdir;
};
webUrl = {
services.pea.app = {
enable = true;
webAttrs = {
scheme = null;
domain = "";
domain = null;
subdir = "/app/";
};
apiAttrs.subdir = apiSubdir;
};
apiUrl = "/api";
};
})
})
];
};
};