Merge pull request #252790 from anthonyroussel/gns3-nixos-module
nixos/gns3-server: init
This commit is contained in:
@@ -24,6 +24,8 @@ In addition to numerous new and upgraded packages, this release has the followin
|
|||||||
|
|
||||||
- [maubot](https://github.com/maubot/maubot), a plugin-based Matrix bot framework. Available as [services.maubot](#opt-services.maubot.enable).
|
- [maubot](https://github.com/maubot/maubot), a plugin-based Matrix bot framework. Available as [services.maubot](#opt-services.maubot.enable).
|
||||||
|
|
||||||
|
- [GNS3](https://www.gns3.com/), a network software emulator. Available as [services.gns3-server](#opt-services.gns3-server.enable).
|
||||||
|
|
||||||
- [Anki Sync Server](https://docs.ankiweb.net/sync-server.html), the official sync server built into recent versions of Anki. Available as [services.anki-sync-server](#opt-services.anki-sync-server.enable).
|
- [Anki Sync Server](https://docs.ankiweb.net/sync-server.html), the official sync server built into recent versions of Anki. Available as [services.anki-sync-server](#opt-services.anki-sync-server.enable).
|
||||||
The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been marked deprecated and will be dropped after 24.05 due to lack of maintenance of the anki-sync-server softwares.
|
The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been marked deprecated and will be dropped after 24.05 due to lack of maintenance of the anki-sync-server softwares.
|
||||||
|
|
||||||
|
|||||||
@@ -946,6 +946,7 @@
|
|||||||
./services/networking/ghostunnel.nix
|
./services/networking/ghostunnel.nix
|
||||||
./services/networking/git-daemon.nix
|
./services/networking/git-daemon.nix
|
||||||
./services/networking/globalprotect-vpn.nix
|
./services/networking/globalprotect-vpn.nix
|
||||||
|
./services/networking/gns3-server.nix
|
||||||
./services/networking/gnunet.nix
|
./services/networking/gnunet.nix
|
||||||
./services/networking/go-autoconfig.nix
|
./services/networking/go-autoconfig.nix
|
||||||
./services/networking/go-neb.nix
|
./services/networking/go-neb.nix
|
||||||
|
|||||||
31
nixos/modules/services/networking/gns3-server.md
Normal file
31
nixos/modules/services/networking/gns3-server.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# GNS3 Server {#module-services-gns3-server}
|
||||||
|
|
||||||
|
[GNS3](https://www.gns3.com/), a network software emulator.
|
||||||
|
|
||||||
|
## Basic Usage {#module-services-gns3-server-basic-usage}
|
||||||
|
|
||||||
|
A minimal configuration looks like this:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
services.gns3-server = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
auth = {
|
||||||
|
enable = true;
|
||||||
|
user = "gns3";
|
||||||
|
passwordFile = "/var/lib/secrets/gns3_password";
|
||||||
|
};
|
||||||
|
|
||||||
|
ssl = {
|
||||||
|
enable = true;
|
||||||
|
certFile = "/var/lib/gns3/ssl/cert.pem";
|
||||||
|
keyFile = "/var/lib/gns3/ssl/key.pem";
|
||||||
|
};
|
||||||
|
|
||||||
|
dynamips.enable = true;
|
||||||
|
ubridge.enable = true;
|
||||||
|
vpcs.enable = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
263
nixos/modules/services/networking/gns3-server.nix
Normal file
263
nixos/modules/services/networking/gns3-server.nix
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.services.gns3-server;
|
||||||
|
|
||||||
|
settingsFormat = pkgs.formats.ini { };
|
||||||
|
configFile = settingsFormat.generate "gns3-server.conf" cfg.settings;
|
||||||
|
|
||||||
|
in {
|
||||||
|
meta = {
|
||||||
|
doc = ./gns3-server.md;
|
||||||
|
maintainers = [ lib.maintainers.anthonyroussel ];
|
||||||
|
};
|
||||||
|
|
||||||
|
options = {
|
||||||
|
services.gns3-server = {
|
||||||
|
enable = lib.mkEnableOption (lib.mdDoc "GNS3 Server daemon");
|
||||||
|
|
||||||
|
package = lib.mkPackageOptionMD pkgs "gns3-server" { };
|
||||||
|
|
||||||
|
auth = {
|
||||||
|
enable = lib.mkEnableOption (lib.mdDoc "password based HTTP authentication to access the GNS3 Server");
|
||||||
|
|
||||||
|
user = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
default = null;
|
||||||
|
example = "gns3";
|
||||||
|
description = lib.mdDoc ''Username used to access the GNS3 Server.'';
|
||||||
|
};
|
||||||
|
|
||||||
|
passwordFile = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.path;
|
||||||
|
default = null;
|
||||||
|
example = "/run/secrets/gns3-server-password";
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
A file containing the password to access the GNS3 Server.
|
||||||
|
|
||||||
|
::: {.warning}
|
||||||
|
This should be a string, not a nix path, since nix paths
|
||||||
|
are copied into the world-readable nix store.
|
||||||
|
:::
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
settings = lib.mkOption {
|
||||||
|
type = lib.types.submodule { freeformType = settingsFormat.type; };
|
||||||
|
default = {};
|
||||||
|
example = { host = "127.0.0.1"; port = 3080; };
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
The global options in `config` file in ini format.
|
||||||
|
|
||||||
|
Refer to <https://docs.gns3.com/docs/using-gns3/administration/gns3-server-configuration-file/>
|
||||||
|
for all available options.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
log = {
|
||||||
|
file = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.path;
|
||||||
|
default = "/var/log/gns3/server.log";
|
||||||
|
description = lib.mdDoc ''Path of the file GNS3 Server should log to.'';
|
||||||
|
};
|
||||||
|
|
||||||
|
debug = lib.mkEnableOption (lib.mdDoc "debug logging");
|
||||||
|
};
|
||||||
|
|
||||||
|
ssl = {
|
||||||
|
enable = lib.mkEnableOption (lib.mdDoc "SSL encryption");
|
||||||
|
|
||||||
|
certFile = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.path;
|
||||||
|
default = null;
|
||||||
|
example = "/var/lib/gns3/ssl/server.pem";
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Path to the SSL certificate file. This certificate will
|
||||||
|
be offered to, and may be verified by, clients.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
keyFile = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.path;
|
||||||
|
default = null;
|
||||||
|
example = "/var/lib/gns3/ssl/server.key";
|
||||||
|
description = lib.mdDoc "Private key file for the certificate.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
dynamips = {
|
||||||
|
enable = lib.mkEnableOption (lib.mdDoc ''Whether to enable Dynamips support.'');
|
||||||
|
package = lib.mkPackageOptionMD pkgs "dynamips" { };
|
||||||
|
};
|
||||||
|
|
||||||
|
ubridge = {
|
||||||
|
enable = lib.mkEnableOption (lib.mdDoc ''Whether to enable uBridge support.'');
|
||||||
|
package = lib.mkPackageOptionMD pkgs "ubridge" { };
|
||||||
|
};
|
||||||
|
|
||||||
|
vpcs = {
|
||||||
|
enable = lib.mkEnableOption (lib.mdDoc ''Whether to enable VPCS support.'');
|
||||||
|
package = lib.mkPackageOptionMD pkgs "vpcs" { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = let
|
||||||
|
flags = {
|
||||||
|
enableDocker = config.virtualisation.docker.enable;
|
||||||
|
enableLibvirtd = config.virtualisation.libvirtd.enable;
|
||||||
|
};
|
||||||
|
|
||||||
|
in lib.mkIf cfg.enable {
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = cfg.ssl.enable -> cfg.ssl.certFile != null;
|
||||||
|
message = "Please provide a certificate to use for SSL encryption.";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = cfg.ssl.enable -> cfg.ssl.keyFile != null;
|
||||||
|
message = "Please provide a private key to use for SSL encryption.";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = cfg.auth.enable -> cfg.auth.user != null;
|
||||||
|
message = "Please provide a username to use for HTTP authentication.";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = cfg.auth.enable -> cfg.auth.passwordFile != null;
|
||||||
|
message = "Please provide a password file to use for HTTP authentication.";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
users.groups.ubridge = lib.mkIf cfg.ubridge.enable { };
|
||||||
|
|
||||||
|
security.wrappers.ubridge = lib.mkIf cfg.ubridge.enable {
|
||||||
|
capabilities = "cap_net_raw,cap_net_admin=eip";
|
||||||
|
group = "ubridge";
|
||||||
|
owner = "root";
|
||||||
|
permissions = "u=rwx,g=rx,o=r";
|
||||||
|
source = lib.getExe cfg.ubridge.package;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.gns3-server.settings = lib.mkMerge [
|
||||||
|
{
|
||||||
|
Server = {
|
||||||
|
appliances_path = lib.mkDefault "/var/lib/gns3/appliances";
|
||||||
|
configs_path = lib.mkDefault "/var/lib/gns3/configs";
|
||||||
|
images_path = lib.mkDefault "/var/lib/gns3/images";
|
||||||
|
projects_path = lib.mkDefault "/var/lib/gns3/projects";
|
||||||
|
symbols_path = lib.mkDefault "/var/lib/gns3/symbols";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
(lib.mkIf (cfg.ubridge.enable) {
|
||||||
|
Server.ubridge_path = lib.mkDefault (lib.getExe cfg.ubridge.package);
|
||||||
|
})
|
||||||
|
(lib.mkIf (cfg.auth.enable) {
|
||||||
|
Server = {
|
||||||
|
auth = lib.mkDefault (lib.boolToString cfg.auth.enable);
|
||||||
|
user = lib.mkDefault cfg.auth.user;
|
||||||
|
password = lib.mkDefault "@AUTH_PASSWORD@";
|
||||||
|
};
|
||||||
|
})
|
||||||
|
(lib.mkIf (cfg.vpcs.enable) {
|
||||||
|
VPCS.vpcs_path = lib.mkDefault (lib.getExe cfg.vpcs.package);
|
||||||
|
})
|
||||||
|
(lib.mkIf (cfg.dynamips.enable) {
|
||||||
|
Dynamips.dynamips_path = lib.mkDefault (lib.getExe cfg.dynamips.package);
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
systemd.services.gns3-server = let
|
||||||
|
commandArgs = lib.cli.toGNUCommandLineShell { } {
|
||||||
|
config = "/etc/gns3/gns3_server.conf";
|
||||||
|
pid = "/run/gns3/server.pid";
|
||||||
|
log = cfg.log.file;
|
||||||
|
ssl = cfg.ssl.enable;
|
||||||
|
# These are implicitly not set if `null`
|
||||||
|
certfile = cfg.ssl.certFile;
|
||||||
|
certkey = cfg.ssl.keyFile;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
description = "GNS3 Server";
|
||||||
|
|
||||||
|
after = [ "network.target" "network-online.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
|
||||||
|
# configFile cannot be stored in RuntimeDirectory, because GNS3
|
||||||
|
# uses the `--config` base path to stores supplementary configuration files at runtime.
|
||||||
|
#
|
||||||
|
preStart = ''
|
||||||
|
install -m660 ${configFile} /etc/gns3/gns3_server.conf
|
||||||
|
|
||||||
|
${lib.optionalString cfg.auth.enable ''
|
||||||
|
${pkgs.replace-secret}/bin/replace-secret \
|
||||||
|
'@AUTH_PASSWORD@' \
|
||||||
|
"''${CREDENTIALS_DIRECTORY}/AUTH_PASSWORD" \
|
||||||
|
/etc/gns3/gns3_server.conf
|
||||||
|
''}
|
||||||
|
'';
|
||||||
|
|
||||||
|
path = lib.optional flags.enableLibvirtd pkgs.qemu;
|
||||||
|
|
||||||
|
reloadTriggers = [ configFile ];
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
ConfigurationDirectory = "gns3";
|
||||||
|
ConfigurationDirectoryMode = "0750";
|
||||||
|
DynamicUser = true;
|
||||||
|
Environment = "HOME=%S/gns3";
|
||||||
|
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
||||||
|
ExecStart = "${lib.getExe cfg.package} ${commandArgs}";
|
||||||
|
Group = "gns3";
|
||||||
|
LimitNOFILE = 16384;
|
||||||
|
LoadCredential = lib.mkIf cfg.auth.enable [ "AUTH_PASSWORD:${cfg.auth.passwordFile}" ];
|
||||||
|
LogsDirectory = "gns3";
|
||||||
|
LogsDirectoryMode = "0750";
|
||||||
|
PIDFile = "/run/gns3/server.pid";
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = 5;
|
||||||
|
RuntimeDirectory = "gns3";
|
||||||
|
StateDirectory = "gns3";
|
||||||
|
StateDirectoryMode = "0750";
|
||||||
|
SupplementaryGroups = lib.optional flags.enableDocker "docker"
|
||||||
|
++ lib.optional flags.enableLibvirtd "libvirtd"
|
||||||
|
++ lib.optional cfg.ubridge.enable "ubridge";
|
||||||
|
User = "gns3";
|
||||||
|
WorkingDirectory = "%S/gns3";
|
||||||
|
|
||||||
|
# Hardening
|
||||||
|
DeviceAllow = lib.optional flags.enableLibvirtd "/dev/kvm";
|
||||||
|
DevicePolicy = "closed";
|
||||||
|
LockPersonality = true;
|
||||||
|
MemoryDenyWriteExecute = true;
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
PrivateTmp = true;
|
||||||
|
PrivateUsers = true;
|
||||||
|
# Don't restrict ProcSubset because python3Packages.psutil requires read access to /proc/stat
|
||||||
|
# ProcSubset = "pid";
|
||||||
|
ProtectClock = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
ProtectHome = true;
|
||||||
|
ProtectHostname = true;
|
||||||
|
ProtectKernelLogs = true;
|
||||||
|
ProtectKernelModules = true;
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectProc = "invisible";
|
||||||
|
ProtectSystem = "strict";
|
||||||
|
RestrictAddressFamilies = [
|
||||||
|
"AF_INET"
|
||||||
|
"AF_INET6"
|
||||||
|
"AF_NETLINK"
|
||||||
|
"AF_UNIX"
|
||||||
|
"AF_PACKET"
|
||||||
|
];
|
||||||
|
RestrictNamespaces = true;
|
||||||
|
RestrictRealtime = true;
|
||||||
|
RestrictSUIDSGID = true;
|
||||||
|
UMask = "0077";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -342,6 +342,7 @@ in {
|
|||||||
gnome-extensions = handleTest ./gnome-extensions.nix {};
|
gnome-extensions = handleTest ./gnome-extensions.nix {};
|
||||||
gnome-flashback = handleTest ./gnome-flashback.nix {};
|
gnome-flashback = handleTest ./gnome-flashback.nix {};
|
||||||
gnome-xorg = handleTest ./gnome-xorg.nix {};
|
gnome-xorg = handleTest ./gnome-xorg.nix {};
|
||||||
|
gns3-server = handleTest ./gns3-server.nix {};
|
||||||
gnupg = handleTest ./gnupg.nix {};
|
gnupg = handleTest ./gnupg.nix {};
|
||||||
go-neb = handleTest ./go-neb.nix {};
|
go-neb = handleTest ./go-neb.nix {};
|
||||||
gobgpd = handleTest ./gobgpd.nix {};
|
gobgpd = handleTest ./gobgpd.nix {};
|
||||||
|
|||||||
55
nixos/tests/gns3-server.nix
Normal file
55
nixos/tests/gns3-server.nix
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import ./make-test-python.nix ({ pkgs, lib, ... }: {
|
||||||
|
name = "gns3-server";
|
||||||
|
meta.maintainers = [ lib.maintainers.anthonyroussel ];
|
||||||
|
|
||||||
|
nodes.machine =
|
||||||
|
{ ... }:
|
||||||
|
let
|
||||||
|
tls-cert = pkgs.runCommand "selfSignedCerts" { buildInputs = [ pkgs.openssl ]; } ''
|
||||||
|
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -nodes -days 365 \
|
||||||
|
-subj '/CN=localhost'
|
||||||
|
install -D -t $out key.pem cert.pem
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
services.gns3-server = {
|
||||||
|
enable = true;
|
||||||
|
auth = {
|
||||||
|
enable = true;
|
||||||
|
user = "user";
|
||||||
|
passwordFile = pkgs.writeText "gns3-auth-password-file" "password";
|
||||||
|
};
|
||||||
|
ssl = {
|
||||||
|
enable = true;
|
||||||
|
certFile = "${tls-cert}/cert.pem";
|
||||||
|
keyFile = "${tls-cert}/key.pem";
|
||||||
|
};
|
||||||
|
dynamips.enable = true;
|
||||||
|
ubridge.enable = true;
|
||||||
|
vpcs.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
security.pki.certificateFiles = [ "${tls-cert}/cert.pem" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = let
|
||||||
|
createProject = pkgs.writeText "createProject.json" (builtins.toJSON {
|
||||||
|
name = "test_project";
|
||||||
|
});
|
||||||
|
in
|
||||||
|
''
|
||||||
|
start_all()
|
||||||
|
|
||||||
|
machine.wait_for_unit("gns3-server.service")
|
||||||
|
machine.wait_for_open_port(3080)
|
||||||
|
|
||||||
|
with subtest("server is listening"):
|
||||||
|
machine.succeed("curl -sSfL -u user:password https://localhost:3080/v2/version")
|
||||||
|
|
||||||
|
with subtest("create dummy project"):
|
||||||
|
machine.succeed("curl -sSfL -u user:password https://localhost:3080/v2/projects -d @${createProject}")
|
||||||
|
|
||||||
|
with subtest("logging works"):
|
||||||
|
log_path = "/var/log/gns3/server.log"
|
||||||
|
machine.wait_for_file(log_path)
|
||||||
|
'';
|
||||||
|
})
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
, fetchFromGitHub
|
, fetchFromGitHub
|
||||||
, pkgsStatic
|
, pkgsStatic
|
||||||
, stdenv
|
, stdenv
|
||||||
|
, nixosTests
|
||||||
, testers
|
, testers
|
||||||
, gns3-server
|
, gns3-server
|
||||||
}:
|
}:
|
||||||
@@ -75,9 +76,12 @@ python3.pkgs.buildPythonApplication {
|
|||||||
"--reruns 3"
|
"--reruns 3"
|
||||||
];
|
];
|
||||||
|
|
||||||
passthru.tests.version = testers.testVersion {
|
passthru.tests = {
|
||||||
package = gns3-server;
|
inherit (nixosTests) gns3-server;
|
||||||
command = "${lib.getExe gns3-server} --version";
|
version = testers.testVersion {
|
||||||
|
package = gns3-server;
|
||||||
|
command = "${lib.getExe gns3-server} --version";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
|
|||||||
Reference in New Issue
Block a user