From 2279b1b3418f2813018b830a214ca43268424021 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Giraudeau Date: Fri, 5 Nov 2021 21:56:11 +0100 Subject: [PATCH] Add nixos service and scripts --- .gitignore | 3 + flake.nix | 20 ++- lib/cli/src/Cardano/CLI.hs | 2 +- nix/nixos/cardano-wallet-service.nix | 193 +++++++++++++++++++++++++++ nix/release-build.nix | 10 +- nix/scripts.nix | 56 ++++++++ 6 files changed, 275 insertions(+), 9 deletions(-) create mode 100644 nix/nixos/cardano-wallet-service.nix create mode 100644 nix/scripts.nix diff --git a/.gitignore b/.gitignore index b6a7b069d47..3dd4ddcc8fb 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,6 @@ hie.yaml ### Docs build /_build/ + +### databases of scripts +/db-cardano-wallet-* diff --git a/flake.nix b/flake.nix index f44cd6cf73c..691bd502474 100644 --- a/flake.nix +++ b/flake.nix @@ -26,7 +26,7 @@ config = import ./nix/config.nix lib customConfig; cardanoWalletLib = import ./nix/util.nix { inherit lib; }; inherit (flake-utils.lib) eachSystem mkApp flattenTree; - inherit (iohkNix.lib) prefixNamesWith; + inherit (iohkNix.lib) evalService; supportedSystems = import ./nix/supported-systems.nix; defaultSystem = lib.head supportedSystems; overlay = final: prev: @@ -34,6 +34,13 @@ 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" @@ -153,7 +160,12 @@ checks = collectChecks isProjectPackage project.hsPkgs; # `benchmarks` are only built, not run. benchmarks = collectComponents "benchmarks" isProjectPackage project.hsPkgs; - }); + }) // + # nix run .#/wallet + (flattenTree (import ./nix/scripts.nix { + inherit project evalService; + customConfigs = [ config ]; + })); in self; # See the imported file for how to use the docker build. @@ -282,7 +294,7 @@ dockerImage = mkDockerImage packages; }; - 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; @@ -294,7 +306,7 @@ in lib.recursiveUpdate (removeAttrs systems [ "systemHydraJobs" ]) { - inherit overlay; + inherit overlay nixosModule nixosModules; hydraJobs = lib.foldl' lib.mergeAttrs { } (lib.attrValues systems.systemHydraJobs) // { inherit required; }; diff --git a/lib/cli/src/Cardano/CLI.hs b/lib/cli/src/Cardano/CLI.hs index f0f326c8bd7..73bcf8a1bdd 100644 --- a/lib/cli/src/Cardano/CLI.hs +++ b/lib/cli/src/Cardano/CLI.hs @@ -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") diff --git a/nix/nixos/cardano-wallet-service.nix b/nix/nixos/cardano-wallet-service.nix new file mode 100644 index 00000000000..17a199cbd12 --- /dev/null +++ b/nix/nixos/cardano-wallet-service.nix @@ -0,0 +1,193 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.services.cardano-wallet; + inherit (lib) optionalString mkIf mkEnableOption mkOption types; + logLevels = types.enum [ "debug" "info" "notice" "warning" "error" "critical" "alert" "emergency" "off" ]; + cardanoEnvAttrs = cfg.environments.${cfg.environment}; +in +{ + options.services.cardano-wallet = { + + enable = mkEnableOption "Cardano Wallet service"; + + script = mkOption { + type = types.str; + internal = true; + default = + let + genesisFile = cardanoEnvAttrs.genesisFile + or cardanoEnvAttrs.nodeConfig.ByronGenesisFile; + in + toString ([ + "exec ${cfg.package}/bin/cardano-wallet serve" + "--listen-address \"${cfg.listenAddress}\"" + "--port ${toString cfg.port}" + "--node-socket \"$CARDANO_NODE_SOCKET_PATH\"" + "--sync-tolerance ${toString cfg.syncTolerance}s" + "--pool-metadata-fetching ${if (cfg.poolMetadataFetching == "smash") + then cardanoEnvAttrs.smashUrl + else cfg.poolMetadataFetching}" + "--log-level ${cfg.logLevel}" + "--${cfg.walletMode}" + ] ++ lib.optional (cfg.walletMode != "mainnet") + "\"${genesisFile}\"" + ++ lib.optional (cfg.tokenMetadataServer != null) + "--token-metadata-server ${cfg.tokenMetadataServer}" + ++ lib.optional (cfg.database != null) + "--database \"${cfg.database}\"" + ++ lib.mapAttrsToList + (name: level: '' + --trace-${name}=${level} '') + cfg.trace + ++ cfg.rtsArgs) + ; + }; + + project = mkOption { + type = types.attrs; + default = (import ../.. { }).legacyPackages.${pkgs.system}; + description = "The cardano-wallet haskell.nix project attribute set."; + }; + + package = mkOption { + type = types.package; + default = cfg.project.hsPkgs.cardano-wallet.components.exes.cardano-wallet; + description = "Package for the cardano wallet executable."; + }; + + listenAddress = mkOption { + type = types.str; + default = "*"; + description = "Which host to bind the API server to."; + }; + + port = mkOption { + type = types.port; + default = 8090; + description = "The default port cardano wallet will listen on."; + }; + + nodeSocket = mkOption { + type = types.str; + default = "/run/cardano-node/node.socket"; + description = ''Cardano-Node local communication socket path.''; + }; + + environment = mkOption { + type = types.enum (builtins.attrNames cfg.environments); + default = "testnet"; + description = '' + The environment name to configure the wallet for. + This name can be an environment name from those found at + iohk-nix/cardano-lib/default.nix, or, it can be a custom + name, for example, if launching a test cluster that does + not have an environment yet defined in iohk-nix. If custom, + the environments option must contain an entry for this environment, + of the same form as in cardano-lib environments found + in iohk-nix. + ''; + }; + + environments = mkOption { + type = types.attrsOf types.attrs; + default = cfg.project.pkgs.cardanoLib.environments; + description = '' + The set of possible environment attribute set to configure the wallet for. + Default to the set of environments found at + iohk-nix/cardano-lib/default.nix, or, it must be an attribute set + of the same form. + ''; + }; + + walletMode = mkOption { + type = types.enum [ "mainnet" "staging" "testnet" ]; + default = + if cfg.environment == "mainnet" + then "mainnet" + else if cfg.environment == "staging" + then "staging" + else "testnet"; + 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.''; + }; + + 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.enum [ "none" "direct" "smash" ]; + default = if cardanoEnvAttrs ? smashUrl then "smash" else "none"; + description = '' + Sets the stake pool metadata fetching strategy. + "smash" will use the 'smashUrl' attribute of the 'environnement' + as metadata proxy server (default if exists). + Use "direct" to fetch directly from the + registered pool URLs, or "none" to completely disable + stake pool metadata (default if no 'smashUrl' defined).''; + }; + + tokenMetadataServer = mkOption { + type = types.nullOr types.str; + default = cardanoEnvAttrs.metadataUrl or 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". + ''; + }; + + rtsArgs = mkOption { + type = types.listOf types.str; + default = [ "-N2" ]; + apply = args: + if args != [ ] then + [ "+RTS" ] ++ args ++ [ "-RTS" ] + else [ ]; + description = ''Extra CLI args for 'cardano-wallet', to be surrounded by "+RTS"/"-RTS"''; + }; + + }; + + config = mkIf cfg.enable { + + systemd.services.cardano-wallet = { + description = "cardano-wallet daemon"; + wantedBy = [ "multi-user.target" ]; + inherit (cfg) script; + + serviceConfig = { + DynamicUser = true; + StateDirectory = "cardano-wallet/${cfg.environment}"; + }; + + environment = { + CARDANO_NODE_SOCKET_PATH = cfg.nodeSocket; + }; + }; + }; +} diff --git a/nix/release-build.nix b/nix/release-build.nix index 626a0b9785d..0d2e7c41d23 100644 --- a/nix/release-build.nix +++ b/nix/release-build.nix @@ -10,7 +10,7 @@ with pkgs.lib; -pkgs.stdenv.mkDerivation rec { +let drv = pkgs.stdenv.mkDerivation rec { name = "${exe.identifier.name}-${version}"; version = exe.identifier.version; phases = [ "installPhase" ]; @@ -20,7 +20,9 @@ pkgs.stdenv.mkDerivation rec { # fixme: remove this cp -Rv ${backend.deployments} $out/deployments ''); - meta.platforms = platforms.all; - passthru = optionalAttrs (backend != null) { inherit backend; }; -} + passthru = { + exePath = drv + "/bin/cardano-wallet"; + } // (optionalAttrs (backend != null) { inherit backend; }); +}; +in drv diff --git a/nix/scripts.nix b/nix/scripts.nix new file mode 100644 index 00000000000..a6207f62583 --- /dev/null +++ b/nix/scripts.nix @@ -0,0 +1,56 @@ +{ evalService +, project +, customConfigs +}: +with project.pkgs; +let + mkScript = envConfig: + let + service = evalService { + inherit pkgs customConfigs; + serviceName = "cardano-wallet"; + modules = [ + ./nixos/cardano-wallet-service.nix + ({ config, ... }: { + services.cardano-wallet = let cfg = config.services.cardano-wallet; in + { + project = lib.mkDefault project; + environment = lib.mkDefault envConfig.name; + database = lib.mkDefault "./db-cardano-wallet-${cfg.environment}"; + }; + }) + ]; + }; + + in + writeScriptBin "cardano-wallet-${service.environment}" '' + #!${pkgs.runtimeShell} + set -euo pipefail + ${service.script} $@ + ''; + + debugDeps = with pkgs; [ + coreutils + findutils + gnugrep + gnused + postgresql + strace + lsof + dnsutils + bashInteractive + iproute + curl + netcat + bat + tree + ]; + +in +cardanoLib.forEnvironments (environment: lib.recurseIntoAttrs rec { + wallet = mkScript environment; + wallet-debug = pkgs.symlinkJoin { + inherit (wallet) name; + paths = [ wallet ] ++ debugDeps; + }; +})