initial import
This commit is contained in:
parent
1869730067
commit
a5ece1f3ce
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
.*
|
||||||
|
\#*
|
||||||
|
*~
|
||||||
|
result
|
||||||
|
!.gitignore
|
7
LICENSE
Executable file
7
LICENSE
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
Copyright 2022 James Andariese
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
31
README.md
Normal file
31
README.md
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# `cascade`
|
||||||
|
|
||||||
|
The next iteration of the cascade network.
|
||||||
|
|
||||||
|
Should it have been thunder?
|
||||||
|
|
||||||
|
Probably.
|
||||||
|
|
||||||
|
It's cascade anyway.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
From a [Proxmox VE][PVE] machine with [Nix][NIX] installed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix-shell
|
||||||
|
```
|
||||||
|
|
||||||
|
Guidance will be printed which should be followed.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
In order to discover your network and configure hosts, this configuration management system requires the following:
|
||||||
|
* Samba DC with functioning DNS and DHCP server.
|
||||||
|
* You must be able to auth with Kerberos to Samba.
|
||||||
|
* Proxmox running on the local host
|
||||||
|
* Proxmox should have a local filesystem called hdd-fs
|
||||||
|
|
||||||
|
|
||||||
|
NIX: https://www.nixos.org
|
||||||
|
PVE: https://www.proxmox.com/en/proxmox-ve
|
37
common/bash-is-needed.nix
Normal file
37
common/bash-is-needed.nix
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
environment.binbash.enable = mkOption {
|
||||||
|
default = true;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Include a /bin/bash in the system.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
environment.binbash.bash = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
default = pkgs.bashInteractive;
|
||||||
|
defaultText = literalExpression "pkgs.bashInteractive";
|
||||||
|
example = literalExpression "pkgs.bash";
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
The bash implementation that will be present in
|
||||||
|
`/bin/bash` after enabling this option.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
system.activationScripts.binbash = if config.environment.binbash.enable
|
||||||
|
then ''
|
||||||
|
mkdir -m 0755 -p /bin
|
||||||
|
ln -sfn ${config.environment.binbash.bash}/bin/bash /bin/.bash.tmp
|
||||||
|
mv /bin/.bash.tmp /bin/bash # atomically replace /usr/bin/env
|
||||||
|
''
|
||||||
|
else ''
|
||||||
|
rm -f /bin/bash
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
21
common/cascade-networking.nix
Normal file
21
common/cascade-networking.nix
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{config, lib, ...}: {
|
||||||
|
|
||||||
|
options = with lib; with types; {
|
||||||
|
cascade.bridge-interface = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "interface on which to create primary bridge (br0)";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = with lib; {
|
||||||
|
networking = {
|
||||||
|
useNetworkd = mkForce true;
|
||||||
|
|
||||||
|
bridges.br0.interfaces = [config.cascade.bridge-interface];
|
||||||
|
interfaces.br0.useDHCP = mkImageMediaOverride true;
|
||||||
|
};
|
||||||
|
#systemd.network.links."05-br0".matchConfig.Name = "br0";
|
||||||
|
#systemd.network.links."05-br0".linkConfig.MACAddressPolicy = "none";
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
11
common/default.nix
Normal file
11
common/default.nix
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
let _ = builtins.trace "${toString ./.}/default.nix"; in
|
||||||
|
{...}:
|
||||||
|
with builtins;
|
||||||
|
with import (toString ../functions);
|
||||||
|
|
||||||
|
let folder = import-folder {path = "${toString ./.}"; filenameMatch = ".*[.]nix"; filenameBadMatch = ".*_.*";};
|
||||||
|
goodNames = attrNames folder;
|
||||||
|
goodPaths = map (n: "${toString ./.}/${n}.nix") goodNames;
|
||||||
|
in
|
||||||
|
|
||||||
|
{ imports = goodPaths; }
|
7
common/ssh.nix
Normal file
7
common/ssh.nix
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{ pkgs, config, ... }: {
|
||||||
|
|
||||||
|
config.programs.ssh.package = pkgs.openssh_gssapi;
|
||||||
|
config.services.openssh.enable = true;
|
||||||
|
config.networking.firewall.allowedTCPPorts = [ 22 ];
|
||||||
|
|
||||||
|
}
|
24
common/users.nix
Normal file
24
common/users.nix
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{pkgs, ...}: {
|
||||||
|
config = {
|
||||||
|
users.users = rec {
|
||||||
|
james = {
|
||||||
|
createHome = true;
|
||||||
|
description = "James Andariese";
|
||||||
|
extraGroups = [ "wheel" ];
|
||||||
|
group = "users";
|
||||||
|
home = "/home/james";
|
||||||
|
shell = pkgs.bashInteractive;
|
||||||
|
uid = 1982;
|
||||||
|
isNormalUser = true;
|
||||||
|
openssh.authorizedKeys.keys = [
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBDEj6S+ISygrn6D7a5GBsrYaUMWjcReyMmrlgRdDUGx james@chimecho"
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBW+t2we/HTgV9ykgcQWiHqiA+vEehVhwOcbsLr4jJvL james@Jamess-MBP.cascade.strudelline.net"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
root.shell = james.shell;
|
||||||
|
root.openssh.authorizedKeys.keys = james.openssh.authorizedKeys.keys;
|
||||||
|
};
|
||||||
|
security.sudo.wheelNeedsPassword = false;
|
||||||
|
nix.settings.trusted-users = [ "root" "@wheel" ];
|
||||||
|
};
|
||||||
|
}
|
20
custom-image-configuration.nix
Normal file
20
custom-image-configuration.nix
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./common
|
||||||
|
];
|
||||||
|
|
||||||
|
config = {
|
||||||
|
system.stateVersion = "22.11";
|
||||||
|
|
||||||
|
nix.nixPath = [
|
||||||
|
"nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos"
|
||||||
|
"nixos-config=/etc/nixos/configuration.nix"
|
||||||
|
"hardware-config=/etc/nixos/hardware-configuration.nix"
|
||||||
|
"/nix/var/nix/profiles/per-user/root/channels"
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
# also pull in all of the qemu-vm profile which will be the basis of the live config
|
||||||
|
// (builtins.removeAttrs (import ./profiles/qemu-vm {inherit lib;}) [ "deployment" ]);
|
||||||
|
}
|
21
custom-image.nix
Normal file
21
custom-image.nix
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{}:
|
||||||
|
let
|
||||||
|
myisoconfig = import ./custom-image-configuration.nix;
|
||||||
|
|
||||||
|
copyChannel = true;
|
||||||
|
system = "x86_64-linux";
|
||||||
|
evalNixos = configuration: import <nixpkgs/nixos> {
|
||||||
|
inherit system configuration;
|
||||||
|
};
|
||||||
|
resultOfEval = (evalNixos myisoconfig);
|
||||||
|
lib = resultOfEval.pkgs.lib;
|
||||||
|
pkgs = resultOfEval.pkgs;
|
||||||
|
config = resultOfEval.config;
|
||||||
|
in
|
||||||
|
import <nixpkgs/nixos/lib/make-disk-image.nix> {
|
||||||
|
inherit lib copyChannel pkgs config;
|
||||||
|
diskSize = "20480";
|
||||||
|
format = "raw";
|
||||||
|
installBootLoader = true;
|
||||||
|
partitionTableType = "hybrid";
|
||||||
|
}
|
5
functions/default.nix
Normal file
5
functions/default.nix
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
let _ = builtins.trace "${toString ./.}/default.nix"; in
|
||||||
|
|
||||||
|
let import-folder = import (toString ./import-folder.nix);
|
||||||
|
in
|
||||||
|
import-folder {path = (toString ./.);}
|
17
functions/import-folder.nix
Normal file
17
functions/import-folder.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
with builtins;
|
||||||
|
let mkIsFilenameAMatch = {filenameMatch ? "[^_].*", filenameBadMatch ? null, ...}@opt:
|
||||||
|
{name, type, ...}:
|
||||||
|
if name == "default.nix" then false
|
||||||
|
else if builtins.match filenameMatch name == null then false
|
||||||
|
else if filenameBadMatch != null && builtins.match filenameBadMatch name != null then false
|
||||||
|
else if ! elem type ["symlink" "regular"] then false
|
||||||
|
else if builtins.match ".*[.]nix" name == null then false
|
||||||
|
else true;
|
||||||
|
readDirItems = import ./readDirItems.nix;
|
||||||
|
extractName = fn: let m = match "(.*[/])?([a-zA-Z0-9-]+)[.]nix" fn; in if m == null then throw "${fn} does not seem to have a correct filename" else head (tail m);
|
||||||
|
matches = {path, ...}@opt:
|
||||||
|
let isFilenameAMatch = mkIsFilenameAMatch opt;
|
||||||
|
in
|
||||||
|
listToAttrs (map ({name,...}: let pname = name; in {name = "${extractName name}"; value = import "${path}/${name}";}) (filter isFilenameAMatch (readDirItems "${path}" )));
|
||||||
|
in
|
||||||
|
matches
|
3
functions/mkAttrItemsFunction.nix
Normal file
3
functions/mkAttrItemsFunction.nix
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
with builtins;
|
||||||
|
|
||||||
|
kname: vname: aset: attrValues (mapAttrs (k: v: {"${kname}" = k; "${vname}" = v;}) aset)
|
3
functions/readDirItems.nix
Normal file
3
functions/readDirItems.nix
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
with builtins;
|
||||||
|
|
||||||
|
p: (import ./mkAttrItemsFunction.nix) "name" "type" (readDir p)
|
8
hosts/_basic.nix
Normal file
8
hosts/_basic.nix
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{ nodes, config, pkgs, ... }: {
|
||||||
|
imports = [
|
||||||
|
(toString ../profiles/qemu-vm)
|
||||||
|
];
|
||||||
|
config = {
|
||||||
|
deployment.tags = [ ];
|
||||||
|
};
|
||||||
|
}
|
5
hosts/default.nix
Normal file
5
hosts/default.nix
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
let _ = builtins.trace "${toString ./.}/default.nix"; in
|
||||||
|
with builtins;
|
||||||
|
with import (toString ../functions);
|
||||||
|
|
||||||
|
import-folder {path = "${toString ./.}"; filenameMatch = ".*[.]nix"; filenameBadMatch = ".*_.*";}
|
13
network.nix
Normal file
13
network.nix
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
with builtins;
|
||||||
|
|
||||||
|
let pkgs = import <nixpkgs> {};
|
||||||
|
network = {
|
||||||
|
inherit pkgs;
|
||||||
|
description = "cascade";
|
||||||
|
};
|
||||||
|
hosts = import (toString ./hosts);
|
||||||
|
in
|
||||||
|
|
||||||
|
hosts // {
|
||||||
|
inherit network;
|
||||||
|
}
|
48
profiles/api/default.nix
Normal file
48
profiles/api/default.nix
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||||
|
# and may be overwritten by future invocations. Please make changes
|
||||||
|
# to /etc/nixos/configuration.nix instead.
|
||||||
|
{ config, lib, pkgs, modulesPath, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [ (toString ../base) ];
|
||||||
|
|
||||||
|
config = {
|
||||||
|
deployment.targetUser = "root";
|
||||||
|
boot.initrd.availableKernelModules = [ "xhci_pci" "dwc3_pci" "usbhid" "usb_storage" "uas" "sd_mod" "sdhci_acpi" ];
|
||||||
|
boot.initrd.kernelModules = [ ];
|
||||||
|
boot.kernelModules = [ "kvm-intel" ];
|
||||||
|
boot.extraModulePackages = [ ];
|
||||||
|
|
||||||
|
fileSystems."/" =
|
||||||
|
{ device = "/dev/mmcblk1p1";
|
||||||
|
fsType = "xfs";
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/boot" =
|
||||||
|
{ device = "/dev/mmcblk1p3";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
|
||||||
|
swapDevices =
|
||||||
|
[ { device = "/dev/mmcblk1p2"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
|
||||||
|
# (the default) this is the recommended approach. When using systemd-networkd it's
|
||||||
|
# still possible to use this option, but it's recommended to use it in conjunction
|
||||||
|
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
|
||||||
|
networking.interfaces.wlp0s20u3.useDHCP = lib.mkDefault false;
|
||||||
|
|
||||||
|
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||||
|
# high-resolution display
|
||||||
|
hardware.video.hidpi.enable = lib.mkDefault true;
|
||||||
|
|
||||||
|
# Use the systemd-boot EFI boot loader.
|
||||||
|
boot.loader.systemd-boot.enable = true;
|
||||||
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
|
||||||
|
#networking.meth.meth0.replaceInterface = "enp1s0";
|
||||||
|
#
|
||||||
|
cascade.bridge-interface = "enp1s0";
|
||||||
|
};
|
||||||
|
}
|
14
profiles/base/default.nix
Normal file
14
profiles/base/default.nix
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{pkgs,...}:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
(toString ../../common)
|
||||||
|
];
|
||||||
|
config = {
|
||||||
|
environment.systemPackages = with pkgs; [ bridge-utils ];
|
||||||
|
programs.neovim.enable = true;
|
||||||
|
programs.neovim.vimAlias = true;
|
||||||
|
programs.neovim.viAlias = true;
|
||||||
|
|
||||||
|
system.stateVersion = "22.11";
|
||||||
|
};
|
||||||
|
}
|
51
profiles/qemu-vm/default.nix
Normal file
51
profiles/qemu-vm/default.nix
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
{lib, ...}:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
{
|
||||||
|
imports = [ (toString ../base) ];
|
||||||
|
|
||||||
|
config = {
|
||||||
|
deployment.targetUser = "root";
|
||||||
|
fileSystems."/" = {
|
||||||
|
device = "/dev/disk/by-label/nixos";
|
||||||
|
fsType = "ext4";
|
||||||
|
autoResize = true;
|
||||||
|
};
|
||||||
|
fileSystems."/boot" = {
|
||||||
|
device = "/dev/disk/by-label/ESP";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
swapDevices = [
|
||||||
|
{device = "/swap"; size = 1024;} # make sure we always have enough memory to rebuild nixos.
|
||||||
|
];
|
||||||
|
|
||||||
|
# boot.initrd.network.enable = true;
|
||||||
|
# networking.useDHCP = true;
|
||||||
|
|
||||||
|
networking.useNetworkd = mkForce true;
|
||||||
|
networking.networkmanager.enable = false;
|
||||||
|
#networking.interfaces.ens18.useDHCP = false;
|
||||||
|
#networking.bridges.br0.interfaces = [ "ens18" ];
|
||||||
|
#networking.interfaces.br0.useDHCP = lib.mkDefault true;
|
||||||
|
|
||||||
|
# hardware.cpu.amd.updateMicrocode = lib.config.hardware.enableRedistributableFirmware;
|
||||||
|
boot.initrd.availableKernelModules = [ "virtio_net" "virtio_pci" "virtio_mmio" "virtio_blk" "virtio_scsi" "9p" "9pnet_virtio" ];
|
||||||
|
boot.initrd.kernelModules = [ "virtio_balloon" "virtio_console" "virtio_rng" ];
|
||||||
|
|
||||||
|
boot.growPartition = true;
|
||||||
|
boot.kernelParams = [ "console=ttyS0" ];
|
||||||
|
boot.loader.grub.device = "/dev/vda";
|
||||||
|
boot.loader.timeout = mkDefault 3;
|
||||||
|
boot.consoleLogLevel = 3;
|
||||||
|
boot.initrd.verbose = true;
|
||||||
|
|
||||||
|
services.getty.autologinUser = "root";
|
||||||
|
|
||||||
|
services.sshd.enable = true;
|
||||||
|
networking.firewall.allowedTCPPorts = [ 22 ];
|
||||||
|
|
||||||
|
services.qemuGuest.enable = true;
|
||||||
|
|
||||||
|
cascade.bridge-interface = "ens18";
|
||||||
|
};
|
||||||
|
}
|
227
shell.nix
Executable file
227
shell.nix
Executable file
|
@ -0,0 +1,227 @@
|
||||||
|
{ pkgs ? import <nixpkgs> {}, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
vault_addr = "http://vault:8200";
|
||||||
|
in
|
||||||
|
|
||||||
|
with pkgs;
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
name = "commands-nix";
|
||||||
|
|
||||||
|
buildInputs = [ terraform vault coreutils-full dig bash samba4Full morph ];
|
||||||
|
|
||||||
|
shellHook = ''
|
||||||
|
export NIX_PATH="nixpkgs=${toString <nixpkgs>}"
|
||||||
|
export LD_LIBRARY_PATH="${libvirt}/lib:$LD_LIBRARY_PATH"
|
||||||
|
export VAULT_ADDR=${escapeShellArg vault_addr}
|
||||||
|
export DOMAIN="$(hostname -d)"
|
||||||
|
|
||||||
|
|
||||||
|
MEMORY=2048
|
||||||
|
name="$1"
|
||||||
|
|
||||||
|
rebuild-nixos-image() {
|
||||||
|
echo "$(nix-build \
|
||||||
|
-I nixos-config=custom-image-configuration.nix \
|
||||||
|
-I hardware-config=profiles/qemu-vm/default.nix \
|
||||||
|
custom-image.nix)/nixos".img
|
||||||
|
}
|
||||||
|
|
||||||
|
mkvirt() {
|
||||||
|
eval "$(env_cascade)" || return 3
|
||||||
|
eval "$(env_name "$1")" || return 4
|
||||||
|
|
||||||
|
if [ -f "./hosts/$name"".nix" ];then
|
||||||
|
1>&2 echo "there is already a file at ./hosts/$name"".nix. move it or remove it."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
cp "./hosts/_basic.nix" "./hosts/""$name"".nix"
|
||||||
|
morph build network.nix --on="$name" &
|
||||||
|
|
||||||
|
[ -f "result/nixos.img" ] || (
|
||||||
|
1>&2 echo "you do not seem to have a result/nixos.img file. building one now."
|
||||||
|
rebuild-nixos-image || errcho "could not build result/nixos.img." || return $?
|
||||||
|
)
|
||||||
|
[ -f "result/nixos.img" ] || errcho "there must be a file in result/nixos.img. make one with rebuild-nixos-image." || return $?
|
||||||
|
IMG="$(realpath result/nixos.img)"
|
||||||
|
[ -f "$IMG" ] || errcho "result/nixos.img must be resolveable to a file. rebuild the image link with rebuild-nixos-image." || return $?
|
||||||
|
|
||||||
|
[ $? -eq 0 ] || return 5
|
||||||
|
VMID=$(sudo pvesh get /cluster/nextid)
|
||||||
|
[ $? -eq 0 ] || return 6
|
||||||
|
sudo qm create $VMID \
|
||||||
|
--memory "$MEMORY" \
|
||||||
|
--net0 virtio,bridge=vmbr0 \
|
||||||
|
--ipconfig0 ip=dhcp \
|
||||||
|
--agent enabled=1,type=virtio \
|
||||||
|
--virtio0 hdd-fs:0,import-from="$IMG",discard=on,format=raw \
|
||||||
|
--boot c \
|
||||||
|
--bootdisk virtio0 \
|
||||||
|
--vga serial0 \
|
||||||
|
--serial0 socket \
|
||||||
|
--name "$name" \
|
||||||
|
--start 1
|
||||||
|
[ $? -eq 0 ] || return 7
|
||||||
|
|
||||||
|
IP="$(wait-for-vm-ipv4 $VMID)"
|
||||||
|
[ $? -eq 0 ] || return 8
|
||||||
|
samba-create-ipv4-records "$IP" "$name" "$DOMAIN"
|
||||||
|
[ $? -eq 0 ] || return 9
|
||||||
|
1>&2 echo "removing any stale ssh keys"
|
||||||
|
ssh-keygen -f "/home/james/.ssh/known_hosts" -R "$name"
|
||||||
|
ssh-keygen -f "/home/james/.ssh/known_hosts" -R "$name.$DOMAIN"
|
||||||
|
ssh-keygen -f "/home/james/.ssh/known_hosts" -R "$IP"
|
||||||
|
1>&2 echo "scanning for new ssh keys"
|
||||||
|
# head -1 allows us to grab the ed25519 key before the rsa key.
|
||||||
|
# at worst, it will yield a single key of some sort which is also fine.
|
||||||
|
(
|
||||||
|
echo
|
||||||
|
ssh-keyscan "$IP" | sort | head -1
|
||||||
|
echo
|
||||||
|
ssh-keyscan "$name" | sort | head -1
|
||||||
|
echo
|
||||||
|
ssh-keyscan "$name.$DOMAIN" | sort | head -1
|
||||||
|
echo
|
||||||
|
) 2> /dev/null >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
1>&2 echo "waiting for morph build to finish"
|
||||||
|
wait
|
||||||
|
1>&2 echo "morphing host"
|
||||||
|
morph deploy network.nix switch --on="$name"
|
||||||
|
}
|
||||||
|
|
||||||
|
samba-create-ipv4-records() {
|
||||||
|
eval "$(env_cascade)"
|
||||||
|
IP="$1"
|
||||||
|
HOST="$2"
|
||||||
|
:;:;:;:;:;:;:;:;: ;_IP_R="$IP"
|
||||||
|
IP1="''${_IP_R%%.*}";_IP_R="''${_IP_R#*.}"
|
||||||
|
IP2="''${_IP_R%%.*}";_IP_R="''${_IP_R#*.}"
|
||||||
|
IP3="''${_IP_R%%.*}";_IP_R="''${_IP_R#*.}"
|
||||||
|
IP4="''${_IP_R}" ;_IP_R="''${_IP_R#*.}"
|
||||||
|
# at the end, the last fragment has no . so if we try to remove another dotted-quad/4,
|
||||||
|
# we simply get no changes. the _desired end state_ is to have _IP_R = IP4.
|
||||||
|
[ x"$IP4" = x"$_IP_R" ] || errcho "error parsing IPv4"
|
||||||
|
|
||||||
|
samba-tool dns cleanup -k yes "$DC" "$HOST"."$DOMAIN"
|
||||||
|
samba-tool dns add -k yes "$DC" "$DOMAIN" "$HOST" A "$IP"
|
||||||
|
samba-tool dns zonecreate "$DC" "$IP3.$IP2.$IP1.in-addr.arpa." -k yes || true
|
||||||
|
samba-tool dns add -k yes "$DC" "$IP3.$IP2.$IP1.in-addr.arpa." "$IP4.$IP3.$IP2.$IP1.in-addr.arpa." PTR "$HOST.$DOMAIN."
|
||||||
|
}
|
||||||
|
|
||||||
|
wait-for-vm-ipv4() {
|
||||||
|
set -x
|
||||||
|
VMID="$1"
|
||||||
|
while true;do
|
||||||
|
IP="$( sudo qm guest cmd $VMID network-get-interfaces | \
|
||||||
|
jq -r '
|
||||||
|
.[]
|
||||||
|
|select(.["hardware-address"] != "00:00:00:00:00:00")
|
||||||
|
|.["ip-addresses"] | select(.) | .[]
|
||||||
|
|select(.["ip-address-type"] == "ipv4")
|
||||||
|
|.["ip-address"]' \
|
||||||
|
2> /dev/null \
|
||||||
|
| grep -E '172|10|192' || true)"
|
||||||
|
if [ x != x"$IP" ];then
|
||||||
|
echo "$IP"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
set +x
|
||||||
|
}
|
||||||
|
|
||||||
|
env_cascade() {
|
||||||
|
DOMAIN="$(hostname -d)"
|
||||||
|
#calculate some other variables
|
||||||
|
REALM="$(echo "$DOMAIN" | tr a-z A-Z)"
|
||||||
|
WORKGROUP="$(echo "$DOMAIN" | cut -d . -f 1)"
|
||||||
|
|
||||||
|
#and recalculate others to fix caps
|
||||||
|
DOMAIN="$(echo "$REALM" | tr A-Z a-z)"
|
||||||
|
DC="$(dig +short -x "$(dig +short "$DOMAIN")")"
|
||||||
|
DC="''${DC%.}" # just in case, let's drop the absolution dot
|
||||||
|
workgroup="$(echo "$WORKGROUP" | tr A-Z a-z)"
|
||||||
|
WORKGROUP="$(echo "$workgroup" | tr a-z A-Z)"
|
||||||
|
printf '%q=%q\n' \
|
||||||
|
DOMAIN "$DOMAIN" \
|
||||||
|
REALM "$REALM" \
|
||||||
|
WORKGROUP "$WORKGROUP" \
|
||||||
|
DC "$DC" \
|
||||||
|
workgroup "$workgroup"
|
||||||
|
}
|
||||||
|
|
||||||
|
env_name() {
|
||||||
|
# protect thy stdout
|
||||||
|
(
|
||||||
|
exec 18>&1-
|
||||||
|
exec 1>&2
|
||||||
|
NAME="$1"
|
||||||
|
[ x"$NAME" != x ] || errcho "you need to provide a hostname"
|
||||||
|
|
||||||
|
exec 1>&18
|
||||||
|
printf '%q=%q\n' name "$(echo "$NAME" | tr A-Z a-z)"
|
||||||
|
printf '%q=%q\n' NAME "$(echo "$NAME" | tr a-z A-Z)"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
errcho() {
|
||||||
|
RC=$?
|
||||||
|
if [ $RC -ne 0 ];then
|
||||||
|
1>&2 printf '%s\n' "$@"
|
||||||
|
return $RC
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
guestbash() {
|
||||||
|
VMID="$1"
|
||||||
|
CMD="$2"
|
||||||
|
shift;shift
|
||||||
|
echo -n "$CMD" | sudo qm guest exec --pass-stdin=1 --timeout=300 "$VMID" -- /run/wrappers/bin/sudo -i bash -s "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
deploy() {
|
||||||
|
nix-build network.nix && morph build network.nix && morph deploy network.nix "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy-host() {
|
||||||
|
while [ $# -gt 0 ];do
|
||||||
|
|
||||||
|
|
||||||
|
VMID="$(sudo qm list | awk -v N="$1" '$2 == N {print $1}')"
|
||||||
|
|
||||||
|
echo "destroying hosts/$1.nix and VM #$VMID" 1>&2
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
sudo qm stop $VMID
|
||||||
|
sudo qm destroy $VMID
|
||||||
|
rm -f hosts/"$1".nix
|
||||||
|
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
cat << EOF
|
||||||
|
Welcome! You've entered the cascade shell.
|
||||||
|
|
||||||
|
You may make a virt on the local proxmox host using:
|
||||||
|
|
||||||
|
mkvirt hostname-here
|
||||||
|
|
||||||
|
You may also register an existing host in DNS using:
|
||||||
|
|
||||||
|
samba-create-ipv4-records IP hostname-here
|
||||||
|
|
||||||
|
Then morph may be used to deploy:
|
||||||
|
|
||||||
|
# Create a hosts/hostname-here.nix file based on hosts/basic.nix.sample
|
||||||
|
|
||||||
|
deploy test # this is an alias which runs morph on network.nix.
|
||||||
|
deploy switch # the argument is the same as to morph deploy and nixos-rebuild
|
||||||
|
EOF
|
||||||
|
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user