Skip to content

Commit

Permalink
Add a bootstrap cli command to generate the appOfApps application
Browse files Browse the repository at this point in the history
  • Loading branch information
arnarg committed Oct 26, 2024
1 parent c154b74 commit cfeb67f
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 43 deletions.
15 changes: 13 additions & 2 deletions modules/build.nix
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@
in {
options = with lib; {
build = {
bootstrapPackage = mkOption {
type = types.package;
internal = true;
description = "The package containing the bootstrap appOfApps application manifest.";
};
extrasPackage = mkOption {
type = types.package;
internal = true;
Expand All @@ -66,6 +71,8 @@ in {

config = {
build = {
bootstrapPackage = mkApp config.applications.__bootstrap;

extrasPackage = pkgs.stdenv.mkDerivation {
name = "nixidy-extras-${envName}";

Expand All @@ -85,11 +92,15 @@ in {
};

environmentPackage = let
joined = pkgs.linkFarm "nixidy-apps-joined-${envName}" (lib.mapAttrsToList (_: app: {
joined = pkgs.linkFarm "nixidy-apps-joined-${envName}" (
map (name: let
app = config.applications.${name};
in {
name = app.output.path;
path = mkApp app;
})
config.applications);
config.nixidy.publicApps
);
in
pkgs.symlinkJoin {
name = "nixidy-environment-${envName}";
Expand Down
2 changes: 1 addition & 1 deletion modules/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@
};
in {
inherit (module) config;
inherit (module.config.build) environmentPackage activationPackage;
inherit (module.config.build) environmentPackage activationPackage bootstrapPackage;
meta = {inherit (module.config.nixidy.target) repository branch;};
}
138 changes: 99 additions & 39 deletions modules/nixidy.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
}: let
cfg = config.nixidy;

apps = builtins.removeAttrs config.applications [cfg.appOfApps.name];

extraFilesOpts = with lib;
{name, ...}: {
options = {
Expand Down Expand Up @@ -167,6 +165,11 @@ in {
default = "argocd";
description = "Destination namespace for generated Argo CD Applications in the app of apps applications.";
};
project = mkOption {
type = types.str;
default = "default";
description = "The project of the generated bootstrap app for appOfApps";
};
};

charts = mkOption {
Expand All @@ -179,50 +182,107 @@ in {
default = null;
description = "Path to a directory containing sub-directory structure that can be used to build a charts attrset. This will be passed as `charts` to every module.";
};

publicApps = mkOption {
type = with types; listOf str;
default = [];
internal = true;
description = ''
List of the names of all applications that do not contain the internal `__` prefix.
'';
};
};

config = {
nixidy.publicApps =

Check warning on line 197 in modules/nixidy.nix

View workflow job for this annotation

GitHub Actions / static-lint

Avoid repeated keys in attribute sets

The key `nixidy` is first assigned here ...
builtins.filter (n: !(lib.hasPrefix "__" n))
(builtins.attrNames config.applications);

applications.${cfg.appOfApps.name} = {
inherit (cfg.appOfApps) namespace;

resources.applications =
lib.attrsets.mapAttrs (
n: app: {
metadata = {
inherit (app) name;
annotations =
if app.annotations != {}
then app.annotations
else null;
};
spec = {
inherit (app) project;

source = {
repoURL = cfg.target.repository;
targetRevision = cfg.target.branch;
path = lib.path.subpath.join [
cfg.target.rootPath
app.output.path
];
};
destination = {
inherit (app) namespace;
inherit (app.destination) server;
};
syncPolicy =
(lib.optionalAttrs app.syncPolicy.autoSync.enabled {
automated = {
inherit (app.syncPolicy.autoSync) prune selfHeal;
resources.applications = let
appsWithoutAppsOfApps = lib.filter (n: n != cfg.appOfApps.name) cfg.publicApps;
in
builtins.listToAttrs
(map (
name: let
app = config.applications.${name};
in {
inherit name;

value = {
metadata = {
inherit (app) name;
annotations =
if app.annotations != {}
then app.annotations
else null;
};
spec = {
inherit (app) project;

source = {
repoURL = cfg.target.repository;
targetRevision = cfg.target.branch;
path = lib.path.subpath.join [
cfg.target.rootPath
app.output.path
];
};
})
// (lib.optionalAttrs (lib.length app.syncPolicy.finalSyncOpts > 0) {
syncOptions = app.syncPolicy.finalSyncOpts;
});
};
}
)
apps;
destination = {
inherit (app) namespace;
inherit (app.destination) server;
};
syncPolicy =
(lib.optionalAttrs app.syncPolicy.autoSync.enabled {
automated = {
inherit (app.syncPolicy.autoSync) prune selfHeal;
};
})
// (lib.optionalAttrs (lib.length app.syncPolicy.finalSyncOpts > 0) {
syncOptions = app.syncPolicy.finalSyncOpts;
});
};
};
}
)
appsWithoutAppsOfApps);
};

# This application's resources are printed on
# stdout when `nixidy bootstrap .#<env>` is run
applications.__bootstrap = let
app = config.applications.${cfg.appOfApps.name};
in {
inherit (cfg.appOfApps) namespace;

resources.applications.${cfg.appOfApps.name} = {
metadata.namespace = cfg.appOfApps.namespace;
spec = {
inherit (cfg.appOfApps) project;

source = {
repoURL = cfg.target.repository;
targetRevision = cfg.target.branch;
path = lib.path.subpath.join [
cfg.target.rootPath
app.output.path
];
};
destination = {
inherit (app) namespace;
inherit (app.destination) server;
};
# Maybe this should be configurable but
# generally I think autoSync would be
# desirable on the initial appOfApps.
syncPolicy.automated = {
prune = true;
selfHeal = true;
};
};
};
};

_module.args.charts = config.nixidy.charts;
Expand Down
25 changes: 24 additions & 1 deletion nixidy/nixidy
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,22 @@ function doSwitch() {
"${ENVIRON}/activate"
}

function doBootstrap() {
setFlakeParam

if [[ -z "$FLAKE_ENV" ]]; then
doHelp
exit 1
fi

BOOTSTRAP=$(nix build "${FLAKE_ROOT}#nixidyEnvs.${NIX_SYSTEM}.${FLAKE_ENV}.bootstrapPackage" --no-link --print-out-paths)

for manifest in "$BOOTSTRAP/*.yaml"; do
echo "---"
cat $manifest
done
}

function doHelp() {
echo "Usage: $0 [OPTION] COMMAND"
echo
Expand All @@ -86,6 +102,10 @@ function doHelp() {
echo
echo " switch FLAKE_URI Build and switch to nixidy environment from flake URI."
echo " Example: .#prod"
echo
echo " bootstrap FLAKE_URI"
echo " Output a manifest to bootstrap appOfApps."
echo " Example: .#prod"
}

COMMAND=""
Expand All @@ -98,7 +118,7 @@ while [[ $# -gt 0 ]]; do
opt="$1"
shift
case $opt in
build|switch|info|help)
build|switch|info|bootstrap|help)
COMMAND="$opt"
;;
--no-link)
Expand Down Expand Up @@ -145,6 +165,9 @@ case $COMMAND in
switch)
doSwitch
;;
bootstrap)
doBootstrap
;;
help)
doHelp
;;
Expand Down
1 change: 1 addition & 0 deletions tests/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
./create-namespace.nix
./yamls.nix
./override-name.nix
./internal-apps.nix
./helm/no-values.nix
./helm/with-values.nix
./helm/transformer.nix
Expand Down
42 changes: 42 additions & 0 deletions tests/internal-apps.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
lib,
config,
...
}: let
apps = config.applications.${config.nixidy.appOfApps.name};
in {
# `__` prefix makes an application an
# internal application
applications.__test = {
# Even if you override the name it
# should use the attribute name to
# exclude internal applications
name = "test";
};

test = with lib; {
name = "internal applications";
description = "Check that applications with the internal application prefix is not a part of appOfApps.";
assertions = [
{
description = "Application `__test` should not be included.";

expression = hasAttr "__test" apps.resources.applications;

expected = false;
}

{
description = "App of apps should not have an Application resource for an internal application.";

expression =
findFirst
(x: x.kind == "Application" && x.metadata.name == "test")
null
apps.objects;

expected = null;
}
];
};
}

0 comments on commit cfeb67f

Please sign in to comment.