diff --git a/default.nix b/default.nix index f337a6a..d4d964a 100644 --- a/default.nix +++ b/default.nix @@ -1,14 +1,21 @@ { pkgs ? import {}, lib ? pkgs.lib }: -let - lib' = lib.extend (lib: self: import ./lib.nix { inherit lib pkgs; }); +with lib; - specialArgs' = { +let + kubenixLib = import ./lib { inherit lib pkgs; }; + lib' = lib.extend (lib: self: import ./lib/extra.nix { inherit lib pkgs; }); + + defaultSpecialArgs = { inherit kubenix; }; - evalKubernetesModules = {module ? null, modules ? [module], specialArgs ? specialArgs', ...}@attrs: let - attrs' = lib.filterAttrs (n: _: n != "module") attrs; + evalModules = { + module ? null, + modules ? [module], + specialArgs ? defaultSpecialArgs, ... + }@attrs: let + attrs' = filterAttrs (n: _: n != "module") attrs; in lib'.evalModules (attrs' // { inherit specialArgs modules; args = { @@ -17,14 +24,11 @@ let }; }); - buildResources = args: - (evalKubernetesModules args).config.kubernetes.generated; - modules = import ./modules; kubenix = { - inherit evalKubernetesModules buildResources kubenix; + inherit evalModules kubenix; - lib = lib'; + lib = kubenixLib; } // modules; in kubenix diff --git a/lib/default.nix b/lib/default.nix new file mode 100644 index 0000000..266b6ed --- /dev/null +++ b/lib/default.nix @@ -0,0 +1,6 @@ +{ lib, pkgs }: + +(import ./extra.nix { inherit pkgs lib; }) // { + k8s = import ./k8s.nix { inherit lib; }; + docker = import ./docker.nix { inherit lib pkgs; }; +} diff --git a/lib/docker.nix b/lib/docker.nix new file mode 100644 index 0000000..8e7451f --- /dev/null +++ b/lib/docker.nix @@ -0,0 +1,15 @@ +{ lib, pkgs }: + +with lib; + +{ + copyDockerImages = { images, dest, args ? "" }: + pkgs.writeScriptBin "copy-docker-images" (concatMapStrings (image: '' + #!${pkgs.bash}/bin/bash + + set -e + + echo "copying ${image.imageName}:${image.imageTag}" + ${pkgs.skopeo}/bin/skopeo copy ${args} $@ docker-archive:${image} ${dest}/${image.imageName}:${image.imageTag} + '') images); +} diff --git a/lib.nix b/lib/extra.nix similarity index 83% rename from lib.nix rename to lib/extra.nix index e1f832f..a165d41 100644 --- a/lib.nix +++ b/lib/extra.nix @@ -1,9 +1,8 @@ -{lib, pkgs}: +{ lib, pkgs }: with lib; -let -in rec { +rec { moduleToAttrs = value: if isAttrs value then mapAttrs (n: v: moduleToAttrs v) (filterAttrs (n: v: !(hasPrefix "_" n) && v != null) value) @@ -39,9 +38,8 @@ in rec { exp = base: exp: foldr (value: acc: acc * base) 1 (range 1 exp); - octalToDecimal = value: - (foldr (char: acc: { - i = acc.i + 1; - value = acc.value + (toInt char) * (exp 8 acc.i); - }) {i = 0; value = 0;} (stringToCharacters value)).value; + octalToDecimal = value: (foldr (char: acc: { + i = acc.i + 1; + value = acc.value + (toInt char) * (exp 8 acc.i); + }) {i = 0; value = 0;} (stringToCharacters value)).value; } diff --git a/lib/k8s.nix b/lib/k8s.nix new file mode 100644 index 0000000..da7729c --- /dev/null +++ b/lib/k8s.nix @@ -0,0 +1,54 @@ +{ lib }: + +with lib; + +rec { + mkSecretOption = {description ? "", default ? null}: mkOption { + inherit description; + type = types.nullOr (types.submodule { + options = { + name = mkOption { + description = "Name of the secret where secret is stored"; + type = types.str; + }; + + key = mkOption { + description = "Name of the key where secret is stored"; + type = types.str; + }; + }; + + config = mkDefault (if default == null then {} else default); + }); + default = {}; + }; + + secretToEnv = value: { + valueFrom.secretKeyRef = { + inherit (value) name key; + }; + }; + + # Creates kubernetes list from a list of kubernetes objects + mkList = { items, labels ? {} }: { + kind = "List"; + apiVersion = "v1"; + + inherit items labels; + }; + + # Creates hashed kubernetes list from a list of kubernetes objects + mkHashedList = { items, labels ? {} }: let + hash = builtins.hashString "sha1" (builtins.toJSON items); + + labeledItems = map (item: recursiveUpdate item { + metadata.labels."kubenix/hash" = hash; + }) items; + + in mkList { + items = labeledItems; + labels = { + "kubenix/hash" = hash; + } // labels; + }; +} diff --git a/modules/k8s/default.nix b/modules/k8s/default.nix index 340d7b9..49a0070 100644 --- a/modules/k8s/default.nix +++ b/modules/k8s/default.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ config, lib, pkgs, k8s, ... }: with lib; @@ -32,12 +32,6 @@ let ) resources ); - toKubernetesList = resources: { - kind = "List"; - apiVersion = "v1"; - items = resources; - }; - apiOptions = { config, ... }: { options = { definitions = mkOption { @@ -114,7 +108,8 @@ let indexOf = lst: value: head (filter (v: v != -1) (imap0 (i: v: if v == value then i else -1) lst)); in { - imports = [./lib.nix]; + # expose k8s helper methods through arg in modules + config._module.args.k8s = import ../../lib/k8s.nix { inherit lib; }; options.kubernetes.version = mkOption { description = "Kubernetes version to use"; @@ -222,7 +217,7 @@ in { }) cfg.customResources; options.kubernetes.objects = mkOption { - description = "Attribute set of kubernetes objects"; + description = "List of generated kubernetes objects"; type = types.listOf types.attrs; apply = items: sort (r1: r2: if elem r1.kind cfg.resourceOrder && elem r2.kind cfg.resourceOrder @@ -239,25 +234,11 @@ in { ) cfg.api.resources); options.kubernetes.generated = mkOption { + description = "Generated kubernetes list object"; type = types.attrs; - description = "Generated json file"; }; - config.kubernetes.generated = let - kubernetesList = toKubernetesList cfg.objects; - - hashedList = kubernetesList // { - labels."kubenix/build" = cfg.hash; - items = map (resource: recursiveUpdate resource { - metadata.labels."kubenix/build" = cfg.hash; - }) kubernetesList.items; - }; - in hashedList; - - options.kubernetes.hash = mkOption { - type = types.str; - description = "Output hash"; + config.kubernetes.generated = k8s.mkHashedList { + items = config.kubernetes.objects; }; - - config.kubernetes.hash = builtins.hashString "sha1" (builtins.toJSON cfg.objects); } diff --git a/modules/k8s/lib.nix b/modules/k8s/lib.nix deleted file mode 100644 index be78877..0000000 --- a/modules/k8s/lib.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ lib, ... }: - -with lib; - -let - k8s = { - mkSecretOption = {description ? "", default ? null}: mkOption { - inherit description; - type = types.nullOr (types.submodule { - options = { - name = mkOption { - description = "Name of the secret where secret is stored"; - type = types.str; - }; - - key = mkOption { - description = "Name of the key where secret is stored"; - type = types.str; - }; - }; - - config = mkDefault (if default == null then {} else default); - }); - default = {}; - }; - - secretToEnv = value: { - valueFrom.secretKeyRef = { - inherit (value) name key; - }; - }; - }; -in { - _module.args.k8s = k8s; -} diff --git a/modules/testing/default.nix b/modules/testing/default.nix index 80eafcc..6027149 100644 --- a/modules/testing/default.nix +++ b/modules/testing/default.nix @@ -71,7 +71,7 @@ let nixosTesting.makeTest { inherit name; - nodes.kube = { config, pkgs, lib, nodes, ... }: { + nodes.kube = { config, pkgs, nodes, ... }: { imports = [ kubernetesBaseConfig ]; services.kubernetes = { roles = ["master" "node"]; @@ -113,14 +113,14 @@ let config._module.args.test = config; }] ++ cfg.defaults; - test = (kubenix.evalKubernetesModules { + test = (kubenix.evalModules { check = false; inherit modules; }).config.test; evaled = if test.enable - then builtins.trace "testing ${test.name}" (kubenix.evalKubernetesModules { + then builtins.trace "testing ${test.name}" (kubenix.evalModules { inherit modules; }) else {success = false;}; diff --git a/tests/default.nix b/tests/default.nix index f32926f..70c6cd8 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -1,6 +1,6 @@ { pkgs ? import {} -, kubenix ? import ../. {inherit pkgs;} -, lib ? kubenix.lib +, lib ? pkgs.lib +, kubenix ? import ../. { inherit pkgs lib; } , k8sVersions ? ["1.7" "1.8" "1.9" "1.10" "1.11" "1.12" "1.13"] # whether any testing error should throw an error @@ -14,7 +14,7 @@ let tests = listToAttrs (map (version: let version' = replaceStrings ["."] ["_"] version; - in nameValuePair "v${version'}" (evalModules { + in nameValuePair "v${version'}" (kubenix.evalModules { modules = [ kubenix.testing diff --git a/tests/helm/simple.nix b/tests/helm/simple.nix index 7070b0e..139c2a7 100644 --- a/tests/helm/simple.nix +++ b/tests/helm/simple.nix @@ -1,7 +1,7 @@ -{ config, lib, test, pkgs, kubenix, k8s, helm, ... }: +{ config, lib, test, pkgs, kubenix, helm, ... }: with lib; -with k8s; +with kubenix.lib; with pkgs.dockerTools; let @@ -56,7 +56,7 @@ in { $kube->waitUntilSucceeds("docker load < ${postgresql}"); $kube->waitUntilSucceeds("docker load < ${postgresqlExporter}"); $kube->waitUntilSucceeds("docker load < ${minideb}"); - $kube->waitUntilSucceeds("kubectl apply -f ${toYAML config.kubernetes.generated}"); + $kube->waitUntilSucceeds("kubectl apply -f ${toYAML config.kubernetes.objects}"); $kube->waitUntilSucceeds("PGPASSWORD=postgres ${pkgs.postgresql}/bin/psql -h app-psql-postgresql.test.svc.cluster.local -U postgres -l"); ''; };