From a1b33cf24e80a15be49ba5e5c79adcaf124ba03e72a0fb55b9bee34f57951f73 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Thu, 27 Nov 2025 15:42:58 +0300 Subject: [PATCH] Apply functionality --- dsc | 53 +++++++++++++++++++------- schema/net/*/apply | 40 +++++++++++++++++++ schema/net/apply | 37 ++++++++++++++++++ schema/ssh/apply | 43 +++++++++++++++++++++ schema/ssh/authorized_keys/*/check | 8 ++++ schema/ssh/authorized_keys/*/pub/check | 8 ++++ schema/ssh/enabled/check | 11 ++++++ schema/ssh/port/check | 11 ++++++ schema/ssh/prv/bin | 0 schema/ssh/pub/check | 8 ++++ schema/ssh/title | 1 + schema/sys/hostname/apply | 3 ++ 12 files changed, 209 insertions(+), 14 deletions(-) create mode 100755 schema/net/*/apply create mode 100755 schema/net/apply create mode 100755 schema/ssh/apply create mode 100755 schema/ssh/authorized_keys/*/check create mode 100755 schema/ssh/authorized_keys/*/pub/check create mode 100755 schema/ssh/enabled/check create mode 100755 schema/ssh/port/check create mode 100644 schema/ssh/prv/bin create mode 100755 schema/ssh/pub/check create mode 100644 schema/ssh/title create mode 100755 schema/sys/hostname/apply diff --git a/dsc b/dsc index fcc6ec3..9a7edad 100755 --- a/dsc +++ b/dsc @@ -50,12 +50,16 @@ if {[catch {set Schema $env(DSC_SCHEMA)}]} {set Schema schema} if {[catch {set Stash $env(DSC_STASH)}]} {set Stash stash} if {[catch {set Saved $env(DSC_SAVED)}]} {set Saved saved} +proc readents {root typ} { + set ents [glob -directory $root -tails -nocomplain -- *] + set ents [lmap d $ents {if {[file type $root/$d] == $typ} {set d} {continue}}] + return [lsort $ents] +} + proc walk {root typ} { set rv [list] set root [string trimright $root /] - set dirs [glob -directory $root -tails -nocomplain -- *] - set dirs [lmap d $dirs {if {[file type $root/$d] == $typ} {set d} {continue}}] - foreach s [lsort $dirs] { + foreach s [readents $root $typ] { lappend rv $root/$s lappend rv {*}[walk $root/$s $typ] } @@ -71,21 +75,21 @@ proc fileread {fn} { proc find-opt-schema {opt} { global Schema - set path . + set pth . set opt [string trimright $opt /] foreach e [split $opt /] { - if {[file exists $Schema/$path/$e]} { - set path $path/$e + if {[file exists $Schema/$pth/$e]} { + set pth $pth/$e continue } - if {[file exists $Schema/$path/*]} { - set path $path/* + if {[file exists $Schema/$pth/*]} { + set pth $pth/* continue } puts stderr "can not find $opt in schema" exit 1 } - return [string range $path 2 end] + return [string range $pth 2 end] } proc is-bin {opt} { @@ -192,7 +196,7 @@ switch [lindex $argv 0] { has { assure-exists $opt } - get-checker { + find-opt-schema { puts [find-opt-schema $opt] } get { @@ -201,10 +205,7 @@ switch [lindex $argv 0] { if {! [file exists $Stash/$opt]} { exit } - set dirs [glob -directory $Stash/$opt -tails -nocomplain -- *] - set dirs [lmap d $dirs { \ - if {[file type $Stash/$opt/$d] == "directory"} {set d} {continue}}] - foreach dir [lsort $dirs] { + foreach dir [readents $Stash/$opt directory] { puts $dir } exit @@ -223,6 +224,30 @@ switch [lindex $argv 0] { } puts -nonewline [run-checker $opt ""] } + apply { + set pth [find-opt-schema $opt] + if {[file exists $Schema/$pth/apply]} { + puts stderr "applying $opt..." + if {[catch {exec | [list "$Schema/$pth/apply" $opt] >@stdout 2>@stderr}]} { + exit 1 + } + exit + } + if {[file exists $Schema/$pth/*]} { + set rc 0 + foreach dir [readents $Stash/$opt directory] { + if {[catch {exec | [list dsc apply $opt/$dir] >@stdout 2>@stderr}]} { + set rc 1 + } + } + exit $rc + } + foreach ent [readents $Schema/$opt directory] { + if {[catch {exec | [list dsc apply $opt/$ent] >@stdout 2>@stderr}]} { + set rc 1 + } + } + } diff { set dirsSaved [file tempfile dirsSaved.XXXXX] set fh [open $dirsSaved w] diff --git a/schema/net/*/apply b/schema/net/*/apply new file mode 100755 index 0000000..fd539ca --- /dev/null +++ b/schema/net/*/apply @@ -0,0 +1,40 @@ +#!/usr/bin/env jimsh + +proc list-addrs {iface} { + set addrs [list] + catch {exec ip addr list dev $iface} lines + foreach l [split $lines \n] { + if {[regexp {inet (\S+)} $l _ addr]} { + lappend addrs $addr + } + if {[regexp {inet6 (\S+)} $l _ addr] && [string range $addr 0 4] != "fe80:"} { + lappend addrs $addr + } + } + return $addrs +} + +# TODO: check that interface exists + +set iface [file tail [lindex $argv 0]] +set mtu [exec dsc get net/$iface/mtu] +puts "ip link set $iface mtu $mtu" +puts "ip link set $iface up" + +set addrs [list] +foreach addr [split [exec dsc get net/$iface/addr/*] \n] { + set prefixlen [exec dsc get net/$iface/addr/$addr/prefixlen] + lappend addrs $addr/$prefixlen +} +foreach addr [list-addrs $iface] { + set idx [lsearch -exact $addrs $addr] + if {$idx == -1} { + puts "ip addr del $addr dev $iface" + } else { + # Address is already present + set $addrs [lreplace $addrs $idx $idx] + } +} +foreach addr $addrs { + puts "ip addr add $addr dev $iface" +} diff --git a/schema/net/apply b/schema/net/apply new file mode 100755 index 0000000..bb5eeec --- /dev/null +++ b/schema/net/apply @@ -0,0 +1,37 @@ +#!/usr/bin/env jimsh + +proc list-addrs {iface} { + set addrs [list] + catch {exec ip addr list dev $iface} lines + foreach l [split $lines \n] { + if {[regexp {inet (\S+)} $l _ addr]} { + lappend addrs $addr + } + if {[regexp {inet6 (\S+)} $l _ addr] && [string range $addr 0 4] != "fe80:"} { + lappend addrs $addr + } + } + return $addrs +} + +set sysIfaces [list] +foreach l [split [exec ip link] \n] { + if {[regexp {^\d+: (\w+): } $l _ iface] && $iface != "lo"} { + lappend sysIfaces $iface + } +} + +set dscIfaces [split [exec dsc get net/*] \n] + +foreach iface $sysIfaces { + if {[lsearch -exact $dscIfaces $iface] == -1} { + # If interface is not mentioned in dsc, then disable it and remove + # all addresses, as they are still known to the system + puts "ip link set $iface down" + foreach addr [list-addrs $iface] { + puts "ip addr del $addr dev $iface" + } + } else { + exec | [list dsc apply net/$iface] >@stdout 2>@stderr + } +} diff --git a/schema/ssh/apply b/schema/ssh/apply new file mode 100755 index 0000000..cadb323 --- /dev/null +++ b/schema/ssh/apply @@ -0,0 +1,43 @@ +#!/bin/sh -e + +tmp=$(mktemp -d) +trap "rm -fr $tmp" HUP PIPE INT QUIT TERM EXIT + +port=$(dsc get ssh/port) +dsc get ssh/pub >$tmp/id_ed25519.pub + +umaskPrev=$(umask) +umask 077 +dsc get ssh/prv >$tmp/id_ed25519 +umask $umaskPrev + +cat >$tmp/run </dev/null || continue + dsc get ssh/authorized_keys/$name/pub >>$tmp/.authorized_keys +done + +enabled=$(dsc get ssh/enabled) +if [ "$enabled" != yes ] ; then + touch $tmp/down +fi + +if [ -d /tmp/dropbear.srv ] ; then + mv /tmp/dropbear.srv $tmp/prev + mv $tmp /tmp/dropbear.srv + rm -r /tmp/dropbear.srv/prev +else + mv $tmp /tmp/dropbear.srv +fi + +if [ "$enabled" = yes ] ; then + echo sv restart /tmp/dropbear.srv +else + echo sv stop /tmp/dropbear.srv +fi diff --git a/schema/ssh/authorized_keys/*/check b/schema/ssh/authorized_keys/*/check new file mode 100755 index 0000000..46e4eea --- /dev/null +++ b/schema/ssh/authorized_keys/*/check @@ -0,0 +1,8 @@ +#!/usr/bin/env jimsh + +set n [read -nonewline stdin] +if {[llength $n] == 0} { + puts {empty name} + exit 1 +} +puts $n diff --git a/schema/ssh/authorized_keys/*/pub/check b/schema/ssh/authorized_keys/*/pub/check new file mode 100755 index 0000000..158ef73 --- /dev/null +++ b/schema/ssh/authorized_keys/*/pub/check @@ -0,0 +1,8 @@ +#!/usr/bin/env jimsh + +set n [read -nonewline stdin] +if {! [regexp {^ssh-ed25519 [.A-Za-z0-9/+]{68,68}} $n]} { + puts {bad ssh-ed25519 key} + exit 1 +} +puts $n diff --git a/schema/ssh/enabled/check b/schema/ssh/enabled/check new file mode 100755 index 0000000..f9a1b3b --- /dev/null +++ b/schema/ssh/enabled/check @@ -0,0 +1,11 @@ +#!/usr/bin/env jimsh + +set n [read -nonewline stdin] +if {$n == ""} { + set n no +} +if {! [string is boolean $n]} { + puts {is not boolean} + exit 1 +} +puts $n diff --git a/schema/ssh/port/check b/schema/ssh/port/check new file mode 100755 index 0000000..8a697a1 --- /dev/null +++ b/schema/ssh/port/check @@ -0,0 +1,11 @@ +#!/usr/bin/env tclsh8.6 + +set n [read -nonewline stdin] +if {$n == ""} { + set n 22 +} +if {! [string is integer -strict $n]} { + puts "invalid integer" + exit 1 +} +puts $n diff --git a/schema/ssh/prv/bin b/schema/ssh/prv/bin new file mode 100644 index 0000000..473a0f4 diff --git a/schema/ssh/pub/check b/schema/ssh/pub/check new file mode 100755 index 0000000..158ef73 --- /dev/null +++ b/schema/ssh/pub/check @@ -0,0 +1,8 @@ +#!/usr/bin/env jimsh + +set n [read -nonewline stdin] +if {! [regexp {^ssh-ed25519 [.A-Za-z0-9/+]{68,68}} $n]} { + puts {bad ssh-ed25519 key} + exit 1 +} +puts $n diff --git a/schema/ssh/title b/schema/ssh/title new file mode 100644 index 0000000..cfb765d --- /dev/null +++ b/schema/ssh/title @@ -0,0 +1 @@ +Dropbear SSH diff --git a/schema/sys/hostname/apply b/schema/sys/hostname/apply new file mode 100755 index 0000000..79db824 --- /dev/null +++ b/schema/sys/hostname/apply @@ -0,0 +1,3 @@ +#!/bin/sh -e + +echo "echo $(dsc get $1) >/etc/hostname" -- 2.52.0