Skip to content

Commit abda0c0

Browse files
Add secondary Nix-based build system (#212)
* Add secondary Nix-based build system * Updated pinned versions. Added product-config properties to docker image. CHanged nix command in tiltfile * Added 'run-dev' target to Makefile to start tilt * Address review comments: - Only add properties.yaml if it exists - Correctly calculate port for Tilt instead of using string concatenation --------- Co-authored-by: Sönke Liebau <[email protected]>
1 parent 46edd8c commit abda0c0

File tree

7 files changed

+324
-0
lines changed

7 files changed

+324
-0
lines changed

playbook/playbook.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@
3333
with_items: "{{ repositories }}"
3434
loop_control:
3535
loop_var: operator
36+
index_var: operator_index

template/Makefile.j2

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,6 @@ regenerate-charts: chart-clean compile-chart
7373
build: regenerate-charts helm-package docker-build
7474

7575
publish: build docker-publish helm-publish
76+
77+
run-dev:
78+
nix run -f. tilt -- up --port {[5430 + operator_index}]

template/Tiltfile

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
default_registry("docker.stackable.tech/sandbox")
2+
3+
meta = read_json('nix/meta.json')
4+
operator_name = meta['operator']['name']
5+
6+
custom_build(
7+
'docker.stackable.tech/sandbox/' + operator_name,
8+
'nix shell -f . crate2nix -c crate2nix generate && nix-build . -A docker --argstr dockerName "${EXPECTED_REGISTRY}/' + operator_name + '" && ./result/load-image | docker load',
9+
deps=['rust', 'Cargo.toml', 'Cargo.lock', 'default.nix', "nix", 'build.rs', 'vendor'],
10+
# ignore=['result*', 'Cargo.nix', 'target', *.yaml],
11+
outputs_image_ref_to='result/ref',
12+
)
13+
14+
# Load the latest CRDs from Nix
15+
watch_file('result')
16+
if os.path.exists('result'):
17+
k8s_yaml('result/crds.yaml')
18+
19+
# Exclude stale CRDs from Helm chart, and apply the rest
20+
helm_crds, helm_non_crds = filter_yaml(
21+
helm(
22+
'deploy/helm/' + operator_name,
23+
name=operator_name,
24+
set=[
25+
'image.repository=docker.stackable.tech/sandbox/' + operator_name,
26+
],
27+
),
28+
api_version = "^apiextensions\\.k8s\\.io/.*$",
29+
kind = "^CustomResourceDefinition$",
30+
)
31+
k8s_yaml(helm_non_crds)

template/default.nix

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
{ sources ? import ./nix/sources.nix # managed by https://github.com/nmattia/niv
2+
, nixpkgs ? sources.nixpkgs
3+
, pkgs ? import nixpkgs {}
4+
, cargo ? import ./Cargo.nix {
5+
inherit nixpkgs pkgs; release = false;
6+
defaultCrateOverrides = pkgs.defaultCrateOverrides // {
7+
prost-build = attrs: {
8+
buildInputs = [ pkgs.protobuf ];
9+
};
10+
tonic-reflection = attrs: {
11+
buildInputs = [ pkgs.rustfmt ];
12+
};
13+
};
14+
}
15+
, meta ? pkgs.lib.importJSON ./nix/meta.json
16+
, dockerName ? "docker.stackable.tech/sandbox/${meta.operator.name}"
17+
, dockerTag ? null
18+
}:
19+
rec {
20+
build = cargo.allWorkspaceMembers;
21+
entrypoint = build+"/bin/stackable-${meta.operator.name}";
22+
crds = pkgs.runCommand "${meta.operator.name}-crds.yaml" {}
23+
''
24+
${entrypoint} crd > $out
25+
'';
26+
27+
dockerImage = pkgs.dockerTools.streamLayeredImage {
28+
name = dockerName;
29+
tag = dockerTag;
30+
contents = [ pkgs.bashInteractive pkgs.coreutils pkgs.util-linuxMinimal ];
31+
config = {
32+
Env =
33+
let
34+
fileRefVars = {
35+
PRODUCT_CONFIG = deploy/config-spec/properties.yaml;
36+
};
37+
in lib.concatLists (lib.mapAttrsToList (env: path: lib.optional (lib.pathExists path) "${env}=${path}") fileRefVars);
38+
Entrypoint = [ entrypoint ];
39+
Cmd = [ "run" ];
40+
};
41+
};
42+
docker = pkgs.linkFarm "listener-operator-docker" [
43+
{
44+
name = "load-image";
45+
path = dockerImage;
46+
}
47+
{
48+
name = "ref";
49+
path = pkgs.writeText "${dockerImage.name}-image-tag" "${dockerImage.imageName}:${dockerImage.imageTag}";
50+
}
51+
{
52+
name = "image-repo";
53+
path = pkgs.writeText "${dockerImage.name}-repo" dockerImage.imageName;
54+
}
55+
{
56+
name = "image-tag";
57+
path = pkgs.writeText "${dockerImage.name}-tag" dockerImage.imageTag;
58+
}
59+
{
60+
name = "crds.yaml";
61+
path = crds;
62+
}
63+
];
64+
65+
# need to use vendored crate2nix because of https://github.com/kolloch/crate2nix/issues/264
66+
crate2nix = import sources.crate2nix {};
67+
tilt = pkgs.tilt;
68+
}

template/nix/meta.json.j2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{[ {'operator': operator} | to_json }]

template/nix/sources.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"crate2nix": {
3+
"branch": "master",
4+
"description": "nix build file generator for rust crates",
5+
"homepage": "",
6+
"owner": "kolloch",
7+
"repo": "crate2nix",
8+
"rev": "45fc83132c8c91c77a1cd61fe0c945411d1edba8",
9+
"sha256": "00w9qza56xh9m98308wzfbjf135gpz6sf7b5yfharvmax1k46c5q",
10+
"type": "tarball",
11+
"url": "https://github.com/kolloch/crate2nix/archive/45fc83132c8c91c77a1cd61fe0c945411d1edba8.tar.gz",
12+
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
13+
},
14+
"nixpkgs": {
15+
"branch": "nixpkgs-unstable",
16+
"description": "Nix Packages collection",
17+
"homepage": "",
18+
"owner": "NixOS",
19+
"repo": "nixpkgs",
20+
"rev": "747927516efcb5e31ba03b7ff32f61f6d47e7d87",
21+
"sha256": "1s4xabv59r99z8vd74w3r84kkxwqggqir3b0nh3ma04mni0m40gf",
22+
"type": "tarball",
23+
"url": "https://github.com/NixOS/nixpkgs/archive/747927516efcb5e31ba03b7ff32f61f6d47e7d87.tar.gz",
24+
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
25+
}
26+
}

template/nix/sources.nix

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
# This file has been generated by Niv.
2+
3+
let
4+
5+
#
6+
# The fetchers. fetch_<type> fetches specs of type <type>.
7+
#
8+
9+
fetch_file = pkgs: name: spec:
10+
let
11+
name' = sanitizeName name + "-src";
12+
in
13+
if spec.builtin or true then
14+
builtins_fetchurl { inherit (spec) url sha256; name = name'; }
15+
else
16+
pkgs.fetchurl { inherit (spec) url sha256; name = name'; };
17+
18+
fetch_tarball = pkgs: name: spec:
19+
let
20+
name' = sanitizeName name + "-src";
21+
in
22+
if spec.builtin or true then
23+
builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
24+
else
25+
pkgs.fetchzip { name = name'; inherit (spec) url sha256; };
26+
27+
fetch_git = name: spec:
28+
let
29+
ref =
30+
if spec ? ref then spec.ref else
31+
if spec ? branch then "refs/heads/${spec.branch}" else
32+
if spec ? tag then "refs/tags/${spec.tag}" else
33+
abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!";
34+
submodules = if spec ? submodules then spec.submodules else false;
35+
submoduleArg =
36+
let
37+
nixSupportsSubmodules = builtins.compareVersions builtins.nixVersion "2.4" >= 0;
38+
emptyArgWithWarning =
39+
if submodules == true
40+
then
41+
builtins.trace
42+
(
43+
"The niv input \"${name}\" uses submodules "
44+
+ "but your nix's (${builtins.nixVersion}) builtins.fetchGit "
45+
+ "does not support them"
46+
)
47+
{}
48+
else {};
49+
in
50+
if nixSupportsSubmodules
51+
then { inherit submodules; }
52+
else emptyArgWithWarning;
53+
in
54+
builtins.fetchGit
55+
({ url = spec.repo; inherit (spec) rev; inherit ref; } // submoduleArg);
56+
57+
fetch_local = spec: spec.path;
58+
59+
fetch_builtin-tarball = name: throw
60+
''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
61+
$ niv modify ${name} -a type=tarball -a builtin=true'';
62+
63+
fetch_builtin-url = name: throw
64+
''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
65+
$ niv modify ${name} -a type=file -a builtin=true'';
66+
67+
#
68+
# Various helpers
69+
#
70+
71+
# https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695
72+
sanitizeName = name:
73+
(
74+
concatMapStrings (s: if builtins.isList s then "-" else s)
75+
(
76+
builtins.split "[^[:alnum:]+._?=-]+"
77+
((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name)
78+
)
79+
);
80+
81+
# The set of packages used when specs are fetched using non-builtins.
82+
mkPkgs = sources: system:
83+
let
84+
sourcesNixpkgs =
85+
import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; };
86+
hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
87+
hasThisAsNixpkgsPath = <nixpkgs> == ./.;
88+
in
89+
if builtins.hasAttr "nixpkgs" sources
90+
then sourcesNixpkgs
91+
else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then
92+
import <nixpkgs> {}
93+
else
94+
abort
95+
''
96+
Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
97+
add a package called "nixpkgs" to your sources.json.
98+
'';
99+
100+
# The actual fetching function.
101+
fetch = pkgs: name: spec:
102+
103+
if ! builtins.hasAttr "type" spec then
104+
abort "ERROR: niv spec ${name} does not have a 'type' attribute"
105+
else if spec.type == "file" then fetch_file pkgs name spec
106+
else if spec.type == "tarball" then fetch_tarball pkgs name spec
107+
else if spec.type == "git" then fetch_git name spec
108+
else if spec.type == "local" then fetch_local spec
109+
else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
110+
else if spec.type == "builtin-url" then fetch_builtin-url name
111+
else
112+
abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
113+
114+
# If the environment variable NIV_OVERRIDE_${name} is set, then use
115+
# the path directly as opposed to the fetched source.
116+
replace = name: drv:
117+
let
118+
saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name;
119+
ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}";
120+
in
121+
if ersatz == "" then drv else
122+
# this turns the string into an actual Nix path (for both absolute and
123+
# relative paths)
124+
if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}";
125+
126+
# Ports of functions for older nix versions
127+
128+
# a Nix version of mapAttrs if the built-in doesn't exist
129+
mapAttrs = builtins.mapAttrs or (
130+
f: set: with builtins;
131+
listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
132+
);
133+
134+
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
135+
range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1);
136+
137+
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
138+
stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
139+
140+
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
141+
stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
142+
concatMapStrings = f: list: concatStrings (map f list);
143+
concatStrings = builtins.concatStringsSep "";
144+
145+
# https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331
146+
optionalAttrs = cond: as: if cond then as else {};
147+
148+
# fetchTarball version that is compatible between all the versions of Nix
149+
builtins_fetchTarball = { url, name ? null, sha256 }@attrs:
150+
let
151+
inherit (builtins) lessThan nixVersion fetchTarball;
152+
in
153+
if lessThan nixVersion "1.12" then
154+
fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
155+
else
156+
fetchTarball attrs;
157+
158+
# fetchurl version that is compatible between all the versions of Nix
159+
builtins_fetchurl = { url, name ? null, sha256 }@attrs:
160+
let
161+
inherit (builtins) lessThan nixVersion fetchurl;
162+
in
163+
if lessThan nixVersion "1.12" then
164+
fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
165+
else
166+
fetchurl attrs;
167+
168+
# Create the final "sources" from the config
169+
mkSources = config:
170+
mapAttrs (
171+
name: spec:
172+
if builtins.hasAttr "outPath" spec
173+
then abort
174+
"The values in sources.json should not have an 'outPath' attribute"
175+
else
176+
spec // { outPath = replace name (fetch config.pkgs name spec); }
177+
) config.sources;
178+
179+
# The "config" used by the fetchers
180+
mkConfig =
181+
{ sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null
182+
, sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile)
183+
, system ? builtins.currentSystem
184+
, pkgs ? mkPkgs sources system
185+
}: rec {
186+
# The sources, i.e. the attribute set of spec name to spec
187+
inherit sources;
188+
189+
# The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
190+
inherit pkgs;
191+
};
192+
193+
in
194+
mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }

0 commit comments

Comments
 (0)