]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
test: iSCSI-related udev tests 20823/head
authorFrantisek Sumsal <frantisek@sumsal.cz>
Wed, 22 Sep 2021 17:26:45 +0000 (19:26 +0200)
committerFrantisek Sumsal <frantisek@sumsal.cz>
Wed, 29 Sep 2021 08:05:21 +0000 (10:05 +0200)
test/TEST-64-UDEV-STORAGE/test.sh
test/units/testsuite-64.sh

index a7138d3704d0250e18f64f43991b17892deb5db3..23cdefa5ce96605d2b431dc244f777e305f1ad55 100755 (executable)
@@ -33,6 +33,12 @@ _host_has_feature() {(
         btrfs)
             modprobe -nv btrfs && command -v mkfs.btrfs && command -v btrfs || return $?
             ;;
+        iscsi)
+            # Client/initiator (Open-iSCSI)
+            command -v iscsiadm && command -v iscsid || return $?
+            # Server/target (TGT)
+            command -v tgtadm && command -v tgtd || return $?
+            ;;
         lvm)
             command -v lvm || return $?
             ;;
@@ -56,6 +62,7 @@ test_append_files() {(
     # checked for here
     local -A features=(
         [btrfs]=install_btrfs
+        [iscsi]=install_iscsi
         [lvm]=install_lvm
         [multipath]=install_multipath
     )
@@ -362,6 +369,35 @@ testcase_btrfs_basic() {
     rm -f "${TESTDIR:?}"/btrfsbasic*.img
 }
 
+testcase_iscsi_lvm() {
+    if ! _host_has_feature "iscsi" || ! _host_has_feature "lvm"; then
+        echo "Missing iSCSI client/server tools (Open-iSCSI/TGT) or LVM utilities, skipping the test..."
+        return 77
+    fi
+
+    local qemu_opts=("-device ahci,id=ahci0")
+    local diskpath i size
+
+    for i in {0..3}; do
+        diskpath="${TESTDIR:?}/iscsibasic${i}.img"
+        # Make the first disk larger for multi-partition tests
+        [[ $i -eq 0 ]] && size=150 || size=64
+        # Make the first disk larger for multi-partition tests
+
+        dd if=/dev/zero of="$diskpath" bs=1M count="$size"
+        qemu_opts+=(
+            "-device ide-hd,bus=ahci0.$i,drive=drive$i,model=foobar,serial=deadbeefiscsi$i"
+            "-drive format=raw,cache=unsafe,file=$diskpath,if=none,id=drive$i"
+        )
+    done
+
+
+    KERNEL_APPEND="systemd.setenv=TEST_FUNCTION_NAME=${FUNCNAME[0]} ${USER_KERNEL_APPEND:-}"
+    QEMU_OPTIONS="${qemu_opts[*]} ${USER_QEMU_OPTIONS:-}"
+    test_run_one "${1:?}" || return $?
+
+    rm -f "${TESTDIR:?}"/iscsibasic*.img
+}
 # Allow overriding which tests should be run from the "outside", useful for manual
 # testing (make -C test/... TESTCASES="testcase1 testcase2")
 if [[ -v "TESTCASES" && -n "$TESTCASES" ]]; then
index 4380fa0fcfa0b8219ccc0f282057fc3f3195e0d9..bcc4dc9f17ead2a388b41b594a56f5b1ce0133d6 100755 (executable)
@@ -40,6 +40,57 @@ helper_check_device_symlinks() {(
     done < <(find "${paths[@]}" -type l)
 )}
 
+# Wait for a specific device link to appear
+# Arguments:
+#   $1 - device path
+#   $2 - number of retries (default: 10)
+helper_wait_for_dev() {
+    local dev="${1:?}"
+    local ntries="${2:-10}"
+    local i
+
+    for ((i = 0; i < ntries; i++)); do
+        test ! -e "$dev" || return 0
+        sleep .2
+    done
+
+    return 1
+}
+
+# Wait for the lvm2-pvscan@.service of a specific device to finish
+# Arguments:
+#   $1 - device path
+#   $2 - number of retries (default: 10)
+helper_wait_for_pvscan() {
+    local dev="${1:?}"
+    local ntries="${2:-10}"
+    local MAJOR MINOR pvscan_svc real_dev
+
+    # Sanity check we got a valid block device (or a symlink to it)
+    real_dev="$(readlink -f "$dev")"
+    if [[ ! -b "$real_dev" ]]; then
+        echo >&2 "ERROR: '$dev ($real_dev) is not a valid block device'"
+        return 1
+    fi
+
+    # Get major and minor numbers from the udev database
+    # (udevadm returns MAJOR= and MINOR= expressions, so let's pull them into
+    # the current environment via `source` for easier parsing)
+    source <(udevadm info -q property "$real_dev" | grep -E "(MAJOR|MINOR)=")
+    # Sanity check if we got correct major and minor numbers
+    test -e "/sys/dev/block/$MAJOR:$MINOR/"
+
+    # Wait n_tries*0.5 seconds until the respective lvm2-pvscan service becomes
+    # active (i.e. it got executed and finished)
+    pvscan_svc="lvm2-pvscan@$MAJOR:$MINOR.service"
+    for ((i = 0; i < ntries; i++)); do
+        ! systemctl -q is-active "$pvscan_svc" || return 0
+        sleep .5
+    done
+
+    return 1
+}
+
 testcase_megasas2_basic() {
     lsblk -S
     [[ "$(lsblk --scsi --noheadings | wc -l)" -ge 128 ]]
@@ -397,6 +448,144 @@ EOF
     udevadm settle
 }
 
+testcase_iscsi_lvm() {
+    local dev i label link lun_id mpoint target_name uuid
+    local target_ip="127.0.0.1"
+    local target_port="3260"
+    local vgroup="iscsi_lvm$RANDOM"
+    local expected_symlinks=()
+    local devices=(
+        /dev/disk/by-id/ata-foobar_deadbeefiscsi{0..3}
+    )
+
+    ls -l "${devices[@]}"
+
+    # Start the target daemon
+    systemctl start tgtd
+    systemctl status tgtd
+
+    echo "iSCSI LUNs backed by devices"
+    # See RFC3721 and RFC7143
+    target_name="iqn.2021-09.com.example:iscsi.test"
+    # Initialize a new iSCSI target <$target_name> consisting of 4 LUNs, each
+    # backed by a device
+    tgtadm --lld iscsi --op new --mode target --tid=1 --targetname "$target_name"
+    for ((i = 0; i < ${#devices[@]}; i++)); do
+        # lun-0 is reserved by iSCSI
+        lun_id="$((i + 1))"
+        tgtadm --lld iscsi --op new --mode logicalunit --tid 1 --lun "$lun_id" -b "${devices[$i]}"
+        tgtadm --lld iscsi --op update --mode logicalunit --tid 1 --lun "$lun_id"
+        expected_symlinks+=(
+            "/dev/disk/by-path/ip-$target_ip:$target_port-iscsi-$target_name-lun-$lun_id"
+        )
+    done
+    tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL
+    # Configure the iSCSI initiator
+    iscsiadm --mode discoverydb --type sendtargets --portal "$target_ip" --discover
+    iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --login
+    udevadm settle
+    # Check if all device symlinks are valid and if all expected device symlinks exist
+    for link in "${expected_symlinks[@]}"; do
+        # We need to do some active waiting anyway, as it may take kernel a bit
+        # to attach the newly connected SCSI devices
+        helper_wait_for_dev "$link"
+        test -e "$link"
+    done
+    udevadm settle
+    helper_check_device_symlinks
+    # Cleanup
+    iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --logout
+    tgtadm --lld iscsi --op delete --mode target --tid=1
+
+    echo "iSCSI LUNs backed by files + LVM"
+    # Note: we use files here to "trick" LVM the disks are indeed on a different
+    #       host, so it doesn't automagically detect another path to the backing
+    #       device once we disconnect the iSCSI devices
+    target_name="iqn.2021-09.com.example:iscsi.lvm.test"
+    mpoint="$(mktemp -d /iscsi_storeXXX)"
+    expected_symlinks=()
+    # Use the first device as it's configured with larger capacity
+    mkfs.ext4 -L iscsi_store "${devices[0]}"
+    udevadm settle
+    mount "${devices[0]}" "$mpoint"
+    for i in {1..4}; do
+        dd if=/dev/zero of="$mpoint/lun$i.img" bs=1M count=32
+    done
+    # Initialize a new iSCSI target <$target_name> consisting of 4 LUNs, each
+    # backed by a file
+    tgtadm --lld iscsi --op new --mode target --tid=2 --targetname "$target_name"
+    # lun-0 is reserved by iSCSI
+    for i in {1..4}; do
+        tgtadm --lld iscsi --op new --mode logicalunit --tid 2 --lun "$i" -b "$mpoint/lun$i.img"
+        tgtadm --lld iscsi --op update --mode logicalunit --tid 2 --lun "$i"
+        expected_symlinks+=(
+            "/dev/disk/by-path/ip-$target_ip:$target_port-iscsi-$target_name-lun-$i"
+        )
+    done
+    tgtadm --lld iscsi --op bind --mode target --tid 2 -I ALL
+    # Configure the iSCSI initiator
+    iscsiadm --mode discoverydb --type sendtargets --portal "$target_ip" --discover
+    iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --login
+    udevadm settle
+    # Check if all device symlinks are valid and if all expected device symlinks exist
+    for link in "${expected_symlinks[@]}"; do
+        # We need to do some active waiting anyway, as it may take kernel a bit
+        # to attach the newly connected SCSI devices
+        helper_wait_for_dev "$link"
+        test -e "$link"
+    done
+    udevadm settle
+    helper_check_device_symlinks
+    # Add all iSCSI devices into a LVM volume group, create two logical volumes,
+    # and check if necessary symlinks exist (and are valid)
+    lvm pvcreate -y "${expected_symlinks[@]}"
+    lvm pvs
+    lvm vgcreate "$vgroup" -y "${expected_symlinks[@]}"
+    lvm vgs
+    lvm vgchange -ay "$vgroup"
+    lvm lvcreate -y -L 4M "$vgroup" -n mypart1
+    lvm lvcreate -y -L 8M "$vgroup" -n mypart2
+    lvm lvs
+    udevadm settle
+    test -e "/dev/$vgroup/mypart1"
+    test -e "/dev/$vgroup/mypart2"
+    mkfs.ext4 -L mylvpart1 "/dev/$vgroup/mypart1"
+    udevadm settle
+    test -e "/dev/disk/by-label/mylvpart1"
+    helper_check_device_symlinks "/dev/disk" "/dev/$vgroup"
+    # Disconnect the iSCSI devices and check all the symlinks
+    iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --logout
+    # "Reset" the DM state, since we yanked the backing storage from under the LVM,
+    # so the currently active VGs/LVs are invalid
+    dmsetup remove_all --deferred
+    udevadm settle
+    # The LVM and iSCSI related symlinks should be gone
+    test ! -e "/dev/$vgroup"
+    test ! -e "/dev/disk/by-label/mylvpart1"
+    for link in "${expected_symlinks[@]}"; do
+        test ! -e "$link"
+    done
+    helper_check_device_symlinks "/dev/disk"
+    # Reconnect the iSCSI devices and check if everything get detected correctly
+    iscsiadm --mode discoverydb --type sendtargets --portal "$target_ip" --discover
+    iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --login
+    udevadm settle
+    for link in "${expected_symlinks[@]}"; do
+        helper_wait_for_dev "$link"
+        helper_wait_for_pvscan "$link"
+        test -e "$link"
+    done
+    udevadm settle
+    test -e "/dev/$vgroup/mypart1"
+    test -e "/dev/$vgroup/mypart2"
+    test -e "/dev/disk/by-label/mylvpart1"
+    helper_check_device_symlinks "/dev/disk" "/dev/$vgroup"
+    # Cleanup
+    iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --logout
+    tgtadm --lld iscsi --op delete --mode target --tid=2
+    umount "$mpoint"
+    rm -rf "$mpoint"
+}
 : >/failed
 
 udevadm settle