138 lines
4.3 KiB
Nix
138 lines
4.3 KiB
Nix
# service-evaluator.nix - Pure Nix evaluation logic for service documentation
|
|
{
|
|
nodes,
|
|
pkgs,
|
|
lib,
|
|
...
|
|
}: let
|
|
# Helper to recursively extract option information
|
|
extractOptions = path: options: let
|
|
pathStr = lib.concatStringsSep "." path;
|
|
in
|
|
lib.flatten (lib.mapAttrsToList (
|
|
name: value: let
|
|
currentPath = path ++ [name];
|
|
currentPathStr = lib.concatStringsSep "." currentPath;
|
|
in
|
|
if (value._type or null) == "option"
|
|
then
|
|
# This is an actual NixOS option
|
|
[
|
|
{
|
|
name = currentPathStr;
|
|
type = value.type.description or (builtins.typeOf (value.default or null));
|
|
default = value.default or null;
|
|
defaultText =
|
|
if value ? defaultText
|
|
then value.defaultText.text or null
|
|
else null;
|
|
description = value.description or "No description available";
|
|
example = value.example or null;
|
|
readOnly = value.readOnly or false;
|
|
}
|
|
]
|
|
else if lib.isAttrs value && !(lib.hasAttr "_type" value)
|
|
then
|
|
# This is a nested attribute set, recurse
|
|
extractOptions currentPath value
|
|
else
|
|
# Skip other types
|
|
[]
|
|
)
|
|
options);
|
|
|
|
# Get service options from the first node (they should be the same across nodes)
|
|
firstNode = lib.head (lib.attrValues nodes);
|
|
homelabServices = firstNode.options.homelab.services or {};
|
|
|
|
# Extract all services and their options
|
|
serviceDefinitions =
|
|
lib.mapAttrs (serviceName: serviceOptions: {
|
|
inherit serviceName;
|
|
options = extractOptions [] serviceOptions;
|
|
features = let
|
|
optionNames = map (opt: opt.name) (extractOptions [] serviceOptions);
|
|
in {
|
|
hasMonitoring = lib.any (name: lib.hasPrefix "monitoring" name) optionNames;
|
|
hasLogging = lib.any (name: lib.hasPrefix "logging" name) optionNames;
|
|
hasProxy = lib.any (name: lib.hasPrefix "proxy" name) optionNames;
|
|
};
|
|
})
|
|
homelabServices;
|
|
|
|
# Also get all services that exist in actual configurations (for deployment info)
|
|
allConfiguredServices = lib.unique (lib.flatten (lib.mapAttrsToList (
|
|
nodeName: node:
|
|
if (node.config.homelab.enable or false)
|
|
then lib.attrNames (node.config.homelab.services or {})
|
|
else []
|
|
)
|
|
nodes));
|
|
|
|
# For each service, get deployment info
|
|
serviceDeployments = lib.listToAttrs (map (serviceName: {
|
|
name = serviceName;
|
|
value =
|
|
lib.foldl (
|
|
acc: nodeName: let
|
|
node = nodes.${nodeName};
|
|
serviceConfig = node.config.homelab.services.${serviceName} or null;
|
|
isEnabled =
|
|
if serviceConfig != null
|
|
then serviceConfig.enable or false
|
|
else false;
|
|
in
|
|
if serviceConfig != null
|
|
then
|
|
acc
|
|
// {
|
|
totalNodes = acc.totalNodes + 1;
|
|
enabledNodes =
|
|
acc.enabledNodes
|
|
+ (
|
|
if isEnabled
|
|
then 1
|
|
else 0
|
|
);
|
|
nodeNames = acc.nodeNames ++ [nodeName];
|
|
enabledNodeNames =
|
|
acc.enabledNodeNames
|
|
++ (
|
|
if isEnabled
|
|
then [nodeName]
|
|
else []
|
|
);
|
|
}
|
|
else acc
|
|
) {
|
|
totalNodes = 0;
|
|
enabledNodes = 0;
|
|
nodeNames = [];
|
|
enabledNodeNames = [];
|
|
} (lib.attrNames nodes);
|
|
})
|
|
allConfiguredServices);
|
|
|
|
# Combine service definitions with deployment info
|
|
servicesWithDeployment =
|
|
lib.mapAttrs (
|
|
serviceName: serviceData:
|
|
serviceData
|
|
// {
|
|
deployment =
|
|
serviceDeployments.${
|
|
serviceName
|
|
} or {
|
|
totalNodes = 0;
|
|
enabledNodes = 0;
|
|
nodeNames = [];
|
|
enabledNodeNames = [];
|
|
};
|
|
}
|
|
)
|
|
serviceDefinitions;
|
|
in {
|
|
services = servicesWithDeployment;
|
|
totalServices = lib.length (lib.attrNames servicesWithDeployment);
|
|
allConfiguredServices = allConfiguredServices;
|
|
}
|