1# Tests whether container images are imported and auto deploying Helm charts,
2# including the bundled traefik, work
3import ../make-test-python.nix (
4 {
5 k3s,
6 lib,
7 pkgs,
8 ...
9 }:
10 let
11 testImageEnv = pkgs.buildEnv {
12 name = "k3s-pause-image-env";
13 paths = with pkgs; [
14 busybox
15 hello
16 ];
17 };
18 testImage = pkgs.dockerTools.buildImage {
19 name = "test.local/test";
20 tag = "local";
21 # Slightly reduces the time needed to import image
22 compressor = "zstd";
23 copyToRoot = testImageEnv;
24 };
25 # pack the test helm chart as a .tgz archive
26 package =
27 pkgs.runCommand "k3s-test-chart.tgz"
28 {
29 nativeBuildInputs = [ pkgs.kubernetes-helm ];
30 }
31 ''
32 helm package ${./k3s-test-chart}
33 mv ./*.tgz $out
34 '';
35 # The common Helm chart that is used in this test
36 testChart = {
37 inherit package;
38 values = {
39 runCommand = "hello";
40 image = {
41 repository = testImage.imageName;
42 tag = testImage.imageTag;
43 };
44 };
45 };
46 in
47 {
48 name = "${k3s.name}-auto-deploy-helm";
49 meta.maintainers = lib.teams.k3s.members;
50 nodes.machine =
51 { pkgs, ... }:
52 {
53 # k3s uses enough resources the default vm fails.
54 virtualisation = {
55 memorySize = 1536;
56 diskSize = 4096;
57 };
58 environment.systemPackages = [ pkgs.yq-go ];
59 services.k3s = {
60 enable = true;
61 package = k3s;
62 # Slightly reduce resource usage
63 extraFlags = [
64 "--disable coredns"
65 "--disable local-storage"
66 "--disable metrics-server"
67 "--disable servicelb"
68 ];
69 images = [
70 # Provides the k3s Helm controller
71 k3s.airgap-images
72 testImage
73 ];
74 autoDeployCharts = {
75 # regular test chart that should get installed
76 hello = testChart;
77 # disabled chart that should not get installed
78 disabled = testChart // {
79 enable = false;
80 };
81 # chart with values set via YAML file
82 values-file = testChart // {
83 # Remove unsafeDiscardStringContext workaround when Nix can convert a string to a path
84 # https://github.com/NixOS/nix/issues/12407
85 values = /.
86 + builtins.unsafeDiscardStringContext (
87 builtins.toFile "k3s-test-chart-values.yaml" ''
88 runCommand: "echo 'Hello, file!'"
89 image:
90 repository: test.local/test
91 tag: local
92 ''
93 );
94 };
95 # advanced chart that should get installed in the "test" namespace with a custom
96 # timeout and overridden values
97 advanced = testChart // {
98 # create the "test" namespace via extraDeploy for testing
99 extraDeploy = [
100 {
101 apiVersion = "v1";
102 kind = "Namespace";
103 metadata.name = "test";
104 }
105 ];
106 extraFieldDefinitions = {
107 spec = {
108 # overwrite chart values
109 valuesContent = ''
110 runCommand: "echo 'advanced hello'"
111 image:
112 repository: ${testImage.imageName}
113 tag: ${testImage.imageTag}
114 '';
115 # overwrite the chart namespace
116 targetNamespace = "test";
117 # set a custom timeout
118 timeout = "69s";
119 };
120 };
121 };
122 };
123 };
124 };
125
126 testScript = # python
127 ''
128 import json
129
130 machine.wait_for_unit("k3s")
131 # check existence/absence of chart manifest files
132 machine.succeed("test -e /var/lib/rancher/k3s/server/manifests/hello.yaml")
133 machine.succeed("test ! -e /var/lib/rancher/k3s/server/manifests/disabled.yaml")
134 machine.succeed("test -e /var/lib/rancher/k3s/server/manifests/values-file.yaml")
135 machine.succeed("test -e /var/lib/rancher/k3s/server/manifests/advanced.yaml")
136 # check that the timeout is set correctly, select only the first doc in advanced.yaml
137 advancedManifest = json.loads(machine.succeed("yq -o json 'select(di == 0)' /var/lib/rancher/k3s/server/manifests/advanced.yaml"))
138 t.assertEqual(advancedManifest["spec"]["timeout"], "69s", "unexpected value for spec.timeout")
139 # wait for test jobs to complete
140 machine.wait_until_succeeds("kubectl wait --for=condition=complete job/hello", timeout=180)
141 machine.wait_until_succeeds("kubectl wait --for=condition=complete job/values-file", timeout=180)
142 machine.wait_until_succeeds("kubectl -n test wait --for=condition=complete job/advanced", timeout=180)
143 # check output of test jobs
144 hello_output = machine.succeed("kubectl logs -l batch.kubernetes.io/job-name=hello")
145 values_file_output = machine.succeed("kubectl logs -l batch.kubernetes.io/job-name=values-file")
146 advanced_output = machine.succeed("kubectl -n test logs -l batch.kubernetes.io/job-name=advanced")
147 # strip the output to remove trailing whitespaces
148 t.assertEqual(hello_output.rstrip(), "Hello, world!", "unexpected output of hello job")
149 t.assertEqual(values_file_output.rstrip(), "Hello, file!", "unexpected output of values file job")
150 t.assertEqual(advanced_output.rstrip(), "advanced hello", "unexpected output of advanced job")
151 # wait for bundled traefik deployment
152 machine.wait_until_succeeds("kubectl -n kube-system rollout status deployment traefik", timeout=180)
153 '';
154 }
155)