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