forked from fediversity/fediversity
Compare commits
10 commits
69579fea1c
...
350245c097
Author | SHA1 | Date | |
---|---|---|---|
350245c097 | |||
631ce8a92d | |||
09119803e8 | |||
4dd1491e71 | |||
2f55e1512a | |||
b59f8a4183 | |||
56b953526b | |||
1f8677e83d | |||
2fae356d0a | |||
046f7c5998 |
11 changed files with 85 additions and 48 deletions
|
@ -79,10 +79,16 @@ in
|
||||||
## and check that they are working properly.
|
## and check that they are working properly.
|
||||||
|
|
||||||
extraTestScript = ''
|
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"):
|
with subtest("Run deployment with no services enabled"):
|
||||||
deployer.succeed("nixops4 apply check-deployment-cli-nothing --show-trace --no-interactive 1>&2")
|
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")
|
garage.fail("systemctl status garage.service")
|
||||||
mastodon.fail("systemctl status mastodon-web.service")
|
mastodon.fail("systemctl status mastodon-web.service")
|
||||||
peertube.fail("systemctl status peertube.service")
|
peertube.fail("systemctl status peertube.service")
|
||||||
|
|
|
@ -53,6 +53,7 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
|
acmeNodeIP = config.nodes.acme.networking.primaryIPAddress;
|
||||||
|
|
||||||
nodes =
|
nodes =
|
||||||
{
|
{
|
||||||
|
|
|
@ -50,13 +50,16 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
security.pki.certificateFiles = [
|
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
|
testCerts.ca.cert
|
||||||
];
|
];
|
||||||
|
|
||||||
## FIXME: it is a bit sad that all this logistics is necessary. look into
|
## FIXME: it is a bit sad that all this logistics is necessary. look into
|
||||||
## better DNS stuff
|
## better DNS stuff
|
||||||
networking.extraHosts = "${config.acmeNodeIP} acme.test";
|
networking.extraHosts = "${config.acmeNodeIP} acme.test";
|
||||||
|
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,11 +33,25 @@
|
||||||
## information coming from the FediPanel.
|
## information coming from the FediPanel.
|
||||||
##
|
##
|
||||||
## FIXME: lock step the interface with the definitions in the FediPanel
|
## FIXME: lock step the interface with the definitions in the FediPanel
|
||||||
panelConfig:
|
panelConfigNullable:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) mkIf;
|
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
|
in
|
||||||
|
|
||||||
## Regular arguments of a NixOps4 deployment module.
|
## Regular arguments of a NixOps4 deployment module.
|
||||||
|
@ -122,7 +136,7 @@ in
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
mkIf (cfg.mastodon.enable || cfg.peertube.enable || cfg.pixelfed.enable) {
|
mkIf (cfg.mastodon.enable || cfg.peertube.enable || cfg.pixelfed.enable) {
|
||||||
fediversity = {
|
fediversity = {
|
||||||
inherit (panelConfig) domain;
|
inherit (cfg) domain;
|
||||||
garage.enable = true;
|
garage.enable = true;
|
||||||
pixelfed = pixelfedS3KeyConfig { inherit pkgs; };
|
pixelfed = pixelfedS3KeyConfig { inherit pkgs; };
|
||||||
mastodon = mastodonS3KeyConfig { inherit pkgs; };
|
mastodon = mastodonS3KeyConfig { inherit pkgs; };
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{
|
{
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11"; # consumed by flake-parts
|
|
||||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||||
git-hooks.url = "github:cachix/git-hooks.nix";
|
git-hooks.url = "github:cachix/git-hooks.nix";
|
||||||
nixops4.follows = "nixops4-nixos/nixops4";
|
nixops4.follows = "nixops4-nixos/nixops4";
|
||||||
|
@ -11,9 +10,11 @@
|
||||||
inputs@{ flake-parts, ... }:
|
inputs@{ flake-parts, ... }:
|
||||||
let
|
let
|
||||||
sources = import ./npins;
|
sources = import ./npins;
|
||||||
|
inherit (import "${flake-inputs}/lib.nix") import-flake;
|
||||||
inherit (sources) git-hooks agenix;
|
inherit (sources) git-hooks agenix;
|
||||||
|
nixpkgs = import-flake sources.nixpkgs;
|
||||||
in
|
in
|
||||||
flake-parts.lib.mkFlake { inherit inputs; } {
|
flake-parts.lib.mkFlake { inputs = inputs // { inherit nixpkgs; }; } {
|
||||||
systems = [
|
systems = [
|
||||||
"x86_64-linux"
|
"x86_64-linux"
|
||||||
"aarch64-linux"
|
"aarch64-linux"
|
||||||
|
|
|
@ -25,6 +25,22 @@
|
||||||
"url": null,
|
"url": null,
|
||||||
"hash": "1w2gsy6qwxa5abkv8clb435237iifndcxq0s79wihqw11a5yb938"
|
"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": {
|
"flake-parts": {
|
||||||
"type": "Git",
|
"type": "Git",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -9,10 +9,4 @@ in
|
||||||
{
|
{
|
||||||
REPO_DIR = toString ../.;
|
REPO_DIR = toString ../.;
|
||||||
# explicitly use nix, as e.g. lix does not have configurable-impure-env
|
# 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
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,7 +146,19 @@ in
|
||||||
${cfg.domain} =
|
${cfg.domain} =
|
||||||
{
|
{
|
||||||
locations = {
|
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/";
|
"/static/".alias = "/var/lib/${name}/static/";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -166,10 +178,18 @@ in
|
||||||
description = "${name} ASGI server";
|
description = "${name} ASGI server";
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
path = [
|
path =
|
||||||
|
[
|
||||||
python-environment
|
python-environment
|
||||||
manage-service
|
manage-service
|
||||||
];
|
]
|
||||||
|
++ (
|
||||||
|
with pkgs;
|
||||||
|
lib.mkBinPath [
|
||||||
|
nix
|
||||||
|
git
|
||||||
|
]
|
||||||
|
);
|
||||||
preStart = ''
|
preStart = ''
|
||||||
# Auto-migrate on first run or if the package has changed
|
# Auto-migrate on first run or if the package has changed
|
||||||
versionFile="/var/lib/${name}/package-version"
|
versionFile="/var/lib/${name}/package-version"
|
||||||
|
|
|
@ -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.
|
# 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.
|
# 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.
|
# path of the root flake to trigger nixops from, see #94.
|
||||||
# to deploy this should be specified, for dev just use a relative path.
|
# to deploy this should be specified, for dev just use a relative path.
|
||||||
repo_dir = env["REPO_DIR"]
|
repo_dir = env["REPO_DIR"]
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.template import Template, Context
|
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
|
|
||||||
|
from panel.templatetags.custom_tags import auth_url
|
||||||
|
|
||||||
class Login(TestCase):
|
class Login(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.username = 'testuser'
|
self.username = 'testuser'
|
||||||
|
@ -27,8 +28,7 @@ class Login(TestCase):
|
||||||
|
|
||||||
# check that the expected login URL is in the response
|
# check that the expected login URL is in the response
|
||||||
context = response.context[0]
|
context = response.context[0]
|
||||||
template = Template("{% load custom_tags %}{% auth_url 'login' %}")
|
login_url = auth_url(context, 'login')
|
||||||
login_url = template.render(context)
|
|
||||||
self.assertIn(login_url, response.content.decode('utf-8'))
|
self.assertIn(login_url, response.content.decode('utf-8'))
|
||||||
|
|
||||||
# log in
|
# log in
|
||||||
|
@ -49,8 +49,7 @@ class Login(TestCase):
|
||||||
|
|
||||||
# check that the expected logout URL is present
|
# check that the expected logout URL is present
|
||||||
context = response.context[0]
|
context = response.context[0]
|
||||||
template = Template("{% load custom_tags %}{% auth_url 'logout' %}")
|
logout_url = auth_url(context, 'logout')
|
||||||
logout_url = template.render(context)
|
|
||||||
self.assertIn(logout_url, response.content.decode('utf-8'))
|
self.assertIn(logout_url, response.content.decode('utf-8'))
|
||||||
|
|
||||||
# log out again
|
# log out again
|
||||||
|
@ -88,8 +87,7 @@ class Login(TestCase):
|
||||||
|
|
||||||
# check that the expected logout URL is present
|
# check that the expected logout URL is present
|
||||||
context = response.context[0]
|
context = response.context[0]
|
||||||
template = Template("{% load custom_tags %}{% auth_url 'logout' %}")
|
logout_url = auth_url(context, 'logout')
|
||||||
logout_url = template.render(context)
|
|
||||||
self.assertIn(logout_url, response.content.decode('utf-8'))
|
self.assertIn(logout_url, response.content.decode('utf-8'))
|
||||||
|
|
||||||
# log out
|
# log out
|
||||||
|
@ -97,8 +95,7 @@ class Login(TestCase):
|
||||||
|
|
||||||
# check that we're at the expected location, logged out
|
# check that we're at the expected location, logged out
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
template = Template("{% load custom_tags %}{% auth_url 'login' %}")
|
login_url = auth_url(context, 'login')
|
||||||
login_url = template.render(context)
|
|
||||||
location, status = response.redirect_chain[-1]
|
location, status = response.redirect_chain[-1]
|
||||||
self.assertEqual(location, unquote(login_url))
|
self.assertEqual(location, unquote(login_url))
|
||||||
self.assertFalse(response.context['user'].is_authenticated)
|
self.assertFalse(response.context['user'].is_authenticated)
|
||||||
|
|
|
@ -65,9 +65,6 @@ class ConfigurationForm(LoginRequiredMixin, APIView):
|
||||||
config.save()
|
config.save()
|
||||||
return redirect(self.success_url)
|
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):
|
class DeploymentStatus(ConfigurationForm):
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
|
@ -84,28 +81,15 @@ class DeploymentStatus(ConfigurationForm):
|
||||||
config.save()
|
config.save()
|
||||||
|
|
||||||
deployment_result, deployment_params = self.deployment(config.parsed_value)
|
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", {
|
return render(self.request, "partials/deployment_result.html", {
|
||||||
"deployment_status": deployment_status,
|
"deployment_succeeded": (deployment_result.returncode == 0),
|
||||||
"services": deployment_params.json(),
|
"services": deployment_params.json(),
|
||||||
})
|
})
|
||||||
|
|
||||||
def deployment(self, config: BaseModel):
|
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 = {
|
env = {
|
||||||
"PATH": settings.bin_path,
|
"PATH": os.environ.get("PATH"),
|
||||||
# pass in form info to our deployment
|
# pass in form info to our deployment
|
||||||
"DEPLOYMENT": config.json()
|
"DEPLOYMENT": config.json()
|
||||||
}
|
}
|
||||||
|
@ -118,10 +102,13 @@ class DeploymentStatus(ConfigurationForm):
|
||||||
"nixops4",
|
"nixops4",
|
||||||
"apply",
|
"apply",
|
||||||
"test",
|
"test",
|
||||||
|
"--show-trace",
|
||||||
|
"--no-interactive",
|
||||||
]
|
]
|
||||||
deployment_result = subprocess.run(
|
deployment_result = subprocess.run(
|
||||||
cmd,
|
cmd,
|
||||||
cwd = settings.repo_dir,
|
cwd = settings.repo_dir,
|
||||||
env = env,
|
env = env,
|
||||||
|
stderr = subprocess.STDOUT,
|
||||||
)
|
)
|
||||||
return deployment_result, config
|
return deployment_result, config
|
||||||
|
|
Loading…
Add table
Reference in a new issue