forgot to commit for a while
parent
a8477a818d
commit
db966f0329
13
Makefile
13
Makefile
|
@ -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
|
||||
|
|
|
@ -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
263
flake.nix
|
@ -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;
|
||||
};
|
||||
})
|
||||
]);
|
||||
};
|
||||
};
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
})
|
||||
})
|
||||
];
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue