-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add push-cache-effect #165
base: master
Are you sure you want to change the base?
Changes from all commits
69feb35
88b2d2e
4ac73c0
bb67abf
79681bd
f3d0426
b225c97
ee2cdc1
275eaa5
a4888df
f5ed263
5ad8f96
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
{ lib, withSystem, config, ... }: | ||
let pkgs-x86_64-linux = withSystem "x86_64-linux" ({ pkgs, ... }: pkgs); | ||
in { | ||
imports = [ ../../flake-module.nix ]; | ||
|
||
options = { | ||
push-cache-effect = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can have a |
||
enable = lib.mkOption { | ||
type = lib.types.bool; | ||
default = false; | ||
description = '' | ||
Enables an effect that pushes certain outputs to a different binary cache. | ||
|
||
Hercules CI normally pushes everything to the cache(s) configured on the agent. This effect supplements that behavior by letting you push a subset of those to a different cache. | ||
Note that it only pushes the output closure, and not the closures of build dependencies used during the build stage of the CI job. (Unless those closures happen to also be part of the output or "runtime" closure) | ||
''; | ||
}; | ||
attic-client-pkg = lib.mkOption { | ||
type = lib.types.package; | ||
description = '' | ||
Version of the attic-client package to use on \"x86_64-linux\". | ||
|
||
Hint: You can use `attic.packages.x86_64-linux.attic-client` from the attic flake. | ||
''; | ||
default = pkgs-x86_64-linux.attic-client or (throw | ||
"push-cache-effect.attic-client-pkg: It seems that attic hasn't been packaged in Nixpkgs (yet?). Please check <nixpkgs packaging request issue> or set <option> manually."); | ||
}; | ||
cachix-pkg = lib.mkOption { | ||
type = lib.types.package; | ||
default = pkgs-x86_64-linux.cachix; | ||
description = | ||
''Version of the cachix package to use on "x86_64-linux".''; | ||
}; | ||
caches = lib.mkOption { | ||
description = '' | ||
An attribute set, each `name: value` pair translates to | ||
an effect under `onPush.default.outputs.effects.push-cache-effect.name`. | ||
''; | ||
example = '' | ||
{ | ||
our-cachix = { | ||
type = \"cachix\"; | ||
secretName = \"our-cachix-token\"; | ||
branches = [ \"master\" ]; | ||
packages = [ pkgs.hello ]; | ||
}; | ||
} | ||
''; | ||
type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: { | ||
options = { | ||
name = lib.mkOption { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The default should be be |
||
type = lib.types.str; | ||
default = name; | ||
description = '' | ||
Name of the effect. By default it's the attribute name. | ||
''; | ||
}; | ||
type = lib.mkOption { | ||
type = lib.types.enum [ "attic" "cachix" ]; | ||
description = ''A string "attic" or "cachix".''; | ||
}; | ||
packages = lib.mkOption { | ||
type = with lib.types; listOf package; | ||
description = "List of packages to push to the cache."; | ||
example = "[ pkgs.hello ]"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As a default, we could use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting! Didn't know There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would involve writing a attribute tree traversal to match the agent behavior, with the right Note also that this effect can not replicate the whole agent behavior, such as pushing all the right build dependencies. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resolved: we leave it unspecified and the responsibility of the caller since replicating default builder behavior is infeasible. |
||
}; | ||
secretName = lib.mkOption { | ||
type = lib.types.str; | ||
description = '' | ||
Name of the HerculesCI secret. See [HerculesCI docs](https://docs.hercules-ci.com/hercules-ci-agent/secrets-json). | ||
The secrets "data" field should contain given data: | ||
|
||
``` | ||
"data": { | ||
"name": "my-cache-name", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think both are acceptable solutions. |
||
"token": "ey536428341723812", | ||
"endpoint": "https://my-cache-name.com" | ||
} | ||
``` | ||
|
||
The "endpoint" field is needed for Attic cache. With Cachix cache the "endpoint" field is not read and can be absent. | ||
''; | ||
}; | ||
branches = lib.mkOption { | ||
type = with lib.types; nullOr (listOf str); | ||
default = null; | ||
description = '' | ||
Branches on which we'd like to execute the effect. Set to `null` to execute on all branches. | ||
''; | ||
}; | ||
}; | ||
})); | ||
}; | ||
}; | ||
}; | ||
|
||
config = let | ||
# file with all the package paths written line by line | ||
# nixpkgs -> [derivation] -> derivation | ||
packagesFile = pkgs: packages: | ||
pkgs.writeText "pushed-paths" (lib.strings.concatStringsSep "\n" | ||
(builtins.map builtins.toString packages)); | ||
|
||
mkAtticPushEffect = { cacheOptions, branch, }: | ||
withSystem "x86_64-linux" ({ hci-effects, pkgs, ... }: | ||
let | ||
pushEffect = hci-effects.mkEffect { | ||
inputs = [ config.push-cache-effect.attic-client-pkg ]; | ||
secretsMap = { token-file = "${cacheOptions.secretName}"; }; | ||
userSetupScript = '' | ||
attic login \ | ||
default \ | ||
$(readSecretString token-file .endpoint) \ | ||
$(readSecretString token-file .token) | ||
''; | ||
effectScript = '' | ||
cat ${ | ||
packagesFile pkgs cacheOptions.packages | ||
} | xargs -s 4096 attic push default:$(readSecretString token-file .name) | ||
''; | ||
}; | ||
in hci-effects.runIf ((cacheOptions.branches == null) | ||
|| (builtins.elem branch cacheOptions.branches)) pushEffect); | ||
|
||
mkCachixPushEffect = { cacheOptions, branch, }: | ||
withSystem "x86_64-linux" ({ hci-effects, pkgs, ... }: | ||
let | ||
pushEffect = hci-effects.mkEffect { | ||
inputs = [ config.push-cache-effect.cachix-pkg ]; | ||
secretsMap = { token-file = "${cacheOptions.secretName}"; }; | ||
userSetupScript = '' | ||
cachix authtoken $(readSecretString token-file .token) | ||
''; | ||
effectScript = '' | ||
cat ${ | ||
packagesFile pkgs cacheOptions.packages | ||
} | cachix push $(readSecretString token-file .name) | ||
''; | ||
}; | ||
in hci-effects.runIf ((cacheOptions.branches == null) | ||
|| (builtins.elem branch cacheOptions.branches)) pushEffect); | ||
in lib.mkIf config.push-cache-effect.enable { | ||
herculesCI = herculesConfig: { | ||
onPush.default.outputs.effects.push-cache-effect = lib.attrsets.mapAttrs' | ||
(_: cacheOptions: { | ||
inherit (cacheOptions) name; | ||
value = builtins.getAttr "${cacheOptions.type}" { | ||
attic = mkAtticPushEffect { | ||
inherit cacheOptions; | ||
inherit (herculesConfig.config.repo) branch; | ||
}; | ||
cachix = mkCachixPushEffect { | ||
inherit cacheOptions; | ||
inherit (herculesConfig.config.repo) branch; | ||
}; | ||
}; | ||
}) config.push-cache-effect.caches; | ||
}; | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should support other systems.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would see what happens if we try to push non
x86_64-linux
derivations using anx86_64-linux
effect before.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those will be scheduled during the build phase of the job, and substituted into the agent's store before the effect is launched.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested: pushing derivations built on other systems to attic works.