diff options
Diffstat (limited to 'nixos')
-rw-r--r-- | nixos/doc/manual/configuration/configuration.xml | 1 | ||||
-rw-r--r-- | nixos/doc/manual/default.nix | 1 | ||||
-rw-r--r-- | nixos/doc/manual/release-notes/rl-unstable.xml | 8 | ||||
-rw-r--r-- | nixos/modules/module-list.nix | 1 | ||||
-rw-r--r-- | nixos/modules/rename.nix | 3 | ||||
-rw-r--r-- | nixos/modules/security/acme.nix | 2 | ||||
-rw-r--r-- | nixos/modules/security/oath.nix | 50 | ||||
-rw-r--r-- | nixos/modules/security/pam.nix | 17 | ||||
-rw-r--r-- | nixos/modules/services/hardware/sane.nix | 17 | ||||
-rw-r--r-- | nixos/modules/services/misc/defaultUnicornConfig.rb | 1 | ||||
-rw-r--r-- | nixos/modules/services/misc/gitlab.nix | 390 | ||||
-rw-r--r-- | nixos/modules/services/misc/gitlab.xml | 103 | ||||
-rw-r--r-- | nixos/modules/services/misc/nix-daemon.nix | 2 | ||||
-rw-r--r-- | nixos/modules/services/network-filesystems/samba.nix | 20 | ||||
-rw-r--r-- | nixos/modules/services/printing/cupsd.nix | 2 | ||||
-rw-r--r-- | nixos/modules/system/activation/switch-to-configuration.pl | 14 | ||||
-rw-r--r-- | nixos/modules/virtualisation/ec2-data.nix | 24 | ||||
-rw-r--r-- | nixos/tests/printing.nix | 5 |
18 files changed, 495 insertions, 166 deletions
diff --git a/nixos/doc/manual/configuration/configuration.xml b/nixos/doc/manual/configuration/configuration.xml index 1e488b59343e..ff00c4feb31a 100644 --- a/nixos/doc/manual/configuration/configuration.xml +++ b/nixos/doc/manual/configuration/configuration.xml @@ -26,6 +26,7 @@ effect after you run <command>nixos-rebuild</command>.</para> <!-- FIXME: auto-include NixOS module docs --> <xi:include href="postgresql.xml" /> +<xi:include href="gitlab.xml" /> <xi:include href="acme.xml" /> <xi:include href="nixos.xml" /> diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix index b4eb3cde81bf..4eda7f94ab4a 100644 --- a/nixos/doc/manual/default.nix +++ b/nixos/doc/manual/default.nix @@ -56,6 +56,7 @@ let cp -prd $sources/* . # */ chmod -R u+w . cp ${../../modules/services/databases/postgresql.xml} configuration/postgresql.xml + cp ${../../modules/services/misc/gitlab.xml} configuration/gitlab.xml cp ${../../modules/security/acme.xml} configuration/acme.xml cp ${../../modules/misc/nixos.xml} configuration/nixos.xml ln -s ${optionsDocBook} options-db.xml diff --git a/nixos/doc/manual/release-notes/rl-unstable.xml b/nixos/doc/manual/release-notes/rl-unstable.xml index 22e605718e33..5bad7f63b61e 100644 --- a/nixos/doc/manual/release-notes/rl-unstable.xml +++ b/nixos/doc/manual/release-notes/rl-unstable.xml @@ -231,6 +231,14 @@ programs.ibus.plugins = with pkgs; [ ibus-anthy mozc ]; overriden by anything else.</para> </listitem> + <listitem> + <para>Large parts of the <literal>services.gitlab</literal> module has been + been rewritten. There are new configuration options available. The + <literal>stateDir</literal> option was renamned to + <literal>statePath</literal> and the <literal>satellitesDir</literal> option + was removed. Please review the currently available options.</para> + </listitem> + </itemizedlist> diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index c2bcc361c447..f41e17189a42 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -93,6 +93,7 @@ ./security/ca.nix ./security/duosec.nix ./security/grsecurity.nix + ./security/oath.nix ./security/pam.nix ./security/pam_usb.nix ./security/pam_mount.nix diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 6d5ee6fc84e9..85435884b199 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -28,6 +28,9 @@ with lib; (mkRenamedOptionModule [ "services" "subsonic" "host" ] [ "services" "subsonic" "listenAddress" ]) (mkRenamedOptionModule [ "jobs" ] [ "systemd" "services" ]) + (mkRenamedOptionModule [ "services" "gitlab" "stateDir" ] [ "services" "gitlab" "statePath" ]) + (mkRemovedOptionModule [ "services" "gitlab" "satelliteDir" ]) + # Old Grub-related options. (mkRenamedOptionModule [ "boot" "initrd" "extraKernelModules" ] [ "boot" "initrd" "kernelModules" ]) (mkRenamedOptionModule [ "boot" "extraKernelParams" ] [ "boot" "kernelParams" ]) diff --git a/nixos/modules/security/acme.nix b/nixos/modules/security/acme.nix index 3d25e811e670..c5cd0fb60ee9 100644 --- a/nixos/modules/security/acme.nix +++ b/nixos/modules/security/acme.nix @@ -56,7 +56,7 @@ let plugins = mkOption { type = types.listOf (types.enum [ - "cert.der" "cert.pem" "chain.pem" "external_pem.sh" + "cert.der" "cert.pem" "chain.pem" "external.sh" "fullchain.pem" "full.pem" "key.der" "key.pem" "account_key.json" ]); default = [ "fullchain.pem" "key.pem" "account_key.json" ]; diff --git a/nixos/modules/security/oath.nix b/nixos/modules/security/oath.nix new file mode 100644 index 000000000000..20f3e2dd9f83 --- /dev/null +++ b/nixos/modules/security/oath.nix @@ -0,0 +1,50 @@ +# This module provides configuration for the OATH PAM modules. + +{ config, lib, pkgs, ... }: + +with lib; + +{ + options = { + + security.pam.oath = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Enable the OATH (one-time password) PAM module. + ''; + }; + + digits = mkOption { + type = types.enum [ 6 7 8 ]; + default = 6; + description = '' + Specify the length of the one-time password in number of + digits. + ''; + }; + + window = mkOption { + type = types.int; + default = 5; + description = '' + Specify the number of one-time passwords to check in order + to accommodate for situations where the system and the + client are slightly out of sync (iteration for HOTP or time + steps for TOTP). + ''; + }; + + usersFile = mkOption { + type = types.path; + default = "/etc/users.oath"; + description = '' + Set the path to file where the user's credentials are + stored. This file must not be world readable! + ''; + }; + }; + + }; +} diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index 2ee8a803d2fe..021c561af759 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -75,7 +75,7 @@ let }; oathAuth = mkOption { - default = config.security.pam.enableOATH; + default = config.security.pam.oath.enable; type = types.bool; description = '' If set, the OATH Toolkit will be used. @@ -259,8 +259,8 @@ let "auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} likeauth try_first_pass"} ${optionalString cfg.otpwAuth "auth sufficient ${pkgs.otpw}/lib/security/pam_otpw.so"} - ${optionalString cfg.oathAuth - "auth sufficient ${pkgs.oathToolkit}/lib/security/pam_oath.so window=5 usersfile=/etc/users.oath"} + ${let oath = config.security.pam.oath; in optionalString cfg.oathAuth + "auth sufficient ${pkgs.oathToolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits}"} ${optionalString config.users.ldap.enable "auth sufficient ${pam_ldap}/lib/security/pam_ldap.so use_first_pass"} ${optionalString config.krb5.enable '' @@ -302,8 +302,6 @@ let "session optional ${pam_krb5}/lib/security/pam_krb5.so"} ${optionalString cfg.otpwAuth "session optional ${pkgs.otpw}/lib/security/pam_otpw.so"} - ${optionalString cfg.oathAuth - "session optional ${pkgs.oathToolkit}/lib/security/pam_oath.so window=5 usersfile=/etc/users.oath"} ${optionalString cfg.startSession "session optional ${pkgs.systemd}/lib/security/pam_systemd.so"} ${optionalString cfg.forwardXAuth @@ -405,13 +403,6 @@ in ''; }; - security.pam.enableOATH = mkOption { - default = false; - description = '' - Enable the OATH (one-time password) PAM module. - ''; - }; - security.pam.enableU2F = mkOption { default = false; description = '' @@ -446,7 +437,7 @@ in ++ optional config.users.ldap.enable pam_ldap ++ optionals config.krb5.enable [pam_krb5 pam_ccreds] ++ optionals config.security.pam.enableOTPW [ pkgs.otpw ] - ++ optionals config.security.pam.enableOATH [ pkgs.oathToolkit ] + ++ optionals config.security.pam.oath.enable [ pkgs.oathToolkit ] ++ optionals config.security.pam.enableU2F [ pkgs.pam_u2f ] ++ optionals config.security.pam.enableEcryptfs [ pkgs.ecryptfs ]; diff --git a/nixos/modules/services/hardware/sane.nix b/nixos/modules/services/hardware/sane.nix index 56504cd2361d..a34037403123 100644 --- a/nixos/modules/services/hardware/sane.nix +++ b/nixos/modules/services/hardware/sane.nix @@ -21,7 +21,13 @@ in hardware.sane.enable = mkOption { type = types.bool; default = false; - description = "Enable support for SANE scanners."; + description = '' + Enable support for SANE scanners. + + <note><para> + Users in the "scanner" group will gain access to the scanner. + </para></note> + ''; }; hardware.sane.snapshot = mkOption { @@ -33,7 +39,14 @@ in hardware.sane.extraBackends = mkOption { type = types.listOf types.path; default = []; - description = "Packages providing extra SANE backends to enable."; + description = '' + Packages providing extra SANE backends to enable. + + <note><para> + The example contains the package for HP scanners. + </para></note> + ''; + example = literalExample "[ pkgs.hplipWithPlugin ]"; }; hardware.sane.configDir = mkOption { diff --git a/nixos/modules/services/misc/defaultUnicornConfig.rb b/nixos/modules/services/misc/defaultUnicornConfig.rb index 81abaf336dc0..84622622db70 100644 --- a/nixos/modules/services/misc/defaultUnicornConfig.rb +++ b/nixos/modules/services/misc/defaultUnicornConfig.rb @@ -187,7 +187,6 @@ working_directory ENV["GITLAB_PATH"] pid ENV["UNICORN_PATH"] + "/tmp/pids/unicorn.pid" listen ENV["UNICORN_PATH"] + "/tmp/sockets/gitlab.socket", :backlog => 1024 -listen "127.0.0.1:8080", :tcp_nopush => true timeout 60 diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix index 949357ab20f4..cc50bfbea531 100644 --- a/nixos/modules/services/misc/gitlab.nix +++ b/nixos/modules/services/misc/gitlab.nix @@ -7,10 +7,13 @@ with lib; let cfg = config.services.gitlab; - ruby = pkgs.gitlab.ruby; + ruby = cfg.packages.gitlab.ruby; bundler = pkgs.bundler; - gemHome = "${pkgs.gitlab.env}/${ruby.gemPath}"; + gemHome = "${cfg.packages.gitlab.env}/${ruby.gemPath}"; + + gitlabSocket = "${cfg.statePath}/tmp/sockets/gitlab.socket"; + pathUrlQuote = url: replaceStrings ["/"] ["%2F"] url; databaseYml = '' production: @@ -21,14 +24,15 @@ let username: ${cfg.databaseUsername} encoding: utf8 ''; + gitlabShellYml = '' - user: gitlab - gitlab_url: "http://${cfg.host}:${toString cfg.port}/" + user: ${cfg.user} + gitlab_url: "http+unix://${pathUrlQuote gitlabSocket}" http_settings: self_signed_cert: false - repos_path: "${cfg.stateDir}/repositories" - secret_file: "${cfg.stateDir}/config/gitlab_shell_secret" - log_file: "${cfg.stateDir}/log/gitlab-shell.log" + repos_path: "${cfg.statePath}/repositories" + secret_file: "${cfg.statePath}/config/gitlab_shell_secret" + log_file: "${cfg.statePath}/log/gitlab-shell.log" redis: bin: ${pkgs.redis}/bin/redis-cli host: 127.0.0.1 @@ -37,33 +41,102 @@ let namespace: resque:gitlab ''; + gitlabConfig = { + # These are the default settings from config/gitlab.example.yml + production = flip recursiveUpdate cfg.extraConfig { + gitlab = { + host = cfg.host; + port = cfg.port; + https = cfg.https; + user = cfg.user; + email_enabled = true; + email_display_name = "GitLab"; + email_reply_to = "noreply@localhost"; + default_theme = 2; + default_projects_features = { + issues = true; + merge_requests = true; + wiki = true; + snippets = false; + builds = true; + }; + }; + artifacts = { + enabled = true; + }; + lfs = { + enabled = true; + }; + gravatar = { + enabled = true; + }; + cron_jobs = { + stuck_ci_builds_worker = { + cron = "0 0 * * *"; + }; + }; + gitlab_ci = { + builds_path = "${cfg.statePath}/builds"; + }; + ldap = { + enabled = false; + }; + omniauth = { + enabled = false; + }; + shared = { + path = "${cfg.statePath}/shared"; + }; + backup = { + path = "${cfg.backupPath}"; + }; + gitlab_shell = { + path = "${cfg.packages.gitlab-shell}"; + repos_path = "${cfg.statePath}/repositories"; + hooks_path = "${cfg.statePath}/shell/hooks"; + secret_file = "${cfg.statePath}/config/gitlab_shell_secret"; + upload_pack = true; + receive_pack = true; + }; + git = { + bin_path = "git"; + max_size = 20971520; # 20MB + timeout = 10; + }; + extra = {}; + }; + }; + + gitlabEnv = { + HOME = "${cfg.statePath}/home"; + GEM_HOME = gemHome; + BUNDLE_GEMFILE = "${cfg.packages.gitlab}/share/gitlab/Gemfile"; + UNICORN_PATH = "${cfg.statePath}/"; + GITLAB_PATH = "${cfg.packages.gitlab}/share/gitlab/"; + GITLAB_STATE_PATH = "${cfg.statePath}"; + GITLAB_UPLOADS_PATH = "${cfg.statePath}/uploads"; + GITLAB_LOG_PATH = "${cfg.statePath}/log"; + GITLAB_SHELL_PATH = "${cfg.packages.gitlab-shell}"; + GITLAB_SHELL_CONFIG_PATH = "${cfg.statePath}/shell/config.yml"; + GITLAB_SHELL_SECRET_PATH = "${cfg.statePath}/config/gitlab_shell_secret"; + GITLAB_SHELL_HOOKS_PATH = "${cfg.statePath}/shell/hooks"; + RAILS_ENV = "production"; + }; + unicornConfig = builtins.readFile ./defaultUnicornConfig.rb; gitlab-runner = pkgs.stdenv.mkDerivation rec { name = "gitlab-runner"; - buildInputs = [ pkgs.gitlab pkgs.bundler pkgs.makeWrapper ]; + buildInputs = [ cfg.packages.gitlab bundler pkgs.makeWrapper ]; phases = "installPhase fixupPhase"; buildPhase = ""; installPhase = '' mkdir -p $out/bin - makeWrapper ${bundler}/bin/bundle $out/bin/gitlab-runner\ - --set RAKEOPT '"-f ${pkgs.gitlab}/share/gitlab/Rakefile"'\ - --set GEM_HOME '${gemHome}'\ - --set UNICORN_PATH "${cfg.stateDir}/"\ - --set GITLAB_PATH "${pkgs.gitlab}/share/gitlab/"\ - --set GITLAB_APPLICATION_LOG_PATH "${cfg.stateDir}/log/application.log"\ - --set GITLAB_SATELLITES_PATH "${cfg.stateDir}/satellites"\ - --set GITLAB_SHELL_PATH "${pkgs.gitlab-shell}"\ - --set GITLAB_REPOSITORIES_PATH "${cfg.stateDir}/repositories"\ - --set GITLAB_SHELL_HOOKS_PATH "${cfg.stateDir}/shell/hooks"\ - --set BUNDLE_GEMFILE "${pkgs.gitlab}/share/gitlab/Gemfile"\ - --set GITLAB_EMAIL_FROM "${cfg.emailFrom}"\ - --set GITLAB_SHELL_CONFIG_PATH "${cfg.stateDir}/shell/config.yml"\ - --set GITLAB_SHELL_SECRET_PATH "${cfg.stateDir}/config/gitlab_shell_secret"\ - --set GITLAB_HOST "${cfg.host}"\ - --set GITLAB_PORT "${toString cfg.port}"\ - --set GITLAB_BACKUP_PATH "${cfg.backupPath}"\ - --set RAILS_ENV "production" + makeWrapper ${bundler}/bin/bundle $out/bin/gitlab-runner \ + ${concatStrings (mapAttrsToList (name: value: "--set ${name} '\"${value}\"' ") gitlabEnv)} \ + --set GITLAB_CONFIG_PATH '"${cfg.statePath}/config"' \ + --set PATH '"${pkgs.nodejs}/bin:${pkgs.gzip}/bin:${config.services.postgresql.package}/bin:$PATH"' \ + --set RAKEOPT '"-f ${cfg.packages.gitlab}/share/gitlab/Rakefile"' ''; }; @@ -79,13 +152,25 @@ in { ''; }; - satelliteDir = mkOption { - type = types.str; - default = "/var/gitlab/git-satellites"; - description = "Gitlab directory to store checked out git trees requires for operation."; + packages.gitlab = mkOption { + type = types.package; + default = pkgs.gitlab; + description = "Reference to the gitlab package"; + }; + + packages.gitlab-shell = mkOption { + type = types.package; + default = pkgs.gitlab-shell; + description = "Reference to the gitlab-shell package"; + }; + + packages.gitlab-workhorse = mkOption { + type = types.package; + default = pkgs.gitlab-workhorse; + description = "Reference to the gitlab-workhorse package"; }; - stateDir = mkOption { + statePath = mkOption { type = types.str; default = "/var/gitlab/state"; description = "Gitlab state directory, logs are stored here."; @@ -93,7 +178,7 @@ in { backupPath = mkOption { type = types.str; - default = cfg.stateDir + "/backup"; + default = cfg.statePath + "/backup"; description = "Gitlab path for backups."; }; @@ -136,14 +221,67 @@ in { port = mkOption { type = types.int; default = 8080; - description = "Gitlab server listening port."; + description = '' + Gitlab server port for copy-paste URLs, e.g. 80 or 443 if you're + service over https. + ''; + }; + + https = mkOption { + type = types.bool; + default = false; + description = "Whether gitlab prints URLs with https as scheme."; + }; + + user = mkOption { + type = types.str; + default = "gitlab"; + description = "User to run gitlab and all related services."; + }; + + group = mkOption { + type = types.str; + default = "gitlab"; + description = "Group to run gitlab and all related services."; + }; + + initialRootEmail = mkOption { + type = types.str; + default = "admin@local.host"; + description = '' + Initial email address of the root account if this is a new install. + ''; + }; + + initialRootPassword = mkOption { + type = types.str; + default = "UseNixOS!"; + description = '' + Initial password of the root account if this is a new install. + ''; + }; + + extraConfig = mkOption { + type = types.attrs; + default = {}; + example = { + gitlab = { + default_projects_features = { + builds = false; + }; + }; + }; + description = '' + Extra options to be merged into config/gitlab.yml as nix + attribute set. + ''; }; }; }; config = mkIf cfg.enable { - environment.systemPackages = [ pkgs.git gitlab-runner pkgs.gitlab-shell ]; + environment.systemPackages = [ pkgs.git gitlab-runner cfg.packages.gitlab-shell ]; assertions = [ { assertion = cfg.databasePassword != ""; @@ -159,39 +297,24 @@ in { services.postfix.enable = mkDefault true; users.extraUsers = [ - { name = "gitlab"; - group = "gitlab"; - home = "${cfg.stateDir}/home"; + { name = cfg.user; + group = cfg.group; + home = "${cfg.statePath}/home"; shell = "${pkgs.bash}/bin/bash"; uid = config.ids.uids.gitlab; - } ]; + } + ]; users.extraGroups = [ - { name = "gitlab"; + { name = cfg.group; gid = config.ids.gids.gitlab; - } ]; + } + ]; systemd.services.gitlab-sidekiq = { after = [ "network.target" "redis.service" ]; wantedBy = [ "multi-user.target" ]; - environment.HOME = "${cfg.stateDir}/home"; - environment.GEM_HOME = gemHome; - environment.UNICORN_PATH = "${cfg.stateDir}/"; - environment.GITLAB_PATH = "${pkgs.gitlab}/share/gitlab/"; - environment.GITLAB_APPLICATION_LOG_PATH = "${cfg.stateDir}/log/application.log"; - environment.GITLAB_SATELLITES_PATH = "${cfg.stateDir}/satellites"; - environment.GITLAB_SHELL_PATH = "${pkgs.gitlab-shell}"; - environment.GITLAB_REPOSITORIES_PATH = "${cfg.stateDir}/repositories"; - environment.GITLAB_SHELL_HOOKS_PATH = "${cfg.stateDir}/shell/hooks"; - environment.BUNDLE_GEMFILE = "${pkgs.gitlab}/share/gitlab/Gemfile"; - environment.GITLAB_EMAIL_FROM = "${cfg.emailFrom}"; - environment.GITLAB_SHELL_CONFIG_PATH = "${cfg.stateDir}/shell/config.yml"; - environment.GITLAB_SHELL_SECRET_PATH = "${cfg.stateDir}/config/gitlab_shell_secret"; - environment.GITLAB_HOST = "${cfg.host}"; - environment.GITLAB_PORT = "${toString cfg.port}"; - environment.GITLAB_DATABASE_HOST = "${cfg.databaseHost}"; - environment.GITLAB_DATABASE_PASSWORD = "${cfg.databasePassword}"; - environment.RAILS_ENV = "production"; + environment = gitlabEnv; path = with pkgs; [ config.services.postgresql.package gitAndTools.git @@ -201,116 +324,131 @@ in { ]; serviceConfig = { Type = "simple"; - User = "gitlab"; - Group = "gitlab"; + User = cfg.user; + Group = cfg.group; TimeoutSec = "300"; - WorkingDirectory = "${pkgs.gitlab}/share/gitlab"; - ExecStart="${bundler}/bin/bundle exec \"sidekiq -q post_receive -q mailer -q system_hook -q project_web_hook -q gitlab_shell -q common -q default -e production -P ${cfg.stateDir}/tmp/sidekiq.pid\""; + WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab"; + ExecStart="${bundler}/bin/bundle exec \"sidekiq -q post_receive -q mailer -q system_hook -q project_web_hook -q gitlab_shell -q common -q default -e production -P ${cfg.statePath}/tmp/sidekiq.pid\""; }; }; - systemd.services.gitlab-git-http-server = { + systemd.services.gitlab-workhorse = { after = [ "network.target" "gitlab.service" ]; wantedBy = [ "multi-user.target" ]; - environment.HOME = "${cfg.stateDir}/home"; + environment.HOME = gitlabEnv.HOME; + environment.GITLAB_SHELL_CONFIG_PATH = gitlabEnv.GITLAB_SHELL_CONFIG_PATH; path = with pkgs; [ gitAndTools.git openssh ]; + preStart = '' + mkdir -p /run/gitlab + chown ${cfg.user}:${cfg.group} /run/gitlab + ''; serviceConfig = { + PermissionsStartOnly = true; # preStart must be run as root Type = "simple"; - User = "gitlab"; - Group = "gitlab"; + User = cfg.user; + Group = cfg.group; TimeoutSec = "300"; - ExecStart = "${pkgs.gitlab-git-http-server}/bin/gitlab-git-http-server -listenUmask 0 -listenNetwork unix -listenAddr ${cfg.stateDir}/tmp/sockets/gitlab-git-http-server.socket -authBackend http://localhost:8080 ${cfg.stateDir}/repositories"; + ExecStart = + "${cfg.packages.gitlab-workhorse}/bin/gitlab-workhorse " + + "-listenUmask 0 " + + "-listenNetwork unix " + + "-listenAddr /run/gitlab/gitlab-workhorse.socket " + + "-authSocket ${gitlabSocket} " + + "-documentRoot ${cfg.packages.gitlab}/share/gitlab/public"; }; }; systemd.services.gitlab = { after = [ "network.target" "postgresql.service" "redis.service" ]; wantedBy = [ "multi-user.target" ]; - environment.HOME = "${cfg.stateDir}/home"; - environment.GEM_HOME = gemHome; - environment.UNICORN_PATH = "${cfg.stateDir}/"; - environment.GITLAB_PATH = "${pkgs.gitlab}/share/gitlab/"; - environment.GITLAB_APPLICATION_LOG_PATH = "${cfg.stateDir}/log/application.log"; - environment.GITLAB_SATELLITES_PATH = "${cfg.stateDir}/satellites"; - environment.GITLAB_SHELL_PATH = "${pkgs.gitlab-shell}"; - environment.GITLAB_SHELL_CONFIG_PATH = "${cfg.stateDir}/shell/config.yml"; - environment.GITLAB_SHELL_SECRET_PATH = "${cfg.stateDir}/config/gitlab_shell_secret"; - environment.GITLAB_REPOSITORIES_PATH = "${cfg.stateDir}/repositories"; - environment.GITLAB_SHELL_HOOKS_PATH = "${cfg.stateDir}/shell/hooks"; - environment.BUNDLE_GEMFILE = "${pkgs.gitlab}/share/gitlab/Gemfile"; - environment.GITLAB_EMAIL_FROM = "${cfg.emailFrom}"; - environment.GITLAB_HOST = "${cfg.host}"; - environment.GITLAB_PORT = "${toString cfg.port}"; - environment.GITLAB_DATABASE_HOST = "${cfg.databaseHost}"; - environment.GITLAB_DATABASE_PASSWORD = "${cfg.databasePassword}"; - environment.RAILS_ENV = "production"; + environment = gitlabEnv; path = with pkgs; [ config.services.postgresql.package gitAndTools.git - ruby openssh nodejs ]; preStart = '' - # TODO: use env vars - mkdir -p ${cfg.stateDir} - mkdir -p ${cfg.stateDir}/log - mkdir -p ${cfg.stateDir}/satellites - mkdir -p ${cfg.stateDir}/repositories - mkdir -p ${cfg.stateDir}/shell/hooks - mkdir -p ${cfg.stateDir}/tmp/pids - mkdir -p ${cfg.stateDir}/tmp/sockets - rm -rf ${cfg.stateDir}/config - mkdir -p ${cfg.stateDir}/config - # TODO: What exactly is gitlab-shell doing with the secret? - tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 20 > ${cfg.stateDir}/config/gitlab_shell_secret - mkdir -p ${cfg.stateDir}/home/.ssh - touch ${cfg.stateDir}/home/.ssh/authorized_keys - - cp -rf ${pkgs.gitlab}/share/gitlab/config ${cfg.stateDir}/ - cp ${pkgs.gitlab}/share/gitlab/VERSION ${cfg.stateDir}/VERSION + mkdir -p ${cfg.backupPath} + mkdir -p ${cfg.statePath}/builds + mkdir -p ${cfg.statePath}/repositories + mkdir -p ${gitlabConfig.production.shared.path}/artifacts + mkdir -p ${gitlabConfig.production.shared.path}/lfs-objects + mkdir -p ${cfg.statePath}/log + mkdir -p ${cfg.statePath}/shell + mkdir -p ${cfg.statePath}/tmp/pids + mkdir -p ${cfg.statePath}/tmp/sockets + + rm -rf ${cfg.statePath}/config ${cfg.statePath}/shell/hooks + mkdir -p ${cfg.statePath}/config ${cfg.statePath}/shell - ln -fs ${pkgs.writeText "database.yml" databaseYml} ${cfg.stateDir}/config/database.yml - ln -fs ${pkgs.writeText "unicorn.rb" unicornConfig} ${cfg.stateDir}/config/unicorn.rb - - chown -R gitlab:gitlab ${cfg.stateDir}/ - chmod -R 755 ${cfg.stateDir}/ + # TODO: What exactly is gitlab-shell doing with the secret? + tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 20 > ${cfg.statePath}/config/gitlab_shell_secret + + # The uploads directory is hardcoded somewhere deep in rails. It is + # symlinked in the gitlab package to /run/gitlab/uploads to make it + # configurable + mkdir -p /run/gitlab + mkdir -p ${cfg.statePath}/uploads + ln -sf ${cfg.statePath}/uploads /run/gitlab/uploads + chown -R ${cfg.user}:${cfg.group} /run/gitlab + + # Prepare home directory + mkdir -p ${gitlabEnv.HOME}/.ssh + touch ${gitlabEnv.HOME}/.ssh/authorized_keys + chown -R ${cfg.user}:${cfg.group} ${gitlabEnv.HOME}/ + chmod -R u+rwX,go-rwx+X ${gitlabEnv.HOME}/ + + cp -rf ${cfg.packages.gitlab}/share/gitlab/config.dist/* ${cfg.statePath}/config + ln -sf ${cfg.statePath}/config /run/gitlab/config + cp ${cfg.packages.gitlab}/share/gitlab/VERSION ${cfg.statePath}/VERSION + + # JSON is a subset of YAML + ln -fs ${pkgs.writeText "gitlab.yml" (builtins.toJSON gitlabConfig)} ${cfg.statePath}/config/gitlab.yml + ln -fs ${pkgs.writeText "database.yml" databaseYml} ${cfg.statePath}/config/database.yml + ln -fs ${pkgs.writeText "unicorn.rb" unicornConfig} ${cfg.statePath}/config/unicorn.rb + + chown -R ${cfg.user}:${cfg.group} ${cfg.statePath}/ + chmod -R ug+rwX,o-rwx+X ${cfg.statePath}/ + + # Install the shell required to push repositories + ln -fs ${pkgs.writeText "config.yml" gitlabShellYml} "$GITLAB_SHELL_CONFIG_PATH" + ln -fs ${cfg.packages.gitlab-shell}/hooks "$GITLAB_SHELL_HOOKS_PATH" + ${cfg.packages.gitlab-shell}/bin/install if [ "${cfg.databaseHost}" = "127.0.0.1" ]; then - if ! test -e "${cfg.stateDir}/db-created"; then + if ! test -e "${cfg.statePath}/db-created"; then psql postgres -c "CREATE ROLE gitlab WITH LOGIN NOCREATEDB NOCREATEROLE NOCREATEUSER ENCRYPTED PASSWORD '${cfg.databasePassword}'" ${config.services.postgresql.package}/bin/createdb --owner gitlab gitlab || true - touch "${cfg.stateDir}/db-created" + touch "${cfg.statePath}/db-created" - # force=yes disables the manual-interaction yes/no prompt - # which breaks without an stdin. - force=yes ${bundler}/bin/bundle exec rake -f ${pkgs.gitlab}/share/gitlab/Rakefile gitlab:setup RAILS_ENV=production + # The gitlab:setup task is horribly broken somehow, these two tasks will do the same for setting up the initial database + ${gitlab-runner}/bin/gitlab-runner exec rake db:migrate RAILS_ENV=production + ${gitlab-runner}/bin/gitlab-runner exec rake db:seed_fu RAILS_ENV=production \ + GITLAB_ROOT_PASSWORD="${cfg.initialRootPassword}" GITLAB_ROOT_EMAIL="${cfg.initialRootEmail}"; fi fi - ${bundler}/bin/bundle exec rake -f ${pkgs.gitlab}/share/gitlab/Rakefile db:migrate RAILS_ENV=production - # Install the shell required to push repositories - ln -fs ${pkgs.writeText "config.yml" gitlabShellYml} ${cfg.stateDir}/shell/config.yml - export GITLAB_SHELL_CONFIG_PATH=""${cfg.stateDir}/shell/config.yml - ${pkgs.gitlab-shell}/bin/install + # Always do the db migrations just to be sure the database is up-to-date + ${gitlab-runner}/bin/gitlab-runner exec rake db:migrate RAILS_ENV=production - # Change permissions in the last step because some of the - # intermediary scripts like to create directories as root. - chown -R gitlab:gitlab ${cfg.stateDir}/ - chmod -R 755 ${cfg.stateDir}/ + # Change permissions in the last step because some of the + # intermediary scripts like to create directories as root. + chown -R ${cfg.user}:${cfg.group} ${cfg.statePath} + chmod -R u+rwX,go-rwx+X ${cfg.statePath} ''; serviceConfig = { PermissionsStartOnly = true; # preStart must be run as root Type = "simple"; - User = "gitlab"; - Group = "gitlab"; + User = cfg.user; + Group = cfg.group; TimeoutSec = "300"; - WorkingDirectory = "${pkgs.gitlab}/share/gitlab"; - ExecStart="${bundler}/bin/bundle exec \"unicorn -c ${cfg.stateDir}/config/unicorn.rb -E production\""; + WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab"; + ExecStart="${bundler}/bin/bundle exec \"unicorn -c ${cfg.statePath}/config/unicorn.rb -E production\""; }; }; diff --git a/nixos/modules/services/misc/gitlab.xml b/nixos/modules/services/misc/gitlab.xml new file mode 100644 index 000000000000..b630fe421130 --- /dev/null +++ b/nixos/modules/services/misc/gitlab.xml @@ -0,0 +1,103 @@ +<chapter xmlns="http://docbook.org/ns/docbook" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:xi="http://www.w3.org/2001/XInclude" + version="5.0" + xml:id="module-services-gitlab"> + +<title>Gitlab</title> + +<para>Gitlab is a feature-rich git hosting service.</para> + +<section><title>Prerequisites</title> + +<para>The gitlab service exposes only an Unix socket at +<literal>/run/gitlab/gitlab-workhorse.socket</literal>. You need to configure a +webserver to proxy HTTP requests to the socket.</para> + +<para>For instance, this could be used for Nginx: + +<programlisting> +services.nginx.httpConfig = '' + server { + server_name git.example.com; + listen 443 ssl spdy; + listen [::]:443 ssl spdy; + + ssl_certificate /var/lib/acme/git.example.com/fullchain.pem; + ssl_certificate_key /var/lib/acme/git.example.com/key.pem; + + location / { + proxy_http_version 1.1; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Ssl on; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_pass http://unix:/run/gitlab/gitlab-workhorse.socket; + } + } +''; +</programlisting> +</para> + +</section> + +<section><title>Configuring</title> + +<para>Gitlab depends on both PostgreSQL and Redis and will automatically enable +both services. In the case of PostgreSQL, a database and a role will be created. +</para> + +<para>The default state dir is /var/gitlab/state. This is where all data like +the repositories and uploads will be stored.</para> + +<para>A basic configuration could look like this: + +<programlisting> +services.gitlab = { + enable = true; + databasePassword = "eXaMpl3"; + initialRootPassword = "UseNixOS!"; + https = true; + host = "git.example.com"; + port = 443; + user = "git"; + group = "git"; + extraConfig = { + gitlab = { + default_projects_features = { builds = false; }; + }; + }; +}; +</programlisting> +</para> + +<para>Refer to <xref linkend="ch-options" /> for all available configuration +options for the <literal>services.gitlab</literal> module.</para> + +</section> + +<section><title>Maintenance</title> + +<para>You can run all Gitlab related commands like rake tasks with +<literal>gitlab-runner</literal> which will be available on the system +when gitlab is enabled. You will have to run the commands as the user that +you configured to run gitlab.</para> + +<para>For instance, to backup a Gitlab instance: + +<programlisting> +$ sudo -u git -H gitlab-runner exec rake gitlab:backup:create +</programlisting> + +A list of all availabe rake tasks can be obtained by running: + +<programlisting> +$ sudo -u git -H gitlab-runner exec rake -T +</programlisting> +</para> + +</section> + +</chapter> diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix index 8e984727a80e..cf2ee20801ab 100644 --- a/nixos/modules/services/misc/nix-daemon.nix +++ b/nixos/modules/services/misc/nix-daemon.nix @@ -367,6 +367,8 @@ in // { CURL_CA_BUNDLE = "/etc/ssl/certs/ca-certificates.crt"; } // config.networking.proxy.envVars; + unitConfig.RequiresMountsFor = "/nix/store"; + serviceConfig = { Nice = cfg.daemonNiceLevel; IOSchedulingPriority = cfg.daemonIONiceLevel; diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix index 576e5c9e87a3..a186982ec9c0 100644 --- a/nixos/modules/services/network-filesystems/samba.nix +++ b/nixos/modules/services/network-filesystems/samba.nix @@ -79,6 +79,14 @@ in description = '' Whether to enable Samba, which provides file and print services to Windows clients through the SMB/CIFS protocol. + + <note> + <para>If you use the firewall consider adding the following:</para> + <programlisting> + networking.firewall.allowedTCPPorts = [ 139 445 ]; + networking.firewall.allowedUDPPorts = [ 137 138 ]; + </programlisting> + </note> ''; }; @@ -86,7 +94,7 @@ in type = types.package; default = pkgs.samba; defaultText = "pkgs.samba"; - example = literalExample "pkgs.samba4"; + example = literalExample "pkgs.samba3"; description = '' Defines which package should be used for the samba server. ''; @@ -118,6 +126,10 @@ in description = '' Additional global section and extra section lines go in here. ''; + example = '' + guest account = nobody + map to guest = bad user + ''; }; configText = mkOption { @@ -154,9 +166,11 @@ in ''; type = types.attrsOf (types.attrsOf types.unspecified); example = - { srv = - { path = "/srv"; + { public = + { path = "/srv/public"; "read only" = true; + browseable = "yes"; + "guest ok" = "yes"; comment = "Public samba share."; }; }; diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix index 98fb33e3256c..80d11565e47d 100644 --- a/nixos/modules/services/printing/cupsd.nix +++ b/nixos/modules/services/printing/cupsd.nix @@ -310,7 +310,7 @@ in [ ! -e "/var/lib/cups/$i" ] && ln -s "${rootdir}/etc/cups/$i" "/var/lib/cups/$i" done ${optionalString cfg.gutenprint '' - ${gutenprint}/bin/cups-genppdupdate + ${gutenprint}/bin/cups-genppdupdate -p /etc/cups/ppd ''} ''; }; diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl index d9048427801f..093b7f1ff225 100644 --- a/nixos/modules/system/activation/switch-to-configuration.pl +++ b/nixos/modules/system/activation/switch-to-configuration.pl @@ -261,12 +261,12 @@ while (my ($unit, $state) = each %{$activePrev}) { sub pathToUnitName { my ($path) = @_; - die unless substr($path, 0, 1) eq "/"; - return "-" if $path eq "/"; - $path = substr($path, 1); - $path =~ s/\//-/g; - # FIXME: handle - and unprintable characters. - return $path; + open my $cmd, "-|", "systemd-escape", "--suffix=mount", "-p", $path + or die "Unable to escape $path!\n"; + my $escaped = join "", <$cmd>; + chomp $escaped; + close $cmd or die; + return $escaped; } sub unique { @@ -290,7 +290,7 @@ my ($newFss, $newSwaps) = parseFstab "$out/etc/fstab"; foreach my $mountPoint (keys %$prevFss) { my $prev = $prevFss->{$mountPoint}; my $new = $newFss->{$mountPoint}; - my $unit = pathToUnitName($mountPoint) . ".mount"; + my $unit = pathToUnitName($mountPoint); if (!defined $new) { # Filesystem entry disappeared, so unmount it. $unitsToStop{$unit} = 1; diff --git a/nixos/modules/virtualisation/ec2-data.nix b/nixos/modules/virtualisation/ec2-data.nix index bee262612680..db3dd9949c12 100644 --- a/nixos/modules/virtualisation/ec2-data.nix +++ b/nixos/modules/virtualisation/ec2-data.nix @@ -43,18 +43,20 @@ with lib; mkdir -m 0755 -p /etc/ssh - key="$(sed 's/|/\n/g; s/SSH_HOST_DSA_KEY://; t; d' $userData)" - key_pub="$(sed 's/SSH_HOST_DSA_KEY_PUB://; t; d' $userData)" - if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_dsa_key ]; then - (umask 077; echo "$key" > /etc/ssh/ssh_host_dsa_key) - echo "$key_pub" > /etc/ssh/ssh_host_dsa_key.pub - fi + if [ -s "$userData" ]; then + key="$(sed 's/|/\n/g; s/SSH_HOST_DSA_KEY://; t; d' $userData)" + key_pub="$(sed 's/SSH_HOST_DSA_KEY_PUB://; t; d' $userData)" + if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_dsa_key ]; then + (umask 077; echo "$key" > /etc/ssh/ssh_host_dsa_key) + echo "$key_pub" > /etc/ssh/ssh_host_dsa_key.pub + fi - key="$(sed 's/|/\n/g; s/SSH_HOST_ED25519_KEY://; t; d' $userData)" - key_pub="$(sed 's/SSH_HOST_ED25519_KEY_PUB://; t; d' $userData)" - if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_ed25519_key ]; then - (umask 077; echo "$key" > /etc/ssh/ssh_host_ed25519_key) - echo "$key_pub" > /etc/ssh/ssh_host_ed25519_key.pub + key="$(sed 's/|/\n/g; s/SSH_HOST_ED25519_KEY://; t; d' $userData)" + key_pub="$(sed 's/SSH_HOST_ED25519_KEY_PUB://; t; d' $userData)" + if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_ed25519_key ]; then + (umask 077; echo "$key" > /etc/ssh/ssh_host_ed25519_key) + echo "$key_pub" > /etc/ssh/ssh_host_ed25519_key.pub + fi fi ''; diff --git a/nixos/tests/printing.nix b/nixos/tests/printing.nix index 02980cee2fbd..10d69b446cd7 100644 --- a/nixos/tests/printing.nix +++ b/nixos/tests/printing.nix @@ -78,7 +78,7 @@ import ./make-test.nix ({pkgs, ... }: { # (showing that the right filters have been applied). Of # course, since there is no actual USB printer attached, the # file will stay in the queue forever. - $server->waitForFile("/var/spool/cups/d00001-001"); + $server->waitForFile("/var/spool/cups/d*-001"); $server->sleep(10); $server->succeed("lpq -a") =~ /$fn/ or die; @@ -90,6 +90,9 @@ import ./make-test.nix ({pkgs, ... }: { Machine::retry sub { return 1 if $server->succeed("lpq -a") =~ /no entries/; }; + # The queue is empty already, so this should be safe. + # Otherwise, pairs of "c*"-"d*-001" files might persist. + $server->execute("rm /var/spool/cups/*"); }; } ''; |