Skip to content

Commit bdda2d5

Browse files
authored
Merge pull request #10 from cspr-rad/casper-node-nixos-module
casper-node: add nixos-module and nixos-test
2 parents 9d01d5c + edac32f commit bdda2d5

13 files changed

+340
-28
lines changed

Diff for: flake.lock

+83-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: flake.nix

+49-26
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@
1616
url = "github:oxalica/rust-overlay";
1717
inputs.nixpkgs.follows = "nixpkgs";
1818
};
19+
agenix = {
20+
url = "github:ryantm/agenix";
21+
inputs.nixpkgs.follows = "nixpkgs";
22+
};
1923
};
2024

21-
outputs = { self, nixpkgs, rust-overlay, ... }:
25+
outputs = { self, nixpkgs, rust-overlay, agenix, ... }:
2226
let
2327
eachSystem = systems: f:
2428
let
@@ -43,31 +47,50 @@
4347
"x86_64-linux"
4448
];
4549
in
46-
{
47-
herculesCI.ciSystems = [ "x86_64-linux" ];
48-
overlays.default = import ./overlay.nix;
49-
}
50-
// eachDefaultSystem (system:
51-
let
52-
pkgs = nixpkgs.legacyPackages.${system}.extend (import rust-overlay);
53-
csprpkgs = pkgs.callPackage ./scope.nix { makeScope = pkgs.lib.makeScope; };
54-
in
50+
nixpkgs.lib.recursiveUpdate
5551
{
56-
packages = {
57-
inherit (csprpkgs)
58-
casper-node
59-
casper-node-contracts
60-
casper-node-launcher
61-
casper-client-rs
62-
;
63-
};
64-
formatter = pkgs.nixpkgs-fmt;
52+
herculesCI.ciSystems = [ "x86_64-linux" "aarch64-linux" ];
53+
54+
overlays.default = import ./overlay.nix;
55+
56+
nixosModules.casper-node =
57+
{ pkgs, lib, ... }:
58+
{
59+
imports = [ ./nixos/modules/casper-node.nix ];
60+
services.casper-node.package = self.packages.${pkgs.system}.casper-node;
61+
};
62+
63+
checks.x86_64-linux.casper-node-smoke-test =
64+
let
65+
pkgs = nixpkgs.legacyPackages.x86_64-linux;
66+
in
67+
pkgs.callPackage ./nixos/tests/casper-node/smoke-test.nix {
68+
casperNodeModule = self.nixosModules.casper-node;
69+
agenixModule = agenix.nixosModules.age;
70+
};
71+
}
72+
(eachDefaultSystem (system:
73+
let
74+
pkgs = nixpkgs.legacyPackages.${system}.extend (import rust-overlay);
75+
csprpkgs = pkgs.callPackage ./scope.nix { makeScope = pkgs.lib.makeScope; };
76+
in
77+
{
78+
packages = {
79+
inherit (csprpkgs)
80+
casper-node
81+
casper-node-contracts
82+
casper-node-launcher
83+
casper-client-rs
84+
;
85+
};
86+
formatter = pkgs.nixpkgs-fmt;
6587

66-
checks.format = pkgs.runCommand "format-check" { buildInputs = [ pkgs.nixpkgs-fmt ]; } ''
67-
set -euo pipefail
68-
cd ${self}
69-
nixpkgs-fmt --check .
70-
touch $out
71-
'';
72-
});
88+
checks.format = pkgs.runCommand "format-check" { buildInputs = [ pkgs.nixpkgs-fmt ]; } ''
89+
set -euo pipefail
90+
cd ${self}
91+
nixpkgs-fmt --check .
92+
touch $out
93+
'';
94+
})
95+
);
7396
}

