mirror of
https://github.com/gensokyo-zone/infrastructure.git
synced 2026-02-09 12:29:19 -08:00
feat: refactoring + system types
This commit is contained in:
parent
a0f9d0ab48
commit
9794026f6c
36 changed files with 653 additions and 537 deletions
|
|
@ -1,4 +1,4 @@
|
|||
{ tf, target, name, meta, config, lib, ... }:
|
||||
{ tf, target, name, meta, pkgs, config, lib, ... }:
|
||||
|
||||
/*
|
||||
This module:
|
||||
|
|
@ -15,9 +15,12 @@ let
|
|||
name = "unmergedValues";
|
||||
merge = loc: defs: map (def: def.value) defs;
|
||||
};
|
||||
in
|
||||
{
|
||||
options.deploy.tf = mkOption {
|
||||
in {
|
||||
options = {
|
||||
out = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
deploy.tf = mkOption {
|
||||
type = types.submodule {
|
||||
inherit (unmerged) freeformType;
|
||||
|
||||
|
|
@ -43,44 +46,68 @@ in
|
|||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = let
|
||||
functionlessConfig = lib.removeAttrs config ["out" "_module" "platform" "deploy"];
|
||||
functionlessConfig = lib.removeAttrs config ["out" "_module" "platform" "deploy" "secrets"];
|
||||
mutatedConfig = functionlessConfig // (optionalAttrs (config.platform != {}) {
|
||||
${functionlessConfig.esphome.platform} = config.platform;
|
||||
});
|
||||
jsonConfig = builtins.toJSON mutatedConfig;
|
||||
secretsMap = mapAttrs (name: _: tf.variables."${config.esphome.name}-secret-${name}".ref) config.secrets;
|
||||
secretsFile = builtins.toJSON secretsMap;
|
||||
closureConfig = pkgs.writeText "${functionlessConfig.esphome.name}.json" jsonConfig;
|
||||
closure-upload = pkgs.writeShellScriptBin "${functionlessConfig.esphome.name}-upload" ''
|
||||
'';
|
||||
in {
|
||||
in mkMerge [
|
||||
{
|
||||
_module.args.tf = mapNullable (target: target.tf) target;
|
||||
out = jsonConfig;
|
||||
deploy.tf = {
|
||||
attrs = [ "import" "imports" "out" "attrs" "triggers" ];
|
||||
import = genAttrs cfg.tf.imports (target: meta.deploy.targets.${target}.tf);
|
||||
out.set = removeAttrs cfg.tf cfg.tf.attrs;
|
||||
triggers = {
|
||||
compile = {
|
||||
upload = {
|
||||
system = config.out;
|
||||
};
|
||||
};
|
||||
resources = {
|
||||
"${name}-secrets" = {
|
||||
provider = "local";
|
||||
type = "file";
|
||||
inputs = {
|
||||
filename = "${tf.terraform.dataDir}/esphome-${name}-secrets.json";
|
||||
content = secretsFile;
|
||||
};
|
||||
};
|
||||
"${name}-upload" = {
|
||||
provider = "null";
|
||||
type = "resource";
|
||||
inputs.triggers = cfg.tf.triggers.compile;
|
||||
inputs.triggers = cfg.tf.triggers.upload;
|
||||
provisioners = [
|
||||
{
|
||||
type = "local-exec";
|
||||
local-exec.command = ''
|
||||
${pkgs.esphome}/bin/esphome upload ${closureConfig}
|
||||
${pkgs.esphome}/bin/esphome compile ${closureConfig} ${tf.resources."${name}-secrets".refAttr "filename"}
|
||||
${pkgs.esphome}/bin/esphome upload ${closureConfig} --device ${name}.local
|
||||
'';
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
_module.args.tf = mapNullable (target: target.tf) target;
|
||||
};
|
||||
}
|
||||
(mkIf (config.secrets != {}) {
|
||||
deploy.tf.variables = mapAttrs' (name: content: let
|
||||
parts = if hasInfix "#" content then splitString "#" content else content;
|
||||
field = head (reverseList parts);
|
||||
path = if length parts > 1 then head parts else "password";
|
||||
in nameValuePair "${config.esphome.name}-secret-${name}" ({
|
||||
value.shellCommand = "bitw get ${path} -f ${field}";
|
||||
type = "string";
|
||||
sensitive = true;
|
||||
})
|
||||
) config.secrets;
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
{ name, config, meta, pkgs, lib, ... }: with lib;
|
||||
{
|
||||
options = {
|
||||
} // genAttrs [ "esphome" "api" "platform" "wifi" "i2c" "logger" "ota" "sensor" ] (key:
|
||||
mkOption {
|
||||
type = types.unspecified;
|
||||
default = {};
|
||||
}
|
||||
);
|
||||
}
|
||||
options = {
|
||||
} // genAttrs [ "esphome" "api" "platform" "wifi" "i2c" "logger" "ota" "sensor" "secrets" ] (key:
|
||||
mkOption {
|
||||
type = types.unspecified;
|
||||
default = {};
|
||||
}
|
||||
);
|
||||
imports = with meta; [
|
||||
esphome.base
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{ inputs, config, pkgs, lib, ... }:
|
||||
{ inputs, tree, config, pkgs, lib, ... }:
|
||||
|
||||
/*
|
||||
This module:
|
||||
|
|
@ -32,7 +32,7 @@ in
|
|||
{
|
||||
imports = [
|
||||
"${toString inputs.tf-nix}/modules/run.nix"
|
||||
] ++ (optional (builtins.pathExists ../../tf/tf.nix) (../../tf/tf.nix));
|
||||
];
|
||||
options = {
|
||||
deploy = {
|
||||
dataDir = mkOption {
|
||||
|
|
@ -73,8 +73,9 @@ in
|
|||
};
|
||||
config.tf = mkMerge (singleton
|
||||
({ ... }: {
|
||||
imports = [
|
||||
../../tf.nix
|
||||
imports = if name == "home" then attrValues (removeAttrs tree.impure.modules.tf [ "acme" "__functor" ])
|
||||
else [
|
||||
tree.impure.modules.tf
|
||||
];
|
||||
deploy.gcroot = {
|
||||
name = mkDefault "kw-${config.name}";
|
||||
|
|
|
|||
7
modules/meta/genesis.nix
Normal file
7
modules/meta/genesis.nix
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{ config, pkgs, root, ... }: {
|
||||
runners.lazy = {
|
||||
file = root;
|
||||
args = [ "--show-trace" ];
|
||||
};
|
||||
deploy.targets.dummy.enable = false;
|
||||
}
|
||||
|
|
@ -32,8 +32,8 @@ with lib;
|
|||
(root + "/nixos/systems/HN/nixos.nix")
|
||||
]);
|
||||
esphomeImports = mkDefault (map (path: toString path) [
|
||||
(root + "/esphome/HN.nix")
|
||||
(root + "/esphome/HN/esphome.nix")
|
||||
(root + "/esphome/boards/HN.nix")
|
||||
(root + "/esphome/boards/HN/esphome.nix")
|
||||
]);
|
||||
darwinImports = mkDefault (map (path: toString path) [
|
||||
(root + "/darwin/systems/HN.nix")
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ with lib;
|
|||
};
|
||||
nodes.esphome = let
|
||||
esphomeType = types.submoduleWith {
|
||||
modules = [ { _module.args.pkgs = pkgs; } ] ++ config.network.esphome.extraModules;
|
||||
modules = config.network.esphome.extraModules;
|
||||
inherit (config.network.esphome) specialArgs;
|
||||
};
|
||||
in mkOption {
|
||||
|
|
@ -140,6 +140,7 @@ with lib;
|
|||
esphome = {
|
||||
extraModules = [
|
||||
meta.modules.esphome
|
||||
meta.modules.system.genesis
|
||||
];
|
||||
specialArgs = {
|
||||
target = config.deploy.targets.home;
|
||||
|
|
@ -149,8 +150,9 @@ with lib;
|
|||
};
|
||||
darwin = {
|
||||
extraModules = [
|
||||
inputs.home-manager.darwinModules.home-manager
|
||||
inputs.home-manager.darwinModules.home-manager
|
||||
meta.modules.darwin
|
||||
meta.modules.system.genesis
|
||||
meta.modules.system
|
||||
meta.system
|
||||
];
|
||||
|
|
@ -161,7 +163,8 @@ with lib;
|
|||
};
|
||||
nixos = {
|
||||
extraModules = [
|
||||
inputs.home-manager.nixosModules.home-manager
|
||||
inputs.home-manager.nixosModules.home-manager
|
||||
meta.modules.system.genesis
|
||||
meta.modules.nixos
|
||||
meta.modules.system
|
||||
meta.nixos.network
|
||||
|
|
|
|||
26
modules/meta/networks.nix
Normal file
26
modules/meta/networks.nix
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
{ config, lib, ... }: with lib; {
|
||||
options = {
|
||||
networks = mkOption {
|
||||
type = with types; attrsOf (submodule ({ name, config, ... }: {
|
||||
options = {
|
||||
member_configs = mkOption {
|
||||
type = unspecified;
|
||||
};
|
||||
members = mkOption {
|
||||
type = unspecified;
|
||||
};
|
||||
};
|
||||
}));
|
||||
};
|
||||
};
|
||||
config = {
|
||||
networks = let
|
||||
names = [ "gensokyo" "chitei" "internet" "tailscale" ];
|
||||
network_filter = network: rec {
|
||||
member_configs = filterAttrs (_: nodeConfig: nodeConfig.networks.${network}.interfaces != []) config.network.nodes.nixos;
|
||||
members = mapAttrs (_: nodeConfig: nodeConfig.networks.${network}) member_configs;
|
||||
};
|
||||
networks' = genAttrs names network_filter;
|
||||
in networks';
|
||||
};
|
||||
}
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
{ config, lib, ... }: with lib; {
|
||||
{ config, pkgs, lib, ... }: with lib; {
|
||||
options.kw.secrets.command = mkOption {
|
||||
type = types.str;
|
||||
default = let
|
||||
bitw = pkgs.writeShellScriptBin "bitw" ''${pkgs.rbw-bitw}/bin/bitw -p gpg://${config.network.nodes.all.${builtins.getEnv "HOME_HOSTNAME"}.kw.secrets.repo.bitw.source} "$@"'';
|
||||
in
|
||||
"${bitw}/bin/bitw get";
|
||||
};
|
||||
}
|
||||
|
|
|
|||
42
modules/meta/tailscale.nix
Normal file
42
modules/meta/tailscale.nix
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
{ config, pkgs, lib, root, ... }: with lib; let
|
||||
home = config.deploy.targets.home.tf;
|
||||
in {
|
||||
options = {
|
||||
tailnet_uri = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
tailnet = mkOption {
|
||||
type = types.attrsOf (types.submodule ({ name, config, ... }: {
|
||||
options = {
|
||||
ipv4 = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
ipv6 = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
pp = mkOption {
|
||||
type = types.unspecified;
|
||||
default = family: port: "http://${config."ipv${toString family}"}:${toString port}/";
|
||||
};
|
||||
ppp = mkOption {
|
||||
type = types.unspecified;
|
||||
default = family: port: path: "http://${config."ipv${toString family}"}:${toString port}/${path}";
|
||||
};
|
||||
tags = mkOption {
|
||||
type = types.listOf types.str;
|
||||
};
|
||||
};
|
||||
}));
|
||||
};
|
||||
};
|
||||
config = {
|
||||
tailnet_uri = "inskip.me";
|
||||
tailnet = let
|
||||
raw = home.resources.tailnet_devices.importAttr "devices";
|
||||
in mkIf (home.state.enable) (mapListToAttrs (elet: nameValuePair (removeSuffix ".${config.tailnet_uri}" elet.name) {
|
||||
tags = elet.tags;
|
||||
ipv4 = head (filter (e: hasInfix "." e) elet.addresses);
|
||||
ipv6 = head (filter (e: hasInfix ":" e) elet.addresses);
|
||||
}) raw);
|
||||
};
|
||||
}
|
||||
3
modules/system/genesis.nix
Normal file
3
modules/system/genesis.nix
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{ config, pkgs, lib, ... }: {
|
||||
_module.args.pkgs = lib.mkDefault pkgs;
|
||||
}
|
||||
23
modules/tf/acme.nix
Normal file
23
modules/tf/acme.nix
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{ config, meta, lib, target, ... }: with lib;
|
||||
let
|
||||
home = meta.deploy.targets.home.tf;
|
||||
in lib.mkIf (target != "home") {
|
||||
acme = {
|
||||
enable = true;
|
||||
account = {
|
||||
register = lib.mkDefault false;
|
||||
emailAddress = "kat@inskip.me";
|
||||
accountKeyPem = home.resources.acme_private_key.importAttr "private_key_pem";
|
||||
};
|
||||
challenge = {
|
||||
defaultProvider = "rfc2136";
|
||||
configs.rfc2136 = {
|
||||
RFC2136_NAMESERVER = config.variables.katdns-address.ref;
|
||||
RFC2136_TSIG_KEY = config.variables.katdns-name.ref;
|
||||
RFC2136_TSIG_SECRET = config.variables.katdns-key.ref;
|
||||
RFC2136_TSIG_ALGORITHM = "hmac-sha512";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
3
modules/tf/gcroot.nix
Normal file
3
modules/tf/gcroot.nix
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{ config, ... }: {
|
||||
deploy.gcroot.enable = true;
|
||||
}
|
||||
31
modules/tf/katdns.nix
Normal file
31
modules/tf/katdns.nix
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
{ config, lib, ... }: with lib; {
|
||||
variables.katdns-address = {
|
||||
value.shellCommand = "${meta.kw.secrets.command} secrets/katdns -f address";
|
||||
type = "string";
|
||||
sensitive = true;
|
||||
};
|
||||
variables.katdns-name = {
|
||||
value.shellCommand = "${meta.kw.secrets.command} secrets/katdns -f username";
|
||||
type = "string";
|
||||
sensitive = true;
|
||||
};
|
||||
variables.katdns-key = {
|
||||
value.shellCommand = "${meta.kw.secrets.command} secrets/katdns -f password";
|
||||
type = "string";
|
||||
sensitive = true;
|
||||
};
|
||||
|
||||
providers.katdns = {
|
||||
type = "dns";
|
||||
inputs.update = {
|
||||
server = config.variables.katdns-address.ref;
|
||||
key_name = config.variables.katdns-name.ref;
|
||||
key_secret = config.variables.katdns-key.ref;
|
||||
key_algorithm = "hmac-sha512";
|
||||
};
|
||||
};
|
||||
|
||||
dns.zones = genAttrs [ "inskip.me." "kittywit.ch." "dork.dev." "gensokyo.zone." ] (_: {
|
||||
provider = "dns.katdns";
|
||||
});
|
||||
}
|
||||
32
modules/type/secretType.nix
Normal file
32
modules/type/secretType.nix
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{ config, lib, ... }: with lib; let
|
||||
secretType = types.submodule ({ name, ... }: {
|
||||
options = {
|
||||
path = mkOption { type = types.str; };
|
||||
field = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
};
|
||||
});
|
||||
repoSecretType = types.submodule ({ name, ... }: {
|
||||
options = {
|
||||
source = mkOption {
|
||||
type = types.path;
|
||||
};
|
||||
text = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
});
|
||||
in {
|
||||
options.secrets = {
|
||||
variables = mkOption {
|
||||
type = types.attrsOf secretType;
|
||||
default = { };
|
||||
};
|
||||
repo = mkOption {
|
||||
type = types.attrsOf repoSecretType;
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue