Created
April 18, 2019 09:21
-
-
Save sdorminey/c269d04cb0df0fb42caa00cdb7a5a09a to your computer and use it in GitHub Desktop.
Kubenix, man...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[mabel ~/blorg] nix-build -A shell --show-trace | |
error: while evaluating the attribute 'buildInputs' of the derivation 'nix-shell' at /nix/store/x5pr7imylmp2j9 | |
while evaluating the attribute 'text' of the derivation 'deploy-to-minikube' at /nix/store/x5pr7imylmp2j9rbw9b | |
while evaluating 'escapeShellArg' at /nix/store/x5pr7imylmp2j9rbw9b4394yvd60aqa0-nixpkgs-19.09pre174594.0c0954 | |
while evaluating the attribute 'kubernetes.objects' at undefined position: | |
while evaluating anonymous function at /nix/store/x5pr7imylmp2j9rbw9b4394yvd60aqa0-nixpkgs-19.09pre174594.0c09 | |
while evaluating the attribute 'value' at /nix/store/x5pr7imylmp2j9rbw9b4394yvd60aqa0-nixpkgs-19.09pre174594.0 | |
while evaluating the option `kubernetes.objects': | |
while evaluating 'apply' at /home/mabel/blorg/kubenix/modules/k8s.nix:255:15, called from /nix/store/x5pr7imyl | |
while evaluating 'unique' at /nix/store/x5pr7imylmp2j9rbw9b4394yvd60aqa0-nixpkgs-19.09pre174594.0c0954781e2/ni | |
while evaluating 'unique' at /nix/store/x5pr7imylmp2j9rbw9b4394yvd60aqa0-nixpkgs-19.09pre174594.0c0954781e2/ni | |
.0c0954781e2/nixpkgs/lib/lists.nix:636:14: | |
while evaluating 'unique' at /nix/store/x5pr7imylmp2j9rbw9b4394yvd60aqa0-nixpkgs-19.09pre174594.0c0954781e2/ni | |
.0c0954781e2/nixpkgs/lib/lists.nix:636:14: | |
while evaluating 'unique' at /nix/store/x5pr7imylmp2j9rbw9b4394yvd60aqa0-nixpkgs-19.09pre174594.0c0954781e2/ni | |
.0c0954781e2/nixpkgs/lib/lists.nix:636:14: | |
while evaluating 'unique' at /nix/store/x5pr7imylmp2j9rbw9b4394yvd60aqa0-nixpkgs-19.09pre174594.0c0954781e2/ni | |
.0c0954781e2/nixpkgs/lib/lists.nix:636:14: | |
while evaluating 'unique' at /nix/store/x5pr7imylmp2j9rbw9b4394yvd60aqa0-nixpkgs-19.09pre174594.0c0954781e2/ni | |
.0c0954781e2/nixpkgs/lib/lists.nix:636:14: | |
while evaluating 'unique' at /nix/store/x5pr7imylmp2j9rbw9b4394yvd60aqa0-nixpkgs-19.09pre174594.0c0954781e2/ni | |
.0c0954781e2/nixpkgs/lib/lists.nix:636:14: | |
while evaluating anonymous function at /nix/store/x5pr7imylmp2j9rbw9b4394yvd60aqa0-nixpkgs-19.09pre174594.0c09 | |
while evaluating anonymous function at /home/mabel/blorg/kubenix/modules/k8s.nix:23:15, called from undefined | |
while evaluating 'moduleToAttrs' at /home/mabel/blorg/kubenix/modules/k8s.nix:18:19, called from /home/mabel/b | |
while evaluating anonymous function at /nix/store/x5pr7imylmp2j9rbw9b4394yvd60aqa0-nixpkgs-19.09pre174594.0c09 | |
while evaluating anonymous function at /home/mabel/blorg/kubenix/modules/generated/v1.13.nix:7554:65, called f | |
x:234:16: | |
while evaluating the attribute 'HYDRA_DBI' at undefined position: | |
while evaluating anonymous function at /nix/store/x5pr7imylmp2j9rbw9b4394yvd60aqa0-nixpkgs-19.09pre174594.0c09 | |
while evaluating the attribute 'value' at /nix/store/x5pr7imylmp2j9rbw9b4394yvd60aqa0-nixpkgs-19.09pre174594.0 | |
while evaluating anonymous function at /nix/store/x5pr7imylmp2j9rbw9b4394yvd60aqa0-nixpkgs-19.09pre174594.0c09 | |
.09pre174594.0c0954781e2/nixpkgs/lib/modules.nix:370:19: | |
The option value `kubernetes.api.deployments.hydra.spec.template.spec.containers.hydra-eval.env.HYDRA_DBI' in |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ config | |
, lib | |
, pkgs | |
, kubenix | |
, ... | |
}: | |
with lib; | |
with kubenix.lib; | |
let | |
dbHostName = config.kubernetes.api.deployments.postgres.spec.template.spec.hostname; | |
HYDRA_DBI = "dbi:Pg:dbname=hydra;host=${dbHostName};user=hydra"; | |
mkContainer = container-name: { | |
image = config.docker.images."${container-name}".path; | |
imagePullPolicy = "IfNotPresent"; | |
env = { | |
PGPASSWORD = k8s.secretToEnv { name = "pgpassword"; key = "value"; }; | |
HYDRA_DBI = "dbi:Pg:dbname=hydra;host=${dbHostName};user=hydra"; | |
}; | |
volumeMounts."/data".name = container-name; | |
}; | |
in let name = "hydra"; in { | |
imports = with kubenix.modules; [ k8s docker ]; | |
options = { | |
dbHostName = mkOption { | |
type = types.str; | |
default = "postgres"; | |
}; | |
}; | |
config = { | |
submodule = { | |
name = "hydra"; | |
version = "0.0.1"; | |
description = ""; | |
}; | |
kubernetes.api.deployments.hydra = { | |
spec = { | |
replicas = 1; | |
selector.matchLabels.app = name; | |
template = { | |
metadata.labels.app = name; | |
spec = { | |
hostname = name; | |
containers.hydra-www = { | |
image = config.docker.images.hydra-www.path; | |
ports = [ { containerPort = 3000; } ]; | |
imagePullPolicy = "IfNotPresent"; | |
env = { | |
PGPASSWORD = k8s.secretToEnv { name = "pgpassword"; key = "value"; }; | |
ROOT_INITIAL_PASSWORD = k8s.secretToEnv { name = "pgpassword"; key = "value"; }; | |
HYDRA_DBI.value = "dbi:Pg:dbname=hydra;host=${dbHostName};user=hydra"; | |
}; | |
volumeMounts."/data".name = container-name; | |
}; | |
containers.hydra-eval = mkContainer "hydra-eval"; | |
containers.hydra-runner = mkContainer "hydra-runner"; | |
volumes.hydra-www.emptyDir = { name = "hydra-www"; }; | |
volumes.hydra-eval.emptyDir = { name = "hydra-eval"; }; | |
volumes.hydra-runner.emptyDir = { name = "hydra-runner"; }; | |
}; | |
}; | |
}; | |
}; | |
kubernetes.api.services.hydra = { | |
spec = { | |
type = "NodePort"; | |
ports = [{ | |
name = name; | |
port = 3000; | |
}]; | |
selector.app = name; | |
}; | |
}; | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# K8S module defines kubernetes definitions for kubenix | |
{ config, lib, pkgs, k8s, ... }: | |
with lib; | |
let | |
cfg = config.kubernetes; | |
getDefaults = resource: group: version: kind: | |
catAttrs "default" (filter (default: | |
(resource == null || default.resource == null || default.resource == resource) && | |
(default.group == null || default.group == group) && | |
(default.version == null || default.version == version) && | |
(default.kind == null || default.kind == kind) | |
) cfg.api.defaults); | |
moduleToAttrs = value: | |
if isAttrs value | |
then mapAttrs (n: v: moduleToAttrs v) (filterAttrs (n: v: v != null && !(hasPrefix "_" n)) value) | |
else if isList value | |
then map (v: moduleToAttrs v) value | |
else value; | |
flattenResources = resources: flatten ( | |
mapAttrsToList (groupName: versions: | |
mapAttrsToList (versionName: kinds: | |
builtins.trace versionName kinds | |
) versions | |
) resources | |
); | |
apiOptions = { config, ... }: { | |
options = { | |
definitions = mkOption { | |
description = "Attribute set of kubernetes definitions"; | |
}; | |
defaults = mkOption { | |
description = "Kubernetes defaults to apply to resources"; | |
type = types.listOf (types.submodule ({config, ...}: { | |
options = { | |
resource = mkOption { | |
description = "Resource to apply default to (all by default)"; | |
type = types.nullOr types.str; | |
default = null; | |
}; | |
group = mkOption { | |
description = "Group to apply default to (all by default)"; | |
type = types.nullOr types.str; | |
default = null; | |
}; | |
version = mkOption { | |
description = "Version to apply default to (all by default)"; | |
type = types.nullOr types.str; | |
default = null; | |
}; | |
kind = mkOption { | |
description = "Kind to apply default to (all by default)"; | |
type = types.nullOr types.str; | |
default = null; | |
}; | |
propagate = mkOption { | |
description = "Whether to propagate default"; | |
type = types.bool; | |
default = false; | |
}; | |
default = mkOption { | |
description = "Default to apply"; | |
type = types.unspecified; | |
default = {}; | |
}; | |
}; | |
})); | |
default = []; | |
}; | |
resources = mkOption { | |
type = types.listOf (types.submodule { | |
options = { | |
group = mkOption { | |
description = "Resoruce group"; | |
type = types.str; | |
}; | |
version = mkOption { | |
description = "Resoruce version"; | |
type = types.str; | |
}; | |
kind = mkOption { | |
description = "Resource kind"; | |
type = types.str; | |
}; | |
resource = mkOption { | |
description = "Resource name"; | |
type = types.str; | |
}; | |
}; | |
}); | |
default = []; | |
}; | |
}; | |
}; | |
indexOf = lst: value: | |
head (filter (v: v != -1) (imap0 (i: v: if v == value then i else -1) lst)); | |
customResourceOptions = map (cr: {config, ...}: let | |
module = { name, ... }: { | |
imports = getDefaults cr.resource cr.group cr.version cr.kind; | |
options = { | |
apiVersion = mkOption { | |
description = "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources"; | |
type = types.nullOr types.str; | |
}; | |
kind = mkOption { | |
description = "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds"; | |
type = types.nullOr types.str; | |
}; | |
metadata = mkOption { | |
description = "Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata."; | |
type = types.nullOr (types.submodule config.definitions."io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta"); | |
}; | |
spec = mkOption { | |
description = "Module spec"; | |
type = types.either types.attrs (types.submodule cr.module); | |
default = {}; | |
}; | |
}; | |
config = { | |
apiVersion = mkOptionDefault "${cr.group}/${cr.version}"; | |
kind = mkOptionDefault cr.kind; | |
metadata.name = mkOptionDefault name; | |
}; | |
}; | |
in if cr.alias != null then { | |
options.${cr.group}.${cr.version}.${cr.kind} = mkOption { | |
description = cr.description; | |
type = types.attrsOf (types.submodule module); | |
default = {}; | |
}; | |
options.${cr.alias} = mkOption { | |
description = cr.description; | |
type = types.attrsOf (types.submodule module); | |
default = {}; | |
}; | |
config.${cr.group}.${cr.version}.${cr.kind} = config.${cr.alias}; | |
} else { | |
options.${cr.group}.${cr.version}.${cr.kind} = mkOption { | |
description = cr.description; | |
type = types.attrsOf (types.submodule module); | |
default = {}; | |
}; | |
}) cfg.customResources; | |
in { | |
imports = [ ./base.nix ./submodules.nix ]; | |
options.kubernetes = { | |
version = mkOption { | |
description = "Kubernetes version to use"; | |
type = types.enum ["1.7" "1.8" "1.9" "1.10" "1.11" "1.12" "1.13"]; | |
default = "1.13"; | |
}; | |
namespace = mkOption { | |
description = "Default namespace where to deploy kubernetes resources"; | |
type = types.str; | |
default = "default"; | |
}; | |
resourceOrder = mkOption { | |
description = "Preffered resource order"; | |
type = types.listOf types.str; | |
default = [ | |
"CustomResourceDefinition" | |
"Namespace" | |
]; | |
}; | |
api = mkOption { | |
type = types.submodule { | |
imports = [ | |
(./generated + ''/v'' + cfg.version + ".nix") | |
apiOptions | |
] ++ customResourceOptions; | |
}; | |
default = {}; | |
}; | |
customResources = mkOption { | |
default = []; | |
description = "List of custom resource definitions to make API for"; | |
type = types.listOf (types.submodule ({config, ...}: { | |
options = { | |
group = mkOption { | |
description = "Custom resource definition group"; | |
type = types.str; | |
}; | |
version = mkOption { | |
description = "Custom resource definition version"; | |
type = types.str; | |
}; | |
kind = mkOption { | |
description = "Custom resource definition kind"; | |
type = types.str; | |
}; | |
resource = mkOption { | |
description = "Custom resource definition resource name"; | |
type = types.nullOr types.str; | |
default = null; | |
}; | |
description = mkOption { | |
description = "Custom resource definition description"; | |
type = types.str; | |
default = ""; | |
}; | |
module = mkOption { | |
description = "Custom resource definition module"; | |
type = types.unspecified; | |
default = {}; | |
}; | |
alias = mkOption { | |
description = "Alias to create for API"; | |
type = types.nullOr types.str; | |
default = null; | |
}; | |
}; | |
})); | |
}; | |
objects = mkOption { | |
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 | |
then indexOf cfg.resourceOrder r1.kind < indexOf cfg.resourceOrder r2.kind | |
else if elem r1.kind cfg.resourceOrder then true else false | |
) (unique items); | |
default = []; | |
}; | |
generated = mkOption { | |
description = "Generated kubernetes list object"; | |
type = types.attrs; | |
}; | |
}; | |
config = { | |
# expose k8s helper methods as module argument | |
_module.args.k8s = import ../lib/k8s.nix { inherit lib; }; | |
_module.features = [ "k8s" ]; | |
kubernetes.api.resources = map (cr: { | |
inherit (cr) group version kind resource; | |
}) cfg.customResources; | |
kubernetes.objects = mkMerge [ | |
# gvk resources | |
(flatten (map (gvk: | |
mapAttrsToList (name: resource: | |
moduleToAttrs resource | |
) cfg.api.${gvk.group}.${gvk.version}.${gvk.kind} | |
) cfg.api.resources)) | |
(flatten (map (gvk: | |
mapAttrsToList (name: resource: | |
moduleToAttrs resource | |
) cfg.api.${gvk.resource} | |
) cfg.api.resources)) | |
# passthru of child kubernetes objects if passthru is enabled on submodule | |
# and submodule has k8s module loaded | |
(flatten (mapAttrsToList (_: submodule: | |
optionals | |
(submodule.passthru.enable && (elem "k8s" submodule.config._module.features)) | |
submodule.config.kubernetes.objects | |
) config.submodules.instances)) | |
]; | |
kubernetes.generated = k8s.mkHashedList { | |
items = config.kubernetes.objects; | |
labels."kubenix/project-name" = config.kubenix.project; | |
}; | |
kubernetes.api.defaults = [{ | |
default = { | |
metadata.namespace = mkDefault config.kubernetes.namespace; | |
metadata.labels = mkMerge [ | |
{ | |
"kubenix/project-name" = config.kubenix.project; | |
} | |
# if we are inside submodule, define additional labels | |
(mkIf (elem "submodule" config._module.features) { | |
"kubenix/module-name" = config.submodule.name; | |
"kubenix/module-version" = config.submodule.version; | |
}) | |
]; | |
}; | |
}]; | |
submodules.defaults = [{ | |
features = [ "k8s" ]; | |
default = { config, name, ... }: { | |
# propagate kubernetes version and namespace | |
kubernetes.version = mkDefault cfg.version; | |
kubernetes.namespace = mkDefault cfg.namespace; | |
# propagate defaults if default propagation is enabled | |
kubernetes.api.defaults = filter (default: default.propagate) cfg.api.defaults; | |
}; | |
}]; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment