Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add configuration management #17

Merged
merged 5 commits into from
Jan 15, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,32 @@ Tests on one orange pi zero show that the time from power on until a login
prompt on the serial console is about 1 minute.


Applying persistent configurations
----------------------------------

Custom configurations are saved as tar.gz archives in conf.d at the root of the
fat16 file system. After the start of userspace and before systemd is launched,
content in each archive is extracted in alphabetical order to /etc of the ramdisk,
so files in an archive towards the end of the list overwrite those from an earlier
archive in case of a filename conflict, and systemd will only see the final
(highest priority) configurations. For example:

/conf.d/00-tomesh-base.tar.gz
10-tomesh-wlan-mesh-top-gs07-rt5572.tar.gz
11-tomesh-wlan-hostap-tplink-tl-wn722n.tar.gz
50-node-config-save.tar.gz
90-user-custom-configs.tar.gz

This allows local mesh communities to customize nodes by distributing archives
of systemd.network configuration files, or any files that are to be read from
/etc. The user simply mounts the fat filesystem like a USB key and drops tar.gz
files into conf.d and backs them up across software updates.

If the node needs to save persistent configurations while running, such as
remembering a MAC address, it can save the current /etc directory into a
50-node-config-save.tar.gz archive by running `config_save`. The user may
also manually add configurations with higher priority archive names.

Test the Debian image using Qemu
--------------------------------

Expand Down
8 changes: 8 additions & 0 deletions boards/common-uboot.mk
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ define uboot_bootdir
MTOOLSRC=$1 mcopy $5 $2boot/dtb
endef

# Create an empty configuration directory in the boot partition
#
# $1 is the mtools config file
# $2 is the mtools drive letter
define uboot_confdir
MTOOLSRC=$1 mmd $2conf.d
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you just add this line to the uboot_bootdir macro above, then you dont have to edit every single board config to make it happen. That macro is already described as the place that all needed boot partition actions are done.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to make conf.d creation as an explicit step because it is not required as part of boot. I know the alternative works, but this was done intentionally to not mix two things, even though they all end up in the same boot partition.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, create a super macro ("uboot_doitall"?) that calls both uboot_bootdir and uboot_confdir - they both take the same params and reducing the amount of lines in each board file makes it easier for others to see and port the important parts.

endef

BUILD_DEPENDS += mtools


Expand Down
1 change: 1 addition & 0 deletions boards/raspberrypi2/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,5 @@ $(DISK_IMAGE): $(BUILD)/mtoolsrc $(BOOT_FILES)
truncate --size=1025K [email protected] # ensure the FAT bootblock is mapped
MTOOLSRC=$(BUILD)/mtoolsrc mformat -v boot -N 1 z:
MTOOLSRC=$(BUILD)/mtoolsrc mcopy $(BOOT_FILES) z:
MTOOLSRC=$(BUILD)/mtoolsrc mmd z:conf.d
mv [email protected] $@
1 change: 1 addition & 0 deletions boards/sun4i-a10-cubieboard/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,5 @@ $(DISK_IMAGE): $(SRC_SPL) $(BUILD)/mtoolsrc $(BOOT_FILES) $(BOOT_DTB_FILES)
$(call allwinner_spl,$(SRC_SPL),[email protected])
truncate --size=1025K [email protected] # ensure the FAT bootblock is mapped
$(call uboot_bootdir,$(BUILD)/mtoolsrc,z:,$$((0x100000/512)),$(BOOT_FILES),$(BOOT_DTB_FILES))
$(call uboot_confdir,$(BUILD)/mtoolsrc,z:)
mv [email protected] $@
1 change: 1 addition & 0 deletions boards/sun7i-a20-bananapi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,5 @@ $(DISK_IMAGE): $(SRC_SPL) $(BUILD)/mtoolsrc $(BOOT_FILES) $(BOOT_DTB_FILES) env
truncate --size=1025K [email protected] # ensure the FAT bootblock is mapped
dd if=env [email protected] conv=notrunc bs=$$((0x088000)) seek=1
$(call uboot_bootdir,$(BUILD)/mtoolsrc,z:,$$((0x100000/512)),$(BOOT_FILES),$(BOOT_DTB_FILES))
$(call uboot_confdir,$(BUILD)/mtoolsrc,z:)
mv [email protected] $@
1 change: 1 addition & 0 deletions boards/sun8i-h2-plus-orangepi-zero/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -107,5 +107,6 @@ $(DISK_IMAGE): $(SRC_SPL) $(BUILD)/mtoolsrc $(BOOT_FILES) $(BOOT_DTB_FILES)
$(call allwinner_spl,$(SRC_SPL),[email protected])
truncate --size=1025K [email protected] # ensure the FAT bootblock is mapped
$(call uboot_bootdir,$(BUILD)/mtoolsrc,z:,$$((0x100000/512)),$(BOOT_FILES),$(BOOT_DTB_FILES))
$(call uboot_confdir,$(BUILD)/mtoolsrc,z:)
mv [email protected] $@

1 change: 1 addition & 0 deletions boards/sun8i-h3-orangepi-lite/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ $(DISK_IMAGE): $(SRC_SPL) $(BUILD)/mtoolsrc $(BOOT_FILES) $(BOOT_DTB_FILES) $(BO
$(call allwinner_spl,$(SRC_SPL),[email protected])
truncate --size=1025K [email protected] # ensure the FAT bootblock is mapped
$(call uboot_bootdir,$(BUILD)/mtoolsrc,z:,$$((0x100000/512)),$(BOOT_FILES),$(BOOT_DTB_FILES))
$(call uboot_confdir,$(BUILD)/mtoolsrc,z:)
MTOOLSRC=$(BUILD)/mtoolsrc mmd z:boot/dtb/overlay
MTOOLSRC=$(BUILD)/mtoolsrc mcopy $(BOOT_DTBO_FILES) z:boot/dtb/overlay
mv [email protected] $@
1 change: 1 addition & 0 deletions boards/sun8i-v3s-licheepi-zero/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ $(DISK_IMAGE): $(SRC_SPL) $(BUILD)/mtoolsrc $(BOOT_FILES) $(BOOT_DTB_FILES) $(BU
$(call allwinner_spl,$(SRC_SPL),[email protected])
truncate --size=1025K [email protected] # ensure the FAT bootblock is mapped
$(call uboot_bootdir,$(BUILD)/mtoolsrc,z:,$(PART1_BEGIN_SEC),$(BOOT_FILES),$(BOOT_DTB_FILES))
$(call uboot_confdir,$(BUILD)/mtoolsrc,z:)
MTOOLSRC=$(BUILD)/mtoolsrc mpartition -c -T0x82 -b $(PART2_BEGIN_SEC) y:
MTOOLSRC=$(BUILD)/mtoolsrc mpartition -c -T0x83 -b $(PART3_BEGIN_SEC) x:
truncate --size=$$(( $(PART3_BEGIN_SEC)*512 )) [email protected]
Expand Down
2 changes: 1 addition & 1 deletion debian/packages.d/README
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ customisations. These customisations are applied in several phases,
and each package that is found installed in the rescue system will
attempt to run its matching script during each phase.

Curently the phases are:
Currently the phases are:

"minimise"
During this phase, anything that can be removed to minimise the
Expand Down
38 changes: 38 additions & 0 deletions debian/packages.d/systemd.customise.add/init.d/20confd.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Apply configurations from conf.d
#
# Copyright (C) 2018 Benedict Lau <[email protected]>

CONFDIR=conf.d

try_partition() {
# Create file system node from partition
mknod /dev/$1 b $2 $3 2>/dev/null

# Mount partition as read-only
mount /dev/$1 /mnt -o ro

# Find conf.d in root of partition and extract in alphabetical order each
# tar.gz archive into the ramdisk /etc, overwriting any existing file
if [ -d "/mnt/$CONFDIR" ]; then
for conf in /mnt/$CONFDIR/*.tar.gz; do
echo Applying configurations from /dev/$1: $conf
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just use "for conf in /mnt/$CONFDIR/*.tar.gz" ?

Using find will traverse subdirs and is not known to be sorted

tar --extract -f $conf -C /etc
done
fi

# Unmount partition
umount /mnt
}

# Mount proc
mount -t proc proc /proc

cat /proc/partitions | while read major minor size name; do
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reads conf.d from all partitions. I guess it's okay for now? It'll be a little weird if multiple partitions have configurations because tar archive order rule doesn't apply here cross partitions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could exit on first found - which has issues if the files are hard to overwrite. we could also collate all the tar files from all the partitions - but that has an unwanted increase in complexity.

by checking all partitions, we try to avoid painting ourselves into an unexpected corner

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither first found or collect sort seem better than current. They are just different but just as non-ideal. I suggest keeping it as is and discourage people from having two partitions with conf.d at root, and state current behaviour.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggested the collect-and-sort method as that is how a lot of things (like systemd) handle multiple sources of config overrides - its an annoying amount of additional work, but could be done if this ever becomes an issue

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On WINDOWS machines, only the FIRST partition is ever recognized OS on usb devices.

Unless you have some reason to put config on partition >2 you could just stick with partition 1 to make it most compatible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue still exists when there are multiple physical disks connected to the board

# Check each partition matching sd*[0-9] (e.g. sda1) or mmcblk*p* (e.g. mmcblk0p1)
case $name in
sd*[0-9]|mmcblk*p*)
echo Checking for configuration files on $name
try_partition $name $major $minor
;;
esac
done
43 changes: 43 additions & 0 deletions debian/packages.d/systemd.customise.add/usr/local/sbin/config_save
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Save current configurations to partition containing conf.d
#
# Copyright (C) 2018 Benedict Lau <[email protected]>

CONFDIR=conf.d

try_partition() {
retval=1

# Mount partition as read-write
mount /dev/$1 /mnt

# Find conf.d in root of partition and save current configurations in /etc
if [ -d "/mnt/$CONFDIR" ]; then
echo Saving configurations to /dev/$1: "/mnt/$CONFDIR/50-node-config-save.tar.gz"
tar --create --gzip -f "/mnt/$CONFDIR/50-node-config-save.tar.gz" -C /etc .

# Set function return value to successful
echo Configurations saved to /dev/$1: "/mnt/$CONFDIR/50-node-config-save.tar.gz"
retval=0
fi

# Unmount partition
umount /mnt

return $retval
}

cat /proc/partitions | while read major minor size name; do
# Check each partition matching sd*[0-9] (e.g. sda1) or mmcblk*p* (e.g. mmcblk0p1)
case $name in
sd*[0-9]|mmcblk*p*)
echo Checking for configuration directory on $name
try_partition $name $major $minor
S=$?

# Save only to the first partition found with conf.d
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hamishcoleman Break like this after first successful save?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems reasonable

if [ $S -eq 0 ]; then
break
fi
;;
esac
done