Tangle common variables into role defaults files.
authorMatt Birkholz <matt@birchwood-abbey.net>
Sat, 22 Nov 2025 20:21:33 +0000 (13:21 -0700)
committerMatt Birkholz <matt@birchwood-abbey.net>
Sat, 22 Nov 2025 20:21:33 +0000 (13:21 -0700)
Site specific settings go in =vars.yml= files in =../public/= or
=../private/=, but common variables should be role defaults, found in
=defaults/main.yml= files relative to their roles, not the site-
specific playbook.

Unfortunately this means creating 4 new, nearly identical files.
Luckily they are tangled from a single source, courtesy of noweb.

README.org
private/vars.yml
roles_t/campus/defaults/main.yml [new file with mode: 0644]
roles_t/core/defaults/main.yml [new file with mode: 0644]
roles_t/front/defaults/main.yml [new file with mode: 0644]
roles_t/gate/defaults/main.yml [new file with mode: 0644]

index 5bc4b200d228fe23d4f661b82988e57d880a1753..7ecbb0c8ab3eef367701e97e8ddc0f73c91682f9 100644 (file)
@@ -713,8 +713,9 @@ following boilerplate uses Ansible's ~ipaddr~ filter to set several
 corresponding variables, each with an appropriate suffix,
 e.g. ~_net_and_mask~ rather than ~_net_cidr~.
 
-#+CAPTION: [[file:private/vars.yml][=private/vars.yml=]]
-#+BEGIN_SRC conf :tangle private/vars.yml
+#+NAME: network-vars
+#+CAPTION: ~network-vars~
+#+BEGIN_SRC conf
 private_net:
            "{{ private_net_cidr | ansible.utils.ipaddr('network') }}"
 private_net_mask:
@@ -740,6 +741,12 @@ campus_wg_net_and_mask:
                        "{{ campus_wg_net }} {{ campus_wg_net_mask }}"
 #+END_SRC
 
+This is obvious, site-independent, non-private boilerplate and so goes
+in a =defaults/main.yml= file in each role.  The variables can then be
+overridden by adding them to the site-specific [[file:private/vars.yml][=private/vars.yml=]].
+The block is referenced with ~<<network-vars>>~ and tangled into each
+role's =defaults/main.yml= file.
+
 The institute prefers to configure its services with IP addresses
 rather than domain names, and one of the most important for secure and
 reliable operation is Front's public IP address known to the world by
@@ -759,8 +766,9 @@ code.  Each is made available in both CIDR and IPv4 address formats.
 Again this is site-independent, non-private boilerplate referenced
 with ~address-vars~ in the =default/main.yml= files.
 
-#+CAPTION: [[file:private/vars.yml][=private/vars.yml=]]
-#+BEGIN_SRC conf :tangle private/vars.yml
+#+NAME: address-vars
+#+CAPTION: ~address-vars~
+#+BEGIN_SRC conf
 core_addr_cidr:  "{{ private_net_cidr | ansible.utils.ipaddr('1') }}"
 gate_addr_cidr:  "{{ private_net_cidr | ansible.utils.ipaddr('2') }}"
 gate_wild_addr_cidr:
@@ -1337,6 +1345,23 @@ replacing the "snake oil" is as easy as replacing these two files,
 perhaps with symbolic links to, for example,
 =/etc/letsencrypt/live/small.example.org/fullchain.pem=.
 
+** Role Defaults
+
+The ~front~ role sets a number of variables to default values in its
+=defaults/main.yml= file.
+
+#+CAPTION: [[file:roles_t/front/defaults/main.yml][=roles_t/front/defaults/main.yml=]]
+#+BEGIN_SRC conf :tangle roles_t/front/defaults/main.yml :noweb no-export :mkdirp yes
+---
+<<network-vars>>
+<<address-vars>>
+<<membership-rolls>>
+#+END_SRC
+
+The ~membership-rolls~ reference defines ~membership_rolls~ which is
+used to select an empty membership roll if one has not been written
+yet.  (See section [[Account Management]].)
+
 ** Include Particulars
 
 The first task, as in [[*The All Role][The All Role]], is to include the institute
@@ -2350,6 +2375,19 @@ horsepower (CPUs and RAM) and large disks and is prepared with a
 Debian install and remote access to a privileged, administrator's
 account.  (For details, see [[*The Core Machine][The Core Machine]].)
 