Diff for: nixos/modules/casper-node.nix

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
{ lib, pkgs, config, ... }:
2+
let
3+
inherit (lib)
4+
types
5+
mkOption
6+
mkIf
7+
mkMerge
8+
mkEnableOption
9+
;
10+
cfg = config.services.casper-node;
11+
12+
mapDotsToUnderscore = lib.stringAsChars (c: if c == "." then "_" else c);
13+
versionsAndHashes = {
14+
"1.5.6" = "sha256-2N2vPKHLKV32RzzZPV004hWH1/lbeZUf3WofTVm+ZZI=";
15+
};
16+
defaultConfigsSrc = pkgs.fetchFromGitHub {
17+
owner = "casper-network";
18+
repo = "casper-protocol-release";
19+
rev = "refs/tags/casper-${cfg.package.version}";
20+
hash = versionsAndHashes.${cfg.package.version};
21+
};
22+
in
23+
{
24+
options.services.casper-node = {
25+
26+
enable = mkEnableOption ("casper-node");
27+
28+
package = mkOption {
29+
type = types.package;
30+
};
31+
32+
port = mkOption {
33+
type = types.port;
34+
default = 35000;
35+
example = 35000;
36+
description = ''
37+
Port to listen on.
38+
'';
39+
};
40+
41+
publicAddress = mkOption {
42+
type = types.str;
43+
example = "https://casper.network:0";
44+
description = ''
45+
The public address other peer nodes should connect to.
46+
'';
47+
};
48+
49+
logLevel = mkOption {
50+
type = types.str;
51+
default = "info";
52+
description = ''
53+
The log-level that should be used.
54+
'';
55+
};
56+
57+
validatorSecretKeyPath = mkOption {
58+
type = types.path;
59+
description = ''
60+
The absolute path to the validator's secret key file used to sign consensus messages.
61+
'';
62+
};
63+
};
64+
65+
config = mkIf cfg.enable {
66+
67+
systemd.services.casper-node =
68+
{
69+
description = "casper-node";
70+
documentation = [ "https://docs.casper.network/operators/setup/" ];
71+
wantedBy = [ "multi-user.target" ];
72+
after = [ "network-online.target" ];
73+
requires = [ "network-online.target" ];
74+
environment = {
75+
RUST_LOG = cfg.logLevel;
76+
};
77+
serviceConfig = mkMerge [
78+
{
79+
ExecStart = "${lib.getExe cfg.package} standard /etc/casper/${mapDotsToUnderscore cfg.package.version}/config.toml";
80+
Restart = "always";
81+
User = "casper-node";
82+
Group = "casper-node";
83+
StateDirectory = "casper"; # creates /var/lib/casper
84+
}
85+
];
86+
};
87+
88+
# Explicit user and group definitions are required instead of using DynamicUser,
89+
# in order to work seemlessly with tools like agenix.
90+
# The agenix service runs and changes ownership of a secret before a service
91+
# with `DynamicUser=true` would create the user.
92+
users.users.casper-node = {
93+
name = "casper-node";
94+
group = "casper-node";
95+
isSystemUser = true;
96+
};
97+
98+
users.groups.casper-node = { };
99+
100+
environment.etc."casper/${mapDotsToUnderscore cfg.package.version}/chainspec.toml".source = "${defaultConfigsSrc}/config/chainspec.toml";
101+
environment.etc."casper/${mapDotsToUnderscore cfg.package.version}/config.toml" =
102+
let
103+
defaultConfig = builtins.fromTOML (builtins.readFile "${defaultConfigsSrc}/config/config-example.toml");
104+
105+
config = lib.recursiveUpdate defaultConfig {
106+
network = {
107+
bind_address = "0.0.0.0:${builtins.toString cfg.port}";
108+
public_address = "${cfg.publicAddress}";
109+
};
110+
consensus.secret_key_path = cfg.validatorSecretKeyPath;
111+
};
112+
113+
format = pkgs.formats.toml { };
114+
configTomlFile = format.generate "config.toml" config;
115+
in
116+
{
117+
source = configTomlFile;
118+
};
119+
};
120+
}
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Do not copy this! It is insecure. This is only okay because we are testing.
2+
{
3+
system.activationScripts.agenixInstall.deps = [ "installSSHHostKeys" ];
4+
5+
system.activationScripts.installSSHHostKeys.text = ''
6+
mkdir -p /etc/ssh
7+
(umask u=rw,g=r,o=r; cp ${./test-ssh-host-keys/nixos-test.pub} /etc/ssh/ssh_host_ed25519_key.pub)
8+
(
9+
umask u=rw,g=,o=
10+
cp ${./test-ssh-host-keys/nixos-test} /etc/ssh/ssh_host_ed25519_key
11+
touch /etc/ssh/ssh_host_rsa_key
12+
)
13+
'';
14+
}

Diff for: nixos/tests/casper-node/smoke-test.nix

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{ nixosTest
2+
, casperNodeModule
3+
, agenixModule
4+
}:
5+
let
6+
hostName = "casper-node";
7+
port = 35001;
8+
in
9+
nixosTest {
10+
name = "casper-node smoke test";
11+
12+
nodes = {
13+
server = { config, pkgs, lib, ... }: {
14+
imports = [
15+
casperNodeModule
16+
agenixModule
17+
./install-test-ssh-host-keys.nix
18+
];
19+
20+
age.identityPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
21+
age.secrets.validator-secret-key = {
22+
file = ../../../secrets/validator-secret-key.age;
23+
mode = "500";
24+
owner = config.systemd.services.casper-node.serviceConfig.User;
25+
group = config.systemd.services.casper-node.serviceConfig.Group;
26+
};
27+
28+
networking.hostName = hostName;
29+
services.casper-node = {
30+
enable = true;
31+
inherit port;
32+
publicAddress = "10.0.0.1:0"; # public address assigned by nixos test driver
33+
validatorSecretKeyPath = config.age.secrets.validator-secret-key.path;
34+
};
35+
};
36+
};
37+
38+
testScript = ''
39+
start_all()
40+
casper_node.wait_for_unit("casper-node.service")
41+
casper_node.wait_for_open_port(${builtins.toString port})
42+
'';
43+
}
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-----BEGIN OPENSSH PRIVATE KEY-----
2+
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
3+
QyNTUxOQAAACARPu+0DXJW3AGk6zwXLe9ywm0sRKe9hwk1leL15iPZeAAAAJglz2R+Jc9k
4+
fgAAAAtzc2gtZWQyNTUxOQAAACARPu+0DXJW3AGk6zwXLe9ywm0sRKe9hwk1leL15iPZeA
5+
AAAECTw1InqBh5qlk95TALDdmQ7nTa+3ZNAzzQmXbawVADrxE+77QNclbcAaTrPBct73LC
6+
bSxEp72HCTWV4vXmI9l4AAAAEGpvaG5AZXhhbXBsZS5jb20BAgMEBQ==
7+
-----END OPENSSH PRIVATE KEY-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBE+77QNclbcAaTrPBct73LCbSxEp72HCTWV4vXmI9l4

0 commit comments

Comments
 (0)