From 6c77690b2898aa8a12184ca8f3c113a11c957e50 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Wed, 26 Mar 2014 18:12:00 -0400 Subject: [PATCH] rippled: initial pkg and module expressions rippled is the Ripple P2P payment network reference server https://ripple.com --- lib/maintainers.nix | 1 + nixos/modules/misc/ids.nix | 1 + nixos/modules/module-list.nix | 1 + nixos/modules/services/misc/rippled.nix | 326 ++++++++++++++++++++++++ pkgs/servers/rippled/default.nix | 32 +++ pkgs/servers/rippled/scons-env.patch | 46 ++++ pkgs/top-level/all-packages.nix | 2 + 7 files changed, 409 insertions(+) create mode 100644 nixos/modules/services/misc/rippled.nix create mode 100644 pkgs/servers/rippled/default.nix create mode 100644 pkgs/servers/rippled/scons-env.patch diff --git a/lib/maintainers.nix b/lib/maintainers.nix index 938e1ed54550..1e3b9a32a529 100644 --- a/lib/maintainers.nix +++ b/lib/maintainers.nix @@ -28,6 +28,7 @@ coroa = "Jonas Hörsch "; edwtjo = "Edward Tjörnhammar "; eelco = "Eelco Dolstra "; + emery = "Emery Hemingawy "; ertes = "Ertugrul Söylemez "; falsifian = "James Cook "; garbas = "Rok Garbas "; diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 9c413e36d568..f03aeed7f65d 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -123,6 +123,7 @@ ngircd = 112; btsync = 113; minecraft = 114; + rippled = 115; # When adding a uid, make sure it doesn't match an existing gid. diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 652a99e7c5a6..79c071087e42 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -132,6 +132,7 @@ ./services/misc/nix-gc.nix ./services/misc/nix-ssh-serve.nix ./services/misc/nixos-manual.nix + ./services/misc/rippled.nix ./services/misc/rogue.nix ./services/misc/svnserve.nix ./services/misc/synergy.nix diff --git a/nixos/modules/services/misc/rippled.nix b/nixos/modules/services/misc/rippled.nix new file mode 100644 index 000000000000..7d339a48b976 --- /dev/null +++ b/nixos/modules/services/misc/rippled.nix @@ -0,0 +1,326 @@ +# configuration building is commented out until better tested. + +{ config, pkgs, ... }: + +with pkgs.lib; + +let + cfg = config.services.rippled; + + rippledStateCfgFile = "/var/lib/rippled/rippled.cfg"; + + rippledCfg = '' + [node_db] + type=HyperLevelDB + path=/var/lib/rippled/db/hyperldb + + [debug_logfile] + /var/log/rippled/debug.log + + '' + /* + + optionalString (cfg.ips != null) '' + [ips] + ${concatStringsSep "\n" cfg.ips} + + '' + + optionalString (cfg.ipsFixed != null) '' + [ips_fixed] + ${concatStringsSep "\n" cfg.ipsFixed} + + '' + */ + + optionalString (cfg.peerIp != null) '' + [peer_ip] + ${cfg.peerIp} + + [peer_port] + ${toString cfg.peerPort} + + '' + + cfg.extraConfig; + + rippledCfgFile = pkgs.writeText "rippled.cfg" rippledCfg; + +in + +{ + + ###### interface + + options = { + + services.rippled = { + + enable = mkOption { + default = false; + description = "Whether to enable rippled"; + }; + + /* + ips = mkOption { + default = [ "r.ripple.com 51235" ]; + example = [ "192.168.0.1" "192.168.0.1 3939" "r.ripple.com 51235" ]; + description = '' + List of hostnames or ips where the Ripple protocol is served. + For a starter list, you can either copy entries from: + https://ripple.com/ripple.txt or if you prefer you can let it + default to r.ripple.com 51235 + + A port may optionally be specified after adding a space to the + address. By convention, if known, IPs are listed in from most + to least trusted. + ''; + }; + + ipsFixed = mkOption { + default = null; + example = [ "192.168.0.1" "192.168.0.1 3939" "r.ripple.com 51235" ]; + description = '' + List of IP addresses or hostnames to which rippled should always + attempt to maintain peer connections with. This is useful for + manually forming private networks, for example to configure a + validation server that connects to the Ripple network through a + public-facing server, or for building a set of cluster peers. + + A port may optionally be specified after adding a space to the address + ''; + }; + */ + + peerIp = mkOption { + default = null; + example = "0.0.0.0"; + description = '' + IP address or domain to bind to allow external connections from peers. + Defaults to not binding, which disallows external connections from peers. + ''; + }; + + peerPort = mkOption { + default = 51235; + description = '' + If peerIp is supplied, corresponding port to bind to for peer connections. + ''; + }; + + /* + peerPortProxy = mkOption { + type = types.int; + example = 51236; + description = '' + An optional, additional listening port number for peers. Incoming + connections on this port will be required to provide a PROXY Protocol + handshake, described in this document (external link): + + http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt + + The PROXY Protocol is a popular method used by elastic load balancing + service providers such as Amazon, to identify the true IP address and + port number of external incoming connections. + + In addition to enabling this setting, it will also be required to + use your provider-specific control panel or administrative web page + to configure your server instance to receive PROXY Protocol handshakes, + and also to restrict access to your instance to the Elastic Load Balancer. + ''; + }; + + peerPrivate = mkOption { + default = null; + example = 0; + description = '' + 0: Request peers to broadcast your address. Normal outbound peer connections [default] + 1: Request peers not broadcast your address. Only connect to configured peers. + ''; + }; + + peerSslCipherList = mkOption { + default = null; + example = "ALL:!LOW:!EXP:!MD5:@STRENGTH"; + description = '' + A colon delimited string with the allowed SSL cipher modes for peer. The + choices for for ciphers are defined by the OpenSSL API function + SSL_CTX_set_cipher_list, documented here (external link): + + http://pic.dhe.ibm.com/infocenter/tpfhelp/current/index.jsp?topic=%2Fcom.ibm.ztpf-ztpfdf.doc_put.cur%2Fgtpc2%2Fcpp_ssl_ctx_set_cipher_list.html + + The default setting of "ALL:!LOW:!EXP:!MD5:@STRENGTH", which allows + non-authenticated peer connections (they are, however, secure). + ''; + }; + + nodeSeed = mkOption { + default = null; + example = "RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE"; + description = '' + This is used for clustering. To force a particular node seed or key, the + key can be set here. The format is the same as the validation_seed field. + To obtain a validation seed, use the rippled validation_create command. + ''; + }; + + clusterNodes = mkOption { + default = null; + example = [ "n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5" ]; + description = '' + To extend full trust to other nodes, place their node public keys here. + Generally, you should only do this for nodes under common administration. + Node public keys start with an 'n'. To give a node a name for identification + place a space after the public key and then the name. + ''; + }; + + sntpServers = mkOption { + default = null; + example = [ "time.nist.gov" "pool.ntp.org" ]; + description = '' + IP address or domain of NTP servers to use for time synchronization. + ''; + }; + + # TODO: websocket options + + rpcAllowRemote = mkOption { + default = false; + description = '' + false: Allow RPC connections only from 127.0.0.1. [default] + true: Allow RPC connections from any IP. + ''; + }; + + rpcAdminAllow = mkOption { + example = [ "10.0.0.4" ]; + description = '' + List of IP addresses allowed to have admin access. + ''; + }; + + rpcAdminUser = mkOption { + type = types.str; + description = '' + As a server, require this as the admin user to be specified. Also, require + rpc_admin_user and rpc_admin_password to be checked for RPC admin functions. + The request must specify these as the admin_user and admin_password in the + request object. + ''; + }; + + rpcAdminPassword = mkOption { + type = types.str; + description = '' + As a server, require this as the admin pasword to be specified. Also, + require rpc_admin_user and rpc_admin_password to be checked for RPC admin + functions. The request must specify these as the admin_user and + admin_password in the request object. + ''; + }; + + rpcIp = mkOption { + type = types.str; + description = '' + IP address or domain to bind to allow insecure RPC connections. + Defaults to not binding, which disallows RPC connections. + ''; + }; + + rpcPort = mkOption { + type = types.int; + description = '' + If rpcIp is supplied, corresponding port to bind to for peer connections. + ''; + }; + + rpcUser = mkOption { + type = types.str; + description = '' + Require a this user to specified and require rpcPassword to + be checked for RPC access via the rpcIp and rpcPort. The user and password + must be specified via HTTP's basic authentication method. + As a client, supply this to the server via HTTP's basic authentication + method. + ''; + }; + + rpcPassword = mkOption { + type = types.str; + description = '' + Require a this password to specified and require rpc_user to + be checked for RPC access via the rpcIp and rpcPort. The user and password + must be specified via HTTP's basic authentication method. + As a client, supply this to the server via HTTP's basic authentication + method. + ''; + }; + + rpcStartup = mkOption { + example = [ ''"command" : "log_level"'' ''"partition" : "ripplecalc"'' ''"severity" : "trace"'' ]; + description = "List of RPC commands to run at startup."; + }; + + rpcSecure = mkOption { + default = false; + description = '' + false: Server certificates are not provided for RPC clients using SSL [default] + true: Client RPC connections wil be provided with SSL certificates. + + Note that if rpc_secure is enabled, it will also be necessasry to configure the + certificate file settings located in rpcSslCert, rpcSslChain, and rpcSslKey + ''; + }; + */ + + extraConfig = mkOption { + default = ""; + description = '' + Extra lines to be added verbatim to the rippled.cfg configuration file. + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + environment = { + etc = singleton + { source = rippledStateCfgFile; + target = "rippled"; + }; + + # users can attempt to send RPC commands to the server. + systemPackages = [ pkgs.rippled ]; + }; + + users.extraUsers = singleton + { name = "rippled"; + description = "Ripple server user"; + uid = config.ids.uids.rippled; + home = "/var/lib/rippled"; + }; + + systemd.services.rippled = { + path = [ pkgs.rippled ]; + + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + ExecStart = "${pkgs.rippled}/bin/rippled --fg -q --conf ${rippledStateCfgFile}"; + WorkingDirectory = "/var/lib/rippled"; + }; + }; + + networking.firewall.allowedTCPPorts = mkIf (cfg.peerIp != null) [ cfg.peerPort ]; + + system.activationScripts.rippled = '' + mkdir -p /var/{lib,log}/rippled + chown -R rippled /var/{lib,log}/rippled + ln -sf ${rippledCfgFile} ${rippledStateCfgFile} + ''; + }; +} diff --git a/pkgs/servers/rippled/default.nix b/pkgs/servers/rippled/default.nix new file mode 100644 index 000000000000..66a0743b367f --- /dev/null +++ b/pkgs/servers/rippled/default.nix @@ -0,0 +1,32 @@ +{ stdenv, fetchurl, scons, pkgconfig, openssl, protobuf, boost155, zlib}: + +stdenv.mkDerivation rec { + name = "rippled-${version}"; + version = "0.23.0"; + + src = fetchurl { + url = "https://github.com/ripple/rippled/archive/${version}.tar.gz"; + sha256 = "0js734sk11jn19fyp403mk6p62azlc6s9kyhr5jfg466fiak537p"; + }; + + patches = [ ./scons-env.patch ]; + + buildInputs = [ scons pkgconfig openssl protobuf boost155 zlib ]; + + RIPPLED_BOOST_HOME = boost155.out; + RIPPLED_ZLIB_HOME = zlib.out; + buildPhase = "scons build/rippled"; + + installPhase = '' + mkdir -p $out/bin + cp build/rippled $out/bin/ + ''; + + meta = { + description = "Ripple P2P payment network reference server"; + homepage = "https://ripple.com"; + maintainers = stdenv.lib.maintainers.emery; + license = stdenv.lib.licenses.isc; + platforms = stdenv.lib.platforms.linux; + }; +} \ No newline at end of file diff --git a/pkgs/servers/rippled/scons-env.patch b/pkgs/servers/rippled/scons-env.patch new file mode 100644 index 000000000000..5b80e77bb2e0 --- /dev/null +++ b/pkgs/servers/rippled/scons-env.patch @@ -0,0 +1,46 @@ +diff --git a/SConstruct b/SConstruct +index 8ba8bbd..95eab3b 100644 +--- a/SConstruct ++++ b/SConstruct +@@ -24,6 +24,8 @@ USING_CLANG = OSX or os.environ.get('CC', None) == 'clang' + # + BOOST_HOME = os.environ.get("RIPPLED_BOOST_HOME", None) + ++ZLIB_HOME = os.environ.get("RIPPLED_ZLIB_HOME", None) ++ + + if OSX or Ubuntu or Debian or Archlinux: + CTAGS = 'ctags' +@@ -36,7 +38,7 @@ else: + # scons tools + # + +-HONOR_ENVS = ['CC', 'CXX', 'PATH'] ++HONOR_ENVS = ['CC', 'CXX', 'PATH', 'PKG_CONFIG_PATH'] + + env = Environment( + tools = ['default', 'protoc'], +@@ -156,8 +158,8 @@ INCLUDE_PATHS = [ + 'build/proto' + ] + +-# if BOOST_HOME: +-# INCLUDE_PATHS.append(BOOST_HOME) ++if BOOST_HOME: ++ INCLUDE_PATHS.append("%s/include" % BOOST_HOME) + + #------------------------------------------------------------------------------- + # +@@ -261,7 +263,11 @@ env.Append( + # such, as installed into `/usr/lib/` + if BOOST_HOME is not None: + env.Prepend( +- LIBPATH = ["%s/stage/lib" % BOOST_HOME]) ++ LIBPATH = ["%s/lib" % BOOST_HOME]) ++ ++if ZLIB_HOME is not None: ++ env.Prepend( ++ LIBPATH = ["%s/lib" % ZLIB_HOME]) + + if not OSX: + env.Append(LINKFLAGS = [ diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index da2edad1e60d..8a9228d15a2b 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -6528,6 +6528,8 @@ let rethinkdb = callPackage ../servers/nosql/rethinkdb { }; + rippled = callPackage ../servers/rippled { }; + spamassassin = callPackage ../servers/mail/spamassassin { inherit (perlPackages) HTMLParser NetDNS NetAddrIP DBFile HTTPDate MailDKIM LWP IOSocketSSL;