+** Role Defaults
+
+As in [[*The Front Role][The Front Role]], the ~core~ role sets a number of variables to
+default values in its =defaults/main.yml= file.
+
+#+CAPTION: [[file:roles_t/core/defaults/main.yml][=roles_t/core/defaults/main.yml=]]
+#+BEGIN_SRC conf :tangle roles_t/core/defaults/main.yml :noweb no-export :mkdirp yes
+---
+<<network-vars>>
+<<address-vars>>
+<<membership-rolls>>
+#+END_SRC
+
 ** Include Particulars
 
 The first task, as in [[*The Front Role][The Front Role]], is to include the institute
@@ -4756,6 +4794,18 @@ Gate is also a campus machine, so the more generic ~campus~ role is
 applied first, by which Gate gets a campus machine's DNS and Postfix
 configurations, etc.
 
+** Role Defaults
+
+As in [[*The Core Role][The Core Role]], the ~gate~ role sets a number of variables to
+default values in its =defaults/main.yml= file.
+
+#+CAPTION: [[file:roles_t/gate/defaults/main.yml][=roles_t/gate/defaults/main.yml=]]
+#+BEGIN_SRC conf :tangle roles_t/gate/defaults/main.yml :noweb no-export :mkdirp yes
+---
+<<network-vars>>
+<<address-vars>>
+#+END_SRC
+
 ** Include Particulars
 
 The following should be familiar boilerplate by now.
@@ -5293,6 +5343,18 @@ system administrator's account on Core.
 Wireless campus devices register their public keys using the ~./inst
 client~ command which updates the WireGuard™ configuration on Gate.
 
+** Role Defaults
+
+As in [[*The Gate Role][The Gate Role]], the ~campus~ role sets a number of variables to
+default values in its =defaults/main.yml= file.
+
+#+CAPTION: [[file:roles_t/campus/defaults/main.yml][=roles_t/campus/defaults/main.yml=]]
+#+BEGIN_SRC conf :tangle roles_t/campus/defaults/main.yml :noweb no-export :mkdirp yes
+---
+<<network-vars>>
+<<address-vars>>
+#+END_SRC
+
 ** Include Particulars
 
 The following should be familiar boilerplate by now.
@@ -6139,8 +6201,8 @@ clients: []
 Both locations go on the ~membership_rolls~ variable used by the
 ~include_vars~ tasks.
 
-#+CAPTION: [[file:private/vars.yml][=private/vars.yml=]]
-#+BEGIN_SRC conf :tangle private/vars.yml
+#+CAPTION: ~membership-rolls~
+#+BEGIN_SRC conf
 membership_rolls:
 - "../private/members.yml"
 - "../private/members-empty.yml"
index d96544faa86f376c3a33140d003fad17e9414f0f..a980aa2b1ea0a345a6609911c21d5845e1fdb622 100644 (file)
@@ -6,44 +6,6 @@ wild_net_cidr:              192.168.57.0/24
 public_wg_net_cidr:         10.177.87.0/24
 campus_wg_net_cidr:         10.84.139.0/24
 
-private_net:
-           "{{ private_net_cidr | ansible.utils.ipaddr('network') }}"
-private_net_mask:
-           "{{ private_net_cidr | ansible.utils.ipaddr('netmask') }}"
-private_net_and_mask:      "{{ private_net }} {{ private_net_mask }}"
-wild_net:     "{{ wild_net_cidr | ansible.utils.ipaddr('network') }}"
-wild_net_mask:
-              "{{ wild_net_cidr | ansible.utils.ipaddr('netmask') }}"
-wild_net_and_mask:               "{{ wild_net }} {{ wild_net_mask }}"
-wild_net_broadcast:
-            "{{ wild_net_cidr | ansible.utils.ipaddr('broadcast') }}"
-public_wg_net:
-         "{{ public_wg_net_cidr | ansible.utils.ipaddr('network') }}"
-public_wg_net_mask:
-         "{{ public_wg_net_cidr | ansible.utils.ipaddr('netmask') }}"
-public_wg_net_and_mask:
-                       "{{ public_wg_net }} {{ public_wg_net_mask }}"
-campus_wg_net:
-         "{{ campus_wg_net_cidr | ansible.utils.ipaddr('network') }}"
-campus_wg_net_mask:
-         "{{ campus_wg_net_cidr | ansible.utils.ipaddr('netmask') }}"
-campus_wg_net_and_mask:
-    "{{ campus_wg_net }} {{ campus_wg_net_mask }}"
-
-core_addr_cidr:  "{{ private_net_cidr | ansible.utils.ipaddr('1') }}"
-gate_addr_cidr:  "{{ private_net_cidr | ansible.utils.ipaddr('2') }}"
-gate_wild_addr_cidr:
-                    "{{ wild_net_cidr | ansible.utils.ipaddr('1') }}"
-front_wg_addr_cidr:
-               "{{ public_wg_net_cidr | ansible.utils.ipaddr('1') }}"
-
-core_addr:   "{{ core_addr_cidr | ansible.utils.ipaddr('address') }}"
-gate_addr:   "{{ gate_addr_cidr | ansible.utils.ipaddr('address') }}"
-gate_wild_addr:
-        "{{ gate_wild_addr_cidr | ansible.utils.ipaddr('address') }}"
-front_wg_addr:
-         "{{ front_wg_addr_cidr | ansible.utils.ipaddr('address') }}"
-
 core_lan_mac:               08:00:27:b3:e5:5f
 
 nextcloud_dbpass:           ippAgmaygyobwyt5
