329 lines
10 KiB
Nix
329 lines
10 KiB
Nix
# Gerrit configuration for the Nixpkgs monorepo
|
|
# Inspired from TVL configuration.
|
|
{ pkgs, config, lib, ... }:
|
|
|
|
let
|
|
inherit (lib) mkEnableOption mkIf mkOption types head;
|
|
cfgGerrit = config.services.gerrit;
|
|
cfg = config.bagel.services.gerrit;
|
|
|
|
jdk = pkgs.openjdk21_headless;
|
|
in
|
|
{
|
|
options.bagel.services.gerrit = {
|
|
enable = mkEnableOption "Gerrit";
|
|
pyroscope.enable = mkEnableOption ''Pyroscope client,
|
|
this will send profiling of all Java processes on the current host
|
|
to our Pyroscope instance.
|
|
'';
|
|
domains = mkOption {
|
|
type = types.listOf types.str;
|
|
description = "List of domains that Gerrit will answer to";
|
|
};
|
|
canonicalDomain = mkOption {
|
|
type = types.str;
|
|
description = "Canonical domain for this Gerrit instance";
|
|
default = head cfg.domains;
|
|
};
|
|
data = mkOption {
|
|
type = types.path;
|
|
default = "/var/lib/gerrit";
|
|
description = "Root of data directory for the Gerrit";
|
|
};
|
|
port = mkOption {
|
|
type = types.port;
|
|
default = 29418;
|
|
readOnly = true;
|
|
description = "Port for the Gerrit SSH server";
|
|
};
|
|
};
|
|
|
|
imports = [
|
|
./www.nix
|
|
./one-way-sync.nix
|
|
];
|
|
|
|
config = mkIf cfg.enable {
|
|
networking.firewall.allowedTCPPorts = [ cfg.port ];
|
|
age.secrets.alloy-push-password.file = ../../secrets/metrics-push-password.age;
|
|
|
|
environment.systemPackages = [ jdk
|
|
pkgs.git
|
|
# https://gerrit.googlesource.com/gerrit/+/refs/heads/master/contrib/git-gc-preserve
|
|
pkgs.git-gc-preserve
|
|
];
|
|
|
|
fileSystems."/var/lib/gerrit" = mkIf (cfg.data != "/var/lib/gerrit") {
|
|
device = cfg.data;
|
|
options = [ "bind" ];
|
|
};
|
|
|
|
users.users.git = {
|
|
isSystemUser = true;
|
|
group = "git";
|
|
};
|
|
users.groups.git = {};
|
|
|
|
services.alloy = {
|
|
enable = cfg.pyroscope.enable;
|
|
extraFlags = [
|
|
# Debugging interface.
|
|
"--server.http.listen-addr=127.0.0.1:15555"
|
|
];
|
|
};
|
|
systemd.services.alloy.serviceConfig = {
|
|
User = lib.mkForce "root";
|
|
Group = lib.mkForce "root";
|
|
DynamicUser = lib.mkForce false;
|
|
};
|
|
systemd.services.alloy.serviceConfig.LoadCredential = [ "password:${config.age.secrets.alloy-push-password.path}" ];
|
|
environment.etc."alloy/config.alloy".text = ''
|
|
pyroscope.write "production" {
|
|
endpoint {
|
|
url = "https://pyroscope.forkos.org"
|
|
basic_auth {
|
|
username = "promtail"
|
|
password_file = "/run/credentials/alloy.service/password"
|
|
}
|
|
}
|
|
}
|
|
|
|
discovery.process "all" {
|
|
refresh_interval = "60s"
|
|
discover_config {
|
|
cwd = true
|
|
exe = true
|
|
commandline = true
|
|
username = true
|
|
uid = true
|
|
container_id = true
|
|
}
|
|
}
|
|
|
|
discovery.relabel "java" {
|
|
targets = discovery.process.all.targets
|
|
rule {
|
|
action = "keep"
|
|
regex = ".*/java$"
|
|
source_labels = ["__meta_process_exe"]
|
|
}
|
|
}
|
|
|
|
pyroscope.java "java" {
|
|
targets = discovery.relabel.java.output
|
|
forward_to = [pyroscope.write.production.receiver]
|
|
profiling_config {
|
|
interval = "60s"
|
|
alloc = "512k"
|
|
cpu = true
|
|
sample_rate = 100
|
|
lock = "1ms"
|
|
}
|
|
}
|
|
'';
|
|
|
|
services.gerrit = {
|
|
enable = true;
|
|
listenAddress = "[::]:4778"; # 4778 - grrt
|
|
serverId = "9e5216ad-038d-4d74-a4e8-716515834a94";
|
|
|
|
builtinPlugins = [
|
|
"gitiles"
|
|
"codemirror-editor"
|
|
"reviewnotes"
|
|
"download-commands"
|
|
"hooks"
|
|
"replication"
|
|
"webhooks"
|
|
];
|
|
|
|
plugins = with pkgs.gerritPlugins; [
|
|
oauth
|
|
metrics-reporter-prometheus
|
|
# Buildbot checks plugin (writeText because services.gerrit.plugins expects packages)
|
|
(pkgs.runCommand "checks.js" {
|
|
BASE_URI = builtins.toJSON "https://buildbot.forkos.org";
|
|
SUPPORTED_PROJECTS = builtins.toJSON [
|
|
"infra"
|
|
"nixpkgs"
|
|
"buildbot-test"
|
|
];
|
|
}
|
|
''
|
|
echo "configuring buildbot checks plugin for $BASE_URI with $SUPPORTED_PROJECTS project list"
|
|
substitute ${./checks.js} $out \
|
|
--replace-fail "@BASE_URI@" "$BASE_URI" \
|
|
--replace-fail "@SUPPORTED_PROJECTS@" "$SUPPORTED_PROJECTS"
|
|
'')
|
|
];
|
|
|
|
package = pkgs.gerrit;
|
|
|
|
jvmHeapLimit = "32g";
|
|
|
|
jvmPackage = jdk;
|
|
|
|
settings = {
|
|
# Performance settings
|
|
sshd.threads = 64;
|
|
sshd.batchThreads = 8;
|
|
|
|
gc.aggressive = true;
|
|
gc.interval = "1 day";
|
|
|
|
database.poolLimit = 250;
|
|
database.poolMaxIdle = 16;
|
|
|
|
httpd.maxThreads = 100;
|
|
|
|
receive.timeout = "4min";
|
|
# Default is 0, infinite.
|
|
# When system is under pressure and there's too many packfiles
|
|
# the search for reuse can take a stupid amount of time.
|
|
transfer.timeout = "60min";
|
|
|
|
# We may overshoot but it's OK.
|
|
core.packedGitWindowSize = "256k";
|
|
# Sum of all current packfiles is ~1.2G
|
|
# Largest packfile is 906MB.
|
|
# Average packfile is ~5-10MB.
|
|
core.packedGitLimit = "2g";
|
|
# We have plenty of memory, let's avoid file system cache → Gerrit needless copies.
|
|
core.packedGitUseStrongRefs = true;
|
|
core.packedGitOpenFiles = 4096;
|
|
# Big files in nixpkgs are usually lockfiles or machine-generated expressions
|
|
# containing a lot of hashes, they would weigh at most ~15MB.
|
|
core.streamFileThreshold = "20m";
|
|
# `mmap()` rather than `mmap()+read()` at the risk of running out of virtual address space.
|
|
core.packedGitMmap = true;
|
|
|
|
## Takes more CPU but the transfer is smaller.
|
|
pack.deltacompression = true;
|
|
pack.threads = 8;
|
|
|
|
# FIXME(raito):
|
|
# Are we supposed to have private / hidden references?
|
|
# For a public server, that seems unlikely.
|
|
# But, we should be careful with this option.
|
|
# https://gerrit-documentation.storage.googleapis.com/Documentation/3.9.5/config-gerrit.html#receive.checkReferencedObjectsAreReachable
|
|
receive.checkReferencedObjectsAreReachable = false;
|
|
|
|
# Other settings
|
|
log.jsonLogging = true;
|
|
log.textLogging = false;
|
|
sshd.advertisedAddress = "${cfg.canonicalDomain}:${toString cfg.port}";
|
|
cache.web_sessions.maxAge = "3 months";
|
|
plugins.allowRemoteAdmin = false;
|
|
change.enableAttentionSet = true;
|
|
change.enableAssignee = false;
|
|
|
|
user = {
|
|
name = "ForkOS Gerrit";
|
|
email = "gerrit@forkos.org";
|
|
anonymousCoward = "ForkOS contributor";
|
|
};
|
|
|
|
# Configures gerrit for being reverse-proxied by nginx as per
|
|
# https://gerrit-review.googlesource.com/Documentation/config-reverseproxy.html
|
|
gerrit = {
|
|
canonicalWebUrl = "https://${cfg.canonicalDomain}";
|
|
docUrl = "/Documentation";
|
|
defaultBranch = "refs/heads/main";
|
|
};
|
|
|
|
httpd.listenUrl = "proxy-https://${cfgGerrit.listenAddress}";
|
|
|
|
download.command = [
|
|
"checkout"
|
|
"cherry_pick"
|
|
"format_patch"
|
|
"pull"
|
|
];
|
|
|
|
# Auto-link other CLs
|
|
commentlink.gerrit = {
|
|
match = "cl/(\\d+)";
|
|
link = "https://${cfg.canonicalDomain}/$1";
|
|
};
|
|
|
|
# Configures integration with Keycloak, which then integrates with a
|
|
# variety of backends.
|
|
auth.type = "OAUTH";
|
|
plugin.gerrit-oauth-provider-keycloak-oauth = {
|
|
root-url = "https://identity.lix.systems";
|
|
realm = "lix-project";
|
|
client-id = "raito-gerrit-testing";
|
|
# client-secret is set in /var/lib/gerrit/etc/secure.config.
|
|
};
|
|
|
|
plugin.code-owners = {
|
|
# A Code-Review +2 vote is required from a code owner.
|
|
requiredApproval = "Code-Review+2";
|
|
# The OWNERS check can be overriden using an Owners-Override vote.
|
|
overrideApproval = "Owners-Override+1";
|
|
# People implicitly approve their own changes automatically.
|
|
enableImplicitApprovals = "TRUE";
|
|
};
|
|
|
|
# Allow users to add additional email addresses to their accounts.
|
|
oauth.allowRegisterNewEmail = true;
|
|
|
|
# Use Gerrit's built-in HTTP passwords, rather than trying to use the
|
|
# password against the backing OAuth provider.
|
|
auth.gitBasicAuthPolicy = "HTTP";
|
|
|
|
# Email sending (emails are relayed via the tazj.in domain's
|
|
# GSuite currently).
|
|
#
|
|
# Note that sendemail.smtpPass is stored in
|
|
# $site_path/etc/secure.config and is *not* controlled by Nix.
|
|
#
|
|
# Receiving email is not currently supported.
|
|
sendemail.enable = false;
|
|
#sendemail = {
|
|
# enable = false;
|
|
# html = false;
|
|
# connectTimeout = "10sec";
|
|
# from = "TVL Code Review <tvlbot@tazj.in>";
|
|
# includeDiff = true;
|
|
# smtpEncryption = "none";
|
|
# smtpServer = "localhost";
|
|
# smtpServerPort = 2525;
|
|
#};
|
|
};
|
|
|
|
# Replication of the depot repository to secondary machines, for
|
|
# serving cgit/josh.
|
|
#replicationSettings = {
|
|
# gerrit.replicateOnStartup = true;
|
|
|
|
# remote.sanduny = {
|
|
# url = "depot@sanduny.tvl.su:/var/lib/depot";
|
|
# projects = "depot";
|
|
# };
|
|
#};
|
|
};
|
|
|
|
systemd.services.gerrit = {
|
|
serviceConfig = {
|
|
# There seems to be no easy way to get `DynamicUser` to play
|
|
# well with other services (e.g. by using SupplementaryGroups,
|
|
# which seem to have no effect) so we force the DynamicUser
|
|
# setting for the Gerrit service to be disabled and reuse the
|
|
# existing 'git' user.
|
|
DynamicUser = lib.mkForce false;
|
|
User = "git";
|
|
Group = "git";
|
|
};
|
|
environment.REVWALK_USE_PRIORITY_QUEUE = "true";
|
|
};
|
|
|
|
age.secrets.gerrit-prometheus-bearer-token.file = ../../secrets/gerrit-prometheus-bearer-token.age;
|
|
bagel.monitoring.grafana-agent.exporters.gerrit = {
|
|
port = 4778; # grrt
|
|
bearerTokenFile = config.age.secrets.gerrit-prometheus-bearer-token.path;
|
|
scrapeConfig.metrics_path = "/plugins/metrics-reporter-prometheus/metrics";
|
|
};
|
|
};
|
|
}
|