diff options
Diffstat (limited to 'nixos')
103 files changed, 2401 insertions, 967 deletions
diff --git a/nixos/doc/manual/configuration.xml b/nixos/doc/manual/configuration.xml index e6d7dee251af..307719d2cd2e 100644 --- a/nixos/doc/manual/configuration.xml +++ b/nixos/doc/manual/configuration.xml @@ -1025,7 +1025,6 @@ users.extraUsers.alice = home = "/home/alice"; description = "Alice Foobar"; extraGroups = [ "wheel" ]; - isSystemUser = false; useDefaultShell = true; openssh.authorizedKeys.keys = [ "ssh-dss AAAAB3Nza... alice@foobar" ]; }; @@ -1184,7 +1183,7 @@ driver from a set of X.org drivers (such as <literal>vesa</literal> and <literal>intel</literal>). You can also specify a driver manually, e.g. <programlisting> -services.xserver.videoDrivers = [ "r128" ]; +hardware.opengl.videoDrivers = [ "r128" ]; </programlisting> to enable X.org’s <literal>xf86-video-r128</literal> driver.</para> @@ -1227,7 +1226,7 @@ $ systemctl start display-manager.service has better 3D performance than the X.org drivers. It is not enabled by default because it’s not free software. You can enable it as follows: <programlisting> -services.xserver.videoDrivers = [ "nvidia" ]; +hardware.opengl.videoDrivers = [ "nvidia" ]; </programlisting> You may need to reboot after enabling this driver to prevent a clash with other kernel modules.</para> diff --git a/nixos/doc/manual/installation.xml b/nixos/doc/manual/installation.xml index 70001577692e..f6b477ed69bc 100644 --- a/nixos/doc/manual/installation.xml +++ b/nixos/doc/manual/installation.xml @@ -1,5 +1,6 @@ <chapter xmlns="http://docbook.org/ns/docbook" - xmlns:xlink="http://www.w3.org/1999/xlink"> + xmlns:xlink="http://www.w3.org/1999/xlink" + xml:id="installing-nixos"> <title>Installing NixOS</title> @@ -295,8 +296,74 @@ $ reboot</screen> }</screen> </example> +<section xml:id="sec-uefi-installation"> + +<title>UEFI Installation</title> + +<para>NixOS can also be installed on UEFI systems. The procedure +is by and large the same as a BIOS installation, with the following +changes: + +<itemizedlist> + <listitem> + <para>You should boot the live CD in UEFI mode (consult your + specific hardware's documentation for instructions).</para> + </listitem> + <listitem> + <para>Instead of <command>fdisk</command>, you should use + <command>gdisk</command> to partition your disks. You will need to + have a separate partition for <filename>/boot</filename> with + partition code EF00, and it should be formatted as a + <literal>vfat</literal> filesystem.</para> + </listitem> + <listitem> + <para>You must set <option>boot.loader.gummiboot.enable</option> to + <literal>true</literal>, and <option>boot.loader.grub.enable</option> + to <literal>false</literal>. <command>nixos-generate-config</command> + should do this automatically for new configurations when booted in + UEFI mode.</para> + </listitem> + <listitem> + <para>You may want to look at the options starting with + <option>boot.loader.efi</option> and <option>boot.loader.gummiboot</option> + as well.</para> + </listitem> + <listitem> + <para>To see console messages during early boot, add <literal>"fbcon"</literal> + to your <option>boot.initrd.kernelModules</option>.</para> + </listitem> +</itemizedlist> +</para> + </section> +<section> + +<title>Booting from a USB stick</title> + +<para>For systems withoua CD drive, the NixOS livecd can be booted from +a usb stick. For non-UEFI installations, +<link xlink:href="http://unetbootin.sourceforge.net/">unetbootin</link> +will work. For UEFI installations, you should mount the ISO, copy its contents +verbatim to your drive, then either: + +<itemizedlist> + <listitem> + <para>Change the label of the disk partition to the label of the ISO + (visible with the blkid command), or</para> + </listitem> + <listitem> + <para>Edit <filename>loader/entries/nixos-livecd.conf</filename> on the drive + and change the <literal>root=</literal> field in the <literal>options</literal> + line to point to your drive (see the documentation on <literal>root=</literal> + in <link xlink:href="https://www.kernel.org/doc/Documentation/kernel-parameters.txt"> + the kernel documentation</link> for more details).</para> + </listitem> +</itemizedlist> +</para> +</section> + +</section> <!--===============================================================--> diff --git a/nixos/doc/manual/manual.xml b/nixos/doc/manual/manual.xml index 6e13281cbd94..f9775f4f0170 100644 --- a/nixos/doc/manual/manual.xml +++ b/nixos/doc/manual/manual.xml @@ -55,9 +55,12 @@ <!-- <xi:include href="userconfiguration.xml" /> --> <xi:include href="troubleshooting.xml" /> <xi:include href="development.xml" /> - <chapter xml:id="ch-options"> + + <xi:include href="release-notes.xml" /> + + <appendix xml:id="ch-options"> <title>List of options</title> <xi:include href="options-db.xml" /> - </chapter> + </appendix> </book> diff --git a/nixos/doc/manual/options-to-docbook.xsl b/nixos/doc/manual/options-to-docbook.xsl index 6d11ad7a6c4a..9647aae0f2fb 100644 --- a/nixos/doc/manual/options-to-docbook.xsl +++ b/nixos/doc/manual/options-to-docbook.xsl @@ -18,15 +18,14 @@ <variablelist> <xsl:for-each select="attrs"> - <varlistentry> - <term> - <option> + <term xml:id="{generate-id(attr[@name = 'name']/string/@value)}" xlink:href="#{generate-id(attr[@name = 'name']/string/@value)}"> + <option> <xsl:for-each select="attr[@name = 'name']/string"> <xsl:value-of select="@value" /> <xsl:if test="position() != last()">.</xsl:if> </xsl:for-each> - </option> + </option> </term> <listitem> diff --git a/nixos/doc/manual/release-notes.xml b/nixos/doc/manual/release-notes.xml new file mode 100644 index 000000000000..8899cbb21498 --- /dev/null +++ b/nixos/doc/manual/release-notes.xml @@ -0,0 +1,57 @@ +<appendix xmlns="http://docbook.org/ns/docbook" + xml:id="ch-release-notes"> + +<title>Release notes</title> + +<!--==================================================================--> + +<section xml:id="sec-release-14.02"> + +<title>Release 14.02 (“Baboon”, 2014/02/??)</title> + +<para>This is the second stable release branch of NixOS. The main +enhancements are the following: + +<itemizedlist> + + <listitem><para>Installation on UEFI systems is now supported. See + <xref linkend="sec-uefi-installation"/> for + details.</para></listitem> + + <listitem><para>NixOS is now based on Glibc 2.18 and GCC + 4.8.</para></listitem> + + <listitem><para>The mysql55 service has been merged into the + mysql service, which no longer sets a default for the 'package + option.</para></listitem> + +</itemizedlist> + +</para> + +<para>When upgrading from a previous release, please be aware of the +following incompatible changes: + +<itemizedlist> + + <listitem><para>The option + <option>boot.loader.grub.memtest86</option> has been renamed to + <option>boot.loader.grub.memtest86.enable</option>.</para></listitem> + +</itemizedlist> + +</para> + +</section> + +<!--==================================================================--> + +<section xml:id="sec-release-13.10"> + +<title>Release 13.10 (“Aardvark”, 2013/10/31)</title> + +<para>This is the first stable release branch of NixOS.</para> + +</section> + +</appendix> diff --git a/nixos/lib/test-driver/test-driver.pl b/nixos/lib/test-driver/test-driver.pl index c6a707cdf6b9..31f3281cefe0 100644 --- a/nixos/lib/test-driver/test-driver.pl +++ b/nixos/lib/test-driver/test-driver.pl @@ -144,6 +144,13 @@ sub runTests { } }); + $log->nest("syncing", sub { + foreach my $vm (values %vms) { + next unless $vm->isUp(); + $vm->execute("sync /tmp/xchg"); + } + }); + if ($nrTests != 0) { $log->log("$nrSucceeded out of $nrTests tests succeeded", ($nrSucceeded < $nrTests ? { error => 1 } : { })); diff --git a/nixos/lib/testing.nix b/nixos/lib/testing.nix index 3407229e921a..d5338bc04cac 100644 --- a/nixos/lib/testing.nix +++ b/nixos/lib/testing.nix @@ -67,62 +67,16 @@ rec { }; - # Generate a coverage report from the coverage data produced by - # runTests. - makeReport = x: runCommand "report" { buildInputs = [rsync]; } - '' - mkdir -p $TMPDIR/gcov/ - - for d in ${x}/coverage-data/*; do - echo "doing $d" - [ -n "$(ls -A "$d")" ] || continue - - for i in $(cd $d/nix/store && ls); do - if ! test -e $TMPDIR/gcov/nix/store/$i; then - echo "copying $i" - mkdir -p $TMPDIR/gcov/$(echo $i | cut -c34-) - rsync -rv /nix/store/$i/.build/* $TMPDIR/gcov/ - fi - done - - chmod -R u+w $TMPDIR/gcov - - find $TMPDIR/gcov -name "*.gcda" -exec rm {} \; - - for i in $(cd $d/nix/store && ls); do - rsync -rv $d/nix/store/$i/.build/* $TMPDIR/gcov/ - done - - find $TMPDIR/gcov -name "*.gcda" -exec chmod 644 {} \; - - echo "producing info..." - ${pkgs.lcov}/bin/geninfo --ignore-errors source,gcov $TMPDIR/gcov --output-file $TMPDIR/app.info - cat $TMPDIR/app.info >> $TMPDIR/full.info - done - - echo "making report..." - mkdir -p $out/coverage - ${pkgs.lcov}/bin/genhtml --show-details $TMPDIR/full.info -o $out/coverage - cp $TMPDIR/full.info $out/coverage/ - - mkdir -p $out/nix-support - cat ${x}/nix-support/hydra-build-products >> $out/nix-support/hydra-build-products - echo "report coverage $out/coverage" >> $out/nix-support/hydra-build-products - [ ! -e ${x}/nix-support/failed ] || touch $out/nix-support/failed - ''; # */ - - makeTest = testFun: complete (call testFun); makeTests = testsFun: lib.mapAttrs (name: complete) (call testsFun); apply = makeTest; # compatibility call = f: f { inherit pkgs system; }; - complete = t: t // rec { + complete = { testScript, ... } @ t: t // rec { + nodes = buildVirtualNetwork ( - if t ? nodes then t.nodes else - if t ? machine then { machine = t.machine; } - else { } ); + t.nodes or (if t ? machine then { machine = t.machine; } else { })); testScript = # Call the test script with the computed nodes. @@ -162,7 +116,7 @@ rec { test = runTests driver; - report = makeReport test; + report = releaseTools.gcovReport { coverageRuns = [ test ]; }; }; diff --git a/nixos/maintainers/scripts/ec2/create-ebs-amis.py b/nixos/maintainers/scripts/ec2/create-ebs-amis.py index 541eadd7b8c9..eab111a2665b 100755 --- a/nixos/maintainers/scripts/ec2/create-ebs-amis.py +++ b/nixos/maintainers/scripts/ec2/create-ebs-amis.py @@ -203,7 +203,7 @@ f = open("{0}.{1}.ami-id".format(args.region, image_type), "w") f.write("{0}".format(ami_id)) f.close() -for dest in [ 'us-east-1', 'us-west-1', 'us-west-2', 'eu-west-1']: +for dest in [ 'us-east-1', 'us-west-1', 'us-west-2', 'eu-west-1', 'ap-southeast-1', 'ap-southeast-2', 'ap-northeast-1', 'sa-east-1']: if args.region != dest: print >> sys.stderr, "copying image from region {0} to {1}".format(args.region, dest) conn = boto.ec2.connect_to_region(dest) diff --git a/nixos/modules/config/i18n.nix b/nixos/modules/config/i18n.nix index 56d541cb9b3b..310739aa1707 100644 --- a/nixos/modules/config/i18n.nix +++ b/nixos/modules/config/i18n.nix @@ -53,7 +53,11 @@ in }; consoleKeyMap = mkOption { - type = types.str; + type = mkOptionType { + name = "string or path"; + check = t: (isString t || types.path.check t); + }; + default = "us"; example = "fr"; description = '' diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix index e7cbe7a28f36..db4f1b43a114 100644 --- a/nixos/modules/config/pulseaudio.nix +++ b/nixos/modules/config/pulseaudio.nix @@ -77,7 +77,7 @@ in { }; package = mkOption { - type = types.path; + type = types.package; default = pulseaudio; example = literalExample "pulseaudio.override { jackaudioSupport = true; }"; description = '' diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index 714de646eb7a..2d9b941a2cae 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -5,7 +5,25 @@ with pkgs.lib; let ids = config.ids; - users = config.users; + cfg = config.users; + + passwordDescription = '' + The options <literal>hashedPassword</literal>, + <literal>password</literal> and <literal>passwordFile</literal> + controls what password is set for the user. + <literal>hashedPassword</literal> overrides both + <literal>password</literal> and <literal>passwordFile</literal>. + <literal>password</literal> overrides <literal>passwordFile</literal>. + If none of these three options are set, no password is assigned to + the user, and the user will not be able to do password logins. + If the option <literal>users.mutableUsers</literal> is true, the + password defined in one of the three options will only be set when + the user is created for the first time. After that, you are free to + change the password with the ordinary user management commands. If + <literal>users.mutableUsers</literal> is false, you cannot change + user passwords, they will always be set according to the password + options. + ''; userOpts = { name, config, ... }: { @@ -28,9 +46,8 @@ let }; uid = mkOption { - type = with types; uniq (nullOr int); - default = null; - description = "The account UID. If undefined, NixOS will select a free UID."; + type = with types; uniq int; + description = "The account UID."; }; group = mkOption { @@ -60,31 +77,54 @@ let createHome = mkOption { type = types.bool; default = false; - description = "If true, the home directory will be created automatically."; + description = '' + If true, the home directory will be created automatically. If this + option is true and the home directory already exists but is not + owned by the user, directory owner and group will be changed to + match the user. + ''; }; useDefaultShell = mkOption { type = types.bool; default = false; - description = "If true, the user's shell will be set to <literal>users.defaultUserShell</literal>."; + description = '' + If true, the user's shell will be set to + <literal>cfg.defaultUserShell</literal>. + ''; + }; + + hashedPassword = mkOption { + type = with types; uniq (nullOr str); + default = null; + description = '' + Specifies the (hashed) password for the user. + ${passwordDescription} + ''; }; password = mkOption { type = with types; uniq (nullOr str); default = null; description = '' - The user's password. If undefined, no password is set for - the user. Warning: do not set confidential information here - because it is world-readable in the Nix store. This option - should only be used for public accounts such as - <literal>guest</literal>. + Specifies the (clear text) password for the user. + Warning: do not set confidential information here + because it is world-readable in the Nix store. This option + should only be used for public accounts. + ${passwordDescription} ''; }; - isSystemUser = mkOption { - type = types.bool; - default = true; - description = "Indicates if the user is a system user or not."; + passwordFile = mkOption { + type = with types; uniq (nullOr string); + default = null; + description = '' + The path to a file that contains the user's password. The password + file is read on each system activation. The file should contain + exactly one line, which should be the password in an encrypted form + that is suitable for the <literal>chpasswd -e</literal> command. + ${passwordDescription} + ''; }; createUser = mkOption { @@ -96,19 +136,11 @@ let then not modify any of the basic properties for the user account. ''; }; - - isAlias = mkOption { - type = types.bool; - default = false; - description = "If true, the UID of this user is not required to be unique and can thus alias another user."; - }; - }; config = { name = mkDefault name; - uid = mkDefault (attrByPath [name] null ids.uids); - shell = mkIf config.useDefaultShell (mkDefault users.defaultUserShell); + shell = mkIf config.useDefaultShell (mkDefault cfg.defaultUserShell); }; }; @@ -123,29 +155,114 @@ let }; gid = mkOption { - type = with types; uniq (nullOr int); - default = null; - description = "The GID of the group. If undefined, NixOS will select a free GID."; + type = with types; uniq int; + description = "The GID of the group."; + }; + + members = mkOption { + type = with types; listOf string; + default = []; + description = '' + The user names of the group members, added to the + <literal>/etc/group</literal> file. + ''; }; }; config = { name = mkDefault name; - gid = mkDefault (attrByPath [name] null ids.gids); }; }; - # Note: the 'X' in front of the password is to distinguish between - # having an empty password, and not having a password. - serializedUser = u: "${u.name}\n${u.description}\n${if u.uid != null then toString u.uid else ""}\n${u.group}\n${toString (concatStringsSep "," u.extraGroups)}\n${u.home}\n${u.shell}\n${toString u.createHome}\n${if u.password != null then "X" + u.password else ""}\n${toString u.isSystemUser}\n${toString u.createUser}\n${toString u.isAlias}\n"; - - usersFile = pkgs.writeText "users" ( + getGroup = gname: let - p = partition (u: u.isAlias) (attrValues config.users.extraUsers); - in concatStrings (map serializedUser p.wrong ++ map serializedUser p.right)); - + groups = mapAttrsToList (n: g: g) ( + filterAttrs (n: g: g.name == gname) cfg.extraGroups + ); + in + if length groups == 1 then head groups + else if groups == [] then throw "Group ${gname} not defined" + else throw "Group ${gname} has multiple definitions"; + + getUser = uname: + let + users = mapAttrsToList (n: u: u) ( + filterAttrs (n: u: u.name == uname) cfg.extraUsers + ); + in + if length users == 1 then head users + else if users == [] then throw "User ${uname} not defined" + else throw "User ${uname} has multiple definitions"; + + mkGroupEntry = gname: + let + g = getGroup gname; + users = mapAttrsToList (n: u: u.name) ( + filterAttrs (n: u: elem g.name u.extraGroups) cfg.extraUsers + ); + in concatStringsSep ":" [ + g.name "x" (toString g.gid) + (concatStringsSep "," (users ++ (filter (u: !(elem u users)) g.members))) + ]; + + mkPasswdEntry = uname: let u = getUser uname; in + concatStringsSep ":" [ + u.name "x" (toString u.uid) + (toString (getGroup u.group).gid) + u.description u.home u.shell + ]; + + sortOn = a: sort (as1: as2: lessThan (getAttr a as1) (getAttr a as2)); + + groupFile = pkgs.writeText "group" ( + concatStringsSep "\n" (map (g: mkGroupEntry g.name) ( + sortOn "gid" (attrValues cfg.extraGroups) + )) + ); + + passwdFile = pkgs.writeText "passwd" ( + concatStringsSep "\n" (map (u: mkPasswdEntry u.name) ( + sortOn "uid" (filter (u: u.createUser) (attrValues cfg.extraUsers)) + )) + ); + + # If mutableUsers is true, this script adds all users/groups defined in + # users.extra{Users,Groups} to /etc/{passwd,group} iff there isn't any + # existing user/group with the same name in those files. + # If mutableUsers is false, the /etc/{passwd,group} files will simply be + # replaced with the users/groups defined in the NixOS configuration. + # The merging procedure could certainly be improved, and instead of just + # keeping the lines as-is from /etc/{passwd,group} they could be combined + # in some way with the generated content from the NixOS configuration. + merger = src: pkgs.writeScript "merger" '' + #!${pkgs.bash}/bin/bash + + PATH=${pkgs.gawk}/bin:${pkgs.gnugrep}/bin:$PATH + + ${if !cfg.mutableUsers + then ''cp ${src} $1.tmp'' + else ''awk -F: '{ print "^"$1":.*" }' $1 | egrep -vf - ${src} | cat $1 - > $1.tmp'' + } + + # set mtime to +1, otherwise change might go unnoticed (vipw/vigr only looks at mtime) + touch -m -t $(date -d @$(($(stat -c %Y $1)+1)) +%Y%m%d%H%M.%S) $1.tmp + + mv -f $1.tmp $1 + ''; + + idsAreUnique = set: idAttr: !(fold (name: args@{ dup, acc }: + let + id = builtins.toString (builtins.getAttr idAttr (builtins.getAttr name set)); + exists = builtins.hasAttr id acc; + newAcc = acc // (builtins.listToAttrs [ { name = id; value = true; } ]); + in if dup then args else if exists + then builtins.trace "Duplicate ${idAttr} ${id}" { dup = true; acc = null; } + else { dup = false; acc = newAcc; } + ) { dup = false; acc = {}; } (builtins.attrNames set)).dup; + uidsAreUnique = idsAreUnique cfg.extraUsers "uid"; + gidsAreUnique = idsAreUnique cfg.extraGroups "gid"; in { @@ -154,6 +271,36 @@ in options = { + users.mutableUsers = mkOption { + type = types.bool; + default = true; + description = '' + If true, you are free to add new users and groups to the system + with the ordinary <literal>useradd</literal> and + <literal>groupadd</literal> commands. On system activation, the + existing contents of the <literal>/etc/passwd</literal> and + <literal>/etc/group</literal> files will be merged with the + contents generated from the <literal>users.extraUsers</literal> and + <literal>users.extraGroups</literal> options. If + <literal>mutableUsers</literal> is false, the contents of the user and + group files will simply be replaced on system activation. This also + holds for the user passwords; if this option is false, all changed + passwords will be reset according to the + <literal>users.extraUsers</literal> configuration on activation. If + this option is true, the initial password for a user will be set + according to <literal>users.extraUsers</literal>, but existing passwords + will not be changed. + ''; + }; + + users.enforceIdUniqueness = mkOption { + type = types.bool; + default = true; + description = '' + Whether to require that no two users/groups share the same uid/gid. + ''; + }; + users.extraUsers = mkOption { default = {}; type = types.loaOf types.optionSet; @@ -194,11 +341,17 @@ in example = "!"; description = '' The (hashed) password for the root account set on initial - installation. The empty string denotes that root can login + installation. The empty string denotes that root can login locally without a password (but not via remote services such as SSH, or indirectly via <command>su</command> or - <command>sudo</command>). The string <literal>!</literal> + <command>sudo</command>). The string <literal>!</literal> prevents root from logging in using a password. + Note, setting this option sets + <literal>users.extraUsers.root.hashedPassword</literal>. + Note, if <literal>users.mutableUsers</literal> is false + you cannot change the root password manually, so in that case + the name of this option is a bit misleading, since it will define + the root password beyond the user initialisation phase. ''; }; @@ -211,144 +364,91 @@ in users.extraUsers = { root = { + uid = ids.uids.root; description = "System administrator"; home = "/root"; - shell = config.users.defaultUserShell; + shell = cfg.defaultUserShell; group = "root"; + hashedPassword = mkDefault config.security.initialRootPassword; }; nobody = { + uid = ids.uids.nobody; description = "Unprivileged account (don't use!)"; + group = "nogroup"; }; }; users.extraGroups = { - root = { }; - wheel = { }; - disk = { }; - kmem = { }; - tty = { }; - floppy = { }; - uucp = { }; - lp = { }; - cdrom = { }; - tape = { }; - audio = { }; - video = { }; - dialout = { }; - nogroup = { }; - users = { }; - nixbld = { }; - utmp = { }; - adm = { }; # expected by journald + root.gid = ids.gids.root; + wheel.gid = ids.gids.wheel; + disk.gid = ids.gids.disk; + kmem.gid = ids.gids.kmem; + tty.gid = ids.gids.tty; + floppy.gid = ids.gids.floppy; + uucp.gid = ids.gids.uucp; + lp.gid = ids.gids.lp; + cdrom.gid = ids.gids.cdrom; + tape.gid = ids.gids.tape; + audio.gid = ids.gids.audio; + video.gid = ids.gids.video; + dialout.gid = ids.gids.dialout; + nogroup.gid = ids.gids.nogroup; + users.gid = ids.gids.users; + nixbld.gid = ids.gids.nixbld; + utmp.gid = ids.gids.utmp; + adm.gid = ids.gids.adm; }; - system.activationScripts.rootPasswd = stringAfter [ "etc" ] - '' - # If there is no password file yet, create a root account with an - # empty password. - if ! test -e /etc/passwd; then - rootHome=/root - touch /etc/passwd; chmod 0644 /etc/passwd - touch /etc/group; chmod 0644 /etc/group - touch /etc/shadow; chmod 0600 /etc/shadow - # Can't use useradd, since it complains that it doesn't know us - # (bootstrap problem!). - echo "root:x:0:0:System administrator:$rootHome:${config.users.defaultUserShell}" >> /etc/passwd - echo "root:${config.security.initialRootPassword}:::::::" >> /etc/shadow - fi - ''; - - # Print a reminder for users to set a root password. - environment.interactiveShellInit = - '' - if [ "$UID" = 0 ]; then - read _l < /etc/shadow - if [ "''${_l:0:6}" = root:: ]; then - cat >&2 <<EOF - [1;31mWarning:[0m Your root account has a null password, allowing local users - to login as root. Please set a non-null password using \`passwd', or - disable password-based root logins using \`passwd -l'. - EOF - fi - unset _l - fi - ''; - - system.activationScripts.users = stringAfter [ "groups" ] - '' - echo "updating users..." - - cat ${usersFile} | while true; do - read name || break - read description - read uid - read group - read extraGroups - read home - read shell - read createHome - read password - read isSystemUser - read createUser - read isAlias - - if [ -z "$createUser" ]; then - continue - fi - - if ! curEnt=$(getent passwd "$name"); then - useradd ''${isSystemUser:+--system} \ - --comment "$description" \ - ''${uid:+--uid $uid} \ - --gid "$group" \ - --groups "$extraGroups" \ - --home "$home" \ - --shell "$shell" \ - ''${createHome:+--create-home} \ - ''${isAlias:+--non-unique} \ - "$name" - if test "''${password:0:1}" = 'X'; then - (echo "''${password:1}"; echo "''${password:1}") | ${pkgs.shadow}/bin/passwd "$name" - fi - else - #echo "updating user $name..." - oldIFS="$IFS"; IFS=:; set -- $curEnt; IFS="$oldIFS" - prevUid=$3 - prevHome=$6 - # Don't change the home directory if it's the same to prevent - # unnecessary warnings about logged in users. - if test "$prevHome" = "$home"; then unset home; fi - usermod \ - --comment "$description" \ - --gid "$group" \ - --groups "$extraGroups" \ - ''${home:+--home "$home"} \ - --shell "$shell" \ - "$name" - fi - - done + system.activationScripts.users = + let + mkhomeUsers = filterAttrs (n: u: u.createHome) cfg.extraUsers; + setpwUsers = filterAttrs (n: u: u.createUser) cfg.extraUsers; + pwFile = u: if !(isNull u.hashedPassword) + then pkgs.writeTextFile { name = "password-file"; text = u.hashedPassword; } + else if !(isNull u.password) + then pkgs.runCommand "password-file" { pw = u.password; } '' + echo -n "$pw" | ${pkgs.mkpasswd}/bin/mkpasswd -s > $out + '' else u.passwordFile; + setpw = n: u: '' + setpw=yes + ${optionalString cfg.mutableUsers '' + test "$(getent shadow '${u.name}' | cut -d: -f2)" != "x" && setpw=no + ''} + if [ "$setpw" == "yes" ]; then + ${if !(isNull (pwFile u)) + then '' + echo -n "${u.name}:" | cat - "${pwFile u}" | \ + ${pkgs.shadow}/sbin/chpasswd -e + '' + else "passwd -l '${u.name}' &>/dev/null" + } + fi + ''; + mkhome = n: u: + let + uid = toString u.uid; + gid = toString ((getGroup u.group).gid); + h = u.home; + in '' + test -a "${h}" || mkdir -p "${h}" || true + test "$(stat -c %u "${h}")" = ${uid} || chown ${uid} "${h}" || true + test "$(stat -c %g "${h}")" = ${gid} || chgrp ${gid} "${h}" || true + ''; + in stringAfter [ "etc" ] '' + touch /etc/group + touch /etc/passwd + VISUAL=${merger groupFile} ${pkgs.shadow}/sbin/vigr &>/dev/null + VISUAL=${merger passwdFile} ${pkgs.shadow}/sbin/vipw &>/dev/null + ${pkgs.shadow}/sbin/grpconv + ${pkgs.shadow}/sbin/pwconv + ${concatStrings (mapAttrsToList mkhome mkhomeUsers)} + ${concatStrings (mapAttrsToList setpw setpwUsers)} ''; - system.activationScripts.groups = stringAfter [ "rootPasswd" "binsh" "etc" "var" ] - '' - echo "updating groups..." + # for backwards compatibility + system.activationScripts.groups = stringAfter [ "users" ] ""; - createGroup() { - name="$1" - gid="$2" - - if ! curEnt=$(getent group "$name"); then - groupadd --system \ - ''${gid:+--gid $gid} \ - "$name" - fi - } - - ${flip concatMapStrings (attrValues config.users.extraGroups) (g: '' - createGroup '${g.name}' '${toString g.gid}' - '')} - ''; + assertions = [ { assertion = !cfg.enforceIdUniqueness || (uidsAreUnique && gidsAreUnique); message = "uids and gids must be unique!"; } ]; }; diff --git a/nixos/modules/services/x11/mesa.nix b/nixos/modules/hardware/opengl.nix index f892a1517582..603012cb1092 100644 --- a/nixos/modules/services/x11/mesa.nix +++ b/nixos/modules/hardware/opengl.nix @@ -2,19 +2,19 @@ let inherit (pkgs.lib) mkOption types mkIf optional optionals elem optionalString optionalAttrs; - cfg = config.services.mesa; + cfg = config.hardware.opengl; kernelPackages = config.boot.kernelPackages; in { options = { - services.mesa.enable = mkOption { - description = "Whether this configuration requires mesa."; + hardware.opengl.enable = mkOption { + description = "Whether this configuration requires opengl."; type = types.bool; default = false; internal = true; }; - services.mesa.driSupport = mkOption { + hardware.opengl.driSupport = mkOption { type = types.bool; default = true; description = '' @@ -23,18 +23,18 @@ in { ''; }; - services.mesa.driSupport32Bit = mkOption { + hardware.opengl.driSupport32Bit = mkOption { type = types.bool; default = false; description = '' On 64-bit systems, whether to support Direct Rendering for 32-bit applications (such as Wine). This is currently only supported for the <literal>nvidia</literal> driver and for - <literal>mesa</literal>. + <literal>Mesa</literal>. ''; }; - services.mesa.s3tcSupport = mkOption { + hardware.opengl.s3tcSupport = mkOption { type = types.bool; default = false; description = '' @@ -47,27 +47,32 @@ in { }; - services.mesa.videoDrivers = mkOption { + hardware.opengl.videoDrivers = mkOption { type = types.listOf types.str; # !!! We'd like "nv" here, but it segfaults the X server. default = [ "ati" "cirrus" "intel" "vesa" "vmware" ]; example = [ "vesa" ]; description = '' - The names of the video drivers that the mesa should - support. Mesa will try all of the drivers listed - here until it finds one that supports your video card. + The names of the opengl video drivers the configuration + supports. They will be tried in order until one that + supports your card is found. ''; }; }; config = mkIf cfg.enable { + assertions = pkgs.lib.singleton { + assertion = cfg.driSupport32Bit -> pkgs.stdenv.isx86_64; + message = "Option driSupport32Bit only makes sens on a 64-bit system."; + }; + system.activationScripts.setup-opengl.deps = []; system.activationScripts.setup-opengl.text = '' rm -f /run/opengl-driver{,-32} - ${optionalString (!cfg.driSupport32Bit) "ln -sf opengl-driver /run/opengl-driver-32"} - - ${# !!! The OpenGL driver depends on what's detected at runtime. - if elem "nvidia" cfg.videoDrivers then + ${optionalString (pkgs.stdenv.isi686) "ln -sf opengl-driver /run/opengl-driver-32"} + '' + #TODO: The OpenGL driver should depend on what's detected at runtime. + +( if elem "nvidia" cfg.videoDrivers then '' ln -sf ${kernelPackages.nvidia_x11} /run/opengl-driver ${optionalString cfg.driSupport32Bit @@ -89,8 +94,7 @@ in { ${optionalString cfg.driSupport32Bit "ln -sf ${pkgs_i686.mesa_drivers} /run/opengl-driver-32"} '' - } - ''; + ); environment.variables.LD_LIBRARY_PATH = [ "/run/opengl-driver/lib" "/run/opengl-driver-32/lib" ] diff --git a/nixos/modules/hardware/video/bumblebee.nix b/nixos/modules/hardware/video/bumblebee.nix new file mode 100644 index 000000000000..504da2cde850 --- /dev/null +++ b/nixos/modules/hardware/video/bumblebee.nix @@ -0,0 +1,41 @@ +{ config, pkgs, ... }: + +let kernel = config.boot.kernelPackages; in +with pkgs.lib; + +{ + + options = { + hardware.bumblebee.enable = mkOption { + default = false; + type = types.bool; + description = '' + Enable the bumblebee daemon to manage Optimus hybrid video cards. + This should power off secondary GPU until its use is requested + by running an application with optirun. + + Only nvidia driver is supported so far. + ''; + }; + }; + + config = mkIf config.hardware.bumblebee.enable { + boot.blacklistedKernelModules = [ "nouveau" "nvidia" ]; + boot.kernelModules = [ "bbswitch" ]; + boot.extraModulePackages = [ kernel.bbswitch kernel.nvidia_x11 ]; + + environment.systemPackages = [ pkgs.bumblebee ]; + + systemd.services.bumblebeed = { + description = "Bumblebee Hybrid Graphics Switcher"; + wantedBy = [ "display-manager.service" ]; + script = "bumblebeed --use-syslog"; + path = [ kernel.bbswitch pkgs.bumblebee ]; + serviceConfig = { + Restart = "always"; + RestartSec = 60; + CPUSchedulingPolicy = "idle"; + }; + }; + }; +} diff --git a/nixos/modules/installer/cd-dvd/installation-cd-base.nix b/nixos/modules/installer/cd-dvd/installation-cd-base.nix index 1aba67dcd9e9..07c054b391af 100644 --- a/nixos/modules/installer/cd-dvd/installation-cd-base.nix +++ b/nixos/modules/installer/cd-dvd/installation-cd-base.nix @@ -19,7 +19,7 @@ with pkgs.lib; # ISO naming. isoImage.isoName = "${config.isoImage.isoBaseName}-${config.system.nixosVersion}-${pkgs.stdenv.system}.iso"; - isoImage.volumeID = substring 0 32 "NIXOS_${config.system.nixosVersion}"; + isoImage.volumeID = substring 0 11 "NIXOS_${config.system.nixosVersion}"; # Make the installer more likely to succeed in low memory # environments. The kernel's overcommit heustistics bite us @@ -36,7 +36,7 @@ with pkgs.lib; isoImage.makeEfiBootable = true; # Add Memtest86+ to the CD. - boot.loader.grub.memtest86 = true; + boot.loader.grub.memtest86.enable = true; # Get a console as soon as the initrd loads fbcon on EFI boot boot.initrd.kernelModules = [ "fbcon" ]; diff --git a/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix b/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix index 7f253d595dc3..c3ced8490014 100644 --- a/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix +++ b/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix @@ -138,8 +138,7 @@ in }; # Setting vesa, we don't get the nvidia driver, which can't work in arm. - services.xserver.videoDriver = "vesa"; - services.xserver.videoDrivers = []; + hardware.opengl.videoDrivers = [ "vesa" ]; services.nixosManual.enable = false; # Include the firmware for various wireless cards. diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl index 1365f3b93961..bf7cdcd37119 100644 --- a/nixos/modules/installer/tools/nixos-generate-config.pl +++ b/nixos/modules/installer/tools/nixos-generate-config.pl @@ -163,7 +163,7 @@ foreach my $path (glob "/sys/bus/pci/devices/*") { pciCheck $path; } -push @attrs, "services.xserver.videoDrivers = [ \"$videoDriver\" ];" if $videoDriver; +push @attrs, "hardware.opengl.videoDrivers = [ \"$videoDriver\" ];" if $videoDriver; # Idem for USB devices. @@ -256,7 +256,7 @@ foreach my $fs (read_file("/proc/self/mountinfo")) { $mountPoint = "/" if $mountPoint eq ""; # Skip special filesystems. - next if in($mountPoint, "/proc") || in($mountPoint, "/dev") || in($mountPoint, "/sys") || in($mountPoint, "/run"); + next if in($mountPoint, "/proc") || in($mountPoint, "/dev") || in($mountPoint, "/sys") || in($mountPoint, "/run") || $mountPoint eq "/var/lib/nfs/rpc_pipefs"; # Skip the optional fields. my $n = 6; $n++ while $fields[$n] ne "-"; $n++; @@ -305,7 +305,15 @@ EOF fileSystems.\"$mountPoint\" = { device = \"$device\"; fsType = \"$fsType\"; - options = \"${\join ",", uniq(@extraOptions, @superOptions, @mountOptions)}\"; +EOF + + if (scalar @extraOptions > 0) { + $fileSystems .= <<EOF; + options = \"${\join ",", uniq(@extraOptions)}\"; +EOF + } + + $fileSystems .= <<EOF; }; EOF diff --git a/nixos/modules/installer/tools/nixos-option.sh b/nixos/modules/installer/tools/nixos-option.sh index 60cee2519da0..edc94d732084 100644 --- a/nixos/modules/installer/tools/nixos-option.sh +++ b/nixos/modules/installer/tools/nixos-option.sh @@ -228,7 +228,7 @@ else escapeQuotes () { eval echo "$1"; } nixMap escapeQuotes "$names" else - echo 1>&2 "An error occured while looking for attribute names." + echo 1>&2 "An error occurred while looking for attribute names." echo $result fi fi diff --git a/nixos/modules/installer/virtualbox-demo.nix b/nixos/modules/installer/virtualbox-demo.nix index 76cc29a1facd..9ef41e470747 100644 --- a/nixos/modules/installer/virtualbox-demo.nix +++ b/nixos/modules/installer/virtualbox-demo.nix @@ -15,5 +15,5 @@ with pkgs.lib; # Add some more video drivers to give X11 a shot at working in # VMware and QEMU. - services.xserver.videoDrivers = mkOverride 40 [ "virtualbox" "vmware" "cirrus" "vesa" ]; + hardware.opengl.videoDrivers = mkOverride 40 [ "virtualbox" "vmware" "cirrus" "vesa" ]; } diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 0a585139521d..b27739c99ce0 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -110,7 +110,15 @@ openldap = 99; memcached = 100; cgminer = 101; - systemd-journal-gateway = 102; + munin = 102; + logcheck = 103; + nix-ssh = 104; + dictd = 105; + couchdb = 106; + searx = 107; + kippo = 108; + jenkins = 109; + systemd-journal-gateway = 110; # When adding a uid, make sure it doesn't match an existing gid. @@ -200,7 +208,14 @@ haproxy = 92; openldap = 93; connman = 94; - systemd-journal-gateway = 95; + munin = 95; + keys = 96; + dictd = 105; + couchdb = 106; + searx = 107; + kippo = 108; + jenkins = 109; + systemd-journal-gateway = 110; # When adding a gid, make sure it doesn't match an existing uid. diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index aa4bada8b28b..b419942057ac 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -29,7 +29,9 @@ ./hardware/network/intel-3945abg.nix ./hardware/network/ralink.nix ./hardware/network/rtl8192c.nix + ./hardware/opengl.nix ./hardware/pcmcia.nix + ./hardware/video/bumblebee.nix ./installer/tools/nixos-checkout.nix ./installer/tools/tools.nix ./misc/assertions.nix @@ -76,16 +78,19 @@ ./services/backup/bacula.nix ./services/backup/mysql-backup.nix ./services/backup/postgresql-backup.nix - ./services/backup/sitecopy-backup.nix ./services/backup/rsnapshot.nix + ./services/backup/sitecopy-backup.nix + ./services/backup/tarsnap.nix + ./services/continuous-integration/jenkins/default.nix + ./services/continuous-integration/jenkins/slave.nix ./services/databases/4store-endpoint.nix ./services/databases/4store.nix + ./services/databases/couchdb.nix ./services/databases/firebird.nix ./services/databases/memcached.nix ./services/databases/mongodb.nix ./services/databases/redis.nix ./services/databases/mysql.nix - ./services/databases/mysql55.nix ./services/databases/openldap.nix ./services/databases/postgresql.nix ./services/databases/virtuoso.nix @@ -123,6 +128,7 @@ ./services/misc/gpsd.nix ./services/misc/nix-daemon.nix ./services/misc/nix-gc.nix + ./services/misc/nix-ssh-serve.nix ./services/misc/nixos-manual.nix ./services/misc/rogue.nix ./services/misc/svnserve.nix @@ -185,6 +191,7 @@ ./services/networking/rdnssd.nix ./services/networking/rpcbind.nix ./services/networking/sabnzbd.nix + ./services/networking/searx.nix ./services/networking/supybot.nix ./services/networking/ssh/lshd.nix ./services/networking/ssh/sshd.nix @@ -201,6 +208,7 @@ ./services/scheduling/cron.nix ./services/scheduling/fcron.nix ./services/search/elasticsearch.nix + ./services/search/solr.nix ./services/security/clamav.nix ./services/security/haveged.nix ./services/security/fprot.nix @@ -223,8 +231,10 @@ ./services/web-servers/lighttpd/cgit.nix ./services/web-servers/lighttpd/gitweb.nix ./services/web-servers/nginx/default.nix + ./services/web-servers/phpfpm.nix ./services/web-servers/tomcat.nix ./services/web-servers/varnish/default.nix + ./services/web-servers/winstone.nix ./services/web-servers/zope2.nix ./services/x11/desktop-managers/default.nix ./services/x11/display-managers/auto.nix @@ -235,7 +245,6 @@ ./services/x11/hardware/multitouch.nix ./services/x11/hardware/synaptics.nix ./services/x11/hardware/wacom.nix - ./services/x11/mesa.nix ./services/x11/window-managers/awesome.nix #./services/x11/window-managers/compiz.nix ./services/x11/window-managers/default.nix diff --git a/nixos/modules/profiles/demo.nix b/nixos/modules/profiles/demo.nix index 396dcf6c5d3b..605cc6aad1de 100644 --- a/nixos/modules/profiles/demo.nix +++ b/nixos/modules/profiles/demo.nix @@ -11,6 +11,6 @@ createHome = true; useDefaultShell = true; password = "demo"; - isSystemUser = false; + uid = 1000; }; } diff --git a/nixos/modules/programs/environment.nix b/nixos/modules/programs/environment.nix index 7c1922cdfd89..489a7a4d269a 100644 --- a/nixos/modules/programs/environment.nix +++ b/nixos/modules/programs/environment.nix @@ -45,7 +45,7 @@ in TERMINFO_DIRS = [ "${i}/share/terminfo" ]; PERL5LIB = [ "${i}/lib/perl5/site_perl" ]; ALSA_PLUGIN_DIRS = [ "${i}/lib/alsa-lib" ]; - GST_PLUGIN_PATH = [ "${i}/lib/gstreamer-0.10" ]; + GST_PLUGIN_SYSTEM_PATH = [ "${i}/lib/gstreamer-0.10" ]; KDEDIRS = [ "${i}" ]; STRIGI_PLUGIN_PATH = [ "${i}/lib/strigi/" ]; QT_PLUGIN_PATH = [ "${i}/lib/qt4/plugins" "${i}/lib/kde4/plugins" ]; diff --git a/nixos/modules/programs/shadow.nix b/nixos/modules/programs/shadow.nix index 9e46ab8b298f..15b083b72d28 100644 --- a/nixos/modules/programs/shadow.nix +++ b/nixos/modules/programs/shadow.nix @@ -58,7 +58,8 @@ in config = { - environment.systemPackages = [ pkgs.shadow ]; + environment.systemPackages = + pkgs.lib.optional config.users.mutableUsers pkgs.shadow; environment.etc = [ { # /etc/login.defs: global configuration for pwdutils. You @@ -94,6 +95,8 @@ in groupmems = { rootOK = true; }; groupdel = { rootOK = true; }; login = { startSession = true; allowNullPassword = true; showMotd = true; updateWtmp = true; }; + chpasswd = { rootOK = true; }; + chgpasswd = { rootOK = true; }; }; security.setuidPrograms = [ "passwd" "chfn" "su" "newgrp" ]; diff --git a/nixos/modules/programs/shell.nix b/nixos/modules/programs/shell.nix index 8052502c21ea..226105a0c979 100644 --- a/nixos/modules/programs/shell.nix +++ b/nixos/modules/programs/shell.nix @@ -28,34 +28,36 @@ in echo "WARNING: bad ownership on $NIX_USER_PROFILE_DIR" >&2 fi - if ! test -L $HOME/.nix-profile; then - if test "$USER" != root; then - ln -s $NIX_USER_PROFILE_DIR/profile $HOME/.nix-profile - else - # Root installs in the system-wide profile by default. - ln -s /nix/var/nix/profiles/default $HOME/.nix-profile - fi - fi + if test -w $HOME; then + if ! test -L $HOME/.nix-profile; then + if test "$USER" != root; then + ln -s $NIX_USER_PROFILE_DIR/profile $HOME/.nix-profile + else + # Root installs in the system-wide profile by default. + ln -s /nix/var/nix/profiles/default $HOME/.nix-profile + fi + fi - # Subscribe the root user to the NixOS channel by default. - if [ "$USER" = root -a ! -e $HOME/.nix-channels ]; then - echo "${config.system.defaultChannel} nixos" > $HOME/.nix-channels - fi + # Subscribe the root user to the NixOS channel by default. + if [ "$USER" = root -a ! -e $HOME/.nix-channels ]; then + echo "${config.system.defaultChannel} nixos" > $HOME/.nix-channels + fi - # Create the per-user garbage collector roots directory. - NIX_USER_GCROOTS_DIR=/nix/var/nix/gcroots/per-user/$USER - mkdir -m 0755 -p $NIX_USER_GCROOTS_DIR - if test "$(stat --printf '%u' $NIX_USER_GCROOTS_DIR)" != "$(id -u)"; then - echo "WARNING: bad ownership on $NIX_USER_GCROOTS_DIR" >&2 - fi + # Create the per-user garbage collector roots directory. + NIX_USER_GCROOTS_DIR=/nix/var/nix/gcroots/per-user/$USER + mkdir -m 0755 -p $NIX_USER_GCROOTS_DIR + if test "$(stat --printf '%u' $NIX_USER_GCROOTS_DIR)" != "$(id -u)"; then + echo "WARNING: bad ownership on $NIX_USER_GCROOTS_DIR" >&2 + fi - # Set up a default Nix expression from which to install stuff. - if [ ! -e $HOME/.nix-defexpr -o -L $HOME/.nix-defexpr ]; then - rm -f $HOME/.nix-defexpr - mkdir $HOME/.nix-defexpr - if [ "$USER" != root ]; then - ln -s /nix/var/nix/profiles/per-user/root/channels $HOME/.nix-defexpr/channels_root - fi + # Set up a default Nix expression from which to install stuff. + if [ ! -e $HOME/.nix-defexpr -o -L $HOME/.nix-defexpr ]; then + rm -f $HOME/.nix-defexpr + mkdir $HOME/.nix-defexpr + if [ "$USER" != root ]; then + ln -s /nix/var/nix/profiles/per-user/root/channels $HOME/.nix-defexpr/channels_root + fi + fi fi ''; diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 6ff5277cf9ca..72093aab5cd7 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -12,18 +12,20 @@ let visible = true; }; + # warn option was renamed obsolete = from: to: rename { inherit from to; name = "Obsolete name"; - use = x: builtins.trace "Obsolete option `${showOption from}' is used instead of `${showOption to}'." x; - define = x: builtins.trace "Obsolete option `${showOption from}' is defined instead of `${showOption to}'." x; + use = x: builtins.trace "Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'." x; + define = x: builtins.trace "Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'." x; }; + # abort if deprecated option is used deprecated = from: to: rename { inherit from to; name = "Deprecated name"; - use = x: abort "Deprecated option `${showOption from}' is used instead of `${showOption to}'."; - define = x: abort "Deprecated option `${showOption from}' is defined instead of `${showOption to}'."; + use = x: abort "Deprecated option `${showOption from}' is used. It was renamed to `${showOption to}'."; + define = x: abort "Deprecated option `${showOption from}' is used. It was renamed to `${showOption to}'."; }; showOption = concatStringsSep "."; @@ -54,7 +56,7 @@ let inherit visible; }); } - { config = setTo (mkIf (fromOf options).isDefined (define (mkMerge (fromOf options).definitions))); + { config = setTo (mkMerge (if (fromOf options).isDefined then [ (define (mkMerge (fromOf options).definitions)) ] else [])); } ]; @@ -101,6 +103,7 @@ in zipModules ([] ++ obsolete [ "services" "sshd" "gatewayPorts" ] [ "services" "openssh" "gatewayPorts" ] ++ obsolete [ "services" "sshd" "permitRootLogin" ] [ "services" "openssh" "permitRootLogin" ] ++ obsolete [ "services" "xserver" "startSSHAgent" ] [ "services" "xserver" "startOpenSSHAgent" ] +++ obsolete [ "services" "xserver" "windowManager" "xbmc" ] [ "services" "xserver" "desktopManager" "xbmc" ] # KDE ++ deprecated [ "kde" "extraPackages" ] [ "environment" "kdePackages" ] @@ -113,10 +116,12 @@ in zipModules ([] # !!! this hardcodes bash, could we detect from config which shell is actually used? ++ obsolete [ "environment" "promptInit" ] [ "programs" "bash" "promptInit" ] -++ obsolete [ "services" "xserver" "driSupport" ] [ "services" "mesa" "driSupport" ] -++ obsolete [ "services" "xserver" "driSupport32Bit" ] [ "services" "mesa" "driSupport32Bit" ] -++ obsolete [ "services" "xserver" "s3tcSupport" ] [ "services" "mesa" "s3tcSupport" ] -++ obsolete [ "services" "xserver" "videoDrivers" ] [ "services" "mesa" "videoDrivers" ] +++ obsolete [ "services" "xserver" "driSupport" ] [ "hardware" "opengl" "driSupport" ] +++ obsolete [ "services" "xserver" "driSupport32Bit" ] [ "hardware" "opengl" "driSupport32Bit" ] +++ obsolete [ "services" "xserver" "s3tcSupport" ] [ "hardware" "opengl" "s3tcSupport" ] +++ obsolete [ "services" "xserver" "videoDrivers" ] [ "hardware" "opengl" "videoDrivers" ] + +++ obsolete [ "services" "mysql55" ] [ "services" "mysql" ] # Options that are obsolete and have no replacement. ++ obsolete' [ "boot" "loader" "grub" "bootDevice" ] diff --git a/nixos/modules/security/ca.nix b/nixos/modules/security/ca.nix index 2e93fb36b450..05cd1c3ecc17 100644 --- a/nixos/modules/security/ca.nix +++ b/nixos/modules/security/ca.nix @@ -10,11 +10,6 @@ with pkgs.lib; [ { source = "${pkgs.cacert}/etc/ca-bundle.crt"; target = "ssl/certs/ca-bundle.crt"; } - - # Backward compatibility; may remove at some point. - { source = "${pkgs.cacert}/etc/ca-bundle.crt"; - target = "ca-bundle.crt"; - } ]; environment.variables.OPENSSL_X509_CERT_FILE = "/etc/ssl/certs/ca-bundle.crt"; diff --git a/nixos/modules/services/backup/tarsnap.nix b/nixos/modules/services/backup/tarsnap.nix new file mode 100644 index 000000000000..03fbd29a191d --- /dev/null +++ b/nixos/modules/services/backup/tarsnap.nix @@ -0,0 +1,203 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + cfg = config.services.tarsnap; + + optionalNullStr = e: v: if e == null then "" else v; + + configFile = pkgs.writeText "tarsnap.conf" '' + cachedir ${cfg.cachedir} + keyfile ${cfg.keyfile} + ${optionalString cfg.nodump "nodump"} + ${optionalString cfg.printStats "print-stats"} + ${optionalNullStr cfg.checkpointBytes "checkpoint-bytes "+cfg.checkpointBytes} + ${optionalString cfg.aggressiveNetworking "aggressive-networking"} + ${concatStringsSep "\n" (map (v: "exclude "+v) cfg.excludes)} + ${concatStringsSep "\n" (map (v: "include "+v) cfg.includes)} + ${optionalString cfg.lowmem "lowmem"} + ${optionalString cfg.verylowmem "verylowmem"} + ''; +in +{ + options = { + services.tarsnap = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + If enabled, NixOS will periodically create backups of the + specified directories using the <literal>tarsnap</literal> + backup service. This installs a <literal>systemd</literal> + service called <literal>tarsnap-backup</literal> which is + periodically run by cron, or you may run it on-demand. + + See <link xlink:href='http://www.tarsnap.com/gettingstarted.html'>Getting Started</link> + Tarsnap page. + ''; + }; + + label = mkOption { + type = types.str; + default = "nixos"; + description = '' + Specifies the label for archives created by Tarsnap. The + full name will be + <literal>label-$(date+"%Y%m%d%H%M%S")</literal>. For + example, by default your backups will look similar to + <literal>nixos-20140301021501</literal>. + ''; + }; + + cachedir = mkOption { + type = types.path; + default = "/var/cache/tarsnap"; + description = '' + Tarsnap operations use a "cache directory" which allows + Tarsnap to identify which blocks of data have been + previously stored; this directory is specified via the + <literal>cachedir</literal> option. If the cache directory + is lost or out of date, tarsnap creation/deletion operations + will exit with an error message instructing you to run + <literal>tarsnap --fsck</literal> to regenerate the cache + directory. + ''; + }; + + keyfile = mkOption { + type = types.path; + default = "/root/tarsnap.key"; + description = '' + Path to the keyfile which identifies the machine associated + with your Tarsnap account. This file can be created using + the <literal>tarsnap-keygen</literal> utility, and providing + your Tarsnap login credentials. + ''; + }; + + nodump = mkOption { + type = types.bool; + default = true; + description = '' + If set to <literal>true</literal>, then don't archive files + which have the <literal>nodump</literal> flag set. + ''; + }; + + printStats = mkOption { + type = types.bool; + default = true; + description = "Print statistics when creating archives."; + }; + + checkpointBytes = mkOption { + type = types.nullOr types.str; + default = "1G"; + description = '' + Create a checkpoint per a particular amount of uploaded + data. By default, Tarsnap will create checkpoints once per + GB of data uploaded. At minimum, + <literal>checkpointBytes</literal> must be 1GB. + + Can also be set to <literal>null</literal> to disable + checkpointing. + ''; + }; + + period = mkOption { + type = types.str; + default = "15 01 * * *"; + description = '' + This option defines (in the format used by cron) when + tarsnap is run for backups. The default is to update at + 01:15 at night every day. + ''; + }; + + aggressiveNetworking = mkOption { + type = types.bool; + default = false; + description = '' + Aggressive network behaviour: Use multiple TCP connections + when writing archives. Use of this option is recommended + only in cases where TCP congestion control is known to be + the limiting factor in upload performance. + ''; + }; + + directories = mkOption { + type = types.listOf types.path; + default = []; + description = "List of filesystem paths to archive."; + }; + + excludes = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Exclude files and directories matching the specified patterns. + ''; + }; + + includes = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Include only files and directories matching the specified patterns. + + Note that exclusions specified via + <literal>excludes</literal> take precedence over inclusions. + ''; + }; + + lowmem = mkOption { + type = types.bool; + default = false; + description = '' + Attempt to reduce tarsnap memory consumption. This option + will slow down the process of creating archives, but may + help on systems where the average size of files being backed + up is less than 1 MB. + ''; + }; + + verylowmem = mkOption { + type = types.bool; + default = false; + description = '' + Try even harder to reduce tarsnap memory consumption. This + can significantly slow down tarsnap, but reduces its memory + usage by an additional factor of 2 beyond what the + <literal>lowmem</literal> option does. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + assertions = + [ { assertion = cfg.directories != []; + message = "Must specify directories for Tarsnap to back up"; + } + { assertion = cfg.lowmem -> !cfg.verylowmem && (cfg.verylowmem -> !cfg.lowmem); + message = "You cannot set both lowmem and verylowmem"; + } + ]; + + systemd.services.tarsnap-backup = { + description = "Tarsnap Backup process"; + path = [ pkgs.tarsnap pkgs.coreutils ]; + script = '' + mkdir -p -m 0755 $(dirname ${cfg.cachedir}) + mkdir -p -m 0600 ${cfg.cachedir} + exec tarsnap --configfile ${configFile} -c -f ${cfg.label}-$(date +"%Y%m%d%H%M%S") ${concatStringsSep " " cfg.directories} + ''; + }; + + services.cron.systemCronJobs = optional cfg.enable + "${cfg.period} root ${config.systemd.package}/bin/systemctl start tarsnap-backup.service"; + + environment.systemPackages = [ pkgs.tarsnap ]; + }; +} diff --git a/nixos/modules/services/continuous-integration/jenkins/default.nix b/nixos/modules/services/continuous-integration/jenkins/default.nix new file mode 100644 index 000000000000..c3dc59a9fbd0 --- /dev/null +++ b/nixos/modules/services/continuous-integration/jenkins/default.nix @@ -0,0 +1,118 @@ +{ config, pkgs, ... }: +with pkgs.lib; +let + cfg = config.services.jenkins; +in { + options = { + services.jenkins = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable the jenkins continuous integration server. + ''; + }; + + user = mkOption { + default = "jenkins"; + type = with types; string; + description = '' + User the jenkins server should execute under. + ''; + }; + + group = mkOption { + default = "jenkins"; + type = with types; string; + description = '' + User the jenkins server should execute under. + ''; + }; + + home = mkOption { + default = "/var/lib/jenkins"; + type = with types; string; + description = '' + The path to use as JENKINS_HOME. If the default user "jenkins" is configured then + this is the home of the "jenkins" user. + ''; + }; + + port = mkOption { + default = 8080; + type = types.uniq types.int; + description = '' + Specifies port number on which the jenkins HTTP interface listens. The default is 8080 + ''; + }; + + packages = mkOption { + default = [ pkgs.stdenv pkgs.git pkgs.jdk pkgs.openssh pkgs.nix ]; + type = types.listOf types.package; + description = '' + Packages to add to PATH for the jenkins process. + ''; + }; + + environment = mkOption { + default = { NIX_REMOTE = "daemon"; }; + type = with types; attrsOf string; + description = '' + Additional environment variables to be passed to the jenkins process. + The environment will always include JENKINS_HOME. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + users.extraGroups = optional (cfg.group == "jenkins") { + name = "jenkins"; + gid = config.ids.gids.jenkins; + }; + + users.extraUsers = optional (cfg.user == "jenkins") { + name = "jenkins"; + description = "jenkins user"; + createHome = true; + home = cfg.home; + group = cfg.group; + useDefaultShell = true; + uid = config.ids.uids.jenkins; + }; + + systemd.services.jenkins = { + description = "Jenkins Continuous Integration Server"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + environment = { + JENKINS_HOME = cfg.home; + } // cfg.environment; + + path = cfg.packages; + + script = '' + ${pkgs.jdk}/bin/java -jar ${pkgs.jenkins} --httpPort=${toString cfg.port} + ''; + + postStart = '' + until ${pkgs.curl}/bin/curl -s -L localhost:${toString cfg.port} ; do + sleep 10 + done + while true ; do + index=`${pkgs.curl}/bin/curl -s -L localhost:${toString cfg.port}` + if [[ !("$index" =~ 'Please wait while Jenkins is restarting' || + "$index" =~ 'Please wait while Jenkins is getting ready to work') ]]; then + exit 0 + fi + sleep 30 + done + ''; + + serviceConfig = { + User = cfg.user; + }; + }; + }; +} diff --git a/nixos/modules/services/continuous-integration/jenkins/slave.nix b/nixos/modules/services/continuous-integration/jenkins/slave.nix new file mode 100644 index 000000000000..1d31ab830f6c --- /dev/null +++ b/nixos/modules/services/continuous-integration/jenkins/slave.nix @@ -0,0 +1,67 @@ +{ config, pkgs, ... }: +with pkgs.lib; +let + cfg = config.services.jenkinsSlave; + masterCfg = config.services.jenkins; +in { + options = { + services.jenkinsSlave = { + # todo: + # * assure the profile of the jenkins user has a JRE and any specified packages. This would + # enable ssh slaves. + # * Optionally configure the node as a jenkins ad-hoc slave. This would imply configuration + # properties for the master node. + enable = mkOption { + type = types.bool; + default = false; + description = '' + If true the system will be configured to work as a jenkins slave. + If the system is also configured to work as a jenkins master then this has no effect. + In progress: Currently only assures the jenkins user is configured. + ''; + }; + + user = mkOption { + default = "jenkins"; + type = with types; string; + description = '' + User the jenkins slave agent should execute under. + ''; + }; + + group = mkOption { + default = "jenkins"; + type = with types; string; + description = '' + User the jenkins slave agent should execute under. + ''; + }; + + home = mkOption { + default = "/var/lib/jenkins"; + type = with types; string; + description = '' + The path to use as JENKINS_HOME. If the default user "jenkins" is configured then + this is the home of the "jenkins" user. + ''; + }; + }; + }; + + config = mkIf (cfg.enable && !masterCfg.enable) { + users.extraGroups = optional (cfg.group == "jenkins") { + name = "jenkins"; + gid = config.ids.gids.jenkins; + }; + + users.extraUsers = optional (cfg.user == "jenkins") { + name = "jenkins"; + description = "jenkins user"; + createHome = true; + home = cfg.home; + group = cfg.group; + useDefaultShell = true; + uid = config.ids.uids.jenkins; + }; + }; +} diff --git a/nixos/modules/services/databases/couchdb.nix b/nixos/modules/services/databases/couchdb.nix new file mode 100644 index 000000000000..b48d3a64767f --- /dev/null +++ b/nixos/modules/services/databases/couchdb.nix @@ -0,0 +1,173 @@ +{ config, pkgs, ... }: + with pkgs.lib; + +let + cfg = config.services.couchdb; + configFile = pkgs.writeText "couchdb.ini" + '' + [couchdb] + database_dir = ${cfg.databaseDir} + uri_file = ${cfg.uriFile} + view_index_dir = ${cfg.viewIndexDir} + + [httpd] + port = ${toString cfg.port} + bind_address = ${cfg.bindAddress} + + [log] + file = ${cfg.logFile} + ''; + +in { + + ###### interface + + options = { + + services.couchdb = { + + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to run CouchDB Server. + ''; + }; + + package = mkOption { + type = types.package; + default = pkgs.couchdb; + example = literalExample "pkgs.couchdb"; + description = '' + CouchDB package to use. + ''; + }; + + + user = mkOption { + type = types.string; + default = "couchdb"; + description = '' + User account under which couchdb runs. + ''; + }; + + group = mkOption { + type = types.string; + default = "couchdb"; + description = '' + Group account under which couchdb runs. + ''; + }; + + # couchdb options: http://docs.couchdb.org/en/latest/config/index.html + + databaseDir = mkOption { + type = types.path; + default = "/var/lib/couchdb"; + description = '' + Specifies location of CouchDB database files (*.couch named). This + location should be writable and readable for the user the CouchDB + service runs as (couchdb by default). + ''; + }; + + uriFile = mkOption { + type = types.path; + default = "/var/run/couchdb/couchdb.uri"; + description = '' + This file contains the full URI that can be used to access this + instance of CouchDB. It is used to help discover the port CouchDB is + running on (if it was set to 0 (e.g. automatically assigned any free + one). This file should be writable and readable for the user that + runs the CouchDB service (couchdb by default). + ''; + }; + + viewIndexDir = mkOption { + type = types.path; + default = "/var/lib/couchdb"; + description = '' + Specifies location of CouchDB view index files. This location should + be writable and readable for the user that runs the CouchDB service + (couchdb by default). + ''; + }; + + bindAddress = mkOption { + type = types.string; + default = "127.0.0.1"; + description = '' + Defines the IP address by which CouchDB will be accessible. + ''; + }; + + port = mkOption { + type = types.int; + default = 5984; + description = '' + Defined the port number to listen. + ''; + }; + + logFile = mkOption { + type = types.path; + default = "/var/log/couchdb.log"; + description = '' + Specifies the location of file for logging output. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra configuration. Overrides any other cofiguration. + ''; + }; + }; + + }; + + ###### implementation + + config = mkIf config.services.couchdb.enable { + + environment.systemPackages = [ cfg.package ]; + + systemd.services.couchdb = { + description = "CouchDB Server"; + wantedBy = [ "multi-user.target" ]; + + preStart = + '' + mkdir -p `dirname ${cfg.uriFile}`; + mkdir -p `dirname ${cfg.logFile}`; + mkdir -p ${cfg.databaseDir}; + mkdir -p ${cfg.viewIndexDir}; + + if [ "$(id -u)" = 0 ]; then + chown ${cfg.user}:${cfg.group} `dirname ${cfg.uriFile}` + chown ${cfg.user}:${cfg.group} ${cfg.databaseDir} + chown ${cfg.user}:${cfg.group} ${cfg.viewIndexDir} + fi + ''; + + serviceConfig = { + PermissionsStartOnly = true; + User = cfg.user; + Group = cfg.group; + ExecStart = "${cfg.package}/bin/couchdb -a ${configFile} -a ${pkgs.writeText "couchdb-extra.ini" cfg.extraConfig}"; + }; + }; + + users.extraUsers.couchdb = { + description = "CouchDB Server user"; + group = "couchdb"; + uid = config.ids.uids.couchdb; + }; + + users.extraGroups.couchdb.gid = config.ids.gids.couchdb; + + }; +} diff --git a/nixos/modules/services/databases/firebird.nix b/nixos/modules/services/databases/firebird.nix index 75c225bdb67b..f9f7e9d7c518 100644 --- a/nixos/modules/services/databases/firebird.nix +++ b/nixos/modules/services/databases/firebird.nix @@ -49,6 +49,7 @@ in package = mkOption { default = pkgs.firebirdSuper; + type = types.package; /* Example: <code>package = pkgs.firebirdSuper.override { icu = pkgs.icu; };</code> which is not recommended for compatibility diff --git a/nixos/modules/services/databases/mongodb.nix b/nixos/modules/services/databases/mongodb.nix index 213a60687b23..a2f2593e7973 100644 --- a/nixos/modules/services/databases/mongodb.nix +++ b/nixos/modules/services/databases/mongodb.nix @@ -39,6 +39,7 @@ in package = mkOption { default = pkgs.mongodb; + type = types.package; description = " Which MongoDB derivation to use. "; diff --git a/nixos/modules/services/databases/mysql.nix b/nixos/modules/services/databases/mysql.nix index 8be05a27cdcb..7e42438fe6d5 100644 --- a/nixos/modules/services/databases/mysql.nix +++ b/nixos/modules/services/databases/mysql.nix @@ -8,10 +8,14 @@ let mysql = cfg.package; + is55 = mysql.mysqlVersion == "5.5"; + + mysqldDir = if is55 then "${mysql}/bin" else "${mysql}/libexec"; + pidFile = "${cfg.pidDir}/mysqld.pid"; mysqldOptions = - "--user=${cfg.user} --datadir=${cfg.dataDir} " + + "--user=${cfg.user} --datadir=${cfg.dataDir} --basedir=${mysql} " + "--pid-file=${pidFile}"; myCnf = pkgs.writeText "my.cnf" @@ -19,7 +23,7 @@ let [mysqld] ${optionalString (cfg.replication.role == "master" || cfg.replication.role == "slave") "log-bin=mysql-bin"} ${optionalString (cfg.replication.role == "master" || cfg.replication.role == "slave") "server-id = ${toString cfg.replication.serverId}"} - ${optionalString (cfg.replication.role == "slave") + ${optionalString (cfg.replication.role == "slave" && !is55) '' master-host = ${cfg.replication.masterHost} master-user = ${cfg.replication.masterUser} @@ -47,7 +51,8 @@ in }; package = mkOption { - default = pkgs.mysql; + type = types.package; + example = literalExample "pkgs.mysql"; description = " Which MySQL derivation to use. "; @@ -176,7 +181,7 @@ in chown -R ${cfg.user} ${cfg.pidDir} ''; - serviceConfig.ExecStart = "${mysql}/libexec/mysqld --defaults-extra-file=${myCnf} ${mysqldOptions}"; + serviceConfig.ExecStart = "${mysqldDir}/mysqld --defaults-extra-file=${myCnf} ${mysqldOptions}"; postStart = '' @@ -216,6 +221,16 @@ in fi '') cfg.initialDatabases} + ${optionalString (cfg.replication.role == "slave" && is55) + '' + # Set up the replication master + + ( echo "stop slave;" + echo "change master to master_host='${cfg.replication.masterHost}', master_user='${cfg.replication.masterUser}', master_password='${cfg.replication.masterPassword}';" + echo "start slave;" + ) | ${mysql}/bin/mysql -u root -N + ''} + ${optionalString (cfg.initialScript != null) '' # Execute initial script diff --git a/nixos/modules/services/databases/mysql55.nix b/nixos/modules/services/databases/mysql55.nix deleted file mode 100644 index fe8b29e3c6b7..000000000000 --- a/nixos/modules/services/databases/mysql55.nix +++ /dev/null @@ -1,248 +0,0 @@ -{ config, pkgs, ... }: - -with pkgs.lib; - -let - - cfg = config.services.mysql55; - - mysql = cfg.package; - - pidFile = "${cfg.pidDir}/mysqld.pid"; - - mysqldOptions = - "--user=${cfg.user} --datadir=${cfg.dataDir} " + - "--pid-file=${pidFile}"; - - myCnf = pkgs.writeText "my.cnf" - '' - [mysqld] - ${optionalString (cfg.replication.role == "master" || cfg.replication.role == "slave") "log-bin=mysql-bin"} - ${optionalString (cfg.replication.role == "master" || cfg.replication.role == "slave") "server-id = ${toString cfg.replication.serverId}"} - ${cfg.extraOptions} - ''; - -in - -{ - - ###### interface - - options = { - - services.mysql55 = { - - enable = mkOption { - default = false; - description = " - Whether to enable the MySQL server. - "; - }; - - package = mkOption { - default = pkgs.mysql55; - description = " - Which MySQL derivation to use. - "; - }; - - port = mkOption { - default = "3306"; - description = "Port of MySQL"; - }; - - user = mkOption { - default = "mysql"; - description = "User account under which MySQL runs"; - }; - - dataDir = mkOption { - default = "/var/mysql"; # !!! should be /var/db/mysql - description = "Location where MySQL stores its table files"; - }; - - pidDir = mkOption { - default = "/var/run/mysql"; - description = "Location of the file which stores the PID of the MySQL server"; - }; - - extraOptions = mkOption { - default = ""; - example = '' - key_buffer_size = 6G - table_cache = 1600 - log-error = /var/log/mysql_err.log - ''; - description = '' - Provide extra options to the MySQL configuration file. - - Please note, that these options are added to the - <literal>[mysqld]</literal> section so you don't need to explicitly - state it again. - ''; - }; - - initialDatabases = mkOption { - default = []; - description = "List of database names and their initial schemas that should be used to create databases on the first startup of MySQL"; - example = [ - { name = "foodatabase"; schema = literalExample "./foodatabase.sql"; } - { name = "bardatabase"; schema = literalExample "./bardatabase.sql"; } - ]; - }; - - initialScript = mkOption { - default = null; - description = "A file containing SQL statements to be executed on the first startup. Can be used for granting certain permissions on the database"; - }; - - # FIXME: remove this option; it's a really bad idea. - rootPassword = mkOption { - default = null; - description = "Path to a file containing the root password, modified on the first startup. Not specifying a root password will leave the root password empty."; - }; - - replication = { - role = mkOption { - default = "none"; - description = "Role of the MySQL server instance. Can be either: master, slave or none"; - }; - - serverId = mkOption { - default = 1; - description = "Id of the MySQL server instance. This number must be unique for each instance"; - }; - - masterHost = mkOption { - description = "Hostname of the MySQL master server"; - }; - - masterUser = mkOption { - description = "Username of the MySQL replication user"; - }; - - masterPassword = mkOption { - description = "Password of the MySQL replication user"; - }; - - masterPort = mkOption { - default = 3306; - description = "Port number on which the MySQL master server runs"; - }; - }; - }; - - }; - - - ###### implementation - - config = mkIf config.services.mysql55.enable { - - users.extraUsers.mysql = { - description = "MySQL server user"; - group = "mysql"; - uid = config.ids.uids.mysql; - }; - - users.extraGroups.mysql.gid = config.ids.gids.mysql; - - environment.systemPackages = [mysql]; - - systemd.services.mysql = - { description = "MySQL Server"; - - wantedBy = [ "multi-user.target" ]; - - unitConfig.RequiresMountsFor = "${cfg.dataDir}"; - - preStart = - '' - if ! test -e ${cfg.dataDir}/mysql; then - mkdir -m 0700 -p ${cfg.dataDir} - chown -R ${cfg.user} ${cfg.dataDir} - ${mysql}/bin/mysql_install_db ${mysqldOptions} - touch /tmp/mysql_init - fi - - mkdir -m 0700 -p ${cfg.pidDir} - chown -R ${cfg.user} ${cfg.pidDir} - ''; - - serviceConfig.ExecStart = "${mysql}/bin/mysqld --defaults-extra-file=${myCnf} ${mysqldOptions}"; - - postStart = - '' - # Wait until the MySQL server is available for use - count=0 - while [ ! -e /tmp/mysql.sock ] - do - if [ $count -eq 30 ] - then - echo "Tried 30 times, giving up..." - exit 1 - fi - - echo "MySQL daemon not yet started. Waiting for 1 second..." - count=$((count++)) - sleep 1 - done - - if [ -f /tmp/mysql_init ] - then - ${concatMapStrings (database: - '' - # Create initial databases - if ! test -e "${cfg.dataDir}/${database.name}"; then - echo "Creating initial database: ${database.name}" - ( echo "create database ${database.name};" - echo "use ${database.name};" - - if [ -f "${database.schema}" ] - then - cat ${database.schema} - elif [ -d "${database.schema}" ] - then - cat ${database.schema}/mysql-databases/*.sql - fi - ) | ${mysql}/bin/mysql -u root -N - fi - '') cfg.initialDatabases} - - ${optionalString (cfg.replication.role == "slave") - '' - # Set up the replication master - - ( echo "stop slave;" - echo "change master to master_host='${cfg.replication.masterHost}', master_user='${cfg.replication.masterUser}', master_password='${cfg.replication.masterPassword}';" - echo "start slave;" - ) | ${mysql}/bin/mysql -u root -N - ''} - - ${optionalString (cfg.initialScript != null) - '' - # Execute initial script - cat ${cfg.initialScript} | ${mysql}/bin/mysql -u root -N - ''} - - ${optionalString (cfg.rootPassword != null) - '' - # Change root password - - ( echo "use mysql;" - echo "update user set Password=password('$(cat ${cfg.rootPassword})') where User='root';" - echo "flush privileges;" - ) | ${mysql}/bin/mysql -u root -N - ''} - - rm /tmp/mysql_init - fi - ''; # */ - - serviceConfig.ExecStop = - "${mysql}/bin/mysqladmin ${optionalString (cfg.rootPassword != null) "--user=root --password=\"$(cat ${cfg.rootPassword})\""} shutdown"; - }; - - }; - -} diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix index 265d26e8ce98..cc4230d4d6a7 100644 --- a/nixos/modules/services/databases/postgresql.nix +++ b/nixos/modules/services/databases/postgresql.nix @@ -55,7 +55,7 @@ in }; package = mkOption { - type = types.path; + type = types.package; example = literalExample "pkgs.postgresql92"; description = '' PostgreSQL package to use. diff --git a/nixos/modules/services/databases/redis.nix b/nixos/modules/services/databases/redis.nix index ea6399ba4f44..9a4ce36a5cb1 100644 --- a/nixos/modules/services/databases/redis.nix +++ b/nixos/modules/services/databases/redis.nix @@ -45,6 +45,7 @@ in package = mkOption { default = pkgs.redis; description = "Which Redis derivation to use."; + type = types.package; }; user = mkOption { diff --git a/nixos/modules/services/logging/logcheck.nix b/nixos/modules/services/logging/logcheck.nix index 2a6a6516f488..ef147f95358c 100644 --- a/nixos/modules/services/logging/logcheck.nix +++ b/nixos/modules/services/logging/logcheck.nix @@ -208,12 +208,13 @@ in mapAttrsToList writeIgnoreRule cfg.ignore ++ mapAttrsToList writeIgnoreCronRule cfg.ignoreCron; - users.extraUsers = singleton - { name = cfg.user; + users.extraUsers = optionalAttrs (cfg.user == "logcheck") (singleton + { name = "logcheck"; + uid = config.ids.uids.logcheck; shell = "/bin/sh"; description = "Logcheck user account"; extraGroups = cfg.extraGroups; - }; + }); system.activationScripts.logcheck = '' mkdir -m 700 -p /var/{lib,lock}/logcheck diff --git a/nixos/modules/services/mail/opensmtpd.nix b/nixos/modules/services/mail/opensmtpd.nix index 2732fd602004..0c18c464520d 100644 --- a/nixos/modules/services/mail/opensmtpd.nix +++ b/nixos/modules/services/mail/opensmtpd.nix @@ -79,5 +79,10 @@ in { preStart = "mkdir -p /var/spool"; serviceConfig.ExecStart = "${opensmtpd}/sbin/smtpd -d -f ${conf} ${args}"; }; + + environment.systemPackages = [ (pkgs.runCommand "opensmtpd-sendmail" {} '' + mkdir -p $out/bin + ln -s ${opensmtpd}/sbin/smtpctl $out/bin/sendmail + '') ]; }; } diff --git a/nixos/modules/services/misc/cgminer.nix b/nixos/modules/services/misc/cgminer.nix index f715013b51f3..20b7c34e886e 100644 --- a/nixos/modules/services/misc/cgminer.nix +++ b/nixos/modules/services/misc/cgminer.nix @@ -42,6 +42,7 @@ in package = mkOption { default = pkgs.cgminer; description = "Which cgminer derivation to use."; + type = types.package; }; user = mkOption { diff --git a/nixos/modules/services/misc/dictd.nix b/nixos/modules/services/misc/dictd.nix index b84fbb3e1281..fd68f8470102 100644 --- a/nixos/modules/services/misc/dictd.nix +++ b/nixos/modules/services/misc/dictd.nix @@ -43,10 +43,12 @@ with pkgs.lib; group = "dictd"; description = "DICT.org dictd server"; home = "${dictdb}/share/dictd"; + uid = config.ids.uids.dictd; }; users.extraGroups = singleton { name = "dictd"; + gid = config.ids.gids.dictd; }; jobs.dictd = diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix index cca42aa11009..785d43973473 100644 --- a/nixos/modules/services/misc/nix-daemon.nix +++ b/nixos/modules/services/misc/nix-daemon.nix @@ -58,7 +58,7 @@ in nix = { package = mkOption { - type = types.path; + type = types.package; default = pkgs.nix; description = '' This option specifies the Nix package instance to use throughout the system. @@ -286,8 +286,8 @@ in systemd.services."nix-daemon" = { description = "Nix Daemon"; - path = [ nix pkgs.openssl pkgs.utillinux ] - ++ optionals cfg.distributedBuilds [ pkgs.openssh pkgs.gzip ]; + path = [ nix pkgs.openssl pkgs.utillinux pkgs.openssh ] + ++ optionals cfg.distributedBuilds [ pkgs.gzip ]; environment = cfg.envVars // { CURL_CA_BUNDLE = "/etc/ssl/certs/ca-bundle.crt"; }; diff --git a/nixos/modules/services/misc/nix-ssh-serve.nix b/nixos/modules/services/misc/nix-ssh-serve.nix new file mode 100644 index 000000000000..80e7961b1f82 --- /dev/null +++ b/nixos/modules/services/misc/nix-ssh-serve.nix @@ -0,0 +1,45 @@ +{ config, lib, pkgs, ... }: + +let + serveOnly = pkgs.writeScript "nix-store-serve" '' + #!${pkgs.stdenv.shell} + if [ "$SSH_ORIGINAL_COMMAND" != "nix-store --serve" ]; then + echo 'Error: You are only allowed to run `nix-store --serve'\'''!' >&2 + exit 1 + fi + exec /run/current-system/sw/bin/nix-store --serve + ''; + + inherit (lib) mkIf mkOption types; +in { + options = { + nix.sshServe = { + enable = mkOption { + description = "Whether to enable serving the nix store over ssh."; + default = false; + type = types.bool; + }; + }; + }; + + config = mkIf config.nix.sshServe.enable { + users.extraUsers.nix-ssh = { + description = "User for running nix-store --serve."; + uid = config.ids.uids.nix-ssh; + shell = pkgs.stdenv.shell; + }; + + services.openssh.enable = true; + + services.openssh.extraConfig = '' + Match User nix-ssh + AllowAgentForwarding no + AllowTcpForwarding no + PermitTTY no + PermitTunnel no + X11Forwarding no + ForceCommand ${serveOnly} + Match All + ''; + }; +} diff --git a/nixos/modules/services/misc/nixos-manual.nix b/nixos/modules/services/misc/nixos-manual.nix index 1a8b85db3290..9a5b170d5e66 100644 --- a/nixos/modules/services/misc/nixos-manual.nix +++ b/nixos/modules/services/misc/nixos-manual.nix @@ -63,7 +63,7 @@ in services.nixosManual.showManual = mkOption { type = types.bool; - default = false; + default = true; description = '' Whether to show the NixOS manual on one of the virtual consoles. diff --git a/nixos/modules/services/monitoring/apcupsd.nix b/nixos/modules/services/monitoring/apcupsd.nix index 58ec8a49694b..38fd53653d62 100644 --- a/nixos/modules/services/monitoring/apcupsd.nix +++ b/nixos/modules/services/monitoring/apcupsd.nix @@ -168,11 +168,11 @@ in # shuts off power.) Copied from here: # http://forums.opensuse.org/english/get-technical-help-here/applications/479499-apcupsd-systemd-killpower-issues.html systemd.services.apcupsd-killpower = { + description = "APC UPS Kill Power"; after = [ "shutdown.target" ]; # append umount.target? before = [ "final.target" ]; wantedBy = [ "shutdown.target" ]; unitConfig = { - Description = "APC UPS Kill Power"; ConditionPathExists = "/run/apcupsd/powerfail"; DefaultDependencies = "no"; }; diff --git a/nixos/modules/services/monitoring/munin.nix b/nixos/modules/services/monitoring/munin.nix index 153f49429029..39c4fb1aefac 100644 --- a/nixos/modules/services/monitoring/munin.nix +++ b/nixos/modules/services/monitoring/munin.nix @@ -173,10 +173,12 @@ in name = "munin"; description = "Munin monitoring user"; group = "munin"; + uid = config.ids.uids.munin; }]; users.extraGroups = [{ name = "munin"; + gid = config.ids.gids.munin; }]; }) (mkIf nodeCfg.enable { diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix index 08a5d6de6a2b..d4ec96a18f6f 100644 --- a/nixos/modules/services/networking/dhcpcd.nix +++ b/nixos/modules/services/networking/dhcpcd.nix @@ -106,7 +106,6 @@ in { description = "DHCP Client"; wantedBy = [ "network.target" ]; - after = [ "systemd-udev-settle.service" ]; # Stopping dhcpcd during a reconfiguration is undesirable # because it brings down the network interfaces configured by diff --git a/nixos/modules/services/networking/firewall.nix b/nixos/modules/services/networking/firewall.nix index 3c0c51e6ec8a..07e05fa6d051 100644 --- a/nixos/modules/services/networking/firewall.nix +++ b/nixos/modules/services/networking/firewall.nix @@ -128,6 +128,17 @@ in ''; }; + networking.firewall.allowedTCPPortRanges = mkOption { + default = []; + example = [ { from = 8999; to = 9003; } ]; + type = types.listOf (types.attrsOf types.int); + description = + '' + A range of TCP ports on which incoming connections are + accepted. + ''; + }; + networking.firewall.allowedUDPPorts = mkOption { default = []; example = [ 53 ]; @@ -138,6 +149,16 @@ in ''; }; + networking.firewall.allowedUDPPortRanges = mkOption { + default = []; + example = [ { from = 60000; to = 61000; } ]; + type = types.listOf (types.attrsOf types.int); + description = + '' + Range of open UDP ports. + ''; + }; + networking.firewall.allowPing = mkOption { default = false; type = types.bool; @@ -150,6 +171,17 @@ in ''; }; + networking.firewall.pingLimit = mkOption { + default = null; + type = types.nullOr (types.separatedString " "); + description = + '' + If pings are allowed, this allows setting rate limits + on them. If non-null, this option should be in the form + of flags like "-limit 1/minute -limit-burst 5" + ''; + }; + networking.firewall.checkReversePath = mkOption { default = kernelHasRPFilter; type = types.bool; @@ -322,6 +354,15 @@ in ) cfg.allowedTCPPorts } + # Accept connections to the allowed TCP port ranges. + ${concatMapStrings (rangeAttr: + let range = toString rangeAttr.from + ":" + toString rangeAttr.to; in + '' + ip46tables -A nixos-fw -p tcp --dport ${range} -j nixos-fw-accept + '' + ) cfg.allowedTCPPortRanges + } + # Accept packets on the allowed UDP ports. ${concatMapStrings (port: '' @@ -330,13 +371,24 @@ in ) cfg.allowedUDPPorts } + # Accept packets on the allowed UDP port ranges. + ${concatMapStrings (rangeAttr: + let range = toString rangeAttr.from + ":" + toString rangeAttr.to; in + '' + ip46tables -A nixos-fw -p udp --dport ${range} -j nixos-fw-accept + '' + ) cfg.allowedUDPPortRanges + } + # Accept IPv4 multicast. Not a big security risk since # probably nobody is listening anyway. #iptables -A nixos-fw -d 224.0.0.0/4 -j nixos-fw-accept # Optionally respond to ICMPv4 pings. ${optionalString cfg.allowPing '' - iptables -A nixos-fw -p icmp --icmp-type echo-request -j nixos-fw-accept + iptables -A nixos-fw -p icmp --icmp-type echo-request ${optionalString (cfg.pingLimit != null) + "-m limit ${cfg.pingLimit} " + }-j nixos-fw-accept ''} # Accept all ICMPv6 messages except redirects and node diff --git a/nixos/modules/services/networking/git-daemon.nix b/nixos/modules/services/networking/git-daemon.nix index a7c7c206198f..2e7c9c68e2fa 100644 --- a/nixos/modules/services/networking/git-daemon.nix +++ b/nixos/modules/services/networking/git-daemon.nix @@ -101,7 +101,7 @@ in name = "git-daemon"; startOn = "ip-up"; exec = "${pkgs.git}/bin/git daemon --reuseaddr " - + (optionalString (cfg.basePath != "") "--basepath=${cfg.basePath} ") + + (optionalString (cfg.basePath != "") "--base-path=${cfg.basePath} ") + (optionalString (cfg.listenAddress != "") "--listen=${cfg.listenAddress} ") + "--port=${toString cfg.port} --user=${gitUser} --group=${gitUser} ${cfg.options} " + "--verbose " + (optionalString cfg.exportAll "--export-all") + concatStringsSep " " cfg.repositories; diff --git a/nixos/modules/services/networking/kippo.nix b/nixos/modules/services/networking/kippo.nix index 76dd66013ba7..164c38940f77 100644 --- a/nixos/modules/services/networking/kippo.nix +++ b/nixos/modules/services/networking/kippo.nix @@ -76,8 +76,9 @@ rec { users.extraUsers = singleton { name = "kippo"; description = "kippo web server privilege separation user"; + uid = 108; # why does config.ids.uids.kippo give an error? }; - users.extraGroups = singleton { name = "kippo"; }; + users.extraGroups = singleton { name = "kippo";gid=108; }; systemd.services.kippo = with pkgs; { description = "Kippo Web Server"; diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix index 0b079e3567a1..fd5ff5e44983 100644 --- a/nixos/modules/services/networking/networkmanager.nix +++ b/nixos/modules/services/networking/networkmanager.nix @@ -31,7 +31,7 @@ let [modem-manager] Identity=unix-group:networkmanager - Action=org.freedesktop.ModemManager.* + Action=org.freedesktop.ModemManager* ResultAny=yes ResultInactive=no ResultActive=yes @@ -42,7 +42,7 @@ let subject.isInGroup("networkmanager") && subject.active && (action.id.indexOf("org.freedesktop.NetworkManager.") == 0 - || action.id.indexOf("org.freedesktop.ModemManager.") == 0 + || action.id.indexOf("org.freedesktop.ModemManager") == 0 )) { return polkit.Result.YES; } }); @@ -89,7 +89,7 @@ in { to change network settings to this group. ''; }; - + packages = mkOption { type = types.listOf types.path; default = [ ]; @@ -161,6 +161,7 @@ in { networkmanager_vpnc networkmanager_openconnect networkmanager_pptp + modemmanager ]; users.extraGroups = singleton { @@ -176,16 +177,13 @@ in { systemd.services."networkmanager-init" = { description = "NetworkManager initialisation"; wantedBy = [ "network.target" ]; - partOf = [ "NetworkManager.service" ]; wants = [ "NetworkManager.service" ]; before = [ "NetworkManager.service" ]; script = '' mkdir -m 700 -p /etc/NetworkManager/system-connections mkdir -m 755 -p ${stateDirs} ''; - serviceConfig = { - Type = "oneshot"; - }; + serviceConfig.Type = "oneshot"; }; # Turn off NixOS' network management @@ -206,6 +204,7 @@ in { networkmanager_vpnc networkmanager_openconnect networkmanager_pptp + modemmanager ]; services.udev.packages = cfg.packages; diff --git a/nixos/modules/services/networking/ntpd.nix b/nixos/modules/services/networking/ntpd.nix index e5e164021d3a..3d388cb10648 100644 --- a/nixos/modules/services/networking/ntpd.nix +++ b/nixos/modules/services/networking/ntpd.nix @@ -15,6 +15,11 @@ let # chroot to ${stateDir}, we have to specify it as /ntp.drift. driftfile /ntp.drift + restrict default kod nomodify notrap nopeer noquery + restrict -6 default kod nomodify notrap nopeer noquery + restrict 127.0.0.1 + restrict -6 ::1 + ${toString (map (server: "server " + server + " iburst\n") config.services.ntp.servers)} ''; diff --git a/nixos/modules/services/networking/searx.nix b/nixos/modules/services/networking/searx.nix new file mode 100644 index 000000000000..30f21151a762 --- /dev/null +++ b/nixos/modules/services/networking/searx.nix @@ -0,0 +1,75 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.searx; + + configFile = cfg.configFile; + +in + +{ + + ###### interface + + options = { + + services.searx = { + + enable = mkOption { + default = false; + description = " + Whether to enable the Searx server. See https://github.com/asciimoo/searx + "; + }; + + configFile = mkOption { + default = ""; + description = " + The path of the Searx server configuration file. If no file + is specified, a default file is used (default config file has + debug mode enabled). + "; + }; + + }; + + }; + + + ###### implementation + + config = mkIf config.services.searx.enable { + + users.extraUsers.searx = + { uid = config.ids.uids.searx; + description = "Searx user"; + createHome = true; + home = "/var/lib/searx"; + }; + + users.extraGroups.searx = + { gid = config.ids.gids.searx; + }; + + systemd.services.searx = + { + description = "Searx server, the meta search engine."; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = "searx"; + ExecStart = "${pkgs.pythonPackages.searx}/bin/searx-run"; + }; + } // (optionalAttrs (configFile != "") { + environment.SEARX_SETTINGS_PATH = configFile; + }); + + + environment.systemPackages = [ pkgs.pythonPackages.searx ]; + + }; + +} diff --git a/nixos/modules/services/networking/vsftpd.nix b/nixos/modules/services/networking/vsftpd.nix index 1c77cc6df4ea..763fa8dc3c42 100644 --- a/nixos/modules/services/networking/vsftpd.nix +++ b/nixos/modules/services/networking/vsftpd.nix @@ -91,6 +91,7 @@ let ${optionalString (pkgs.stdenv.system == "x86_64-linux") '' seccomp_sandbox=NO ''} + anon_umask=${cfg.anonymousUmask} ''; in @@ -139,6 +140,13 @@ in description = "RSA certificate file."; }; + anonymousUmask = mkOption { + type = types.string; + default = "077"; + example = "002"; + description = "Anonymous write umask."; + }; + } // (listToAttrs (catAttrs "nixosOption" optionDescription)); }; diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix index 1be3587c3bb9..fb8923e107a8 100644 --- a/nixos/modules/services/printing/cupsd.nix +++ b/nixos/modules/services/printing/cupsd.nix @@ -143,7 +143,9 @@ in }; services.printing.drivers = - [ pkgs.cups pkgs.cups_pdf_filter pkgs.ghostscript additionalBackends pkgs.perl pkgs.coreutils pkgs.gnused ]; + [ pkgs.cups pkgs.cups_pdf_filter pkgs.ghostscript additionalBackends + pkgs.perl pkgs.coreutils pkgs.gnused pkgs.bc pkgs.gawk pkgs.gnugrep + ]; services.printing.cupsdConf = '' diff --git a/nixos/modules/services/search/solr.nix b/nixos/modules/services/search/solr.nix new file mode 100644 index 000000000000..eab18c4229b7 --- /dev/null +++ b/nixos/modules/services/search/solr.nix @@ -0,0 +1,114 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.solr; + +in { + + options = { + services.solr = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Enables the solr service. + ''; + }; + + javaPackage = mkOption { + type = types.package; + default = pkgs.openjre; + description = '' + Which Java derivation to use for running solr. + ''; + }; + + solrPackage = mkOption { + type = types.package; + default = pkgs.solr; + description = '' + Which solr derivation to use for running solr. + ''; + }; + + log4jConfiguration = mkOption { + type = types.lines; + default = '' + log4j.rootLogger=INFO, stdout + log4j.appender.stdout=org.apache.log4j.ConsoleAppender + log4j.appender.stdout.Target=System.out + log4j.appender.stdout.layout=org.apache.log4j.PatternLayout + log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n + ''; + description = '' + Contents of the <literal>log4j.properties</literal> used. By default, + everything is logged to stdout (picked up by systemd) with level INFO. + ''; + }; + + user = mkOption { + type = types.str; + description = '' + The user that should run the solr process and. + the working directories. + ''; + }; + + group = mkOption { + type = types.str; + description = '' + The group that will own the working directory. + ''; + }; + + solrHome = mkOption { + type = types.str; + description = '' + The solr home directory. It is your own responsibility to + make sure this directory contains a working solr configuration, + and is writeable by the the user running the solr service. + Failing to do so, the solr will not start properly. + ''; + }; + + extraJavaOptions = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Extra command line options given to the java process running + solr. + ''; + }; + + extraWinstoneOptions = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Extra command line options given to the Winstone, which is + the servlet container hosting solr. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + + services.winstone.solr = { + serviceName = "solr"; + inherit (cfg) user group javaPackage; + warFile = "${cfg.solrPackage}/lib/solr.war"; + extraOptions = [ + "--commonLibFolder=${cfg.solrPackage}/lib/ext" + ] ++ cfg.extraWinstoneOptions; + extraJavaOptions = [ + "-Dsolr.solr.home=${cfg.solrHome}" + "-Dlog4j.configuration=file://${pkgs.writeText "log4j.properties" cfg.log4jConfiguration}" + ] ++ cfg.extraJavaOptions; + }; + + }; + +} diff --git a/nixos/modules/services/system/nscd.nix b/nixos/modules/services/system/nscd.nix index b817b1df779f..3259bdbbe128 100644 --- a/nixos/modules/services/system/nscd.nix +++ b/nixos/modules/services/system/nscd.nix @@ -5,6 +5,7 @@ with pkgs.lib; let nssModulesPath = config.system.nssModules.path; + cfg = config.services.nscd; inherit (pkgs.lib) singleton; @@ -24,6 +25,12 @@ in description = "Whether to enable the Name Service Cache Daemon."; }; + config = mkOption { + type = types.lines; + default = builtins.readFile ./nscd.conf; + description = "Configuration to use for Name Service Cache Daemon."; + }; + }; }; @@ -31,7 +38,7 @@ in ###### implementation - config = mkIf config.services.nscd.enable { + config = mkIf cfg.enable { users.extraUsers = singleton { name = "nscd"; @@ -56,7 +63,7 @@ in restartTriggers = [ config.environment.etc.hosts.source ]; serviceConfig = - { ExecStart = "@${pkgs.glibc}/sbin/nscd nscd -f ${./nscd.conf}"; + { ExecStart = "@${pkgs.glibc}/sbin/nscd nscd -f ${pkgs.writeText "nscd.conf" cfg.config}"; Type = "forking"; PIDFile = "/run/nscd/nscd.pid"; Restart = "always"; diff --git a/nixos/modules/services/ttys/agetty.nix b/nixos/modules/services/ttys/agetty.nix index ae4fa87d4b7b..ca4fbeb0add3 100644 --- a/nixos/modules/services/ttys/agetty.nix +++ b/nixos/modules/services/ttys/agetty.nix @@ -28,6 +28,17 @@ with pkgs.lib; ''; }; + serialSpeed = mkOption { + type = types.listOf types.int; + default = [ 115200 57600 38400 9600 ]; + example = [ 38400 9600 ]; + description = '' + Bitrates to allow for agetty's listening on serial ports. Listing more + bitrates gives more interoperability but at the cost of long delays + for getting a sync on the line. + ''; + }; + }; }; @@ -37,81 +48,25 @@ with pkgs.lib; config = { - # FIXME: these are mostly copy/pasted from the systemd sources, - # which some small modifications, which is annoying. - - # Generate a separate job for each tty. - systemd.units."getty@.service".text = - '' - [Unit] - Description=Getty on %I - Documentation=man:agetty(8) - After=systemd-user-sessions.service plymouth-quit-wait.service - - # If additional gettys are spawned during boot then we should make - # sure that this is synchronized before getty.target, even though - # getty.target didn't actually pull it in. - Before=getty.target - IgnoreOnIsolate=yes - - ConditionPathExists=/dev/tty0 - - [Service] - Environment=TERM=linux - Environment=LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive - ExecStart=@${pkgs.utillinux}/sbin/agetty agetty --noclear --login-program ${pkgs.shadow}/bin/login %I 38400 - Type=idle - Restart=always - RestartSec=0 - UtmpIdentifier=%I - TTYPath=/dev/%I - TTYReset=yes - TTYVHangup=yes - TTYVTDisallocate=yes # set to no to prevent clearing the screen - KillMode=process - IgnoreSIGPIPE=no - - # Some login implementations ignore SIGTERM, so we send SIGHUP - # instead, to ensure that login terminates cleanly. - KillSignal=SIGHUP - - X-RestartIfChanged=false - ''; - - systemd.units."serial-getty@.service".text = - '' - [Unit] - Description=Serial Getty on %I - Documentation=man:agetty(8) man:systemd-getty-generator(8) - BindsTo=dev-%i.device - After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service - - # If additional gettys are spawned during boot then we should make - # sure that this is synchronized before getty.target, even though - # getty.target didn't actually pull it in. - Before=getty.target - IgnoreOnIsolate=yes - - [Service] - Environment=TERM=linux - Environment=LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive - ExecStart=@${pkgs.utillinux}/sbin/agetty agetty --login-program ${pkgs.shadow}/bin/login %I 115200,57600,38400,9600 - Type=idle - Restart=always - RestartSec=0 - UtmpIdentifier=%I - TTYPath=/dev/%I - TTYReset=yes - TTYVHangup=yes - KillMode=process - IgnoreSIGPIPE=no - - # Some login implementations ignore SIGTERM, so we send SIGHUP - # instead, to ensure that login terminates cleanly. - KillSignal=SIGHUP - - X-RestartIfChanged=false - ''; + systemd.services."getty@" = + { baseUnit = pkgs.runCommand "getty.service" {} + '' + sed '/ExecStart/ d' < ${config.systemd.package}/example/systemd/system/getty@.service > $out + ''; + serviceConfig.ExecStart = "@${pkgs.utillinux}/sbin/agetty agetty --noclear --login-program ${pkgs.shadow}/bin/login %I 38400"; + restartIfChanged = false; + }; + + systemd.services."serial-getty@" = + { baseUnit = pkgs.runCommand "serial-getty.service" {} + '' + sed '/ExecStart/ d' < ${config.systemd.package}/example/systemd/system/serial-getty@.service > $out + ''; + serviceConfig.ExecStart = + let speeds = concatStringsSep "," (map toString config.services.mingetty.serialSpeed); + in "@${pkgs.utillinux}/sbin/agetty agetty --login-program ${pkgs.shadow}/bin/login %I ${speeds}"; + restartIfChanged = false; + }; environment.etc = singleton { # Friendly greeting on the virtual consoles. diff --git a/nixos/modules/services/ttys/kmscon.nix b/nixos/modules/services/ttys/kmscon.nix index 302e660a7bff..70555e5d8825 100644 --- a/nixos/modules/services/ttys/kmscon.nix +++ b/nixos/modules/services/ttys/kmscon.nix @@ -44,6 +44,7 @@ in { After=systemd-user-sessions.service After=plymouth-quit-wait.service After=systemd-logind.service + After=systemd-vconsole-setup.service Requires=systemd-logind.service Before=getty.target Conflicts=getty@%i.service @@ -62,17 +63,19 @@ in { X-RestartIfChanged=false ''; - systemd.units."autovt@.service".linkTarget = "${config.systemd.units."kmsconvt@.service".unit}/kmsconvt@.service"; - - systemd.services."systemd-vconsole-setup".restartIfChanged = false; + systemd.units."autovt@.service".unit = pkgs.runCommand "unit" { } + '' + mkdir -p $out + ln -s ${config.systemd.units."kmsconvt@.service".unit}/kmsconvt@.service $out/autovt@.service + ''; - systemd.units."kmsconvt@tty1.service".extraConfig.wait-for-vconsole-setup = "After=systemd-vconsole-setup.service"; + systemd.services.systemd-vconsole-setup.restartIfChanged = false; services.kmscon.extraConfig = mkIf cfg.hwRender '' drm hwaccel ''; - services.mesa.enable = mkIf cfg.hwRender true; + hardware.opengl.enable = mkIf cfg.hwRender true; }; } diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix index 2552ec18bb92..a22ef10312d4 100644 --- a/nixos/modules/services/web-servers/apache-httpd/default.nix +++ b/nixos/modules/services/web-servers/apache-httpd/default.nix @@ -63,6 +63,7 @@ let enablePHP = false; phpOptions = ""; options = {}; + documentRoot = null; }; res = defaults // svcFunction { inherit config pkgs serverInfo php; }; in res; @@ -188,7 +189,11 @@ let subservices = callSubservices serverInfo cfg.extraSubservices; - documentRoot = if cfg.documentRoot != null then cfg.documentRoot else + maybeDocumentRoot = fold (svc: acc: + if acc == null then svc.documentRoot else assert svc.documentRoot == null; acc + ) null ([ cfg ] ++ subservices); + + documentRoot = if maybeDocumentRoot != null then maybeDocumentRoot else pkgs.runCommand "empty" {} "ensureDir $out"; documentRootConf = '' @@ -240,7 +245,7 @@ let ${robotsConf} - ${if isMainServer || cfg.documentRoot != null then documentRootConf else ""} + ${if isMainServer || maybeDocumentRoot != null then documentRootConf else ""} ${if cfg.enableUserDir then '' @@ -414,7 +419,7 @@ in }; package = mkOption { - type = types.path; + type = types.package; default = pkgs.apacheHttpd.override { mpm = mainCfg.multiProcessingModule; }; example = "pkgs.apacheHttpd_2_4"; description = '' @@ -628,8 +633,8 @@ in ++ concatMap (svc: svc.extraServerPath) allSubservices; environment = - { PHPRC = if enablePHP then phpIni else ""; - } // (listToAttrs (concatMap (svc: svc.globalEnvVars) allSubservices)); + optionalAttrs enablePHP { PHPRC = phpIni; } + // (listToAttrs (concatMap (svc: svc.globalEnvVars) allSubservices)); preStart = '' diff --git a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix index 423087991e13..f5669faebc97 100644 --- a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix +++ b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix @@ -93,6 +93,10 @@ let ensureDir $out cp -r * $out cp ${mediawikiConfig} $out/LocalSettings.php + sed -i 's|/bin/bash|${pkgs.stdenv.shell}|' \ + $out/maintenance/fuzz-tester.php \ + $out/bin/ulimit.sh \ + $out/includes/GlobalFunctions.php ''; }; @@ -122,7 +126,18 @@ in </Directory> ''} - Alias ${config.urlPrefix} ${mediawikiRoot} + ${if config.urlPrefix != "" then "Alias ${config.urlPrefix} ${mediawikiRoot}" else '' + RewriteEngine On + RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f + RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d + RewriteRule ${if config.enableUploads + then "!^/images" + else "^.*\$" + } %{DOCUMENT_ROOT}/${if config.articleUrlPrefix == "" + then "" + else "${config.articleUrlPrefix}/" + }index.php [L] + ''} <Directory ${mediawikiRoot}> Order allow,deny @@ -135,6 +150,8 @@ in ''} ''; + documentRoot = if config.urlPrefix == "" then mediawikiRoot else null; + enablePHP = true; options = { @@ -290,6 +307,7 @@ in echo COMMIT ) | ${pkgs.postgresql}/bin/psql -U "${config.dbUser}" "${config.dbName}" fi + ${php}/bin/php ${mediawikiRoot}/maintenance/update.php ''); robotsEntries = optionalString (config.articleUrlPrefix != "") diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 4a1b6de2873f..1a39fe43bbee 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -9,6 +9,7 @@ let user ${cfg.user} ${cfg.group}; daemon off; ${cfg.config} + ${cfg.appendConfig} ''; in @@ -24,6 +25,7 @@ in package = mkOption { default = pkgs.nginx; + type = types.package; description = " Nginx package to use. "; @@ -36,6 +38,19 @@ in "; }; + appendConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Configuration lines appended to the generated Nginx + configuration file. Commonly used by different modules + providing http snippets. <option>appendConfig</option> + can be specified more than once and it's value will be + concatenated (contrary to <option>config</option> which + can be set only once). + ''; + }; + stateDir = mkOption { default = "/var/spool/nginx"; description = " diff --git a/nixos/modules/services/web-servers/phpfpm.nix b/nixos/modules/services/web-servers/phpfpm.nix new file mode 100644 index 000000000000..76ec41244627 --- /dev/null +++ b/nixos/modules/services/web-servers/phpfpm.nix @@ -0,0 +1,77 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + cfg = config.services.phpfpm; + + stateDir = "/run/phpfpm"; + + pidFile = "${stateDir}/phpfpm.pid"; + + cfgFile = pkgs.writeText "phpfpm.conf" '' + [global] + pid = ${pidFile} + error_log = syslog + daemonize = yes + ${cfg.extraConfig} + + ${concatStringsSep "\n" (mapAttrsToList (n: v: "[${n}]\n${v}") cfg.poolConfigs)} + ''; + +in { + + options = { + services.phpfpm = { + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra configuration that should be put in the global section of + the PHP FPM configuration file. Do not specify the options + <literal>pid</literal>, <literal>error_log</literal> or + <literal>daemonize</literal> here, since they are generated by + NixOS. + ''; + }; + + poolConfigs = mkOption { + type = types.attrsOf types.lines; + default = {}; + example = { + mypool = '' + listen = /run/phpfpm/mypool + user = nobody + pm = dynamic + pm.max_children = 75 + pm.start_servers = 10 + pm.min_spare_servers = 5 + pm.max_spare_servers = 20 + pm.max_requests = 500 + ''; + }; + description = '' + A mapping between PHP FPM pool names and their configurations. + See the documentation on <literal>php-fpm.conf</literal> for + details on configuration directives. If no pools are defined, + the phpfpm service is disabled. + ''; + }; + }; + }; + + config = mkIf (cfg.poolConfigs != {}) { + + systemd.services.phpfpm = { + wantedBy = [ "multi-user.target" ]; + preStart = '' + mkdir -p "${stateDir}" + ''; + serviceConfig = { + ExecStart = "${pkgs.php54}/sbin/php-fpm -y ${cfgFile}"; + PIDFile = pidFile; + }; + }; + + }; +} diff --git a/nixos/modules/services/web-servers/winstone.nix b/nixos/modules/services/web-servers/winstone.nix new file mode 100644 index 000000000000..33c7e7301182 --- /dev/null +++ b/nixos/modules/services/web-servers/winstone.nix @@ -0,0 +1,129 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.winstone; + + winstoneOpts = { name, ... }: { + options = { + name = mkOption { + default = name; + internal = true; + }; + + serviceName = mkOption { + type = types.str; + description = '' + The name of the systemd service. By default, it is + derived from the winstone instance name. + ''; + }; + + warFile = mkOption { + type = types.str; + description = '' + The WAR file that Winstone should serve. + ''; + }; + + javaPackage = mkOption { + type = types.package; + default = pkgs.openjre; + description = '' + Which Java derivation to use for running Winstone. + ''; + }; + + user = mkOption { + type = types.str; + description = '' + The user that should run this Winstone process and + own the working directory. + ''; + }; + + group = mkOption { + type = types.str; + description = '' + The group that will own the working directory. + ''; + }; + + workDir = mkOption { + type = types.str; + description = '' + The working directory for this Winstone instance. Will + contain extracted webapps etc. The directory will be + created if it doesn't exist. + ''; + }; + + extraJavaOptions = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Extra command line options given to the java process running + Winstone. + ''; + }; + + extraOptions = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Extra command line options given to the Winstone process. + ''; + }; + }; + + config = { + workDir = mkDefault "/run/winstone/${name}"; + serviceName = mkDefault "winstone-${name}"; + }; + }; + + mkService = cfg: let + opts = concatStringsSep " " (cfg.extraOptions ++ [ + "--warfile ${cfg.warFile}" + ]); + + javaOpts = concatStringsSep " " (cfg.extraJavaOptions ++ [ + "-Djava.io.tmpdir=${cfg.workDir}" + "-jar ${pkgs.winstone}/lib/winstone.jar" + ]); + in { + wantedBy = [ "multi-user.target" ]; + description = "winstone service for ${cfg.name}"; + preStart = '' + mkdir -p "${cfg.workDir}" + chown ${cfg.user}:${cfg.group} "${cfg.workDir}" + ''; + serviceConfig = { + ExecStart = "${cfg.javaPackage}/bin/java ${javaOpts} ${opts}"; + User = cfg.user; + PermissionsStartOnly = true; + }; + }; + +in { + + options = { + services.winstone = mkOption { + default = {}; + type = types.attrsOf types.optionSet; + options = [ winstoneOpts ]; + description = '' + Defines independent Winstone services, each serving one WAR-file. + ''; + }; + }; + + config = mkIf (cfg != {}) { + + systemd.services = mapAttrs' (n: c: nameValuePair c.serviceName (mkService c)) cfg; + + }; + +} diff --git a/nixos/modules/services/x11/desktop-managers/default.nix b/nixos/modules/services/x11/desktop-managers/default.nix index 035b23b4e1bb..753babf6a225 100644 --- a/nixos/modules/services/x11/desktop-managers/default.nix +++ b/nixos/modules/services/x11/desktop-managers/default.nix @@ -7,9 +7,9 @@ let xcfg = config.services.xserver; cfg = xcfg.desktopManager; - # Whether desktop manager `d' is capable of setting a background. - # If it isn't, the `feh' program is used as a fallback. - needBGCond = d: ! (d ? bgSupport && d.bgSupport); + # If desktop manager `d' isn't capable of setting a background and + # the xserver is enabled, the `feh' program is used as a fallback. + needBGCond = d: ! (d ? bgSupport && d.bgSupport) && xcfg.enable; in @@ -17,7 +17,7 @@ in # Note: the order in which desktop manager modules are imported here # determines the default: later modules (if enabled) are preferred. # E.g., if KDE is enabled, it supersedes xterm. - imports = [ ./none.nix ./xterm.nix ./xfce.nix ./kde4.nix ./e17.nix ]; + imports = [ ./none.nix ./xterm.nix ./xfce.nix ./kde4.nix ./e17.nix ./gnome3.nix ./xbmc.nix ]; options = { diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix new file mode 100644 index 000000000000..456975015a22 --- /dev/null +++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix @@ -0,0 +1,68 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + cfg = config.services.xserver.desktopManager.gnome3; + gnome3 = pkgs.gnome3; +in { + + options = { + + services.xserver.desktopManager.gnome3.enable = mkOption { + default = false; + example = true; + description = "Enable Gnome 3 desktop manager."; + }; + + }; + + config = mkIf cfg.enable { + + # Enable helpful DBus services. + security.polkit.enable = true; + services.udisks2.enable = true; + networking.networkmanager.enable = true; + services.upower.enable = config.powerManagement.enable; + + fonts.extraFonts = [ pkgs.dejavu_fonts ]; + + services.xserver.desktopManager.session = singleton + { name = "gnome3"; + start = '' + # Set GTK_DATA_PREFIX so that GTK+ can find the themes + export GTK_DATA_PREFIX=${config.system.path} + + # find theme engines + export GTK_PATH=${config.system.path}/lib/gtk-3.0:${config.system.path}/lib/gtk-2.0 + + export XDG_MENU_PREFIX=gnome + + ${gnome3.gnome_session}/bin/gnome-session& + waitPID=$! + ''; + }; + + environment.variables.GIO_EXTRA_MODULES = "${gnome3.dconf}/lib/gio/modules"; + environment.systemPackages = + [ gnome3.evince + gnome3.eog + gnome3.dconf + gnome3.vino + gnome3.epiphany + gnome3.baobab + gnome3.gucharmap + gnome3.nautilus + gnome3.yelp + pkgs.ibus + gnome3.gnome_shell + gnome3.gnome_settings_daemon + gnome3.gnome_terminal + gnome3.gnome_icon_theme + gnome3.gnome_themes_standard + gnome3.gnome_control_center + ]; + }; + + +} diff --git a/nixos/modules/services/x11/desktop-managers/xbmc.nix b/nixos/modules/services/x11/desktop-managers/xbmc.nix new file mode 100644 index 000000000000..51278c5fadb6 --- /dev/null +++ b/nixos/modules/services/x11/desktop-managers/xbmc.nix @@ -0,0 +1,31 @@ +{ pkgs, config, ... }: + +with pkgs.lib; + +let + cfg = config.services.xserver.desktopManager.xbmc; +in + +{ + options = { + services.xserver.desktopManager.xbmc = { + enable = mkOption { + default = false; + example = true; + description = "Enable the xbmc multimedia center."; + }; + }; + }; + + config = mkIf cfg.enable { + services.xserver.desktopManager.session = [{ + name = "xbmc"; + start = '' + ${pkgs.xbmc}/bin/xbmc --lircdev /var/run/lirc/lircd --standalone & + waitPID=$! + ''; + }]; + + environment.systemPackages = [ pkgs.xbmc ]; + }; +} \ No newline at end of file diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix index 5e5fab3ed2bb..3c67571ffd5b 100644 --- a/nixos/modules/services/x11/desktop-managers/xfce.nix +++ b/nixos/modules/services/x11/desktop-managers/xfce.nix @@ -29,7 +29,7 @@ in start = '' # Set GTK_PATH so that GTK+ can find the theme engines. - export GTK_PATH=${config.system.path}/lib/gtk-2.0 + export GTK_PATH="${config.system.path}/lib/gtk-2.0:${config.system.path}/lib/gtk-3.0" # Set GTK_DATA_PREFIX so that GTK+ can find the Xfce themes. export GTK_DATA_PREFIX=${config.system.path} diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix index e4125891e6cb..0fa16a77c1b9 100644 --- a/nixos/modules/services/x11/display-managers/lightdm.nix +++ b/nixos/modules/services/x11/display-managers/lightdm.nix @@ -55,8 +55,8 @@ let '' [LightDM] greeter-user = ${config.users.extraUsers.lightdm.name} - xgreeters-directory = ${cfg.greeter.package} - xsessions-directory = ${dmcfg.session.desktops} + greeters-directory = ${cfg.greeter.package} + sessions-directory = ${dmcfg.session.desktops} [SeatDefaults] xserver-command = ${xserverWrapper} diff --git a/nixos/modules/services/x11/hardware/synaptics.nix b/nixos/modules/services/x11/hardware/synaptics.nix index 91e01f2e30b1..fe9dcd51a7a6 100644 --- a/nixos/modules/services/x11/hardware/synaptics.nix +++ b/nixos/modules/services/x11/hardware/synaptics.nix @@ -2,9 +2,23 @@ with pkgs.lib; -let cfg = config.services.xserver.synaptics; in - -{ +let cfg = config.services.xserver.synaptics; + tapConfig = if cfg.tapButtons then enabledTapConfig else disabledTapConfig; + enabledTapConfig = '' + Option "MaxTapTime" "180" + Option "MaxTapMove" "220" + Option "TapButton1" "${builtins.elemAt cfg.buttonsMap 0}" + Option "TapButton2" "${builtins.elemAt cfg.buttonsMap 1}" + Option "TapButton3" "${builtins.elemAt cfg.buttonsMap 2}" + ''; + disabledTapConfig = '' + Option "MaxTapTime" "0" + Option "MaxTapMove" "0" + Option "TapButton1" "0" + Option "TapButton2" "0" + Option "TapButton3" "0" + ''; +in { options = { @@ -106,15 +120,10 @@ let cfg = config.services.xserver.synaptics; in MatchIsTouchpad "on" ${optionalString (cfg.dev != null) ''MatchDevicePath "${cfg.dev}"''} Driver "synaptics" - Option "MaxTapTime" "180" - Option "MaxTapMove" "220" Option "MinSpeed" "${cfg.minSpeed}" Option "MaxSpeed" "${cfg.maxSpeed}" Option "AccelFactor" "${cfg.accelFactor}" - ${if cfg.tapButtons then "" else ''Option "MaxTapTime" "0"''} - Option "TapButton1" "${builtins.elemAt cfg.buttonsMap 0}" - Option "TapButton2" "${builtins.elemAt cfg.buttonsMap 1}" - Option "TapButton3" "${builtins.elemAt cfg.buttonsMap 2}" + ${optionalString cfg.tapButtons tapConfig} Option "ClickFinger1" "${builtins.elemAt cfg.buttonsMap 0}" Option "ClickFinger2" "${builtins.elemAt cfg.buttonsMap 1}" Option "ClickFinger3" "${builtins.elemAt cfg.buttonsMap 2}" diff --git a/nixos/modules/services/x11/redshift.nix b/nixos/modules/services/x11/redshift.nix index b9ad962d8e46..02416f5ef129 100644 --- a/nixos/modules/services/x11/redshift.nix +++ b/nixos/modules/services/x11/redshift.nix @@ -14,24 +14,37 @@ in { services.redshift.latitude = mkOption { description = "Your current latitude"; - type = types.string; + type = types.uniq types.string; }; services.redshift.longitude = mkOption { description = "Your current longitude"; - type = types.string; + type = types.uniq types.string; }; services.redshift.temperature = { day = mkOption { description = "Colour temperature to use during day time"; default = 5500; - type = types.int; + type = types.uniq types.int; }; night = mkOption { description = "Colour temperature to use during night time"; default = 3700; - type = types.int; + type = types.uniq types.int; + }; + }; + + services.redshift.brightness = { + day = mkOption { + description = "Screen brightness to apply during the day (between 0.1 and 1.0)"; + default = "1"; + type = types.uniq types.string; + }; + night = mkOption { + description = "Screen brightness to apply during the night (between 0.1 and 1.0)"; + default = "1"; + type = types.uniq types.string; }; }; }; @@ -41,10 +54,12 @@ in { description = "Redshift colour temperature adjuster"; requires = [ "display-manager.service" ]; after = [ "display-manager.service" ]; - script = '' + wantedBy = [ "graphical.target" ]; + serviceConfig.ExecStart = '' ${pkgs.redshift}/bin/redshift \ -l ${cfg.latitude}:${cfg.longitude} \ - -t ${toString cfg.temperature.day}:${toString cfg.temperature.night} + -t ${toString cfg.temperature.day}:${toString cfg.temperature.night} \ + -b ${toString cfg.brightness.day}:${toString cfg.brightness.night} ''; environment = { DISPLAY = ":0"; }; serviceConfig.Restart = "always"; diff --git a/nixos/modules/services/x11/terminal-server.nix b/nixos/modules/services/x11/terminal-server.nix index bf9c3435503d..f16a424b4573 100644 --- a/nixos/modules/services/x11/terminal-server.nix +++ b/nixos/modules/services/x11/terminal-server.nix @@ -27,7 +27,7 @@ in config = { services.xserver.enable = true; - services.xserver.videoDrivers = []; + hardware.opengl.videoDrivers = []; # Enable KDM. Any display manager will do as long as it supports XDMCP. services.xserver.displayManager.kdm.enable = true; diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix index 4d52e398b477..1c10333462c8 100644 --- a/nixos/modules/services/x11/window-managers/default.nix +++ b/nixos/modules/services/x11/window-managers/default.nix @@ -16,7 +16,6 @@ in ./wmii.nix ./xmonad.nix ./i3.nix - ./xbmc.nix ./herbstluftwm.nix ]; diff --git a/nixos/modules/services/x11/window-managers/xbmc.nix b/nixos/modules/services/x11/window-managers/xbmc.nix deleted file mode 100644 index 46494202b404..000000000000 --- a/nixos/modules/services/x11/window-managers/xbmc.nix +++ /dev/null @@ -1,31 +0,0 @@ -{pkgs, config, ...}: - -let - inherit (pkgs.lib) mkOption mkIf; - cfg = config.services.xserver.windowManager.xbmc; -in - -{ - options = { - services.xserver.windowManager.xbmc = { - enable = mkOption { - default = false; - example = true; - description = "Enable the xbmc multimedia center."; - }; - }; - }; - - config = mkIf cfg.enable { - services.xserver.windowManager = { - session = [{ - name = "xbmc"; - start = " - ${pkgs.xbmc}/bin/xbmc --lircdev /var/run/lirc/lircd --standalone & - waitPID=$! - "; - }]; - }; - environment.systemPackages = [ pkgs.xbmc ]; - }; -} diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix index 5600ce7fac13..2677f7584565 100644 --- a/nixos/modules/services/x11/xserver.nix +++ b/nixos/modules/services/x11/xserver.nix @@ -22,7 +22,7 @@ let virtualbox = { modules = [ kernelPackages.virtualboxGuestAdditions ]; driverName = "vboxvideo"; }; }; - driverNames = config.services.mesa.videoDrivers; + driverNames = config.hardware.opengl.videoDrivers; drivers = flip map driverNames (name: { inherit name; driverName = name; } // @@ -181,7 +181,7 @@ in description = '' The name of the video driver for your graphics card. This option is obsolete; please set the - <option>services.mesa.videoDrivers</option> instead. + <option>hardware.opengl.videoDrivers</option> instead. ''; }; @@ -381,8 +381,8 @@ in ###### implementation config = mkIf cfg.enable { - services.mesa.enable = true; - services.mesa.videoDrivers = mkIf (cfg.videoDriver != null) [ cfg.videoDriver ]; + hardware.opengl.enable = true; + hardware.opengl.videoDrivers = mkIf (cfg.videoDriver != null) [ cfg.videoDriver ]; assertions = [ { assertion = !(cfg.startOpenSSHAgent && cfg.startGnuPGAgent); diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl index 33ae3aef9fca..e0649448c834 100644 --- a/nixos/modules/system/activation/switch-to-configuration.pl +++ b/nixos/modules/system/activation/switch-to-configuration.pl @@ -93,8 +93,13 @@ sub parseFstab { sub parseUnit { my ($filename) = @_; + parseKeyValues(read_file($filename)); +} + +sub parseKeyValues { + my @lines = @_; my $info = {}; - foreach my $line (read_file($filename)) { + foreach my $line (@_) { # FIXME: not quite correct. $line =~ /^([^=]+)=(.*)$/ or next; $info->{$1} = $2; @@ -123,7 +128,7 @@ while (my ($unit, $state) = each %{$activePrev}) { $baseName =~ s/\.[a-z]*$//; if (-e $prevUnitFile && ($state->{state} eq "active" || $state->{state} eq "activating")) { - if (! -e $newUnitFile) { + if (! -e $newUnitFile || abs_path($newUnitFile) eq "/dev/null") { push @unitsToStop, $unit; } @@ -337,8 +342,21 @@ system("@systemd@/bin/systemctl", "reload", "dbus.service"); my (@failed, @new, @restarting); my $activeNew = getActiveUnits; while (my ($unit, $state) = each %{$activeNew}) { - push @failed, $unit if $state->{state} eq "failed" || $state->{substate} eq "auto-restart"; - push @new, $unit if $state->{state} ne "failed" && !defined $activePrev->{$unit}; + if ($state->{state} eq "failed") { + push @failed, $unit; + } + elsif ($state->{state} eq "auto-restart") { + # A unit in auto-restart state is a failure *if* it previously failed to start + my $lines = `@systemd@/bin/systemctl show '$unit'`; + my $info = parseKeyValues(split "\n", $lines); + + if ($info->{ExecMainStatus} ne '0') { + push @failed, $unit; + } + } + elsif ($state->{state} ne "failed" && !defined $activePrev->{$unit}) { + push @new, $unit; + } } print STDERR "the following new units were started: ", join(", ", sort(@new)), "\n" diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix index 2b075bf6a6d2..327f3b7e1128 100644 --- a/nixos/modules/system/boot/kernel.nix +++ b/nixos/modules/system/boot/kernel.nix @@ -159,7 +159,7 @@ in boot.kernel.sysctl."kernel.printk" = config.boot.consoleLogLevel; - boot.kernelModules = [ "loop" ]; + boot.kernelModules = [ "loop" "configs" ]; boot.initrd.availableKernelModules = [ # Note: most of these (especially the SATA/PATA modules) diff --git a/nixos/modules/system/boot/loader/grub/memtest.nix b/nixos/modules/system/boot/loader/grub/memtest.nix index 80c1a160cfde..afe194e672ae 100644 --- a/nixos/modules/system/boot/loader/grub/memtest.nix +++ b/nixos/modules/system/boot/loader/grub/memtest.nix @@ -6,28 +6,82 @@ with pkgs.lib; let memtest86 = pkgs.memtest86plus; + cfg = config.boot.loader.grub.memtest86; in { options = { - boot.loader.grub.memtest86 = mkOption { - default = false; - type = types.bool; - description = '' - Make Memtest86+, a memory testing program, available from the - GRUB boot menu. - ''; + boot.loader.grub.memtest86 = { + + enable = mkOption { + default = false; + type = types.bool; + description = '' + Make Memtest86+, a memory testing program, available from the + GRUB boot menu. + ''; + }; + + params = mkOption { + default = []; + example = [ "console=ttyS0,115200" ]; + type = types.listOf types.str; + description = '' + Parameters added to the Memtest86+ command line. As of memtest86+ 5.01 + the following list of (apparently undocumented) parameters are + accepted: + + <itemizedlist> + + <listitem> + <para><literal>console=...</literal>, set up a serial console. + Examples: + <literal>console=ttyS0</literal>, + <literal>console=ttyS0,9600</literal> or + <literal>console=ttyS0,115200n8</literal>.</para> + </listitem> + + <listitem> + <para><literal>btrace</literal>, enable boot trace.</para> + </listitem> + + <listitem> + <para><literal>maxcpus=N</literal>, limit number of CPUs.</para> + </listitem> + + <listitem> + <para><literal>onepass</literal>, run one pass and exit if there + are no errors.</para> + </listitem> + + <listitem> + <para><literal>tstlist=...</literal>, list of tests to run. + Example: <literal>0,1,2</literal>.</para> + </listitem> + + <listitem> + <para><literal>cpumask=...</literal>, set a CPU mask, to select CPUs + to use for testing.</para> + </listitem> + + </itemizedlist> + + This list of command line options was obtained by reading the + Memtest86+ source code. + ''; + }; + }; }; - config = mkIf config.boot.loader.grub.memtest86 { + config = mkIf cfg.enable { boot.loader.grub.extraEntries = if config.boot.loader.grub.version == 2 then '' menuentry "Memtest86+" { - linux16 @bootRoot@/memtest.bin + linux16 @bootRoot@/memtest.bin ${toString cfg.params} } '' else diff --git a/nixos/modules/system/boot/loader/gummiboot/gummiboot-builder.py b/nixos/modules/system/boot/loader/gummiboot/gummiboot-builder.py index 9ea224b51f63..db73544181b6 100644 --- a/nixos/modules/system/boot/loader/gummiboot/gummiboot-builder.py +++ b/nixos/modules/system/boot/loader/gummiboot/gummiboot-builder.py @@ -9,7 +9,6 @@ import tempfile import errno def copy_if_not_exists(source, dest): - known_paths.append(dest) if not os.path.exists(dest): shutil.copyfile(source, dest) @@ -38,12 +37,13 @@ def write_loader_conf(generation): print >> f, "default nixos-generation-%d" % (generation) os.rename("@efiSysMountPoint@/loader/loader.conf.tmp", "@efiSysMountPoint@/loader/loader.conf") -def copy_from_profile(generation, name): +def copy_from_profile(generation, name, dry_run=False): store_file_path = os.readlink("%s/%s" % (system_dir(generation), name)) suffix = os.path.basename(store_file_path) store_dir = os.path.basename(os.path.dirname(store_file_path)) efi_file_path = "/efi/nixos/%s-%s.efi" % (store_dir, suffix) - copy_if_not_exists(store_file_path, "@efiSysMountPoint@%s" % (efi_file_path)) + if not dry_run: + copy_if_not_exists(store_file_path, "@efiSysMountPoint@%s" % (efi_file_path)) return efi_file_path def add_entry(generation): @@ -72,6 +72,10 @@ def get_generations(profile): def remove_old_entries(gens): slice_start = len("@efiSysMountPoint@/loader/entries/nixos-generation-") slice_end = -1 * len(".conf") + known_paths = [] + for gen in gens: + known_paths.append(copy_from_profile(gen, "kernel", True)) + known_paths.append(copy_from_profile(gen, "initrd", True)) for path in glob.iglob("@efiSysMountPoint@/loader/entries/nixos-generation-[1-9]*.conf"): try: gen = int(path[slice_start:slice_end]) @@ -94,7 +98,6 @@ if os.getenv("NIXOS_INSTALL_GRUB") == "1": else: subprocess.check_call(["@gummiboot@/bin/gummiboot", "--path=@efiSysMountPoint@", "--no-variables", "install"]) -known_paths = [] mkdir_p("@efiSysMountPoint@/efi/nixos") mkdir_p("@efiSysMountPoint@/loader/entries") try: @@ -106,9 +109,8 @@ except IOError as e: machine_id = None gens = get_generations("system") +remove_old_entries(gens) for gen in gens: add_entry(gen) if os.readlink(system_dir(gen)) == args.default_config: write_loader_conf(gen) - -remove_old_entries(gens) diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix index 8547682284f7..117c526fcd38 100644 --- a/nixos/modules/system/boot/luksroot.nix +++ b/nixos/modules/system/boot/luksroot.nix @@ -39,153 +39,123 @@ let ${optionalString (luks.yubikeySupport && (yubikey != null)) '' rbtohex() { - od -An -vtx1 | tr -d ' \n' + ( od -An -vtx1 | tr -d ' \n' ) } hextorb() { - tr '[:lower:]' '[:upper:]' | sed -e 's|\([0-9A-F]\{2\}\)|\\\\\\x\1|gI' | xargs printf - } - - take() { - local c="$1" - shift - head -c $c "$@" - } - - drop() { - local c="$1" - shift - if [ -e "$1" ]; then - cat "$1" | ( dd of=/dev/null bs="$c" count=1 2>/dev/null ; dd 2>/dev/null ) - else - ( dd of=/dev/null bs="$c" count=1 2>/dev/null ; dd 2>/dev/null ) - fi + ( tr '[:lower:]' '[:upper:]' | sed -e 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf ) } open_yubikey() { + # Make all of these local to this function + # to prevent their values being leaked + local salt + local iterations + local k_user + local challenge + local response + local k_luks + local opened + local new_salt + local new_iterations + local new_challenge + local new_response + local new_k_luks + mkdir -p ${yubikey.storage.mountPoint} mount -t ${yubikey.storage.fsType} ${toString yubikey.storage.device} ${yubikey.storage.mountPoint} - local uuid_r - local k_user - local challenge - local k_blob - local aes_blob_decrypted - local checksum_correct - local checksum - local uuid_luks - local user_record - - uuid_luks="$(cryptsetup luksUUID ${device} | take 36 | tr -d '-')" - - ${optionalString (!yubikey.multiUser) '' - user_record="$(cat ${yubikey.storage.mountPoint}${yubikey.storage.path})" - uuid_r="$(echo -n $user_record | take 32)" - ''} + salt="$(cat ${yubikey.storage.mountPoint}${yubikey.storage.path} | sed -n 1p | tr -d '\n')" + iterations="$(cat ${yubikey.storage.mountPoint}${yubikey.storage.path} | sed -n 2p | tr -d '\n')" + challenge="$(echo -n $salt | openssl-wrap dgst -binary -sha512 | rbtohex)" + response="$(ykchalresp -${toString yubikey.slot} -x $challenge 2>/dev/null)" for try in $(seq 3); do - ${optionalString yubikey.multiUser '' - local user_id - echo -n "Enter user id: " - read -s user_id - echo - ''} - ${optionalString yubikey.twoFactor '' echo -n "Enter two-factor passphrase: " read -s k_user echo ''} - ${optionalString yubikey.multiUser '' - local user_id_hash - user_id_hash="$(echo -n $user_id | openssl-wrap dgst -binary -sha512 | rbtohex)" - - user_record="$(sed -n -e /^$user_id_hash[^$]*$/p ${yubikey.storage.mountPoint}${yubikey.storage.path} | tr -d '\n')" - - if [ ! -z "$user_record" ]; then - user_record="$(echo -n $user_record | drop 128)" - uuid_r="$(echo -n $user_record | take 32)" - ''} - - challenge="$(echo -n $k_user$uuid_r$uuid_luks | openssl-wrap dgst -binary -sha1 | rbtohex)" - - k_blob="$(ykchalresp -${toString yubikey.slot} -x $challenge 2>/dev/null)" - - aes_blob_decrypted="$(echo -n $user_record | drop 32 | hextorb | openssl-wrap enc -d -aes-256-ctr -K $k_blob -iv $uuid_r | rbtohex)" + if [ ! -z "$k_user" ]; then + k_luks="$(echo -n $k_user | pbkdf2-sha512 ${toString yubikey.keyLength} $iterations $response | rbtohex)" + else + k_luks="$(echo | pbkdf2-sha512 ${toString yubikey.keyLength} $iterations $response | rbtohex)" + fi - checksum="$(echo -n $aes_blob_decrypted | drop 168)" - if [ "$(echo -n $aes_blob_decrypted | hextorb | take 84 | openssl-wrap dgst -binary -sha512 | rbtohex)" == "$checksum" ]; then - checksum_correct=1 - break - else - checksum_correct=0 - echo "Authentication failed!" - fi + echo -n "$k_luks" | hextorb | cryptsetup luksOpen ${device} ${name} ${optionalString allowDiscards "--allow-discards"} --key-file=- - ${optionalString yubikey.multiUser '' + if [ $? == "0" ]; then + opened=true + break else - checksum_correct=0 + opened=false echo "Authentication failed!" fi - ''} done - if [ "$checksum_correct" != "1" ]; then + if [ "$opened" == false ]; then umount ${yubikey.storage.mountPoint} echo "Maximum authentication errors reached" exit 1 fi - local k_yubi - k_yubi="$(echo -n $aes_blob_decrypted | take 40)" + echo -n "Gathering entropy for new salt (please enter random keys to generate entropy if this blocks for long)..." + for i in $(seq ${toString yubikey.saltLength}); do + byte="$(dd if=/dev/random bs=1 count=1 2>/dev/null | rbtohex)"; + new_salt="$new_salt$byte"; + echo -n . + done; + echo "ok" - local k_luks - k_luks="$(echo -n $aes_blob_decrypted | drop 40 | take 128)" + new_iterations="$iterations" + ${optionalString (yubikey.iterationStep > 0) '' + new_iterations="$(($new_iterations + ${toString yubikey.iterationStep}))" + ''} - echo -n "$k_luks" | hextorb | cryptsetup luksOpen ${device} ${name} ${optionalString allowDiscards "--allow-discards"} --key-file=- + new_challenge="$(echo -n $new_salt | openssl-wrap dgst -binary -sha512 | rbtohex)" - update_failed=false + new_response="$(ykchalresp -${toString yubikey.slot} -x $new_challenge 2>/dev/null)" - local new_uuid_r - new_uuid_r="$(uuidgen)" - if [ $? != "0" ]; then - for try in $(seq 10); do - sleep 1 - new_uuid_r="$(uuidgen)" - if [ $? == "0" ]; then break; fi - if [ $try -eq 10 ]; then update_failed=true; fi - done + if [ ! -z "$k_user" ]; then + new_k_luks="$(echo -n $k_user | pbkdf2-sha512 ${toString yubikey.keyLength} $new_iterations $new_response | rbtohex)" + else + new_k_luks="$(echo | pbkdf2-sha512 ${toString yubikey.keyLength} $new_iterations $new_response | rbtohex)" fi - if [ "$update_failed" == false ]; then - new_uuid_r="$(echo -n $new_uuid_r | take 36 | tr -d '-')" - - local new_challenge - new_challenge="$(echo -n $k_user$new_uuid_r$uuid_luks | openssl-wrap dgst -binary -sha1 | rbtohex)" - - local new_k_blob - new_k_blob="$(echo -n $new_challenge | hextorb | openssl-wrap dgst -binary -sha1 -mac HMAC -macopt hexkey:$k_yubi | rbtohex)" + mkdir -p ${yubikey.ramfsMountPoint} + # A ramfs is used here to ensure that the file used to update + # the key slot with cryptsetup will never get swapped out. + # Warning: Do NOT replace with tmpfs! + mount -t ramfs none ${yubikey.ramfsMountPoint} - local new_aes_blob - new_aes_blob=$(echo -n "$k_yubi$k_luks$checksum" | hextorb | openssl-wrap enc -e -aes-256-ctr -K "$new_k_blob" -iv "$new_uuid_r" | rbtohex) + echo -n "$new_k_luks" | hextorb > ${yubikey.ramfsMountPoint}/new_key + echo -n "$k_luks" | hextorb | cryptsetup luksChangeKey ${device} --key-file=- ${yubikey.ramfsMountPoint}/new_key - ${optionalString yubikey.multiUser '' - sed -i -e "s|^$user_id_hash$user_record|$user_id_hash$new_uuid_r$new_aes_blob|1" - ''} - - ${optionalString (!yubikey.multiUser) '' - echo -n "$new_uuid_r$new_aes_blob" > ${yubikey.storage.mountPoint}${yubikey.storage.path} - ''} + if [ $? == "0" ]; then + echo -ne "$new_salt\n$new_iterations" > ${yubikey.storage.mountPoint}${yubikey.storage.path} else - echo "Warning: Could not obtain new UUID, current challenge persists!" + echo "Warning: Could not update LUKS key, current challenge persists!" fi + rm -f ${yubikey.ramfsMountPoint}/new_key + umount ${yubikey.ramfsMountPoint} + rm -rf ${yubikey.ramfsMountPoint} + umount ${yubikey.storage.mountPoint} } + ${optionalString (yubikey.gracePeriod > 0) '' + echo -n "Waiting ${toString yubikey.gracePeriod} seconds as grace..." + for i in $(seq ${toString yubikey.gracePeriod}); do + sleep 1 + echo -n . + done + echo "ok" + ''} + yubikey_missing=true ykinfo -v 1>/dev/null 2>&1 if [ $? != "0" ]; then @@ -336,21 +306,45 @@ in description = "Whether to use a passphrase and a Yubikey (true), or only a Yubikey (false)"; }; - multiUser = mkOption { - default = false; - type = types.bool; - description = "Whether to allow multiple users to authenticate with a Yubikey"; - }; - slot = mkOption { default = 2; type = types.int; description = "Which slot on the Yubikey to challenge"; }; + saltLength = mkOption { + default = 16; + type = types.int; + description = "Length of the new salt in byte (64 is the effective maximum)"; + }; + + keyLength = mkOption { + default = 64; + type = types.int; + description = "Length of the LUKS slot key derived with PBKDF2 in byte"; + }; + + iterationStep = mkOption { + default = 0; + type = types.int; + description = "How much the iteration count for PBKDF2 is increased at each successful authentication"; + }; + + gracePeriod = mkOption { + default = 2; + type = types.int; + description = "Time in seconds to wait before attempting to find the Yubikey"; + }; + + ramfsMountPoint = mkOption { + default = "/crypt-ramfs"; + type = types.string; + description = "Path where the ramfs used to update the LUKS key will be mounted in stage-1"; + }; + storage = mkOption { type = types.optionSet; - description = "Options related to the authentication record"; + description = "Options related to the storing the salt"; options = { device = mkOption { @@ -358,7 +352,7 @@ in type = types.path; description = '' An unencrypted device that will temporarily be mounted in stage-1. - Must contain the authentication record for this LUKS device. + Must contain the current salt to create the challenge for this LUKS device. ''; }; @@ -378,7 +372,7 @@ in default = "/crypt-storage/default"; type = types.string; description = '' - Absolute path of the authentication record on the unencrypted device with + Absolute path of the salt on the unencrypted device with that device's root directory as "/". ''; }; @@ -420,11 +414,13 @@ in cp -pdv ${pkgs.popt}/lib/libpopt*.so.* $out/lib ${optionalString luks.yubikeySupport '' - cp -pdv ${pkgs.utillinux}/bin/uuidgen $out/bin cp -pdv ${pkgs.ykpers}/bin/ykchalresp $out/bin cp -pdv ${pkgs.ykpers}/bin/ykinfo $out/bin cp -pdv ${pkgs.openssl}/bin/openssl $out/bin + cc -O3 -I${pkgs.openssl}/include -L${pkgs.openssl}/lib ${./pbkdf2-sha512.c} -o $out/bin/pbkdf2-sha512 -lcrypto + strip -s $out/bin/pbkdf2-sha512 + cp -pdv ${pkgs.libusb1}/lib/libusb*.so.* $out/lib cp -pdv ${pkgs.ykpers}/lib/libykpers*.so.* $out/lib cp -pdv ${pkgs.libyubikey}/lib/libyubikey*.so.* $out/lib @@ -444,7 +440,6 @@ EOF boot.initrd.extraUtilsCommandsTest = '' $out/bin/cryptsetup --version ${optionalString luks.yubikeySupport '' - $out/bin/uuidgen --version $out/bin/ykchalresp -V $out/bin/ykinfo -V cat > $out/bin/openssl-wrap <<EOF diff --git a/nixos/modules/system/boot/modprobe.nix b/nixos/modules/system/boot/modprobe.nix index 027a7ac99d51..f694fd29dd04 100644 --- a/nixos/modules/system/boot/modprobe.nix +++ b/nixos/modules/system/boot/modprobe.nix @@ -68,7 +68,10 @@ with pkgs.lib; config = mkIf (!config.boot.isContainer) { - environment.etc = singleton + environment.etc = [ + { source = "${pkgs.kmod-blacklist-ubuntu}/modprobe.conf"; + target = "modprobe.d/ubuntu.conf"; + } { source = pkgs.writeText "modprobe.conf" '' ${flip concatMapStrings config.boot.blacklistedKernelModules (name: '' @@ -77,26 +80,11 @@ with pkgs.lib; ${config.boot.extraModprobeConfig} ''; target = "modprobe.d/nixos.conf"; - }; + } + ]; environment.systemPackages = [ config.system.sbin.modprobe pkgs.kmod ]; - boot.blacklistedKernelModules = - [ # This module is for debugging and generates gigantic amounts - # of log output, so it should never be loaded automatically. - "evbug" - - # This module causes ALSA to occassionally select the wrong - # default sound device, and is little more than an annoyance - # on modern machines. - "snd_pcsp" - - # The cirrusfb module prevents X11 from starting. FIXME: - # Ubuntu blacklists all framebuffer devices because they're - # "buggy" and cause suspend problems. Maybe we should too? - "cirrusfb" - ]; - system.activationScripts.modprobe = '' # Allow the kernel to find our wrapped modprobe (which searches diff --git a/nixos/modules/system/boot/pbkdf2-sha512.c b/nixos/modules/system/boot/pbkdf2-sha512.c new file mode 100644 index 000000000000..b40c383ac023 --- /dev/null +++ b/nixos/modules/system/boot/pbkdf2-sha512.c @@ -0,0 +1,38 @@ +#include <stdint.h> +#include <string.h> +#include <stdio.h> +#include <openssl/evp.h> + +void hextorb(uint8_t* hex, uint8_t* rb) +{ + while(sscanf(hex, "%2x", rb) == 1) + { + hex += 2; + rb += 1; + } + *rb = '\0'; +} + +int main(int argc, char** argv) +{ + uint8_t k_user[2048]; + uint8_t salt[2048]; + uint8_t key[4096]; + + uint32_t key_length = atoi(argv[1]); + uint32_t iteration_count = atoi(argv[2]); + + hextorb(argv[3], salt); + uint32_t salt_length = strlen(argv[3]) / 2; + + fgets(k_user, 2048, stdin); + uint32_t k_user_length = strlen(k_user); + if(k_user[k_user_length - 1] == '\n') { + k_user[k_user_length - 1] = '\0'; + } + + PKCS5_PBKDF2_HMAC(k_user, k_user_length, salt, salt_length, iteration_count, EVP_sha512(), key_length, key); + fwrite(key, 1, key_length, stdout); + + return 0; +} \ No newline at end of file diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh index 1f65026b5def..d0f4576f8112 100644 --- a/nixos/modules/system/boot/stage-1-init.sh +++ b/nixos/modules/system/boot/stage-1-init.sh @@ -14,7 +14,7 @@ fail() { # in an interactive shell. cat <<EOF -An error occured in stage 1 of the boot process, which must mount the +An error occurred in stage 1 of the boot process, which must mount the root filesystem on \`$targetRoot' and then start stage 2. Press one of the following keys: @@ -320,6 +320,10 @@ while read -u 3 mountPoint; do echo -n "waiting for device $device to appear..." for try in $(seq 1 20); do sleep 1 + # also re-try lvm activation now that new block devices might have appeared + lvm vgchange -ay + # and tell udev to create nodes for the new LVs + udevadm trigger --action=add if test -e $device; then break; fi echo -n "." done diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh index 2fadd3de1f0f..b749172a3ff3 100644 --- a/nixos/modules/system/boot/stage-2-init.sh +++ b/nixos/modules/system/boot/stage-2-init.sh @@ -131,6 +131,16 @@ if ! mountpoint -q /run; then mount -t tmpfs -o "mode=0755,size=@runSize@" none /run fi +# Create a ramfs on /run/keys to hold secrets that shouldn't +# be written to disk (generally used for nixops, harmless +# elsehwere) +if ! mountpoint -q /run/keys; then + rm -rf /run/keys + mkdir -m 0750 /run/keys + chown root:keys /run/keys + mount -t ramfs none /run/keys +fi + mkdir -m 0755 -p /run/lock diff --git a/nixos/modules/system/boot/systemd-unit-options.nix b/nixos/modules/system/boot/systemd-unit-options.nix index c0518599f17a..113990814efa 100644 --- a/nixos/modules/system/boot/systemd-unit-options.nix +++ b/nixos/modules/system/boot/systemd-unit-options.nix @@ -41,6 +41,12 @@ in rec { ''; }; + baseUnit = mkOption { + type = types.nullOr types.path; + default = null; + description = "Path to an upstream unit file on which the NixOS unit configuration will be based."; + }; + description = mkOption { default = ""; type = types.str; @@ -135,6 +141,7 @@ in rec { restartTriggers = mkOption { default = []; + type = types.listOf types.unspecified; description = '' An arbitrary list of items such as derivations. If any item in the list changes between reconfigurations, the service will diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index aaa496955402..49502b3e6851 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -11,20 +11,18 @@ let systemd = cfg.package; makeUnit = name: unit: - pkgs.runCommand "unit" { preferLocalBuild = true; inherit (unit) text; } - ((if !unit.enable then '' - mkdir -p $out - ln -s /dev/null $out/${name} - '' else if unit.linkTarget != null then '' - mkdir -p $out - ln -s ${unit.linkTarget} $out/${name} - '' else if unit.text != null then '' - mkdir -p $out - echo -n "$text" > $out/${name} - '' else "") + optionalString (unit.extraConfig != {}) '' - mkdir -p $out/${name}.d - ${concatStringsSep "\n" (mapAttrsToList (n: v: "echo -n \"${v}\" > $out/${name}.d/${n}") unit.extraConfig)} - ''); + if unit.enable then + pkgs.runCommand "unit" { preferLocalBuild = true; inherit (unit) text; } + '' + mkdir -p $out + echo -n "$text" > $out/${name} + '' + else + pkgs.runCommand "unit" { preferLocalBuild = true; } + '' + mkdir -p $out + ln -s /dev/null $out/${name} + ''; upstreamUnits = [ # Targets. @@ -156,15 +154,23 @@ let unitConfig = { name, config, ... }: { config = { unitConfig = - { Requires = concatStringsSep " " config.requires; - Wants = concatStringsSep " " config.wants; - After = concatStringsSep " " config.after; - Before = concatStringsSep " " config.before; - BindsTo = concatStringsSep " " config.bindsTo; - PartOf = concatStringsSep " " config.partOf; - Conflicts = concatStringsSep " " config.conflicts; - "X-Restart-Triggers" = toString config.restartTriggers; - } // optionalAttrs (config.description != "") { + optionalAttrs (config.requires != []) + { Requires = toString config.requires; } + // optionalAttrs (config.wants != []) + { Wants = toString config.wants; } + // optionalAttrs (config.after != []) + { After = toString config.after; } + // optionalAttrs (config.before != []) + { Before = toString config.before; } + // optionalAttrs (config.bindsTo != []) + { BindsTo = toString config.bindsTo; } + // optionalAttrs (config.partOf != []) + { PartOf = toString config.partOf; } + // optionalAttrs (config.conflicts != []) + { Conflicts = toString config.conflicts; } + // optionalAttrs (config.restartTriggers != []) + { X-Restart-Triggers = toString config.restartTriggers; } + // optionalAttrs (config.description != "") { Description = config.description; }; }; @@ -172,7 +178,7 @@ let serviceConfig = { name, config, ... }: { config = mkMerge - [ { # Default path for systemd services. Should be quite minimal. + [ (mkIf (config.baseUnit == null) { # Default path for systemd services. Should be quite minimal. path = [ pkgs.coreutils pkgs.findutils @@ -181,7 +187,7 @@ let systemd ]; environment.PATH = config.path; - } + }) (mkIf (config.preStart != "") { serviceConfig.ExecStartPre = makeJobScript "${name}-pre-start" '' #! ${pkgs.stdenv.shell} -e @@ -249,6 +255,14 @@ let (if isList value then value else [value])) as)); + commonUnitText = def: + optionalString (def.baseUnit != null) '' + .include ${def.baseUnit} + '' + '' + [Unit] + ${attrsToSection def.unitConfig} + ''; + targetToUnit = name: def: { inherit (def) wantedBy requiredBy enable; text = @@ -260,11 +274,8 @@ let serviceToUnit = name: def: { inherit (def) wantedBy requiredBy enable; - text = + text = commonUnitText def + '' - [Unit] - ${attrsToSection def.unitConfig} - [Service] ${let env = cfg.globalEnvironment // def.environment; in concatMapStrings (n: "Environment=\"${n}=${getAttr n env}\"\n") (attrNames env)} @@ -276,11 +287,8 @@ let socketToUnit = name: def: { inherit (def) wantedBy requiredBy enable; - text = + text = commonUnitText def + '' - [Unit] - ${attrsToSection def.unitConfig} - [Socket] ${attrsToSection def.socketConfig} ${concatStringsSep "\n" (map (s: "ListenStream=${s}") def.listenStreams)} @@ -289,11 +297,8 @@ let timerToUnit = name: def: { inherit (def) wantedBy requiredBy enable; - text = + text = commonUnitText def + '' - [Unit] - ${attrsToSection def.unitConfig} - [Timer] ${attrsToSection def.timerConfig} ''; @@ -301,11 +306,8 @@ let mountToUnit = name: def: { inherit (def) wantedBy requiredBy enable; - text = + text = commonUnitText def + '' - [Unit] - ${attrsToSection def.unitConfig} - [Mount] ${attrsToSection def.mountConfig} ''; @@ -313,11 +315,8 @@ let automountToUnit = name: def: { inherit (def) wantedBy requiredBy enable; - text = + text = commonUnitText def + '' - [Unit] - ${attrsToSection def.unitConfig} - [Automount] ${attrsToSection def.automountConfig} ''; @@ -432,25 +431,9 @@ in internal = true; description = "The generated unit."; }; - linkTarget = mkOption { - default = null; - description = "The file to symlink this target to."; - type = types.nullOr types.path; - }; - extraConfig = mkOption { - default = {}; - example = { "foo@1.conf" = "X-RestartIfChanged=false"; }; - type = types.attrsOf types.lines; - description = '' - Extra files to be appended to the configuration for the unit. - This can be used to override configuration for a unit provided - by systemd or another package, or to override only a single instance - of a template unit. - ''; - }; }; config = { - unit = makeUnit name config; + unit = mkDefault (makeUnit name config); }; }; }; @@ -662,8 +645,11 @@ in ''; # Target for ‘charon send-keys’ to hook into. + users.extraGroups.keys.gid = config.ids.gids.keys; + systemd.targets.keys = { description = "Security Keys"; + unitConfig.X-StopOnReconfiguration = true; }; systemd.units = diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index 9619f0f5ebe7..548685377a90 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -50,6 +50,26 @@ let ''; }; + ipv6Address = mkOption { + default = null; + example = "2001:1470:fffd:2098::e006"; + type = types.nullOr types.string; + description = '' + IPv6 address of the interface. Leave empty to configure the + interface using NDP. + ''; + }; + + ipv6prefixLength = mkOption { + default = 64; + example = 64; + type = types.int; + description = '' + Subnet mask of the interface, specified as the number of + bits in the prefix (<literal>64</literal>). + ''; + }; + macAddress = mkOption { default = null; example = "00:11:22:33:44:55"; @@ -401,9 +421,11 @@ in EOF # Disable or enable IPv6. - if [ -e /proc/sys/net/ipv6/conf/all/disable_ipv6 ]; then - echo ${if cfg.enableIPv6 then "0" else "1"} > /proc/sys/net/ipv6/conf/all/disable_ipv6 - fi + ${optionalString (!config.boot.isContainer) '' + if [ -e /proc/sys/net/ipv6/conf/all/disable_ipv6 ]; then + echo ${if cfg.enableIPv6 then "0" else "1"} > /proc/sys/net/ipv6/conf/all/disable_ipv6 + fi + ''} # Set the default gateway. ${optionalString (cfg.defaultGateway != "") '' @@ -435,6 +457,7 @@ in (let mask = if i.prefixLength != null then toString i.prefixLength else if i.subnetMask != "" then i.subnetMask else "32"; + staticIPv6 = cfg.enableIPv6 && i.ipv6Address != null; in { description = "Configuration of ${i.name}"; wantedBy = [ "network-interfaces.target" ]; @@ -468,11 +491,31 @@ in echo "configuring interface..." ip -4 addr flush dev "${i.name}" ip -4 addr add "${i.ipAddress}/${mask}" dev "${i.name}" + restart_network_setup=true + else + echo "skipping configuring interface" + fi + '' + + optionalString (staticIPv6) + '' + # Only do a flush/add if it's necessary. This is + # useful when the Nix store is accessed via this + # interface (e.g. in a QEMU VM test). + if ! ip -6 -o a show dev "${i.name}" | grep "${i.ipv6Address}/${toString i.ipv6prefixLength}"; then + echo "configuring interface..." + ip -6 addr flush dev "${i.name}" + ip -6 addr add "${i.ipv6Address}/${toString i.ipv6prefixLength}" dev "${i.name}" + restart_network_setup=true + else + echo "skipping configuring interface" + fi + '' + + optionalString (i.ipAddress != null || staticIPv6) + '' + if [ restart_network_setup = true ]; then # Ensure that the default gateway remains set. # (Flushing this interface may have removed it.) ${config.systemd.package}/bin/systemctl try-restart --no-block network-setup.service - else - echo "skipping configuring interface" fi ${config.systemd.package}/bin/systemctl start ip-up.target '' diff --git a/nixos/modules/virtualisation/amazon-image.nix b/nixos/modules/virtualisation/amazon-image.nix index abd2a1084bd9..99d6f927ef0b 100644 --- a/nixos/modules/virtualisation/amazon-image.nix +++ b/nixos/modules/virtualisation/amazon-image.nix @@ -164,5 +164,5 @@ with pkgs.lib; # Prevent logging in as root without a password. This doesn't really matter, # since the only PAM services that allow logging in with a null # password are local ones that are inaccessible on EC2 machines. - security.initialRootPassword = "!"; + security.initialRootPassword = mkDefault "!"; } diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix index bcbfaacd703f..d87284de4fc1 100644 --- a/nixos/modules/virtualisation/containers.nix +++ b/nixos/modules/virtualisation/containers.nix @@ -55,7 +55,7 @@ with pkgs.lib; modules = let extraConfig = { boot.isContainer = true; - security.initialRootPassword = "!"; + security.initialRootPassword = mkDefault "!"; networking.hostName = mkDefault name; }; in [ extraConfig config.config ]; @@ -134,4 +134,4 @@ with pkgs.lib; }) config.systemd.containers; }; -} \ No newline at end of file +} diff --git a/nixos/modules/virtualisation/google-compute-image.nix b/nixos/modules/virtualisation/google-compute-image.nix index 098c9ede8533..634932ff0077 100644 --- a/nixos/modules/virtualisation/google-compute-image.nix +++ b/nixos/modules/virtualisation/google-compute-image.nix @@ -114,7 +114,7 @@ with pkgs.lib; # Prevent logging in as root without a password. This doesn't really matter, # since the only PAM services that allow logging in with a null # password are local ones that are inaccessible on Google Compute machines. - security.initialRootPassword = "!"; + security.initialRootPassword = mkDefault "!"; # Configure default metadata hostnames networking.extraHosts = '' diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix index 2218e1045eb8..a866b513f0f2 100644 --- a/nixos/modules/virtualisation/qemu-vm.nix +++ b/nixos/modules/virtualisation/qemu-vm.nix @@ -386,8 +386,7 @@ in # When building a regular system configuration, override whatever # video driver the host uses. - services.xserver.videoDriver = mkVMOverride null; - services.xserver.videoDrivers = mkVMOverride [ "vesa" ]; + hardware.opengl.videoDrivers = mkVMOverride [ "vesa" ]; services.xserver.defaultDepth = mkVMOverride 0; services.xserver.resolutions = mkVMOverride [ { x = 1024; y = 768; } ]; services.xserver.monitorSection = diff --git a/nixos/modules/virtualisation/virtualbox-guest.nix b/nixos/modules/virtualisation/virtualbox-guest.nix index 664fd21781cd..e4c00fe4a419 100644 --- a/nixos/modules/virtualisation/virtualbox-guest.nix +++ b/nixos/modules/virtualisation/virtualbox-guest.nix @@ -52,7 +52,7 @@ optionalAttrs (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) # ugly... serviceConfig.ExecStart = "@${kernel.virtualboxGuestAdditions}/sbin/VBoxService VBoxService --foreground"; }; - services.xserver.videoDrivers = mkOverride 50 [ "virtualbox" ]; + hardware.opengl.videoDrivers = mkOverride 50 [ "virtualbox" ]; services.xserver.config = '' diff --git a/nixos/modules/virtualisation/virtualbox-image.nix b/nixos/modules/virtualisation/virtualbox-image.nix index 71bdf31a98d2..06bea2d8acff 100644 --- a/nixos/modules/virtualisation/virtualbox-image.nix +++ b/nixos/modules/virtualisation/virtualbox-image.nix @@ -111,5 +111,5 @@ with pkgs.lib; # Prevent logging in as root without a password. For NixOps, we # don't need this because the user can login via SSH, and for the # demo images, there is a demo user account that can sudo to root. - security.initialRootPassword = "!"; + security.initialRootPassword = mkDefault "!"; } diff --git a/nixos/release-combined.nix b/nixos/release-combined.nix index dccc3acbf464..94bc2f796eb7 100644 --- a/nixos/release-combined.nix +++ b/nixos/release-combined.nix @@ -44,7 +44,7 @@ in rec { (all nixos.iso_graphical) (all nixos.ova) - #(all nixos.tests.efi-installer.simple) + # (all nixos.tests.efi-installer.simple) (all nixos.tests.firefox) (all nixos.tests.firewall) (all nixos.tests.installer.grub1) @@ -61,6 +61,7 @@ in rec { (all nixos.tests.printing) (all nixos.tests.proxy) (all nixos.tests.xfce) + (all nixos.tests.gnome3) nixpkgs.tarball (all nixpkgs.emacs) diff --git a/nixos/release.nix b/nixos/release.nix index ff094cce05fa..b98976c2ccea 100644 --- a/nixos/release.nix +++ b/nixos/release.nix @@ -213,7 +213,8 @@ in rec { with lib; let testsFor = system: - mapAttrsRecursiveCond (x: !x ? test) (n: v: listToAttrs [(nameValuePair system v.test)]) + mapAttrsRecursiveCond (x: !x ? test) + (n: v: listToAttrs [(nameValuePair system (if v.makeCoverageReport or false then v.report else v.test))]) (import ./tests { inherit nixpkgs system; }); in fold recursiveUpdate {} (map testsFor systems); } diff --git a/nixos/tests/common/user-account.nix b/nixos/tests/common/user-account.nix index 8157cf8d263e..0239a3c4d08a 100644 --- a/nixos/tests/common/user-account.nix +++ b/nixos/tests/common/user-account.nix @@ -7,5 +7,6 @@ createHome = true; useDefaultShell = true; password = "foobar"; + uid = 1000; }; } diff --git a/nixos/tests/default.nix b/nixos/tests/default.nix index 574e1dd2f8b8..5b68862a2cd1 100644 --- a/nixos/tests/default.nix +++ b/nixos/tests/default.nix @@ -12,7 +12,9 @@ with import ../lib/testing.nix { inherit system minimal; }; firewall = makeTest (import ./firewall.nix); installer = makeTests (import ./installer.nix); efi-installer = makeTests (import ./efi-installer.nix); + gnome3 = makeTest (import ./gnome3.nix); ipv6 = makeTest (import ./ipv6.nix); + jenkins = makeTest (import ./jenkins.nix); kde4 = makeTest (import ./kde4.nix); #kexec = makeTest (import ./kexec.nix); login = makeTest (import ./login.nix {}); diff --git a/nixos/tests/gnome3.nix b/nixos/tests/gnome3.nix new file mode 100644 index 000000000000..98a76137842e --- /dev/null +++ b/nixos/tests/gnome3.nix @@ -0,0 +1,31 @@ +{ pkgs, ... }: + +{ + + machine = + { config, pkgs, ... }: + + { imports = [ ./common/user-account.nix ]; + + services.xserver.enable = true; + + services.xserver.displayManager.auto.enable = true; + services.xserver.displayManager.auto.user = "alice"; + services.xserver.desktopManager.gnome3.enable = true; + }; + + testScript = + '' + $machine->waitForX; + $machine->sleep(15); + + # Check that logging in has given the user ownership of devices. + $machine->succeed("getfacl /dev/snd/timer | grep -q alice"); + + $machine->succeed("su - alice -c 'DISPLAY=:0.0 gnome-terminal &'"); + $machine->waitForWindow(qr/Terminal/); + $machine->sleep(10); + $machine->screenshot("screen"); + ''; + +} diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix index 7581c10a01d0..b32012ea0347 100644 --- a/nixos/tests/installer.nix +++ b/nixos/tests/installer.nix @@ -238,7 +238,7 @@ in { "mkfs.ext3 -L nixos /dev/vda3", "mount LABEL=nixos /mnt", "mkfs.ext3 -L boot /dev/vda1", - "mkdir /mnt/boot", + "mkdir -p /mnt/boot", "mount LABEL=boot /mnt/boot", ); ''; @@ -252,9 +252,9 @@ in { '' $machine->succeed( "parted /dev/vda mklabel msdos", - "parted /dev/vda -- mkpart primary 1M 2048M", # first PV + "parted /dev/vda -- mkpart primary 1M 2048M", # PV1 "parted /dev/vda -- set 1 lvm on", - "parted /dev/vda -- mkpart primary 2048M -1s", # second PV + "parted /dev/vda -- mkpart primary 2048M -1s", # PV2 "parted /dev/vda -- set 2 lvm on", "udevadm settle", "pvcreate /dev/vda1 /dev/vda2", diff --git a/nixos/tests/jenkins.nix b/nixos/tests/jenkins.nix new file mode 100644 index 000000000000..e6524ec56538 --- /dev/null +++ b/nixos/tests/jenkins.nix @@ -0,0 +1,35 @@ +# verifies: +# 1. jenkins service starts on master node +# 2. jenkins user can be extended on both master and slave +# 3. jenkins service not started on slave node +{ pkgs, ... }: +{ + nodes = { + master = { pkgs, config, ... }: { + services.jenkins.enable = true; + + # should have no effect + services.jenkinsSlave.enable = true; + + users.extraUsers.jenkins.extraGroups = [ "users" ]; + }; + slave = { pkgs, config, ... }: { + services.jenkinsSlave.enable = true; + + users.extraUsers.jenkins.extraGroups = [ "users" ]; + }; + }; + + testScript = '' + startAll; + + $master->waitForUnit("jenkins"); + print $master->execute("sudo -u jenkins groups"); + $master->mustSucceed("sudo -u jenkins groups | grep jenkins | grep users"); + + print $slave->execute("sudo -u jenkins groups"); + $slave->mustSucceed("sudo -u jenkins groups | grep jenkins | grep users"); + + $slave->mustFail("systemctl status jenkins.service"); + ''; +} diff --git a/nixos/tests/mysql-replication.nix b/nixos/tests/mysql-replication.nix index 28a1187dd184..f8c82f7ce9c8 100644 --- a/nixos/tests/mysql-replication.nix +++ b/nixos/tests/mysql-replication.nix @@ -11,11 +11,12 @@ in { services.mysql.enable = true; - services.mysql.replication.role = "master"; - services.mysql.initialDatabases = [ { name = "testdb"; schema = ./testdb.sql; } ]; - services.mysql.initialScript = pkgs.writeText "initmysql" + services.mysql.package = pkgs.mysql; + services.mysql.replication.role = "master"; + services.mysql.initialDatabases = [ { name = "testdb"; schema = ./testdb.sql; } ]; + services.mysql.initialScript = pkgs.writeText "initmysql" '' - create user '${replicateUser}'@'%' identified by '${replicatePassword}'; + create user '${replicateUser}'@'%' identified by '${replicatePassword}'; grant replication slave on *.* to '${replicateUser}'@'%'; ''; }; @@ -25,11 +26,12 @@ in { services.mysql.enable = true; - services.mysql.replication.role = "slave"; - services.mysql.replication.serverId = 2; - services.mysql.replication.masterHost = nodes.master.config.networking.hostName; - services.mysql.replication.masterUser = replicateUser; - services.mysql.replication.masterPassword = replicatePassword; + services.mysql.package = pkgs.mysql; + services.mysql.replication.role = "slave"; + services.mysql.replication.serverId = 2; + services.mysql.replication.masterHost = nodes.master.config.networking.hostName; + services.mysql.replication.masterUser = replicateUser; + services.mysql.replication.masterPassword = replicatePassword; }; slave2 = @@ -37,11 +39,12 @@ in { services.mysql.enable = true; - services.mysql.replication.role = "slave"; - services.mysql.replication.serverId = 3; - services.mysql.replication.masterHost = nodes.master.config.networking.hostName; - services.mysql.replication.masterUser = replicateUser; - services.mysql.replication.masterPassword = replicatePassword; + services.mysql.package = pkgs.mysql; + services.mysql.replication.role = "slave"; + services.mysql.replication.serverId = 3; + services.mysql.replication.masterHost = nodes.master.config.networking.hostName; + services.mysql.replication.masterUser = replicateUser; + services.mysql.replication.masterPassword = replicatePassword; }; }; diff --git a/nixos/tests/mysql.nix b/nixos/tests/mysql.nix index b48850738b72..bceeb8beabc2 100644 --- a/nixos/tests/mysql.nix +++ b/nixos/tests/mysql.nix @@ -7,8 +7,9 @@ { services.mysql.enable = true; - services.mysql.replication.role = "master"; - services.mysql.initialDatabases = [ { name = "testdb"; schema = ./testdb.sql; } ]; + services.mysql.replication.role = "master"; + services.mysql.initialDatabases = [ { name = "testdb"; schema = ./testdb.sql; } ]; + services.mysql.package = pkgs.mysql; }; }; diff --git a/nixos/tests/quake3.nix b/nixos/tests/quake3.nix index 925011077805..fefbd75b4a3c 100644 --- a/nixos/tests/quake3.nix +++ b/nixos/tests/quake3.nix @@ -14,11 +14,13 @@ in rec { + makeCoverageReport = true; + client = { config, pkgs, ... }: { imports = [ ./common/x11.nix ]; - services.xserver.driSupport = true; + hardware.opengl.driSupport = true; services.xserver.defaultDepth = pkgs.lib.mkOverride 0 16; environment.systemPackages = [ pkgs.quake3demo ]; nixpkgs.config.packageOverrides = overrides; diff --git a/nixos/tests/subversion.nix b/nixos/tests/subversion.nix index 309da90c5df1..49450c78f3b8 100644 --- a/nixos/tests/subversion.nix +++ b/nixos/tests/subversion.nix @@ -20,7 +20,7 @@ let # To build the kernel with coverage instrumentation, we need a # special patch to make coverage data available under /proc. linux = pkgs.linux.override (orig: { - stdenv = cleanupBuildTree (keepBuildTree orig.stdenv); + stdenv = overrideInStdenv pkgs.stdenv [ pkgs.keepBuildTree ]; extraConfig = '' GCOV_KERNEL y |