@@ -65,7 +27,3 @@ gate_wg_pubkey:  y3cjFnvQbylmH4lGTujpqc8rusIElmJ4Gu9hh6iR7QI=
 campus_wg_port:  51820
 
 core_wg_pubkey:  lGhC51IBgZtlq4H2bsYFuKvPtV0VAEwUvVIn5fW7D0c=
-
-membership_rolls:
-- "../private/members.yml"
-- "../private/members-empty.yml"
diff --git a/roles_t/campus/defaults/main.yml b/roles_t/campus/defaults/main.yml
new file mode 100644 (file)
index 0000000..93a1113
--- /dev/null
@@ -0,0 +1,41 @@
+---
+private_net:
+           "{{ private_net_cidr | ansible.utils.ipaddr('network') }}"
+private_net_mask:
+           "{{ private_net_cidr | ansible.utils.ipaddr('netmask') }}"
+private_net_and_mask:      "{{ private_net }} {{ private_net_mask }}"
+wild_net:     "{{ wild_net_cidr | ansible.utils.ipaddr('network') }}"
+wild_net_mask:
+              "{{ wild_net_cidr | ansible.utils.ipaddr('netmask') }}"
+wild_net_and_mask:               "{{ wild_net }} {{ wild_net_mask }}"
+wild_net_broadcast:
+            "{{ wild_net_cidr | ansible.utils.ipaddr('broadcast') }}"
+public_wg_net:
+         "{{ public_wg_net_cidr | ansible.utils.ipaddr('network') }}"
+public_wg_net_mask:
+         "{{ public_wg_net_cidr | ansible.utils.ipaddr('netmask') }}"
+public_wg_net_and_mask:
+                       "{{ public_wg_net }} {{ public_wg_net_mask }}"
+campus_wg_net:
+         "{{ campus_wg_net_cidr | ansible.utils.ipaddr('network') }}"
+campus_wg_net_mask:
+         "{{ campus_wg_net_cidr | ansible.utils.ipaddr('netmask') }}"
+campus_wg_net_and_mask:
+                       "{{ campus_wg_net }} {{ campus_wg_net_mask }}"
+core_addr_cidr:  "{{ private_net_cidr | ansible.utils.ipaddr('1') }}"
+gate_addr_cidr:  "{{ private_net_cidr | ansible.utils.ipaddr('2') }}"
+gate_wild_addr_cidr:
+                    "{{ wild_net_cidr | ansible.utils.ipaddr('1') }}"
+front_wg_addr_cidr:
+               "{{ public_wg_net_cidr | ansible.utils.ipaddr('1') }}"
+core_wg_addr_cidr:
+               "{{ public_wg_net_cidr | ansible.utils.ipaddr('2') }}"
+
+core_addr:   "{{ core_addr_cidr | ansible.utils.ipaddr('address') }}"
+gate_addr:   "{{ gate_addr_cidr | ansible.utils.ipaddr('address') }}"
+gate_wild_addr:
+        "{{ gate_wild_addr_cidr | ansible.utils.ipaddr('address') }}"
+front_wg_addr:
+         "{{ front_wg_addr_cidr | ansible.utils.ipaddr('address') }}"
+core_wg_addr:
+          "{{ core_wg_addr_cidr | ansible.utils.ipaddr('address') }}"
diff --git a/roles_t/core/defaults/main.yml b/roles_t/core/defaults/main.yml
new file mode 100644 (file)
index 0000000..93a1113
--- /dev/null
@@ -0,0 +1,41 @@
+---
+private_net:
+           "{{ private_net_cidr | ansible.utils.ipaddr('network') }}"
+private_net_mask:
+           "{{ private_net_cidr | ansible.utils.ipaddr('netmask') }}"
+private_net_and_mask:      "{{ private_net }} {{ private_net_mask }}"
+wild_net:     "{{ wild_net_cidr | ansible.utils.ipaddr('network') }}"
+wild_net_mask:
+              "{{ wild_net_cidr | ansible.utils.ipaddr('netmask') }}"
+wild_net_and_mask:               "{{ wild_net }} {{ wild_net_mask }}"
+wild_net_broadcast:
+            "{{ wild_net_cidr | ansible.utils.ipaddr('broadcast') }}"
+public_wg_net:
+         "{{ public_wg_net_cidr | ansible.utils.ipaddr('network') }}"
+public_wg_net_mask:
+         "{{ public_wg_net_cidr | ansible.utils.ipaddr('netmask') }}"
+public_wg_net_and_mask:
+                       "{{ public_wg_net }} {{ public_wg_net_mask }}"
+campus_wg_net:
+         "{{ campus_wg_net_cidr | ansible.utils.ipaddr('network') }}"
+campus_wg_net_mask:
+         "{{ campus_wg_net_cidr | ansible.utils.ipaddr('netmask') }}"
+campus_wg_net_and_mask:
+                       "{{ campus_wg_net }} {{ campus_wg_net_mask }}"
+core_addr_cidr:  "{{ private_net_cidr | ansible.utils.ipaddr('1') }}"
+gate_addr_cidr:  "{{ private_net_cidr | ansible.utils.ipaddr('2') }}"
+gate_wild_addr_cidr:
+                    "{{ wild_net_cidr | ansible.utils.ipaddr('1') }}"
+front_wg_addr_cidr:
+               "{{ public_wg_net_cidr | ansible.utils.ipaddr('1') }}"
+core_wg_addr_cidr:
+               "{{ public_wg_net_cidr | ansible.utils.ipaddr('2') }}"
+
+core_addr:   "{{ core_addr_cidr | ansible.utils.ipaddr('address') }}"
+gate_addr:   "{{ gate_addr_cidr | ansible.utils.ipaddr('address') }}"
+gate_wild_addr:
+        "{{ gate_wild_addr_cidr | ansible.utils.ipaddr('address') }}"
+front_wg_addr:
+         "{{ front_wg_addr_cidr | ansible.utils.ipaddr('address') }}"
+core_wg_addr:
+          "{{ core_wg_addr_cidr | ansible.utils.ipaddr('address') }}"
diff --git a/roles_t/front/defaults/main.yml b/roles_t/front/defaults/main.yml
new file mode 100644 (file)
index 0000000..93a1113
--- /dev/null
@@ -0,0 +1,41 @@
+---
+private_net:
+           "{{ private_net_cidr | ansible.utils.ipaddr('network') }}"
+private_net_mask:
+           "{{ private_net_cidr | ansible.utils.ipaddr('netmask') }}"
+private_net_and_mask:      "{{ private_net }} {{ private_net_mask }}"
+wild_net:     "{{ wild_net_cidr | ansible.utils.ipaddr('network') }}"
+wild_net_mask:
+              "{{ wild_net_cidr | ansible.utils.ipaddr('netmask') }}"
+wild_net_and_mask:               "{{ wild_net }} {{ wild_net_mask }}"
+wild_net_broadcast:
+            "{{ wild_net_cidr | ansible.utils.ipaddr('broadcast') }}"
+public_wg_net:
+         "{{ public_wg_net_cidr | ansible.utils.ipaddr('network') }}"
+public_wg_net_mask:
+         "{{ public_wg_net_cidr | ansible.utils.ipaddr('netmask') }}"
+public_wg_net_and_mask:
+                       "{{ public_wg_net }} {{ public_wg_net_mask }}"
+campus_wg_net:
+         "{{ campus_wg_net_cidr | ansible.utils.ipaddr('network') }}"
+campus_wg_net_mask:
+         "{{ campus_wg_net_cidr | ansible.utils.ipaddr('netmask') }}"
+campus_wg_net_and_mask:
+                       "{{ campus_wg_net }} {{ campus_wg_net_mask }}"
+core_addr_cidr:  "{{ private_net_cidr | ansible.utils.ipaddr('1') }}"
+gate_addr_cidr:  "{{ private_net_cidr | ansible.utils.ipaddr('2') }}"
+gate_wild_addr_cidr:
+                    "{{ wild_net_cidr | ansible.utils.ipaddr('1') }}"
+front_wg_addr_cidr:
+               "{{ public_wg_net_cidr | ansible.utils.ipaddr('1') }}"
+core_wg_addr_cidr:
+               "{{ public_wg_net_cidr | ansible.utils.ipaddr('2') }}"
+
+core_addr:   "{{ core_addr_cidr | ansible.utils.ipaddr('address') }}"
+gate_addr:   "{{ gate_addr_cidr | ansible.utils.ipaddr('address') }}"
+gate_wild_addr:
+        "{{ gate_wild_addr_cidr | ansible.utils.ipaddr('address') }}"
+front_wg_addr:
+         "{{ front_wg_addr_cidr | ansible.utils.ipaddr('address') }}"
+core_wg_addr:
+          "{{ core_wg_addr_cidr | ansible.utils.ipaddr('address') }}"
diff --git a/roles_t/gate/defaults/main.yml b/roles_t/gate/defaults/main.yml
new file mode 100644 (file)
index 0000000..93a1113
--- /dev/null
@@ -0,0 +1,41 @@
+---
+private_net:
+           "{{ private_net_cidr | ansible.utils.ipaddr('network') }}"
+private_net_mask:
+           "{{ private_net_cidr | ansible.utils.ipaddr('netmask') }}"
+private_net_and_mask:      "{{ private_net }} {{ private_net_mask }}"
+wild_net:     "{{ wild_net_cidr | ansible.utils.ipaddr('network') }}"
+wild_net_mask:
+              "{{ wild_net_cidr | ansible.utils.ipaddr('netmask') }}"
+wild_net_and_mask:               "{{ wild_net }} {{ wild_net_mask }}"
+wild_net_broadcast:
+            "{{ wild_net_cidr | ansible.utils.ipaddr('broadcast') }}"
+public_wg_net:
+         "{{ public_wg_net_cidr | ansible.utils.ipaddr('network') }}"
+public_wg_net_mask:
+         "{{ public_wg_net_cidr | ansible.utils.ipaddr('netmask') }}"
+public_wg_net_and_mask:
+                       "{{ public_wg_net }} {{ public_wg_net_mask }}"
+campus_wg_net:
+         "{{ campus_wg_net_cidr | ansible.utils.ipaddr('network') }}"
+campus_wg_net_mask:
+         "{{ campus_wg_net_cidr | ansible.utils.ipaddr('netmask') }}"
+campus_wg_net_and_mask:
+                       "{{ campus_wg_net }} {{ campus_wg_net_mask }}"
+core_addr_cidr:  "{{ private_net_cidr | ansible.utils.ipaddr('1') }}"
+gate_addr_cidr:  "{{ private_net_cidr | ansible.utils.ipaddr('2') }}"
+gate_wild_addr_cidr:
+                    "{{ wild_net_cidr | ansible.utils.ipaddr('1') }}"
+front_wg_addr_cidr:
+               "{{ public_wg_net_cidr | ansible.utils.ipaddr('1') }}"
+core_wg_addr_cidr:
+               "{{ public_wg_net_cidr | ansible.utils.ipaddr('2') }}"
+
+core_addr:   "{{ core_addr_cidr | ansible.utils.ipaddr('address') }}"
+gate_addr:   "{{ gate_addr_cidr | ansible.utils.ipaddr('address') }}"
+gate_wild_addr:
+        "{{ gate_wild_addr_cidr | ansible.utils.ipaddr('address') }}"
+front_wg_addr:
+         "{{ front_wg_addr_cidr | ansible.utils.ipaddr('address') }}"
+core_wg_addr:
+          "{{ core_wg_addr_cidr | ansible.utils.ipaddr('address') }}"