Merge branch 'bleeding'
This commit is contained in:
commit
77ddfcde7d
26 changed files with 714 additions and 551 deletions
|
|
@ -23,3 +23,11 @@ Minor patches
|
|||
- cerulean no longer depends on `nixpkgs`, `base` package set should be set instead
|
||||
- rename `extraModules` -> `modules`
|
||||
- rename `specialArgs` -> `args`
|
||||
|
||||
## v0.2.3-alpha
|
||||
>[!TODO]
|
||||
> I've been too focused on upcoming changes...
|
||||
|
||||
## v0.2.4-alpha
|
||||
- `homeManager` flake reference may now be specified in snowflake
|
||||
- ``
|
||||
|
|
|
|||
26
NOTICE
Normal file
26
NOTICE
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
Cerulean (https://dobutterfliescry.net/cerulean)
|
||||
Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
|
||||
This product includes software developed by
|
||||
_cry64 (Emile Clark-Boman) (https://github.com/cry128/nt) under the MIT license.
|
||||
Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
|
||||
This product includes software developed by
|
||||
Eelco Dolstra and the Nixpkgs/NixOS contributors under the MIT license.
|
||||
Copyright 2003-2026 Eelco Dolstra and the Nixpkgs/NixOS contributors
|
||||
|
||||
This product includes software developed by
|
||||
the Home Manager contributors (https://github.com/nix-community/home-manager) under the MIT license.
|
||||
Copyright 2017-2026 Home Manager contributors
|
||||
|
||||
This product includes software developed by
|
||||
Serokell (https://serokell.io) under the MPL-2.0 license.
|
||||
Copyright 2020-2026 Serokell
|
||||
|
||||
This product includes software developed by
|
||||
nix-systems (https://github.com/nix-systems) under the MIT license.
|
||||
Copyright 2023 nix-systems
|
||||
|
||||
This product includes software developed by
|
||||
Astro (https://github.com/astro) and the MicroVM.nix contributors (https://github.com/microvm-nix/microvm.nix) under the MIT license.
|
||||
Copyright 2021 Astro, and MicroVM.nix contributors
|
||||
15
TODO.md
15
TODO.md
|
|
@ -1,10 +1,15 @@
|
|||
- [ ] base should automatically be set as the default (dont do anything with the default)
|
||||
- [ ] try to remove common foot guns, ie abort if the user provides the home-manager or microvm nixosModules
|
||||
## Next
|
||||
- [ ] use the Nix module system instead of projectOnto for `cerulean.mkNexus`
|
||||
- [ ] add `options.experimental` for snowflake
|
||||
- [ ] add `legacyImports` support
|
||||
|
||||
## Queued
|
||||
- [X] base should automatically be set as the default (dont do anything with the default)
|
||||
- [X] try to remove common foot guns, ie abort if the user provides the home-manager or microvm nixosModules
|
||||
since cerulean ALREADY provides these
|
||||
|
||||
- [ ] deploy port should default to the first port given to `services.openssh`
|
||||
|
||||
- [ ] use the Nix module system instead of projectOnto for `cerulean.mkNexus`
|
||||
- [ ] create an alternative to nixos-install called cerulean-install that
|
||||
allows people to easily bootstrap new machines (and host it on dobutterfliescry.net)
|
||||
|
||||
|
|
@ -34,10 +39,6 @@
|
|||
that allows transformations (ie a stop post config, ie outputs, which
|
||||
it then returns instead of config)
|
||||
|
||||
|
||||
- [ ] what if we automated the process of replacing windows with Nix??
|
||||
then push this to nixos-anywhere or nix-infect lmaooo
|
||||
|
||||
- [ ] patch microvm so that acpi=off https://github.com/microvm-nix/microvm.nix/commit/b59a26962bb324cc0a134756a323f3e164409b72
|
||||
cause otherwise 2GB causes a failure
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2025 Emile Clark-Boman
|
||||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2025 Emile Clark-Boman
|
||||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2025 Emile Clark-Boman
|
||||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2025 Emile Clark-Boman
|
||||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2026 Emile Clark-Boman
|
||||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2025 Emile Clark-Boman
|
||||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2025 Emile Clark-Boman
|
||||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2025 Emile Clark-Boman
|
||||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
@ -17,20 +17,23 @@
|
|||
...
|
||||
} @ args:
|
||||
mix.newMixture args (mixture: {
|
||||
includes.public = [
|
||||
./nexus
|
||||
submods.public = [
|
||||
./snow
|
||||
];
|
||||
|
||||
version = "0.2.2";
|
||||
version = "0.2.3";
|
||||
|
||||
nixosModules = rec {
|
||||
default = cerulean;
|
||||
cerulean = ./nixos;
|
||||
};
|
||||
# WARNING: legacy
|
||||
mkFlake = mixture.snow.flake;
|
||||
|
||||
overlays = [
|
||||
# build deploy-rs as a package not from the flake input,
|
||||
# hence we can rely on a nixpkg binary cache.
|
||||
inputs.deploy-rs.overlays.default
|
||||
];
|
||||
|
||||
nixosModules = rec {
|
||||
default = cerulean;
|
||||
cerulean = ./nixos;
|
||||
};
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,297 +0,0 @@
|
|||
# Copyright 2025 Emile Clark-Boman
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
{
|
||||
self,
|
||||
this,
|
||||
nt,
|
||||
inputs,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(builtins)
|
||||
all
|
||||
attrNames
|
||||
concatLists
|
||||
concatStringsSep
|
||||
elem
|
||||
filter
|
||||
getAttr
|
||||
isAttrs
|
||||
isFunction
|
||||
isList
|
||||
mapAttrs
|
||||
pathExists
|
||||
typeOf
|
||||
;
|
||||
|
||||
inherit
|
||||
(this)
|
||||
mapNodes
|
||||
;
|
||||
|
||||
inherit
|
||||
(nt)
|
||||
findImport
|
||||
;
|
||||
|
||||
templateNexus = let
|
||||
inherit
|
||||
(nt.naive.terminal)
|
||||
Terminal
|
||||
;
|
||||
in {
|
||||
base = null;
|
||||
modules = [];
|
||||
args = Terminal {};
|
||||
homeManager = null;
|
||||
|
||||
groups = Terminal {};
|
||||
nodes = Terminal {};
|
||||
};
|
||||
|
||||
ROOT_GROUP_NAME = "all";
|
||||
|
||||
parseGroupDecl = groups: let
|
||||
validGroup = g:
|
||||
isAttrs g
|
||||
|| throw ''
|
||||
Cerulean Nexus groups must be provided as attribute sets, got "${typeOf g}" instead!
|
||||
Ensure all the group definitions are attribute sets under your call to `cerulean.mkNexus`.
|
||||
NOTE: Groups can be accessed via `self.groups.PATH.TO.YOUR.GROUP`
|
||||
'';
|
||||
delegate = parent: gName: g: let
|
||||
result =
|
||||
(g
|
||||
// {
|
||||
_name = gName;
|
||||
_parent = parent;
|
||||
})
|
||||
|> mapAttrs (name: value:
|
||||
if elem name ["_name" "_parent"]
|
||||
# ignore metadata fields
|
||||
then value
|
||||
else assert validGroup value; (delegate result name value));
|
||||
in
|
||||
result;
|
||||
in
|
||||
assert validGroup groups;
|
||||
delegate null ROOT_GROUP_NAME groups;
|
||||
|
||||
parseNexus = nexus:
|
||||
assert isAttrs nexus
|
||||
|| abort ''
|
||||
Cerulean Nexus config must be provided as an attribute set, got "${typeOf nexus}" instead!
|
||||
Ensure the `nexus` declaration is an attribute set under your call to `cerulean.mkNexus`.
|
||||
''; let
|
||||
decl = nt.projectOnto templateNexus nexus;
|
||||
in
|
||||
# XXX: TODO: create a different version of nt.projectOnto that can actually
|
||||
# XXX: TODO: handle applying a transformation to the result of each datapoint
|
||||
decl
|
||||
// {
|
||||
groups = parseGroupDecl decl.groups;
|
||||
};
|
||||
|
||||
parseDecl = outputsBuilder: let
|
||||
decl = (
|
||||
if isFunction outputsBuilder
|
||||
then outputsBuilder final # provide `self`
|
||||
else
|
||||
assert (isAttrs outputsBuilder)
|
||||
|| abort ''
|
||||
Cerulean declaration must be provided as an attribute set, got "${typeOf outputsBuilder}" instead!
|
||||
Ensure your declaration is an attribute set or function under your call to `cerulean.mkNexus`.
|
||||
''; outputsBuilder
|
||||
);
|
||||
|
||||
final =
|
||||
decl
|
||||
// {
|
||||
nexus = parseNexus (decl.nexus or {});
|
||||
};
|
||||
in
|
||||
final;
|
||||
|
||||
getGroupModules = root: nodeName: node:
|
||||
assert isList node.groups
|
||||
|| throw ''
|
||||
Cerulean Nexus node "${nodeName}" does not declare group membership as a list, got "${typeOf node.groups}" instead!
|
||||
Ensure `nexus.nodes.${nodeName}.groups` is a list under your call to `cerulean.mkNexus`.
|
||||
'';
|
||||
# ensure root group is always added
|
||||
(node.groups
|
||||
++ [
|
||||
{
|
||||
_parent = null;
|
||||
_name = ROOT_GROUP_NAME;
|
||||
}
|
||||
])
|
||||
# ensure all members are actually groups
|
||||
|> map (group: let
|
||||
got =
|
||||
if ! isAttrs group
|
||||
then toString group
|
||||
else
|
||||
group
|
||||
|> attrNames
|
||||
|> map (name: "${name} = <${typeOf (getAttr name group)}>;")
|
||||
|> concatStringsSep " "
|
||||
|> (x: "{ ${x} }");
|
||||
in
|
||||
if group ? _name
|
||||
then group
|
||||
else
|
||||
throw ''
|
||||
Cerulean Nexus node "${nodeName}" is a member of an incorrectly structured group.
|
||||
Got "${got}" of primitive type "${typeOf group}".
|
||||
NOTE: Groups can be accessed via `self.groups.PATH.TO.YOUR.GROUP`
|
||||
'')
|
||||
# add all inherited groups via _parent
|
||||
|> map (let
|
||||
delegate = g:
|
||||
if g._parent == null
|
||||
then [g]
|
||||
else [g] ++ delegate (g._parent);
|
||||
in
|
||||
delegate)
|
||||
# flatten recursion result
|
||||
|> concatLists
|
||||
# find import location
|
||||
|> map (group: findImport (root + "/groups/${group._name}"))
|
||||
# filter by uniqueness
|
||||
|> nt.prim.unique
|
||||
# ignore missing groups
|
||||
|> filter pathExists;
|
||||
in {
|
||||
mkNexus = root: outputsBuilder: let
|
||||
decl = parseDecl outputsBuilder;
|
||||
|
||||
inherit
|
||||
(decl)
|
||||
nexus
|
||||
;
|
||||
customOutputs = removeAttrs decl ["nexus"];
|
||||
|
||||
outputs = rec {
|
||||
nixosConfigurations = mapNodes nexus (
|
||||
{
|
||||
base,
|
||||
lib,
|
||||
nodeName,
|
||||
node,
|
||||
...
|
||||
}: let
|
||||
nixosDecl = let
|
||||
homeManager =
|
||||
if node.homeManager != null
|
||||
then node.homeManager
|
||||
else nexus.homeManager;
|
||||
|
||||
userArgs = nexus.args // node.args;
|
||||
ceruleanArgs = {
|
||||
inherit root base;
|
||||
inherit (node) system;
|
||||
_cerulean = {
|
||||
inherit inputs userArgs ceruleanArgs homeManager;
|
||||
specialArgs = userArgs // ceruleanArgs;
|
||||
};
|
||||
};
|
||||
specialArgs = assert (userArgs
|
||||
|> attrNames
|
||||
|> all (argName:
|
||||
! ceruleanArgs ? argName
|
||||
|| abort ''
|
||||
`specialArgs` are like super important to Cerulean my love... </3
|
||||
But `args.${argName}` is a reserved argument name :(
|
||||
''));
|
||||
ceruleanArgs._cerulean.specialArgs;
|
||||
in
|
||||
lib.nixosSystem {
|
||||
inherit (node) system;
|
||||
inherit specialArgs;
|
||||
modules =
|
||||
[
|
||||
self.nixosModules.default
|
||||
(findImport (root + "/hosts/${nodeName}"))
|
||||
|
||||
# inputs.microvm.nixosModules.microvm
|
||||
]
|
||||
++ (homeManager.nixosModules.default or [])
|
||||
++ (getGroupModules root nodeName node)
|
||||
++ node.modules
|
||||
++ nexus.modules;
|
||||
};
|
||||
in
|
||||
nixosDecl
|
||||
);
|
||||
|
||||
deploy.nodes = mapNodes nexus ({
|
||||
nodeName,
|
||||
node,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(node.deploy)
|
||||
activationTimeout
|
||||
autoRollback
|
||||
confirmTimeout
|
||||
interactiveSudo
|
||||
magicRollback
|
||||
remoteBuild
|
||||
ssh
|
||||
sudo
|
||||
user
|
||||
;
|
||||
|
||||
nixosFor = system: inputs.deploy-rs.lib.${system}.activate.nixos;
|
||||
in {
|
||||
hostname = ssh.host;
|
||||
|
||||
profilesOrder = ["default"]; # profiles priority
|
||||
profiles.default = {
|
||||
path = nixosFor node.system nixosConfigurations.${nodeName};
|
||||
|
||||
user = user;
|
||||
sudo = sudo;
|
||||
interactiveSudo = interactiveSudo;
|
||||
|
||||
fastConnection = false;
|
||||
|
||||
autoRollback = autoRollback;
|
||||
magicRollback = magicRollback;
|
||||
activationTimeout = activationTimeout;
|
||||
confirmTimeout = confirmTimeout;
|
||||
|
||||
remoteBuild = remoteBuild;
|
||||
sshUser = ssh.user;
|
||||
sshOpts =
|
||||
ssh.opts
|
||||
++ (
|
||||
if elem "-p" ssh.opts
|
||||
then []
|
||||
else ["-p" (toString ssh.port)]
|
||||
)
|
||||
++ (
|
||||
if elem "-A" ssh.opts
|
||||
then []
|
||||
else ["-A"]
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
checks = mapAttrs (system: deployLib: deployLib.deployChecks deploy) inputs.deploy-rs.lib;
|
||||
};
|
||||
in
|
||||
outputs // customOutputs;
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
# Copyright 2025 Emile Clark-Boman
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
{nt, ...}: let
|
||||
inherit
|
||||
(builtins)
|
||||
isAttrs
|
||||
mapAttrs
|
||||
typeOf
|
||||
;
|
||||
in rec {
|
||||
# abstract node instance that stores all default values
|
||||
templateNode = name: system: let
|
||||
inherit
|
||||
(nt.naive.terminal)
|
||||
Terminal
|
||||
;
|
||||
|
||||
missing = msg: path:
|
||||
Terminal (abort ''
|
||||
Each Cerulean Nexus node is required to specify ${msg}!
|
||||
Ensure `nexus.${path}` exists under your call to `cerulean.mkNexus`.
|
||||
'');
|
||||
in {
|
||||
enabled = true;
|
||||
system = missing "its system architecture" "system";
|
||||
groups = [];
|
||||
modules = [];
|
||||
args = Terminal {};
|
||||
|
||||
homeManager = null;
|
||||
|
||||
base = null;
|
||||
|
||||
deploy = {
|
||||
user = "root";
|
||||
sudo = "sudo -u";
|
||||
interactiveSudo = false;
|
||||
|
||||
remoteBuild = false; # prefer local builds for remote deploys
|
||||
|
||||
autoRollback = true; # reactivate previous profile if activation fails
|
||||
magicRollback = true;
|
||||
|
||||
activationTimeout = 500; # timeout in seconds for profile activation
|
||||
confirmTimeout = 30; # timeout in seconds for profile activation confirmation
|
||||
|
||||
ssh = {
|
||||
host = name;
|
||||
user = "ceru-build"; # ceru-build is the default connection user
|
||||
port = 22;
|
||||
opts = [];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
parseNode = name: nodeAttrs:
|
||||
if !(isAttrs nodeAttrs)
|
||||
then
|
||||
# fail if node is not an attribute set
|
||||
abort ''
|
||||
Cerulean Nexus nodes must be provided as an attribute set, got "${typeOf nodeAttrs}" instead!
|
||||
Ensure all `cerulean.nexus.nodes.${name}` declarations are attribute sets under your call to `cerulean.mkNexus`.
|
||||
''
|
||||
else let
|
||||
templateAttrs = templateNode name nodeAttrs.system;
|
||||
in
|
||||
nt.projectOnto templateAttrs nodeAttrs;
|
||||
|
||||
mapNodes = nexus: f:
|
||||
nexus.nodes
|
||||
|> mapAttrs (nodeName: nodeAttrs: let
|
||||
node = parseNode nodeName nodeAttrs;
|
||||
|
||||
# use per-node base or default to nexus base
|
||||
base =
|
||||
if node.base != null
|
||||
then node.base
|
||||
else if nexus.base != null
|
||||
then nexus.base
|
||||
else
|
||||
abort ''
|
||||
Cerulean cannot construct nexus node "${nodeName}" without a base package source.
|
||||
Ensure `nexus.nodes.*.base` or `nexus.base` is a flake reference to the github:NixOS/nixpkgs repository.
|
||||
'';
|
||||
in
|
||||
f {
|
||||
inherit nodeName node base;
|
||||
inherit (base) lib;
|
||||
});
|
||||
}
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
# Copyright 2026 Emile Clark-Boman
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
{
|
||||
inputs,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
# nexus
|
||||
options = let
|
||||
inherit
|
||||
(lib)
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
in {
|
||||
modules = mkOption {
|
||||
type = types.listOf types.path;
|
||||
};
|
||||
args = mkOption {
|
||||
type = types.attrs;
|
||||
};
|
||||
|
||||
groups = mkOption {
|
||||
type = types.attrs;
|
||||
};
|
||||
|
||||
nodes = mkOption {
|
||||
type = types.attrsOf (types.submoduleWith ({...}: {
|
||||
options = {
|
||||
enabled = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
};
|
||||
system = mkOption {
|
||||
type = types.enum inputs.systems;
|
||||
};
|
||||
groups = mkOption {
|
||||
type = types.list;
|
||||
};
|
||||
modules = mkOption {
|
||||
type = types.list;
|
||||
};
|
||||
args = mkOption {
|
||||
type = types.attrs;
|
||||
};
|
||||
|
||||
deploy = {
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
sudoCmd = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
interactiveSudo = mkOption {
|
||||
type = types.bool;
|
||||
};
|
||||
|
||||
remoteBuild = mkOption {
|
||||
type = types.bool;
|
||||
};
|
||||
autoRollback = mkOption {
|
||||
type = types.bool;
|
||||
};
|
||||
magicRollback = mkOption {
|
||||
type = types.bool;
|
||||
};
|
||||
|
||||
activationTimeout = mkOption {
|
||||
type = types.int;
|
||||
};
|
||||
confirmTimeout = mkOption {
|
||||
type = types.int;
|
||||
};
|
||||
|
||||
ssh = {
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
port = mkOption {
|
||||
type = types.int;
|
||||
};
|
||||
opts = mkOption {
|
||||
type = types.listOf types.str;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}));
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
};
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2026 Emile Clark-Boman
|
||||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
@ -13,16 +13,23 @@
|
|||
# limitations under the License.
|
||||
{
|
||||
root,
|
||||
pkgs,
|
||||
system,
|
||||
_cerulean,
|
||||
...
|
||||
} @ args: {
|
||||
imports =
|
||||
imports = with _cerulean.inputs;
|
||||
[
|
||||
# add support for `options.legacyImports`
|
||||
# ./legacy-imports.nix
|
||||
|
||||
# user configuration
|
||||
(import (root + "/nixpkgs.nix"))
|
||||
# options declarations
|
||||
(import ./nixpkgs.nix (args // {contextName = "hosts";}))
|
||||
|
||||
sops-nix.nixosModules.sops
|
||||
# microvm.nixosModules.microvm
|
||||
]
|
||||
++ (
|
||||
if _cerulean.homeManager != null
|
||||
|
|
@ -30,7 +37,11 @@
|
|||
else []
|
||||
);
|
||||
|
||||
environment.systemPackages = with _cerulean.inputs; [
|
||||
deploy-rs.packages.${system}.default
|
||||
];
|
||||
environment.systemPackages =
|
||||
(with pkgs; [
|
||||
sops
|
||||
])
|
||||
++ (with _cerulean.inputs; [
|
||||
deploy-rs.packages.${system}.default
|
||||
]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2026 Emile Clark-Boman
|
||||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
@ -25,6 +25,10 @@
|
|||
pathExists
|
||||
;
|
||||
in {
|
||||
imports = [
|
||||
_cerulean.homeManager.nixosModules.default
|
||||
];
|
||||
|
||||
home-manager = {
|
||||
users =
|
||||
config.users.users
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2026 Emile Clark-Boman
|
||||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2026 Emile Clark-Boman
|
||||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2026 Emile Clark-Boman
|
||||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
@ -75,19 +75,19 @@ in {
|
|||
# NOTE: _module.args is a special option that allows us to
|
||||
# NOTE: set extend specialArgs from inside the modules.
|
||||
# WARNING: pkgs is a reserved specialArg
|
||||
_module.args = removeAttrs repos ["pkgs"];
|
||||
_module.args = removeAttrs repos ["pkgs" "default"];
|
||||
|
||||
nixpkgs =
|
||||
if contextName == "hosts"
|
||||
then {
|
||||
flake.source = lib.mkOverride 200 base; # DEBUG: temp while getting base to work
|
||||
overlays = lib.mkOverride 200 (defaultPkgs.overlays or {});
|
||||
config = lib.mkOverride 200 (defaultPkgs.config or {});
|
||||
flake.source = lib.mkForce base; # DEBUG: temp while getting base to work
|
||||
overlays = lib.mkForce (defaultPkgs.overlays or {});
|
||||
config = lib.mkForce (defaultPkgs.config or {});
|
||||
}
|
||||
else if contextName == "homes"
|
||||
then {
|
||||
config = lib.mkOverride 200 (defaultPkgs.config or {});
|
||||
overlays = lib.mkOverride 200 (defaultPkgs.overlays or []);
|
||||
config = lib.mkForce (defaultPkgs.config or {});
|
||||
overlays = lib.mkForce (defaultPkgs.overlays or []);
|
||||
}
|
||||
else {};
|
||||
};
|
||||
|
|
|
|||
182
cerulean/snow/default.nix
Normal file
182
cerulean/snow/default.nix
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
{
|
||||
this,
|
||||
self,
|
||||
inputs,
|
||||
systems,
|
||||
nt,
|
||||
mix,
|
||||
...
|
||||
} @ args: let
|
||||
inherit
|
||||
(builtins)
|
||||
all
|
||||
attrNames
|
||||
elem
|
||||
mapAttrs
|
||||
warn
|
||||
;
|
||||
|
||||
inherit (inputs.nixpkgs) lib;
|
||||
|
||||
inherit (nt) findImport;
|
||||
in
|
||||
mix.newMixture args (mixture: let
|
||||
inherit (mixture) mapNodes;
|
||||
in {
|
||||
includes.private = [
|
||||
./lib/nodes.nix
|
||||
];
|
||||
|
||||
inherit findImport;
|
||||
|
||||
# snow.flake
|
||||
flake = flakeInputs: root: let
|
||||
module = lib.evalModules {
|
||||
class = "snowflake";
|
||||
# TODO: abort if inputs contains reserved names
|
||||
specialArgs =
|
||||
flakeInputs
|
||||
// {
|
||||
inherit root;
|
||||
inherit systems;
|
||||
inherit (this) snow; # please don't be infinite recursion...
|
||||
inputs = flakeInputs;
|
||||
};
|
||||
|
||||
modules = [
|
||||
./module.nix
|
||||
];
|
||||
};
|
||||
|
||||
nodes = module.config.nodes;
|
||||
in rec {
|
||||
nixosConfigurations = mapNodes nodes (
|
||||
{
|
||||
base,
|
||||
lib,
|
||||
name,
|
||||
node,
|
||||
groupModules,
|
||||
...
|
||||
}: let
|
||||
homeManager =
|
||||
if node.homeManager != null
|
||||
then node.homeManager
|
||||
else if nodes.homeManager != null
|
||||
then nodes.homeManager
|
||||
else
|
||||
warn ''
|
||||
[snowflake] Neither `nodes.homeManager` nor `nodes.nodes.${name}.homeManager` were specified!
|
||||
[snowflake] home-manager will NOT be used! User configuration will be ignored!
|
||||
''
|
||||
null;
|
||||
|
||||
userArgs = nodes.args // node.args;
|
||||
ceruleanArgs = {
|
||||
inherit systems root base;
|
||||
inherit (node) system;
|
||||
inherit (this) snow;
|
||||
|
||||
_cerulean = {
|
||||
inherit inputs userArgs ceruleanArgs homeManager;
|
||||
specialArgs = userArgs // ceruleanArgs;
|
||||
};
|
||||
};
|
||||
specialArgs = assert (userArgs
|
||||
|> attrNames
|
||||
|> all (argName:
|
||||
! ceruleanArgs ? argName
|
||||
|| abort ''
|
||||
`specialArgs` are like super important to Cerulean my love... </3
|
||||
But `args.${argName}` is a reserved argument name :(
|
||||
''));
|
||||
ceruleanArgs._cerulean.specialArgs;
|
||||
in
|
||||
lib.nixosSystem {
|
||||
inherit (node) system;
|
||||
inherit specialArgs;
|
||||
modules =
|
||||
[
|
||||
self.nixosModules.default
|
||||
(findImport (root + "/hosts/${name}"))
|
||||
]
|
||||
++ (groupModules root)
|
||||
++ node.modules
|
||||
++ nodes.modules;
|
||||
}
|
||||
);
|
||||
|
||||
deploy.nodes = mapNodes nodes ({
|
||||
name,
|
||||
node,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(node.deploy)
|
||||
ssh
|
||||
user
|
||||
sudoCmd
|
||||
interactiveSudo
|
||||
remoteBuild
|
||||
rollback
|
||||
autoRollback
|
||||
magicRollback
|
||||
activationTimeout
|
||||
confirmTimeout
|
||||
;
|
||||
|
||||
nixosFor = system: inputs.deploy-rs.lib.${system}.activate.nixos;
|
||||
in {
|
||||
hostname = ssh.host;
|
||||
|
||||
profilesOrder = ["default"]; # profiles priority
|
||||
profiles.default = {
|
||||
path = nixosFor node.system nixosConfigurations.${name};
|
||||
|
||||
user = user;
|
||||
sudo = sudoCmd;
|
||||
interactiveSudo = interactiveSudo;
|
||||
|
||||
fastConnection = false;
|
||||
|
||||
autoRollback = autoRollback -> rollback;
|
||||
magicRollback = magicRollback -> rollback;
|
||||
activationTimeout = activationTimeout;
|
||||
confirmTimeout = confirmTimeout;
|
||||
|
||||
remoteBuild = remoteBuild;
|
||||
sshUser = ssh.user;
|
||||
sshOpts =
|
||||
ssh.opts
|
||||
++ (
|
||||
if elem "-p" ssh.opts
|
||||
then []
|
||||
else ["-p" (toString ssh.port)]
|
||||
)
|
||||
++ (
|
||||
if elem "-A" ssh.opts
|
||||
then []
|
||||
else ["-A"]
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
checks =
|
||||
inputs.deploy-rs.lib
|
||||
|> mapAttrs (system: deployLib:
|
||||
deployLib.deployChecks deploy);
|
||||
};
|
||||
})
|
||||
96
cerulean/snow/lib/nodes.nix
Normal file
96
cerulean/snow/lib/nodes.nix
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
{nt, ...}: let
|
||||
inherit
|
||||
(builtins)
|
||||
concatLists
|
||||
elem
|
||||
filter
|
||||
isAttrs
|
||||
mapAttrs
|
||||
pathExists
|
||||
typeOf
|
||||
;
|
||||
|
||||
rootGroupName = "all";
|
||||
|
||||
parseGroupsDecl = groups: let
|
||||
validGroup = g:
|
||||
isAttrs g
|
||||
|| throw ''
|
||||
Cerulean Nexus groups must be provided as attribute sets, got "${typeOf g}" instead!
|
||||
Ensure all the group definitions are attribute sets under your call to `cerulean.mkNexus`.
|
||||
NOTE: Groups can be accessed via `self.groups.PATH.TO.YOUR.GROUP`
|
||||
'';
|
||||
delegate = parent: gName: g: let
|
||||
result =
|
||||
(g
|
||||
// {
|
||||
_name = gName;
|
||||
_parent = parent;
|
||||
})
|
||||
|> mapAttrs (name: value:
|
||||
if elem name ["_name" "_parent"]
|
||||
# ignore metadata fields
|
||||
then value
|
||||
else assert validGroup value; (delegate result name value));
|
||||
in
|
||||
result;
|
||||
in
|
||||
assert validGroup groups;
|
||||
delegate null rootGroupName groups;
|
||||
|
||||
getGroupModules = root: groups:
|
||||
# ensure root group is always added
|
||||
groups
|
||||
# add all inherited groups via _parent
|
||||
|> map (let
|
||||
delegate = g:
|
||||
if g._parent == null
|
||||
then [g]
|
||||
else [g] ++ delegate (g._parent);
|
||||
in
|
||||
delegate)
|
||||
# flatten recursion result
|
||||
|> concatLists
|
||||
# find import location
|
||||
|> map (group: nt.findImport (root + "/groups/${group._name}"))
|
||||
# filter by uniqueness
|
||||
|> nt.prim.unique
|
||||
# ignore missing groups
|
||||
|> filter pathExists;
|
||||
in {
|
||||
mapNodes = nodes: f:
|
||||
nodes.nodes
|
||||
|> mapAttrs (name: node: let
|
||||
# use per-node base or default to nodes' base
|
||||
base =
|
||||
if node.base != null
|
||||
then node.base
|
||||
else if nodes.base != null
|
||||
then nodes.base
|
||||
else
|
||||
abort ''
|
||||
Cerulean cannot construct nodes node "${name}" without a base package source.
|
||||
Ensure `nodes.nodes.*.base` or `nodes.base` is a flake reference to the github:NixOS/nixpkgs repository.
|
||||
'';
|
||||
in
|
||||
f rec {
|
||||
inherit name node base;
|
||||
inherit (base) lib;
|
||||
|
||||
groups = node.groups (parseGroupsDecl nodes.groups);
|
||||
groupModules = root: getGroupModules root groups;
|
||||
});
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2025 Emile Clark-Boman
|
||||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
@ -11,10 +11,13 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
{mix, ...} @ args:
|
||||
mix.newMixture args (mixture: {
|
||||
includes.public = [
|
||||
./nodes.nix
|
||||
./nexus.nix
|
||||
{
|
||||
root,
|
||||
snow,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
./nodes
|
||||
(snow.findImport (root + "/snow"))
|
||||
];
|
||||
})
|
||||
}
|
||||
62
cerulean/snow/nodes/default.nix
Normal file
62
cerulean/snow/nodes/default.nix
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
{
|
||||
lib,
|
||||
specialArgs,
|
||||
...
|
||||
}: {
|
||||
options.nodes = let
|
||||
inherit
|
||||
(lib)
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
in
|
||||
mkOption {
|
||||
description = ''
|
||||
Cerulean node declarations.
|
||||
'';
|
||||
type = types.submoduleWith {
|
||||
inherit specialArgs;
|
||||
|
||||
modules = [
|
||||
{
|
||||
imports = [./shared.nix];
|
||||
|
||||
options = {
|
||||
groups = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
example = lib.literalExpression "{ servers = { staging = {}; production = {}; }; }";
|
||||
description = ''
|
||||
Hierarchical groups that nodes can be a member of.
|
||||
'';
|
||||
};
|
||||
|
||||
nodes = mkOption {
|
||||
type = types.attrsOf (types.submoduleWith {
|
||||
inherit specialArgs;
|
||||
modules = [(import ./submodule.nix)];
|
||||
});
|
||||
# example = { ... }; # TODO
|
||||
description = ''
|
||||
Node (host systems) declarations.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
82
cerulean/snow/nodes/shared.nix
Normal file
82
cerulean/snow/nodes/shared.nix
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
{lib, ...}: let
|
||||
inherit
|
||||
(lib)
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
|
||||
flakeRef = types.either types.str types.path;
|
||||
in {
|
||||
options = {
|
||||
base = lib.mkOption {
|
||||
# In newer Nix versions, particularly with lazy trees, outPath of
|
||||
# flakes becomes a Nix-language path object. We deliberately allow this
|
||||
# to gracefully come through the interface in discussion with @roberth.
|
||||
#
|
||||
# See: https://github.com/NixOS/nixpkgs/pull/278522#discussion_r1460292639
|
||||
type = types.nullOr flakeRef;
|
||||
|
||||
default = null;
|
||||
defaultText = "if (using nixpkgsFlake.lib.nixosSystem) then self.outPath else null";
|
||||
|
||||
example = lib.literalExpression "inputs.nixpkgs";
|
||||
|
||||
description = ''
|
||||
The path to the nixpkgs source used to build a system. A `base` package set
|
||||
is required to be set, and can be specified via either:
|
||||
1. `options.nodes.base` (default `base` used for all systems)
|
||||
2. `options.nodes.nodes.<name>.base` (takes prescedence over `options.nodes.base`)
|
||||
|
||||
This can also be optionally set if the NixOS system is not built with a flake but still uses
|
||||
pinned sources: set this to the store path for the nixpkgs sources used to build the system,
|
||||
as may be obtained by `fetchTarball`, for example.
|
||||
|
||||
Note: the name of the store path must be "source" due to
|
||||
<https://github.com/NixOS/nix/issues/7075>.
|
||||
'';
|
||||
};
|
||||
|
||||
modules = mkOption {
|
||||
type = types.listOf types.raw;
|
||||
default = [];
|
||||
example = lib.literalExpression "[ { environment.systemPackages = [ pkgs.git ]; } ]";
|
||||
description = ''
|
||||
Shared modules to import; equivalent to the NixOS module system's `extraModules`.
|
||||
'';
|
||||
};
|
||||
|
||||
args = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
example = lib.literalExpression "{ inherit inputs; }";
|
||||
description = ''
|
||||
Shared args to provided for each node; equivalent to the NixOS module system's `specialArgs`.
|
||||
'';
|
||||
};
|
||||
|
||||
homeManager = mkOption {
|
||||
type = types.nullOr flakeRef;
|
||||
default = null;
|
||||
example = lib.literalExpression "inputs.home-manager";
|
||||
description = ''
|
||||
The path to the home-manager source. A `homeManager` flake reference
|
||||
is required to be set for `homes/` to be evaluated, and can be specified via either:
|
||||
1. `options.nodes.homeManager` (default `homManager` used for all systems)
|
||||
2. `options.nodes.nodes.<name>.homeManager` (takes prescedence over `options.nodes.homeManager`)
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
185
cerulean/snow/nodes/submodule.nix
Normal file
185
cerulean/snow/nodes/submodule.nix
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
{
|
||||
lib,
|
||||
systems,
|
||||
...
|
||||
}: {
|
||||
imports = [./shared.nix];
|
||||
|
||||
options = let
|
||||
inherit
|
||||
(lib)
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
in {
|
||||
enabled = lib.mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
example = true;
|
||||
description = ''
|
||||
Whether to enable this node. Nodes are enabled by default.
|
||||
'';
|
||||
};
|
||||
|
||||
system = mkOption {
|
||||
type = types.nullOr (types.enum systems);
|
||||
default = null;
|
||||
example = "x86_64-linux";
|
||||
description = ''
|
||||
The target system architecture to compile for.
|
||||
'';
|
||||
};
|
||||
|
||||
groups = mkOption {
|
||||
# TODO: write a custom group type that validates better than types.attrs lol
|
||||
type = types.functionTo (types.listOf types.attrs);
|
||||
default = groups: [];
|
||||
example = lib.literalExpression "( groups: [ groups.servers groups.secure-boot ] )";
|
||||
description = ''
|
||||
A function from the `groups` hierarchy to a list of groups this node inherits from.
|
||||
'';
|
||||
};
|
||||
|
||||
deploy = {
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "root";
|
||||
example = "admin";
|
||||
description = ''
|
||||
The user that the system derivation will be deployed to. The command specified in
|
||||
`<node>.deploy.sudoCmd` will be used if `<node>.deploy.user` is not the
|
||||
same as `<node>.deploy.ssh.user` the same as above).
|
||||
'';
|
||||
};
|
||||
|
||||
sudoCmd = mkOption {
|
||||
type = types.str;
|
||||
default = "sudo -u";
|
||||
example = "doas -u";
|
||||
description = ''
|
||||
Which sudo command to use. Must accept at least two arguments:
|
||||
1. the user name to execute commands as
|
||||
2. the rest is the command to execute
|
||||
'';
|
||||
};
|
||||
|
||||
interactiveSudo = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = false;
|
||||
description = ''
|
||||
Whether to enable interactive sudo (password based sudo).
|
||||
NOT RECOMMENDED. Use one of Cerulean's recommended auth methods instead.
|
||||
'';
|
||||
};
|
||||
|
||||
remoteBuild = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = false;
|
||||
description = ''
|
||||
Whether to build the system derivation on the target system.
|
||||
Will also fetch all external dependencies from the target system's substituters.
|
||||
'';
|
||||
};
|
||||
|
||||
rollback = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
example = true;
|
||||
description = ''
|
||||
Enables both `autoRollback` and `magicRollback`.
|
||||
'';
|
||||
};
|
||||
|
||||
autoRollback = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
example = true;
|
||||
description = ''
|
||||
If the previous system derivation should be re-activated if activation fails.
|
||||
'';
|
||||
};
|
||||
|
||||
magicRollback = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
example = true;
|
||||
description = ''
|
||||
TODO: im fucking lazy
|
||||
'';
|
||||
};
|
||||
|
||||
activationTimeout = mkOption {
|
||||
type = types.int;
|
||||
default = 500;
|
||||
example = 30;
|
||||
description = ''
|
||||
Time window in seconds allowed for system derivation activation.
|
||||
If timeout occurs, remote deployment is considered to have failed.
|
||||
'';
|
||||
};
|
||||
|
||||
confirmTimeout = mkOption {
|
||||
type = types.int;
|
||||
default = 30;
|
||||
example = 15;
|
||||
description = ''
|
||||
Time window in seconds allowed for activation confirmation.
|
||||
If timeout occurs, remote deployment is considered to have failed.
|
||||
'';
|
||||
};
|
||||
|
||||
ssh = {
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
example = "dobutterfliescry.net";
|
||||
description = ''
|
||||
The host to connect to over ssh during deployment
|
||||
'';
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "cerubld";
|
||||
example = "custom-user";
|
||||
description = ''
|
||||
The user to connect to over ssh during deployment.
|
||||
'';
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.int;
|
||||
default = 22;
|
||||
example = 2222;
|
||||
description = ''
|
||||
The port to connect to over ssh during deployment.
|
||||
'';
|
||||
};
|
||||
|
||||
opts = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = ["-i" "~/.ssh/id_rsa"];
|
||||
description = ''
|
||||
Extra ssh arguments to use during deployment.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2025 Emile Clark-Boman
|
||||
# Copyright 2025-2026 _cry64 (Emile Clark-Boman)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
@ -32,6 +32,11 @@
|
|||
url = "github:microvm-nix/microvm.nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
sops-nix = {
|
||||
url = "github:Mic92/sops-nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = {
|
||||
|
|
@ -43,5 +48,6 @@
|
|||
{
|
||||
inherit inputs self nt;
|
||||
inherit (nt) mix;
|
||||
systems = import inputs.systems;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue