Compare commits

...

10 commits

Author SHA1 Message Date
350245c097 use deployed environment for launching nixops4 from the panel
this still needs more work to clean up fully
2025-06-06 12:14:34 +02:00
631ce8a92d use Nixpkgs from npins in the flake 2025-06-06 12:13:51 +02:00
09119803e8 Deployment: handle nullable config fields
This is quite frustrating. In the meantime, it does get the deployment
working again.
2025-06-06 11:50:48 +02:00
4dd1491e71 FediPanel: fix deployment status
also remove unused `dummy_user`
2025-06-06 11:02:40 +02:00
2f55e1512a FediPanel: bump nginx timeout to an hour 2025-06-06 10:57:19 +02:00
b59f8a4183 simplify login tests (#352)
don't go through template generation but use underlying the tag
implementation directly

Co-authored-by: Nicolas Jeannerod <nicolas.jeannerod@moduscreate.com>
Reviewed-on: Fediversity/Fediversity#352
2025-06-06 10:56:34 +02:00
56b953526b Deployment tests: Check status of services before deploying 2025-06-06 10:54:06 +02:00
1f8677e83d FediPanel: better logging of NixOps4 2025-06-06 10:53:22 +02:00
2fae356d0a Deployment tests: also make acmeNodeIP available in NixOS test 2025-06-06 10:52:49 +02:00
046f7c5998 Deployment tests: comment on Pebble's certificate 2025-06-06 10:52:18 +02:00
11 changed files with 85 additions and 48 deletions

View file

@ -79,10 +79,16 @@ in
## and check that they are working properly.
extraTestScript = ''
with subtest("Check the status of the services - there should be none"):
garage.fail("systemctl status garage.service")
mastodon.fail("systemctl status mastodon-web.service")
peertube.fail("systemctl status peertube.service")
pixelfed.fail("systemctl status phpfpm-pixelfed.service")
with subtest("Run deployment with no services enabled"):
deployer.succeed("nixops4 apply check-deployment-cli-nothing --show-trace --no-interactive 1>&2")
with subtest("Check the status of the services - there should be none"):
with subtest("Check the status of the services - there should still be none"):
garage.fail("systemctl status garage.service")
mastodon.fail("systemctl status mastodon-web.service")
peertube.fail("systemctl status peertube.service")

View file

@ -53,6 +53,7 @@ in
};
config = {
acmeNodeIP = config.nodes.acme.networking.primaryIPAddress;
nodes =
{

View file

@ -50,13 +50,16 @@ in
};
security.pki.certificateFiles = [
## NOTE: This certificate is the one used by the Pebble HTTPS server.
## This is NOT the root CA of the Pebble server. We do add it here so
## that Pebble clients can talk to its API, but this will not allow
## those machines to verify generated certificates.
testCerts.ca.cert
];
## FIXME: it is a bit sad that all this logistics is necessary. look into
## better DNS stuff
networking.extraHosts = "${config.acmeNodeIP} acme.test";
})
];
}

View file

