Fri, 12/07/2012 - 03:59 -- scrappy
Configure HAST feature to FreeNAS FreeBSD

FreeNAS is awesome, but until recently it lacked HAST (Highly Available STorage). Fortunately now TrueNAS allows for this function to work. HAST is integrated into the FreeBSD base system, in turn HAST can be added into FreeNAS manually.

After FreeNAS booting, first setup the LAN, DNS (freenas1->192.168.137.31, freenas2->192.168.137.32), etc. then login into shell.

# change the / directory read-write
mount -uw /
 
# create raid3 of da1, da2, da3, suppose we have 3 disks here to provide storage
graid3 label gr0raid3 da1 da2 da3
 
# CARP support & enable hastd daemon, if there is no if_carp.ko in /boot/kernel, 
# copy it from FreeBSD 8.2 release
cat <<EOF >> /conf/base/etc/rc.conf
ifconfig carp0 create
ifconfig carp0 vhid 1 pass freenashast 192.168.137.30/24
# enable HAST daemon
hastd_enable="YES"
EOF
 
# create hast.conf
cat <<EOF > /conf/base/etc/hast.conf
resource freenashast {
        on freenas1 {
                local /dev/raid3/gr0raid3
                remote freenas2
        }
        on freenas2 {
                local /dev/raid3/gr0raid3
                remote freenas1
        }
}
EOF
 
# copy of hast.conf in /etc or reboot your box
cp /conf/base/etc/hast.conf /etc
 
# create the hast storage
hastctl create freenashast
 
# change its role to primary, then /dev/hast/freenashast device appears
hastctl role primary freenashast
 
# create zpool in freenashast
zpool create -m /mnt gr0 /dev/hast/freenashast
 
# create a link in raid3 directory so that GUI can recognize it.
ln -s /dev/hast/freenashast /dev/raid3/gr1raid3
 
# now, you can "automatically import" the gr0 volume in GUI
# setup file share serivce on this volume in GUI
 
# add devd daemon options to switch hast when necessory  
cat <<EOF >> /conf/base/etc/devd.conf
notify 30 {
        match "system" "IFNET";
        match "subsystem" "carp0";
        match "type" "LINK_UP";
        action "/usr/local/sbin/carp-hast-switch master";
};
 
notify 30 {
        match "system" "IFNET";
        match "subsystem" "carp0";
        match "type" "LINK_DOWN";
        action "/usr/local/sbin/carp-hast-switch slave";
};
EOF
 
# hast-carp-switch do the switching job
cat <<EOF > /usr/local/sbin/carp-hast-switch
#!/bin/sh
resources="freenashast"
zfspool="gr0"
delay=3
log="local0.debug"
name="carp-hast"
 
case "$1" in
        master)
                logger -p $log -t $name "Switching to primary provider for $resources."
                # in order to wait for the original primary provider to change role state
                # otherwise, brain-split may happen
                sleep $delay
                for disk in $resources; do
                        # ensure that this storage can be switched                        
                        while $(pgrep -lf "hastd: $disk \(secondary\)" > /dev/null 2>&1 ); do
                                sleep 1
                        done
 
                        # Switch role for each disk
                        hastctl role primary $disk
                        if [ $? -ne 0 ]; then
                                logger -p $log -t $name "Unable to change role to primary for resouc                                                                                          e ${disk}."
                                exit 1
                        fi
                done
 
                # Wait for the /dev/hast/* devices to appear
                for disk in $resources; do
                        for I in $(jot 60); do
                                [ -c "/dev/hast/${disk}" ] && break
                                sleep 0.5
                        done
                        if [ ! -c "/dev/hast/${disk}" ] ; then
                                logger -p $log -t $name "GEOM provider /dev/hast/$disk did not appea                                                                                          r."
                                exit 1
                        fi
                done
 
                logger -p $log -t $name "Role for HAST resources switched to primary."
 
                logger -p $log -t $name "Importing ZFS pool."
                zpool import -f $zfspool
 
                # restart the enabled services
                for srv in $(sqlite3 /data/freenas-v1.db "select srv_service from services_services where srv_enable=1" \
                                | xargs printf "grep 'bool_.*%s' /etc/rc.conf.local\n" | sh | awk '{print $2}')
               do
                         case $srv in
                             winbindd_enable|samba_enable) /etc/local/rc.d/samba restart
                                        ;;
                             netatalk_enable)        /etc/local/rc.d/netatalk restart
                                        ;;
                             proftpd_enable)         /etc/local/rc.d/proftpd restart
                                        ;;
                             inetd_enable)           /etc/rc.d/inetd restart
                                        ;;
                             nfs_server_enable)      /etc/rc.d/nfsserver restart
                                        ;;
                             mountd_enable)          /etc/rc.d/mountd restart
                                        ;;
                             nfsd_enable)            /etc/rc.d/nfsd restart
                                        ;;
                             rsyncd_enable)          /etc/local/rc.d/rsyncd restart
                                        ;;
                         esac
              done
 
                ;;
 
        slave)
                logger -p $log -t $name "Switching to secondary provider for $resources."
                # stop the running services
                for srv in $(sqlite3 /data/freenas-v1.db "select srv_service from services_services where srv_enable=1" \
                                | xargs printf "grep 'bool_.*%s' /etc/rc.conf.local\n" | sh | awk '{print $2}')
               do
                         case $srv in
                             winbindd_enable|samba_enable) /etc/local/rc.d/samba stop
                                        ;;
                             netatalk_enable)        /etc/local/rc.d/netatalk stop
                                        ;;
                             proftpd_enable)         /etc/local/rc.d/proftpd stop
                                        ;;
                             inetd_enable)           /etc/rc.d/inetd stop
                                        ;;
                             nfs_server_enable)      /etc/rc.d/nfsserver stop
                                        ;;
                             mountd_enable)          /etc/rc.d/mountd stop
                                        ;;
                             nfsd_enable)            /etc/rc.d/nfsd stop
                                        ;;
                             rsyncd_enable)          /etc/local/rc.d/rsyncd stop
                                        ;;
                       esac
                done
 
                # export the zfs pool & change role to slave
                for disk in $resources; do
                        zpool export -f $zfspool
                        sleep $delay
                        hastctl role secondary $disk 2>&1
                        if [ $? -ne 0 ]; then
                                logger -p $log -t $name "Unable to switch role to secondary for resource $disk."
                                exit 1
                        fi
                        logger -p $log -t name "Role switched to secondary for resource $disk"
                done
                ;;
        *)
                logger -p $log -t $name "Usage: $0 "
                exit 1
                ;;
esac
 
chmod +x /usr/local/sbin/carp-hast-switch
 
reboot

After rebooting, manually set the FreeNAS’ HAST role according to their state:

hastctl role primary freenashast

The slave FreeNAS’ settings is almost the same as above, but the carp0 should be lower priority

ifconfig carp0 vhid 1 pass freenashast advskew 100 192.168.137.30/24