Skip to content

Commit

Permalink
Add nixos service and scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
jbgi committed Jan 18, 2022
1 parent 84bc45a commit 98ee27e
Show file tree
Hide file tree
Showing 10 changed files with 384 additions and 9 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Expand Up @@ -46,3 +46,6 @@ hie.yaml

### Docs build
/_build/

### databases of scripts
/db-cardano-wallet-*
32 changes: 28 additions & 4 deletions flake.nix
Expand Up @@ -58,13 +58,21 @@
config = import ./nix/config.nix lib customConfig;
inherit (flake-utils.lib) eachSystem mkApp flattenTree;
removeRecurse = lib.filterAttrsRecursive (n: _: n != "recurseForDerivations");
inherit (iohkNix.lib) evalService;
supportedSystems = import ./nix/supported-systems.nix;
defaultSystem = lib.head supportedSystems;
overlay = final: prev:
{
cardanoWalletHaskellProject = self.legacyPackages.${final.system};
inherit (final.cardanoWalletHaskellProject.hsPkgs.cardano-wallet.components.exes) cardano-wallet;
};
nixosModule = { pkgs, lib, ... }: {
imports = [ ./nix/nixos/cardano-wallet-service.nix ];
services.cardano-node.project = lib.mkDefault self.legacyPackages.${pkgs.system};
};
nixosModules = {
cardano-wallet = nixosModule;
};
# Which exes should be put in the release archives.
releaseContents = jobs: map (exe: jobs.${exe}) [
"cardano-wallet"
Expand Down Expand Up @@ -192,6 +200,12 @@
in
self;

# nix run .#<network>/wallet
mkScripts = project: flattenTree (import ./nix/scripts.nix {
inherit project evalService;
customConfigs = [ config ];
});

# See the imported file for how to use the docker build.
mkDockerImage = packages: pkgs.callPackage ./nix/docker.nix {
exes = with packages; [ cardano-wallet local-cluster ];
Expand Down Expand Up @@ -233,6 +247,7 @@
linux = {
# Don't run tests on linux native, because they are run for linux musl.
native = removeAttrs (mkPackages hydraProject) [ "checks" "testCoverageReport" ] // {
scripts = mkScripts hydraProject;
shells = (mkDevShells hydraProject) // {
default = hydraProject.shell;
};
Expand All @@ -245,6 +260,10 @@
project = hydraProject.roots;
iohk-nix-utils = pkgs.iohk-nix-utils.roots;
};
nixosTests = import ./nix/nixos/tests {
inherit pkgs;
project = hydraProject;
};
};
musl =
let
Expand Down Expand Up @@ -302,6 +321,7 @@
shells = (mkDevShells hydraProject) // {
default = hydraProject.shell;
};
scripts = mkScripts hydraProject;
internal.roots = {
project = hydraProject.roots;
iohk-nix-utils = pkgs.iohk-nix-utils.roots;
Expand All @@ -319,7 +339,7 @@
# Run by `nix run .`
defaultApp = apps.cardano-wallet;

packages = mkPackages project // rec {
packages = mkPackages project // mkScripts project // rec {
dockerImage = mkDockerImage (mkPackages project.projectCross.musl64);
pushDockerImage = import ./.buildkite/docker-build-push.nix {
hostPkgs = import hostNixpkgs { inherit system; };
Expand All @@ -330,9 +350,13 @@
inherit (project.stack-nix.passthru) generateMaterialized;
buildToolsGenerateMaterialized = pkgs.haskell-build-tools.regenerateMaterialized;
iohkNixGenerateMaterialized = pkgs.iohk-nix-utils.regenerateMaterialized;
};
} // (lib.optionalAttrs buildPlatform.isLinux {
nixosTests = import ./nix/nixos/tests {
inherit pkgs project;
};
});

apps = lib.mapAttrs (n: p: { type = "app"; program = if (p ? exePath) then p.exePath else "${p}/bin/${n}"; }) packages;
apps = lib.mapAttrs (n: p: { type = "app"; program = p.exePath or "${p}/bin/${p.name or n}"; }) packages;

devShell = project.shell;