@ -33,11 +33,25 @@
## information coming from the FediPanel.
##
## FIXME: lock step the interface with the definitions in the FediPanel
panelConfig:
panelConfigNullable:
let
inherit (lib) mkIf;
nonNull = x: v: if x == null then v else x;
panelConfig = {
domain = nonNull panelConfigNullable.domain "fediversity.net";
initialUser = nonNull panelConfigNullable.initialUser {
displayName = "Testy McTestface";
username = "test";
password = "testtest";
email = "test@test.com";
};
mastodon = nonNull panelConfigNullable.mastodon { enable = false; };
peertube = nonNull panelConfigNullable.peertube { enable = false; };
pixelfed = nonNull panelConfigNullable.pixelfed { enable = false; };
};
in
## Regular arguments of a NixOps4 deployment module.
@ -122,7 +136,7 @@ in
{ pkgs, ... }:
mkIf (cfg.mastodon.enable || cfg.peertube.enable || cfg.pixelfed.enable) {
fediversity = {
inherit (panelConfig) domain;
inherit (cfg) domain;
garage.enable = true;
pixelfed = pixelfedS3KeyConfig { inherit pkgs; };
mastodon = mastodonS3KeyConfig { inherit pkgs; };

View file

@ -1,6 +1,5 @@
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11"; # consumed by flake-parts
flake-parts.url = "github:hercules-ci/flake-parts";
git-hooks.url = "github:cachix/git-hooks.nix";
nixops4.follows = "nixops4-nixos/nixops4";
@ -11,9 +10,11 @@
inputs@{ flake-parts, ... }:
let
sources = import ./npins;
inherit (import "${flake-inputs}/lib.nix") import-flake;
inherit (sources) git-hooks agenix;
nixpkgs = import-flake sources.nixpkgs;
in
flake-parts.lib.mkFlake { inherit inputs; } {
flake-parts.lib.mkFlake { inputs = inputs // { inherit nixpkgs; }; } {
systems = [
"x86_64-linux"
"aarch64-linux"

View file

@ -25,6 +25,22 @@
"url": null,
"hash": "1w2gsy6qwxa5abkv8clb435237iifndcxq0s79wihqw11a5yb938"
},
"flake-inputs": {
"type": "GitRelease",
"repository": {
"type": "GitHub",
"owner": "fricklerhandwerk",
"repo": "flake-inputs"
},
"pre_releases": false,
"version_upper_bound": null,
"release_prefix": null,
"submodules": false,
"version": "1.1",
"revision": "6461d0b56e790bf289af07c5e5261abbf4f536af",
"url": "https://api.github.com/repos/fricklerhandwerk/flake-inputs/tarball/1.1",
"hash": "03mwisvr1mc3nd33nvg4bvcyxjxpm4lwhwym39r0768cm1007ixl"
},
"flake-parts": {
"type": "Git",
"repository": {

View file

@ -9,10 +9,4 @@ in
{
REPO_DIR = toString ../.;
# explicitly use nix, as e.g. lix does not have configurable-impure-env
BIN_PATH = lib.makeBinPath [
# explicitly use nix, as e.g. lix does not have configurable-impure-env
pkgs.nix
# nixops error maybe due to our flake git hook: executing 'git': No such file or directory
pkgs.git
];
}

View file

@ -146,7 +146,19 @@ in
${cfg.domain} =
{
locations = {
"/".proxyPass = "http://localhost:${toString cfg.port}";
"/" = {
proxyPass = "http://localhost:${toString cfg.port}";
extraConfig = ''
## FIXME: The following is necessary because /deployment/status
## can take aaaaages to respond. I think this is horrendous
## design from the panel and should be changed there, but in the
## meantime we bump nginx's timeouts to one hour.
proxy_connect_timeout 3600;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
send_timeout 3600;
'';
};
"/static/".alias = "/var/lib/${name}/static/";
};
}
@ -166,10 +178,18 @@ in
description = "${name} ASGI server";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
path = [
python-environment
manage-service
];
path =
[
python-environment
manage-service
]
++ (
with pkgs;
lib.mkBinPath [
nix
git
]
);
preStart = ''
# Auto-migrate on first run or if the package has changed
versionFile="/var/lib/${name}/package-version"

View file

@ -240,8 +240,6 @@ if user_settings_file is not None:
# The correct thing to do here would be using a helper function such as with `get_secret()` that will catch the exception and explain what's wrong and where to put the right values.
# Replacing the `USER_SETTINGS_FILE` mechanism following the comment there would probably be a good thing.
# PATH to expose to launch button
bin_path=env['BIN_PATH']
# path of the root flake to trigger nixops from, see #94.
# to deploy this should be specified, for dev just use a relative path.
repo_dir = env["REPO_DIR"]

View file

@ -1,9 +1,10 @@
from django.test import TestCase
from django.urls import reverse
from django.contrib.auth.models import User
from django.template import Template, Context
from urllib.parse import unquote
from panel.templatetags.custom_tags import auth_url
class Login(TestCase):
def setUp(self):
self.username = 'testuser'
@ -27,8 +28,7 @@ class Login(TestCase):
# check that the expected login URL is in the response
context = response.context[0]
template = Template("{% load custom_tags %}{% auth_url 'login' %}")
login_url = template.render(context)
login_url = auth_url(context, 'login')
self.assertIn(login_url, response.content.decode('utf-8'))
# log in
@ -49,8 +49,7 @@ class Login(TestCase):
# check that the expected logout URL is present
context = response.context[0]
template = Template("{% load custom_tags %}{% auth_url 'logout' %}")
logout_url = template.render(context)
logout_url = auth_url(context, 'logout')
self.assertIn(logout_url, response.content.decode('utf-8'))
# log out again
@ -88,8 +87,7 @@ class Login(TestCase):
# check that the expected logout URL is present
context = response.context[0]
template = Template("{% load custom_tags %}{% auth_url 'logout' %}")
logout_url = template.render(context)
logout_url = auth_url(context, 'logout')
self.assertIn(logout_url, response.content.decode('utf-8'))
# log out
@ -97,8 +95,7 @@ class Login(TestCase):
# check that we're at the expected location, logged out
self.assertEqual(response.status_code, 200)
template = Template("{% load custom_tags %}{% auth_url 'login' %}")
login_url = template.render(context)
login_url = auth_url(context, 'login')
location, status = response.redirect_chain[-1]
self.assertEqual(location, unquote(login_url))
self.assertFalse(response.context['user'].is_authenticated)

View file

@ -65,9 +65,6 @@ class ConfigurationForm(LoginRequiredMixin, APIView):
config.save()
return redirect(self.success_url)
# TODO(@fricklerhandwerk):
# this is broken after changing the form view.
# but if there's no test for it, how do we know it ever worked in the first place?
class DeploymentStatus(ConfigurationForm):
def post(self, request):
@ -84,28 +81,15 @@ class DeploymentStatus(ConfigurationForm):
config.save()
deployment_result, deployment_params = self.deployment(config.parsed_value)
if deployment_result.returncode == 0:
deployment_status = "Deployment Succeeded"
else:
deployment_status = "Deployment Failed"
return render(self.request, "partials/deployment_result.html", {
"deployment_status": deployment_status,
"deployment_succeeded": (deployment_result.returncode == 0),
"services": deployment_params.json(),
})
def deployment(self, config: BaseModel):
# FIXME: let the user specify these from the form (#190)
dummy_user = {
"initialUser": {
"displayName": "Testy McTestface",
"username": "test",
"password": "testtest",
"email": "test@test.com",
},
}
env = {
"PATH": settings.bin_path,
"PATH": os.environ.get("PATH"),
# pass in form info to our deployment
"DEPLOYMENT": config.json()
}
@ -118,10 +102,13 @@ class DeploymentStatus(ConfigurationForm):
"nixops4",
"apply",
"test",
"--show-trace",
"--no-interactive",
]
deployment_result = subprocess.run(
cmd,
cwd=settings.repo_dir,
env=env,
cwd = settings.repo_dir,
env = env,
stderr = subprocess.STDOUT,
)
return deployment_result, config