2024-08-01 22:33:42 +00:00
|
|
|
{ lib, config, pkgs, ... }:
|
2024-08-31 18:03:11 +00:00
|
|
|
# FIXME(raito): I'm really really really not happy with this design of NixOS module, clean up all of this someday.
|
2024-08-01 22:33:42 +00:00
|
|
|
let
|
2024-08-31 18:03:11 +00:00
|
|
|
inherit (lib) mkEnableOption mkOption types mkIf mapAttrsToList mkPackageOption concatStringsSep mkMerge;
|
2024-08-01 22:33:42 +00:00
|
|
|
cfg = config.bagel.nixpkgs.channel-scripts;
|
|
|
|
toml = pkgs.formats.toml { };
|
|
|
|
configFile = toml.generate "forkos.toml" cfg.settings;
|
|
|
|
orderLib = import ./service-order.nix { inherit lib; };
|
|
|
|
makeUpdateJob = channelName: mainJob: {
|
|
|
|
name = "update-${channelName}";
|
|
|
|
value = {
|
|
|
|
description = "Update channel ${channelName}";
|
|
|
|
path = with pkgs; [ git ];
|
|
|
|
serviceConfig = {
|
|
|
|
Type = "oneshot";
|
|
|
|
RemainAfterExit = false;
|
|
|
|
User = "channel-scripts";
|
|
|
|
DynamicUser = true;
|
|
|
|
StateDirectory = "channel-scripts";
|
|
|
|
MemoryHigh = "80%";
|
|
|
|
EnvironmentFile = [
|
|
|
|
cfg.releaseBucketCredentialsFile
|
|
|
|
];
|
|
|
|
Environment = cfg.extraEnvironment;
|
2024-08-31 17:56:46 +00:00
|
|
|
# TODO: we should have our own secret for this.
|
|
|
|
LoadCredential = [ "password:${config.age.secrets.alloy-push-password.path}" ];
|
2024-08-01 22:33:42 +00:00
|
|
|
};
|
|
|
|
unitConfig.After = [ "networking.target" ];
|
|
|
|
script =
|
|
|
|
''
|
|
|
|
# A stateful copy of nixpkgs
|
|
|
|
dir=/var/lib/channel-scripts/nixpkgs
|
|
|
|
if ! [[ -e $dir ]]; then
|
|
|
|
git clone --bare ${cfg.nixpkgsUrl} $dir
|
|
|
|
fi
|
|
|
|
GIT_DIR=$dir git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
|
|
|
|
|
2024-08-31 17:56:46 +00:00
|
|
|
CREDENTIAL=$(echo -en "promtail:$(cat $CREDENTIALS_DIRECTORY/password)" | base64)
|
|
|
|
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic $CREDENTIAL"
|
2024-08-01 22:33:42 +00:00
|
|
|
# TODO: use escapeShellArgs
|
|
|
|
exec ${cfg.package}/bin/mirror-forkos -c ${configFile} ${concatStringsSep " " cfg.extraArgs} apply ${channelName} ${mainJob}
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
updateJobs = orderLib.mkOrderedChain (mapAttrsToList (n: { job, ... }: makeUpdateJob n job) cfg.channels);
|
|
|
|
channelOpts = { ... }: {
|
|
|
|
options = {
|
|
|
|
job = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
example = "nixos/trunk-combined/tested";
|
|
|
|
};
|
|
|
|
|
|
|
|
variant = mkOption {
|
|
|
|
type = types.enum [ "primary" "small" "darwin" "aarch64" ];
|
|
|
|
example = "primary";
|
|
|
|
};
|
|
|
|
|
|
|
|
status = mkOption {
|
|
|
|
type = types.enum [ "beta" "stable" "deprecated" "unmaintained" "rolling" ];
|
|
|
|
example = "rolling";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
in
|
|
|
|
{
|
|
|
|
options.bagel.nixpkgs.channel-scripts = {
|
|
|
|
enable = mkEnableOption ''the channel scripts.
|
|
|
|
Fast forwarding channel branches which are read-only except for this privileged bot
|
|
|
|
based on our Hydra acceptance tests.
|
|
|
|
'';
|
|
|
|
|
|
|
|
otlp.enable = mkEnableOption "the OTLP export process";
|
|
|
|
|
|
|
|
s3 = {
|
|
|
|
release = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
};
|
|
|
|
|
|
|
|
channel = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
package = mkPackageOption pkgs "mirror-forkos" { };
|
|
|
|
|
|
|
|
settings = mkOption {
|
|
|
|
type = types.attrsOf types.anything;
|
|
|
|
};
|
|
|
|
|
|
|
|
nixpkgsUrl = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "https://cl.forkos.org/nixpkgs.git";
|
|
|
|
description = "URL to the nixpkgs repository to clone and to push to";
|
|
|
|
};
|
|
|
|
|
|
|
|
binaryCacheUrl = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "https://cache.forkos.org";
|
|
|
|
description = "URL to the binary cache";
|
|
|
|
};
|
|
|
|
|
|
|
|
baseUriForGitRevisions = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
description = "Base URI to generate link to a certain revision";
|
|
|
|
};
|
|
|
|
|
|
|
|
extraArgs = mkOption {
|
|
|
|
type = types.listOf types.str;
|
|
|
|
default = [ ];
|
|
|
|
description = "Extra arguments passed to the mirroring program";
|
|
|
|
};
|
|
|
|
|
|
|
|
releaseBucketCredentialsFile = mkOption {
|
|
|
|
type = types.path;
|
|
|
|
description = ''Path to the release bucket credentials file exporting S3-style environment variables.
|
|
|
|
For example, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` for the S3 operations to work.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
deployKeyFile = mkOption {
|
|
|
|
type = types.path;
|
|
|
|
description = ''Path to the private SSH key which is allowed to deploy things to the protected channel references on the Git repository.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
hydraUrl = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "https://hydra.forkos.org";
|
|
|
|
description = "URL to the Hydra instance";
|
|
|
|
};
|
|
|
|
|
|
|
|
channels = mkOption {
|
|
|
|
type = types.attrsOf (types.submodule channelOpts);
|
|
|
|
description = "List of channels to mirror";
|
|
|
|
};
|
|
|
|
|
|
|
|
extraEnvironment = mkOption {
|
|
|
|
type = types.listOf types.str;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
2024-08-31 18:03:11 +00:00
|
|
|
bagel.nixpkgs.channel-scripts.extraEnvironment = mkMerge [
|
|
|
|
([
|
|
|
|
"RUST_LOG=info"
|
|
|
|
])
|
|
|
|
(mkIf cfg.otlp.enable [
|
|
|
|
''OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://tempo.forkos.org/v1/traces"''
|
|
|
|
])
|
2024-08-31 17:56:46 +00:00
|
|
|
];
|
2024-08-01 22:33:42 +00:00
|
|
|
bagel.nixpkgs.channel-scripts.settings = {
|
|
|
|
hydra_uri = cfg.hydraUrl;
|
|
|
|
binary_cache_uri = cfg.binaryCacheUrl;
|
|
|
|
base_git_uri_for_revision = cfg.baseUriForGitRevisions;
|
|
|
|
nixpkgs_dir = "/var/lib/channel-scripts/nixpkgs";
|
|
|
|
s3_release_bucket_name = cfg.s3.release;
|
|
|
|
s3_channel_bucket_name = cfg.s3.channel;
|
|
|
|
};
|
|
|
|
|
|
|
|
users.users.channel-scripts = {
|
|
|
|
description = "Channel scripts user";
|
|
|
|
isSystemUser = true;
|
|
|
|
group = "channel-scripts";
|
|
|
|
};
|
|
|
|
users.groups.channel-scripts = {};
|
|
|
|
|
|
|
|
systemd.services = (lib.listToAttrs updateJobs) // {
|
|
|
|
"update-all-channels" = {
|
|
|
|
description = "Start all channel updates.";
|
|
|
|
unitConfig = {
|
|
|
|
After = map
|
|
|
|
(service: "${service.name}.service")
|
|
|
|
updateJobs;
|
|
|
|
Wants = map
|
|
|
|
(service: "${service.name}.service")
|
|
|
|
updateJobs;
|
|
|
|
};
|
|
|
|
script = "true";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
systemd.timers."update-all-channels" = {
|
|
|
|
description = "Start all channel updates.";
|
|
|
|
wantedBy = [ "timers.target" ];
|
|
|
|
timerConfig = {
|
|
|
|
OnUnitInactiveSec = 600;
|
|
|
|
OnBootSec = 900;
|
|
|
|
AccuracySec = 300;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|