Expand All @@ -346,7 +370,7 @@
in
lib.recursiveUpdate (removeAttrs systems [ "systemHydraJobs" "systemHydraJobsPr" "systemHydraJobsBors" ])
{
inherit overlay;
inherit overlay nixosModule nixosModules;
hydraJobs = mkHydraJobs systems.systemHydraJobs;
hydraJobsPr = mkHydraJobs systems.systemHydraJobsPr;
hydraJobsBors = mkHydraJobs systems.systemHydraJobsBors;
Expand Down
2 changes: 1 addition & 1 deletion lib/cli/src/Cardano/CLI.hs
Expand Up @@ -1186,7 +1186,7 @@ hostPreferenceOption = option str $ mempty
<> long "listen-address"
<> metavar "HOST"
<> help
("Specification of which host to the bind API server to. " <>
("Specification of which host to bind the API server to. " <>
"Can be an IPv[46] address, hostname, or '*'.")
<> value "127.0.0.1"
<> showDefaultWith (const "127.0.0.1")
Expand Down
197 changes: 197 additions & 0 deletions nix/nixos/cardano-wallet-service.nix
@@ -0,0 +1,197 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.cardano-wallet;
inherit (lib) mkIf mkEnableOption mkOption types;
logLevels = types.enum [ "debug" "info" "notice" "warning" "error" "critical" "alert" "emergency" "off" ];
in
{
options.services.cardano-wallet = {

enable = mkEnableOption "Cardano Wallet service";

serverArgs = mkOption {
description = "Command-line to launch cardano-wallet server.";
type = types.separatedString " ";
default = lib.concatStringsSep " " ([
"--listen-address"
(lib.escapeShellArg cfg.listenAddress)
"--port"
(toString cfg.port)
"--node-socket"
(lib.escapeShellArg "$CARDANO_NODE_SOCKET_PATH")
"--sync-tolerance"
"${toString cfg.syncTolerance}s"
"--log-level"
cfg.logLevel
"--pool-metadata-fetching"
(if (cfg.poolMetadataFetching.enable)
then
(if cfg.poolMetadataFetching.smashUrl != null
then cfg.poolMetadataFetching.smashUrl else "direct")
else "none")
"--${cfg.walletMode}"
] ++ lib.optional (cfg.walletMode != "mainnet")
(lib.escapeShellArg cfg.genesisFile)
++ lib.optionals (cfg.tokenMetadataServer != null)
[ "--token-metadata-server" cfg.tokenMetadataServer ]
++ lib.optionals (cfg.database != null)
[ "--database" (lib.escapeShellArg cfg.database) ]
++ lib.mapAttrsToList
(name: level: "--trace-${name}=${level}")
cfg.trace
);
};

command = mkOption {
type = types.str;
internal = true;
default = lib.concatStringsSep " " ([
"${cfg.package}/bin/${cfg.package.exeName}"
"serve"
cfg.serverArgs
] ++ lib.optionals (cfg.rtsOpts != "") [ "+RTS" cfg.rtsOpts "-RTS" ]);
};

package = mkOption {
type = types.package;
default = ((import ../.. { }).legacyPackages.${pkgs.system}).hsPkgs.cardano-wallet.components.exes.cardano-wallet;
description = "Package for the cardano wallet executable.";
};

genesisFile = mkOption {
type = types.nullOr (types.either types.str types.path);
default = null;
description = "Path to genesis file, if not running on mainnet.";
};

listenAddress = mkOption {
type = types.str;
default = "127.0.0.1";
description = "Which host to bind the API server to.";
};

port = mkOption {
type = types.port;
default = 8090;
description = "The port on which the cardano-wallet HTTP API server will listen.";
};

nodeSocket = mkOption {
type = types.str;
default = "/run/cardano-node/node.socket";
description = ''Cardano-Node local communication socket path.'';
};

walletMode = mkOption {
type = types.enum [ "mainnet" "staging" "testnet" ];
default = "mainnet";
description = "Which mode to start wallet in: --mainnet, --staging or --testnet";
};

database = mkOption {
type = types.nullOr types.str;
default = "$STATE_DIRECTORY";
description = ''Directory for storing wallets.
Run in-memory if null.
Default to '/var/lib/cardano-wallet'.
'';
};

syncTolerance = mkOption {
type = types.ints.positive;
default = 300;
description = "Time duration within which we consider being synced with the network. Expressed in seconds.";
};

poolMetadataFetching = mkOption {
type = types.submodule {
options = {
enable = mkEnableOption "Stake pool metadata fetching.";
smashUrl = mkOption {
description = ''
URL of SMASH metadata proxy to use.
If null, metadata will be fetched directly from the
stake pool's URL.
'';
type = types.nullOr types.str;
default = null;
};
};
};
default = { enable = false; };
example = {
enable = true;
smashUrl = "https://smash.cardano-mainnet.iohk.io";
};
};

tokenMetadataServer = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Sets the URL of the token metadata server,
default to 'metadataUrl' of the 'environnement' attribute, if exists.
If unset, metadata will not be fetched. By using this
option, you are fully trusting the operator of the
metadata server to provide authentic token metadata.
'';
};

logLevel = mkOption {
type = logLevels;
default = "info";
description = "Global minimum severity for a message to be logged.";
};

trace = mkOption {
type = types.attrsOf logLevels;
default = { };
description = ''
For each tracer, minimum severity for a message to be logged, or
"off" to disable the tracer".
'';
};

rtsOpts = mkOption {
type = types.separatedString " ";
default = "-N2";
example = "-M2G -N4";
description = ''
GHC runtime-system options for the cardano-wallet process.
See https://downloads.haskell.org/ghc/8.10.7/docs/html/users_guide/runtime_control.html#setting-rts-options-on-the-command-line for documentation.
'';
};

};

config = mkIf cfg.enable {

assertions = [
{
assertion = (cfg.walletMode == "mainnet") == (cfg.genesisFile == null);
message = ''The option services.cardano-wallet.genesisFile must be set
if, and only if, services.cardano-wallet.walletMode is not \"mainnet\".
'';
}
{
assertion = !(lib.hasPrefix "/" cfg.database || lib.hasPrefix ".." cfg.database);
message = "The option services.cardano-node.database should be a relative path (of /var/lib/).";
}
];

systemd.services.cardano-wallet = {
description = "cardano-wallet daemon";
wantedBy = [ "multi-user.target" ];

serviceConfig = {
DynamicUser = true;
ExecStart = cfg.command;
StateDirectory = if cfg.database == "$STATE_DIRECTORY" then "cardano-wallet" else cfg.database;
};

environment = {
CARDANO_NODE_SOCKET_PATH = cfg.nodeSocket;
};
};
};
}
1 change: 1 addition & 0 deletions nix/nixos/default.nix
@@ -0,0 +1 @@
{ imports = import ./module-list.nix; }
3 changes: 3 additions & 0 deletions nix/nixos/module-list.nix
@@ -0,0 +1,3 @@
[
./cardano-wallet-service.nix
]
17 changes: 17 additions & 0 deletions nix/nixos/tests/default.nix
@@ -0,0 +1,17 @@
{ pkgs
, project
}:
let
importTest = fn: args:
let
imported = import fn;
test = import (pkgs.path + "/nixos/tests/make-test-python.nix") imported;
in
test ({
inherit pkgs project;
inherit (pkgs) system config;
} // args);
in
{
basicTest = importTest ./service-basic-test.nix { };
}
59 changes: 59 additions & 0 deletions nix/nixos/tests/service-basic-test.nix
@@ -0,0 +1,59 @@
{ pkgs, project, lib, ... }: with pkgs;
let
inherit (project.hsPkgs.cardano-wallet.components.exes) cardano-wallet;
inherit (pkgs) cardanoLib;
in
{
name = "wallet-nixos-test";
nodes = {
machine = { config, ... }: {
nixpkgs.pkgs = pkgs;
imports = [
../.
(project.pkg-set.config.packages.cardano-node.src + "/nix/nixos")
];
services.cardano-wallet = {
enable = true;
package = cardano-wallet;
walletMode = "mainnet";
nodeSocket = config.services.cardano-node.socketPath;
poolMetadataFetching = {
enable = true;
smashUrl = cardanoLib.environments.mainnet.smashUrl;
};
tokenMetadataServer = cardanoLib.environments.mainnet.metadataUrl;
};
services.cardano-node = {
enable = true;
environment = "mainnet";
environments = { mainnet = { }; };
package = project.hsPkgs.cardano-node.components.exes.cardano-node;
inherit (cardanoLib.environments.mainnet) nodeConfig;
topology = cardanoLib.mkEdgeTopology {
port = 3001;
edgeNodes = [ "127.0.0.1" ];
};
systemdSocketActivation = true;
};
systemd.services.cardano-node.serviceConfig.Restart = lib.mkForce "no";
systemd.services.cardano-wallet = {
after = [ "cardano-node.service" ];
serviceConfig = {
Restart = "no";
SupplementaryGroups = "cardano-node";
};
};
};
};
testScript = ''
start_all()
machine.wait_for_unit("cardano-node.service")
machine.wait_for_open_port(3001)
machine.wait_for_unit("cardano-wallet.service")
machine.wait_for_open_port(8090)
machine.succeed(
"${cardano-wallet}/bin/cardano-wallet network information"
)
'';

}

0 comments on commit 98ee27e

Please sign in to comment.