# unattended install with non-standard ZFS pools



## keleathi (Aug 2, 2019)

I need to create an unattended installation iso for a specific appliance-like image I'm creating.  It needs to have 2 zfs pools; the root pool will be as the standard `bsdinstall zfsboot` script would create it, except that it should be no more than 3GB.  The second pool will take the rest of the disk, and sit on top of a GELI encrypted partition.

I can't figure out how to do this in a `bsdinstall` script without modifying `bsdinstall` itself.

If I set ZFSBOOT_DISKS I can only get the standard setup, with a single freebsd-zfs partition that takes up all of the disk (beyond the boot and swap).  

If I don't set ZFSBOOT_DISKS or PARTITIONS, but have the script just build the partitions I want as in:


```
#!/bin/sh

disk=`ls /dev/|grep -E "ada0$|vtbd0$" |head -n1`

#create partition scheme
gpart destroy -F $disk
gpart create -s gpt $disk

gpart add -s 512K -a 1M -t freebsd-boot $disk
gpart add -s 2G -a 1M -t freebsd-swap -l swap $disk
gpart add -s 3G -a 1M -t freebsd-zfs -l base $disk
gpart add -a 1M -t freebsd-zfs -l appdata $disk

gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 $disk

#create geli key, initialize, and attach
mkdir -p /tmp/bsdinstall_boot/geli
dd if=/dev/random of=/tmp/bsdinstall_boot/geli/base.key bs=64 count=1
geli init -e AES-XTS -l 256 -s 4096 -P -K /tmp/bsdinstall_boot/geli/base.key /dev/gpt/appdata
geli attach -p -k /tmp/bsdinstall_boot/geli/base.key /dev/gpt/appdata

#create zpools
zpool create -o altroot=$BSDINSTALL_CHROOT -O canmount=off -m none -f zbase gpt/base
zpool create -o altroot=$BSDINSTALL_CHROOT -O canmount=off -m none -f zappdata gpt/appdata.eli

#create zfs datasets
zfs create -o mountpoint=none                                  zbase/ROOT
zfs create -o mountpoint=/ -o canmount=noauto                  zbase/ROOT/default

mount -t zfs zbase/ROOT/default $BSDINSTALL_CHROOT

zfs create -o mountpoint=/tmp  -o exec=on      -o setuid=off   zbase/tmp
zfs create -o canmount=off -o mountpoint=/usr                  zbase/usr
zfs create                                                     zbase/usr/home
zfs create -o canmount=off -o mountpoint=/var                  zbase/var
zfs create                     -o exec=off     -o setuid=off   zbase/var/audit
zfs create                     -o exec=off     -o setuid=off   zbase/var/crash
zfs create                     -o exec=off     -o setuid=off   zbase/var/log
zfs create -o atime=on         -o exec=off     -o setuid=off   zbase/var/mail
zfs create                     -o exec=on      -o setuid=off   zbase/var/tmp
zfs create -o mountpoint=/usr/local/jails                      zappdata/jails
zfs create -o mountpoint=/usr/local/jail_data                  zappdata/jail_data

zpool set bootfs=zbase/ROOT/default zbase
```

This works, it'll create all the partitions, zpools, and datasets I need, but the script sees that ZFSBOOT_DISKS isn't set, so tries to call `bsdinstall scriptedpart $PARTITIONS` which fails because PARTITIONS isn't set.

Since the `bsdinstall scriptedpart $PARTITIONS` is called after my script, if I set PARTITIONS to the actual drive, it'll blow away the partitions and zfs setup that I created manually.

I can obviously comment out the offending lines in the /usr/libexec/bsdinstall/script script, but then of course I have to maintain a fork or patch for bsdinstall, which is much less than ideal.

Am I missing something?  Is there a way to manually create the partition structure in the unattended installation script?  The one thing I can think of is there might be a PARTITIONS I can pass to `bsdinstall scriptedpart` that wouldn't do anything, but I'm not even close to a C programmer, so the code to scriptedpart might as well be an alien language.


----------



## T-Daemon (Aug 2, 2019)

keleathi said:


> If I set ZFSBOOT_DISKS I can only get the standard setup, with a single freebsd-zfs partition *that takes up all of the disk* ...


You have missed ZFSBOOT_POOL_SIZE. Please read bsdinstall(8) carefully.

I was thinking, instead of creating zbase "manually", together with zappdata mixed, let `bsdinstall` creat it first, i.e.:

```
export ZFSBOOT_DISKS=
export ZFSBOOT_POOL_SIZE=3g
export ZFSBOOT_BOOT_POOL_NAME=zbase
export ZFSBOOT_DATASETS=
export nonInteractive="YES"
```
and subsequently let the script create zappdata.


----------



## keleathi (Aug 2, 2019)

Thank you, I did miss ZFSBOOT_POOL_SIZE!  I'll try that when I get back to the lab machine.

That said, from reading the `bsdinstall script` code, the "preamble" shell script looks like it runs before the `bsdinstall zfsboot` command is called, which would mean it actually wouldn't work like that since `bsdinstall zfsboot` would blow away whatever partition table I created in the script, which of course means zappdata would disappear.  

But.. as I said, I'll try it anyway in hopes that I'm missing something about the ordering in `bsdinstall zfsboot`.


----------



## keleathi (Aug 2, 2019)

Actually, now that I take a look I didn't miss ZFSBOOT_POOL_SIZE, because it doesn't exist.   (Just to make sure, I went to https://github.com/freebsd/freebsd/...e0c566fd0/usr.sbin/bsdinstall/scripts/zfsboot and searched; it's not present there or in the man page).  There IS a ZFSBOOT_BOOT_POOL_SIZE, but that's only used for a separate boot pool, with zroot (or whatever the root pool is called) taking up the rest of the disk.  

So unfortunately, this definitely will not work.


----------



## T-Daemon (Aug 3, 2019)

Dude, nicley done, giving others advice to read man pages carefully, but not following them myself. To my defence, reading, posting from mobile phone, small screen, small font size.

I misread ZFSBOOT_BOOT_POOL_SIZE for ZFSBOOT_POOL_SIZE, and didn't pay attention to the explanation. Sorry waisting your time with that.

How about letting `bsdinstall scriptedpart` create the partition scheme, excluding it from your script commands ? i.e.:

.../etc/installerconfig

```
export PARTITIONS="ada0 GPT { 3G freebsd-zfs, 2G freebsd-swap, auto freebsd-zfs }"

# label the partitions base and appdata.
# Your commands:
# create geli key, initialize, and attach.
# create zpools.
# create zfs datasets.
```
Note: PREAMBLE is interpreted as a sh shell script, no need to set #!/bin/sh.


----------

