Compare commits

...

12 Commits
hcloud ... main

16 changed files with 391 additions and 187 deletions

22
.auto.tfvars.enc.yaml Normal file
View File

@ -0,0 +1,22 @@
tf_cloud_token: ENC[AES256_GCM,data:XkG5QZ6Ul4tIZELgDE3gBwa+iwyUY175L+szDpfz2u/n345LjDwWAqcbwsSm/c6YRUlxdH1WDvNKUWwnlSyD56ksrfO5t0vqPbIQIeHAD/XlCM21lkiPp1hc,iv:2gTTM5jgDZ39LNjlGgv18RVSAEzBOT0soQ6ip5RFbk4=,tag:JPPyvWxXnV0s9Avp5y9iNA==,type:str]
hcloud_api_token: ENC[AES256_GCM,data:sJW3nPzVKAn2tLJGKcGi7iuA6WfB3B/06R0E5gsOMDLBYMznRnHyP0BtRyLRxfk4RpMAgWI8QWxn7VQsAXjNzw==,iv:RL5JTCy+oU7B9feRZFnKHCFmaEW7O7PB5xzFUpjDhM8=,tag:3S9rJPj5C0DhgCmn2Um/uA==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age1d53yeje0ggysc93uptlpufyhpchyyfs006368j8mw9r20uyeeydse3n7aw
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4RTU4Z3hja24wM1JCU2sz
UFdRQ2loZ25RdmNQN3ZZZXZOTTFoUk1VVVg4ClBybkJoeW5kTDY1TndsYUFQREVr
TENza0M1TDRLTUtMcTJPS3c4K0R5UnMKLS0tIGRHYzBOQ1JHYnhQN1RDWXFMMVQ3
RzNnVTJKSDd0aE41YjRvSmJFVHZDQzQKIvfq+ccMlZ1ypgxrBMOm+On0Nl3GVhKW
Y8b//WmiuhmYZueq7ZMp0gT40144cE1HneDyuVRZ1az5XnFv5OGXag==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2024-01-18T17:54:28Z"
mac: ENC[AES256_GCM,data:nEwl132d1V7+gzQGP/qTl0/VpX7psgdNzmfLLOhefJZGqoC5INCgt5DVGE4fiHv1yM8Q+3irDuQPvx4N0dt1y7lY+UdhqbAhANtI+OPdbuC5xpLplgTUiaLuiPGLbeDpNZxpgxqXK1oVCJF356rEmLevYmytKO8HUFMt+qZjjqE=,iv:40JxgMB/+CxNvOTSwLpZCijni24stfF+Qg8sps3xTCE=,tag:S/7fsmwfJvuW+hexuA4p2g==,type:str]
pgp: []
unencrypted_suffix: _unencrypted
version: 3.8.1

3
.envrc
View File

@ -1 +1,2 @@
use flake
use flake
export SOPS_AGE_KEY_FILE=./keys.txt

3
.gitignore vendored
View File

@ -1,8 +1,5 @@
*.bck
# sops
/secrets.yaml
# age
/keys.txt

View File

@ -4,7 +4,7 @@ keys:
# actual sops config
creation_rules:
- path_regex: secrets(\.enc)?\.yaml$
- path_regex: \.auto\.tfvars(\.enc)?\.(yaml|json)$
key_groups:
- age:
- *automation

View File

@ -1,20 +1,6 @@
# This file is maintained automatically by "tofu init".
# Manual edits may be lost in future updates.
provider "registry.opentofu.org/carlpett/sops" {
version = "1.0.0"
hashes = [
"h1:tnN2Mgl0NUF3cg7a0HtGmtOhHcG+tkaT6ncOPRuA9l8=",
"zh:064e63ea800cd1a8e575064097bc7de6fd5faa8ad50dbb3f2f9d8a3ebc9d7b97",
"zh:0663900085949d2faf24c170c7cdfbf76e545797915cc331da8304144c02bf27",
"zh:2ff26c7e5ee356c30791a12dd8e114c6237bd873d09e52805cb30dd5d758ed23",
"zh:44211fa474112ad0c9fcdae03f13ec7c75cdefd3ab29979b99cb834208055593",
"zh:6c3ab441c12b9679ad1dcac580d1ee7782f0d94efe6da6e983435ed39335cd3f",
"zh:8924cc939b52382ef042dc38bde93cdf438ff0aeab5e1801fbd198f05b80cd47",
"zh:ebc189ce22c23b903399f71e33d465001a79d7de7f7bf115c7763fcf794f4b58",
]
}
provider "registry.opentofu.org/hashicorp/local" {
version = "2.4.1"
hashes = [
@ -52,3 +38,22 @@ provider "registry.opentofu.org/hetznercloud/hcloud" {
"zh:fb0e083d2925f289999dc561ef1c2f84a9e0ab11388c40162ca8b470f50f71f5",
]
}
provider "registry.terraform.io/hashicorp/nomad" {
version = "2.1.0"
hashes = [
"h1:ek0L7fA+4R1/BXhbutSRqlQPzSZ5aY/I2YfVehuYeEU=",
"zh:39ba4d4fc9557d4d2c1e4bf866cf63973359b73e908cce237c54384512bdb454",
"zh:40d2b66e3f3675e6b88000c145977c1d5288510c76b702c6c131d9168546c605",
"zh:40fbe575d85a083f96d4703c6b7334e9fc3e08e4f1d441de2b9513215184ebcc",
"zh:42ce6db79e2f94557fae516ee3f22e5271f0b556638eb45d5fbad02c99fc7af3",
"zh:4acf63dfb92f879b3767529e75764fef68886521b7effa13dd0323c38133ce88",
"zh:72cf35a13c2fb542cd3c8528826e2390db9b8f6f79ccb41532e009ad140a3269",
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
"zh:8b8bcc136c05916234cb0c3bcc3d48fda7ca551a091ad8461ea4ab16fb6960a3",
"zh:8e1c2f924eae88afe7ac83775f000ae8fd71a04e06228edf7eddce4df2421169",
"zh:abc6e725531fc06a8e02e84946aaabc3453ecafbc1b7a442ea175db14fd9c86a",
"zh:b735fcd1fb20971df3e92f81bb6d73eef845dcc9d3d98e908faa3f40013f0f69",
"zh:ce59797282505d872903789db8f092861036da6ec3e73f6507dac725458a5ec9",
]
}

View File

@ -1,6 +1,3 @@
# sops
/secrets.yaml
# age
/keys.txt

View File

@ -11,97 +11,43 @@ Contains [OpenTofu](https://opentofu.org/) code used to manage our infrastructur
## Usage
- Before issuing any other commands, enter the development environment (if not using [`direnv`](https://zero-to-flakes.com/direnv)):
### Development shell
```sh
nix develop -c $SHELL
```
Before issuing any other commands, enter the development environment (if not using [`direnv`](https://zero-to-flakes.com/direnv)):
- Applying changes:
```sh
nix develop -c $SHELL
```
```sh
nix run
```
### Commands
- Validating logic:
```sh
just -l
```
```sh
nix run .#check
```
### Handling [credentials](#secrets)
- Showing the generated plan:
```sh
nix run .#plan
```
- Applying changes, approving automatically:
```sh
nix run .#cd
```
- Removing local state and derived credentials:
```sh
nix run .#destroy
```
- Updating dependencies:
```sh
nix flake update
```
- Simulating a CI test ([substituting](#secrets) `<SOPS_AGE_KEY>`):
```sh
woodpecker-cli exec --env "SOPS_AGE_KEY=<SOPS_AGE_KEY>"
```
### Secrets
## Secrets
- if you want to reset secrets:
- generate an [`age`](https://age-encryption.org/) key pair, using [`rage`](https://github.com/str4d/rage) installed as part of the nix shell:
```sh
rage-keygen -o keys.txt
```
- generate keypair: `just keygen`
- list it in [`sops`](https://getsops.io/) config file `.sops.yaml`
- key setup: set environment variable `SOPS_AGE_KEY_FILE` or `SOPS_AGE_KEY` so `sops` can locate the secret key to an `age` key pair that has its public key listed in `.sops.yaml`
- encoding secrets:
- key setup: set environment variable `SOPS_AGE_KEY_FILE` or `SOPS_AGE_KEY` so `sops` can locate the secret key to an `age` key pair that has its public key listed in `.sops.yaml`, e.g. (listed in `.envrc`):
```sh
sops -e secrets.yaml > secrets.enc.yaml
```
- decoding secrets:
```sh
sops -d secrets.enc.yaml > secrets.yaml
export SOPS_AGE_KEY_FILE=./keys.txt
```
- setting Terraform Cloud credentials, either by:
- reusing the shared session:
```sh
source login.sh
```
- log in to the Terraform Cloud backend:
```sh
tofu login app.terraform.io
```
- decode (as per above) to reuse the shared session
- log in to the Terraform Cloud backend: `just login`
### Configuring
Create a file `.auto.tfvars` containing override for any OpenTofu variables, e.g.:
In `.auto.tfvars.json` override any OpenTofu variables, e.g.:
```tfvars
hcloud_location = "nbg1"
```
## [HCL to Nix](https://gist.github.com/KiaraGrouwstra/249ede6a7dfc00ea44d85bc6bdbcd875)

View File

@ -20,13 +20,10 @@ let
# { a = 1; } -> { name = "a"; a = 1; }
setNames = lib.mapAttrs (k: v: { name = k; } // v);
# "foo" -> "\${data.sops_file.secrets.data[\"foo\"]}"
secret = str: lib.tfRef "data.sops_file.secrets.data[\"${str}\"]";
hetzner = let
# https://docs.hetzner.com/cloud/api/getting-started/generating-api-token
token = secret "hcloud_api_token";
token = lib.tfRef "var.hcloud_api_token";
in { inherit token; };
@ -34,12 +31,6 @@ in rec {
terraform = {
required_providers = {
sops.source = "carlpett/sops";
};
cloud = {
hostname = "app.terraform.io";
organization = "bij1";
@ -52,8 +43,6 @@ in rec {
provider = {
sops = {};
# Configure the Hetzner Cloud Provider
hcloud.token = lib.mkForce hetzner.token;
@ -61,7 +50,9 @@ in rec {
resource = (inNamespace "hcloud" {
ssh_key = setNames (lib.mapAttrs (_: v: { public_key = v; }) my-lib.ssh-keys);
ssh_key = setNames
(lib.mapAttrs (_: v: { public_key = v; })
(my-lib.dirContents ".pub" ./ssh-keys));
});
@ -69,6 +60,18 @@ in rec {
# or using -var="hcloud_api_token=..." CLI option
variable = {
# suppress warning, otherwise unused here
tf_cloud_token = {
type = "string";
sensitive = true;
};
hcloud_api_token = {
type = "string";
description = "[Hetzner Cloud API Token](https://docs.hetzner.com/cloud/api/getting-started/generating-api-token)";
sensitive = true;
};
};
# https://github.com/terranix/terranix-hcloud/blob/main/options.md
@ -82,10 +85,6 @@ in rec {
data = {
sops_file.secrets = {
source_file = "secrets.enc.yaml";
};
hcloud_ssh_keys."all_keys" = {};
};

View File

@ -32,6 +32,21 @@
"type": "github"
}
},
"flake-compat": {
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
@ -50,6 +65,59 @@
"type": "github"
}
},
"gomod2nix": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1705314449,
"narHash": "sha256-yfQQ67dLejP0FLK76LKHbkzcQqNIrux6MFe32MMFGNQ=",
"owner": "tweag",
"repo": "gomod2nix",
"rev": "30e3c3a9ec4ac8453282ca7f67fca9e1da12c3e6",
"type": "github"
},
"original": {
"owner": "tweag",
"repo": "gomod2nix",
"type": "github"
}
},
"nix-nomad": {
"inputs": {
"flake-compat": [
"flake-compat"
],
"flake-utils": [
"flake-utils"
],
"gomod2nix": [
"gomod2nix"
],
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1672531382,
"narHash": "sha256-zbvXzPBBbv5mYPwy/XB3NaBAx3yTYQWNYjz/c/ccH3w=",
"owner": "tristanpemble",
"repo": "nix-nomad",
"rev": "ffbb8c97b2b665ec3a0dd393af79c0192a5546db",
"type": "github"
},
"original": {
"owner": "tristanpemble",
"repo": "nix-nomad",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1704999660,
@ -65,10 +133,49 @@
"type": "github"
}
},
"nixpkgs-lib": {
"locked": {
"lastModified": 1671929364,
"narHash": "sha256-N9GW06FZTKDpkv9YLMXswUxnX27b9qEtfTg7WsSdXjc=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "a909f7a2fb4ec6d14d52b8a727bb9ba465e15766",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"nixpkgs-unfree": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1701957584,
"narHash": "sha256-xEpFaRdrneHl3Xdyzp3emd4QVxML7AR3GC91wuWi0Ok=",
"owner": "numtide",
"repo": "nixpkgs-unfree",
"rev": "127b9b18583de04c6207c2a0e674abf64fc4a3b1",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "nixpkgs-unfree",
"type": "github"
}
},
"root": {
"inputs": {
"flake-compat": "flake-compat",
"flake-utils": "flake-utils",
"gomod2nix": "gomod2nix",
"nix-nomad": "nix-nomad",
"nixpkgs": "nixpkgs",
"nixpkgs-unfree": "nixpkgs-unfree",
"terranix": "terranix",
"terranix-hcloud": "terranix-hcloud"
}

View File

@ -1,7 +1,12 @@
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs";
nixpkgs-unfree = {
url = "github:numtide/nixpkgs-unfree";
inputs.nixpkgs.follows = "nixpkgs";
};
flake-utils.url = "github:numtide/flake-utils";
flake-compat.url = "github:edolstra/flake-compat";
terranix = {
url = "github:terranix/terranix";
inputs.nixpkgs.follows = "nixpkgs";
@ -13,23 +18,45 @@
inputs.flake-utils.follows = "flake-utils";
inputs.terranix.follows = "terranix";
};
nix-nomad = {
url = "github:tristanpemble/nix-nomad";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-utils.follows = "flake-utils";
inputs.flake-compat.follows = "flake-compat";
inputs.gomod2nix.follows = "gomod2nix";
};
gomod2nix = {
url = "github:tweag/gomod2nix";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-utils.follows = "flake-utils";
};
};
outputs = { self, nixpkgs, ... }@inputs:
outputs = { self, nixpkgs, nix-nomad, ... }@inputs:
inputs.flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
tfConfig = inputs.terranix.lib.terranixConfiguration {
inherit system;
modules = [
unfree = inputs.nixpkgs-unfree.legacyPackages.${system}.pkgs;
modules = {
hcloud = [
inputs.terranix-hcloud.terranixModules.hcloud
./config.nix
];
nomad = [
"${nix-nomad}/modules"
./nomad.nix
];
};
tfConfig = modules: inputs.terranix.lib.terranixConfiguration { inherit system modules; };
tfCfg = builtins.mapAttrs (_: tfConfig) {
hcloud = modules.hcloud ++ modules.nomad;
nomad = modules.nomad;
};
tf = "${pkgs.opentofu}/bin/tofu";
sops = "${pkgs.sops}/bin/sops";
in
{
defaultPackage = tfConfig;
defaultPackage = tfCfg.hcloud;
# Auto formatters. This also adds a flake check to ensure that the
# source tree was auto formatted.
@ -44,51 +71,60 @@
devShell = pkgs.mkShell {
buildInputs = with pkgs; [
treefmt
sops
just
pkgs.sops
rage
woodpecker-cli
jq
inputs.terranix.defaultPackage.${system}
(opentofu.withPlugins (p: with p; [
sops # https://registry.terraform.io/providers/carlpett/sops/latest/docs
hcloud # https://registry.terraform.io/providers/hetznercloud/hcloud/latest/docs
nomad # https://registry.terraform.io/providers/hashicorp/nomad/latest/docs
]))
unfree.nomad
damon
levant
];
};
apps = let
locally = ''
# using local state, stash cloud state to prevent error `workspaces not supported`
if [[ -e .terraform/terraform.tfstate ]]; then mv .terraform/terraform.tfstate terraform.tfstate.d/$(tofu workspace show)/terraform.tfstate; fi;
'';
compile = tfModule: ''
echo ${tfModule};
cp ${tfModule} config.tf.json \
&& chmod 0600 config.tf.json;
'';
tfCommand = cmd: ''
if [[ -e config.tf.json ]]; then rm -f config.tf.json; fi;
export TF_CLOUD_TOKEN=$(${pkgs.sops}/bin/sops -d --extract '["tf_cloud_token"]' secrets.enc.yaml)
export TF_CLI_CONFIG_FILE="ci.tfrc"
cat << EOF > "$TF_CLI_CONFIG_FILE"
credentials "app.terraform.io" {
token = "$TF_CLOUD_TOKEN"
}
EOF
cp ${tfConfig} config.tf.json \
&& ${tf} init \
&& ${tf} ${cmd}
# need cloud token as env var for CLI commands like `workspace`
export TF_TOKEN_app_terraform_io="$(${sops} -d --extract '["tf_cloud_token"]' .auto.tfvars.enc.yaml)";
'' + compile tfCfg.hcloud + locally + ''
# load cloud state to prevent error `Cloud backend initialization required: please run "tofu init"`
mv terraform.tfstate.d/hcloud/terraform.tfstate .terraform/terraform.tfstate;
${tf} workspace select -or-create hcloud;
${tf} init && ${tf} ${cmd};
'';
in builtins.mapAttrs (name: script: {
type = "app";
program = toString (pkgs.writers.writeBash name script);
}) {
# nix run .#check
check = tfCommand "validate";
# nix run .#apply
validate = tfCommand "validate";
apply = tfCommand "apply";
# nix run .#plan
plan = tfCommand "plan";
# nix run .#cd
cd = tfCommand "apply -auto-approve";
# nix run .#destroy
local = locally + compile tfCfg.nomad + ''
${tf} workspace select -or-create nomad;
${tf} init && ${tf} apply -auto-approve;
'';
destroy = ''
${tfCommand "destroy"}
rm ${toString ./.}/config.tf.json
rm ${toString ./.}/*.tfstate*
rm ${toString ./.}/secrets.yaml
rm ${toString ./.}/ci.tfrc
for f in "config.tf.json *.tfstate* *.tfvars.json ci.tfrc .terraform terraform.tfstate.d"; do
echo $f
if [[ -e "${toString ./.}/$f" ]]; then
rm -rf "${toString ./.}/$f";
fi;
done
'';
};

0
jobs/.gitkeep Normal file
View File

50
justfile Normal file
View File

@ -0,0 +1,50 @@
# try locally
default: local
# encode secrets
encode:
sops --output-type yaml -e .auto.tfvars.json > .auto.tfvars.enc.yaml
# decode secrets
decode:
sops --output-type json -d .auto.tfvars.enc.yaml > .auto.tfvars.json
# log in to the Terraform Cloud backend
login:
tofu login app.terraform.io
# validate logic
validate:
nix run .#validate
# apply changes
apply:
nix run .#apply
# show generated plan
plan:
nix run .#plan
# run CI test locally
ci:
woodpecker-cli exec --env "SOPS_AGE_KEY=$SOPS_AGE_KEY"
# apply changes, approving automatically
cd:
nix run .#cd
# run Nomad jobs locally
local:
nix run .#local
# generate an [`age`](https://age-encryption.org/) key pair
keygen:
rage-keygen -o keys.txt
# remove local state and derived credentials
destroy:
nix run .#destroy
# update dependencies
update:
nix flake update

View File

@ -1,5 +1,36 @@
{ lib, ... }:
let
# ".ext" -> ./subdir -> { "foo" = "<CONTENTS OF a/b/foo.ext>"; "bar" = "<CONTENTS OF a/b/bar.ext>"; }
dirContents = let
# ".ext" -> "a/b.ext" -> "b"
fileAttrName = suffix: path: let
ext = lib.last (lib.splitString "." path);
in lib.removeSuffix suffix (builtins.baseNameOf path);
# maps a file to a path
# ".ext" -> "a/b" -> "c/d.ext" -> { name = "d"; value = "a/b/c/d.ext"; }
fileAttrInPath = suffix: path: name: {
name = fileAttrName suffix name;
value = path + "/${name}";
};
# get an object of files in a directory with a given suffix
# ".ext" -> "a/b" -> { "foo" = "a/b/foo.ext"; "bar" = "a/b/bar.ext"; }
dirAttrs = suffix: path: lib.mapAttrs'
(name: _: fileAttrInPath suffix path name)
(lib.filterAttrs
(name: type: lib.hasSuffix suffix name && type == "regular")
(builtins.readDir path));
in suffix: path: lib.mapAttrs (_: lib.readFile) (dirAttrs suffix path);
in
{
ssh-keys = import ./ssh-keys.nix { inherit lib; };
inherit dirContents;
}

View File

@ -1,25 +0,0 @@
{ lib, ... }:
let
# "a/b.ext" -> "b"
fileAttrName = path: let
ext = lib.last (lib.splitString "." path);
in lib.removeSuffix ".${ext}" (builtins.baseNameOf path);
# maps a file to a path
# "a/b" -> "c/d.ext" -> { name = "d"; value = "a/b/c/d.ext"; }
fileAttrInPath = path: name: {
name = fileAttrName name;
value = path + "/${name}";
};
# get an object of files in a directory with a given suffix
# "a/b" -> { "foo" = "a/b/foo.ext"; "bar" = "a/b/bar.ext"; }
dirAttrs = suffix: path: lib.mapAttrs'
(name: _: fileAttrInPath path name)
(lib.filterAttrs
(name: type: lib.hasSuffix suffix name && type == "regular")
(builtins.readDir path));
in lib.mapAttrs (_: lib.readFile) (dirAttrs ".pub" ../ssh-keys)

60
nomad.nix Normal file
View File

@ -0,0 +1,60 @@
{ config, options, lib, ... }:
let
var = options.variable;
my-lib = import ./lib/default.nix { inherit lib; };
in
{
terraform.required_providers.nomad.source = "registry.terraform.io/hashicorp/nomad";
# https://developer.hashicorp.com/nomad/docs/job-specification/hcl2/variables
# https://developer.hashicorp.com/nomad/docs/runtime/interpolation
variable = {
nomad_host = {
type = "string";
description = "host of the nomad instance, defaults to local";
default = "http://127.0.0.1";
};
};
provider.nomad.address = "${lib.tfRef "var.nomad_host"}:4646";
# keys: https://tristanpemble.github.io/nix-nomad/
# vals: https://developer.hashicorp.com/nomad/api-docs/json-jobs
# https://github.com/hetznercloud/csi-driver/blob/main/docs/nomad/README.md#getting-started
job = {
bar = {
type = "batch";
group.bar.task.bar = {
driver = "raw_exec";
config = {
command = "echo";
args = ["hello"];
};
};
};
};
# https://registry.terraform.io/providers/hashicorp/nomad/latest/docs/
resource = {
nomad_job =
# nix jobs
lib.mapAttrs (_: v: {
json = true;
jobspec = lib.strings.toJSON v;
}) config.nomad.build.apiJob
# hcl jobs
// lib.mapAttrs (_: v: {
jobspec = v;
}) (my-lib.dirContents ".nomad.hcl" ./jobs);
};
}

View File

@ -1,22 +0,0 @@
tf_cloud_token: ENC[AES256_GCM,data:3vx1n4s7eQxMR2ntOlmnASUuCMxhMMHKLuhf644mNLWbv99aPLsqoUQ+cP01hW/Ra98v3U0C0uYZWfkFn/X8CaVIeu1QPv12D1+XSJB0SJal8NZHJTNVTgzL,iv:W0H4lftTD96/ENjV8tA2a8QqAGI2z/jRvgMtQmaGeB0=,tag:MuXGtyDTbRlNW1xshtCH0g==,type:str]
hcloud_api_token: ENC[AES256_GCM,data:HojFdI9gGnO8IkfOREx4bTqrCNBsCDxnUUOmb+VuLMNIEWEifo9tBhm25I+xAogRd0TuYcY4fkARboGL9qsgrw==,iv:18QLpHdNnG82603FxLL38KJaB9sPJ9gj0vmqQWNb1e0=,tag:/6QPhVZy5P5dvP92HUQR6g==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age1d53yeje0ggysc93uptlpufyhpchyyfs006368j8mw9r20uyeeydse3n7aw
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHa2EzMFlLdTQvMUtzL3FL
Rk5JZEdoVkpEQkk3eTR6QkFKY01CaGVwUnpFCm00OWg2bmJ3U2xRMExyeFZ6WVRB
UWVjVzY5Y01EOUpDNHYrMFYzVE9GUUEKLS0tIE1LYm80b3V3OUkrNWxQVTRaRGhk
TkxRZlprc0I3Q3dQRS82bEd4b1VxTUkKvHZc4c7+9Tsny8w5Cm5L6H+enU1R0tY4
9OcNPXGv8II5OJp1eT14U/sNecPbiBaQSeK4xHaRDKbGyqx92DtQ8A==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2024-01-16T21:29:11Z"
mac: ENC[AES256_GCM,data:eIoSEDuND1O5XPisSs/kq7N1UsiZMer9+Ok43o+8HwfH/HAoElM/0fXNhKQWcQQVUdwLIQnJZzHEXIJ77Uh5sDsWynj3ihJBhruDPu3FxOXTvRHBcdxU31b3iQGliaChRD19L2GDhsNO2Pfvhpoovsy2PHoFtpqtYt4+7UmcOCw=,iv:Zz1czzz+3Tb5f81o6adhO7eJSSr+ksXhMQwendPAhM0=,tag:bjF2pXTkGxef9+1kKw0FlQ==,type:str]
pgp: []
unencrypted_suffix: _unencrypted
version: 3.8.1