From 8cf73a70ef1d5dd8913245eba0717b7dbd9d43b8 Mon Sep 17 00:00:00 2001 From: technofab Date: Thu, 13 Nov 2025 21:47:52 +0100 Subject: [PATCH] chore: initial commit --- .envrc | 2 + .gitignore | 1 + .gitlab-ci.yml | 5 + README.md | 9 ++ flake.lock | 63 ++++++++++ flake.nix | 35 ++++++ nix-kubernetes/coder.nix | 121 +++++++++++++++++++ nix-kubernetes/default.nix | 8 ++ nix-kubernetes/kubernetes.nix | 216 ++++++++++++++++++++++++++++++++++ nix-kubernetes/parameters.nix | 112 ++++++++++++++++++ nix-kubernetes/variables.nix | 26 ++++ nix/packages/flake.lock | 28 +++++ nix/packages/flake.nix | 10 ++ nix/packages/image.nix | 150 +++++++++++++++++++++++ nix/packages/packages.nix | 23 ++++ nix/repo/ci.nix | 71 +++++++++++ nix/repo/devShells.nix | 23 ++++ nix/repo/flake.lock | 82 +++++++++++++ nix/repo/flake.nix | 19 +++ 19 files changed, 1004 insertions(+) create mode 100644 .envrc create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 README.md create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 nix-kubernetes/coder.nix create mode 100644 nix-kubernetes/default.nix create mode 100644 nix-kubernetes/kubernetes.nix create mode 100644 nix-kubernetes/parameters.nix create mode 100644 nix-kubernetes/variables.nix create mode 100644 nix/packages/flake.lock create mode 100644 nix/packages/flake.nix create mode 100644 nix/packages/image.nix create mode 100644 nix/packages/packages.nix create mode 100644 nix/repo/ci.nix create mode 100644 nix/repo/devShells.nix create mode 100644 nix/repo/flake.lock create mode 100644 nix/repo/flake.nix diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..565a52a --- /dev/null +++ b/.envrc @@ -0,0 +1,2 @@ +source $(fetchurl https://gitlab.com/rensa-nix/direnv/-/raw/v0.3.0/direnvrc "sha256-u7+KEz684NnIZ+Vh5x5qLrt8rKdnUNexewBoeTcEVHQ=") +use ren //repo/devShells/default diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b2be92b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +result diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..e1db81f --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,5 @@ +# Generated by soonix, DO NOT EDIT +include: +- component: gitlab.com/TECHNOFAB/nix-gitlab-ci/nix-gitlab-ci@3.0.1 + inputs: + version: 3.0.1 diff --git a/README.md b/README.md new file mode 100644 index 0000000..c0a0bd2 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# Coder Templates + +Templates for [Coder](https://coder.com), built with [Tofunix](https://tofunix.projects.tf). + +## Templates + +- Nix Kubernetes + > provisions a Coder workspace on Kubernetes, running a Nix-built image, + > which also contains Nix and supports Dotfiles management using home-manager. diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..3fb2aac --- /dev/null +++ b/flake.lock @@ -0,0 +1,63 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1762596750, + "narHash": "sha256-rXXuz51Bq7DHBlfIjN7jO8Bu3du5TV+3DSADBX7/9YQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b6a8526db03f735b89dd5ff348f53f752e7ddc8e", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1754184128, + "narHash": "sha256-AjhoyBL4eSyXf01Bmc6DiuaMrJRNdWopmdnMY0Pa/M0=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "02e72200e6d56494f4a7c0da8118760736e41b60", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "ren": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "dir": "lib", + "lastModified": 1758738378, + "narHash": "sha256-NjzqdvQCDDdObEBH8x/vdhbdhrIB+N9E570uCdksGHY=", + "owner": "rensa-nix", + "repo": "core", + "rev": "abe19f9f13aff41de2b63304545c87d193d19ef4", + "type": "gitlab" + }, + "original": { + "dir": "lib", + "owner": "rensa-nix", + "repo": "core", + "type": "gitlab" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "ren": "ren" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..c28db2e --- /dev/null +++ b/flake.nix @@ -0,0 +1,35 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + ren.url = "gitlab:rensa-nix/core?dir=lib"; + }; + + outputs = { + ren, + self, + ... + } @ inputs: + ren.buildWith + { + inherit inputs; + cellsFrom = ./nix; + transformInputs = system: i: + i + // { + pkgs = import i.nixpkgs { + inherit system; + }; + }; + cellBlocks = with ren.blocks; [ + (simple "devShells") + (simple "ci") + (simple "packages") + ]; + } + { + packages = ren.select self [ + ["repo" "ci" "packages"] + ["packages" "packages"] + ]; + }; +} diff --git a/nix-kubernetes/coder.nix b/nix-kubernetes/coder.nix new file mode 100644 index 0000000..f324f75 --- /dev/null +++ b/nix-kubernetes/coder.nix @@ -0,0 +1,121 @@ +{ + ref, + utils, + ... +}: { + locals."git_repo_folder" = with utils; let + split_repo = split (quot "") ref.data.coder_parameter.git_repo.value; + in + try [ + (element split_repo "${rb (length split_repo)} - 1") + (quot "") + ]; + + data = { + coder_external_auth."gitlab" = { + id = "gitlab"; + optional = false; + }; + coder_workspace."me" = {}; + coder_workspace_owner."me" = {}; + }; + + resource = { + coder_agent."coder" = { + arch = ref.var.arch; + os = "linux"; + metadata = [ + { + display_name = "Container CPU Usage"; + key = "0_cpu_usage"; + script = "coder stat cpu --host=false"; + interval = 10; + timeout = 1; + } + { + display_name = "Container RAM Usage"; + key = "1_ram_usage"; + script = "coder stat mem --host=false"; + interval = 10; + timeout = 1; + } + { + display_name = "Home Disk"; + key = "2_home_disk"; + script = "coder stat disk --path $HOME"; + interval = 60; + timeout = 1; + } + { + display_name = "Nix Store Disk"; + key = "3_nix_store_disk"; + script = "coder stat disk --path /nix"; + interval = 60; + timeout = 1; + } + ]; + }; + coder_script."git_clone" = { + agent_id = ref.coder_agent.coder.id; + display_name = "Git Clone"; + icon = "/icon/git.svg"; + script = let + repo = ref.data.coder_parameter.git_repo.value; + repo_folder = ref.local.git_repo_folder; + in + # sh + '' + mkdir -p ~/repos + if [ ! -z "${repo}" ]; then + echo "Cloning repo \"${repo}\" if it does not exist" + pushd ~/repos >/dev/null + if [[ ! -d "${repo_folder}" ]] then + git clone ${repo} ${repo_folder} + fi + popd >/dev/null + else + echo "No git repo specified, skipping..." + fi + ''; + run_on_start = true; + start_blocks_login = true; + }; + coder_script."home-manager" = { + agent_id = ref.coder_agent.coder.id; + display_name = "Home Manager"; + icon = "/emojis/1f3e0.png"; + script = + # sh + '' + if [ ! -z "$DOTFILES_REPO" ]; then + echo "Dotfiles present, reloading home-manager profile" + reload-dotfiles + # the homeConfiguration can specify a program "coder_startup", run it + # here if it exists + if command -v coder_startup &> /dev/null; then + echo "Running startup tasks..." + coder_startup + fi + else + echo "No dotfiles repo specified, skipping..." + fi + ''; + run_on_start = true; + start_blocks_login = true; + }; + coder_script."home-manager-shutdown" = { + agent_id = ref.coder_agent.coder.id; + display_name = "Home Manager Shutdown"; + icon = "/emojis/1f3e0.png"; + script = + # sh + '' + if command -v coder_shutdown &> /dev/null; then + echo "Running shutdown tasks..." + coder_shutdown + fi + ''; + run_on_stop = true; + }; + }; +} diff --git a/nix-kubernetes/default.nix b/nix-kubernetes/default.nix new file mode 100644 index 0000000..fea682e --- /dev/null +++ b/nix-kubernetes/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./parameters.nix + ./variables.nix + ./coder.nix + ./kubernetes.nix + ]; +} diff --git a/nix-kubernetes/kubernetes.nix b/nix-kubernetes/kubernetes.nix new file mode 100644 index 0000000..ee91958 --- /dev/null +++ b/nix-kubernetes/kubernetes.nix @@ -0,0 +1,216 @@ +{ + ref, + utils, + ... +}: let + identifier = with utils; "${lower ref.data.coder_workspace_owner.me.name}-${lower ref.data.coder_workspace.me.name}"; +in { + resource = { + kubernetes_pod."workspace" = { + count = ref.data.coder_workspace.me.start_count; + metadata = [ + { + name = "coder-${identifier}"; + namespace = ref.var.namespace; + annotations."com.coder.user.email" = ref.data.coder_workspace_owner.me.email; + labels = { + "app.kubernetes.io/instance" = "coder-workspace-${identifier}"; + "app.kubernetes.io/name" = "coder-workspace"; + "app.kubernetes.io/part-of" = "coder"; + "com.coder.resource" = "true"; + "com.coder.user.id" = ref.data.coder_workspace_owner.me.id; + "com.coder.user.name" = ref.data.coder_workspace_owner.me.name; + "com.coder.workspace.id" = ref.data.coder_workspace.me.id; + "com.coder.workspace.name" = ref.data.coder_workspace.me.name; + }; + } + ]; + # give the shutdown tasks enough time to run + timeouts.delete = "31m"; + spec = [ + { + termination_grace_period_seconds = 1800; + affinity.pod_anti_affinity.preferred_during_scheduling_ignored_during_execution = { + weight = 1; + pod_affinity_term = { + topology_key = "kubernetes.io/hostname"; + label_selector.match_expressions = { + key = "app.kubernetes.io/name"; + operator = "In"; + values = ["coder-workspace"]; + }; + }; + }; + init_container = [ + { + name = "chown"; + image = "alpine:3"; + command = ["chown" "1000:1000" "/mnt/nix" "/mnt/tmp" "/mnt/home"]; + security_context.run_as_user = "0"; + volume_mount = [ + { + mount_path = "/mnt/home"; + name = "home"; + read_only = false; + } + { + mount_path = "/mnt/nix"; + name = "nix-store"; + read_only = false; + } + { + mount_path = "/mnt/tmp"; + name = "tmp"; + read_only = false; + } + ]; + } + { + name = "copy-nix-store"; + image = "registry.gitlab.com/technofab/coder-templates/nix-coder-image:${ref.data.coder_parameter.image_tag.value}"; + command = ["cp" "-nR" "/nix/." "/pv_nix"]; + security_context.run_as_user = "1000"; + volume_mount = [ + { + mount_path = "/pv_nix"; + name = "nix-store"; + read_only = false; + } + ]; + } + ]; + container = [ + { + name = "workspace"; + image = "registry.gitlab.com/technofab/coder-templates/nix-coder-image:${ref.data.coder_parameter.image_tag.value}"; + command = ["/bin/sh" "-c" "${ref.coder_agent.coder.init_script}"]; + env = [ + { + name = "CODER_AGENT_TOKEN"; + value = ref.coder_agent.coder.token; + } + { + name = "DOTFILES_REPO"; + value = ref.data.coder_parameter.dotfiles_repo.value; + } + { + name = "TZ"; + value = ref.data.coder_parameter.timezone.value; + } + { + name = "NIX_CONFIG"; + value = ref.data.coder_parameter.nix_config.value; + } + ]; + resources = { + requests = { + cpu = ref.var.cpu_request; + memory = ref.var.memory_request; + }; + limits = { + cpu = ref.data.coder_parameter.cpu.value; + memory = ref.data.coder_parameter.memory.value; + }; + }; + security_context = { + run_as_user = "1000"; + run_as_group = "1000"; + }; + volume_mount = [ + { + mount_path = "/home"; + name = "home"; + read_only = false; + } + { + mount_path = "/nix"; + name = "nix-store"; + read_only = false; + } + { + mount_path = "/tmp"; + name = "tmp"; + read_only = false; + } + ]; + } + ]; + security_context = { + run_as_user = "1000"; + run_as_group = "1000"; + }; + volume = [ + { + name = "home"; + persistent_volume_claim.claim_name = ref.kubernetes_persistent_volume_claim.home.metadata ".0.name"; + } + { + name = "nix-store"; + persistent_volume_claim.claim_name = ref.kubernetes_persistent_volume_claim.nix-store.metadata ".0.name"; + } + { + name = "tmp"; + empty_dir = { + medium = "Memory"; + # not used for now + # sizeLimit = "200Mi"; + }; + } + ]; + } + ]; + }; + kubernetes_persistent_volume_claim."home" = { + metadata = [ + { + name = "coder-home-${identifier}"; + namespace = ref.var.namespace; + annotations."com.coder.user.email" = ref.data.coder_workspace_owner.me.email; + labels = { + "app.kubernetes.io/instance" = "coder-pvc-home-${identifier}"; + "app.kubernetes.io/name" = "coder-pvc"; + "app.kubernetes.io/part-of" = "coder"; + "com.coder.resource" = "true"; + "com.coder.user.id" = ref.data.coder_workspace_owner.me.id; + "com.coder.user.name" = ref.data.coder_workspace_owner.me.name; + "com.coder.workspace.id" = ref.data.coder_workspace.me.id; + "com.coder.workspace.name" = ref.data.coder_workspace.me.name; + }; + } + ]; + spec = [ + { + access_modes = ["ReadWriteOnce"]; + resources.requests.storage = "${ref.data.coder_parameter.home_disk_size.value}Gi"; + } + ]; + wait_until_bound = false; + }; + kubernetes_persistent_volume_claim."nix-store" = { + metadata = [ + { + name = "coder-nix-store-${identifier}"; + namespace = ref.var.namespace; + annotations."com.coder.user.email" = ref.data.coder_workspace_owner.me.email; + labels = { + "app.kubernetes.io/instance" = "coder-pvc-nix-store-${identifier}"; + "app.kubernetes.io/name" = "coder-pvc"; + "app.kubernetes.io/part-of" = "coder"; + "com.coder.resource" = "true"; + "com.coder.user.id" = ref.data.coder_workspace_owner.me.id; + "com.coder.user.name" = ref.data.coder_workspace_owner.me.name; + "com.coder.workspace.id" = ref.data.coder_workspace.me.id; + "com.coder.workspace.name" = ref.data.coder_workspace.me.name; + }; + } + ]; + spec = [ + { + access_modes = ["ReadWriteOnce"]; + resources.requests.storage = "${ref.data.coder_parameter.nix_store_disk_size.value}Gi"; + } + ]; + wait_until_bound = false; + }; + }; +} diff --git a/nix-kubernetes/parameters.nix b/nix-kubernetes/parameters.nix new file mode 100644 index 0000000..18c88e6 --- /dev/null +++ b/nix-kubernetes/parameters.nix @@ -0,0 +1,112 @@ +{ + data.coder_parameter = { + "dotfiles_repo" = { + name = "Dotfiles Repository (passed to home-manager)"; + description = '' + Nix flake URI to your dotfiles repository, eg. + github:example/dotfiles#coder + + Your flake.nix has to expose a homeManagerConfiguration.coder in this case. + ''; + default = ""; + order = 1; + type = "string"; + mutable = true; + }; + "git_repo" = { + name = "Git Repository"; + description = '' + URI for a git repository which should automatically be cloned to ~/repos/ + ''; + default = ""; + order = 2; + type = "string"; + mutable = true; + }; + "image_tag" = { + name = "Image Tag"; + description = '' + Which container image tag should be used. + ''; + default = "latest"; + order = 3; + type = "string"; + mutable = true; + }; + "cpu" = { + name = "CPU"; + description = '' + CPU Limit for Kubernetes Pod. Kubernetes Notation (eg. 500m) + ''; + default = "500m"; + order = 4; + type = "string"; + mutable = true; + }; + "memory" = { + name = "Memory"; + description = '' + Memory Limit for Kubernetes Pod. Kubernetes Notation (eg. 1Gi) + ''; + default = "1Gi"; + order = 5; + type = "string"; + mutable = true; + }; + "home_disk_size" = { + name = "Home Disk Size"; + description = '' + Size for the /home PV in GB + ''; + default = "5"; + order = 6; + type = "number"; + mutable = true; + validation = [ + { + min = 1; + max = 100; + monotonic = "increasing"; + } + ]; + }; + "nix_store_disk_size" = { + name = "Nix Store Disk Size"; + description = '' + Size for the /nix PV in GB. This might grow pretty big. + ''; + default = "5"; + order = 7; + type = "number"; + mutable = true; + validation = [ + { + min = 1; + max = 100; + monotonic = "increasing"; + } + ]; + }; + "timezone" = { + name = "Timezone"; + description = '' + Content of the TZ environment variable. + ''; + default = ""; + order = 8; + type = "string"; + mutable = true; + }; + "nix_config" = { + name = "Nix Config"; + description = '' + Nix config, will be put into $NIX_CONFIG + ''; + default = ""; + order = 9; + type = "string"; + form_type = "textarea"; + mutable = true; + }; + }; +} diff --git a/nix-kubernetes/variables.nix b/nix-kubernetes/variables.nix new file mode 100644 index 0000000..4662a16 --- /dev/null +++ b/nix-kubernetes/variables.nix @@ -0,0 +1,26 @@ +{ + variable = { + "namespace" = { + type = "string"; + description = "Kubernetes namespace (must exist prior to creating workspaces)"; + }; + "arch" = { + type = "string"; + description = "Architecture of the host"; + validation = { + condition = ''''${contains(["amd64", "arm64"], var.arch)}''; + error_message = "Invalid architecture selected"; + }; + }; + "cpu_request" = { + type = "string"; + description = "CPU request to apply to workspaces. Kubernetes Notation (eg. 500m)"; + default = "0"; + }; + "memory_request" = { + type = "string"; + description = "Memory request to apply to workspaces. Kubernetes Notation (eg. 1Gi)"; + default = "0"; + }; + }; +} diff --git a/nix/packages/flake.lock b/nix/packages/flake.lock new file mode 100644 index 0000000..af7ba8d --- /dev/null +++ b/nix/packages/flake.lock @@ -0,0 +1,28 @@ +{ + "nodes": { + "root": { + "inputs": { + "tofunix-lib": "tofunix-lib" + } + }, + "tofunix-lib": { + "locked": { + "dir": "lib", + "lastModified": 1763036122, + "narHash": "sha256-AFsuSeZ6MjJk5kxfL09rmhKh+AxUICfQhactWAMzVmo=", + "owner": "TECHNOFAB", + "repo": "tofunix", + "rev": "69bffa53c525d6128b6a23743149e37c72d3d5ba", + "type": "gitlab" + }, + "original": { + "dir": "lib", + "owner": "TECHNOFAB", + "repo": "tofunix", + "type": "gitlab" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/nix/packages/flake.nix b/nix/packages/flake.nix new file mode 100644 index 0000000..6f4c53a --- /dev/null +++ b/nix/packages/flake.nix @@ -0,0 +1,10 @@ +{ + inputs = { + tofunix-lib.url = "gitlab:TECHNOFAB/tofunix?dir=lib"; + }; + outputs = i: + i + // { + tofulib = i.tofunix-lib.lib {inherit (i.parent) pkgs;}; + }; +} diff --git a/nix/packages/image.nix b/nix/packages/image.nix new file mode 100644 index 0000000..604766a --- /dev/null +++ b/nix/packages/image.nix @@ -0,0 +1,150 @@ +{ + lib, + pkgs, + ... +}: let + baseSystem = let + packages = with pkgs; [ + nix + bashInteractive + coreutils-full + procps + gnugrep + openssh + gitMinimal + curl + ncurses + less + + cacert.out + + (writeShellScriptBin "reload-dotfiles" '' + ${home-manager}/bin/home-manager switch --flake ''${DOTFILES_REPO:-$1} --option tarball-ttl 0 + '') + ]; + rootEnv = pkgs.buildPackages.buildEnv { + name = "root-profile-env"; + paths = packages; + }; + + nixConf = { + sandbox = "false"; + experimental-features = "nix-command flakes"; + min-free = toString (100 * 1024 * 1024); + max-free = toString (1024 * 1024 * 1024); + }; + + nixConfContents = + (lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: let + vStr = + if builtins.isList v + then lib.concatStringsSep " " v + else v; + in "${n} = ${vStr}") + nixConf)) + + "\n"; + + manifest = pkgs.buildPackages.runCommand "manifest.nix" {} '' + cat > $out < $out/etc/nix/nix.conf + echo "ID=nixos" > $out/etc/os-release + + echo "coder:x:1000:1000::/home/coder:/bin/bash" > $out/etc/passwd + echo "coder:!:::::::" > $out/etc/shadow + echo "coder:x:1000:" > $out/etc/group + echo "coder:x::" > $out/etc/gshadow + echo "coder:100000:65536" > $out/etc/subuid + echo "coder:100000:65536" > $out/etc/subgid + + # support timezones + ln -s ${pkgs.tzdata}/share/zoneinfo $out/etc/zoneinfo + + ln -s ${profile} $out/nix/var/nix/profiles/default-1-link + ln -s /nix/var/nix/profiles/default-1-link $out/nix/var/nix/profiles/default + + # prevents the profiles from being cleaned up by the GC + ln -s /nix/var/nix/profiles $out/nix/var/nix/gcroots/profiles + + ln -s ${pkgs.coreutils}/bin/env $out/usr/bin/env + ln -s ${pkgs.bashInteractive}/bin/bash $out/bin/sh + ln -s ${pkgs.bashInteractive}/bin/bash $out/bin/bash + ''; +in + pkgs.dockerTools.buildLayeredImageWithNixDb { + name = "nix-coder"; + tag = "latest"; + + contents = [baseSystem]; + maxLayers = 10; + + uid = 1000; + gid = 1000; + fakeRootCommands = '' + chown -R 1000:1000 ./ + chmod 1777 tmp + chmod 1777 var/tmp + ''; + + config = { + Cmd = ["/bin/bash"]; + User = "1000:1000"; + Env = [ + "USER=coder" + "HOME=/home/coder" + "TMPDIR=/tmp" + "XDG_RUNTIME_DIR=/tmp" + "TZDIR=/etc/zoneinfo" + "PATH=${lib.concatStringsSep ":" [ + "/home/coder/.nix-profile/bin" + # this makes all the packages defined at the top available + # in the workspace + "/nix/var/nix/profiles/default/bin" + "/nix/var/nix/profiles/default/sbin" + ]}" + "SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt" + "GIT_SSL_CAINFO=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt" + "NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt" + "NIX_PATH=/nix/var/nix/profiles/per-user/coder/channels:/home/coder/.nix-defexpr/channels" + ]; + }; + } diff --git a/nix/packages/packages.nix b/nix/packages/packages.nix new file mode 100644 index 0000000..8beda23 --- /dev/null +++ b/nix/packages/packages.nix @@ -0,0 +1,23 @@ +{inputs, ...}: let + inherit (inputs) self pkgs tofulib; +in rec { + nix-coder-image = pkgs.callPackage ./image.nix {}; + nix-kubernetes = nix-kubernetes-cli.tfjson; + nix-kubernetes-cli = tofulib.mkCliAio { + plugins = [ + (tofulib.mkOpentofuProvider { + owner = "coder"; + repo = "coder"; + version = "2.8.0"; + hash = "sha256-wnjgnD1c6U42ceizqfBG6SE4YXm7rZ7kyYkAdtE8t0k="; + }) + (tofulib.mkOpentofuProvider { + owner = "hashicorp"; + repo = "kubernetes"; + version = "2.29.0"; + hash = "sha256-r8DomSe+gUAbHuc8ciiuVl/6IeeIjJK6HFVaqAsnze8="; + }) + ]; + moduleConfig = "${self}/nix-kubernetes"; + }; +} diff --git a/nix/repo/ci.nix b/nix/repo/ci.nix new file mode 100644 index 0000000..7834b14 --- /dev/null +++ b/nix/repo/ci.nix @@ -0,0 +1,71 @@ +{inputs, ...}: let + inherit (inputs) pkgs cilib; + inherit (pkgs.lib) concatStringsSep; +in + cilib.mkCI { + pipelines."default" = { + stages = ["build" "upload"]; + jobs = let + SYSTEMS = ["aarch64-linux" "x86_64-linux"]; + TEMPLATES = ["nix-kubernetes"]; + in { + "build" = { + stage = "build"; + parallel.matrix = [ + {TEMPLATE = TEMPLATES;} + ]; + nix.deps = [pkgs.gnutar]; + script = [ + # sh + '' + nix build .#''${TEMPLATE} + install -D result templates/''${TEMPLATE}.tf.json + tar -cf templates/''${TEMPLATE}.tar -C templates ''${TEMPLATE}.tf.json + '' + ]; + artifacts.paths = ["templates/"]; + }; + "build:image" = { + stage = "build"; + parallel.matrix = [ + {SYSTEM = SYSTEMS;} + ]; + script = [ + # sh + '' + nix build .#nix-coder-image --system $SYSTEM + install -D result dist/nix-coder-image_''${SYSTEM}.tar.gz + '' + ]; + artifacts.paths = ["dist/"]; + }; + "upload" = { + stage = "upload"; + nix.deps = [pkgs.buildah]; + needs = ["build:image"]; + before_script = [ + # sh + '' + export REGISTRY_AUTH_FILE=''${HOME}/auth.json + echo "$CI_REGISTRY_PASSWORD" | buildah login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY + mkdir -p /etc/containers + echo '{"default":[{"type":"insecureAcceptAnything"}]}' > /etc/containers/policy.json + mkdir -p /var/tmp + '' + ]; + script = [ + # sh + '' + buildah manifest create localhost/nix-coder-image + ${concatStringsSep "\n" (map ( + sys: "buildah manifest add localhost/nix-coder-image docker-archive:dist/nix-coder-image_${sys}.tar.gz" + ) + SYSTEMS)} + buildah manifest push --all localhost/nix-coder-image \ + docker://''${CI_REGISTRY_IMAGE}/nix-coder-image:$CI_COMMIT_SHORT_SHA + '' + ]; + }; + }; + }; + } diff --git a/nix/repo/devShells.nix b/nix/repo/devShells.nix new file mode 100644 index 0000000..7628231 --- /dev/null +++ b/nix/repo/devShells.nix @@ -0,0 +1,23 @@ +{ + inputs, + cell, + ... +}: let + inherit (inputs) pkgs devshell treefmt soonix; + inherit (cell) ci; +in { + default = devshell.mkShell { + imports = [ + soonix.devshellModule + ]; + packages = [ + (treefmt.mkWrapper pkgs { + programs = { + alejandra.enable = true; + mdformat.enable = true; + }; + }) + ]; + soonix.hooks.ci = ci.soonix; + }; +} diff --git a/nix/repo/flake.lock b/nix/repo/flake.lock new file mode 100644 index 0000000..09a1bc6 --- /dev/null +++ b/nix/repo/flake.lock @@ -0,0 +1,82 @@ +{ + "nodes": { + "devshell-lib": { + "locked": { + "dir": "lib", + "lastModified": 1758204313, + "narHash": "sha256-ainbY0Oajb1HMdvy+A8QxF/P5qwcbEzJGEY5pzKdDdc=", + "owner": "rensa-nix", + "repo": "devshell", + "rev": "7d0c4bc78d9f017a739b0c7eb2f4e563118353e6", + "type": "gitlab" + }, + "original": { + "dir": "lib", + "owner": "rensa-nix", + "repo": "devshell", + "type": "gitlab" + } + }, + "nix-gitlab-ci-lib": { + "locked": { + "dir": "lib", + "lastModified": 1763066668, + "narHash": "sha256-mcNiuWf5R0qS7Be4EFAxPStl3SSYPhg4PSPAXgjKJj0=", + "owner": "TECHNOFAB", + "repo": "nix-gitlab-ci", + "rev": "524bdf9cdcfb8008c08d7e54a95992ebf05331d5", + "type": "gitlab" + }, + "original": { + "dir": "lib", + "owner": "TECHNOFAB", + "ref": "3.0.1", + "repo": "nix-gitlab-ci", + "type": "gitlab" + } + }, + "root": { + "inputs": { + "devshell-lib": "devshell-lib", + "nix-gitlab-ci-lib": "nix-gitlab-ci-lib", + "soonix-lib": "soonix-lib", + "treefmt-nix": "treefmt-nix" + } + }, + "soonix-lib": { + "locked": { + "dir": "lib", + "lastModified": 1758615778, + "narHash": "sha256-tggru+siXlLcLUjHtMojkJJWTS/8I3gm8nhnlz+qrTo=", + "owner": "TECHNOFAB", + "repo": "soonix", + "rev": "e04b71c07413251dcb52036b4a51c6c7c0dca2ad", + "type": "gitlab" + }, + "original": { + "dir": "lib", + "owner": "TECHNOFAB", + "repo": "soonix", + "type": "gitlab" + } + }, + "treefmt-nix": { + "flake": false, + "locked": { + "lastModified": 1762410071, + "narHash": "sha256-aF5fvoZeoXNPxT0bejFUBXeUjXfHLSL7g+mjR/p5TEg=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "97a30861b13c3731a84e09405414398fbf3e109f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/nix/repo/flake.nix b/nix/repo/flake.nix new file mode 100644 index 0000000..aa4a142 --- /dev/null +++ b/nix/repo/flake.nix @@ -0,0 +1,19 @@ +{ + inputs = { + devshell-lib.url = "gitlab:rensa-nix/devshell?dir=lib"; + soonix-lib.url = "gitlab:TECHNOFAB/soonix?dir=lib"; + nix-gitlab-ci-lib.url = "gitlab:TECHNOFAB/nix-gitlab-ci/3.0.1?dir=lib"; + treefmt-nix = { + url = "github:numtide/treefmt-nix"; + flake = false; + }; + }; + outputs = i: + i + // { + devshell = i.devshell-lib.lib {inherit (i.parent) pkgs;}; + soonix = i.soonix-lib.lib {inherit (i.parent) pkgs;}; + cilib = i.nix-gitlab-ci-lib.lib {inherit (i.parent) pkgs;}; + treefmt = import i.treefmt-nix; + }; +}