├── LICENSE ├── README.md ├── default.nix ├── machines └── vbox.nix ├── modules ├── apps │ ├── cassandra │ │ ├── default.nix │ │ └── instance.nix │ ├── cli.nix │ ├── default.nix │ ├── docker │ │ ├── default.nix │ │ └── instance.nix │ ├── filebackup.nix │ ├── gnupg │ │ ├── default.nix │ │ └── instance.nix │ ├── icinga2.nix │ ├── icingaweb2.nix │ ├── jenkins │ │ ├── default.nix │ │ └── instance.nix │ ├── juandelacosa.nix │ ├── logrotate.nix │ ├── mariadb │ │ ├── default.nix │ │ ├── mysqld.nix │ │ ├── procedures.sql │ │ ├── replicate.nix │ │ ├── roles.nix │ │ └── slave-watchdog.nix │ ├── mediawiki │ │ ├── default.nix │ │ └── localSettings.nix │ ├── memcached │ │ ├── default.nix │ │ └── instance.nix │ ├── mysqlbackup.nix │ ├── mywatch.nix │ ├── nginx.nix │ ├── nix-serve.nix │ ├── openldap │ │ ├── default.nix │ │ └── instance.nix │ ├── pgbackup.nix │ ├── php-fpm.nix │ ├── postgresql │ │ ├── default.nix │ │ ├── functions.pgsql │ │ └── server.nix │ ├── sproxy-web.nix │ ├── sproxy2.nix │ └── strongswan │ │ ├── default.nix │ │ └── options │ │ ├── ca.nix │ │ ├── conn.nix │ │ ├── lib.nix │ │ └── setup.nix ├── default.nix ├── deployment │ ├── default.nix │ └── keyrings.nix ├── overlay.nix └── system │ ├── default.nix │ ├── firewall.nix │ ├── raid0.nix │ ├── sysops.nix │ ├── users.nix │ └── worldWritableDirs.nix └── pkgs ├── cassandra3 └── default.nix ├── check_aws_ec2_elb ├── check_aws_ec2_elb ├── check_aws_ec2_elb.conf └── default.nix ├── check_aws_rds ├── check_aws_rds ├── check_aws_rds.conf └── default.nix ├── check_aws_s3_file ├── check_aws_s3_file ├── check_aws_s3_file.conf └── default.nix ├── check_json ├── check_json ├── check_json.conf └── default.nix ├── check_mdstat ├── check_mdstat └── default.nix ├── check_solr ├── cabal2nix.nix └── default.nix ├── check_systemd ├── check_systemd └── default.nix ├── default.nix ├── fakeSSL ├── cert.pem ├── default.nix └── key.pem ├── gpg.nix ├── hoogle ├── default.nix └── main.nix ├── hyperic-sigar └── default.nix ├── icinga2 ├── check_mysql_slave.patch └── default.nix ├── icingaweb2 ├── default.nix └── sproxy.patch ├── jenkins.nix ├── jenkinsUpdateCenter ├── default.nix └── update-center.actual.json ├── jenkinsWithPlugins ├── default.nix └── fromBase64.nix ├── juandelacosa ├── default.nix └── main.nix ├── kibana5 └── default.nix ├── ldapply ├── default.nix ├── ldap.nix └── main.nix ├── mariadb_10_1 └── default.nix ├── mathJax.nix ├── mediawiki ├── T122487.patch ├── default.nix └── file-backend-default-mode.patch ├── mediawikiExtensions ├── Sproxy │ └── Sproxy.php └── default.nix ├── monitoringPlugins ├── check_mysql_MYSQL_PORT.patch ├── default.nix ├── mysql_check_slave.patch └── test-str-format.patch ├── mywatch ├── default.nix └── main.nix ├── nagios-plugins-rabbitmq └── default.nix ├── nix-serve ├── default.nix └── nix-serve.psgi ├── nodejs-sass ├── default.nix ├── generate.sh ├── main.json ├── main.nix ├── node-env.nix └── node-packages.nix ├── openldap-modular.nix ├── postcss-cli ├── default.nix ├── generate.sh ├── main.json ├── main.nix ├── node-env.nix └── node-packages.nix ├── postcss-plugins ├── default.nix ├── find.sh ├── generate.sh ├── node-env.nix ├── node-packages.nix ├── plugins.json └── plugins.nix ├── probes.nix ├── pyresttest ├── add-unix-socket.patch └── default.nix ├── rdsdump ├── default.nix └── rdsdump.bash ├── sass-lint ├── default.nix ├── generate.sh ├── main.json ├── main.nix ├── node-env.nix └── node-packages.nix ├── sproxy-web ├── cabal2nix.nix └── default.nix ├── sproxy2 ├── default.nix └── main.nix ├── uglify-js ├── default.nix ├── generate.sh ├── main.json ├── main.nix ├── node-env.nix └── node-packages.nix ├── writeBashScript.nix ├── writeBashScriptBin.nix ├── writePHPFile.nix ├── writeXML.nix ├── writeYAML.nix └── xinclude2nix ├── default.nix └── xinclude2nix.hs /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Zalora South East Asia Pte. Ltd 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | About 2 | ===== 3 | 4 | Nixsap is a set of modules built on top of 5 | [NixOS](https://nixos.org/)/[Nixpkgs](https://nixos.org/nixpkgs/). Nixsap 6 | provides NixOS modules in the `nixsap` "namespace", e. g. `nixsap.apps.mariadb` 7 | or `nixsap.system.users`, and adds or overrides some packages in Nixpkgs. 8 | From vanila Nixpkgs, Nixsap relies only on basic services like systemd, ssh, ntpd 9 | and package set (extending and overriding it). 10 | 11 | 12 | Features 13 | ======== 14 | 15 | 16 | Plug & Play 17 | ----------- 18 | 19 | Each module under the [modules](./modules) directory is automatically available. 20 | When creating a new machine just use 21 | 22 | imports = [ ]; 23 | 24 | Each package `foo` under the [./pkgs](./pkgs) is automatically available as `pkgs.foo`. 25 | For example: 26 | 27 | pkgs/writeXML.nix => pkgs.writeXML 28 | pkgs/rdsdump/default.nix => pkgs.rdsdump 29 | 30 | You can use this techniques in your own projects. You can take out any modules 31 | or packages and put them into your project with your modifications without 32 | maintaning a fork of Nixsap. When taking modules you have to change the 33 | `nixsap` namespace to something different to avoid conflicts. 34 | 35 | 36 | Package Overlay 37 | --------------- 38 | 39 | Nixsap modules use a package overlay located in [./pkgs/default.nix](./pkgs/default.nix). 40 | It is also possible to build and install packages from this overlay independently, 41 | for example: 42 | 43 | ``` 44 | nix-build -E '(import { overlays = [ (import ./pkgs/default.nix) ]; })' -A icinga2 45 | ``` 46 | 47 | 48 | Automatic unix user id 49 | ----------------------- 50 | 51 | To create daemon users just add their names into the list 52 | `nixsap.system.users.daemons`. List `nixsap.system.users.normal` 53 | does the same for users with login shell, and `nixsap.system.groups` 54 | for unix groups. Users and groups will automatically get their 55 | ids based on their names in a deterministic manner. See examples 56 | in the [applications directory](./modules/apps) and implementation in 57 | [modules/system/users.nix](modules/system/users.nix). This feature is used 58 | throughout `nixsap.apps`. 59 | 60 | Examples: 61 | 62 | # id icinga 63 | uid=1240920351(icinga) gid=100(users) groups=21(proc),100(users) 64 | 65 | # id pashev 66 | uid=1141737888(pashev) gid=100(users) groups=100(users),21(proc),62(systemd-journal),1061782283(sysops) 67 | 68 | # id jenkins-dumpoo 69 | uid=1201814562(jenkins-dumpoo) gid=1201814562(jenkins-dumpoo) groups=96(keys),1201814562(jenkins-dumpoo) 70 | 71 | # id mariadb 72 | uid=1213117043(mariadb) gid=1213117043(mariadb) groups=96(keys),1213117043(mariadb) 73 | 74 | 75 | 76 | Keyrings 77 | -------- 78 | 79 | [Keyrings](modules/deployment/keyrings.nix) provide a means of 80 | deploying secret files with sensitive content. It's inspired by 81 | [NixOps](https://nixos.org/nixops/) and relies on it as on reference 82 | implementation. Most applications from `nixsap.apps` recognize keys from their 83 | parameters or extract them from configuration files and automatically build 84 | their keyrings. 85 | 86 | 87 | Multi-instance applications 88 | --------------------------- 89 | 90 | For most [applications](./modules/apps) it is possible to run multiple 91 | instances of them on the same machine. Each instance may have its own 92 | home directory and user. For example `jenkins-foo` with home directory 93 | `/jenkins/foo` and user `jenkins-foo`. Not all applications allow that 94 | purely for historical reasons, and this will be fixed eventually. 95 | 96 | 97 | 98 | 99 | Design 100 | ====== 101 | 102 | 103 | Static analysis 104 | --------------- 105 | 106 | There are a handful of tools used thoughout the applications to ensure 107 | correctness at build time: `writeBashScript`, `writeXML`, `writePHPFile`. 108 | `writeBashScript` uses [shellcheck](https://www.shellcheck.net/). `writeXML` 109 | runs [xmllint](http://xmlsoft.org/xmllint.html). `writePHPFile` relies on 110 | PHP's built-in syntax checker. 111 | 112 | The objective it to do static analysis and linting for every single file 113 | _at build time_. What is wanted: configuration files for Nginx, Icinga; 114 | MySQL and PostgreSQL scripts, etc. 115 | 116 | 117 | Parametrization 118 | --------------- 119 | 120 | Everything that _can_ be used at build time should have a parameter (integer, 121 | string, path, etc.). Examples are TCP port, data directory, UNIX user. TCP 122 | port can be used for configuring firewall or HTTP proxy, data directory can 123 | be used for setting up mount points, UNIX user can be included into extra 124 | groups, etc. When we have it all parametrized we do not repeat ourselves. 125 | 126 | Parametrization also helps modularity. I. e. you can define default set of 127 | values and override only some of them in specific setups. 128 | 129 | Some applications accept only discrete set of options, in that case we should 130 | parametrize them all. Examples are memcached, php-fpm and sproxy2. 131 | 132 | Parametrization should give access to all application features. Ideally, 133 | parameters should exactly match to the application options, including 134 | their names and meanings. Examples are MariaDB and PostgreSQL. This makes 135 | documentation unnecessary, because each parameter is documented somewhere else. 136 | 137 | Almost every parameter, if it's not required by application (i. e. has 138 | a built-in default value), should have value `null` by default. If such 139 | parameter is not set, it is not passed to the application. This is twofold: 140 | more transparency because we use _application's_ defaults (not ours), and it 141 | is safer to use different versions of application, when particular options 142 | may be added or removed. 143 | 144 | Even though, if the value of parameter is required at build time, the parameter 145 | should have default value, preferably application's default. Example is 146 | MariaDB's TCP port. We need it to configure firewall, thus we define it to 147 | be 3306 by default. 148 | 149 | If application default value is known to be insecure, we should set our own, 150 | _secure_, default value. 151 | 152 | 153 | Recommendations 154 | =============== 155 | 156 | * [nixpkgs](https://nixos.org/nixpkgs/) >= 18.03 157 | 158 | 159 | License 160 | ======= 161 | 162 | This project is under the MIT license (see [LICENSE](LICENSE)), 163 | unless stated otherwise in individual files. 164 | 165 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ ./modules ]; 3 | } 4 | 5 | -------------------------------------------------------------------------------- /machines/vbox.nix: -------------------------------------------------------------------------------- 1 | # This is for NixOps (https://nixos.org/nixops/) 2 | 3 | { config, pkgs, lib, ... }: 4 | let 5 | inherit (config.nixsap) apps; 6 | inherit (lib) mkForce mkDefault mkIf; 7 | inherit (pkgs) writeText; 8 | memorySize = config.deployment.virtualbox.memorySize * 1024 * 1024; 9 | in { 10 | deployment.targetEnv = "virtualbox"; 11 | deployment.virtualbox = { 12 | headless = mkDefault true; 13 | memorySize = mkDefault 1024; # megabytes 14 | disks = { 15 | sdb = { port = 1; size = 30000; }; 16 | sdc = { port = 2; size = 30000; }; 17 | sdd = { port = 4; size = 2000; }; 18 | }; 19 | }; 20 | swapDevices = [{ device = "/dev/sdd"; randomEncryption = true; }]; 21 | 22 | 23 | nixsap.system.lvm.raid0.apps = { 24 | stripes = 2; 25 | units = "g"; 26 | physical = [ "/dev/sdb" "/dev/sdc" ]; 27 | fileSystems."${apps.icinga2.stateDir}" = mkIf apps.icinga2.enable 1; 28 | fileSystems."${apps.icingaweb2.configDir}" = mkIf apps.icingaweb2.enable 1; 29 | fileSystems."${apps.mysqlbackup.dumpDir}" = mkIf (apps.mysqlbackup.servers != {}) 10; 30 | fileSystems."${apps.nginx.stateDir}" = mkIf (apps.nginx.conf.http.servers != {}) 1; 31 | fileSystems."/jenkins" = mkIf (apps.jenkins != {}) 15; 32 | fileSystems."/mariadb" = mkIf apps.mariadb.enable 30; 33 | fileSystems."/postgresql" = mkIf (apps.postgresql != {}) 2; 34 | fileSystems."/tmp" = 1; 35 | }; 36 | 37 | nixsap.apps.icinga2.notifications = mkForce false; 38 | 39 | nixsap.apps.mariadb.mysqld = { 40 | datadir = mkForce "/mariadb/db"; 41 | innodb_buffer_pool_size = (40 * memorySize) / 100; 42 | log_bin = mkForce "/mariadb/binlog/binlog"; 43 | relay_log = mkForce "/mariadb/relay/relay"; 44 | server_id = mkForce 1; 45 | ssl_cert = mkForce "${pkgs.fakeSSL}/cert.pem"; 46 | ssl_key = mkForce "${pkgs.fakeSSL}/key.pem"; 47 | }; 48 | 49 | nixsap.apps.sproxy2 = { 50 | ssl_cert = mkForce "${pkgs.fakeSSL}/cert.pem"; 51 | ssl_key = mkForce "${pkgs.fakeSSL}/key.pem"; 52 | }; 53 | 54 | nixsap.apps.sproxy-web = { 55 | connectionString = mkForce "user=sproxy dbname=sproxy port=${toString apps.postgresql.fcebkl.server.port}"; 56 | }; 57 | 58 | nixsap.apps.mediawiki.localSettings = { 59 | wgDBerrorLog = "/tmp/wiki-db.log"; 60 | wgDebugLogFile = "/tmp/wiki.log"; 61 | wgShowDBErrorBacktrace = true; 62 | wgShowExceptionDetails = true; 63 | }; 64 | 65 | security.sudo.wheelNeedsPassword = mkForce false; 66 | environment.systemPackages = with pkgs; [ 67 | curl file htop iftop iotop jq lsof mc mtr ncdu netcat nmap openssl 68 | pigz pv pwgen pxz sysstat tcpdump telnet tmux traceroute tree vim wget 69 | ]; 70 | 71 | programs.bash.enableCompletion = mkForce true; 72 | 73 | services.openssh.authorizedKeysFiles = mkForce [ 74 | "/etc/ssh/authorized_keys.d/%u" 75 | "/root/.ssh/authorized_keys" 76 | "/root/.vbox-nixops-client-key" 77 | ]; 78 | 79 | nixsap.apps.postgresql.fcebkl = mkIf apps.sproxy-web.enable { 80 | package = pkgs.postgresql95; 81 | server = { 82 | data_directory = "/postgresql/9.5/fcebkl"; 83 | port = 9999; 84 | hba_file = '' 85 | local sproxy all peer map=sproxymap 86 | ''; 87 | ident_file = '' 88 | sproxymap ${apps.sproxy2.user} sproxy-readonly 89 | sproxymap ${apps.sproxy-web.user} sproxy 90 | ''; 91 | }; 92 | roles = [ "sproxy" "sproxy-readonly" ]; 93 | databases = [ "sproxy" ]; 94 | configure = '' 95 | ALTER ROLE sproxy LOGIN; 96 | ALTER ROLE "sproxy-readonly" LOGIN; 97 | ALTER DATABASE sproxy OWNER TO sproxy; 98 | 99 | \c sproxy; 100 | SET ROLE sproxy; 101 | 102 | GRANT SELECT ON ALL TABLES IN SCHEMA public TO "sproxy-readonly"; 103 | ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO "sproxy-readonly"; 104 | 105 | BEGIN; 106 | CREATE TABLE IF NOT EXISTS "group" ( 107 | "group" TEXT NOT NULL PRIMARY KEY 108 | ); 109 | CREATE TABLE IF NOT EXISTS group_member ( 110 | "group" TEXT REFERENCES "group" ("group") ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, 111 | email TEXT NOT NULL, 112 | PRIMARY KEY ("group", email) 113 | ); 114 | CREATE TABLE IF NOT EXISTS domain ( 115 | domain TEXT NOT NULL PRIMARY KEY 116 | ); 117 | CREATE TABLE IF NOT EXISTS privilege ( 118 | "domain" TEXT REFERENCES domain (domain) ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, 119 | privilege TEXT NOT NULL, 120 | PRIMARY KEY ("domain", privilege) 121 | ); 122 | CREATE TABLE IF NOT EXISTS privilege_rule ( 123 | "domain" TEXT NOT NULL, 124 | privilege TEXT NOT NULL, 125 | "path" TEXT NOT NULL, 126 | "method" TEXT NOT NULL, 127 | FOREIGN KEY ("domain", privilege) REFERENCES privilege ("domain", privilege) ON UPDATE CASCADE ON DELETE CASCADE, 128 | PRIMARY KEY ("domain", "path", "method") 129 | ); 130 | CREATE TABLE IF NOT EXISTS group_privilege ( 131 | "group" TEXT REFERENCES "group" ("group") ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, 132 | "domain" TEXT NOT NULL, 133 | privilege TEXT NOT NULL, 134 | FOREIGN KEY ("domain", privilege) REFERENCES privilege ("domain", privilege) ON UPDATE CASCADE ON DELETE CASCADE, 135 | PRIMARY KEY ("group", "domain", privilege) 136 | ); 137 | COMMIT; 138 | 139 | BEGIN; 140 | INSERT INTO domain (domain) VALUES ('%') ON CONFLICT DO NOTHING; 141 | INSERT INTO "group" ("group") VALUES ('all') ON CONFLICT DO NOTHING; 142 | INSERT INTO "group" ("group") VALUES ('devops') ON CONFLICT DO NOTHING; 143 | INSERT INTO "group" ("group") VALUES ('foo') ON CONFLICT DO NOTHING; 144 | INSERT INTO group_member ("group", email) VALUES ('all', '%') ON CONFLICT DO NOTHING; 145 | INSERT INTO group_member ("group", email) VALUES ('devops', '%') ON CONFLICT DO NOTHING; 146 | INSERT INTO group_member ("group", email) VALUES ('foo', '%') ON CONFLICT DO NOTHING; 147 | INSERT INTO privilege (domain, privilege) VALUES ('%', 'full') ON CONFLICT DO NOTHING; 148 | INSERT INTO group_privilege ("group", domain, privilege) VALUES ('all', '%', 'full') ON CONFLICT DO NOTHING; 149 | INSERT INTO group_privilege ("group", domain, privilege) VALUES ('devops', '%', 'full') ON CONFLICT DO NOTHING; 150 | INSERT INTO group_privilege ("group", domain, privilege) VALUES ('foo', '%', 'full') ON CONFLICT DO NOTHING; 151 | INSERT INTO privilege_rule (domain, privilege, path, method) VALUES ('%', 'full', '%', '%') ON CONFLICT DO NOTHING; 152 | COMMIT; 153 | 154 | RESET ROLE; 155 | \c postgres; 156 | ''; 157 | }; 158 | } 159 | -------------------------------------------------------------------------------- /modules/apps/cassandra/default.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | let 4 | 5 | inherit (builtins) 6 | match ; 7 | 8 | inherit (lib) 9 | concatMapStringsSep concatStringsSep filterAttrs flatten foldAttrs foldl 10 | mapAttrsToList mkOption ; 11 | 12 | inherit (lib.types) 13 | attrsOf submodule ; 14 | 15 | explicit = filterAttrs (n: v: n != "_module" && v != null); 16 | concatMapAttrsSep = s: f: attrs: concatStringsSep s (mapAttrsToList f attrs); 17 | 18 | instances = explicit config.nixsap.apps.cassandra; 19 | users = mapAttrsToList (_: i: i.user) instances; 20 | 21 | keyrings = 22 | let 23 | ik = mapAttrsToList (n: i: { "${i.user}" = []; } ) instances; 24 | in foldAttrs (l: r: l ++ r) [] ik; 25 | 26 | mkService = name: cfg: 27 | let 28 | 29 | tmpdir = "${cfg.home}/tmp"; 30 | cp = concatStringsSep ":" cfg.classpath; 31 | 32 | isDir = d: _: match ".*_director(y|ies)$" d != null; 33 | directories = [ cfg.home ] 34 | ++ flatten (mapAttrsToList (_: d: d) (filterAttrs isDir (explicit cfg.parameters))); 35 | 36 | directories_sh = concatMapStringsSep " " (d: "'${d}'") directories; 37 | 38 | 39 | start = pkgs.writeBashScriptBin "cassandra-${name}" '' 40 | set -euo pipefail 41 | umask 0027 42 | export HOME='${cfg.home}' 43 | 44 | rm -rf -- '${cfg.jre.properties.java.io.tmpdir}' 45 | mkdir -p -- '${cfg.jre.properties.java.io.tmpdir}' 46 | 47 | exec ${cfg.jre.package}/bin/java \ 48 | -Dcassandra.config='${cfg.jre.properties.cassandra.config}' \ 49 | -Djava.io.tmpdir='${cfg.jre.properties.java.io.tmpdir}' \ 50 | -Djava.library.path='${concatStringsSep ":" cfg.jre.properties.java.library.path}' \ 51 | -cp '${cp}' \ 52 | org.apache.cassandra.service.CassandraDaemon 53 | 54 | ''; 55 | 56 | in { 57 | "cassandra-${name}" = { 58 | description = "Cassandra (${name}) distributed NoSQL database"; 59 | wantedBy = [ "multi-user.target" ]; 60 | after = [ "keys.target" "network.target" "local-fs.target" ]; 61 | preStart = '' 62 | mkdir -p -- ${directories_sh} 63 | 64 | find ${directories_sh} -not -type l \( \ 65 | -not -user '${cfg.user}' \ 66 | -or -not -group '${cfg.user}' \ 67 | -or \( -type d -not -perm -u=wrx,g=rx \) \ 68 | -or \( -type f -not -perm -u=rw,g=r \) \ 69 | \) \ 70 | -exec chown -c -- '${cfg.user}:${cfg.user}' {} + \ 71 | -exec chmod -c -- u=rwX,g=rX,o= {} + 72 | 73 | ''; 74 | 75 | unitConfig = { 76 | # XXX It can be running long before fail: 77 | StartLimitBurst = 3; 78 | StartLimitIntervalSec = 60; 79 | }; 80 | 81 | serviceConfig = { 82 | ExecStart = "${start}/bin/cassandra-${name}"; 83 | KillMode = "mixed"; 84 | PermissionsStartOnly = true; 85 | Restart = "always"; 86 | TimeoutSec = 0; 87 | User = cfg.user; 88 | LimitAS = "infinity"; 89 | LimitMEMLOCK = "infinity"; 90 | LimitNOFILE = 10000; 91 | LimitNPROC = 32768; 92 | }; 93 | }; 94 | }; 95 | 96 | in { 97 | 98 | options.nixsap.apps.cassandra = mkOption { 99 | description = "Cassandra instances"; 100 | default = {}; 101 | type = attrsOf (submodule (import ./instance.nix pkgs)); 102 | }; 103 | 104 | config = { 105 | systemd.services = foldl (a: b: a//b) {} (mapAttrsToList mkService instances); 106 | nixsap.deployment.keyrings = keyrings; 107 | nixsap.system.users.daemons = users; 108 | }; 109 | 110 | } 111 | -------------------------------------------------------------------------------- /modules/apps/cli.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ...}: 2 | 3 | let 4 | 5 | inherit (lib) 6 | concatMapStrings filterAttrs mapAttrs mapAttrsToList mkOption unique ; 7 | inherit (lib.types) 8 | attrsOf path str submodule ; 9 | 10 | explicit = filterAttrs (n: v: n != "_module" && v != null); 11 | apps = explicit config.nixsap.apps.cli; 12 | 13 | exec = name: { user, command, ... }: 14 | let 15 | cc = "${pkgs.gcc}/bin/gcc -Wall -Wextra -Werror -s -std=gnu99 -O2"; 16 | uid = toString config.users.users.${user}.uid; 17 | gid = uid; 18 | src = pkgs.writeText "${name}.c" '' 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | int main (int __attribute__((unused)) argc, char *argv[]) 27 | { 28 | int rc; 29 | 30 | if (getuid() != ${uid}) { 31 | if (geteuid() != 0) { 32 | fprintf(stderr, "Forbidden.\n"); 33 | return EXIT_FAILURE; 34 | } 35 | 36 | rc = initgroups("${user}", ${gid}); 37 | if (0 != rc) { 38 | perror("initgroups()"); 39 | return EXIT_FAILURE; 40 | } 41 | 42 | rc = setgid(${gid}); 43 | if (0 != rc) { 44 | perror("setgid()"); 45 | return EXIT_FAILURE; 46 | } 47 | 48 | rc = setuid(${uid}); 49 | if (0 != rc) { 50 | perror("setuid()"); 51 | return EXIT_FAILURE; 52 | } 53 | 54 | if ((getuid() != ${uid}) || (geteuid() != ${uid})) { 55 | fprintf(stderr, "Something went wrong.\n"); 56 | return EXIT_FAILURE; 57 | } 58 | 59 | struct passwd * pw = getpwuid(${uid}); 60 | if (NULL == pw) { 61 | perror("getpwuid()"); 62 | return EXIT_FAILURE; 63 | } 64 | 65 | if (NULL != pw->pw_dir) { 66 | rc = chdir(pw->pw_dir); 67 | if (0 != rc) { 68 | rc = chdir("/"); 69 | } 70 | } else { 71 | rc = chdir("/"); 72 | } 73 | if (0 != rc) { 74 | perror("chdir()"); 75 | return EXIT_FAILURE; 76 | } 77 | } 78 | 79 | argv[0] = "${command}"; 80 | execv(argv[0], argv); 81 | 82 | perror("execv()"); 83 | return EXIT_FAILURE; 84 | } 85 | ''; 86 | in pkgs.runCommand name {} "${cc} -o $out ${src}"; 87 | 88 | cliapp = submodule({name, ...}: 89 | { 90 | options = { 91 | user = mkOption { 92 | description = '' 93 | User (and group) to run as. Only users in this group can execute 94 | this application. 95 | ''; 96 | type = str; 97 | default = name; 98 | }; 99 | command = mkOption { 100 | description = "Path to executable"; 101 | type = path; 102 | }; 103 | }; 104 | }); 105 | 106 | in { 107 | options.nixsap = { 108 | apps.cli = mkOption { 109 | description = '' 110 | Command line applications that should run as other users and likely 111 | have special privileges, e. g. to access secret keys. This is 112 | implemented with setuid-wrappers. Each wrapper is launched as root, 113 | immediately switches to specified user, then executes something 114 | useful. This is like sudo, but access is controlled via wrapper's 115 | group: only users in wrapper's group can execute the wrapper. 116 | 117 | Starting as set-uid-non-root is not sufficient, because we might 118 | need supplementary groups, like "keys". 119 | ''; 120 | type = attrsOf cliapp; 121 | default = {}; 122 | }; 123 | }; 124 | 125 | config = { 126 | nixsap.system.users.daemons = unique (mapAttrsToList (_: a: a.user) apps); 127 | security.wrappers = mapAttrs (n: a: 128 | { source = exec n a; 129 | owner = "root"; 130 | group = a.user; 131 | setuid = true; 132 | setgid = false; 133 | permissions = "u+rx,g+x,o="; 134 | }) apps; 135 | }; 136 | } 137 | 138 | -------------------------------------------------------------------------------- /modules/apps/default.nix: -------------------------------------------------------------------------------- 1 | {lib, ... }: 2 | 3 | let 4 | all = lib.filterAttrs 5 | ( n: _: n != "default.nix" && ! lib.hasPrefix "." n ) 6 | (builtins.readDir ./.); 7 | 8 | in { 9 | imports = map (p: ./. + "/${p}") ( builtins.attrNames all ); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /modules/apps/docker/default.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | let 4 | 5 | inherit (builtins) toJSON; 6 | 7 | inherit (lib) 8 | filterAttrs foldl mapAttrsToList mkOption optional 9 | ; 10 | 11 | inherit (lib.types) attrsOf submodule; 12 | 13 | explicit = filterAttrs (n: v: n != "_module" && v != null); 14 | 15 | instances = explicit config.nixsap.apps.docker; 16 | 17 | groups = mapAttrsToList (_: i: i.daemon.group) instances; 18 | clis = mapAttrsToList (_: i: i.docker-cli) instances; 19 | 20 | mkService = name: opts: 21 | let 22 | config-file = pkgs.runCommand "dockerd-${name}.json" {} '' 23 | cat <<'EOF' | ${pkgs.jq}/bin/jq . > $out 24 | ${toJSON (explicit (opts.daemon))} 25 | EOF 26 | ''; 27 | in { 28 | "docker-${name}" = { 29 | description = "Docker daemon (${name})"; 30 | wantedBy = [ "multi-user.target" ]; 31 | after = [ "local-fs.target" ]; 32 | path = [ pkgs.kmod ] ++ (optional (opts.daemon.storage-driver == "zfs") pkgs.zfs); 33 | preStart = '' 34 | mkdir -p -- '${opts.daemon.data-root}' 35 | rm -rf -- '${opts.daemon.exec-root}' 36 | mkdir -p -- '${opts.daemon.exec-root}' 37 | 38 | chown -c -- 'root:root' '${opts.daemon.data-root}' 39 | chmod -c -- u=rwX,g=rX,o= '${opts.daemon.data-root}' 40 | ''; 41 | serviceConfig = { 42 | ExecStart = "${opts.package}/bin/dockerd --config-file ${config-file}"; 43 | ExecReload = "${pkgs.procps}/bin/kill -s HUP $MAINPID"; 44 | }; 45 | }; 46 | }; 47 | 48 | in { 49 | 50 | options.nixsap.apps.docker = mkOption { 51 | description = "Instances of Docker"; 52 | type = attrsOf (submodule (import ./instance.nix pkgs)); 53 | default = {}; 54 | }; 55 | 56 | config = { 57 | systemd.services = foldl (a: b: a//b) {} (mapAttrsToList mkService instances); 58 | nixsap.system.groups = groups; 59 | environment.systemPackages = clis; 60 | }; 61 | 62 | } 63 | 64 | -------------------------------------------------------------------------------- /modules/apps/docker/instance.nix: -------------------------------------------------------------------------------- 1 | pkgs: 2 | 3 | { lib, name, config, ... }: 4 | 5 | let 6 | 7 | inherit (lib) 8 | mkOption 9 | ; 10 | 11 | inherit (lib.types) 12 | bool enum int listOf nullOr package path str 13 | ; 14 | 15 | default = d: t: mkOption { type = t; default = d; }; 16 | optional = t: mkOption { type = nullOr t; default = null; }; 17 | readonly = d: t: mkOption { type = nullOr t; default = d; readOnly = true; }; 18 | 19 | socket = "unix://${config.daemon.exec-root}/dockerd.sock"; 20 | 21 | in { 22 | options = { 23 | package = mkOption { 24 | description = "Docker package"; 25 | default = pkgs.docker; 26 | type = package; 27 | }; 28 | 29 | docker-cli = mkOption { 30 | description = "Convenient wrapper of docker command line uitlity for this Docker instance"; 31 | type = package; 32 | readOnly = true; 33 | default = pkgs.runCommand "docker-${name}" {} '' 34 | mkdir -p $out/bin 35 | mkdir -p $out/share/bash-completion/completions 36 | 37 | cat << 'ETC' > "$out/share/bash-completion/completions/docker-${name}" 38 | . ${config.package}/share/bash-completion/completions/docker 39 | complete -r docker 40 | complete -F _docker 'docker-${name}' 41 | ETC 42 | 43 | cat << 'BIN' > "$out/bin/docker-${name}" 44 | exec ${config.package}/bin/docker --host '${socket}' "$@" 45 | BIN 46 | 47 | chmod +x "$out/bin/docker-${name}" 48 | ''; 49 | }; 50 | 51 | daemon = { 52 | debug = optional bool; 53 | add-runtime = optional (listOf str); 54 | allow-nondistributable-artifacts = optional (listOf str); 55 | api-cors-header = optional str; 56 | authorization-plugin = optional (listOf str); 57 | bip = optional str; 58 | bridge = optional str; 59 | cgroup-parent = optional str; 60 | containerd = optional str; 61 | cpu-rt-period = optional int; 62 | cpu-rt-runtime = optional int; 63 | data-root = default "/docker/${name}" path; 64 | default-gateway = optional str; 65 | default-gateway-v6 = optional str; 66 | default-runtime = optional str; 67 | # TBD: default-ulimit = optional attributes 68 | dns = optional (listOf str); 69 | dns-opt = optional (listOf str); 70 | dns-search = optional (listOf str); 71 | exec-root = readonly "${config.daemon.data-root}/run" path; 72 | experimental = optional bool; 73 | fixed-cidr = optional str; 74 | fixed-cidr-v6 = optional str; 75 | group = default "docker-${name}" str; 76 | hosts = readonly [socket] (listOf str); 77 | icc = optional bool; 78 | init = optional bool; 79 | init-path = optional path; 80 | insecure-registry = optional (listOf str); 81 | ip = optional str; 82 | ip-forward = optional bool; 83 | ip-masq = optional bool; 84 | iptables = optional bool; 85 | ipv6 = optional bool; 86 | live-restore = optional bool; 87 | log-driver = readonly "journald" str; 88 | log-level = optional (enum ["debug" "info" "warn" "error" "fatal"]); 89 | max-concurrent-downloads = optional int; 90 | max-concurrent-uploads = optional int; 91 | metrics-addr = optional str; 92 | mtu = optional int; 93 | no-new-privileges = optional bool; 94 | oom-score-adjust = optional int; 95 | pidfile = readonly "${config.daemon.exec-root}/dockerd.pid" path; 96 | raw-logs = optional bool; 97 | registry-mirror = optional (listOf str); 98 | seccomp-profile = optional path; 99 | selinux-enabled = optional bool; 100 | shutdown-timeout = optional int; 101 | storage-driver = optional (enum ["aufs" "devicemapper" "btrfs" "zfs" "overlay" "overlay2"]); 102 | storage-opt = optional (listOf str); 103 | swarm-default-advertise-addr = optional str; 104 | userland-proxy = optional bool; 105 | userland-proxy-path = optional path; 106 | userns-remap = optional str; 107 | }; 108 | }; 109 | } 110 | -------------------------------------------------------------------------------- /modules/apps/gnupg/default.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | let 4 | 5 | inherit (lib) 6 | concatMapStringsSep concatStrings filterAttrs foldAttrs mapAttrs' 7 | mapAttrsToList mkOption optionalString ; 8 | 9 | inherit (lib.types) 10 | attrsOf submodule ; 11 | 12 | explicit = filterAttrs (n: v: n != "_module" && v != null); 13 | instances = explicit config.nixsap.apps.gnupg; 14 | 15 | keyrings = 16 | let 17 | ik = mapAttrsToList (_: i: { 18 | "${i.user}" = i.secretKeys ++ mapAttrsToList (_: f: f) i.passphrase; 19 | }) instances; 20 | in foldAttrs (l: r: l ++ r) [] ik; 21 | 22 | 23 | mkService = name: cfg: 24 | let 25 | 26 | pubring = pkgs.runCommand "gnupg-${name}-pubring.kbx" {} '' 27 | ${cfg.package}/bin/gpg2 \ 28 | --homedir . \ 29 | --import \ 30 | ${concatMapStringsSep " " (k: "'${k}'") cfg.publicKeys} 31 | cp pubring.kbx $out 32 | ''; 33 | 34 | start = pkgs.writeBashScriptBin "gnupg-${name}" '' 35 | set -euo pipefail 36 | umask 0077 37 | 38 | cat <<'CONF' > '${cfg.home}/gpg.conf' 39 | batch 40 | no-tty 41 | trust-model always 42 | yes 43 | CONF 44 | 45 | # XXX forking. 46 | # XXX is 30 years enough? 47 | ${cfg.package}/bin/gpg-agent \ 48 | --homedir '${cfg.home}' \ 49 | --allow-preset-passphrase \ 50 | --batch \ 51 | --max-cache-ttl 999999999 \ 52 | --quiet \ 53 | --daemon 54 | 55 | ${optionalString (cfg.publicKeys != []) '' 56 | ln -sf '${pubring}' '${cfg.home}/pubring.kbx' 57 | ''} 58 | 59 | export GNUPGHOME='${cfg.home}' 60 | 61 | ${optionalString (cfg.secretKeys != []) '' 62 | ${cfg.package}/bin/gpg2 --import \ 63 | ${concatMapStringsSep " " (k: "'${k}'") cfg.secretKeys} 64 | ''} 65 | 66 | 67 | ${concatStrings (mapAttrsToList (cacheid: f: '' 68 | head -n 1 '${f}' \ 69 | | ${cfg.package}/libexec/gpg-preset-passphrase \ 70 | --verbose --preset '${cacheid}' 71 | '') cfg.passphrase) 72 | } 73 | 74 | 75 | ''; 76 | 77 | in { 78 | name = "gnupg-${name}"; 79 | value = { 80 | description = "gnupg (${name})"; 81 | wantedBy = [ "multi-user.target" ]; 82 | after = [ "keys.target" "local-fs.target" ]; 83 | preStart = '' 84 | mkdir -p -- '${cfg.home}' 85 | rm -rf -- '${cfg.home}/'* 86 | chmod u=rwX,g=,o= -- '${cfg.home}' 87 | chown '${cfg.user}.${cfg.user}' -- '${cfg.home}' 88 | ''; 89 | 90 | serviceConfig = { 91 | ExecStart = "${start}/bin/gnupg-${name}"; 92 | PermissionsStartOnly = true; 93 | Restart = "always"; 94 | Type = "forking"; 95 | User = cfg.user; 96 | }; 97 | }; 98 | }; 99 | 100 | in { 101 | 102 | options = { 103 | nixsap.apps.gnupg = mkOption { 104 | description = "GnuPG instances"; 105 | default = {}; 106 | type = attrsOf (submodule (import ./instance.nix pkgs)); 107 | }; 108 | }; 109 | 110 | config = { 111 | nixsap.deployment.keyrings = keyrings; 112 | systemd.services = mapAttrs' mkService instances; 113 | }; 114 | 115 | } 116 | 117 | -------------------------------------------------------------------------------- /modules/apps/gnupg/instance.nix: -------------------------------------------------------------------------------- 1 | pkgs: 2 | { lib, name, ... }: 3 | 4 | let 5 | 6 | inherit (lib) 7 | mkOption ; 8 | 9 | inherit (lib.types) 10 | attrsOf listOf package path str ; 11 | 12 | in { 13 | options = { 14 | 15 | user = mkOption { 16 | description = '' 17 | User to run as ang keyring owner. This option is required. 18 | Note that this user is not created automatically. 19 | ''; 20 | type = str; 21 | }; 22 | 23 | home = mkOption { 24 | description = '' 25 | GnuPG home directory where keyrings and gpg-agent socket 26 | will be located. 27 | ''; 28 | type = path; 29 | default = "/gnupg/${name}"; 30 | }; 31 | 32 | package = mkOption { 33 | description = "GnuPG2 package"; 34 | type = package; 35 | default = pkgs.gnupg21; 36 | }; 37 | 38 | publicKeys = mkOption { 39 | description = "Public GPG keys"; 40 | type = listOf path; 41 | default = []; 42 | }; 43 | 44 | secretKeys = mkOption { 45 | description = "Secret GPG keys"; 46 | type = listOf path; 47 | default = []; 48 | }; 49 | 50 | passphrase = mkOption { 51 | description = '' 52 | Secret files with pass-phrase to unlock secret keys. Keys are 53 | identified by cacheid, which is either a 40 character keygrip of 54 | hexadecimal characters identifying the key or an arbitrary string 55 | identifying a passphrase. Refer to the `gpg-preset-passphrase` 56 | documentation, because it is what stays behind this mechanism. 57 | Generally in unattended environments you need to use keygrip. 58 | ''; 59 | type = attrsOf path; 60 | default = {}; 61 | example = { 62 | "ABCD...321" = "/run/keys/foo"; 63 | "myapp:mykey" = "/run/keys/bar"; 64 | }; 65 | }; 66 | }; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /modules/apps/jenkins/instance.nix: -------------------------------------------------------------------------------- 1 | pkgs: 2 | { lib, name, config, ... }: 3 | 4 | let 5 | 6 | inherit (builtins) all attrNames; 7 | 8 | inherit (lib) 9 | concatStrings filterAttrs hasSuffix mapAttrsToList mkOption ; 10 | 11 | inherit (lib.types) 12 | addCheck attrsOf bool either enum int listOf nullOr package path str 13 | submodule 14 | ; 15 | 16 | default = d: t: mkOption { type = t; default = d; }; 17 | optional = t: mkOption { type = nullOr t; default = null; }; 18 | readonly = d: t: mkOption { type = nullOr t; default = d; readOnly = true; }; 19 | 20 | in { 21 | options = { 22 | 23 | jre = { 24 | package = mkOption { 25 | description = "Java runtime package"; 26 | default = pkgs.jre8; 27 | type = package; 28 | }; 29 | 30 | properties = { 31 | hudson.model.DirectoryBrowserSupport.CSP = optional str; 32 | java.io.tmpdir = readonly "${config.home}/tmp" path; 33 | java.util.logging.config.file = optional path; 34 | }; 35 | }; 36 | 37 | war = mkOption { 38 | description = "Jenkins web application archive (WAR)"; 39 | default = pkgs.jenkins; 40 | type = path; 41 | }; 42 | 43 | user = mkOption { 44 | description = "User to run as"; 45 | default = "jenkins-${name}"; 46 | readOnly = true; 47 | type = str; 48 | }; 49 | 50 | home = mkOption { 51 | description = "Jenkins data directory"; 52 | type = path; 53 | default = "/jenkins/${name}"; 54 | }; 55 | 56 | master-access-control = mkOption { 57 | description = '' 58 | Enable Agent -> Master Access Control. 59 | See https://wiki.jenkins.io/display/JENKINS/Slave+To+Master+Access+Control 60 | ''; 61 | type = bool; 62 | default = true; 63 | }; 64 | 65 | nodes = mkOption { 66 | description = '' 67 | Nodes. Each value is either inline XML text or an XML file. 68 | Any existing nodes, not mentioned here, are physically removed. 69 | ''; 70 | type = attrsOf (either str path); 71 | default = {}; 72 | }; 73 | 74 | jobs = mkOption { 75 | description = '' 76 | Jenkins jobs. Each value is either inline XML text or an XML file. 77 | Any existing jobs, not mentioned here, are physically removed. 78 | ''; 79 | type = attrsOf (either str path); 80 | default = {}; 81 | }; 82 | 83 | config = mkOption { 84 | description = '' 85 | Jenkins XML configuration files. Either inline text or file. Any 86 | existing XML files, not mentioned here, are physically removed. You 87 | might want to add `config.xml` at least. You can use XInclude 88 | facility to include sensitive pieces of configuration like passwords 89 | or private keys. Those grains will be processed (expanded) to 90 | create proper configuration files. Also they will be automatically 91 | picked up and deployed (requires read-write mode of evaluation). 92 | E. g. if you write '', 93 | that file will be deployed as a secret key, and when Jenkins starts, 94 | that piece will be replaced by the file contents. All configuration 95 | files reside in Jenkins private directory so secrets remain secret. 96 | ''; 97 | type = addCheck (attrsOf (either str path)) (aa: all (hasSuffix ".xml") (attrNames aa)); 98 | default = {}; 99 | }; 100 | 101 | path = mkOption { 102 | description = '' 103 | Additional packages available to Jenkins in PATH. You also may opt in specifying 104 | paths to executables in various config files. 105 | ''; 106 | type = listOf package; 107 | default = []; 108 | example = [ pkgs.gitMinimal ]; 109 | }; 110 | 111 | options = { 112 | controlPort = optional int; 113 | debug = optional (enum [1 2 3 4 5 6 7 8 9]); 114 | httpKeepAliveTimeout = optional int; 115 | httpListenAddress = default "127.0.0.1" str; 116 | httpPort = default 8080 int; 117 | prefix = optional str; 118 | sessionTimeout = optional int; 119 | }; 120 | 121 | }; 122 | } 123 | 124 | -------------------------------------------------------------------------------- /modules/apps/juandelacosa.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | let 4 | inherit (lib) types mkOption mkEnableOption mkIf hasPrefix 5 | concatStrings optionalString; 6 | inherit (types) str path int nullOr; 7 | 8 | cfg = config.nixsap.apps.juandelacosa; 9 | 10 | ExecStart = concatStrings [ 11 | "${pkgs.juandelacosa}/bin/juandelacosa" 12 | (optionalString (cfg.myFile != null) " -f '${cfg.myFile}'") 13 | (optionalString (cfg.myGroup != null) " -g ${cfg.myGroup}") 14 | (if (cfg.port != null) 15 | then " -p ${toString cfg.port}" 16 | else " -s '${cfg.socket}'") 17 | ]; 18 | 19 | in { 20 | options.nixsap.apps.juandelacosa = { 21 | enable = mkEnableOption "Juan de la Cosa"; 22 | user = mkOption { 23 | description = "User to run as"; 24 | default = "juandelacosa"; 25 | type = str; 26 | }; 27 | port = mkOption { 28 | description = "TCP port to listen on"; 29 | default = null; 30 | type = nullOr int; 31 | }; 32 | socket = mkOption { 33 | description = "UNIX socket to listen on. Ignored when TCP port is set"; 34 | default = "/tmp/juandelacosa.sock"; 35 | type = path; 36 | }; 37 | myFile = mkOption { 38 | description = "MySQL client configuration file"; 39 | default = null; 40 | type = nullOr path; 41 | }; 42 | myGroup = mkOption { 43 | description = "Options group in the MySQL client configuration file"; 44 | default = null; 45 | type = nullOr str; 46 | }; 47 | }; 48 | 49 | config = mkIf cfg.enable { 50 | nixsap.system.users.daemons = [ cfg.user ]; 51 | nixsap.deployment.keyrings.${cfg.user} = [ cfg.myFile ]; 52 | systemd.services.juandelacosa = { 53 | description = "captain of the MariaDB"; 54 | wantedBy = [ "multi-user.target" ]; 55 | wants = [ "keys.target" ]; 56 | after = [ "keys.target" "network.target" "local-fs.target" ]; 57 | serviceConfig = { 58 | inherit ExecStart; 59 | User = cfg.user; 60 | Restart = "on-failure"; 61 | }; 62 | }; 63 | }; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /modules/apps/logrotate.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | let 4 | 5 | inherit (builtins) 6 | elem isBool isString ; 7 | 8 | inherit (lib) 9 | concatMapStringsSep concatStringsSep filter filterAttrs 10 | mapAttrsToList mkIf mkOption optionalString ; 11 | 12 | inherit (lib.types) 13 | attrsOf bool either int listOf nullOr path str submodule ; 14 | 15 | cfg = config.nixsap.apps.logrotate; 16 | 17 | concatNonEmpty = sep: list: concatStringsSep sep (filter (s: s != "") list); 18 | explicit = filterAttrs (n: v: n != "_module" && v != null); 19 | mandatory = t: mkOption { type = t; }; 20 | optional = t: mkOption { type = nullOr t; default = null; }; 21 | 22 | mkConf = name: opts: 23 | let 24 | files = concatMapStringsSep " " (f: ''"${f}"'') opts.files; 25 | show = k: v: 26 | if elem k ["postrotate" "preremove" "prerotate"] 27 | then " ${k}\n ${v}\n endscript" 28 | else if isBool v then optionalString v " ${k}" 29 | else if isString v then " ${k} ${v}" 30 | else " ${k} ${toString v}"; 31 | 32 | in pkgs.writeText "logrotate-${name}.conf" '' 33 | ${files} { 34 | ${concatNonEmpty "\n" (mapAttrsToList show (explicit opts.directives))} 35 | } 36 | ''; 37 | 38 | configFile = pkgs.writeText "logrotate.conf" '' 39 | compress 40 | compresscmd ${pkgs.gzip}/bin/gzip 41 | compressext .gz 42 | compressoptions -6 43 | rotate 4 44 | uncompresscmd ${pkgs.gzip}/bin/gunzip 45 | 46 | ${concatMapStringsSep "\n" (f: "include ${f}") (mapAttrsToList mkConf (explicit cfg.conf))} 47 | ''; 48 | 49 | entry = { 50 | options = { 51 | files = mandatory (listOf path); 52 | directives = { 53 | compress = optional bool; 54 | compresscmd = optional path; 55 | compressext = optional str; 56 | compressoptions = optional str; 57 | copy = optional bool; 58 | copytruncate = optional bool; 59 | create = optional (either bool str); 60 | daily = optional bool; 61 | dateext = optional bool; 62 | dateformat = optional str; 63 | dateyesterday = optional bool; 64 | delaycompress = optional bool; 65 | extension = optional str; 66 | firstaction = optional path; 67 | hourly = optional bool; 68 | ifempty = optional bool; 69 | lastaction = optional path; 70 | mail = optional str; 71 | mailfirst = optional bool; 72 | maillast = optional bool; 73 | maxage = optional int; 74 | maxsize = optional int; 75 | minsize = optional int; 76 | missingok = optional bool; 77 | monthly = optional bool; 78 | nocompress = optional bool; 79 | nocopy = optional bool; 80 | nocopytruncate = optional bool; 81 | nocreate = optional bool; 82 | nodateext = optional bool; 83 | nodelaycompress = optional bool; 84 | nomail = optional bool; 85 | nomissingok = optional bool; 86 | nosharedscripts = optional bool; 87 | notifempty = optional bool; 88 | postrotate = optional path; 89 | preremove = optional path; 90 | prerotate = optional path; 91 | rotate = optional int; 92 | sharedscripts = optional bool; 93 | size = optional int; 94 | su = optional str; 95 | uncompresscmd = optional path; 96 | weekly = optional bool; 97 | yearly = optional bool; 98 | }; 99 | }; 100 | }; 101 | 102 | exec = pkgs.writeBashScriptBin "logrotate" '' 103 | exec ${pkgs.logrotate}/bin/logrotate \ 104 | -s '${cfg.stateDir}/status' \ 105 | ${optionalString cfg.verbose " -v"} \ 106 | ${optionalString (cfg.mail != null) " -m '${cfg.mail}'"} \ 107 | ${configFile} 108 | ''; 109 | 110 | in { 111 | options.nixsap.apps.logrotate = { 112 | 113 | stateDir = mkOption { 114 | description = "Directory for logrotate state file"; 115 | type = path; 116 | default = "/logrotate"; 117 | }; 118 | 119 | conf = mkOption { 120 | description = "Logrotate configuration"; 121 | type = attrsOf (submodule entry); 122 | default = {}; 123 | }; 124 | 125 | mail = mkOption { 126 | description = '' 127 | Tells logrotate which command to use when mailing logs. This command 128 | should accept two arguments: 1) the subject of the message, and 2) 129 | the recipient. 130 | ''; 131 | type = nullOr path; 132 | default = null; 133 | }; 134 | 135 | verbose = mkOption { 136 | description = "Turns on verbose mode."; 137 | type = bool; 138 | default = true; 139 | }; 140 | 141 | startAt = mkOption { 142 | description = "Time to start in systemd format"; 143 | type = str; 144 | default = "hourly"; 145 | }; 146 | }; 147 | 148 | config = mkIf ({} != explicit cfg.conf) { 149 | systemd.services.logrotate = { 150 | description = "rotates, compresses, and mails system logs"; 151 | inherit (cfg) startAt; 152 | preStart = '' 153 | mkdir -p '${cfg.stateDir}' 154 | chown -Rc root:root '${cfg.stateDir}' 155 | chmod -Rc u=rwX,g=rX,o= '${cfg.stateDir}' 156 | ''; 157 | serviceConfig = { 158 | ExecStart = "${exec}/bin/logrotate"; 159 | }; 160 | }; 161 | }; 162 | } 163 | 164 | -------------------------------------------------------------------------------- /modules/apps/mariadb/procedures.sql: -------------------------------------------------------------------------------- 1 | -- These procedures belong to the mysql DB, e. g. 2 | -- CALL mysql.resetSlave('foo'); 3 | -- Keep it simple: each procedure should be self-contained. 4 | 5 | DELIMITER $$ 6 | 7 | DROP PROCEDURE IF EXISTS stopSlave $$ 8 | CREATE PROCEDURE stopSlave (IN ch VARCHAR(64)) 9 | COMMENT 'Stops slave channel (both I/O and SQL threads)' 10 | BEGIN 11 | -- Ignore ERROR 1617 (HY000): There is no master connection 'foo' 12 | DECLARE EXIT HANDLER FOR 1617 13 | BEGIN 14 | SELECT 'No such master connection' 15 | AS warning; 16 | END; 17 | 18 | SET default_master_connection = ch; 19 | STOP SLAVE; 20 | END $$ 21 | 22 | DROP PROCEDURE IF EXISTS startSlave $$ 23 | CREATE PROCEDURE startSlave (IN ch VARCHAR(64)) 24 | COMMENT 'Starts slave channel (both I/O and SQL threads)' 25 | BEGIN 26 | DECLARE EXIT HANDLER FOR 1617 27 | BEGIN 28 | SELECT 'No such master connection' 29 | AS warning; 30 | END; 31 | 32 | SET default_master_connection = ch; 33 | START SLAVE; 34 | END $$ 35 | 36 | DROP PROCEDURE IF EXISTS kickSlave $$ 37 | CREATE PROCEDURE kickSlave (IN ch VARCHAR(64)) 38 | COMMENT 'Skips the next event from the master' 39 | BEGIN 40 | DECLARE EXIT HANDLER FOR 1617 41 | BEGIN 42 | SELECT 'No such master connection' 43 | AS warning; 44 | END; 45 | 46 | SET default_master_connection = ch; 47 | STOP SLAVE; 48 | SET GLOBAL sql_slave_skip_counter = 1; 49 | START SLAVE; 50 | END $$ 51 | 52 | DROP PROCEDURE IF EXISTS pauseSlave $$ 53 | CREATE PROCEDURE pauseSlave (IN ch VARCHAR(64)) 54 | COMMENT 'Stops SQL thread of the slave channel' 55 | BEGIN 56 | DECLARE EXIT HANDLER FOR 1617 57 | BEGIN 58 | SELECT 'No such master connection' 59 | AS warning; 60 | END; 61 | 62 | SET default_master_connection = ch; 63 | STOP SLAVE SQL_THREAD; 64 | END $$ 65 | 66 | DROP PROCEDURE IF EXISTS resetSlave $$ 67 | CREATE PROCEDURE resetSlave (IN ch VARCHAR(64)) 68 | COMMENT 'Stops and deletes slave channel' 69 | BEGIN 70 | DECLARE EXIT HANDLER FOR 1617 71 | BEGIN 72 | SELECT 'No such master connection' 73 | AS warning; 74 | END; 75 | 76 | SET default_master_connection = ch; 77 | STOP SLAVE; 78 | RESET SLAVE ALL; 79 | END $$ 80 | 81 | DROP PROCEDURE IF EXISTS stopAllSlaves $$ 82 | CREATE PROCEDURE stopAllSlaves () 83 | COMMENT 'Stops all slaves' 84 | BEGIN 85 | STOP ALL SLAVES; 86 | END $$ 87 | 88 | DROP PROCEDURE IF EXISTS pauseAllSlaves $$ 89 | CREATE PROCEDURE pauseAllSlaves () 90 | COMMENT 'Stops SQL thread of all slaves' 91 | BEGIN 92 | STOP ALL SLAVES SQL_THREAD; 93 | END $$ 94 | 95 | DROP PROCEDURE IF EXISTS startAllSlaves $$ 96 | CREATE PROCEDURE startAllSlaves () 97 | COMMENT 'Starts all slaves' 98 | BEGIN 99 | START ALL SLAVES; 100 | END $$ 101 | 102 | DROP PROCEDURE IF EXISTS enableGeneralLog $$ 103 | CREATE PROCEDURE enableGeneralLog () 104 | BEGIN 105 | SET GLOBAL general_log = ON; 106 | END $$ 107 | 108 | DROP PROCEDURE IF EXISTS disableGeneralLog $$ 109 | CREATE PROCEDURE disableGeneralLog () 110 | BEGIN 111 | SET GLOBAL general_log = OFF; 112 | END $$ 113 | 114 | DROP PROCEDURE IF EXISTS truncateGeneralLog $$ 115 | CREATE PROCEDURE truncateGeneralLog () 116 | BEGIN 117 | TRUNCATE mysql.general_log; 118 | END $$ 119 | 120 | DROP PROCEDURE IF EXISTS truncateSlowLog $$ 121 | CREATE PROCEDURE truncateSlowLog () 122 | BEGIN 123 | TRUNCATE mysql.slow_log; 124 | END $$ 125 | 126 | DROP PROCEDURE IF EXISTS showEvents $$ 127 | CREATE PROCEDURE showEvents () 128 | COMMENT 'Shows all events for the mysql schema' 129 | BEGIN 130 | SHOW EVENTS IN mysql; 131 | END $$ 132 | 133 | DELIMITER ; 134 | 135 | -------------------------------------------------------------------------------- /modules/apps/mariadb/replicate.nix: -------------------------------------------------------------------------------- 1 | { config, lib, ... }: 2 | with lib; 3 | with lib.types; 4 | let 5 | mandatory = type: mkOption { inherit type; }; 6 | optional = type: mkOption { type = nullOr type; default = null; }; 7 | 8 | common = foldl (a: b: a//b) {} [ 9 | { host = mandatory str; } 10 | { password-file = optional path; } 11 | { port = optional int; } 12 | { ssl = optional bool; } 13 | { ssl-ca = optional path; } 14 | { ssl-cert = optional path; } 15 | { ssl-key = optional path; } 16 | { ssl-verify-server-cert = optional bool; } 17 | { user = mandatory str; } 18 | ]; 19 | 20 | master.options = foldl (a: b: a//b) {} [ 21 | { connect-retry = optional int; } 22 | { heartbeat-period = optional int; } 23 | common 24 | ]; 25 | 26 | mysqldump.options = foldl (a: b: a//b) {} [ 27 | { compress = optional bool; } 28 | { lock-tables = optional bool; } 29 | { path = optional path; } 30 | { single-transaction = optional bool; } 31 | common 32 | ]; 33 | 34 | in { 35 | options = { 36 | databases = mkOption { 37 | type = listOf str; 38 | description = '' 39 | List of databases to dump and replicate. This will be written as 40 | `foo.replicate_wild_do_table = db.%`. 41 | ''; 42 | example = [ "oms_live_sg" "bob_live_sg" ]; 43 | }; 44 | 45 | ignore-tables = mkOption { 46 | type = listOf str; 47 | description = '' 48 | List of tables to ignore. This will be written as 49 | `foo.replicate_ignore_table = db.table`. If database prefix is 50 | omitted, expressions for all databases will be generated. 51 | ''; 52 | example = [ "schema_updates" "bob_live_sg.locks" ]; 53 | default = []; 54 | }; 55 | 56 | ignore-databases = mkOption { 57 | type = listOf str; 58 | description = '' 59 | List of databases to ignore. You do not need this in most cases. 60 | See http://dev.mysql.com/doc/refman/en/replication-rules.html. 61 | This will be written as `foo.replicate_ignore_db = mysql`. This is 62 | useful when you want procedures in other databases, like `mysql`, 63 | not to be replicated. 64 | ''; 65 | default = [ "mysql" "test" "tmp" ]; 66 | }; 67 | 68 | master = mkOption { type = submodule (master); }; 69 | mysqldump = mkOption { type = submodule (mysqldump); }; 70 | }; 71 | 72 | config = { 73 | mysqldump = { 74 | compress = mkDefault true; 75 | host = mkDefault config.master.host; 76 | password-file = mkDefault config.master.password-file; 77 | port = mkDefault config.master.port; 78 | single-transaction = mkDefault true; 79 | ssl = mkDefault config.master.ssl; 80 | ssl-ca = mkDefault config.master.ssl-ca; 81 | ssl-cert = mkDefault config.master.ssl-cert; 82 | ssl-key = mkDefault config.master.ssl-key; 83 | user = mkDefault config.master.user; 84 | }; 85 | }; 86 | } 87 | 88 | -------------------------------------------------------------------------------- /modules/apps/mariadb/slave-watchdog.nix: -------------------------------------------------------------------------------- 1 | { cfg, changeMaster, importDump }: '' 2 | set -euo pipefail 3 | 4 | ch="$1" 5 | status=$(mktemp) 6 | trap 'rm -f "$status"' EXIT 7 | 8 | slave_status () { 9 | if ! ${cfg.package}/bin/mysql -e ';'; then 10 | echo unknown; return 11 | fi 12 | 13 | if ${cfg.package}/bin/mysql -e "SHOW SLAVE '$1' STATUS\\G" | sed 's,^ *,,' > "$status"; then 14 | if grep -oE '\bMaster_Server_Id:\s*[1-9][0-9]*' "$status" >&2; then 15 | io_errno=$(awk '/Last_IO_Errno:/ {print $2}' "$status") 16 | sql_errno=$(awk '/Last_SQL_Errno:/ {print $2}' "$status") 17 | case "$io_errno:$sql_errno" in 18 | 0:0) 19 | echo ok 20 | return 21 | ;; 22 | 0:*) 23 | awk '/Last_SQL_Error:/ {print $0}' "$status" >&2 24 | echo "sql_error:$sql_errno" 25 | return 26 | ;; 27 | *:*) 28 | awk '/Last_IO_Error:/ {print $0}' "$status" >&2 29 | echo "io_error:$io_errno" 30 | return 31 | ;; 32 | esac 33 | fi 34 | fi 35 | echo none 36 | } 37 | 38 | sql_errors=0 39 | none_count=0 40 | while true; do 41 | st=$(slave_status "$ch") 42 | 43 | case "$st" in 44 | ok|unknown) 45 | echo "status: $st" >&2 46 | exit 47 | ;; 48 | none) 49 | # XXX existing slave might not be initialized yet after mariadb restarts 50 | (( ++none_count )) 51 | echo "status: $st (count: $none_count)" >&2 52 | if [ "$none_count" -lt 10 ]; then 53 | sleep 1m 54 | continue 55 | fi 56 | ${cfg.package}/bin/mysql -v -N -e "CALL mysql.resetSlave('$ch')" >&2 57 | ${changeMaster} "$ch" | ${cfg.package}/bin/mysql 58 | if ${importDump} "$ch" | ${cfg.package}/bin/mysql; then 59 | ${cfg.package}/bin/mysql -v -N -e "CALL mysql.startSlave('$ch')" >&2 60 | exit 61 | else 62 | echo 'Import failed. Starting over' >&2 63 | ${cfg.package}/bin/mysql -v -N -e "CALL mysql.resetSlave('$ch')" >&2 64 | exit 1 65 | fi 66 | ;; 67 | io_error:*) 68 | echo "status: $st" >&2 69 | ${cfg.package}/bin/mysql -v -N -e "CALL mysql.stopSlave('$ch')" >&2 70 | ${changeMaster} "$ch" | ${cfg.package}/bin/mysql 71 | ${cfg.package}/bin/mysql -v -N -e "CALL mysql.startSlave('$ch')" >&2 72 | exit 1 73 | ;; 74 | sql_error:1205) # Lock wait timeout exceeded 75 | echo "status: $st" >&2 76 | ${cfg.package}/bin/mysql -v -N -e "CALL mysql.startSlave('$ch')" >&2 77 | exit 1 78 | ;; 79 | sql_error:*) 80 | (( ++sql_errors )) 81 | echo "status: $st (count: $sql_errors)" >&2 82 | if [ "$sql_errors" -le 1 ]; then 83 | ${cfg.package}/bin/mysql -v -N -e "CALL mysql.pauseSlave('$ch')" >&2 84 | sleep 1s 85 | ${cfg.package}/bin/mysql -v -N -e "CALL mysql.startSlave('$ch')" >&2 86 | elif [ "$sql_errors" -le 2 ]; then 87 | ${cfg.package}/bin/mysql -v -N -e "CALL mysql.stopSlave('$ch')" >&2 88 | # this *unlikely* *may* change replication option (ignore tables, etc.) 89 | ${changeMaster} "$ch" | ${cfg.package}/bin/mysql 90 | ${cfg.package}/bin/mysql -v -N -e "CALL mysql.startSlave('$ch')" >&2 91 | else 92 | echo '!!! Resetting slave !!!' >&2 93 | ${cfg.package}/bin/mysql -v -N -e "CALL mysql.resetSlave('$ch')" >&2 94 | exit 1 95 | fi 96 | sleep 2m 97 | ;; 98 | *) echo "BUG: $st" >&2; exit 255;; 99 | esac 100 | sleep 1s 101 | done 102 | '' 103 | 104 | -------------------------------------------------------------------------------- /modules/apps/memcached/default.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | let 4 | 5 | inherit (builtins) 6 | elem filter isBool isList ; 7 | 8 | inherit (lib) 9 | concatMapStringsSep concatStringsSep filterAttrs flatten 10 | foldAttrs mapAttrs' mapAttrsToList mkOption optionalString ; 11 | 12 | inherit (lib.types) 13 | attrsOf submodule ; 14 | 15 | concatMapAttrsSep = s: f: attrs: concatStringsSep s (mapAttrsToList f attrs); 16 | 17 | explicit = filterAttrs (n: v: n != "_module" && v != null); 18 | instances = explicit config.nixsap.apps.memcached; 19 | users = mapAttrsToList (_: i: i.user) instances; 20 | 21 | 22 | mkService = name: cfg: 23 | let 24 | 25 | show = n: v: 26 | if isList v then map (s: "-${n} '${toString s}'") v 27 | else if isBool v then (optionalString v "-${n}") 28 | else "-${n} '${toString v}'"; 29 | 30 | args = flatten (mapAttrsToList show (explicit cfg.args)); 31 | 32 | start = pkgs.writeBashScriptBin "memcached-${name}" '' 33 | set -euo pipefail 34 | umask 0027 35 | 36 | exec ${cfg.package}/bin/memcached \ 37 | ${concatStringsSep " \\\n" args} 38 | ''; 39 | 40 | in { 41 | name = "memcached-${name}"; 42 | value = { 43 | description = "memcached (${name})"; 44 | wantedBy = [ "multi-user.target" ]; 45 | after = [ "keys.target" "network.target" "local-fs.target" ]; 46 | serviceConfig = { 47 | ExecStart = "${start}/bin/memcached-${name}"; 48 | Restart = "always"; 49 | User = cfg.user; 50 | }; 51 | }; 52 | }; 53 | 54 | in { 55 | 56 | options.nixsap.apps.memcached = mkOption { 57 | description = "Memcached instances"; 58 | default = {}; 59 | type = attrsOf (submodule (import ./instance.nix pkgs)); 60 | }; 61 | 62 | config = { 63 | systemd.services = mapAttrs' mkService instances; 64 | nixsap.system.users.daemons = users; 65 | }; 66 | 67 | } 68 | 69 | -------------------------------------------------------------------------------- /modules/apps/memcached/instance.nix: -------------------------------------------------------------------------------- 1 | pkgs: 2 | { lib, name, ... }: 3 | 4 | let 5 | 6 | inherit (builtins) match ; 7 | 8 | inherit (lib) 9 | mkOption mkOptionType ; 10 | 11 | inherit (lib.types) 12 | bool enum int listOf nullOr package path str submodule ; 13 | 14 | default = v: type: mkOption { type = type; default = v; }; 15 | optional = type: mkOption { type = nullOr type; default = null; }; 16 | 17 | isFloat = x: match "^[0-9]+(\\.[0-9]+)?$" (toString x) != null; 18 | 19 | float = mkOptionType { 20 | name = "positive float"; 21 | check = isFloat; 22 | }; 23 | 24 | in { 25 | options = { 26 | 27 | user = mkOption { 28 | description = "User to run as"; 29 | type = str; 30 | default = "memcached-${name}"; 31 | }; 32 | 33 | package = mkOption { 34 | description = "Memcached package"; 35 | type = package; 36 | default = pkgs.memcached; 37 | }; 38 | 39 | args = mkOption { 40 | description = "Memcached command line arguments. Refer to memcached man page."; 41 | default = {}; 42 | type = submodule { 43 | options = { 44 | M = optional bool; 45 | R = optional int; 46 | B = optional (enum ["auto" "ascii" "binary"]); 47 | I = optional int; 48 | L = optional bool; 49 | l = default ["127.0.0.1"] (listOf str); 50 | b = optional int; 51 | c = optional int; 52 | f = optional float; 53 | p = default 11211 int; 54 | t = optional int; 55 | D = optional str; 56 | a = optional str; 57 | m = optional int; 58 | n = optional int; 59 | F = optional bool; 60 | U = default 11211 int; 61 | C = optional bool; 62 | k = optional bool; 63 | A = optional bool; 64 | S = optional bool; 65 | s = optional path; 66 | }; 67 | }; 68 | }; 69 | }; 70 | } 71 | 72 | -------------------------------------------------------------------------------- /modules/apps/mywatch.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | let 4 | inherit (lib) types mkOption mkEnableOption mkIf hasPrefix 5 | concatStrings optionalString; 6 | inherit (types) str path int nullOr; 7 | 8 | cfg = config.nixsap.apps.mywatch; 9 | 10 | ExecStart = concatStrings [ 11 | "${pkgs.mywatch}/bin/mywatch" 12 | (if (cfg.port != null) 13 | then " -p ${toString cfg.port}" 14 | else " -s '${cfg.socket}'") 15 | " '${cfg.myFile}'" 16 | ]; 17 | 18 | in { 19 | options.nixsap.apps.mywatch = { 20 | enable = mkEnableOption "MyWatch"; 21 | user = mkOption { 22 | description = "User to run as"; 23 | default = "mywatch"; 24 | type = str; 25 | }; 26 | port = mkOption { 27 | description = "TCP port to listen on (insecure)"; 28 | default = null; 29 | type = nullOr int; 30 | }; 31 | socket = mkOption { 32 | description = "UNIX socket to listen on. Ignored when TCP port is set"; 33 | default = "/tmp/mywatch.sock"; 34 | type = path; 35 | }; 36 | myFile = mkOption { 37 | description = "MySQL client configuration file"; 38 | type = path; 39 | }; 40 | }; 41 | 42 | config = mkIf cfg.enable { 43 | nixsap.system.users.daemons = [ cfg.user ]; 44 | nixsap.deployment.keyrings.${cfg.user} = [ cfg.myFile ]; 45 | systemd.services.mywatch = { 46 | description = "watch queries on multiple MySQL servers"; 47 | wantedBy = [ "multi-user.target" ]; 48 | wants = [ "keys.target" ]; 49 | after = [ "keys.target" "network.target" ]; 50 | serviceConfig = { 51 | inherit ExecStart; 52 | User = cfg.user; 53 | Restart = "on-failure"; 54 | }; 55 | }; 56 | }; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /modules/apps/nginx.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | let 4 | 5 | inherit (builtins) 6 | elem filter isBool ; 7 | 8 | inherit (lib) 9 | concatMapStrings concatStringsSep filterAttrs mapAttrsToList mkDefault 10 | mkEnableOption mkIf mkOption ; 11 | 12 | inherit (lib.types) 13 | attrsOf bool either enum int lines nullOr package path str submodule ; 14 | 15 | 16 | cfg = config.nixsap.apps.nginx; 17 | explicit = filterAttrs (n: v: n != "_module" && v != null); 18 | 19 | attrs = opts: submodule { options = opts; }; 20 | default = d: t: mkOption { type = t; default = d; }; 21 | optional = t: mkOption { type = nullOr t; default = null; }; 22 | 23 | show = v: if isBool v then (if v then "on" else "off") else toString v; 24 | 25 | format = indent: set: 26 | let mkEntry = k: v: "${indent}${k} ${show v};"; 27 | in concatStringsSep "\n" (mapAttrsToList mkEntry (explicit set)); 28 | 29 | mkServer = name: text: pkgs.writeText "nginx-${name}.conf" '' 30 | # ${name}: 31 | server { 32 | ${text} 33 | } 34 | ''; 35 | 36 | # Hardcode defaults that could be overriden in server context. 37 | # Add options for http-only directives. 38 | nginx-conf = pkgs.writeText "nginx.conf" '' 39 | daemon off; 40 | user ${cfg.user} ${cfg.user}; 41 | pid ${cfg.runDir}/nginx.pid; 42 | 43 | ${format "" (filterAttrs (n: _: ! elem n ["events" "http"]) cfg.conf)} 44 | 45 | events { 46 | ${format " " cfg.conf.events} 47 | } 48 | 49 | http { 50 | ${cfg.conf.http.context} 51 | 52 | ${concatMapStrings (s: "include ${s};\n") (mapAttrsToList mkServer cfg.conf.http.servers)} 53 | } 54 | ''; 55 | 56 | exec = "${cfg.package}/bin/nginx -c ${nginx-conf} -p ${cfg.stateDir}"; 57 | 58 | enabled = {} != explicit cfg.conf.http.servers; 59 | 60 | in { 61 | 62 | options.nixsap.apps.nginx = { 63 | package = mkOption { 64 | description = "Nginx package"; 65 | type = package; 66 | default = pkgs.nginx; 67 | }; 68 | user = mkOption { 69 | description = "User to run as"; 70 | type = str; 71 | default = "nginx"; 72 | }; 73 | stateDir = mkOption { 74 | description = "Directory holding all state for nginx to run"; 75 | type = path; 76 | default = "/nginx"; 77 | }; 78 | logDir = mkOption { 79 | description = '' 80 | Nginx directory for logs. This is read-only. Use it in configuration 81 | files of nginx itself or logrotate. 82 | ''; 83 | type = path; 84 | readOnly = true; 85 | default = "${cfg.stateDir}/logs"; 86 | }; 87 | runDir = mkOption { 88 | description = '' 89 | Directory for sockets and PID-file. 90 | UNIX-sockets created by nginx are world-writable. 91 | So if you want some privacy, put sockets in this directory. 92 | It is owned by nginx user and group, and has mode 0640. 93 | ''; 94 | type = path; 95 | readOnly = true; 96 | default = "/run/nginx"; 97 | }; 98 | 99 | conf = default {} (attrs { 100 | pcre_jit = optional bool; 101 | timer_resolution = optional int; 102 | worker_cpu_affinity = optional str; 103 | worker_priority = optional int; 104 | worker_processes = default "auto" (either int (enum ["auto"])); 105 | worker_rlimit_core = optional int; 106 | worker_rlimit_nofile = optional int; 107 | 108 | events = default {} (attrs { 109 | accept_mutex = optional bool; 110 | accept_mutex_delay = optional int; 111 | multi_accept = optional bool; 112 | worker_aio_requests = optional int; 113 | worker_connections = optional int; 114 | }); 115 | 116 | http = default {} (attrs { 117 | servers = default {} (attrsOf lines); 118 | context = mkOption { 119 | description = '' 120 | Default directives in the http context. You normally don't 121 | need to change it, because most of directives can be overriden 122 | in server or location contexts. This parameter has a reasonale 123 | default value which you should append in nixos modules, i. e. by 124 | adding geoip directives or maps. Use `lib.mkForce` to completely 125 | omit default directives. 126 | ''; 127 | type = lines; 128 | }; 129 | }); 130 | }); 131 | }; 132 | 133 | config = { 134 | nixsap.apps.nginx.conf.http.context = '' 135 | include ${cfg.package}/conf/mime.types; 136 | default_type application/octet-stream; 137 | 138 | # This is `combined` format with $remote_user replaced by $http_from. 139 | # $http_from is provided by Sproxy: https://hackage.haskell.org/package/sproxy2 140 | log_format sproxy '$remote_addr - $http_from [$time_local] ' 141 | '"$request" $status $body_bytes_sent ' 142 | '"$http_referer" "$http_user_agent"'; 143 | 144 | access_log off; 145 | error_log stderr info; 146 | 147 | gzip on; 148 | keepalive_timeout 65; 149 | sendfile on; 150 | ssl_prefer_server_ciphers on; 151 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 152 | tcp_nodelay on; 153 | tcp_nopush on; 154 | types_hash_max_size 2048; 155 | 156 | # https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/ 157 | fastcgi_param HTTP_PROXY ""; 158 | proxy_set_header Proxy ""; 159 | ''; 160 | 161 | nixsap.system.users.daemons = mkIf enabled [ cfg.user ]; 162 | 163 | nixsap.apps.logrotate.conf.nginx = mkIf enabled { 164 | files = [ "${cfg.logDir}/*.log" ]; 165 | directives = { 166 | su = "${cfg.user} ${cfg.user}"; 167 | delaycompress = mkDefault true; 168 | missingok = mkDefault true; 169 | notifempty = mkDefault true; 170 | rotate = mkDefault 14; 171 | sharedscripts = true; 172 | daily = mkDefault true; 173 | create = mkDefault "0640 ${cfg.user} ${cfg.user}"; 174 | postrotate = pkgs.writeBashScript "logrotate-nginx-postrotate" 175 | "systemctl kill -s SIGUSR1 --kill-who=main nginx.service"; 176 | }; 177 | }; 178 | 179 | systemd.services.nginx = mkIf enabled { 180 | description = "web/proxy server"; 181 | wants = [ "keys.target" ]; 182 | after = [ "keys.target" "local-fs.target" "network.target" ]; 183 | wantedBy = [ "multi-user.target" ]; 184 | preStart = '' 185 | rm -rf '${cfg.runDir}' 186 | mkdir -p '${cfg.stateDir}/logs' '${cfg.runDir}' 187 | chown -Rc '${cfg.user}:${cfg.user}' '${cfg.stateDir}' '${cfg.runDir}' 188 | chmod -Rc u=rwX,g=rX,o= '${cfg.stateDir}' '${cfg.runDir}' 189 | ''; 190 | serviceConfig = { 191 | ExecStart = exec; 192 | ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; 193 | RestartSec = "10s"; 194 | StartLimitInterval = "1min"; 195 | Restart = "always"; 196 | }; 197 | }; 198 | }; 199 | } 200 | 201 | -------------------------------------------------------------------------------- /modules/apps/nix-serve.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | let 4 | 5 | inherit (lib) 6 | mkEnableOption mkIf mkOption optionalString ; 7 | 8 | inherit (lib.types) 9 | int nullOr package path str ; 10 | 11 | cfg = config.nixsap.apps.nix-serve; 12 | 13 | start = 14 | let 15 | maybeTCP = optionalString (cfg.port != null) 16 | "--listen '${cfg.address}:${toString cfg.port}'"; 17 | in pkgs.writeBashScriptBin "nix-serve" '' 18 | umask 0117 # for socket mode 19 | 20 | export NIX_REMOTE="daemon" 21 | 22 | ${optionalString (cfg.secretKeyFile != null) '' 23 | export NIX_SECRET_KEY_FILE='${cfg.secretKeyFile}' 24 | ''} 25 | 26 | exec "${cfg.package}/bin/nix-serve" \ 27 | ${maybeTCP} \ 28 | --listen '${cfg.socket}' \ 29 | --workers ${toString cfg.workers} 30 | ''; 31 | 32 | in 33 | { 34 | options = { 35 | nixsap.apps.nix-serve = { 36 | enable = mkEnableOption "nix-serve, the standalone Nix binary cache server"; 37 | 38 | user = mkOption { 39 | description = "User and group to run as"; 40 | type = str; 41 | default = "nix-serve"; 42 | }; 43 | 44 | home = mkOption { 45 | description = "Home directory (currently for Unix socket only)"; 46 | type = path; 47 | default = "/nix-serve"; 48 | }; 49 | 50 | package = mkOption { 51 | description = "nix-serve package"; 52 | type = package; 53 | default = pkgs.nix-serve; 54 | }; 55 | 56 | workers = mkOption { 57 | type = int; 58 | default = 5; 59 | description = "Specifies the number of worker pool"; 60 | }; 61 | 62 | port = mkOption { 63 | type = nullOr int; 64 | default = null; 65 | description = '' 66 | Port number where nix-serve will listen on in addition to Unix 67 | socket. By default nix-serve listens on Unix socket only. 68 | ''; 69 | }; 70 | 71 | address = mkOption { 72 | type = str; 73 | default = "127.0.0.1"; 74 | description = '' 75 | IP address where nix-serve will bind its TCP listening socket. 76 | ''; 77 | }; 78 | 79 | socket = mkOption { 80 | description = '' 81 | Unix socket to listen on. 82 | ''; 83 | readOnly = true; 84 | type = path; 85 | default = "${cfg.home}/socket"; 86 | }; 87 | 88 | secretKeyFile = mkOption { 89 | type = nullOr path; 90 | default = null; 91 | description = '' 92 | The path to the file used for signing derivation data. 93 | ''; 94 | }; 95 | }; 96 | }; 97 | 98 | config = mkIf cfg.enable { 99 | nix.allowedUsers = [ cfg.user ]; 100 | 101 | nixsap.deployment.keyrings.${cfg.user} = [ cfg.secretKeyFile ]; 102 | nixsap.system.users.daemons = [ cfg.user ]; 103 | 104 | systemd.services.nix-serve = { 105 | description = "nix-serve binary cache server"; 106 | wantedBy = [ "multi-user.target" ]; 107 | wants = [ "keys.target" ]; 108 | after = [ "keys.target" "network.target" "local-fs.target" ]; 109 | 110 | preStart = '' 111 | mkdir -p -- '${cfg.home}' 112 | rm -rf -- '${cfg.socket}' 113 | chown -Rc '${cfg.user}:${cfg.user}' -- '${cfg.home}' 114 | chmod -Rc u=rwX,g=rX,o= -- '${cfg.home}' 115 | ''; 116 | 117 | serviceConfig = { 118 | ExecStart = "${start}/bin/nix-serve"; 119 | KillMode = "mixed"; 120 | PermissionsStartOnly = true; 121 | Restart = "always"; 122 | User = cfg.user; 123 | }; 124 | }; 125 | }; 126 | } 127 | -------------------------------------------------------------------------------- /modules/apps/openldap/instance.nix: -------------------------------------------------------------------------------- 1 | pkgs: 2 | { config, lib, name, ... }: 3 | 4 | let 5 | 6 | inherit (lib) 7 | mkOption mkOrder ; 8 | 9 | inherit (lib.types) 10 | either enum int lines listOf nullOr package path str ; 11 | 12 | optional = t: mkOption { type = nullOr t; default = null; }; 13 | default = d: t: mkOption { type = t; default = d; }; 14 | 15 | in { 16 | options = { 17 | 18 | user = mkOption { 19 | description = "User to run as"; 20 | type = str; 21 | default = "openldap-${name}"; 22 | }; 23 | 24 | package = mkOption { 25 | description = "OpenLDAP package"; 26 | type = package; 27 | default = pkgs.openldap; 28 | }; 29 | 30 | home = mkOption { 31 | description = '' 32 | OpenLDAP home directory, where all the databases are stored, 33 | including `cn=config`. 34 | ''; 35 | type = path; 36 | default = "/openldap/${name}"; 37 | }; 38 | 39 | debugLevel = mkOption { 40 | description = "What to log"; 41 | type = listOf (enum [ 42 | "acl" "any" "args" "ber" "config" "conns" "filter" "none" 43 | "packets" "parse" "pcache" "shell" "stats" "stats2" "sync" 44 | "trace" 45 | ]); 46 | default = [ "acl" "config" ]; 47 | }; 48 | 49 | urlList = mkOption { 50 | description = '' 51 | Passed as is for the -h option to slapd. Note that one more url 52 | ldapi:// will be passed anyway for internal maintenance. 53 | ''; 54 | type = str; 55 | default = "ldap://127.0.0.1"; 56 | example = "ldapi://%2Ftmp%2Fldapi ldaps:///"; 57 | }; 58 | 59 | "cn=config" = { 60 | olcConnMaxPending = optional int; 61 | olcConnMaxPendingAuth = optional int; 62 | olcIdleTimeout = optional int; 63 | olcReferral = default [] (listOf str); 64 | olcTLSCACertificateFile = optional path; 65 | olcTLSCACertificatePath = optional path; 66 | olcTLSCRLCheck = optional (enum ["none" "peer" "all"]); 67 | olcTLSCRLFile = optional path; 68 | olcTLSCertificateFile = optional path; 69 | olcTLSCertificateKeyFile = optional path; 70 | olcTLSCipherSuite = optional str; 71 | olcTLSDHParamFile = optional path; 72 | olcTLSRandFile = optional path; 73 | olcTLSVerifyClient = optional (enum ["never" "allow" "try"]); 74 | olcThreads = optional int; 75 | olcWriteTimeout = optional int; 76 | 77 | ldif = mkOption { 78 | description = '' 79 | OpenLDAP configuration in LDIF format. This is fed to the slapadd 80 | utility before slapd is started and completely replaces any existing 81 | slapd configuration (`cn=config`). You may include schema files 82 | here, add databases, load modules. Any `olcDbDirectory` mentioned 83 | here will be automatically created iff it is under home directory. 84 | To configure `cn=config` itself use dedicated options. 85 | ''; 86 | type = lines; 87 | example = '' 88 | dn: olcDatabase={1}mdb,cn=config 89 | objectClass: olcDatabaseConfig 90 | objectClass: olcMdbConfig 91 | olcAccess: {0}to attrs=userPassword 92 | by anonymous auth 93 | by * break 94 | olcAccess: {1}to dn.subtree="dc=example,dc=com" 95 | by dn="cn=admin,dc=example,dc=com" write 96 | by * break 97 | olcDatabase: {1}mdb 98 | olcDbCheckpoint: 512 30 99 | olcDbDirectory: $\{apps.openldap.foo.home\}/example.com 100 | olcDbIndex: cn eq 101 | olcDbMaxSize: 1073741824 102 | olcSuffix: dc=example,dc=com 103 | ''; 104 | }; 105 | }; 106 | 107 | apply = mkOption { 108 | description = '' 109 | LDIF files to apply. This data is idempotently applied by the 110 | `ldapply` tool. Useful for initial configuration. These files are 111 | processed in order, after slapd is started and ready. Important 112 | note: if you want to apply to a specific tree/object, make sure to 113 | append 'by * break' to any access rule targeting this tree/object. 114 | Otherwise internal maintenance script will not be able to operate. 115 | For example, 'olcAccess: to dn.subtree="dc=example,dc=com" by 116 | dn="cn=admin,dc=example,dc=com" write by * break'. This is because 117 | the default rule is 'by * none stop'. 118 | ''; 119 | type = listOf (either str path); 120 | default = []; 121 | example = [ "/foo/addusers.ldif" "/run/keys/set_passwords.ldif" ]; 122 | }; 123 | }; 124 | 125 | config = { 126 | "cn=config".ldif = mkOrder 0 '' 127 | include: file://${config.package}/etc/openldap/schema/core.ldif 128 | include: file://${config.package}/etc/openldap/schema/cosine.ldif 129 | include: file://${config.package}/etc/openldap/schema/inetorgperson.ldif 130 | ''; 131 | }; 132 | } 133 | 134 | -------------------------------------------------------------------------------- /modules/apps/postgresql/functions.pgsql: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION IF NOT EXISTS dblink; 2 | 3 | DROP FUNCTION IF EXISTS create_role_if_not_exists(TEXT); 4 | CREATE FUNCTION create_role_if_not_exists(IN name TEXT) 5 | RETURNS VOID AS $$ 6 | BEGIN 7 | IF NOT EXISTS (SELECT 1 FROM pg_catalog.pg_roles WHERE rolname = name) THEN 8 | EXECUTE format('CREATE ROLE %I', name); 9 | END IF; 10 | END; 11 | $$ LANGUAGE PLPGSQL; 12 | 13 | DROP FUNCTION IF EXISTS create_db_if_not_exists(TEXT); 14 | CREATE FUNCTION create_db_if_not_exists(IN dbname TEXT) 15 | RETURNS VOID AS $$ 16 | DECLARE port INT; 17 | DECLARE junk TEXT; 18 | BEGIN 19 | IF NOT EXISTS (SELECT 1 FROM pg_catalog.pg_database WHERE datname = dbname) THEN 20 | SELECT setting FROM pg_settings WHERE name = 'port' INTO port; 21 | SELECT dblink_exec('user=postgres dbname=postgres port=' || port, 'CREATE DATABASE ' || quote_ident(dbname)) INTO junk; 22 | END IF; 23 | END; 24 | $$ LANGUAGE PLPGSQL; 25 | 26 | -------------------------------------------------------------------------------- /modules/apps/sproxy-web.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | let 4 | 5 | inherit (lib) 6 | concatStrings hasPrefix mkEnableOption mkIf mkOption 7 | optionalString types ; 8 | inherit (types) 9 | int nullOr path str ; 10 | 11 | cfg = config.nixsap.apps.sproxy-web; 12 | 13 | ExecStart = concatStrings [ 14 | "${pkgs.sproxy-web}/bin/sproxy-web" 15 | (optionalString (cfg.connectionString != null) " -c '${cfg.connectionString}'") 16 | (if (cfg.port != null) 17 | then " -p ${toString cfg.port}" 18 | else " -s '${cfg.socket}'") 19 | ]; 20 | 21 | in { 22 | options.nixsap.apps.sproxy-web = { 23 | enable = mkEnableOption "Sproxy Web"; 24 | user = mkOption { 25 | description = "User to run as"; 26 | default = "sproxy-web"; 27 | type = str; 28 | }; 29 | connectionString = mkOption { 30 | description = "PostgreSQL connection string"; 31 | type = str; 32 | example = "user=sproxy-web dbname=sproxy port=6001"; 33 | }; 34 | pgPassFile = mkOption { 35 | description = "postgreSQL password file (secret)"; 36 | default = null; 37 | type = nullOr path; 38 | }; 39 | socket = mkOption { 40 | description = "UNIX socket to listen on. Ignored when TCP port is set"; 41 | default = "/tmp/sproxy-web.sock"; 42 | type = path; 43 | }; 44 | port = mkOption { 45 | description = "TCP port to listen on (insecure)"; 46 | type = nullOr int; 47 | default = null; 48 | }; 49 | }; 50 | 51 | config = mkIf cfg.enable { 52 | nixsap.system.users.daemons = [ cfg.user ]; 53 | nixsap.deployment.keyrings.${cfg.user} = [ cfg.pgPassFile ]; 54 | systemd.services.sproxy-web = { 55 | description = "Web interface to Sproxy database"; 56 | wantedBy = [ "multi-user.target" ]; 57 | wants = [ "keys.target" ]; 58 | after = [ "keys.target" "network.target" "local-fs.target" ]; 59 | serviceConfig = { 60 | inherit ExecStart; 61 | Restart = "on-failure"; 62 | User = cfg.user; 63 | }; 64 | environment.PGPASSFILE = cfg.pgPassFile; 65 | }; 66 | }; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /modules/apps/sproxy2.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | let 4 | 5 | inherit (builtins) elem isBool isInt isString; 6 | inherit (lib) 7 | concatMapStringsSep concatStringsSep filterAttrs imap 8 | mapAttrsToList mkIf mkOption optionalString ; 9 | inherit (lib.types) 10 | attrsOf bool either enum int listOf nullOr path str submodule ; 11 | 12 | default = v: type: mkOption { type = type; default = v; }; 13 | explicit = filterAttrs (n: v: n != "_module" && v != null); 14 | mandatory = t: mkOption { type = t; }; 15 | optional = t: mkOption { type = nullOr t; default = null; }; 16 | 17 | secret = either str ( 18 | submodule { options = { file = mandatory path; }; } 19 | ); 20 | 21 | concatMapAttrsSep = s: f: attrs: concatStringsSep s (mapAttrsToList f attrs); 22 | 23 | cfg = config.nixsap.apps.sproxy2; 24 | 25 | show = v: 26 | if v ? file then "!include '${v.file}'" 27 | else if isInt v then "${toString v}" 28 | else if isBool v then (if v then "true" else "false") 29 | else "'${v}'"; 30 | 31 | top = concatMapAttrsSep "\n" (k: v: "${k}: ${show v}") 32 | (filterAttrs (n: _: 33 | ! elem n [ 34 | "backends" 35 | "enable" 36 | "oauth2" 37 | "ssl_cert_chain" 38 | ] 39 | ) (explicit cfg)); 40 | 41 | configFile = with cfg; pkgs.writeYAML "sproxy.yml" '' 42 | # yamllint disable rule:empty-lines 43 | # yamllint disable rule:line-length 44 | --- 45 | ${top} 46 | 47 | ${optionalString (ssl_cert_chain != []) 48 | ''ssl_cert_chain: 49 | ${concatMapStringsSep "\n" (f: " - ${show f}") ssl_cert_chain}''} 50 | 51 | 52 | oauth2: 53 | ${concatMapAttrsSep "\n\n" (p: {client_id, client_secret, ...}: '' 54 | ${" ${p}"}: 55 | client_id: ${show client_id} 56 | client_secret: ${show client_secret}'' 57 | ) cfg.oauth2} 58 | 59 | 60 | backends: 61 | ${concatMapStringsSep "\n\n" (b: 62 | let lines = mapAttrsToList (k: v: "${k}: ${show v}") (explicit b); 63 | be = imap (i: l: " " + (if i == 1 then "- ${l}" else " ${l}")) lines; 64 | in concatStringsSep "\n" be 65 | ) cfg.backends} 66 | 67 | ... 68 | ''; 69 | 70 | maybeKey = a: if a ? file then a.file else null; 71 | keys = [ cfg.ssl_key cfg.pgpassfile ( maybeKey cfg.key ) ] 72 | ++ mapAttrsToList (_: c: maybeKey c.client_secret) (explicit cfg.oauth2) 73 | ; 74 | 75 | oauth2 = mkOption { 76 | description = '' 77 | OAuth2 providers. At least one is required. 78 | Refer to Sproxy2 for supported providers. 79 | ''; 80 | type = attrsOf (submodule { 81 | options = { 82 | client_id = mandatory str; 83 | client_secret = mandatory secret; 84 | }; 85 | }); 86 | }; 87 | 88 | backends = mkOption { 89 | description = '' 90 | Backends. At least one is required. 91 | Refer to Sproxy2 for description. 92 | ''; 93 | type = listOf (submodule { 94 | options = { 95 | address = optional str; 96 | conn_count = optional int; 97 | cookie_domain = optional str; 98 | cookie_max_age = optional int; 99 | cookie_name = optional str; 100 | name = optional str; 101 | port = optional int; 102 | socket = optional path; 103 | }; 104 | }); 105 | default = []; 106 | }; 107 | 108 | in { 109 | options.nixsap.apps.sproxy2 = { 110 | enable = mkOption { 111 | description = "Enable Sproxy2"; 112 | type = bool; 113 | default = (cfg.backends != []); 114 | }; 115 | 116 | inherit oauth2 backends; 117 | user = mkOption { 118 | description = "User to run as"; 119 | type = str; 120 | default = "sproxy2"; 121 | }; 122 | home = mkOption { 123 | description = "Sproxy2 home directory for internal data"; 124 | type = path; 125 | default = "/sproxy2"; 126 | }; 127 | listen = mkOption { 128 | description = "TCP port to listen on"; 129 | type = int; 130 | default = 443; 131 | }; 132 | listen80 = mkOption { 133 | description = "Whether to listen on port 80 (and redirect to HTTPS)"; 134 | type = bool; 135 | default = true; 136 | }; 137 | http2 = mkOption { 138 | description = "Whether HTTP/2 is enabled"; 139 | type = nullOr bool; 140 | default = null; 141 | }; 142 | ssl = mkOption { 143 | description = "Whether SSL is enabled."; 144 | type = nullOr bool; 145 | default = null; 146 | }; 147 | https_port = mkOption { 148 | description = "Port used in redirect to HTTPS"; 149 | type = nullOr int; 150 | default = null; 151 | }; 152 | log_level = mkOption { 153 | description = "Log level"; 154 | type = enum [ "error" "warn" "info" "debug" ]; 155 | default = "info"; 156 | }; 157 | key = mkOption { 158 | description = "A key used to sign cookies and state (secret)"; 159 | type = nullOr secret; 160 | default = null; 161 | }; 162 | database = mkOption { 163 | description = "PostgreSQL connection string"; 164 | type = nullOr str; 165 | default = null; 166 | example = "host=db.example.net user=sproxy dbname=sproxy port=6000"; 167 | }; 168 | pgpassfile = mkOption { 169 | description = "PostgreSQL password file (secret)"; 170 | type = nullOr path; 171 | default = null; 172 | }; 173 | datafile = mkOption { 174 | description = "Read permissions from this file"; 175 | type = nullOr path; 176 | default = null; 177 | }; 178 | ssl_key = mkOption { 179 | description = "SSL key (PEM format) - secret"; 180 | type = nullOr path; 181 | default = null; 182 | }; 183 | ssl_cert = mkOption { 184 | description = "SSL certificate (PEM format)"; 185 | type = nullOr path; 186 | default = null; 187 | }; 188 | ssl_cert_chain = mkOption { 189 | description = "SSL certificate chain"; 190 | type = listOf path; 191 | default = []; 192 | }; 193 | }; 194 | 195 | config = mkIf cfg.enable { 196 | nixsap.system.users.daemons = [ cfg.user ]; 197 | nixsap.deployment.keyrings.${cfg.user} = keys; 198 | systemd.services.sproxy2 = { 199 | description = "Sproxy2 secure HTTP proxy"; 200 | wantedBy = [ "multi-user.target" ]; 201 | wants = [ "keys.target" ]; 202 | after = [ "keys.target" "network.target" "local-fs.target" ]; 203 | preStart = '' 204 | mkdir -p -- '${cfg.home}' 205 | chown -Rc '${cfg.user}:${cfg.user}' -- '${cfg.home}' 206 | chmod -Rc u=rwX,g=rX,o= -- '${cfg.home}' 207 | ''; 208 | serviceConfig = { 209 | ExecStart = "${pkgs.sproxy2}/bin/sproxy2 --config=${configFile}"; 210 | Restart = "always"; 211 | }; 212 | }; 213 | }; 214 | } 215 | 216 | -------------------------------------------------------------------------------- /modules/apps/strongswan/default.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | let 4 | 5 | inherit (lib) mkIf mkOption types filterAttrs hasPrefix 6 | mapAttrsToList concatStringsSep concatMapStringsSep; 7 | inherit (types) listOf submodule path attrsOf; 8 | inherit (builtins) toFile isList isBool; 9 | 10 | cfg = config.nixsap.apps.strongswan; 11 | explicit = filterAttrs (n: v: n != "_module" && v != null); 12 | 13 | ipsecSecrets = toFile "ipsec.secrets" '' 14 | ${concatMapStringsSep "\n" (f: "include ${f}") cfg.secrets} 15 | ''; 16 | 17 | ipsecConf = 18 | let 19 | show = k: v: 20 | if k == "charondebug" then concatStringsSep "," 21 | (mapAttrsToList (t: l: "${t} ${toString l}") (explicit v)) 22 | else if isList v then concatStringsSep "," v 23 | else if isBool v then (if v then "yes" else "no") 24 | else toString v; 25 | makeSections = type: sections: concatStringsSep "\n\n" ( 26 | mapAttrsToList (sec: attrs: 27 | "${type} ${sec}\n" + 28 | (concatStringsSep "\n" ( 29 | mapAttrsToList (k: v: " ${k}=${show k v}") (explicit attrs) 30 | )) 31 | ) (explicit sections) 32 | ); 33 | setupSec = makeSections "config" { inherit (cfg) setup; }; 34 | caSec = makeSections "ca" cfg.ca; 35 | connSec = makeSections "conn" cfg.conn; 36 | in toFile "ipsec.conf" '' 37 | ${setupSec} 38 | ${caSec} 39 | ${connSec} 40 | ''; 41 | 42 | strongswanConf = toFile "strongswan.conf" '' 43 | charon { plugins { stroke { secrets_file = ${ipsecSecrets} } } } 44 | starter { config_file = ${ipsecConf } } 45 | ''; 46 | 47 | in { 48 | options.nixsap.apps.strongswan = { 49 | secrets = mkOption { 50 | description = '' 51 | A list of paths to IPSec secret files. These files will be included into 52 | the main ipsec.secrets file by the "include" directive 53 | ''; 54 | type = listOf path; 55 | default = []; 56 | }; 57 | setup = mkOption { 58 | description = '' 59 | A set of options for the ‘config setup’ section of the 60 | ipsec.conf file. Defines general configuration parameters 61 | ''; 62 | type = submodule (import ./options/setup.nix); 63 | default = {}; 64 | }; 65 | ca = mkOption { 66 | description = '' 67 | A set of CAs (certification authorities) and their options for 68 | the ‘ca xxx’ sections of the ipsec.conf file 69 | ''; 70 | type = attrsOf (submodule (import ./options/ca.nix)); 71 | default = {}; 72 | }; 73 | conn = mkOption { 74 | description = '' 75 | A set of connections and their options for the ‘conn xxx’ 76 | sections of the ipsec.conf file 77 | ''; 78 | type = attrsOf (submodule (import ./options/conn.nix)); 79 | default = {}; 80 | }; 81 | }; 82 | 83 | config = mkIf ({} != explicit cfg.conn) { 84 | nixsap.deployment.keyrings.root = cfg.secrets; 85 | environment.systemPackages = [ pkgs.strongswan ]; 86 | systemd.services.strongswan = { 87 | description = "strongSwan IPSec Service"; 88 | wantedBy = [ "multi-user.target" ]; 89 | path = with pkgs; [ config.system.sbin.modprobe iproute iptables utillinux ]; 90 | wants = [ "keys.target" ]; 91 | after = [ "network.target" "keys.target" "local-fs.target" ]; 92 | environment = { 93 | STRONGSWAN_CONF = strongswanConf; 94 | }; 95 | serviceConfig = { 96 | ExecStart = "${pkgs.strongswan}/sbin/ipsec start --nofork"; 97 | Restart = "always"; 98 | }; 99 | }; 100 | }; 101 | } 102 | -------------------------------------------------------------------------------- /modules/apps/strongswan/options/ca.nix: -------------------------------------------------------------------------------- 1 | { config, lib, ... }: 2 | 3 | let 4 | 5 | inherit (lib) foldl; 6 | inherit (lib.types) str path enum; 7 | inherit (import ./lib.nix lib) optional; 8 | 9 | in { 10 | options = foldl (a: b: a//b) {} [ 11 | { also = optional str; } 12 | { auto = optional (enum [ "add" "ignore" ]); } 13 | { cacert = optional path; } 14 | { certuribase = optional str; } 15 | { crluri = optional str; } 16 | { crluri2 = optional str; } 17 | { ocspuri = optional str; } 18 | { ocspuri2 = optional str; } 19 | ]; 20 | } 21 | -------------------------------------------------------------------------------- /modules/apps/strongswan/options/conn.nix: -------------------------------------------------------------------------------- 1 | { config, lib, ... }: 2 | 3 | let 4 | 5 | inherit (lib) foldl attrNames head; 6 | inherit (lib.types) int str path either listOf enum; 7 | inherit (import ./lib.nix lib) boolean boolOr default optional; 8 | 9 | leftright = map 10 | (a: let n = head (attrNames a); 11 | in { 12 | "left${n}" = a."${n}"; 13 | "right${n}" = a."${n}"; 14 | }) 15 | [ 16 | { allowany = optional boolean; } 17 | { auth = optional str; } 18 | { auth2 = optional str; } 19 | { ca = optional str; } 20 | { ca2 = optional str; } 21 | { cert = optional path; } 22 | { cert2 = optional path; } 23 | { dns = optional (listOf str); } 24 | { firewall = optional boolean; } 25 | { groups = optional (listOf str); } 26 | { hostaccess = optional boolean; } 27 | { id = optional str; } 28 | { id2 = optional str; } 29 | { policy = optional (listOf str); } 30 | { sendcert = optional (boolOr [ "never" "always" "ifasked" ]); } 31 | { sigkey = optional str; } 32 | { sourceip = optional str; } 33 | { subnet = optional (listOf str); } 34 | { updown = optional path; } 35 | ]; 36 | 37 | conn = leftright ++ [ 38 | { aaa_identity = optional str; } 39 | { aggressive = optional boolean; } 40 | { ah = optional (listOf str); } 41 | { also = optional str; } 42 | { authby = optional (enum [ "pubkey" "rsasig" "ecdsasig" "psk" "secret" "xauthrsasig" "xauthpsk" "never" ]); } 43 | { auto = optional (enum [ "ignore" "add" "route" "start" ]); } 44 | { closeaction = optional (enum [ "none" "clear" "hold" "restart" ]); } 45 | { compress = optional boolean; } 46 | { dpdaction = optional (enum [ "none" "clear" "hold" "restart" ]); } 47 | { dpddelay = optional int; } 48 | { dpdtimeout = optional int; } 49 | { eap_identity = optional str; } 50 | { esp = optional (listOf str); } 51 | { forceencaps = optional boolean; } 52 | { fragmentation = optional (boolOr [ "force" ]); } 53 | { ike = optional (listOf str); } 54 | { ikedscp = optional str; } 55 | { ikelifetime = optional int; } 56 | { inactivity = optional int; } 57 | { installpolicy = optional boolean; } 58 | { keyexchange = optional (enum [ "ikev1" "ikev2" ]); } 59 | { keyingtries = optional (either int (enum [ "%forever" ])); } 60 | { left = optional str; } 61 | { lifebytes = optional int; } 62 | { lifepackets = optional int; } 63 | { lifetime = optional int; } 64 | { marginbytes = optional int; } 65 | { marginpackets = optional int; } 66 | { mark = optional str; } 67 | { mark_in = optional str; } 68 | { mark_out = optional str; } 69 | { me_peerid = optional str; } 70 | { mediated_by = optional str; } 71 | { mediation = optional boolean; } 72 | { mobike = optional boolean; } 73 | { modeconfig = optional (enum [ "push" "pull" ]); } 74 | { reauth = optional boolean; } 75 | { rekey = optional boolean; } 76 | { rekeyfuzz = optional int; } 77 | { replay_window = optional int; } 78 | { reqid = optional int; } 79 | { right = optional str; } 80 | { tfc = optional (either int (enum [ "%mtu" ])); } 81 | { type = optional (enum [ "tunnel" "transport" "transport_proxy" "passthrough" "drop" ]); } 82 | { xauth = optional (enum [ "client" "server" ]); } 83 | { xauth_identity = optional str; } 84 | ]; 85 | 86 | in { 87 | options = foldl (a: b: a//b) {} conn; 88 | } 89 | -------------------------------------------------------------------------------- /modules/apps/strongswan/options/lib.nix: -------------------------------------------------------------------------------- 1 | lib: 2 | 3 | let 4 | inherit (lib) mkOption mkOptionType mergeOneOption elem flip concatStringsSep; 5 | inherit (lib.types) nullOr submodule bool either; 6 | 7 | in rec { 8 | default = v: type: mkOption { type = type; default = v; }; 9 | optional = type: mkOption { type = nullOr type; default = null; }; 10 | set = opts: mkOption { type = nullOr (submodule { options = opts; }); default = null; }; 11 | 12 | # XXX https://github.com/NixOS/nixpkgs/issues/9826 13 | enum' = values: 14 | let show = v: let t = builtins.typeOf v; 15 | in if t == "string" then ''"${v}"'' 16 | else if t == "int" then builtins.toString v 17 | else ''<${t}>''; 18 | in mkOptionType { 19 | name = "one of ${concatStringsSep ", " (map show values)}"; 20 | check = flip elem values; 21 | merge = mergeOneOption; 22 | }; 23 | 24 | boolean = either bool (enum' [ "yes" "no" ]); 25 | boolOr = l: either bool (enum' ([ "yes" "no" ] ++ l)); 26 | } 27 | -------------------------------------------------------------------------------- /modules/apps/strongswan/options/setup.nix: -------------------------------------------------------------------------------- 1 | { config, lib, ... }: 2 | 3 | let 4 | 5 | inherit (lib) foldl genAttrs; 6 | inherit (import ./lib.nix lib) boolean boolOr default optional set enum'; 7 | 8 | charondebug = genAttrs [ 9 | "asn" "cfg" "chd" "dmn" 10 | "enc" "esp" "ike" "imc" 11 | "imv" "job" "knl" "lib" 12 | "mgr" "net" "pts" "tls" 13 | "tnc" 14 | ] (_: optional (enum' [ (-1) 0 1 2 3 4 ])); 15 | 16 | in { 17 | options = foldl (a: b: a//b) {} [ 18 | { cachecrls = optional boolean; } 19 | { charondebug = set charondebug; } 20 | { charonstart = optional boolean; } 21 | { strictcrlpolicy = optional (boolOr [ "ifuri" ]); } 22 | { uniqueids = optional (boolOr [ "never" "replace" "keep" ]); } 23 | ]; 24 | } 25 | -------------------------------------------------------------------------------- /modules/default.nix: -------------------------------------------------------------------------------- 1 | {lib, ... }: 2 | 3 | let 4 | all = lib.filterAttrs 5 | ( n: _: n != "default.nix" && ! lib.hasPrefix "." n ) 6 | (builtins.readDir ./.); 7 | 8 | in { 9 | imports = map (p: ./. + "/${p}") ( builtins.attrNames all ); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /modules/deployment/default.nix: -------------------------------------------------------------------------------- 1 | {lib, ... }: 2 | 3 | let 4 | all = lib.filterAttrs 5 | ( n: _: n != "default.nix" && ! lib.hasPrefix "." n ) 6 | (builtins.readDir ./.); 7 | 8 | in { 9 | imports = map (p: ./. + "/${p}") ( builtins.attrNames all ); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /modules/deployment/keyrings.nix: -------------------------------------------------------------------------------- 1 | { config, lib, ... }: 2 | 3 | let 4 | 5 | inherit (builtins) 6 | attrNames baseNameOf head match pathExists readFile ; 7 | inherit (lib) 8 | filter foldl genAttrs hasPrefix mapAttrsToList mkOption 9 | optionalAttrs unique ; 10 | inherit (lib.types) 11 | attrsOf listOf nullOr path ; 12 | 13 | allusers = config.users.users; 14 | cfg = config.nixsap.deployment; 15 | 16 | # XXX If the file is encrypted: 17 | # error: the contents of the file ‘...’ cannot be represented as a Nix string 18 | read = key: 19 | let 20 | m = match "^(.+)@[^@]+$" key; 21 | s = if m != null then head m else key; 22 | in if cfg.secrets != null 23 | then readFile (cfg.secrets + "/${s}") 24 | else ""; 25 | 26 | in { 27 | options.nixsap.deployment = { 28 | secrets = mkOption { 29 | description = '' 30 | Directory with the secrets on the deploy machine. If not specified, 31 | each key will be an empty file. 32 | ''; 33 | type = nullOr path; 34 | default = null; 35 | example = ""; 36 | }; 37 | 38 | keyStore = mkOption { 39 | description = '' 40 | Directory with the keys on the target machine. NixOps uses /run/keys, 41 | and this is default. If you use another deployment tool, you would 42 | like to set it to something else. 43 | ''; 44 | type = path; 45 | default = "/run/keys"; 46 | example = "/root/keys"; 47 | }; 48 | 49 | keyrings = mkOption { 50 | type = attrsOf (listOf (nullOr path)); 51 | description = '' 52 | Binds keys to a user. It's possible to share the same key between 53 | multiple users, of course by different names: "/run/keys/foo" 54 | and "/run/keys/foo@bar" will use the same secret file "foo". Any 55 | file whose path does not start with `nixsap.deployment.keyStore` is 56 | deliberately ignored. E. i. you can pass any file names, and nixsap 57 | will pick up keys for you. For convenience, it is allowed to pass 58 | null values, which are filtered-out as well. 59 | ''; 60 | default = {}; 61 | example = { mysqlbackup = [ "/run/keys/s3cmd.cfg" ]; 62 | pgbackup = [ "/run/keys/s3cmd.cfg@pgbackup" ]; 63 | }; 64 | }; 65 | }; 66 | 67 | config = { 68 | users.users = genAttrs (attrNames cfg.keyrings) ( 69 | name: optionalAttrs (name != "root") { extraGroups = [ "keys" ]; } 70 | ); 71 | 72 | deployment.keys = foldl (a: b: a//b) {} ( 73 | mapAttrsToList (name: keys: 74 | let realkeys = unique (filter (n: n != null && hasPrefix cfg.keyStore n) keys); 75 | in genAttrs (map baseNameOf realkeys) 76 | (key: { text = read key; 77 | user = toString allusers.${name}.uid; 78 | }) 79 | ) cfg.keyrings 80 | ); 81 | }; 82 | } 83 | -------------------------------------------------------------------------------- /modules/overlay.nix: -------------------------------------------------------------------------------- 1 | { 2 | nixpkgs.overlays = [ (import ../pkgs) ]; 3 | } 4 | -------------------------------------------------------------------------------- /modules/system/default.nix: -------------------------------------------------------------------------------- 1 | {lib, ... }: 2 | 3 | let 4 | all = lib.filterAttrs 5 | ( n: _: n != "default.nix" && ! lib.hasPrefix "." n ) 6 | (builtins.readDir ./.); 7 | 8 | in { 9 | imports = map (p: ./. + "/${p}") ( builtins.attrNames all ); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /modules/system/firewall.nix: -------------------------------------------------------------------------------- 1 | { config, lib, ... }: 2 | 3 | let 4 | inherit (builtins) length replaceStrings; 5 | inherit (lib) concatMapStringsSep optionalString splitString mkOption; 6 | inherit (lib.types) listOf int submodule enum str; 7 | 8 | inherit (config.nixsap.system.firewall) whitelist; 9 | 10 | iptablesAllow = { dport, protocol, source, comment, ... }: 11 | let 12 | ports = concatMapStringsSep "," toString dport; 13 | iptables = if 1 < length (splitString ":" source) 14 | then "ip6tables" else "iptables"; 15 | in "${iptables} -w -A nixos-fw -m multiport " 16 | + "-p ${protocol} --dport ${ports} -s ${source} -j nixos-fw-accept" 17 | + optionalString (comment != "") 18 | " -m comment --comment '${replaceStrings ["'"] ["'\\''"] comment} '"; 19 | 20 | in { 21 | options.nixsap.system.firewall.whitelist = mkOption { 22 | description = "Inbound connection rules (whitelist)"; 23 | default = []; 24 | type = listOf (submodule { 25 | options = { 26 | dport = mkOption { 27 | description = "Destination ports"; 28 | type = listOf int; 29 | }; 30 | source = mkOption { 31 | description = "Source specification: a network IP address (with optional /mask)"; 32 | type = str; 33 | }; 34 | protocol = mkOption { 35 | description = "The network protocol"; 36 | type = enum [ "tcp" "udp" ]; 37 | default = "tcp"; 38 | }; 39 | comment = mkOption { 40 | description = "Free-form comment"; 41 | type = str; 42 | default = ""; 43 | }; 44 | }; 45 | }); 46 | }; 47 | 48 | config = { 49 | networking.firewall.extraCommands = 50 | concatMapStringsSep "\n" iptablesAllow whitelist; 51 | }; 52 | } 53 | -------------------------------------------------------------------------------- /modules/system/raid0.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | let 4 | 5 | inherit (builtins) 6 | attrNames 7 | ; 8 | 9 | inherit (lib) 10 | concatStringsSep filterAttrs foldl genAttrs mapAttrs' mapAttrsToList 11 | mkOption nameValuePair removePrefix replaceStrings 12 | ; 13 | 14 | inherit (lib.types) 15 | attrsOf enum ints nonEmptyListOf path submodule 16 | ; 17 | 18 | groups = filterAttrs (n: _: n != "_module") config.nixsap.system.lvm.raid0; 19 | 20 | createLV = vg: lv: s: opts: 21 | let 22 | new = toString s; 23 | stripes = toString opts.stripes; 24 | sizeSpec = if opts.units == "%" 25 | then "--extents ${new}%VG" 26 | else "--size ${new}${opts.units}"; 27 | scale = { 28 | "%" = "* 100 / $(vgs --unit b --noheadings --nosuffix --options vg_size ${vg})"; 29 | "M" = "/ ${toString (1000 * 1000)}"; 30 | "m" = "/ ${toString (1024 * 1024)}"; 31 | "G" = "/ ${toString (1000 * 1000 * 1000)}"; 32 | "g" = "/ ${toString (1024 * 1024 * 1024)}"; 33 | "T" = "/ ${toString (1000 * 1000 * 1000 * 1000)}"; 34 | "t" = "/ ${toString (1024 * 1024 * 1024 * 1024)}"; 35 | }; 36 | in pkgs.writeBashScript "raid0-create-${vg}-${lv}" '' 37 | set -eu 38 | device=/dev/${vg}/${lv} 39 | 40 | lv_size=$(lvs --unit b --noheadings --nosuffix --options lv_size "$device" || echo 0) 41 | old=$(( lv_size ${scale."${opts.units}"} )) 42 | 43 | if (( ${new} == old )) ; then 44 | exit 0 45 | elif (( old == 0 )); then 46 | lvcreate ${vg} --name ${lv} ${sizeSpec} --stripes ${stripes} 47 | elif (( ${new} < old )) ; then 48 | echo "Cannot shrink volume $device from $old ${opts.units} to ${new} ${opts.units}" >&2 49 | exit 1 50 | else 51 | lvextend "$device" ${sizeSpec} 52 | resize2fs "$device" 53 | fi 54 | ''; 55 | 56 | createVG = vg: pv: pkgs.writeBashScript "raid0-create-vg-${vg}" '' 57 | set -eu 58 | for pv in ${toString pv}; do 59 | type=$(blkid -p -s TYPE -o value "$pv" || true) 60 | if [ "$type" != LVM2_member ]; then 61 | pvcreate "$pv" 62 | if ! vgs ${vg}; then 63 | vgcreate ${vg} "$pv" 64 | else 65 | vgextend ${vg} "$pv" 66 | fi 67 | fi 68 | done 69 | ''; 70 | 71 | mkRaidService = vg: opts: 72 | let 73 | ExecStart = pkgs.writeBashScript "raid0-${vg}" '' 74 | set -eu 75 | ${createVG vg opts.physical} 76 | ${concatStringsSep "\n" ( 77 | mapAttrsToList (v: s: 78 | "${createLV vg (baseNameOf v) s opts}") 79 | opts.fileSystems 80 | )} 81 | vgchange -ay ${vg} 82 | udevadm trigger --action=add 83 | ''; 84 | 85 | in nameValuePair "raid0-${vg}" rec { 86 | wantedBy = map (v: "dev-${vg}-${baseNameOf v}.device") (attrNames opts.fileSystems); 87 | requires = map (pv: replaceStrings ["/"] ["-"] (removePrefix "/" pv) + ".device") opts.physical; 88 | after = requires; 89 | before = wantedBy; 90 | unitConfig.DefaultDependencies = false; 91 | path = with pkgs; [ utillinux lvm2 e2fsprogs ]; 92 | serviceConfig = { 93 | inherit ExecStart; 94 | RemainAfterExit = true; 95 | Type = "oneshot"; 96 | }; 97 | }; 98 | 99 | in { 100 | options.nixsap.system = { 101 | lvm.raid0 = mkOption { 102 | description = "Set of LVM2 volume groups"; 103 | default = {}; 104 | type = attrsOf (submodule { 105 | options = { 106 | stripes = mkOption { 107 | description = "Number of stripes"; 108 | type = ints.positive; 109 | example = 2; 110 | }; 111 | physical = mkOption { 112 | description = "List of physical devices (must be even for stripes)"; 113 | example = [ "/dev/sdb" "/dev/sdc" ]; 114 | type = nonEmptyListOf path; 115 | }; 116 | fileSystems = mkOption { 117 | description = "Filesystems and their sizes"; 118 | type = attrsOf ints.positive; 119 | example = { "/mariadb/db" = 100; }; 120 | }; 121 | units = mkOption { 122 | description = "Units of size"; 123 | type = enum [ "%" "m" "g" "t" "M" "G" "T"]; 124 | }; 125 | }; 126 | }); 127 | }; 128 | }; 129 | 130 | config = { 131 | systemd.services = mapAttrs' mkRaidService groups; 132 | 133 | fileSystems = foldl (a: b: a//b) {} ( 134 | mapAttrsToList (vg: opts: genAttrs (attrNames opts.fileSystems) 135 | (fs: { 136 | fsType = "ext4"; 137 | autoFormat = true; 138 | device = "/dev/${vg}/${baseNameOf fs}"; 139 | }) 140 | ) groups 141 | ); 142 | }; 143 | } 144 | 145 | -------------------------------------------------------------------------------- /modules/system/sysops.nix: -------------------------------------------------------------------------------- 1 | { config, lib, ...}: 2 | let 3 | 4 | inherit (lib) concatStringsSep genAttrs mkIf ; 5 | 6 | bindir = "/run/current-system/sw/bin"; 7 | 8 | commands = concatStringsSep ", " ( 9 | [ 10 | "${bindir}/du *" 11 | "${bindir}/iftop" 12 | "${bindir}/iotop" 13 | "${bindir}/ip6tables -L*" 14 | "${bindir}/ipsec *" 15 | "${bindir}/iptables -L*" 16 | "${bindir}/journalctl *" 17 | "${bindir}/lsof *" 18 | "${bindir}/mtr *" 19 | "${bindir}/nix-collect-garbage *" 20 | "${bindir}/nmap *" 21 | "${bindir}/tcpdump *" 22 | "${bindir}/traceroute *" 23 | ] ++ map (c: "${bindir}/systemctl ${c} *") 24 | [ "kill" "reload" "reset-failed" "restart" "start" "status" "stop" ] 25 | ); 26 | 27 | in { 28 | 29 | config = mkIf ( [] != config.nixsap.system.users.sysops ) { 30 | nixsap.system.groups = [ "sysops" ]; 31 | 32 | users.users = genAttrs config.nixsap.system.users.sysops ( 33 | name: { 34 | extraGroups = [ "sysops" "systemd-journal" "proc" ]; 35 | } 36 | ); 37 | 38 | security.sudo.extraConfig = '' 39 | %sysops ALL=(ALL) NOPASSWD: ${commands} 40 | ''; 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /modules/system/users.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | let 4 | 5 | inherit (builtins) 6 | genList hashString mul substring ; 7 | 8 | inherit (lib) 9 | foldl genAttrs imap mkOption stringToCharacters toLower 10 | types unique ; 11 | 12 | inherit (types) 13 | listOf str ; 14 | 15 | uid = name: 16 | let 17 | dec = { 18 | "0" = 0; "1" = 1; "2" = 2; "3" = 3; 19 | "4" = 4; "5" = 5; "6" = 6; "7" = 7; 20 | "8" = 8; "9" = 9; "a" = 10; "b" = 11; 21 | "c" = 12; "d" = 13; "e" = 14; "f" = 15; 22 | }; 23 | base = 1000000000; # 2^32 > base + 16^7 24 | hex = toLower (substring 0 7 (hashString "sha1" name)); 25 | pow = b: n: foldl mul 1 (genList (_: b) n); 26 | digits = imap (i: d: {m = pow 16 (i - 1); d = d;}) (stringToCharacters hex); 27 | f = a: {m, d}: a + m * dec.${d}; 28 | 29 | in foldl f base digits; 30 | 31 | daemons = config.nixsap.system.users.daemons; 32 | normal = config.nixsap.system.users.normal; 33 | groups = config.nixsap.system.groups; 34 | 35 | mkGroup = name: { gid = uid name; }; 36 | mkDaemonUser = name: 37 | { 38 | isNormalUser = false; 39 | uid = uid name; 40 | group = name; 41 | }; 42 | 43 | mkNormalUser = name: 44 | { 45 | isNormalUser = true; 46 | uid = uid name; 47 | }; 48 | 49 | in { 50 | options.nixsap.system = { 51 | users.daemons = mkOption { 52 | type = listOf str; 53 | description = "List of system users with automatic UID and group"; 54 | default = []; 55 | }; 56 | users.normal = mkOption { 57 | type = listOf str; 58 | description = "List of regular users with automatic UID"; 59 | default = []; 60 | }; 61 | users.sysops = mkOption { 62 | description = '' 63 | List of local users with special roles in applications or system-wide. 64 | The users in this list are not create automatically. 65 | ''; 66 | type = listOf str; 67 | default = []; 68 | }; 69 | groups = mkOption { 70 | type = listOf str; 71 | description = "List of groups with automatic GID"; 72 | default = []; 73 | }; 74 | }; 75 | 76 | # XXX: Modules for automatic unicity of user names: 77 | imports = [ 78 | { users.groups = genAttrs (unique (daemons ++ groups)) mkGroup; } 79 | { users.users = genAttrs daemons mkDaemonUser; } 80 | { users.users = genAttrs normal mkNormalUser; } 81 | ]; 82 | } 83 | 84 | -------------------------------------------------------------------------------- /modules/system/worldWritableDirs.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | let 3 | dirs = config.nixsap.system.worldWritableDirs; 4 | 5 | in { 6 | options.nixsap.system.worldWritableDirs = lib.mkOption { 7 | type = lib.types.listOf lib.types.path; 8 | description = "These dirs will be chmod'ed 1777"; 9 | default = [ "/tmp" "/var/tmp" ]; 10 | }; 11 | 12 | config = lib.mkIf (dirs != []) { 13 | systemd.services.chmod1777 = { 14 | description = "Make some dirs world-writable"; 15 | unitConfig.RequiresMountsFor = dirs; 16 | before = [ "local-fs.target" ]; 17 | wantedBy = [ "local-fs.target" ]; 18 | serviceConfig = { 19 | ExecStart = "${pkgs.coreutils}/bin/chmod -c 1777 ${lib.concatStringsSep " " dirs}"; 20 | Type = "oneshot"; 21 | RemainAfterExit = true; 22 | }; 23 | }; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /pkgs/cassandra3/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: 2 | 3 | pkgs.stdenv.mkDerivation rec { 4 | version = "3.11"; 5 | name = "cassandra-${version}"; 6 | 7 | src = pkgs.fetchgit { 8 | url = "https://git-wip-us.apache.org/repos/asf/cassandra.git"; 9 | rev = "30412b08c0eb4a5cc5296725c7359f2741483ea2"; 10 | sha256 = "0a5xgsgd5a91qckh4i40bxa6w9fw4bry0cqa3aj2hc7friwj199s"; 11 | }; 12 | 13 | buildInputs = with pkgs; [ ant jdk ]; 14 | 15 | patches = [ 16 | ]; 17 | 18 | configurePhase = '' 19 | rm -rfv lib/*sigar* 20 | cp --symbolic-link -fv ${pkgs.hyperic-sigar}/share/java/* lib/ 21 | ''; 22 | 23 | buildPhase = '' 24 | ant jar 25 | ''; 26 | 27 | installPhase = '' 28 | mkdir -p $out/lib/jni 29 | mkdir -p $out/share/java 30 | 31 | cp -v lib/*.jar $out/share/java/ 32 | cp -v lib/*.zip $out/share/java/ 33 | cp -v build/apache-cassandra*.jar $out/share/java/ 34 | 35 | cp --symbolic-link -fv ${pkgs.hyperic-sigar}/share/java/* $out/share/java/ 36 | cp --symbolic-link -fv ${pkgs.hyperic-sigar}/lib/jni/* $out/lib/jni/ 37 | 38 | ''; 39 | } 40 | -------------------------------------------------------------------------------- /pkgs/check_aws_ec2_elb/check_aws_ec2_elb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | outOfServicePercentWarn=20 6 | outOfServicePercentCrit=33 7 | endpoint='' 8 | 9 | while [ $# -gt 0 ]; do 10 | case "$1" in 11 | -f) export BOTO_CONFIG="$2"; shift 2;; 12 | -h) endpoint="$2"; shift 2;; 13 | -w) outOfServicePercentWarn="$2"; shift 2;; 14 | -c) outOfServicePercentCrit="$2"; shift 2;; 15 | *) echo "$0: unsupported argument: $1" >&2; exit 1;; 16 | esac 17 | done 18 | 19 | cmd=( aws elb describe-instance-health ) 20 | 21 | c=0 22 | while [[ "$endpoint" != *.*.elb.amazonaws.com* ]]; do 23 | endpoint=$(dig "$endpoint" CNAME +short) 24 | (( ++c )) 25 | if (( c > 10 )); then 26 | echo "failed to resolve '$1'" >&2 27 | exit 255 28 | fi 29 | done 30 | 31 | cmd+=( --region $(echo "$endpoint" | cut -d. -f2) ) 32 | elbName=$(echo "$endpoint" | cut -d. -f1 | sed -r 's/^(internal-)?(.*)-[0-9]+$/\2/') 33 | cmd+=( --load-balancer-name "$elbName" ) 34 | 35 | json=$("${cmd[@]}") 36 | 37 | totalCount=$(echo "$json" | jq -c '.InstanceStates | length') 38 | outOfServiceInfo=$(echo "$json" | jq -c '.InstanceStates | map(select(.State == "OutOfService") | .InstanceId)') 39 | outOfServiceCount=$(echo "$outOfServiceInfo" | jq -r 'length') 40 | 41 | outOfServiceCountWarn=${outOfServiceCountWarn:-$(( totalCount * outOfServicePercentWarn / 100 ))} 42 | outOfServiceCountCrit=${outOfServiceCountCrit:-$(( totalCount * outOfServicePercentCrit / 100 ))} 43 | 44 | stat="total=$totalCount out_of_service=$outOfServiceCount;$outOfServiceCountWarn;$outOfServiceCountCrit" 45 | outOfServiceInstances=$(echo "$outOfServiceInfo" | jq -r 'join(", ")') 46 | 47 | if [ "$outOfServiceCount" -eq 0 ]; then 48 | echo "OK: $elbName - $totalCount instances|$stat" 49 | exit 0 50 | elif [ "$outOfServiceCount" -ge "$outOfServiceCountCrit" ]; then 51 | echo "CRITICAL: $elbName - $outOfServiceCount/$totalCount out of service: $outOfServiceInstances|$stat" 52 | exit 2 53 | elif [ "$outOfServiceCount" -ge "$outOfServiceCountWarn" ]; then 54 | echo "WARNING: $elbName - $outOfServiceCount/$totalCount out of service: $outOfServiceInstances|$stat" 55 | exit 1 56 | else 57 | echo "OK: $elbName - $outOfServiceCount/$totalCount out of service: $outOfServiceInstances|$stat" 58 | exit 0 59 | fi 60 | 61 | -------------------------------------------------------------------------------- /pkgs/check_aws_ec2_elb/check_aws_ec2_elb.conf: -------------------------------------------------------------------------------- 1 | object CheckCommand "aws-ec2-elb" { 2 | import "plugin-check-command" 3 | 4 | command = [ "check_aws_ec2_elb" ] 5 | 6 | arguments = { 7 | "-h" = "$aws_ec2_elb_address$" 8 | "-f" = "$aws_ec2_elb_boto_config$" 9 | "-w" = "$aws_ec2_elb_warn$" 10 | "-c" = "$aws_ec2_elb_crit$" 11 | } 12 | vars.aws_ec2_elb_address = "$address$" 13 | } 14 | 15 | -------------------------------------------------------------------------------- /pkgs/check_aws_ec2_elb/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, pkgs, makeWrapper }: 2 | 3 | stdenv.mkDerivation { 4 | name = "check_aws_ec2_elb"; 5 | outputs = [ "out" "conf" ]; 6 | unpackPhase = ":"; 7 | nativeBuildInputs = [ makeWrapper ]; 8 | installPhase = '' 9 | mkdir -p $out/bin 10 | 11 | cp ${./check_aws_ec2_elb} $out/bin/check_aws_ec2_elb 12 | cp ${./check_aws_ec2_elb.conf} $conf 13 | 14 | chmod +x "$out/bin/"* 15 | 16 | substituteInPlace "$conf" \ 17 | --replace check_aws_ec2_elb "$out/bin/check_aws_ec2_elb" 18 | 19 | wrapProgram "$out/bin/check_aws_ec2_elb" \ 20 | --prefix PATH : "${pkgs.awscli}/bin:${pkgs.gnused}/bin:${pkgs.jq}/bin:${pkgs.bind.dnsutils}/bin" 21 | ''; 22 | } 23 | -------------------------------------------------------------------------------- /pkgs/check_aws_rds/check_aws_rds: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | cmd=( pmp-check-aws-rds ) 6 | 7 | getId () { 8 | local endpoint="$1" 9 | local c=0 10 | while [[ "$endpoint" != *.*.*.rds.amazonaws.com* ]]; do 11 | endpoint=$(dig "$endpoint" CNAME +short) 12 | (( ++c )) 13 | if (( c > 10 )); then 14 | echo "failed to resolve '$1'" >&2 15 | exit 255 16 | fi 17 | done 18 | 19 | cmd+=( -r $(echo "$endpoint" | cut -d. -f3) ) 20 | cmd+=( -i $(echo "$endpoint" | cut -d. -f1) ) 21 | } 22 | 23 | while [ $# -gt 0 ]; do 24 | case "$1" in 25 | -m|-w|-c) cmd+=( $1 $2 ); shift 2;; 26 | -f) export BOTO_CONFIG="$2"; shift 2;; 27 | -h) getId "$2"; shift 2;; 28 | *) echo "$0: unsupported argument: $1" >&2; exit 1;; 29 | esac 30 | done 31 | exec "${cmd[@]}" 32 | 33 | -------------------------------------------------------------------------------- /pkgs/check_aws_rds/check_aws_rds.conf: -------------------------------------------------------------------------------- 1 | template CheckCommand "aws-rds-common" { 2 | import "plugin-check-command" 3 | 4 | command = [ "check_aws_rds" ] 5 | 6 | arguments = { 7 | "-h" = "$aws_rds_address$" 8 | "-f" = "$aws_rds_boto_config$" 9 | "-m" = "$aws_rds_metric$" 10 | "-w" = "$aws_rds_warning$" 11 | "-c" = "$aws_rds_critical$" 12 | } 13 | vars.aws_rds_address = "$address$" 14 | } 15 | 16 | object CheckCommand "aws-rds-status" { 17 | import "aws-rds-common" 18 | vars.aws_rds_metric = "status" 19 | } 20 | 21 | object CheckCommand "aws-rds-load" { 22 | import "aws-rds-common" 23 | vars.aws_rds_metric = "load" 24 | vars.aws_rds_critical = "99,97,95" 25 | vars.aws_rds_warning = "95,93,90" 26 | } 27 | 28 | object CheckCommand "aws-rds-memory" { 29 | import "aws-rds-common" 30 | vars.aws_rds_metric = "memory" 31 | vars.aws_rds_critical = "5" 32 | vars.aws_rds_warning = "9" 33 | } 34 | 35 | object CheckCommand "aws-rds-storage" { 36 | import "aws-rds-common" 37 | vars.aws_rds_metric = "storage" 38 | vars.aws_rds_critical = "5" 39 | vars.aws_rds_warning = "15" 40 | } 41 | 42 | -------------------------------------------------------------------------------- /pkgs/check_aws_rds/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, pkgs, fetchurl, python27Packages }: 2 | let 3 | 4 | rev = "7f4a9852a0e470698d90afc0036d2738a4906477"; 5 | 6 | pmp-check-aws-rds = stdenv.mkDerivation rec { 7 | name = "pmp-check-aws-rds"; 8 | src = fetchurl { 9 | url = "https://raw.githubusercontent.com/percona/percona-monitoring-plugins/${rev}/nagios/bin/pmp-check-aws-rds.py"; 10 | sha256 = "1ps7ag2hmbbzg3w6h76l6j4ijigfhlvmirj8h7v9qyrdcgzlsjma"; 11 | }; 12 | 13 | buildInputs = with python27Packages; [ python wrapPython ]; 14 | pythonPath = with python27Packages; [ boto ]; 15 | phases = [ "installPhase" "fixupPhase" ]; 16 | 17 | installPhase = '' 18 | mkdir -p $out/bin 19 | cp $src $out/bin/${name} 20 | chmod +x $out/bin/${name} 21 | wrapPythonPrograms 22 | ''; 23 | 24 | }; 25 | 26 | in stdenv.mkDerivation { 27 | name = "check_aws_rds"; 28 | outputs = [ "out" "conf" ]; 29 | 30 | phases = [ "installPhase" "fixupPhase" ]; 31 | nativeBuildInputs = with pkgs; [ makeWrapper ]; 32 | 33 | installPhase = '' 34 | mkdir -p $out/bin 35 | 36 | cp ${./check_aws_rds} $out/bin/check_aws_rds 37 | cp ${./check_aws_rds.conf} $conf 38 | 39 | chmod +x "$out/bin/"* 40 | 41 | substituteInPlace "$conf" \ 42 | --replace check_aws_rds "$out/bin/check_aws_rds" 43 | 44 | wrapProgram "$out/bin/check_aws_rds" \ 45 | --prefix PATH : "${pmp-check-aws-rds}/bin:${pkgs.bind.dnsutils}/bin" 46 | ''; 47 | } 48 | -------------------------------------------------------------------------------- /pkgs/check_aws_s3_file/check_aws_s3_file: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | sizeWarn='' 6 | sizeCrit='' 7 | timeWarn='' 8 | timeCrit='' 9 | bucket='' 10 | key='' 11 | 12 | usage() { 13 | cat < AWS CLI credentials file 23 | 24 | -b S3 bucket name, required 25 | -k object key, e. g. "hosts/foo/bar.gz" 26 | 27 | -s object size warning threshold 28 | -S object size critical threshold 29 | 30 | -t object age warning threshold 31 | -T object age critical threshold 32 | 33 | Examples: 34 | 35 | $0 -b foobucket # check the bucket is available 36 | $0 -b foobucket -k hosts/foo/file.gz 37 | $0 -b foobucket -k hosts/foo/file.gz -t 86400 38 | $0 -b foobucket -k hosts/foo/file.gz -t 3600: -s 1000: 39 | 40 | USAGE 41 | } 42 | 43 | die () { 44 | echo "$0: " "$@" >&2 45 | exit 1 46 | } 47 | 48 | while [ $# -gt 0 ]; do 49 | case "$1" in 50 | -f) export AWS_SHARED_CREDENTIALS_FILE="$2"; shift 2;; 51 | -b) bucket="$2"; shift 2;; 52 | -k) key="$2"; shift 2;; 53 | -s) sizeWarn="$2"; shift 2;; 54 | -S) sizeCrit="$2"; shift 2;; 55 | -t) timeWarn="$2"; shift 2;; 56 | -T) timeCrit="$2"; shift 2;; 57 | -h|--help) usage; exit 1;; 58 | *) die "unsupported argument: $1";; 59 | esac 60 | done 61 | 62 | inrange () { 63 | local r v 64 | local v1 v2 65 | local outter 66 | local sIFS 67 | 68 | r="$1" 69 | v="$2" 70 | 71 | case "$r" in 72 | @*) outter=true; r="${r/@/}";; 73 | *) outter=false;; 74 | esac 75 | 76 | sIFS=$IFS 77 | 78 | IFS=: 79 | set -- $r 80 | v1=${1-} 81 | v2=${2-} 82 | IFS=$sIFS 83 | 84 | case "$v1" in 85 | $r) v2=$v1; v1=0;; 86 | ~*) v1=;; 87 | esac 88 | 89 | if $outter; then 90 | { [ -n "$v1" ] && [ "$v" -le "$v1" ]; } || { [ -n "$v2" ] && [ "$v" -ge "$v2" ]; } 91 | else 92 | { [ -z "$v1" ] || [ "$v" -ge "$v1" ]; } && { [ -z "$v2" ] || [ "$v" -le "$v2" ]; } 93 | fi 94 | } 95 | 96 | humanSize() { 97 | local n u 98 | 99 | n=$1 100 | for u in B KiB MiB GiB TiB; do 101 | if (( n > 1024 )); then 102 | (( n /= 1024 )) 103 | else 104 | break 105 | fi 106 | done 107 | 108 | echo "${n} ${u}" 109 | } 110 | 111 | 112 | [ -n "$bucket" ] || die "missing S3 bucket" 113 | 114 | if [ -z "$key" ]; then 115 | if out=$(aws s3api head-bucket --bucket "$bucket" 2>&1); then 116 | echo "OK: bucket $bucket exists and is accessible" 117 | exit 0 118 | else 119 | printf 'CRITICAL: %s\n' "$(echo "$out" | grep .)" 120 | exit 2 121 | fi 122 | fi 123 | 124 | if ! out=$(aws s3api head-object --bucket "$bucket" --key "$key" 2>&1); then 125 | printf 'UNKNOWN: %s\n' "$(echo "$out" | grep .)" 126 | exit 3 127 | fi 128 | 129 | json=$out 130 | 131 | size=$(echo "$json" | jq -r .ContentLength) 132 | date=$(echo "$json" | jq -r .LastModified) 133 | 134 | date_s=$(date -d "$date" +%s) 135 | now_s=$(date -d now +%s) 136 | age_s=$((now_s - date_s)) 137 | size_h=$(humanSize "$size") 138 | 139 | stat="size=${size}B;${sizeWarn};${sizeCrit};0 age=${age_s}s;${timeWarn};${timeCrit}" 140 | 141 | if [ -n "$timeCrit" ] && ! inrange "$timeCrit" "$age_s"; then 142 | echo "CRITICAL: last modified $date|$stat" 143 | exit 2 144 | fi 145 | 146 | if [ -n "$sizeCrit" ] && ! inrange "$sizeCrit" "$size"; then 147 | echo "CRITICAL: size $size_h|$stat" 148 | exit 2 149 | fi 150 | 151 | if [ -n "$timeWarn" ] && ! inrange "$timeWarn" "$age_s"; then 152 | echo "WARNING: last modified $date|$stat" 153 | exit 1 154 | fi 155 | 156 | if [ -n "$sizeWarn" ] && ! inrange "$sizeWarn" "$size"; then 157 | echo "WARNING: size $size_h|$stat" 158 | exit 1 159 | fi 160 | 161 | echo "OK: size $size_h, last modified $date|$stat" 162 | exit 0 163 | 164 | -------------------------------------------------------------------------------- /pkgs/check_aws_s3_file/check_aws_s3_file.conf: -------------------------------------------------------------------------------- 1 | object CheckCommand "aws-s3-file" { 2 | import "plugin-check-command" 3 | 4 | command = [ "check_aws_s3_file" ] 5 | 6 | arguments = { 7 | "-f" = "$aws_s3_file_credentials$" 8 | "-b" = "$aws_s3_file_bucket$" 9 | "-k" = "$aws_s3_file_key$" 10 | "-s" = "$aws_s3_file_size_warn$" 11 | "-S" = "$aws_s3_file_size_crit$" 12 | "-t" = "$aws_s3_file_age_warn$" 13 | "-T" = "$aws_s3_file_age_crit$" 14 | } 15 | vars.aws_s3_file_bucket = "$host.name$" 16 | vars.aws_s3_file_key = "$service.name$" 17 | } 18 | 19 | -------------------------------------------------------------------------------- /pkgs/check_aws_s3_file/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, pkgs, makeWrapper }: 2 | 3 | stdenv.mkDerivation { 4 | name = "check_aws_s3_file"; 5 | outputs = [ "out" "conf" ]; 6 | unpackPhase = ":"; 7 | nativeBuildInputs = [ makeWrapper ]; 8 | installPhase = '' 9 | mkdir -p $out/bin 10 | 11 | cp ${./check_aws_s3_file} $out/bin/check_aws_s3_file 12 | cp ${./check_aws_s3_file.conf} $conf 13 | 14 | chmod +x "$out/bin/"* 15 | 16 | substituteInPlace "$conf" \ 17 | --replace check_aws_s3_file "$out/bin/check_aws_s3_file" 18 | 19 | wrapProgram "$out/bin/check_aws_s3_file" \ 20 | --prefix PATH : "${pkgs.awscli}/bin:${pkgs.gnugrep}/bin:${pkgs.jq}/bin" 21 | ''; 22 | } 23 | -------------------------------------------------------------------------------- /pkgs/check_json/check_json: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | warn='' 6 | crit='' 7 | url='' 8 | query='.' 9 | title='' 10 | netrc='' 11 | name='value' 12 | unit='' 13 | 14 | usage() { 15 | cat < jq query, must return an integer (default: $query) 29 | -u URL to fetch 30 | 31 | -t short description of the parameter 32 | -p <name> name of the parameter (default: $name) 33 | -m <unit> unit of measure (default: $unit) 34 | 35 | -n <file> netrc file with credentials 36 | 37 | -w <spec> warning threshold 38 | -c <spec> critical threshold 39 | 40 | Examples: 41 | 42 | $0 -u example.com/errors_list -w 1 -c 4 -q '. | length' 43 | $0 -u example.net/counter -w 1:4 -m c 44 | 45 | USAGE 46 | } 47 | 48 | die () { 49 | echo "$0: " "$@" >&2 50 | exit 1 51 | } 52 | 53 | while [ $# -gt 0 ]; do 54 | case "$1" in 55 | -q) query="$2"; shift 2;; 56 | -u) url="$2"; shift 2;; 57 | -t) title="$2"; shift 2;; 58 | -p) name="$2"; shift 2;; 59 | -m) unit="$2"; shift 2;; 60 | -n) netrc="$2"; shift 2;; 61 | -w) warn="$2"; shift 2;; 62 | -c) crit="$2"; shift 2;; 63 | -h|--help) usage; exit 1;; 64 | *) die "unsupported argument: $1";; 65 | esac 66 | done 67 | 68 | inrange () { 69 | local r v 70 | local v1 v2 71 | local outter 72 | local sIFS 73 | 74 | r="$1" 75 | v="$2" 76 | 77 | case "$r" in 78 | @*) outter=true; r="${r/@/}";; 79 | *) outter=false;; 80 | esac 81 | 82 | sIFS=$IFS 83 | 84 | IFS=: 85 | set -- $r 86 | v1=${1-} 87 | v2=${2-} 88 | IFS=$sIFS 89 | 90 | case "$v1" in 91 | $r) v2=$v1; v1=0;; 92 | ~*) v1=;; 93 | esac 94 | 95 | if $outter; then 96 | { [ -n "$v1" ] && [ "$v" -le "$v1" ]; } || { [ -n "$v2" ] && [ "$v" -ge "$v2" ]; } 97 | else 98 | { [ -z "$v1" ] || [ "$v" -ge "$v1" ]; } && { [ -z "$v2" ] || [ "$v" -le "$v2" ]; } 99 | fi 100 | } 101 | 102 | [ -n "$url" ] || die "missing url" 103 | 104 | cmd=(curl --fail --silent --show-error --location) 105 | if [ -n "$netrc" ]; then 106 | cmd+=(--netrc-file "$netrc") 107 | fi 108 | cmd+=("$url") 109 | 110 | if ! out=$("${cmd[@]}" 2>&1); then 111 | printf 'UNKNOWN: %s\n' "$(echo "$out" | grep . | head -n 1)" 112 | exit 3 113 | fi 114 | 115 | json=$out 116 | 117 | if ! value=$(echo "$json" | jq -c -r "$query" 2>&1); then 118 | printf 'UNKNOWN: %s\n' "$(echo "$value" | grep . | head -n 1)" 119 | exit 3 120 | fi 121 | 122 | if [[ ! "$value" =~ ^[-+]?[0-9]+$ ]]; then 123 | echo "UNKNOWN: not an integer: $value" 124 | exit 3 125 | fi 126 | 127 | stat="$name=$value$unit;$warn;$crit" 128 | 129 | [ -n "$title" ] || title="some $name" 130 | text="$value - $title|$stat" 131 | 132 | if [ -n "$crit" ] && ! inrange "$crit" "$value"; then 133 | echo "CRITICAL: $text" 134 | exit 2 135 | fi 136 | 137 | if [ -n "$warn" ] && ! inrange "$warn" "$value"; then 138 | echo "WARNING: $text" 139 | exit 1 140 | fi 141 | 142 | echo "OK: $text" 143 | exit 0 144 | 145 | -------------------------------------------------------------------------------- /pkgs/check_json/check_json.conf: -------------------------------------------------------------------------------- 1 | object CheckCommand "http_json" { 2 | import "plugin-check-command" 3 | 4 | command = [ "check_json" ] 5 | 6 | arguments = { 7 | "-q" = "$http_json_query$" 8 | "-u" = "$http_json_url$" 9 | "-t" = "$http_json_title$" 10 | "-p" = "$http_json_name$" 11 | "-m" = "$http_json_unit$" 12 | "-n" = "$http_json_netrc$" 13 | "-w" = "$http_json_warn$" 14 | "-c" = "$http_json_crit$" 15 | } 16 | vars.http_json_title = "$service.name$" 17 | } 18 | 19 | -------------------------------------------------------------------------------- /pkgs/check_json/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, pkgs, makeWrapper }: 2 | 3 | stdenv.mkDerivation { 4 | name = "check_json"; 5 | outputs = [ "out" "conf" ]; 6 | unpackPhase = ":"; 7 | nativeBuildInputs = [ makeWrapper ]; 8 | installPhase = '' 9 | mkdir -p $out/bin 10 | 11 | cp ${./check_json} $out/bin/check_json 12 | cp ${./check_json.conf} $conf 13 | 14 | chmod +x "$out/bin/"* 15 | 16 | substituteInPlace "$conf" \ 17 | --replace check_json "$out/bin/check_json" 18 | 19 | wrapProgram "$out/bin/check_json" \ 20 | --prefix PATH : "${pkgs.curl.bin}/bin:${pkgs.gnugrep}/bin:${pkgs.jq}/bin" 21 | ''; 22 | } 23 | -------------------------------------------------------------------------------- /pkgs/check_mdstat/check_mdstat: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | stat=/proc/mdstat 4 | 5 | if [ ! -e "$stat" ]; then 6 | echo "WARNING: $stat does not exist" 7 | exit 1 8 | fi 9 | 10 | if [ ! -r "$stat" ]; then 11 | echo "WARNING: cannot read $stat" 12 | exit 1 13 | fi 14 | 15 | count=$(grep ^md -c "$stat") 16 | 17 | if [ "$count" -eq 0 ]; then 18 | echo 'WARNING: no arrays found.' 19 | exit 1 20 | elif [ "$count" -eq 1 ]; then 21 | out="Linux Software RAID: $count array" 22 | else 23 | out="Linux Software RAID: $count arrays" 24 | fi 25 | 26 | degrated=$(grep -c '\[.*_.*\]' "$stat") 27 | recovering=$(awk '/recovery/ {print $4}' "$stat") 28 | resyncing=$(awk '/resync/ {print $4}' "$stat") 29 | 30 | if [ -n "$recovering" ]; then 31 | out="$out, recovering: $recovering" 32 | elif [ -n "$resyncing" ]; then 33 | out="$out, resyncing: $resyncing" 34 | elif [ "$degrated" -gt 0 ]; then 35 | out="$out, degrated: $degrated" 36 | fi 37 | 38 | if [ "$degrated" -gt 0 ]; then 39 | echo "CRITICAL: $out." 40 | exit 2 41 | fi 42 | 43 | if [ -n "$recovering$resyncing" ]; then 44 | echo "WARNING: $out." 45 | exit 1 46 | fi 47 | 48 | echo "OK: $out." 49 | exit 0 50 | 51 | -------------------------------------------------------------------------------- /pkgs/check_mdstat/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, gawk, gnugrep }: 2 | 3 | stdenv.mkDerivation { 4 | name = "check_mdstat"; 5 | src = ./check_mdstat; 6 | outputs = [ "out" "conf" ]; 7 | unpackPhase = ":"; 8 | installPhase = '' 9 | mkdir -p $out/bin 10 | 11 | cp "$src" $out/bin/check_mdstat 12 | 13 | substituteInPlace "$out/bin/"* \ 14 | --replace awk '${gawk}/bin/awk' \ 15 | --replace grep '${gnugrep}/bin/grep' 16 | 17 | chmod +x "$out/bin/"* 18 | 19 | cat <<CONF > $conf 20 | object CheckCommand "mdstat" { 21 | import "plugin-check-command" 22 | command = [ "$out/bin/check_mdstat" ] 23 | } 24 | CONF 25 | ''; 26 | } 27 | -------------------------------------------------------------------------------- /pkgs/check_solr/cabal2nix.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, aeson, base, base64-bytestring, bytestring, docopt 2 | , fetchgit, HTTP, http-conduit, nagios-check, raw-strings-qq 3 | , regex-tdfa, scientific, stdenv, text, unordered-containers 4 | }: 5 | mkDerivation { 6 | pname = "check-solr"; 7 | version = "0.1.0"; 8 | src = fetchgit { 9 | url = "https://github.com/ip1981/check-solr.git"; 10 | sha256 = "0hama3kglnn4kyzkssl1llb61kcgyhynpbbk6xsf015hvi90hsa0"; 11 | rev = "869c945fb56f0ff187125ee352a6876002eba596"; 12 | }; 13 | isLibrary = true; 14 | isExecutable = true; 15 | libraryHaskellDepends = [ 16 | aeson base base64-bytestring bytestring docopt HTTP http-conduit 17 | nagios-check raw-strings-qq regex-tdfa scientific text 18 | unordered-containers 19 | ]; 20 | executableHaskellDepends = [ base docopt raw-strings-qq ]; 21 | description = "Icinga / Nagios plugin for Solr"; 22 | license = stdenv.lib.licenses.mit; 23 | } 24 | -------------------------------------------------------------------------------- /pkgs/check_solr/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, haskellPackages }: 2 | let 3 | 4 | haskellPackage = haskellPackages.callPackage ./cabal2nix.nix {}; 5 | 6 | in stdenv.mkDerivation { 7 | name = "check-solr-${haskellPackage.version}"; 8 | phases = [ "installPhase" ]; 9 | installPhase = '' 10 | mkdir -p $out/bin 11 | cp -a ${haskellPackage}/bin/* $out/bin/ 12 | ''; 13 | } 14 | -------------------------------------------------------------------------------- /pkgs/check_systemd/check_systemd: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | readarray -t failed < <( systemctl show '*.service' \ 6 | --state=failed --property=Names \ 7 | | sed -r -n 's,Names=(.+)\.service,\1,p' \ 8 | | sort 9 | ) 10 | 11 | if [ ${#failed[@]} -ne 0 ]; then 12 | printf -v list ', %s' "${failed[@]}" 13 | printf 'WARNING: %s failed\n' "${list:2}" 14 | exit 1 15 | else 16 | echo "OK: no failed services" 17 | exit 0 18 | fi 19 | 20 | 21 | -------------------------------------------------------------------------------- /pkgs/check_systemd/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, gnused }: 2 | 3 | stdenv.mkDerivation { 4 | name = "check_systemd"; 5 | src = ./check_systemd; 6 | outputs = [ "out" "conf" ]; 7 | unpackPhase = ":"; 8 | installPhase = '' 9 | mkdir -p $out/bin 10 | 11 | cp "$src" $out/bin/check_systemd 12 | 13 | substituteInPlace "$out/bin/"* \ 14 | --replace sed '${gnused}/bin/sed' 15 | 16 | chmod +x "$out/bin/"* 17 | 18 | cat <<CONF > $conf 19 | object CheckCommand "systemd" { 20 | import "plugin-check-command" 21 | command = [ "$out/bin/check_systemd" ] 22 | } 23 | CONF 24 | ''; 25 | } 26 | -------------------------------------------------------------------------------- /pkgs/default.nix: -------------------------------------------------------------------------------- 1 | self: super: 2 | let 3 | all = super.lib.attrNames ( 4 | super.lib.filterAttrs 5 | ( n: _: n != "default.nix" && ! super.lib.hasPrefix "." n ) 6 | (builtins.readDir ./.) 7 | ); 8 | in super.lib.listToAttrs (map (f: 9 | { name = super.lib.removeSuffix ".nix" f; 10 | value = super.callPackage (./. + "/${f}") {}; } 11 | ) all) 12 | 13 | -------------------------------------------------------------------------------- /pkgs/fakeSSL/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID4zCCAsugAwIBAgIJAL6M3P/DUPxZMA0GCSqGSIb3DQEBCwUAMIGHMQswCQYD 3 | VQQGEwJYWDESMBAGA1UECAwJTmV2ZXJob29kMRAwDgYDVQQHDAdDaXR5IDE3MRkw 4 | FwYDVQQKDBBIb3JucyBhbmQgaG9vdmVzMRYwFAYDVQQDDA0qLmV4YW1wbGUubmV0 5 | MR8wHQYJKoZIhvcNAQkBFhBmYWtlQGV4YW1wbGUubmV0MB4XDTE2MDQxOTA2MTc1 6 | NVoXDTE2MDUxOTA2MTc1NVowgYcxCzAJBgNVBAYTAlhYMRIwEAYDVQQIDAlOZXZl 7 | cmhvb2QxEDAOBgNVBAcMB0NpdHkgMTcxGTAXBgNVBAoMEEhvcm5zIGFuZCBob292 8 | ZXMxFjAUBgNVBAMMDSouZXhhbXBsZS5uZXQxHzAdBgkqhkiG9w0BCQEWEGZha2VA 9 | ZXhhbXBsZS5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGQ0pr 10 | esyupc80YSW3q9IM348QJqYwj2DrwSdPSZmToyFmYNz87SCBxT9B4pqQt7iXWaUq 11 | ZB1/3CAa8ErqcMg2rJg0QCIAVuzYpgdpBQaihvbH4InyUk6W+dxgRfwot275triD 12 | G36RxCCQAwR9J4dmb1EZqzRdnb8IAO9WoAvHsTD9yBoo0YzD1o0BeMScL2h0lelM 13 | NU+gQTEb37f8kLJVAxKHEj9soH1K0V2IcOtZKZuWAaAyffhP2BXDltBraOF3MqrV 14 | LMfhSgRhLazq6Zxy8BoMYUpKetzQVmR6tYbVVwL3XiyxY8JoDoQo9JO8mAdS0Slj 15 | JnQvbAIwc1PU14JrAgMBAAGjUDBOMB0GA1UdDgQWBBTXU8kHHsrUOm5CWWub5vQ6 16 | wa40zzAfBgNVHSMEGDAWgBTXU8kHHsrUOm5CWWub5vQ6wa40zzAMBgNVHRMEBTAD 17 | AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB+HNSaJG0MCbyCehGvfoPZg75KWDRbZuwQ 18 | MtJ19SMn1Z0QJ6CAWyqm6O3BPyCL77bQYej1I4lyWI1jsSCBzA+zXU9xtFcUdrxP 19 | ecB+pb1hgXDf9N08mF8R8HblT8Hcl7vnOOfs5cuu3K/KEiRM1cEknF1uog5+Jzha 20 | yFRAslphmSO+mC4ebdUnbqWzSxuiQFXXhplHMUksymBknPqUMXY7t6Bny2LuWeOe 21 | xHCNVcTQ3TA/Jkf/IbPYhW/WInfIxgBAyPHwEtkF+jhf9adIk4B7+VeNygCEmIeC 22 | 8EoBqcV0b5sLo7+15g0by8Cfs7hNfy/uBd9tcFw3R6K1Fekb9S+O 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /pkgs/fakeSSL/default.nix: -------------------------------------------------------------------------------- 1 | # Via openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -nodes 2 | { stdenv }: 3 | stdenv.mkDerivation { 4 | name = "fakeSSL"; 5 | phases = [ "installPhase" ]; 6 | installPhase = '' 7 | mkdir -p $out 8 | ln -sf ${./cert.pem} "$out/cert.pem" 9 | ln -sf ${./key.pem} "$out/key.pem" 10 | ''; 11 | } 12 | -------------------------------------------------------------------------------- /pkgs/fakeSSL/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDGQ0presyupc80 3 | YSW3q9IM348QJqYwj2DrwSdPSZmToyFmYNz87SCBxT9B4pqQt7iXWaUqZB1/3CAa 4 | 8ErqcMg2rJg0QCIAVuzYpgdpBQaihvbH4InyUk6W+dxgRfwot275triDG36RxCCQ 5 | AwR9J4dmb1EZqzRdnb8IAO9WoAvHsTD9yBoo0YzD1o0BeMScL2h0lelMNU+gQTEb 6 | 37f8kLJVAxKHEj9soH1K0V2IcOtZKZuWAaAyffhP2BXDltBraOF3MqrVLMfhSgRh 7 | Lazq6Zxy8BoMYUpKetzQVmR6tYbVVwL3XiyxY8JoDoQo9JO8mAdS0SljJnQvbAIw 8 | c1PU14JrAgMBAAECggEAFUa5YMlf18oxb0SRoKFOvFTtbGVJZmKsmwAycL7MPVy/ 9 | Q9ZXQMlNuL9rJ23i+m7M32keYWs3AzajN2DcGUabJcrl1o2fWHv7lNBUcT+50406 10 | RH7jLt8IUglkTeyUv+XXgfLK4D7+GTR77hh0zd2FGUgO4vtNdlJsYrZ++MPaH8bC 11 | xwCNQog5YDkOvMo4fYI88/Ih2HS+IHTK4BTqmHIRwZQh0D21SEGGueoYiQh0VMHU 12 | OrbfK8Nuvk2xRfxmBNHbFmEOA327v9RCmXRfOR/B2qhAmLH41NkEbBNwoWo+V4zu 13 | zU1ZQX/dWSuLIB4p4HD1m2039dFJSwdEMKXFnf1REQKBgQDl7EcbrWLwP4rWTwFH 14 | pfaiBeSlYcU+gSKnjxrkm4FcSstR27pKPeVpKEI+E/2WtYwjOZjPvUaIrETFzBGB 15 | +lbLZ1ZHqUn4+40kCdtGpoGHjPrcbdjSqPdN4URaxzWO/pI//c/QmnKOQROo+B90 16 | JgZVKcMGREgLLVHMLfHfN815iQKBgQDcv8Y3jdUwgJEzzxQbPPTfZV75DmpwqfOA 17 | Kc4n4ukJP8QYmQP227WxLyjuo1V4Ma2F4cZUYlbnS3jUJXghJwBmNLE9QmPo3c1i 18 | 4ZsaByV4gm/czDG1FJRK3OAk+EzV0AZODM5d4PT1XH3ZM3qrhgNe77IIEv5ULRH6 19 | BqgaPciDUwKBgQCmWkqkitGP09mm7yiU505Hsg3ZXqDwdUxWgWLKznxNA0ySIHFr 20 | r9bhO6CZ+6q5tQb8oXqfq2lyD3n+xoRQT4kmx9CULrb3r0FSNtNxDZ2gLm9+tvdu 21 | i5PKxFbJe2KT4Dp+lCwc2PJTXGBWG5feWHiye3HAgfzCIXsSSJe8kkpXSQKBgG4F 22 | xy15K4B5E+XWmBbbUtDlHWjUnoh4rDx8mZuXpL5PYdVArpEjAHPHJYeLMNYvLGVG 23 | GiuEt/ufyiEya6VaYwCN0qjNpi4yHmPiPgPC/BIMMOTDgSLXlvGZFL5YYzNN81aD 24 | W3e+31hLOQ5Acit7J8LxhLIxhUE/FW6gUriBgqaxAoGADuGUWEho5biRLUIKpue6 25 | VucCtNCs9XLfBWPm+o9SsaNFiUfDOJxDYlMVu9CRgTMt3ZElWkTngGuO36PQrm/E 26 | AQqCahV5OSagum60dEHB8hJWTdoujC5EFA/6b6OfQPi1N3s404UzC9p++9+57TvX 27 | T55OyyLwGCZO3tzA2p4Gpfg= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /pkgs/gpg.nix: -------------------------------------------------------------------------------- 1 | { gnupg }: 2 | gnupg.override { 3 | adns = null; 4 | libusb = null; 5 | openldap = null; 6 | pinentry = null; 7 | readline = null; 8 | guiSupport = false; 9 | } 10 | -------------------------------------------------------------------------------- /pkgs/hoogle/default.nix: -------------------------------------------------------------------------------- 1 | { haskell, haskellPackages }: 2 | 3 | let myHaskellPkgs = haskellPackages.override { 4 | overrides = self: super: { 5 | }; 6 | }; 7 | 8 | in haskell.lib.justStaticExecutables (myHaskellPkgs.callPackage ./main.nix {}) 9 | 10 | -------------------------------------------------------------------------------- /pkgs/hoogle/main.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, aeson, base, binary, bytestring, cmdargs, conduit 2 | , conduit-extra, connection, containers, deepseq, directory, extra 3 | , filepath, haskell-src-exts, http-conduit, http-types, js-flot 4 | , js-jquery, mmap, network, network-uri, old-locale, process 5 | , process-extras, QuickCheck, resourcet, stdenv, tar 6 | , template-haskell, text, time, transformers, uniplate, utf8-string 7 | , vector, wai, wai-logger, warp, warp-tls, zlib 8 | }: 9 | mkDerivation { 10 | pname = "hoogle"; 11 | version = "5.0.13"; 12 | sha256 = "1wxdzkifgm3bnpzr45sf49dyqwnb8bnc5wmqbv5yhxv19gmjk8kn"; 13 | isLibrary = true; 14 | isExecutable = true; 15 | libraryHaskellDepends = [ 16 | aeson base binary bytestring cmdargs conduit conduit-extra 17 | connection containers deepseq directory extra filepath 18 | haskell-src-exts http-conduit http-types js-flot js-jquery mmap 19 | network network-uri old-locale process process-extras QuickCheck 20 | resourcet tar template-haskell text time transformers uniplate 21 | utf8-string vector wai wai-logger warp warp-tls zlib 22 | ]; 23 | executableHaskellDepends = [ base ]; 24 | testTarget = "--test-option=--no-net"; 25 | homepage = "http://hoogle.haskell.org/"; 26 | description = "Haskell API Search"; 27 | license = stdenv.lib.licenses.bsd3; 28 | } 29 | -------------------------------------------------------------------------------- /pkgs/hyperic-sigar/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl, ant, jdk, perl }: 2 | 3 | stdenv.mkDerivation rec { 4 | name = "hyperic-sigar-${version}"; 5 | version = "1.6.4"; 6 | 7 | src = fetchurl { 8 | url = "https://github.com/hyperic/sigar/archive/sigar-${version}.tar.gz"; 9 | sha256 = "0bh5l1wzmv464v3np5zjb59d7i0vbk9ciy71683fa43yxg0h96qp"; 10 | }; 11 | 12 | nativeBuildInputs = [ ant jdk perl ]; 13 | buildInputs = [ ]; 14 | 15 | configurePhase = ":"; 16 | 17 | buildPhase = '' 18 | cd bindings/java 19 | ant build 20 | ''; 21 | 22 | installPhase = '' 23 | mkdir -p $out/{lib/jni,share/java} 24 | cp sigar-bin/lib/sigar.jar $out/share/java/ 25 | cp sigar-bin/lib/libsigar-* $out/lib/jni/ 26 | ''; 27 | 28 | meta = with stdenv.lib; { 29 | description = "System Information Gatherer And Reporter"; 30 | license = licenses.asl20; 31 | platforms = platforms.unix; 32 | }; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /pkgs/icinga2/check_mysql_slave.patch: -------------------------------------------------------------------------------- 1 | Index: icinga2-2.4.1/itl/command-plugins.conf 2 | =================================================================== 3 | --- icinga2-2.4.1.orig/itl/command-plugins.conf 4 | +++ icinga2-2.4.1/itl/command-plugins.conf 5 | @@ -1775,6 +1775,36 @@ object CheckCommand "mysql" { 6 | vars.mysql_hostname = "$check_address$" 7 | } 8 | 9 | +object CheckCommand "mysql_slave" { 10 | + import "plugin-check-command" 11 | + import "ipv4-or-ipv6" 12 | + 13 | + command = [ PluginDir + "/check_mysql_slave" ] 14 | + 15 | + arguments = { 16 | + "-H" = "$mysql_hostname$" 17 | + "-P" = "$mysql_port$" 18 | + "-s" = "$mysql_socket$" 19 | + "-f" = "$mysql_file$" 20 | + "-g" = "$mysql_group$" 21 | + "-u" = "$mysql_username$" 22 | + "-p" = "$mysql_password$" 23 | + "-N" = "$mysql_connection_name$" 24 | + "-w" = "$mysql_warning$" 25 | + "-c" = "$mysql_critical$" 26 | + "-l" = { 27 | + set_if = "$mysql_ssl$" 28 | + } 29 | + "-C" = "$mysql_cacert$" 30 | + "-a" = "$mysql_cert$" 31 | + "-k" = "$mysql_key$" 32 | + "-D" = "$mysql_cadir$" 33 | + "-L" = "$mysql_ciphers$" 34 | + } 35 | + 36 | + vars.mysql_hostname = "$check_address$" 37 | +} 38 | + 39 | object CheckCommand "negate" { 40 | import "plugin-check-command" 41 | 42 | -------------------------------------------------------------------------------- /pkgs/icinga2/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl 2 | , bison, boost, cmake, flex 3 | , libedit, mariadb, postgresql 4 | , openssl, yajl, pkgconfig 5 | , makeWrapper 6 | }: 7 | 8 | stdenv.mkDerivation rec { 9 | version = "2.10.1"; 10 | name = "icinga2-${version}"; 11 | 12 | src = fetchurl { 13 | url = "https://github.com/Icinga/icinga2/archive/v${version}.tar.gz"; 14 | sha256 = "0hwpf080w7y4lhw7fl71npf2dscnqnccsii1iqibqb46g3cxqalk"; 15 | }; 16 | 17 | buildInputs = [ 18 | bison boost cmake flex libedit makeWrapper mariadb.client openssl 19 | pkgconfig postgresql yajl 20 | ]; 21 | 22 | patches = [ 23 | ./check_mysql_slave.patch 24 | ]; 25 | 26 | cmakeFlags = [ 27 | "-DCMAKE_INSTALL_LOCALSTATEDIR=/icinga2" 28 | "-DCMAKE_INSTALL_SYSCONFDIR=/icinga2/etc" # this will need runtime support 29 | "-DICINGA2_COMMAND_GROUP=icingacmd" 30 | "-DICINGA2_GROUP=icinga" 31 | "-DICINGA2_RUNDIR=/run" 32 | "-DICINGA2_USER=icinga" 33 | "-DMYSQL_INCLUDE_DIR=${mariadb.client.dev}/include/mysql" 34 | ]; 35 | 36 | # XXX Without DESTDIR it tries to write to /icinga2 and /run: 37 | installPhase = '' 38 | rm -rf tmp 39 | mkdir -p tmp 40 | make install DESTDIR=$(pwd)/tmp 41 | mv -v tmp/$out $out 42 | mv -v tmp/icinga2 $out/icinga2 43 | 44 | rm -rvf \ 45 | $out/icinga2/cache \ 46 | $out/icinga2/etc/icinga2/features-enabled \ 47 | $out/icinga2/etc/init.d \ 48 | $out/icinga2/etc/logrotate.d \ 49 | $out/icinga2/log \ 50 | $out/icinga2/spool \ 51 | $out/run \ 52 | $out/share/doc/icinga2/markdown 53 | 54 | for s in $out/icinga2/etc/icinga2/scripts/* ; do 55 | substituteInPlace $s --replace /usr/bin/printf printf 56 | done 57 | 58 | wrapProgram $out/lib/icinga2/sbin/icinga2 \ 59 | --prefix LD_LIBRARY_PATH : $out/lib/icinga2 60 | 61 | rm -vf $out/sbin/icinga2 62 | ln -svf $out/lib/icinga2/sbin/icinga2 $out/sbin/icinga2 63 | test -x $out/sbin/icinga2 64 | ''; 65 | 66 | buildPhase = '' 67 | make VERBOSE=1 68 | ''; 69 | } 70 | -------------------------------------------------------------------------------- /pkgs/icingaweb2/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl 2 | , php 3 | }: 4 | 5 | stdenv.mkDerivation rec { 6 | version = "2.6.0"; 7 | name = "icingaweb2-${version}"; 8 | 9 | src = fetchurl { 10 | url = "https://github.com/Icinga/icingaweb2/archive/v${version}.tar.gz"; 11 | sha256 = "1m0gi8zbrag4jwdcqicq5bb3s07z7kz0fg41a22cbqlgx6adivaa"; 12 | }; 13 | 14 | patches = [ 15 | ./sproxy.patch 16 | ]; 17 | 18 | buildPhase = "true"; 19 | 20 | installPhase = '' 21 | mkdir -p $out 22 | cp -a * $out 23 | 24 | cd $out 25 | rm -rvf \ 26 | .??* \ 27 | Vagrantfile \ 28 | icingaweb2.spec \ 29 | modules/doc \ 30 | modules/setup \ 31 | modules/test \ 32 | modules/translation \ 33 | packages \ 34 | test 35 | ''; 36 | } 37 | -------------------------------------------------------------------------------- /pkgs/icingaweb2/sproxy.patch: -------------------------------------------------------------------------------- 1 | From 64d9685260f93b5c2f18cc7abbc862575e5b2904 Mon Sep 17 00:00:00 2001 2 | From: Igor Pashev <pashev.igor@gmail.com> 3 | Date: Thu, 19 Apr 2018 13:27:24 +0300 4 | Subject: [PATCH] Add Sproxy backend 5 | 6 | --- 7 | .../Icinga/Authentication/User/SproxyBackend.php | 51 ++++++++++++++++++++++ 8 | library/Icinga/Authentication/User/UserBackend.php | 6 +++ 9 | 2 files changed, 57 insertions(+) 10 | create mode 100644 library/Icinga/Authentication/User/SproxyBackend.php 11 | 12 | diff --git a/library/Icinga/Authentication/User/SproxyBackend.php b/library/Icinga/Authentication/User/SproxyBackend.php 13 | new file mode 100644 14 | index 0000000000..f36c362374 15 | --- /dev/null 16 | +++ b/library/Icinga/Authentication/User/SproxyBackend.php 17 | @@ -0,0 +1,51 @@ 18 | +<?php 19 | +/* 2016 Zalora South East Asia Pte. Ltd | GPLv2+ */ 20 | + 21 | +namespace Icinga\Authentication\User; 22 | + 23 | +use Icinga\Data\ConfigObject; 24 | +use Icinga\User; 25 | + 26 | +/** 27 | + * Login with Sproxy authentication mechanism. 28 | + * This is similar to the "external" backend. 29 | + * 30 | + * Sproxy provides at least two HTTP headers: 31 | + * 32 | + * "From" - the user's email address. 33 | + * "X-Groups" - a comma-separated list of the user's groups. 34 | + * 35 | + * 36 | + * See <https://hackage.haskell.org/package/sproxy2>, 37 | + * or <https://github.com/ip1981/sproxy2>, 38 | + * or <https://gitlab.com/ip1981/sproxy2>, 39 | + * or <https://bitbucket.org/IgorPashev/sproxy2>. 40 | + */ 41 | +class SproxyBackend extends ExternalBackend 42 | +{ 43 | + /** 44 | + * {@inheritdoc} 45 | + */ 46 | + public function authenticate(User $user, $password = null) 47 | + { 48 | + if (! empty($_SERVER['HTTP_FROM'])) { 49 | + $email = $_SERVER['HTTP_FROM']; 50 | + $user->setUsername($email); 51 | + $user->setEmail($email); 52 | + $user->setExternalUserInformation($email, 'HTTP_FROM'); 53 | + 54 | + if (! empty($_SERVER['HTTP_X_GIVEN_NAME'])) { 55 | + $user->setFirstname($_SERVER['HTTP_X_GIVEN_NAME']); 56 | + } 57 | + if (! empty($_SERVER['HTTP_X_GROUPS'])) { 58 | + $user->setGroups(explode(',', $_SERVER['HTTP_X_GROUPS'])); 59 | + } 60 | + if (! empty($_SERVER['HTTP_X_FAMILY_NAME'])) { 61 | + $user->setLastname($_SERVER['HTTP_X_FAMILY_NAME']); 62 | + } 63 | + 64 | + return true; 65 | + } 66 | + return false; 67 | + } 68 | +} 69 | diff --git a/library/Icinga/Authentication/User/UserBackend.php b/library/Icinga/Authentication/User/UserBackend.php 70 | index 8130c56cde..366b84fd4f 100644 71 | --- a/library/Icinga/Authentication/User/UserBackend.php 72 | +++ b/library/Icinga/Authentication/User/UserBackend.php 73 | @@ -22,6 +22,7 @@ class UserBackend implements ConfigAwareFactory 74 | * @var array 75 | */ 76 | protected static $defaultBackends = array( 77 | + 'sproxy', 78 | 'external', 79 | 'db', 80 | 'ldap', 81 | @@ -176,6 +177,11 @@ public static function create($name, ConfigObject $backendConfig = null) 82 | $backend->setName($name); 83 | return $backend; 84 | } 85 | + if ($backendType === 'sproxy') { 86 | + $backend = new SproxyBackend($backendConfig); 87 | + $backend->setName($name); 88 | + return $backend; 89 | + } 90 | if (in_array($backendType, static::$defaultBackends)) { 91 | // The default backend check is the first one because of performance reasons: 92 | // Do not attempt to load a custom user backend unless it's actually required 93 | -------------------------------------------------------------------------------- /pkgs/jenkins.nix: -------------------------------------------------------------------------------- 1 | { jenkinsWithPlugins }: jenkinsWithPlugins (_: {}) 2 | -------------------------------------------------------------------------------- /pkgs/jenkinsUpdateCenter/default.nix: -------------------------------------------------------------------------------- 1 | {}: 2 | 3 | /* 4 | This package exists to override Jenkins easily. 5 | You override this package instead of jenkinsWithPlugins. 6 | You even can fetch from Jenkins site directly. 7 | */ 8 | 9 | 10 | /* 11 | jq to make it human readable: 12 | curl https://updates.jenkins-ci.org/current/update-center.actual.json | jq . > update-center.actual.json 13 | */ 14 | 15 | 16 | # capture into nix store to track changes: 17 | "${./update-center.actual.json}" 18 | -------------------------------------------------------------------------------- /pkgs/jenkinsWithPlugins/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, lib, stdenv, fetchurl }: 2 | 3 | /* 4 | 5 | `pluginsFunc` is a function that should return an attribute set of plugins 6 | to be included in the WAR. 7 | 8 | The plugins are provided by `pkgs.jenkinsUpdateCenter.plugins`. 9 | Dependencies between those plugins are automatically resolved within the 10 | same jenkinsUpdateCenter. 11 | 12 | Example: 13 | 14 | pkgs.jenkinsWithPlugins 15 | (plugins: { 16 | inherit (plugins) BlameSubversion ... ; 17 | inherit (pkgs) my-plugin; 18 | }) 19 | 20 | Each attribute of `plugins` is a derivation and you can return in 21 | the set any other plugins that are not available in Jenkins registry 22 | (https://updates.jenkins-ci.org/) or replacing plugins in the registry. 23 | 24 | Non-optional dependencies, if any, are automatically added. Optional 25 | dependencies are ignored, you have to add them explicitly. 26 | 27 | */ 28 | 29 | pluginsFunc: 30 | 31 | let 32 | 33 | inherit (builtins) 34 | attrNames fromJSON readFile ; 35 | 36 | inherit (lib) 37 | concatStrings filter filterAttrs flatten genAttrs mapAttrs 38 | mapAttrsToList unique ; 39 | 40 | fromBase64 = import ./fromBase64.nix; 41 | 42 | updateCenter = 43 | let 44 | registry = fromJSON (readFile pkgs.jenkinsUpdateCenter); 45 | in 46 | registry // { 47 | core = with registry.core; fetchurl { 48 | inherit url; 49 | name = "jenkins-core-${version}.war"; 50 | sha1 = fromBase64 sha1; 51 | meta = registry.core; 52 | }; 53 | 54 | plugins = mapAttrs ( 55 | _: plugin: fetchurl { 56 | inherit (plugin) url; 57 | sha1 = fromBase64 plugin.sha1; 58 | name = "jenkins-plugin-${plugin.name}-${plugin.version}.hpi"; 59 | meta = plugin; 60 | } 61 | ) registry.plugins; 62 | }; 63 | 64 | inherit (updateCenter) core; 65 | 66 | neededPlugins = 67 | let 68 | rootPlugins = pluginsFunc updateCenter.plugins; 69 | hasDeps = _: p: (p ? meta) && (p.meta ? dependencies); 70 | directDeps = nn: 71 | let 72 | isRequired = d: ! (d ? optional && d.optional); 73 | deps = p: map (d: d.name) (filter isRequired p.meta.dependencies); 74 | in flatten (map (n: deps updateCenter.plugins.${n}) nn); 75 | 76 | getDepsRecursive = nn: if nn == [] then [] else nn ++ getDepsRecursive (directDeps nn); 77 | depNames = unique (getDepsRecursive (attrNames (filterAttrs hasDeps rootPlugins))); 78 | deps = genAttrs depNames (n: updateCenter.plugins.${n}); 79 | in deps // rootPlugins; 80 | 81 | pluginsPack = stdenv.mkDerivation { 82 | name = "jenkins-plugins-pack"; 83 | phases = [ "installPhase" ]; 84 | installPhase = '' 85 | mkdir -p $out 86 | ${concatStrings ( 87 | mapAttrsToList (n: p: '' 88 | ln -svf '${p}' "$out/${n}.hpi" 89 | '') neededPlugins)} 90 | ''; 91 | }; 92 | 93 | pack = stdenv.mkDerivation rec { 94 | name = "jenkins-${core.meta.version}+plugins.war"; 95 | 96 | # https://wiki.jenkins-ci.org/display/JENKINS/Bundling+plugins+with+Jenkins 97 | build-xml = pkgs.writeXML "jenkins.build.xml" 98 | '' 99 | <?xml version="1.0" encoding="UTF-8"?> 100 | <project basedir="." name="Jenkins-Bundle"> 101 | <target name="bundle" description="Merge plugins into jenkins.war"> 102 | <zip destfile="jenkins.war" level="9"> 103 | <zipfileset src="${core}" /> 104 | <zipfileset dir="${pluginsPack}" prefix="WEB-INF/plugins" /> 105 | </zip> 106 | </target> 107 | </project> 108 | ''; 109 | 110 | meta = with stdenv.lib; { 111 | description = "An extendable open source continuous integration server"; 112 | homepage = http://jenkins-ci.org; 113 | license = licenses.mit; 114 | platforms = platforms.all; 115 | }; 116 | 117 | buildInputs = with pkgs; [ ant jdk ]; 118 | 119 | phases = [ "buildPhase" "installPhase" ]; 120 | buildPhase = '' 121 | ln -sf ${build-xml} build.xml 122 | ant bundle 123 | ''; 124 | installPhase = "cp jenkins.war $out"; 125 | }; 126 | 127 | in if neededPlugins == [] then core else pack 128 | 129 | -------------------------------------------------------------------------------- /pkgs/jenkinsWithPlugins/fromBase64.nix: -------------------------------------------------------------------------------- 1 | strBase64: 2 | 3 | let 4 | 5 | inherit (builtins) 6 | concatStringsSep genList stringLength substring trace ; 7 | 8 | base64 = { 9 | # n=0; for l in {A..Z} {a..z} {0..9} + /; do printf '"%s" = %2s; ' $l $n; (( n++ )); (( n % 8 )) || echo; done 10 | "A" = 0; "B" = 1; "C" = 2; "D" = 3; "E" = 4; "F" = 5; "G" = 6; "H" = 7; 11 | "I" = 8; "J" = 9; "K" = 10; "L" = 11; "M" = 12; "N" = 13; "O" = 14; "P" = 15; 12 | "Q" = 16; "R" = 17; "S" = 18; "T" = 19; "U" = 20; "V" = 21; "W" = 22; "X" = 23; 13 | "Y" = 24; "Z" = 25; "a" = 26; "b" = 27; "c" = 28; "d" = 29; "e" = 30; "f" = 31; 14 | "g" = 32; "h" = 33; "i" = 34; "j" = 35; "k" = 36; "l" = 37; "m" = 38; "n" = 39; 15 | "o" = 40; "p" = 41; "q" = 42; "r" = 43; "s" = 44; "t" = 45; "u" = 46; "v" = 47; 16 | "w" = 48; "x" = 49; "y" = 50; "z" = 51; "0" = 52; "1" = 53; "2" = 54; "3" = 55; 17 | "4" = 56; "5" = 57; "6" = 58; "7" = 59; "8" = 60; "9" = 61; "+" = 62; "/" = 63; 18 | }; 19 | 20 | quartet_to_int24 = q: 21 | # https://en.wikipedia.org/wiki/Base64 22 | let 23 | s = n: assert (stringLength q == 4); substring (3 - n) 1 q; 24 | d = n: base64.${s n}; 25 | in if s 0 != "=" then 26 | 64 * (64 * (64 * (d 3) + (d 2)) + (d 1)) + (d 0) 27 | else if s 1 != "=" then 28 | 64 * (64 * (64 * (d 3) + (d 2)) + (d 1)) / 256 # right shift by 8 bits 29 | else 30 | 64 * (64 * (64 * (d 3) + (d 2))) / 65536 # right shift by 16 bits 31 | ; 32 | 33 | int24_to_hex = i: # 16777215 (0xFFFFFF, 2^24-1) max 34 | let 35 | hex = "0123456789abcdef"; 36 | toHex = n: 37 | let 38 | d = n / 16; 39 | r = n - 16 * d; 40 | in "${if d != 0 then toHex d else ""}${substring r 1 hex}"; 41 | in assert (0 <= i && i <= 16777215); toHex i; 42 | 43 | quartets = s: 44 | let 45 | l = stringLength s; 46 | h = substring 0 4 s; 47 | t = substring 4 (l - 4) s; 48 | in [h] ++ (if t != "" then quartets t else []); 49 | 50 | 51 | quartet_to_hex = q: # base64 quartet into hex with padding 52 | let 53 | i = quartet_to_int24 q; 54 | h = int24_to_hex i; 55 | s = if substring 2 1 q == "=" then 1 56 | else if substring 3 1 q == "=" then 2 57 | else 3; # number of bytes 58 | w = s * 2; # number of hexadecimal digits 59 | filler = concatStringsSep "" (genList (_: "0") (w - stringLength h)); 60 | in "${filler}${h}"; 61 | 62 | /* 63 | 64 | FIXME: usage of library functions like concatMapString 65 | causes very cryptic errors: 66 | 67 | # nix-instantiate --eval --expr 'import ./fromBase64.nix "kjOzmCPxyw0bPciMsGSh5q+bT9g="' --show-trace 68 | error: while evaluating anonymous function at .../fromBase64.nix:1:1, called from (string):1:18: 69 | value is a function while a set was expected, at .../fromBase64.nix:3:4 70 | 71 | */ 72 | 73 | in concatStringsSep "" (map quartet_to_hex (quartets strBase64)) 74 | 75 | -------------------------------------------------------------------------------- /pkgs/juandelacosa/default.nix: -------------------------------------------------------------------------------- 1 | { haskell, haskellPackages }: 2 | 3 | let myHaskellPkgs = haskellPackages.override { 4 | overrides = self: super: { 5 | mysql = haskell.lib.dontCheck super.mysql; 6 | mysql-simple = haskell.lib.dontCheck super.mysql-simple; 7 | }; 8 | }; 9 | 10 | in myHaskellPkgs.callPackage ./main.nix { } 11 | 12 | -------------------------------------------------------------------------------- /pkgs/juandelacosa/main.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, base64-bytestring, bytestring 2 | , data-default-class, docopt, entropy, fast-logger, http-types 3 | , interpolatedstring-perl6, mtl, mysql, mysql-simple, network 4 | , resource-pool, scotty, stdenv, text, unix, wai, wai-extra 5 | , wai-middleware-static, warp 6 | }: 7 | mkDerivation { 8 | pname = "juandelacosa"; 9 | version = "0.1.1"; 10 | sha256 = "060zq739i3xhr7w448p460r7x3jyyzf7pn61abp7f9g8vjn6vqw7"; 11 | isLibrary = false; 12 | isExecutable = true; 13 | executableHaskellDepends = [ 14 | base base64-bytestring bytestring data-default-class docopt entropy 15 | fast-logger http-types interpolatedstring-perl6 mtl mysql 16 | mysql-simple network resource-pool scotty text unix wai wai-extra 17 | wai-middleware-static warp 18 | ]; 19 | description = "Manage users in MariaDB >= 10.1.1"; 20 | license = stdenv.lib.licenses.mit; 21 | } 22 | -------------------------------------------------------------------------------- /pkgs/kibana5/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl }: 2 | 3 | stdenv.mkDerivation rec { 4 | name = "kibana-${version}.tar.xz"; 5 | version = "5.0.2"; 6 | 7 | # JS is a realm of sorrow. node2nix, npm2nix failed to package kibana 8 | # mostly because of npm and its registry being dumb beasts. 9 | # Instead, we are loading prebuild package. It's arch-dependent 10 | # only for bundled Node.JS binary (sic!). We remove it, and use our own. 11 | # This also makes it easier to patch the whole thing when needed. 12 | # Even worse: kibana can't run from a read-only directory. 13 | # So we will keep it in a tarball and extract before running. 14 | # Essentially it's like Java's WAR archives. 15 | src = fetchurl { 16 | url = "https://artifacts.elastic.co/downloads/kibana/kibana-${version}-linux-x86_64.tar.gz"; 17 | sha1 = "c68eb5d3397a0afb7132630f120b1d53724a2fd9"; 18 | }; 19 | 20 | phases = [ "unpackPhase" "installPhase" ]; 21 | 22 | installPhase = '' 23 | rm -r node bin 24 | tar cJf $out --transform 's,^,kibana-${version}/,' * 25 | ''; 26 | 27 | meta = { 28 | description = "Visualize logs and time-stamped data"; 29 | homepage = http://www.elasticsearch.org/overview/kibana; 30 | license = stdenv.lib.licenses.asl20; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /pkgs/ldapply/default.nix: -------------------------------------------------------------------------------- 1 | { haskell, haskellPackages }: 2 | 3 | let myHaskellPkgs = haskellPackages.override { 4 | overrides = self: super: { 5 | LDAP = self.callPackage ./ldap.nix { }; # Version with ldapExternalSaslBind 6 | ldif = haskell.lib.dontCheck super.ldif; # requires ancient HUnit == 1.2.* 7 | }; 8 | }; 9 | 10 | in myHaskellPkgs.callPackage ./main.nix { } 11 | 12 | -------------------------------------------------------------------------------- /pkgs/ldapply/ldap.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, HUnit, cyrus_sasl, openldap, stdenv }: 2 | mkDerivation { 3 | pname = "LDAP"; 4 | version = "0.6.11"; 5 | doCheck = false; # XXX: missing file in tarball 6 | sha256 = "1cwh3272zi5r0zznmixghf87vskz7s35bmz6ifyky0xk3s04ijq1"; 7 | libraryHaskellDepends = [ base ]; 8 | librarySystemDepends = [ cyrus_sasl openldap ]; 9 | testHaskellDepends = [ base HUnit ]; 10 | testSystemDepends = [ openldap ]; 11 | homepage = "https://github.com/ezyang/ldap-haskell"; 12 | description = "Haskell binding for C LDAP API"; 13 | license = stdenv.lib.licenses.bsd3; 14 | } 15 | -------------------------------------------------------------------------------- /pkgs/ldapply/main.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, bytestring, docopt, interpolatedstring-perl6 2 | , LDAP, ldif, stdenv, unordered-containers 3 | }: 4 | mkDerivation { 5 | pname = "ldapply"; 6 | version = "0.2.0"; 7 | sha256 = "0qgpb22k9krdhwjydzyfhjf85crxc49ss7x74mrqj8ivkzg5hl28"; 8 | isLibrary = false; 9 | isExecutable = true; 10 | executableHaskellDepends = [ 11 | base bytestring docopt interpolatedstring-perl6 LDAP ldif 12 | unordered-containers 13 | ]; 14 | description = "LDIF idempotent apply tool"; 15 | license = stdenv.lib.licenses.mit; 16 | } 17 | -------------------------------------------------------------------------------- /pkgs/mariadb_10_1/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl, cmake, pkgconfig, ncurses, zlib, xz, lzo, lz4, bzip2, snappy 2 | , openssl, boost, judy, bison, libxml2 3 | , libaio, libevent, groff, jemalloc, cracklib, systemd, numactl, perl 4 | }: 5 | 6 | with stdenv.lib; 7 | 8 | let # in mariadb # spans the whole file 9 | 10 | mariadb = everything // { 11 | inherit client; # libmysqlclient.so in .out, necessary headers in .dev and utils in .bin 12 | server = everything; # a full single-output build, including everything in `client` again 13 | lib = client; # compat. with the old mariadb split 14 | }; 15 | 16 | common = rec { # attributes common to both builds 17 | version = "10.1.30"; 18 | 19 | src = fetchurl { 20 | url = "https://downloads.mariadb.org/interstitial/mariadb-${version}/source/mariadb-${version}.tar.gz"; 21 | sha256 = "123ck7q5lk535qm8i5b0gk1pc5j9k1f9pl1vki30m7l14id5wfhp"; 22 | }; 23 | 24 | prePatch = '' 25 | substituteInPlace cmake/libutils.cmake \ 26 | --replace /usr/bin/libtool libtool 27 | sed -i 's,[^"]*/var/log,/var/log,g' storage/mroonga/vendor/groonga/CMakeLists.txt 28 | ''; 29 | 30 | nativeBuildInputs = [ cmake pkgconfig ]; 31 | 32 | buildInputs = [ ncurses openssl zlib jemalloc libaio systemd ]; 33 | 34 | cmakeFlags = [ 35 | "-DBUILD_CONFIG=mysql_release" 36 | "-DMANUFACTURER=NixSap" 37 | "-DDEFAULT_CHARSET=utf8" 38 | "-DDEFAULT_COLLATION=utf8_general_ci" 39 | "-DSECURITY_HARDENED=ON" 40 | 41 | "-DMYSQL_UNIX_ADDR=/run/mysqld/mysqld.sock" 42 | "-DINSTALL_MYSQLSHAREDIR=share/mysql" 43 | 44 | "-DWITH_ZLIB=system" 45 | "-DWITH_SSL=system" 46 | "-DWITH_PCRE=auto" 47 | 48 | ] 49 | ; 50 | 51 | preConfigure = '' 52 | cmakeFlags="$cmakeFlags -DINSTALL_INCLUDEDIR=''${!outputDev}/include/mysql" 53 | ''; 54 | 55 | postInstall = '' 56 | rm "$out"/lib/*.a 57 | find "''${!outputBin}/bin" -name '*test*' -delete 58 | ''; 59 | 60 | passthru.mysqlVersion = "5.6"; 61 | }; 62 | 63 | 64 | client = stdenv.mkDerivation (common // { 65 | name = "mariadb-client-${common.version}"; 66 | 67 | outputs = [ "bin" "dev" "out" ]; 68 | 69 | propagatedBuildInputs = [ openssl zlib ]; # required from mariadb.pc 70 | 71 | cmakeFlags = common.cmakeFlags ++ [ 72 | "-DWITHOUT_SERVER=ON" 73 | ]; 74 | 75 | preConfigure = common.preConfigure + '' 76 | cmakeFlags="$cmakeFlags \ 77 | -DINSTALL_BINDIR=$bin/bin -DINSTALL_SCRIPTDIR=$bin/bin \ 78 | -DINSTALL_SUPPORTFILESDIR=$bin/share/mysql \ 79 | -DINSTALL_DOCDIR=$bin/share/doc/mysql -DINSTALL_DOCREADMEDIR=$bin/share/doc/mysql \ 80 | " 81 | ''; 82 | 83 | # prevent cycle; it needs to reference $dev 84 | postInstall = common.postInstall + '' 85 | moveToOutput bin/mysql_config "$dev" 86 | ''; 87 | 88 | enableParallelBuilding = true; # the client should be OK 89 | }); 90 | 91 | 92 | everything = stdenv.mkDerivation (common // { 93 | name = "mariadb-${common.version}"; 94 | 95 | patches = [ 96 | ]; 97 | 98 | nativeBuildInputs = common.nativeBuildInputs ++ [ bison ]; 99 | 100 | buildInputs = common.buildInputs ++ [ 101 | xz lzo lz4 bzip2 snappy 102 | libxml2 boost judy libevent cracklib 103 | ] 104 | ++ optionals (stdenv.isLinux && !stdenv.isArm) [ numactl ] 105 | ; 106 | 107 | cmakeFlags = common.cmakeFlags ++ [ 108 | "-DMYSQL_DATADIR=/var/lib/mysql" 109 | "-DINSTALL_SYSCONFDIR=etc/mysql" 110 | "-DINSTALL_INFODIR=share/mysql/docs" 111 | "-DINSTALL_MANDIR=share/man" 112 | "-DINSTALL_PLUGINDIR=lib/mysql/plugin" 113 | "-DINSTALL_SCRIPTDIR=bin" 114 | "-DINSTALL_SUPPORTFILESDIR=share/mysql" 115 | "-DINSTALL_DOCREADMEDIR=share/doc/mysql" 116 | "-DINSTALL_DOCDIR=share/doc/mysql" 117 | "-DINSTALL_SHAREDIR=share/mysql" 118 | 119 | "-DENABLED_LOCAL_INFILE=ON" 120 | "-DWITH_READLINE=ON" 121 | "-DWITH_EXTRA_CHARSETS=complex" 122 | "-DWITH_EMBEDDED_SERVER=ON" 123 | "-DWITH_ARCHIVE_STORAGE_ENGINE=1" 124 | "-DWITH_BLACKHOLE_STORAGE_ENGINE=1" 125 | "-DWITH_INNOBASE_STORAGE_ENGINE=1" 126 | "-DWITH_PARTITION_STORAGE_ENGINE=1" 127 | "-DWITHOUT_EXAMPLE_STORAGE_ENGINE=1" 128 | "-DWITHOUT_FEDERATED_STORAGE_ENGINE=1" 129 | "-DWITH_WSREP=ON" 130 | ]; 131 | 132 | postInstall = common.postInstall + '' 133 | rm -r "$out"/{mysql-test,sql-bench,data} # Don't need testing data 134 | rm "$out"/share/man/man1/mysql-test-run.pl.1 135 | 136 | # Don't install mysqlbug to prevent a dependency on gcc. 137 | rm $out/bin/mysqlbug 138 | ''; 139 | }); 140 | 141 | in mariadb 142 | 143 | -------------------------------------------------------------------------------- /pkgs/mathJax.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl }: 2 | 3 | stdenv.mkDerivation rec { 4 | version = "2.6.1"; 5 | name = "mathjax-${version}"; 6 | 7 | src = fetchurl { 8 | url = "https://github.com/mathjax/MathJax/archive/${version}.tar.gz"; 9 | sha256 = "1f7v48s7km9fi9i0bignn8f91z3bk04n4jx407l3xsd4hxfr8in7"; 10 | }; 11 | 12 | installPhase = '' 13 | mkdir -p $out 14 | cp -a * $out/ 15 | rm -rf $out/unpacked 16 | rm -rf "$out/"*.json 17 | ''; 18 | } 19 | -------------------------------------------------------------------------------- /pkgs/mediawiki/T122487.patch: -------------------------------------------------------------------------------- 1 | Description: fix warning on upload page 2 | Bug: https://phabricator.wikimedia.org/T122487 3 | Index: mediawiki-1.23.13/includes/User.php 4 | =================================================================== 5 | --- mediawiki-1.23.13.orig/includes/User.php 6 | +++ mediawiki-1.23.13/includes/User.php 7 | @@ -3806,6 +3806,9 @@ class User { 8 | * @return boolean: Whether the token matches 9 | */ 10 | public function matchEditToken( $val, $salt = '', $request = null ) { 11 | + if ($val === null) { 12 | + return false; 13 | + } 14 | $sessionToken = $this->getEditToken( $salt, $request ); 15 | $equals = hash_equals( $sessionToken, $val ); 16 | if ( !$equals ) { 17 | -------------------------------------------------------------------------------- /pkgs/mediawiki/default.nix: -------------------------------------------------------------------------------- 1 | { lib, pkgs }: 2 | 3 | let 4 | inherit (builtins) elemAt; 5 | inherit (lib) splitString concatMapStrings; 6 | 7 | bundled = [ 8 | "Cite" "ConfirmEdit" "Gadgets" "ImageMap" "InputBox" "Interwiki" 9 | "LocalisationUpdate" "Nuke" "ParserFunctions" "PdfHandler" "Poem" 10 | "Renameuser" "SpamBlacklist" "SyntaxHighlight_GeSHi" "TitleBlacklist" 11 | "WikiEditor" 12 | ]; 13 | 14 | in pkgs.stdenv.mkDerivation rec { 15 | version = "1.23.17"; 16 | name = "mediawiki-${version}"; 17 | 18 | src = let 19 | v = splitString "." version; 20 | minor = "${elemAt v 0}.${elemAt v 1}"; 21 | in pkgs.fetchurl { 22 | url = "https://releases.wikimedia.org/mediawiki/${minor}/${name}.tar.gz"; 23 | sha256 = "1fxymqirjj2sfbrgcgxig9k6ik5ndw9qq9qn91xm9cnpjksc079x"; 24 | }; 25 | 26 | patches = [ 27 | ./T122487.patch 28 | ./file-backend-default-mode.patch 29 | ]; 30 | 31 | outputs = [ "out" ] ++ bundled; 32 | 33 | installPhase = '' 34 | cp -a . $out 35 | 36 | rm -rf $out/tests 37 | rm -rf $out/mw-config 38 | rm -rf $out/maintenance/dev 39 | rm -rf $out/maintenance/hiphop 40 | 41 | sed -i \ 42 | -e 's|/bin/bash|${pkgs.bash}/bin/bash|g' \ 43 | -e 's|/usr/bin/timeout|${pkgs.coreutils}/bin/timeout|g' \ 44 | $out/includes/limit.sh \ 45 | $out/includes/GlobalFunctions.php 46 | 47 | cat <<'EOF' > $out/LocalSettings.php 48 | <?php 49 | $MEDIAWIKI_LOCAL_SETTINGS = getenv('MEDIAWIKI_LOCAL_SETTINGS'); 50 | if (isset($MEDIAWIKI_LOCAL_SETTINGS)) { 51 | require_once ($MEDIAWIKI_LOCAL_SETTINGS); 52 | }; 53 | ?> 54 | EOF 55 | 56 | ${concatMapStrings (e: '' 57 | mv $out/extensions/${e} ''${${e}} 58 | '') bundled} 59 | ''; 60 | } 61 | -------------------------------------------------------------------------------- /pkgs/mediawiki/file-backend-default-mode.patch: -------------------------------------------------------------------------------- 1 | Index: mediawiki-1.23.13/includes/DefaultSettings.php 2 | =================================================================== 3 | --- mediawiki-1.23.13.orig/includes/DefaultSettings.php 4 | +++ mediawiki-1.23.13/includes/DefaultSettings.php 5 | @@ -429,7 +429,7 @@ $wgImgAuthUrlPathMap = array(); 6 | * leave the paths in unchanged, or 'simple' to replace paths with 7 | * placeholders. Default for LocalRepo is 'simple'. 8 | * - fileMode This allows wikis to set the file mode when uploading/moving files. Default 9 | - * is 0644. 10 | + * is 0640. 11 | * - directory The local filesystem directory where public files are stored. Not used for 12 | * some remote repos. 13 | * - thumbDir The base thumbnail directory. Defaults to "<directory>/thumb". 14 | Index: mediawiki-1.23.13/includes/filerepo/FSRepo.php 15 | =================================================================== 16 | --- mediawiki-1.23.13.orig/includes/filerepo/FSRepo.php 17 | +++ mediawiki-1.23.13/includes/filerepo/FSRepo.php 18 | @@ -50,7 +50,7 @@ class FSRepo extends FileRepo { 19 | : "{$directory}/transcoded"; 20 | $fileMode = isset( $info['fileMode'] ) 21 | ? $info['fileMode'] 22 | - : 0644; 23 | + : 0640; 24 | 25 | $repoName = $info['name']; 26 | // Get the FS backend configuration 27 | Index: mediawiki-1.23.13/includes/filebackend/FSFileBackend.php 28 | =================================================================== 29 | --- mediawiki-1.23.13.orig/includes/filebackend/FSFileBackend.php 30 | +++ mediawiki-1.23.13/includes/filebackend/FSFileBackend.php 31 | @@ -82,7 +82,7 @@ class FSFileBackend extends FileBackendS 32 | } 33 | } 34 | 35 | - $this->fileMode = isset( $config['fileMode'] ) ? $config['fileMode'] : 0644; 36 | + $this->fileMode = isset( $config['fileMode'] ) ? $config['fileMode'] : 0640; 37 | if ( isset( $config['fileOwner'] ) && function_exists( 'posix_getuid' ) ) { 38 | $this->fileOwner = $config['fileOwner']; 39 | $info = posix_getpwuid( posix_getuid() ); 40 | Index: mediawiki-1.23.13/includes/filebackend/FileBackendGroup.php 41 | =================================================================== 42 | --- mediawiki-1.23.13.orig/includes/filebackend/FileBackendGroup.php 43 | +++ mediawiki-1.23.13/includes/filebackend/FileBackendGroup.php 44 | @@ -88,7 +88,7 @@ class FileBackendGroup { 45 | : "{$directory}/transcoded"; 46 | $fileMode = isset( $info['fileMode'] ) 47 | ? $info['fileMode'] 48 | - : 0644; 49 | + : 0640; 50 | // Get the FS backend configuration 51 | $autoBackends[] = array( 52 | 'name' => $backendName, 53 | -------------------------------------------------------------------------------- /pkgs/mediawikiExtensions/Sproxy/Sproxy.php: -------------------------------------------------------------------------------- 1 | <?php 2 | 3 | // This program is free software: you can redistribute it and/or modify it 4 | // under the terms of the GNU General Public License as published by the Free 5 | // Software Foundation, either version 2 of the License, or (at your option) 6 | // any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, but WITHOUT 9 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | // more details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // this program. If not, see <http://www.gnu.org/licenses/>. 15 | // 16 | // Copyright 2006 Otheus Shelling 17 | // Copyright 2007 Rusty Burchfield 18 | // Copyright 2009 James Kinsman 19 | // Copyright 2010 Daniel Thomas 20 | // Copyright 2010 Ian Ward Comfort 21 | // Copyright 2013-2016 Zalora South East Asia Pte Ltd 22 | // 23 | // In 2009, the copyright holders determined that the original publishing of this code 24 | // under GPLv3 was legally and logistically in error, and re-licensed it under GPLv2. 25 | // 26 | // See http://www.mediawiki.org/wiki/Extension:AutomaticREMOTE_USER 27 | // 28 | // Adapted by Rusty to be compatible with version 1.9 of MediaWiki 29 | // Optional settings from Emmanuel Dreyfus 30 | // Adapted by VibroAxe (James Kinsman) to be compatible with version 1.16 of MediaWiki 31 | // Adapted by VibroAxe (James Kinsman) to allow domain substitution for Integrated Windows Authentication 32 | // Adapted by drt24 (Daniel Thomas) to add the optional $wgAuthRemoteuserMailDomain and remove hardcoding 33 | // of permissions for anonymous users. 34 | // Adapted by Ian Ward Comfort to detect mismatches between the session user and REMOTE_USER 35 | // Adapted to sproxy by Chris Forno 36 | // Extension credits that show up on Special:Version 37 | 38 | $wgExtensionCredits['other'][] = array( 39 | 'name' => 'Sproxy', 40 | 'version' => '0.2.0', 41 | 'author' => array( 42 | 'Otheus Shelling', 43 | 'Rusty Burchfield', 44 | 'James Kinsman', 45 | 'Daniel Thomas', 46 | 'Ian Ward Comfort', 47 | 'Chris Forno' 48 | ) , 49 | 'url' => '', 50 | 'description' => 'Automatically authenticates users using sproxy HTTP headers.', 51 | ); 52 | 53 | // We must allow zero length passwords. This extension does not work in MW 1.16 without this. 54 | $wgMinimalPasswordLength = 0; 55 | 56 | function sproxy_hook() 57 | { 58 | global $wgUser, $wgRequest, $wgAuth; 59 | 60 | // For a few special pages, don't do anything. 61 | $skipPages = array( 62 | Title::makeName(NS_SPECIAL, 'UserLogin') , 63 | Title::makeName(NS_SPECIAL, 'UserLogout') , 64 | ); 65 | 66 | if (in_array($wgRequest->getVal('title') , $skipPages)) { 67 | return; 68 | } 69 | 70 | // Don't do anything if there's already a valid session. 71 | $user = User::newFromSession(); 72 | if (!$user->isAnon()) { 73 | return; 74 | } 75 | 76 | // If the login form returns NEED_TOKEN try once more with the right token 77 | $trycount = 0; 78 | $token = ''; 79 | $errormessage = ''; 80 | do { 81 | $tryagain = false; 82 | // Submit a fake login form to authenticate the user. 83 | $params = new FauxRequest(array( 84 | 'wpName' => sproxy_username() , 85 | 'wpPassword' => '', 86 | 'wpDomain' => '', 87 | 'wpLoginToken' => $token, 88 | 'wpRemember' => '', 89 | )); 90 | // Authenticate user data will automatically create new users. 91 | $loginForm = new LoginForm($params); 92 | $result = $loginForm->authenticateUserData(); 93 | switch ($result) { 94 | case LoginForm::SUCCESS: 95 | $wgUser->setOption('rememberpassword', 1); 96 | $wgUser->setCookies(); 97 | break; 98 | 99 | case LoginForm::NEED_TOKEN: 100 | $token = $loginForm->getLoginToken(); 101 | $tryagain = ($trycount == 0); 102 | break; 103 | 104 | default: 105 | error_log("Unexpected sproxy authentication failure (code: $result)"); 106 | break; 107 | } 108 | $trycount++; 109 | } 110 | while ($tryagain); 111 | } 112 | 113 | $wgExtensionFunctions[] = 'sproxy_hook'; 114 | function sproxy_email() 115 | { 116 | return $_SERVER['HTTP_FROM']; 117 | } 118 | 119 | function sproxy_username() 120 | { 121 | return sproxy_email(); 122 | } 123 | 124 | function sproxy_real_name() 125 | { 126 | return $_SERVER['HTTP_X_GIVEN_NAME'] . ' ' . $_SERVER['HTTP_X_FAMILY_NAME']; 127 | } 128 | 129 | class AuthSproxy extends AuthPlugin 130 | { 131 | public function userExists($username) 132 | { 133 | // This does not mean does the user already exist in the Mediawiki database. 134 | return true; 135 | } 136 | 137 | public function authenticate($username, $password) 138 | { 139 | // All users are already authenticated. 140 | return true; 141 | } 142 | 143 | public function autoCreate() 144 | { 145 | // Automatically create Mediawiki users for sproxy users. 146 | return true; 147 | } 148 | 149 | function allowPasswordChange() 150 | { 151 | // This doesn't make any sense so don't allow it. 152 | return false; 153 | } 154 | 155 | public function strict() 156 | { 157 | // Don't check passwords against the Mediawiki database; 158 | return true; 159 | } 160 | 161 | public function initUser(&$user, $autocreate = false) 162 | { 163 | $user->setEmail(sproxy_email()); 164 | $user->mEmailAuthenticated = wfTimestampNow(); 165 | $user->setToken(); 166 | $user->setRealName(sproxy_real_name()); 167 | 168 | // turn on e-mail notifications 169 | if (isset($wgAuthRemoteuserNotify) && $wgAuthRemoteuserNotify) { 170 | $user->setOption('enotifwatchlistpages', 1); 171 | $user->setOption('enotifusertalkpages', 1); 172 | $user->setOption('enotifminoredits', 1); 173 | $user->setOption('enotifrevealaddr', 1); 174 | } 175 | $user->saveSettings(); 176 | } 177 | } 178 | 179 | $wgAuth = new AuthSproxy(); 180 | 181 | // Don't let anonymous people do things... 182 | $wgGroupPermissions['*']['createaccount'] = false; 183 | $wgGroupPermissions['*']['read'] = false; 184 | $wgGroupPermissions['*']['edit'] = false; 185 | 186 | // see http://www.mediawiki.org/wiki/Manual:Hooks/SpecialPage_initList 187 | // and http://www.mediawiki.org/w/Manual:Special_pages 188 | // and http://lists.wikimedia.org/pipermail/mediawiki-l/2009-June/031231.html 189 | // disable login and logout functions for all users 190 | function LessSpecialPages(&$list) 191 | { 192 | unset($list['ChangeEmail']); 193 | unset($list['Userlogin']); 194 | unset($list['Userlogout']); 195 | return true; 196 | } 197 | $wgHooks['SpecialPage_initList'][] = 'LessSpecialPages'; 198 | 199 | // http://www.mediawiki.org/wiki/Extension:Windows_NTLM_LDAP_Auto_Auth 200 | // remove login and logout buttons for all users 201 | function StripLogin(&$personal_urls, &$wgTitle) 202 | { 203 | unset($personal_urls["login"]); 204 | unset($personal_urls["logout"]); 205 | unset($personal_urls['anonlogin']); 206 | return true; 207 | } 208 | $wgHooks['PersonalUrls'][] = 'StripLogin'; 209 | 210 | -------------------------------------------------------------------------------- /pkgs/mediawikiExtensions/default.nix: -------------------------------------------------------------------------------- 1 | { lib, fetchgit, mediawiki }: 2 | 3 | let 4 | inherit (lib) filter genAttrs; 5 | 6 | bundled = filter (n: n != "out") mediawiki.outputs; 7 | 8 | in genAttrs bundled (e: mediawiki.${e}) // 9 | { 10 | 11 | EmbedVideo= fetchgit { 12 | url = https://github.com/HydraWiki/mediawiki-embedvideo.git; 13 | rev = "1c1904bfc040bc948726719cbef41708c62546b3"; 14 | sha256 = "1vlls0ywvfmzx29abgwhhcrjl8lhfhiphj2bsfq0sx76213wci8l"; 15 | }; 16 | 17 | GraphViz = fetchgit { 18 | url = https://gerrit.wikimedia.org/r/p/mediawiki/extensions/GraphViz.git; 19 | rev = "c968ec19090ab6febcd12ccd5816c5875fddc9df"; 20 | sha256 = "1f82dnjzyszpdhy8lcjllxfppqwaqiykhv0hvnzgggr4dq747ga1"; 21 | }; 22 | 23 | /* TODO Use with Mediawiki 1.26+ 24 | MathJax = fetchgit { 25 | url = https://github.com/hbshim/mediawiki-mathjax.git; 26 | rev = "56061635eaeffbd13d50d243077e44fcbf3f5da1"; 27 | sha256 = "1xx9cpcl5c8n1jn3qckcva5dnl8z7i1bd2ff4ycpd2cdp930gsy6"; 28 | }; 29 | */ 30 | 31 | MathJax = fetchgit { 32 | url = https://github.com/zalora/Mediawiki-MathJax.git; 33 | rev = "880adf7f9da55dbe257043fe431f825211ee96e1"; 34 | sha256 = "17s3pbxj6jhywsbdss1hqmss8slb89jkwirlsbd0h16m130q72n8"; 35 | }; 36 | 37 | MsUpload = fetchgit { 38 | url = https://phabricator.wikimedia.org/diffusion/EMSU/extension-msupload.git; 39 | rev = "d2983b9cd44203173b39e64bf25cdcd73612fcc0"; 40 | sha256 = "1ssngwhr9j598v1rcrwxrpdnl9jk7843qfsngz5ba10c14ba58rx"; 41 | }; 42 | 43 | Sproxy = ./Sproxy; # TODO: review, update & publish 44 | 45 | UserPageEditProtection = fetchgit { 46 | url = https://gerrit.wikimedia.org/r/p/mediawiki/extensions/UserPageEditProtection.git; 47 | rev = "13ff835e8278654ab8cfae03c8b8196bdfe6e410"; 48 | sha256 = "106acsi4g05wgnhsc7rcdnmy0c0l46bnlq6dgnq1a6j0giilz87w"; 49 | }; 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /pkgs/monitoringPlugins/check_mysql_MYSQL_PORT.patch: -------------------------------------------------------------------------------- 1 | From 399cc141526ee77e1befce469f1fab40645f299d Mon Sep 17 00:00:00 2001 2 | From: Bernard Spil <Sp1l@users.noreply.github.com> 3 | Date: Mon, 6 Nov 2017 17:31:44 +0100 4 | Subject: [PATCH] Fix build issue with MariaDB 10.2 5 | 6 | As of 10.2 MariaDB no longer defines MYSQL_PORT. 7 | --- 8 | plugins/common.h | 5 +++++ 9 | 1 file changed, 5 insertions(+) 10 | 11 | diff --git a/plugins/common.h b/plugins/common.h 12 | index 8719b502..6bf4fca4 100644 13 | --- a/plugins/common.h 14 | +++ b/plugins/common.h 15 | @@ -174,6 +174,11 @@ 16 | * 17 | */ 18 | 19 | +/* MariaDB 10.2 client does not set MYSQL_PORT */ 20 | +#ifndef MYSQL_PORT 21 | +# define MYSQL_PORT 3306 22 | +#endif 23 | + 24 | enum { 25 | OK = 0, 26 | ERROR = -1 27 | -------------------------------------------------------------------------------- /pkgs/monitoringPlugins/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, fetchurl, pkgs }: 2 | 3 | stdenv.mkDerivation rec { 4 | version = "2.2"; 5 | name = "monitoring-plugins-${version}"; 6 | src = fetchurl { 7 | url = "https://github.com/monitoring-plugins/monitoring-plugins/archive/v${version}.tar.gz"; 8 | sha256 = "0nq0ilnfmwka5ds9k3bkgqd9238cv1yfyik8xhqbvnkpc3nh1cfk"; 9 | }; 10 | 11 | buildInputs = with pkgs; [ 12 | autoreconfHook bind.dnsutils fping libdbi libtap mariadb.client.dev 13 | openldap.dev openssh openssl.dev perl postgresql procps smbclient sudo 14 | ]; 15 | 16 | doCheck = false; # tests are broken badly 17 | 18 | patches = [ 19 | ./mysql_check_slave.patch 20 | ./test-str-format.patch 21 | ./check_mysql_MYSQL_PORT.patch 22 | ]; 23 | 24 | configurePhase = '' 25 | ./configure \ 26 | --prefix=$out \ 27 | --sysconfdir=/etc \ 28 | --localstatedir=/var \ 29 | --disable-nls \ 30 | --with-ping-command="/run/wrappers/bin/ping -n -U -w %d -c %d %s" \ 31 | --with-ping6-command="/run/wrappers/bin/ping6 -n -U -w %d -c %d %s" \ 32 | --with-trusted-path=/run/wrappers/bin:/run/current-system/sw/bin:/usr/bin 33 | ''; 34 | } 35 | -------------------------------------------------------------------------------- /pkgs/monitoringPlugins/test-str-format.patch: -------------------------------------------------------------------------------- 1 | Description; fix warning/error 2 | error: format not a string literal and no format arguments 3 | [-Werror=format-security] 4 | --- monitoring-plugins-2.2.orig/lib/tests/test_utils.c 5 | +++ monitoring-plugins-2.2/lib/tests/test_utils.c 6 | @@ -489,16 +489,16 @@ main (int argc, char **argv) 7 | int tlen = strlen(testname); 8 | 9 | strcpy(testname+tlen, states[i]); 10 | - ok(i==mp_translate_state(states[i]), testname); 11 | + ok(i==mp_translate_state(states[i]), "%s", testname); 12 | 13 | strcpy(testname+tlen, statelower); 14 | - ok(i==mp_translate_state(statelower), testname); 15 | + ok(i==mp_translate_state(statelower), "%s", testname); 16 | 17 | strcpy(testname+tlen, stateupper); 18 | - ok(i==mp_translate_state(stateupper), testname); 19 | + ok(i==mp_translate_state(stateupper), "%s", testname); 20 | 21 | strcpy(testname+tlen, statenum); 22 | - ok(i==mp_translate_state(statenum), testname); 23 | + ok(i==mp_translate_state(statenum), "%s", testname); 24 | } 25 | ok(ERROR==mp_translate_state("warningfewgw"), "Translate state string with garbage"); 26 | ok(ERROR==mp_translate_state("00"), "Translate state string: bad numeric string 1"); 27 | -------------------------------------------------------------------------------- /pkgs/mywatch/default.nix: -------------------------------------------------------------------------------- 1 | { haskell, haskellPackages }: 2 | 3 | let myHaskellPkgs = haskellPackages.override { 4 | overrides = self: super: { 5 | mysql = haskell.lib.dontCheck super.mysql; 6 | mysql-simple = haskell.lib.dontCheck super.mysql-simple; 7 | }; 8 | }; 9 | 10 | in myHaskellPkgs.callPackage ./main.nix { } 11 | 12 | -------------------------------------------------------------------------------- /pkgs/mywatch/main.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, aeson, base, bytestring, ConfigFile 2 | , data-default-class, docopt, fast-logger, filepath, http-types 3 | , interpolatedstring-perl6, MissingH, mtl, mysql, mysql-simple 4 | , network, resource-pool, scotty, stdenv, text, unix 5 | , unordered-containers, wai, wai-extra, wai-middleware-static, warp 6 | }: 7 | mkDerivation { 8 | pname = "mywatch"; 9 | version = "0.3.0"; 10 | sha256 = "1a7fqyn0pvnbxzn9fiaib4pj7hq5p2qgnbdwryg70lkgnjm4y0h4"; 11 | isLibrary = false; 12 | isExecutable = true; 13 | executableHaskellDepends = [ 14 | aeson base bytestring ConfigFile data-default-class docopt 15 | fast-logger filepath http-types interpolatedstring-perl6 MissingH 16 | mtl mysql mysql-simple network resource-pool scotty text unix 17 | unordered-containers wai wai-extra wai-middleware-static warp 18 | ]; 19 | description = "Web application to view and kill MySQL queries"; 20 | license = stdenv.lib.licenses.mit; 21 | } 22 | -------------------------------------------------------------------------------- /pkgs/nagios-plugins-rabbitmq/default.nix: -------------------------------------------------------------------------------- 1 | { fetchurl 2 | , makeWrapper 3 | , perl 4 | , perlPackages 5 | , stdenv 6 | }: 7 | 8 | stdenv.mkDerivation rec { 9 | version = "2.0.3"; 10 | name = "nagios-plugins-rabbitmq-${version}"; 11 | 12 | src = fetchurl { 13 | url = "https://github.com/nagios-plugins-rabbitmq/nagios-plugins-rabbitmq/archive/${version}.tar.gz"; 14 | sha256 = "1fw40hzvb8sk5ss0hvrgv338lr019d2q9cc9ayy4hvk1c5bh3ljb"; 15 | }; 16 | 17 | buildInputs = [ 18 | makeWrapper 19 | perl 20 | perlPackages.JSON 21 | perlPackages.LWPUserAgent 22 | perlPackages.ModuleBuild 23 | perlPackages.MonitoringPlugin 24 | perlPackages.URI 25 | ]; 26 | 27 | buildPhase = "perl Build.PL --prefix=$out; ./Build build"; 28 | installPhase = '' 29 | ./Build install 30 | 31 | for n in "$out/bin/"*; do 32 | wrapProgram "$n" --prefix PERL5LIB : "$PERL5LIB" 33 | done 34 | ''; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /pkgs/nix-serve/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, coreutils, pxz, nix, perl, perlPackages }: 2 | 3 | let 4 | inherit (stdenv.lib) 5 | makeBinPath 6 | ; 7 | 8 | in stdenv.mkDerivation { 9 | name = "nix-serve"; 10 | 11 | src = "${./nix-serve.psgi}"; 12 | 13 | buildInputs = [ perl nix.perl-bindings ] 14 | ++ (with perlPackages; [ DBI DBDSQLite Plack Starman ]); 15 | 16 | phases = [ "installPhase" ]; 17 | 18 | installPhase = '' 19 | mkdir -p $out/libexec/nix-serve 20 | perl -c "$src" 21 | cat "$src" > "$out/libexec/nix-serve.psgi" 22 | 23 | mkdir -p $out/bin 24 | cat > $out/bin/nix-serve <<EOF 25 | #! ${stdenv.shell} 26 | export PATH=${makeBinPath [ coreutils pxz nix ]}:\$PATH 27 | export PERL5LIB=$PERL5LIB 28 | exec ${perlPackages.Starman}/bin/starman "$out/libexec/nix-serve.psgi" "\$@" 29 | EOF 30 | chmod +x $out/bin/nix-serve 31 | ''; 32 | } 33 | -------------------------------------------------------------------------------- /pkgs/nix-serve/nix-serve.psgi: -------------------------------------------------------------------------------- 1 | # This is nix-serve (https://github.com/edolstra/nix-serve) using pxz instead of bzip2 2 | use MIME::Base64; 3 | use Nix::Config; 4 | use Nix::Manifest; 5 | use Nix::Store; 6 | use Nix::Utils; 7 | use strict; 8 | 9 | sub stripPath { 10 | my ($x) = @_; 11 | $x =~ s/.*\///; $x 12 | } 13 | 14 | my $app = sub { 15 | my $env = shift; 16 | my $path = $env->{PATH_INFO}; 17 | 18 | if ($path eq "/nix-cache-info") { 19 | return [200, ['Content-Type' => 'text/plain'], ["StoreDir: $Nix::Config::storeDir\nWantMassQuery: 1\nPriority: 30\n"]]; 20 | } 21 | 22 | elsif ($path =~ '/([0-9a-z]+)\.narinfo$') { 23 | my $hashPart = $1; 24 | my $storePath = queryPathFromHashPart($hashPart); 25 | return [404, ['Content-Type' => 'text/plain'], ["No such path.\n"]] unless $storePath; 26 | my ($deriver, $narHash, $time, $narSize, $refs) = queryPathInfo($storePath, 1) or die; 27 | my $compression; 28 | my $ext; 29 | if ($narSize < 1024) { 30 | $compression = 'none'; 31 | $ext = ''; 32 | } else { 33 | $compression = 'xz'; 34 | $ext = '.xz'; 35 | } 36 | my $res = 37 | "StorePath: $storePath\n" . 38 | "URL: nar/$hashPart.nar$ext\n" . 39 | "Compression: $compression\n" . 40 | "NarHash: $narHash\n" . 41 | "NarSize: $narSize\n"; 42 | $res .= "References: " . join(" ", map { stripPath($_) } @$refs) . "\n" 43 | if scalar @$refs > 0; 44 | $res .= "Deriver: " . stripPath($deriver) . "\n" if defined $deriver; 45 | my $secretKeyFile = $ENV{'NIX_SECRET_KEY_FILE'}; 46 | if (defined $secretKeyFile) { 47 | my $secretKey = readFile $secretKeyFile; 48 | chomp $secretKey; 49 | my $fingerprint = fingerprintPath($storePath, $narHash, $narSize, $refs); 50 | my $sig = signString($secretKey, $fingerprint); 51 | $res .= "Sig: $sig\n"; 52 | } 53 | return [200, ['Content-Type' => 'text/x-nix-narinfo'], [$res]]; 54 | } 55 | 56 | elsif ($path =~ '/nar/([0-9a-z]+)\.nar.xz$') { 57 | my $hashPart = $1; 58 | my $storePath = queryPathFromHashPart($hashPart); 59 | return [404, ['Content-Type' => 'text/plain'], ["No such path.\n"]] unless $storePath; 60 | my $fh = new IO::Handle; 61 | open $fh, "nix-store --dump '$storePath' | nice -n 19 pxz -0 |"; 62 | return [200, ['Content-Type' => 'application/x-xz'], $fh]; 63 | } 64 | 65 | elsif ($path =~ '/nar/([0-9a-z]+)\.nar$') { 66 | my $hashPart = $1; 67 | my $storePath = queryPathFromHashPart($hashPart); 68 | return [404, ['Content-Type' => 'text/plain'], ["No such path.\n"]] unless $storePath; 69 | my $fh = new IO::Handle; 70 | open $fh, "nix-store --dump '$storePath' |"; 71 | return [200, ['Content-Type' => 'application/octet-stream'], $fh]; 72 | } 73 | 74 | else { 75 | return [404, ['Content-Type' => 'text/plain'], ["File not found.\n"]]; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /pkgs/nodejs-sass/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: 2 | 3 | let 4 | 5 | inherit (builtins) 6 | attrNames fromJSON head readFile ; 7 | 8 | packages = fromJSON (readFile ./main.json); 9 | package = head packages; 10 | 11 | name = head (attrNames package); 12 | version = package.${name}; 13 | 14 | main = 15 | let m = (import ./main.nix { 16 | inherit pkgs; 17 | inherit (pkgs) nodejs; 18 | inherit (pkgs.stdenv) system; 19 | }); 20 | in m // { 21 | "${name}-${version}" = m."${name}-${version}".override (super: { 22 | # XXX: build bundled libsassl, DO NOT DOWNLOAD binaries! 23 | # XXX --nodedir is to prevent gyp from downloading nodejs headers 24 | # XXX: ref. https://github.com/nodejs/node-gyp/issues/1133 25 | preRebuild = '' 26 | npm run build --nodedir=${pkgs.nodejs} 27 | ''; 28 | }); 29 | }; 30 | 31 | 32 | in 33 | pkgs.runCommand "nodejs-sass-${version}" {} 34 | '' 35 | mkdir -p $out/bin 36 | ln -s ${main."${name}-${version}"}/lib/node_modules/node-sass/bin/node-sass \ 37 | $out/bin/node-sass 38 | test -x $out/bin/node-sass 39 | '' 40 | -------------------------------------------------------------------------------- /pkgs/nodejs-sass/generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | node2nix -8 --bypass-cache --flatten -i main.json -c main.nix 4 | 5 | -------------------------------------------------------------------------------- /pkgs/nodejs-sass/main.json: -------------------------------------------------------------------------------- 1 | [ 2 | { "node-sass" : "4.7.2" } 3 | ] 4 | -------------------------------------------------------------------------------- /pkgs/nodejs-sass/main.nix: -------------------------------------------------------------------------------- 1 | # This file has been generated by node2nix 1.5.3. Do not edit! 2 | 3 | {pkgs ? import <nixpkgs> { 4 | inherit system; 5 | }, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-8_x"}: 6 | 7 | let 8 | nodeEnv = import ./node-env.nix { 9 | inherit (pkgs) stdenv python2 utillinux runCommand writeTextFile; 10 | inherit nodejs; 11 | libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null; 12 | }; 13 | in 14 | import ./node-packages.nix { 15 | inherit (pkgs) fetchurl fetchgit; 16 | inherit nodeEnv; 17 | } -------------------------------------------------------------------------------- /pkgs/openldap-modular.nix: -------------------------------------------------------------------------------- 1 | # Enabled all modules, except perl, ndb, sql. 2 | # See https://github.com/NixOS/nixpkgs/commit/8e319c5ddac707fb4cb3315f9eadea9a70fc8c84 3 | { stdenv, fetchurl, openssl, cyrus_sasl, db, groff, libtool }: 4 | 5 | stdenv.mkDerivation rec { 6 | name = "openldap-modular-2.4.44"; 7 | 8 | src = fetchurl { 9 | url = "http://www.openldap.org/software/download/OpenLDAP/openldap-release/${name}.tgz"; 10 | sha256 = "0044p20hx07fwgw2mbwj1fkx04615hhs1qyx4mawj2bhqvrnppnp"; 11 | }; 12 | 13 | # TODO: separate "out" and "bin" 14 | outputs = [ "out" "dev" "man" "devdoc" ]; 15 | 16 | enableParallelBuilding = true; 17 | 18 | buildInputs = [ openssl cyrus_sasl db groff libtool ]; 19 | 20 | configureFlags = 21 | [ 22 | "--disable-dependency-tracking" # speeds up one-time build 23 | "--disable-ndb" 24 | "--disable-perl" 25 | "--disable-sql" 26 | "--enable-backends=mod" 27 | "--enable-modules" 28 | "--enable-overlays=mod" 29 | ] ++ stdenv.lib.optional (openssl == null) "--without-tls" 30 | ++ stdenv.lib.optional (cyrus_sasl == null) "--without-cyrus-sasl" 31 | ++ stdenv.lib.optional stdenv.isFreeBSD "--with-pic"; 32 | 33 | # 1. Fixup broken libtool 34 | # 2. Libraries left in the build location confuse `patchelf --shrink-rpath` 35 | # Delete these to let patchelf discover the right path instead. 36 | # FIXME: that one can be removed when https://github.com/NixOS/patchelf/pull/98 37 | # is in Nixpkgs patchelf. 38 | preFixup = '' 39 | sed -e 's,-lsasl2,-L${cyrus_sasl.out}/lib -lsasl2,' \ 40 | -e 's,-lssl,-L${openssl.out}/lib -lssl,' \ 41 | -i $out/lib/libldap.la -i $out/lib/libldap_r.la 42 | 43 | rm -rf $out/var 44 | rm -r libraries/*/.libs 45 | ''; 46 | 47 | postInstall = '' 48 | chmod +x "$out"/lib/*.{so,dylib} 49 | ''; 50 | 51 | meta = with stdenv.lib; { 52 | homepage = http://www.openldap.org/; 53 | description = "An open source implementation of the Lightweight Directory Access Protocol"; 54 | maintainers = with maintainers; [ lovek323 mornfall ]; 55 | platforms = platforms.unix; 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /pkgs/postcss-cli/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, pkgs, nodejs, writeScript }: 2 | 3 | let 4 | 5 | inherit (builtins) 6 | attrNames 7 | fromJSON 8 | head 9 | readFile 10 | ; 11 | 12 | packages = fromJSON (readFile ./main.json); 13 | package = head packages; 14 | 15 | name = head (attrNames package); 16 | version = package.${name}; 17 | 18 | main = (import ./main.nix { 19 | inherit pkgs; 20 | inherit (pkgs) nodejs; 21 | inherit (stdenv) system; 22 | })."${name}-${version}"; 23 | 24 | in main 25 | -------------------------------------------------------------------------------- /pkgs/postcss-cli/generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | node2nix -8 --bypass-cache --flatten -i main.json -c main.nix 4 | 5 | -------------------------------------------------------------------------------- /pkgs/postcss-cli/main.json: -------------------------------------------------------------------------------- 1 | [ 2 | { "postcss-cli" : "4.1.0" } 3 | ] 4 | -------------------------------------------------------------------------------- /pkgs/postcss-cli/main.nix: -------------------------------------------------------------------------------- 1 | # This file has been generated by node2nix 1.5.3. Do not edit! 2 | 3 | {pkgs ? import <nixpkgs> { 4 | inherit system; 5 | }, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-8_x"}: 6 | 7 | let 8 | nodeEnv = import ./node-env.nix { 9 | inherit (pkgs) stdenv python2 utillinux runCommand writeTextFile; 10 | inherit nodejs; 11 | libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null; 12 | }; 13 | in 14 | import ./node-packages.nix { 15 | inherit (pkgs) fetchurl fetchgit; 16 | inherit nodeEnv; 17 | } -------------------------------------------------------------------------------- /pkgs/postcss-plugins/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, pkgs, nodejs }: 2 | 3 | let 4 | 5 | plugins = (import ./plugins.nix { 6 | inherit pkgs; 7 | inherit (pkgs) nodejs; 8 | inherit (stdenv) system; 9 | }); 10 | 11 | in plugins 12 | -------------------------------------------------------------------------------- /pkgs/postcss-plugins/find.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | curl --globoff 'https://registry.npmjs.org/-/_view/byKeyword?startkey=["postcss-plugin"]&endkey=["postcss-plugin",{}]&group_level=2' \ 4 | | jq '.rows | map(.key | .[1])' > plugins.json 5 | 6 | -------------------------------------------------------------------------------- /pkgs/postcss-plugins/generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | node2nix -8 --bypass-cache --flatten -i plugins.json -c plugins.nix 4 | 5 | -------------------------------------------------------------------------------- /pkgs/postcss-plugins/plugins.nix: -------------------------------------------------------------------------------- 1 | # This file has been generated by node2nix 1.5.3. Do not edit! 2 | 3 | {pkgs ? import <nixpkgs> { 4 | inherit system; 5 | }, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-8_x"}: 6 | 7 | let 8 | nodeEnv = import ./node-env.nix { 9 | inherit (pkgs) stdenv python2 utillinux runCommand writeTextFile; 10 | inherit nodejs; 11 | libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null; 12 | }; 13 | in 14 | import ./node-packages.nix { 15 | inherit (pkgs) fetchurl fetchgit; 16 | inherit nodeEnv; 17 | } -------------------------------------------------------------------------------- /pkgs/probes.nix: -------------------------------------------------------------------------------- 1 | { stdenv, pkgs, lib }: 2 | 3 | let 4 | plugins = [ 5 | "check_disk" 6 | "check_file_age" 7 | "check_load" 8 | "check_log" 9 | "check_procs" 10 | "check_swap" 11 | "check_users" 12 | ]; 13 | 14 | in stdenv.mkDerivation { 15 | name = "local-monitoring-plugins"; 16 | phases = [ "installPhase" ]; 17 | installPhase = '' 18 | mkdir -p $out/bin 19 | ${lib.concatMapStringsSep "\n" (p: '' 20 | cp -a ${pkgs.monitoringPlugins}/libexec/${p} $out/bin/${p} 21 | '') plugins} 22 | cp -a '${pkgs.check_mdstat}/bin/'* $out/bin/ 23 | cp -a '${pkgs.check_systemd}/bin/'* $out/bin/ 24 | ''; 25 | } 26 | -------------------------------------------------------------------------------- /pkgs/pyresttest/add-unix-socket.patch: -------------------------------------------------------------------------------- 1 | From 95364551209815ca2c2380ce270474989b924dda Mon Sep 17 00:00:00 2001 2 | From: Igor Pashev <pashev.igor@gmail.com> 3 | Date: Sat, 26 Jan 2019 11:48:48 +0200 4 | Subject: [PATCH] Add --unix-socket option 5 | 6 | --- 7 | pyresttest/resttest.py | 9 +++++++++ 8 | 1 file changed, 9 insertions(+) 9 | 10 | diff --git a/pyresttest/resttest.py b/pyresttest/resttest.py 11 | index 0344746..845c438 100644 12 | --- a/pyresttest/resttest.py 13 | +++ b/pyresttest/resttest.py 14 | @@ -111,6 +111,7 @@ class TestConfig: 15 | verbose = False 16 | ssl_insecure = False 17 | skip_term_colors = False # Turn off output term colors 18 | + unix_socket = None 19 | 20 | # Binding and creation of generators 21 | variable_binds = None 22 | @@ -331,6 +332,8 @@ def run_test(mytest, test_config=TestConfig(), context=None, curl_handle=None, * 23 | if test_config.ssl_insecure: 24 | curl.setopt(pycurl.SSL_VERIFYPEER, 0) 25 | curl.setopt(pycurl.SSL_VERIFYHOST, 0) 26 | + if test_config.unix_socket != None: 27 | + curl.setopt(pycurl.UNIX_SOCKET_PATH, test_config.unix_socket) 28 | 29 | result.passed = None 30 | 31 | @@ -798,6 +801,7 @@ def main(args): 32 | Keys allowed for args: 33 | url - REQUIRED - Base URL 34 | test - REQUIRED - Test file (yaml) 35 | + unix_socket - OPTIONAL - connect to this UNIX socket 36 | print_bodies - OPTIONAL - print response body 37 | print_headers - OPTIONAL - print response headers 38 | log - OPTIONAL - set logging level {debug,info,warning,error,critical} (default=warning) 39 | @@ -854,6 +858,9 @@ def main(args): 40 | if 'ssl_insecure' in args and args['ssl_insecure'] is not None: 41 | t.config.ssl_insecure = safe_to_bool(args['ssl_insecure']) 42 | 43 | + if 'unix_socket' in args and args['unix_socket'] is not None: 44 | + t.config.unix_socket = args['unix_socket'] 45 | + 46 | if 'skip_term_colors' in args and args['skip_term_colors'] is not None: 47 | t.config.skip_term_colors = safe_to_bool(args['skip_term_colors']) 48 | 49 | @@ -877,6 +884,8 @@ def parse_command_line_args(args_in): 50 | action="store", type="string") 51 | parser.add_option( 52 | u"--url", help="Base URL to run tests against", action="store", type="string") 53 | + parser.add_option(u"--unix-socket", help="Connect to this UNIX socket", 54 | + action="store", type="string", dest="unix_socket") 55 | parser.add_option(u"--test", help="Test file to use", 56 | action="store", type="string") 57 | parser.add_option(u'--import_extensions', 58 | -------------------------------------------------------------------------------- /pkgs/pyresttest/default.nix: -------------------------------------------------------------------------------- 1 | { fetchgit, python3Packages }: 2 | 3 | python3Packages.buildPythonApplication rec { 4 | pname = "pyresttest"; 5 | version = "1.7.1+git"; 6 | 7 | src = fetchgit { 8 | url = "https://github.com/svanoort/pyresttest.git"; 9 | rev = "f92acf8e838c4623ddd8e12e880f31046ff9317f"; 10 | sha256 = "0zwizn57x7grvwrvz4ahdrabkgiadyffgf4sqnhdacpczxpry57r"; 11 | }; 12 | 13 | patches = [ 14 | ./add-unix-socket.patch 15 | ]; 16 | 17 | propagatedBuildInputs = with python3Packages; [ 18 | future jmespath pycurl pyyaml 19 | ]; 20 | 21 | doCheck = false; 22 | } 23 | -------------------------------------------------------------------------------- /pkgs/rdsdump/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, bash, mysql, makeWrapper }: 2 | 3 | stdenv.mkDerivation { 4 | name = "rdsdump"; 5 | buildInputs = [ bash ]; 6 | phases = [ "installPhase" ]; 7 | nativeBuildInputs = [ makeWrapper ]; 8 | installPhase = '' 9 | mkdir -p $out/bin 10 | cp -a ${./rdsdump.bash} $out/bin/rdsdump 11 | chmod +x $out/bin/rdsdump 12 | patchShebangs $out/bin/rdsdump 13 | wrapProgram "$out/bin/rdsdump" \ 14 | --prefix PATH : '${mysql.client.bin}/bin' 15 | ''; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /pkgs/rdsdump/rdsdump.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | mysql_args= 5 | mysqldump_args= 6 | master_data=0 7 | while [ $# -gt 0 ]; do 8 | case $1 in 9 | --host=*|--password=*|--user=*|\ 10 | --defaults-file=*|--defaults-extra-file=*|\ 11 | --ssl=*|--ssl-ca=*|--ssl-key=*|--ssl-cert=*|\ 12 | -h?*|-u?*|-p?*) 13 | mysql_args="$mysql_args $1" 14 | mysqldump_args="$mysqldump_args $1" 15 | shift 1;; 16 | --host|--user|\ 17 | --defaults-file|--defaults-extra-file|\ 18 | --ssl-ca|--ssl-key|--ssl-cert|\ 19 | -h|-u) 20 | mysql_args="$mysql_args $1 $2" 21 | mysqldump_args="$mysqldump_args $1 $2" 22 | shift 2;; 23 | --master-data=*) 24 | master_data=$(echo "$1" | cut -d= -f2) 25 | shift;; 26 | --master-data) 27 | master_data=$2 28 | shift 2;; 29 | *) 30 | mysqldump_args="$mysqldump_args $1" 31 | shift;; 32 | esac 33 | done 34 | 35 | replica () { 36 | mysql $mysql_args "$@" 37 | } 38 | 39 | start_replication () { 40 | replica -N -e "CALL mysql.rds_start_replication;" >&2 41 | } 42 | 43 | stop_replication () { 44 | replica -N -e "CALL mysql.rds_stop_replication;" >&2 45 | } 46 | 47 | trap 'start_replication' EXIT 48 | stop_replication 49 | 50 | if [ "$master_data" -gt 0 ]; then 51 | if [ "$master_data" -eq 2 ]; then 52 | printf '-- ' 53 | fi 54 | replica -e 'SHOW SLAVE STATUS\G' | awk -f <(cat - <<- 'AWK' 55 | /\<Exec_Master_Log_Pos\>/ { log_pos = $2 }; 56 | /\<Relay_Master_Log_File\>/ { log_file = $2 }; 57 | END { 58 | printf "CHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%d;\n", log_file, log_pos 59 | } 60 | AWK 61 | ) 62 | fi 63 | 64 | mysqldump $mysqldump_args & 65 | sleep 30 66 | 67 | start_replication 68 | trap - EXIT 69 | 70 | wait 71 | -------------------------------------------------------------------------------- /pkgs/sass-lint/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, pkgs, nodejs, writeScript }: 2 | 3 | let 4 | 5 | inherit (builtins) 6 | attrNames 7 | fromJSON 8 | head 9 | readFile 10 | ; 11 | 12 | packages = fromJSON (readFile ./main.json); 13 | package = head packages; 14 | 15 | name = head (attrNames package); 16 | version = package.${name}; 17 | 18 | main = (import ./main.nix { 19 | inherit pkgs; 20 | inherit (pkgs) nodejs; 21 | inherit (stdenv) system; 22 | })."${name}-${version}"; 23 | 24 | in 25 | pkgs.runCommand "${name}-${version}" {} 26 | '' 27 | mkdir -p $out/bin 28 | ln -s ${main}/bin/${name} $out/bin/${name} 29 | test -x $out/bin/${name} 30 | '' 31 | -------------------------------------------------------------------------------- /pkgs/sass-lint/generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | node2nix -8 --bypass-cache --flatten -i main.json -c main.nix 4 | 5 | -------------------------------------------------------------------------------- /pkgs/sass-lint/main.json: -------------------------------------------------------------------------------- 1 | [ 2 | { "sass-lint" : "1.12.1" } 3 | ] 4 | -------------------------------------------------------------------------------- /pkgs/sass-lint/main.nix: -------------------------------------------------------------------------------- 1 | # This file has been generated by node2nix 1.5.3. Do not edit! 2 | 3 | {pkgs ? import <nixpkgs> { 4 | inherit system; 5 | }, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-8_x"}: 6 | 7 | let 8 | nodeEnv = import ./node-env.nix { 9 | inherit (pkgs) stdenv python2 utillinux runCommand writeTextFile; 10 | inherit nodejs; 11 | libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null; 12 | }; 13 | in 14 | import ./node-packages.nix { 15 | inherit (pkgs) fetchurl fetchgit; 16 | inherit nodeEnv; 17 | } -------------------------------------------------------------------------------- /pkgs/sproxy-web/cabal2nix.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, aeson, base, blaze-html, blaze-markup, bytestring 2 | , data-default-class, directory, docopt, fast-logger, filepath 3 | , http-types, interpolatedstring-perl6, mtl, network 4 | , postgresql-simple, resource-pool, scotty, stdenv, text, unix, wai 5 | , wai-extra, wai-middleware-static, warp 6 | }: 7 | mkDerivation { 8 | pname = "sproxy-web"; 9 | version = "0.4.1"; 10 | sha256 = "0jvkvk5yqp4gibg61q67iczaqvfszikxvvgf04fg6xs23gjkpihp"; 11 | isLibrary = false; 12 | isExecutable = true; 13 | executableHaskellDepends = [ 14 | aeson base blaze-html blaze-markup bytestring data-default-class 15 | directory docopt fast-logger filepath http-types 16 | interpolatedstring-perl6 mtl network postgresql-simple 17 | resource-pool scotty text unix wai wai-extra wai-middleware-static 18 | warp 19 | ]; 20 | description = "Web interface to sproxy database"; 21 | license = stdenv.lib.licenses.mit; 22 | } 23 | -------------------------------------------------------------------------------- /pkgs/sproxy-web/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, haskellPackages }: 2 | 3 | haskellPackages.callPackage ./cabal2nix.nix {} 4 | 5 | -------------------------------------------------------------------------------- /pkgs/sproxy2/default.nix: -------------------------------------------------------------------------------- 1 | { haskellPackages }: 2 | 3 | haskellPackages.callPackage ./main.nix { } 4 | 5 | -------------------------------------------------------------------------------- /pkgs/sproxy2/main.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, aeson, base, base64-bytestring, blaze-builder 2 | , bytestring, cereal, conduit, cookie, docopt, entropy, Glob 3 | , http-client, http-conduit, http-types, interpolatedstring-perl6 4 | , network, postgresql-simple, resource-pool, SHA, sqlite-simple 5 | , stdenv, text, time, unix, unordered-containers, wai, wai-conduit 6 | , warp, warp-tls, word8, yaml 7 | }: 8 | mkDerivation { 9 | pname = "sproxy2"; 10 | version = "1.97.1"; 11 | sha256 = "a43358ca9ebba23b121d74a1388926ed33c016636b00098ce749825b17a673e5"; 12 | isLibrary = false; 13 | isExecutable = true; 14 | executableHaskellDepends = [ 15 | aeson base base64-bytestring blaze-builder bytestring cereal 16 | conduit cookie docopt entropy Glob http-client http-conduit 17 | http-types interpolatedstring-perl6 network postgresql-simple 18 | resource-pool SHA sqlite-simple text time unix unordered-containers 19 | wai wai-conduit warp warp-tls word8 yaml 20 | ]; 21 | description = "Secure HTTP proxy for authenticating users via OAuth2"; 22 | license = stdenv.lib.licenses.mit; 23 | } 24 | -------------------------------------------------------------------------------- /pkgs/uglify-js/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, pkgs, nodejs, writeScript }: 2 | 3 | let 4 | 5 | inherit (builtins) 6 | attrNames 7 | fromJSON 8 | head 9 | readFile 10 | ; 11 | 12 | packages = fromJSON (readFile ./main.json); 13 | package = head packages; 14 | 15 | name = head (attrNames package); 16 | version = package.${name}; 17 | 18 | main = (import ./main.nix { 19 | inherit pkgs; 20 | inherit (pkgs) nodejs; 21 | inherit (stdenv) system; 22 | })."${name}-${version}"; 23 | 24 | in main 25 | -------------------------------------------------------------------------------- /pkgs/uglify-js/generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | node2nix -8 --bypass-cache --flatten -i main.json -c main.nix 4 | 5 | -------------------------------------------------------------------------------- /pkgs/uglify-js/main.json: -------------------------------------------------------------------------------- 1 | [ 2 | { "uglify-js" : "3.4.9" } 3 | ] 4 | -------------------------------------------------------------------------------- /pkgs/uglify-js/main.nix: -------------------------------------------------------------------------------- 1 | # This file has been generated by node2nix 1.5.3. Do not edit! 2 | 3 | {pkgs ? import <nixpkgs> { 4 | inherit system; 5 | }, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-8_x"}: 6 | 7 | let 8 | nodeEnv = import ./node-env.nix { 9 | inherit (pkgs) stdenv python2 utillinux runCommand writeTextFile; 10 | inherit nodejs; 11 | libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null; 12 | }; 13 | in 14 | import ./node-packages.nix { 15 | inherit (pkgs) fetchurl fetchgit; 16 | inherit nodeEnv; 17 | } -------------------------------------------------------------------------------- /pkgs/uglify-js/node-packages.nix: -------------------------------------------------------------------------------- 1 | # This file has been generated by node2nix 1.5.3. Do not edit! 2 | 3 | {nodeEnv, fetchurl, fetchgit, globalBuildInputs ? []}: 4 | 5 | let 6 | sources = { 7 | "commander-2.17.1" = { 8 | name = "commander"; 9 | packageName = "commander"; 10 | version = "2.17.1"; 11 | src = fetchurl { 12 | url = "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz"; 13 | sha512 = "21fbnprzkj53pjsp5wd7f5wa50jrirag11gq351jr8hhrib5gw62kylpvcddv3c2a1vcs1p8llq80wdnflh6lny3frnq7v7l6vi9wy0"; 14 | }; 15 | }; 16 | "source-map-0.6.1" = { 17 | name = "source-map"; 18 | packageName = "source-map"; 19 | version = "0.6.1"; 20 | src = fetchurl { 21 | url = "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"; 22 | sha512 = "3p7hw8p69ikj5mwapmqkacsjnbvdfk5ylyamjg9x5izkl717xvzj0vk3fnmx1n4pf54h5rs7r8ig5kk4jv4ycqqj0hv75cnx6k1lf2j"; 23 | }; 24 | }; 25 | }; 26 | in 27 | { 28 | "uglify-js-3.4.9" = nodeEnv.buildNodePackage { 29 | name = "uglify-js"; 30 | packageName = "uglify-js"; 31 | version = "3.4.9"; 32 | src = fetchurl { 33 | url = "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz"; 34 | sha512 = "3axdjl69nv292w1d80vw7pa6rlj14xz4j307268hz2xszfgqf03fswhbf56w4fvkfk5b24c5ag4m9lv7aqyibrwn74vj4ddldn6q8ph"; 35 | }; 36 | dependencies = [ 37 | sources."commander-2.17.1" 38 | sources."source-map-0.6.1" 39 | ]; 40 | buildInputs = globalBuildInputs; 41 | meta = { 42 | description = "JavaScript parser, mangler/compressor and beautifier toolkit"; 43 | homepage = "https://github.com/mishoo/UglifyJS2#readme"; 44 | license = "BSD-2-Clause"; 45 | }; 46 | production = true; 47 | bypassCache = true; 48 | }; 49 | } -------------------------------------------------------------------------------- /pkgs/writeBashScript.nix: -------------------------------------------------------------------------------- 1 | { bash, writeTextFile, haskellPackages }: 2 | 3 | let 4 | 5 | shellcheck = haskellPackages.ShellCheck; 6 | 7 | in 8 | 9 | name: text: 10 | writeTextFile 11 | { 12 | inherit name; 13 | executable = true; 14 | text = '' 15 | #!${bash}/bin/bash 16 | ${text} 17 | ''; 18 | checkPhase = '' 19 | ${shellcheck}/bin/shellcheck "$out" 20 | ''; 21 | } 22 | -------------------------------------------------------------------------------- /pkgs/writeBashScriptBin.nix: -------------------------------------------------------------------------------- 1 | { writeBashScript, runCommand }: 2 | 3 | name: text: 4 | runCommand name { } '' 5 | mkdir -p $out/bin 6 | cp -a ${writeBashScript name text} $out/bin/${name} 7 | '' 8 | -------------------------------------------------------------------------------- /pkgs/writePHPFile.nix: -------------------------------------------------------------------------------- 1 | { writeTextFile, php }: 2 | 3 | name: text: 4 | writeTextFile 5 | { 6 | inherit name text; 7 | checkPhase = '' 8 | ${php}/bin/php -l "$out" 9 | ''; 10 | } 11 | -------------------------------------------------------------------------------- /pkgs/writeXML.nix: -------------------------------------------------------------------------------- 1 | { writeTextFile, libxml2 }: 2 | 3 | name: text: 4 | writeTextFile 5 | { 6 | inherit name text; 7 | checkPhase = '' 8 | ${libxml2.bin}/bin/xmllint \ 9 | --format --noblanks --nocdata "$out" > linted 10 | mv linted "$out" 11 | ''; 12 | } 13 | -------------------------------------------------------------------------------- /pkgs/writeYAML.nix: -------------------------------------------------------------------------------- 1 | { writeTextFile, pythonPackages }: 2 | 3 | let 4 | 5 | yamllint = pythonPackages.yamllint; 6 | 7 | in 8 | 9 | name: text: 10 | writeTextFile 11 | { 12 | inherit name text; 13 | checkPhase = '' 14 | ${yamllint}/bin/yamllint "$out" 15 | ''; 16 | } 17 | -------------------------------------------------------------------------------- /pkgs/xinclude2nix/default.nix: -------------------------------------------------------------------------------- 1 | { runCommand, haskellPackages }: 2 | 3 | /* 4 | Given a list of XML files, produces a Nix file with a list of files included 5 | with the XInclude mechanism. The file produced can be imported into other 6 | Nix files. This requires read-write mode of evaluation. 7 | 8 | Use case: XML config files with portions of sensitive data (secrets, keys), 9 | merged in runtime. With this package, deployment tools like NixOps can be 10 | taught to extract keys and deploy them automatically. 11 | 12 | 13 | Example of input file (for Jenkins): 14 | 15 | <?xml version="1.0" encoding="UTF-8"?> 16 | <hudson xmlns:xi="http://www.w3.org/2001/XInclude"> 17 | <useSecurity>true</useSecurity> 18 | <authorizationStrategy class="hudson.security.ProjectMatrixAuthorizationStrategy"> 19 | <permission>hudson.model.Hudson.Read:ip1981</permission> 20 | <permission>hudson.model.Item.Build:ip1981</permission> 21 | <permission>hudson.model.Item.Cancel:ip1981</permission> 22 | <permission>hudson.model.Item.Read:ip1981</permission> 23 | <permission>hudson.model.Hudson.Administer:ip1981</permission> 24 | </authorizationStrategy> 25 | <securityRealm class="org.jenkinsci.plugins.GithubSecurityRealm"> 26 | <clientID>XXXXXXXXXXXXXXXXXXX</clientID> 27 | <xi:include href="/run/keys/github-oauth-XXXXXXXXXXXXXXXXXXX.xml"/> 28 | <oauthScopes>read:org,user:email</oauthScopes> 29 | </securityRealm> 30 | </hudson> 31 | 32 | 33 | Corresponding output file (/nix/store/abc...xyz-xinclude.nix): 34 | 35 | ["/run/keys/github-oauth-XXXXXXXXXXXXXXXXXXX.xml"] 36 | 37 | */ 38 | 39 | # XXX: either string or list of strings 40 | xmlFiles: 41 | 42 | let 43 | 44 | inherit (builtins) toString; 45 | 46 | xinclude2nix = 47 | let 48 | deps = hpkgs: with hpkgs; [ hxt ]; 49 | ghc = "${haskellPackages.ghcWithPackages deps}/bin/ghc -Wall -static"; 50 | in runCommand "xinclude2nix" {} '' 51 | ${ghc} -o $out ${./xinclude2nix.hs} 52 | ''; 53 | 54 | in runCommand "xinclude.nix" {} '' 55 | echo ${xinclude2nix} ${toString xmlFiles} >&2 56 | ${xinclude2nix} ${toString xmlFiles} > $out 57 | echo -n "$out: " >&2 58 | cat "$out" >&2 59 | '' 60 | 61 | -------------------------------------------------------------------------------- /pkgs/xinclude2nix/xinclude2nix.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE Arrows #-} 2 | 3 | {- 4 | Takes a list of XML files 5 | Parses them for xi:xinclude elements 6 | Extract included files 7 | Prints list of included files 8 | -} 9 | module Main 10 | ( main 11 | ) where 12 | 13 | import Data.List (isPrefixOf, stripPrefix) 14 | import Data.Maybe (fromMaybe) 15 | import System.Environment (getArgs) 16 | import Text.XML.HXT.Core 17 | ((>>>), deep, getAttrValue, hasAttr, hasName, isElem, readDocument, 18 | returnA, runX) 19 | 20 | getXIncludes :: FilePath -> IO [String] 21 | getXIncludes xmlFileName = 22 | runX $ 23 | readDocument [] xmlFileName >>> 24 | deep (isElem >>> hasName "xi:include" >>> hasAttr "href") >>> 25 | proc d -> 26 | do href <- getAttrValue "href" -< d 27 | returnA -< href 28 | 29 | getFiles :: [String] -> [String] 30 | getFiles = map stripScheme . filter isFile 31 | where 32 | fileScheme = "file://" 33 | isFile s = "/" `isPrefixOf` s || (fileScheme `isPrefixOf` s) 34 | stripScheme u = fromMaybe u (stripPrefix fileScheme u) 35 | 36 | unique :: [String] -> [String] 37 | unique [] = [] 38 | unique (x:xs) 39 | | x `elem` xs = unique xs 40 | | otherwise = x : unique xs 41 | 42 | toNix :: [String] -> String 43 | toNix ss = "[" ++ unwords (map show ss) ++ "]" 44 | 45 | main :: IO () 46 | main = do 47 | paths <- getArgs 48 | includedFiles <- unique . getFiles . concat <$> mapM getXIncludes paths 49 | putStrLn $ toNix includedFiles 50 | --------------------------------------------------------------------------------