disko2: Add rudimenatary "generate" mode

This commit is contained in:
Felix Uhl 2024-10-27 20:44:53 +01:00
parent 6f579bd98a
commit 21539593db
5 changed files with 165 additions and 3 deletions

18
disko2
View file

@ -1,8 +1,8 @@
#!/usr/bin/env nu
use lib [eval-disko-file eval-flake exit-on-error print-info print-help]
use lib [eval-disko-file eval-flake exit-on-error print-info print-help generate-config]
def modes [] { ["destroy", "format", "mount", "format,mount", "destroy,format,mount"] }
def modes [] { ["destroy", "format", "mount", "format,mount", "destroy,format,mount", "generate"] }
def with-context [context: string] {
$in | insert context $context
@ -24,6 +24,18 @@ export def run [
}
}
match $args.mode {
"generate" => (mode-generate $args)
_ => (mode-format $args)
}
}
export def mode-generate [args: record] {
generate-config | with-context "generate config"
}
export def mode-format [args: record] {
if not ($args.flake? != null xor $args.disko_file? != null) {
return {
success: false,
@ -49,7 +61,7 @@ export def run [
}
export def main [
mode: string@modes, # Mode to use. Allowed values are 'destroy', 'format', 'mount', 'format,mount', 'destroy,format,mount'
mode: string@modes, # Mode to use. Allowed values are 'destroy', 'format', 'mount', 'format,mount', 'destroy,format,mount', 'generate'
disko_file?: path, # File to read the disko configuration from. Can be a .nix file or a .json file
--flake (-f): string # Flake URI to search for the disko configuration
]: nothing -> nothing {

View file

@ -1,2 +1,3 @@
export use eval-config.nu [eval-disko-file eval-flake]
export use errors.nu [exit-on-error print-info print-help]
export use types [generate-config]

10
lib/types/filesystem.nu Normal file
View file

@ -0,0 +1,10 @@
export def generate-config [partition: record] {
assert ($partition.type == 'part') $'BUG! filesystem generate-config called with non-partition: ($partition)'
{
type: 'filesystem',
format: $partition.fstype,
mountpoint: $partition.mountpoint,
}
}

65
lib/types/gpt.nu Normal file
View file

@ -0,0 +1,65 @@
use std assert
use std log
use filesystem.nu
def add-type-if-required [partition: record]: record -> record {
let config = $in
let type = match ($partition.parttype) {
'c12a7328-f81f-11d2-ba4b-00a0c93ec93b' => 'EF00' # EFI System
'21686148-6449-6e6f-744e-656564454649' => 'EF02' # BIOS boot
_ => null
}
if $type == null {
$config
} else {
$config | insert type $type
}
}
def generate-identifier [partition: record]: record -> string {
if not (partition.uuid | is-empty) {
$'UUID:($partition.uuid)...'
} else {
$'PARTUUID:($partition.partuuid)'
}
}
def generate-content [partition: record]: record -> record {
match ($partition.fstype) {
# Add filesystems that are more complicated than mkfs
_ => (filesystem generate-config $partition)
}
}
export def generate-config [device: record]: nothing -> record {
assert ($device.pttype == 'gpt') $'BUG! gpt generate-config called with non-gpt device: ($device)'
log debug $'Generating config for GPT device ($device.path)'
let partitions = $device.children
| each { |part|
{
($'UUID:($part.uuid)'): (
{
size: $part.size,
content: (generate-content $part)
}
| add-type-if-required $part
)
}
}
| into record
{
type: 'gpt',
partitions: $partitions
}
}
export def print-disks []: record -> nothing {
$in | each { print }
}

74
lib/types/mod.nu Normal file
View file

@ -0,0 +1,74 @@
export use gpt.nu
# To see what other fields are available in the lsblk output and what
# sort of values you can expect from them, run:
# lsblk -O | less -S
const lsblk_output_fields = [
ID-LINK,
FSTYPE,
FSSIZE,
FSUSE%,
KNAME,
LABEL,
MODEL,
PARTFLAGS,
PARTLABEL,
PARTN,
PARTTYPE,
PARTTYPENAME,
PARTUUID, # The UUID used for /dev/disk/by-partuuid
PATH,
PHY-SEC,
PTTYPE,
REV,
SERIAL,
SIZE,
START,
MOUNTPOINT, # Canonical mountpoint
MOUNTPOINTS, # All mountpoints, including e.g. bind mounts
TYPE,
UUID, # The UUID used for /dev/disk/by-uuid, if available
]
export def list-block-devices []: nothing -> table {
^lsblk --output ($lsblk_output_fields | str join ',') --json --tree
| from json
| $in.blockdevices
}
def generate-content [device: record] nothing -> record {
match $device.pttype {
gpt => (gpt generate-config $device)
_ => { errors: [ { code: ERR_UNSUPPORTED_PARTITION_TABLE_TYPE, details: { pttype: $device.pttype } } ] }
}
}
export def generate-config [block_devices?: table]: nothing -> record {
let block_devices = $block_devices | default (list-block-devices)
let disks = $block_devices
| each { |device|
{
($'MODEL:($device.model),SN:($device.serial)'):{
device: $device.kname,
type: $device.type,
content: (generate-content $device)
}
}
}
| into record
return {
success: true,
value: {
disk: $disks
# TODO: Add lvm_vg, mdadm, nodev and zpool
}
}
}
export def print-disks []: record -> nothing {
$in | each { print }
}