panel deploys thru model

Signed-off-by: Kiara Grouwstra <kiara@procolix.eu>
This commit is contained in:
Kiara Grouwstra 2025-11-23 16:08:51 +01:00
parent 1fef30fa58
commit da16381a9b
Signed by: kiara
SSH key fingerprint: SHA256:COspvLoLJ5WC5rFb9ZDe5urVCkK4LJZOsjfF4duRJFU
10 changed files with 103 additions and 86 deletions

View file

@ -4,6 +4,7 @@
ancilliary,
sources ? import ../../npins,
conf ? { },
key-file ? null,
...
}@args:
let
@ -19,7 +20,6 @@ let
};
sshOpts = [ ];
username = "root";
key-file = null;
apps = lib.attrNames host-mapping;
nodes = lib.attrNames ancilliary ++ apps;
hosts = ancilliary // host-mapping;

View file

@ -14,61 +14,69 @@
...
}:
let
inherit (lib) types mkOption;
inherit (lib) types mkOption mkEnableOption;
inherit (types)
enum
nullOr
submodule
str
;
in
{
_class = "nixops4Deployment";
options = {
enable = lib.mkEnableOption "Fediversity configuration";
enable = mkEnableOption "Fediversity configuration";
domain = mkOption {
type =
with types;
enum [
"fediversity.net"
];
type = enum [
"fediversity.net"
];
description = ''
Apex domain under which the services will be deployed.
'';
default = "fediversity.net";
};
pixelfed = mkOption {
applications = mkOption {
description = ''
Configuration for the Pixelfed service
Applications to deploy.
'';
type =
with types;
nullOr (submodule {
options = {
enable = lib.mkEnableOption "Pixelfed";
type = nullOr (submodule {
options = {
pixelfed = mkOption {
description = ''
Configuration for the Pixelfed service
'';
type = nullOr (submodule {
options = {
enable = mkEnableOption "Pixelfed";
};
});
default = null;
};
});
default = null;
};
peertube = mkOption {
description = ''
Configuration for the PeerTube service
'';
type =
with types;
nullOr (submodule {
options = {
enable = lib.mkEnableOption "Peertube";
peertube = mkOption {
description = ''
Configuration for the PeerTube service
'';
type = nullOr (submodule {
options = {
enable = mkEnableOption "Peertube";
};
});
default = null;
};
});
default = null;
};
mastodon = mkOption {
description = ''
Configuration for the Mastodon service
'';
type =
with types;
nullOr (submodule {
options = {
enable = lib.mkEnableOption "Mastodon";
mastodon = mkOption {
description = ''
Configuration for the Mastodon service
'';
type = nullOr (submodule {
options = {
enable = mkEnableOption "Mastodon";
};
});
default = null;
};
});
};
});
default = null;
};
initialUser = mkOption {
@ -76,28 +84,26 @@ in
Some services require an initial user to access them.
This option sets the credentials for such an initial user.
'';
type =
with types;
nullOr (submodule {
options = {
displayName = mkOption {
type = types.str;
description = "Display name of the user";
};
username = mkOption {
type = types.str;
description = "Username for login";
};
email = mkOption {
type = types.str;
description = "User's email address";
};
password = mkOption {
type = types.str;
description = "Password for login";
};
type = nullOr (submodule {
options = {
displayName = mkOption {
type = str;
description = "Display name of the user";
};
});
username = mkOption {
type = str;
description = "Username for login";
};
email = mkOption {
type = str;
description = "User's email address";
};
password = mkOption {
type = str;
description = "Password for login";
};
};
});
default = null;
};
};

View file

@ -1,6 +1,7 @@
let
inherit (import ../default.nix { }) pkgs;
inherit (pkgs.callPackage ./utils.nix { })
optionalEnv
mapKeys
getSomeAttrs
evalOption
@ -16,6 +17,11 @@ in
{
_class = "nix-unit";
test-optionalEnv = {
expr = optionalEnv "NOT_SET";
expected = null;
};
test-mapKeys = {
expr = mapKeys (k: "${k}${k}") { a = 1; };
expected = {

View file

@ -5,6 +5,13 @@
...
}:
rec {
optionalEnv =
k:
let
v = builtins.getEnv k;
in
if v != "" then v else null;
mapKeys =
keyMapper:
lib.mapAttrs' (

View file

@ -54,6 +54,7 @@
};
apps =
let
inherit (pkgs.callPackage ./deployment/utils.nix { }) optionalEnv;
default-configuration = builtins.fromJSON (
let
env = builtins.getEnv "DEPLOYMENT";
@ -74,6 +75,11 @@
(import ./deployment/fediversity {
inherit system host-mapping;
ancilliary.garage = "test01";
key-file =
let
key = optionalEnv "SSH_PRIVATE_KEY_FILE";
in
builtins.trace ("SSH_PRIVATE_KEY_FILE: " + builtins.toString key) key;
conf."default-configuration" = default-configuration // {
enable = true;
applications = lib.mapAttrs (_app: _: { enable = true; }) host-mapping;

View file

@ -9,6 +9,7 @@
}:
let
inherit (pkgs) lib;
inherit (pkgs.callPackage ../deployment/utils.nix { }) optionalEnv;
manage = pkgs.writeScriptBin "manage" ''
exec ${pkgs.lib.getExe pkgs.python3} ${toString ./src/manage.py} $@
'';
@ -28,10 +29,15 @@ in
];
env = {
DEPLOYMENT_FLAKE = toString ../.;
DEPLOYMENT_NAME = "test";
DEPLOYMENT_NAME = "operator";
NPINS_DIRECTORY = toString ../npins;
CREDENTIALS_DIRECTORY = toString ./.credentials;
DATABASE_URL = "sqlite:///${toString ./src}/db.sqlite3";
SSH_PRIVATE_KEY_FILE =
let
key = optionalEnv "SSH_PRIVATE_KEY_FILE";
in
builtins.trace ("SSH_PRIVATE_KEY_FILE: " + builtins.toString key) key;
};
shellHook = ''
${lib.concatStringsSep "\n" (

View file

@ -137,19 +137,6 @@ in
type = types.attrsOf types.path;
default = { };
};
nixops4Package = mkOption {
type = types.package;
description = ''
A package providing NixOps4.
TODO: This should not be at the level of the NixOS module, but instead
at the level of the panel's package. Until one finds a way to grab
NixOps4 from the package's npins-based code, we will have to do with
this workaround.
'';
default = pkgs.nixops4;
};
deployment = {
flake = mkOption {
type = types.path;
@ -160,7 +147,7 @@ in
};
name = mkOption {
type = types.str;
default = "test";
default = "operator";
description = ''
The name of the deployment within the flake.
'';
@ -213,9 +200,6 @@ in
path = [
python-environment
manage-service
## NixOps4 and its dependencies
cfg.nixops4Package
pkgs.nix
pkgs.openssh
pkgs.git

View file

@ -8,6 +8,7 @@
sources ? import ../../npins,
}:
let
inherit (builtins) toFile toJSON;
src =
with lib.fileset;
toSource {
@ -33,7 +34,7 @@ let
let
jsonschema = callPackage "${sources.clan-core}/lib/jsonschema" { } { };
frontend-options = jsonschema.parseModule ../../deployment/options.nix;
schema = with builtins; toFile "schema.json" (toJSON frontend-options);
schema = toFile "schema.json" (toJSON frontend-options);
in
[
{
@ -69,7 +70,7 @@ python3.pkgs.buildPythonPackage {
preBuild = ''
echo "recursive-include ${name} *" > MANIFEST.in
cp ${builtins.toFile "source" pyproject-toml} pyproject.toml
cp ${toFile "source" pyproject-toml} pyproject.toml
'';
propagatedBuildInputs =

View file

@ -32,7 +32,7 @@ class ConfigurationForm(TestCase):
form_data = context['serializer'].instance.dict().copy()
form_data = {
"enable": True,
"mastodon.enable": True,
"applications.mastodon.enable": True,
}
response = self.client.post(self.config_url, data=form_data, follow=True)

View file

@ -90,15 +90,16 @@ class DeploymentStatus(ConfigurationForm):
def deployment(self, config: BaseModel):
env = {
"PATH": os.environ.get("PATH"),
"SSH_PRIVATE_KEY_FILE": os.environ.get("SSH_PRIVATE_KEY_FILE"),
# pass in form info to our deployment
"DEPLOYMENT": config.json()
}
cmd = [
"nixops4",
"apply",
settings.deployment_name,
"nix",
"run",
"--impure",
f".#{settings.deployment_name}",
"--show-trace",
"--no-interactive",
]
deployment_result = subprocess.run(
cmd,