Skip to content
Draft
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
597 changes: 597 additions & 0 deletions SPEC-iscsi-vm-target.md

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion containers/runner/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ RUN dnf -y update && \
python3-rpm \
squid \
make \
openssh-clients && \
openssh-clients \
sshpass && \
dnf -y clean all

# FIXME(workaround): LIBGUESTFS_BACKEND=direct — remove when fixed upstream.
Expand Down
150 changes: 150 additions & 0 deletions functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,156 @@
fi
}

ISCSI_TARGET_SSH_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=2 -o PubkeyAuthentication=no"

create_iscsi_target_vm() {
local wwn=$1
local initiator=$2

Check warning

Code scanning / shellcheck

SC2034 Warning

initiator appears unused. Verify use (or export if used externally).
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
local tmpdir=$3
local logfile=$4

local port_seed=$(echo "${tmpdir}" | cksum | awk '{print $1}')

Check warning

Code scanning / shellcheck

SC2155 Warning

Declare and assign separately to avoid masking return values.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
local mcast_port=$((10000 + port_seed % 20000))
local ssh_port=$((30000 + (port_seed + 1) % 20000))
local target_ip=10.10.10.1
local disk_img=${tmpdir}/iscsi-target.qcow2
local domain_name="iscsi-target-$(basename ${tmpdir})"

Check warning

Code scanning / shellcheck

SC2155 Warning

Declare and assign separately to avoid masking return values.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed

echo ${domain_name} > ${tmpdir}/iscsi-target-domain
echo ${disk_img} > ${tmpdir}/iscsi-target-disk
echo ${mcast_port} > ${tmpdir}/iscsi-mcast-port
echo ${ssh_port} > ${tmpdir}/iscsi-ssh-port

local cache_dir=${KSTEST_ISCSI_CACHE:-/var/tmp/kstest-iscsi-cache}
local base_img="${cache_dir}/iscsi-target-base.qcow2"

if [ ! -f "${base_img}" ]; then
mkdir -p "${cache_dir}"
(
flock -x 9
# Re-check after acquiring lock (another process may have created it)
if [ -f "${base_img}" ]; then
exit 0
fi
local image_url=${KSTEST_ISCSI_TARGET_IMAGE:-"https://download.fedoraproject.org/pub/fedora/linux/releases/42/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-42-1.1.x86_64.qcow2"}
Comment thread
bruno-fs marked this conversation as resolved.
Outdated

if [[ "${image_url}" == http* ]]; then
echo "Downloading iSCSI target base image..." >&2
curl -f -L --retry 3 -o "${cache_dir}/download.tmp.$$" "${image_url}" &>> ${logfile} || {
echo "ERROR: Failed to download iSCSI target image from ${image_url}" >&2
rm -f "${cache_dir}/download.tmp.$$"
exit 1
}
mv "${cache_dir}/download.tmp.$$" "${cache_dir}/downloaded.$$.qcow2"
else
cp "${image_url}" "${cache_dir}/downloaded.$$.qcow2" || {
echo "ERROR: Failed to copy iSCSI target image from ${image_url}" >&2
exit 1
}
fi

echo "Preparing iSCSI target base image with virt-customize..." >&2
virt-customize -a "${cache_dir}/downloaded.$$.qcow2" \
--root-password password:testcase \
--install targetcli,NetworkManager \
--run-command 'systemctl enable sshd target' \
--run-command 'echo "PermitRootLogin yes" >> /etc/ssh/sshd_config.d/99-kstest.conf' \
--run-command 'systemctl disable cloud-init cloud-init-local cloud-config cloud-final 2>/dev/null; true' \
--selinux-relabel \
&>> ${logfile} || {
echo "ERROR: virt-customize failed" >&2
rm -f "${cache_dir}/downloaded.$$.qcow2"
exit 1
}

mv "${cache_dir}/downloaded.$$.qcow2" "${base_img}"
echo "Cached iSCSI target base image at ${base_img}" >&2
) 9>"${cache_dir}/base.lock" || return 1
fi

qemu-img create -f qcow2 -b "${base_img}" -F qcow2 "${disk_img}" &>> ${logfile}

virt-install \
--name ${domain_name} \
--ram 2048 --vcpus 1 \
--disk path=${disk_img},bus=virtio \
--import --graphics none --noautoconsole \
--osinfo detect=on,require=off \
--seclabel type=none \
--network none \
--qemu-commandline="-netdev" \
"--qemu-commandline=socket,id=net0,mcast=230.0.0.1:${mcast_port},localaddr=127.0.0.1" \
--qemu-commandline="-device" \
"--qemu-commandline=virtio-net-pci,netdev=net0,addr=0x10" \
--qemu-commandline="-netdev" \
"--qemu-commandline=user,id=net1,hostfwd=tcp::${ssh_port}-:22" \
--qemu-commandline="-device" \
"--qemu-commandline=virtio-net-pci,netdev=net1,addr=0x11" \
&>> ${logfile}

local ssh_cmd="sshpass -p testcase ssh ${ISCSI_TARGET_SSH_OPTS} -p ${ssh_port} root@127.0.0.1"
local ssh_ok=false
for i in $(seq 1 120); do

Check warning

Code scanning / shellcheck

SC2034 Warning

i appears unused. Verify use (or export if used externally).
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
if ${ssh_cmd} 'echo ready' &>/dev/null; then
ssh_ok=true
break
fi
sleep 1
done

if ! ${ssh_ok}; then
echo "ERROR: iSCSI target VM did not become reachable in 120s" >&2
return 1
fi

${ssh_cmd} << SSHEOF &>> ${logfile}
set -e
IFACE=\$(ls /sys/bus/pci/devices/0000:00:10.0/net/ 2>/dev/null | head -1)
if [ -z "\$IFACE" ]; then
IFACE=\$(ip -o link show | grep -v lo | head -1 | awk -F': ' '{print \$2}')
fi
nmcli connection add type ethernet con-name iscsi-net ifname \$IFACE \
ipv4.method manual ipv4.addresses ${target_ip}/24 ipv6.method disabled
nmcli connection up iscsi-net

dd if=/dev/zero of=/root/disk bs=1M count=1 seek=10240

targetcli "/backstores/fileio create file_or_dev=/root/disk name=disk write_back=false"
targetcli "/iscsi create wwn=${wwn}"
targetcli "/iscsi/${wwn}/tpg1/luns create /backstores/fileio/disk"
targetcli "/iscsi/${wwn}/tpg1 set attribute authentication=0 demo_mode_write_protect=0 generate_node_acls=1 cache_dynamic_acls=1"
targetcli "/iscsi/${wwn}/tpg1/portals delete 0.0.0.0 3260" 2>/dev/null || true
targetcli "/iscsi/${wwn}/tpg1/portals delete ::0 3260" 2>/dev/null || true
targetcli "/iscsi/${wwn}/tpg1/portals create ${target_ip} 3260"
targetcli "/ saveconfig"

firewall-cmd --permanent --add-service=iscsi-target 2>/dev/null && \
firewall-cmd --reload 2>/dev/null || true
SSHEOF

if [ $? -ne 0 ]; then
echo "ERROR: iSCSI target VM setup failed" >&2
return 1
fi

${ssh_cmd} 'ss -tlnp | grep -q 3260' &>> ${logfile} || {
echo "ERROR: iSCSI target not listening on port 3260" >&2
return 1
}
}

remove_iscsi_target_vm() {
local domain_name=$1
local disk_img=$2
local logfile=$3

if [ -n "${domain_name}" ]; then
virsh destroy ${domain_name} &>> ${logfile} || true
virsh undefine ${domain_name} &>> ${logfile} || true
fi
rm -f ${disk_img}
}

apply_updates_image() {
local image_url="${1}"
local updates_dir="${2}"
Expand Down
8 changes: 4 additions & 4 deletions iscsi-bind.ks.in
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
iscsiname @KSTEST_ISCSINAME@
iscsi --ipaddr @KSTEST_ISCSI_IP@ --port @KSTEST_ISCSI_PORT@ --target @KSTEST_ISCSI_TARGET@ --iface=@KSTEST_NETDEV1@

bootloader --timeout=1
bootloader --location=none
zerombr
clearpart --all
autopart
autopart --nohome

# for non-offload iSCSI /boot can be on iSCSI only when using iBFT,
# so put it to local disk
Expand All @@ -20,7 +20,7 @@ keyboard us
lang en
timezone America/New_York
rootpw qweqwe
shutdown
poweroff

%packages
%end
Expand All @@ -33,7 +33,7 @@ function check_iscsi_session_nochroot() {
local transport="$1"
local target="$2"

iscsiadm -m session | egrep -q '^'${transport}':.*'${target}
iscsiadm -m session | grep -Eq '^'${transport}':.*'${target}
if [[ $? -ne 0 ]]; then
echo "*** Failed check: ${target} session using ${transport} exists" >> $SYSROOT/root/RESULT
fi
Expand Down
25 changes: 24 additions & 1 deletion iscsi-bind.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,30 @@

# Ignore unused variable parsed out by tooling scripts as test tags metadata
# shellcheck disable=SC2034
TESTTYPE="knownfailure iscsi"
TESTTYPE=${TESTTYPE:-"iscsi"}

. ${KSTESTDIR}/iscsi.sh

prepare() {
local ks=$1
local tmpdir=$2

local test_id=$(basename ${tmpdir})

Check warning

Code scanning / shellcheck

SC2155 Warning

Declare and assign separately to avoid masking return values.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
local lc_test_id=$(echo "${test_id,,}" | tr -c 'a-z0-9\n' '-')

Check warning

Code scanning / shellcheck

SC2155 Warning

Declare and assign separately to avoid masking return values.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
local wwn=iqn.2003-01.kickstart.test:${lc_test_id}
local initiator=iqn.2009-02.com.example:${lc_test_id}
local logfile=${tmpdir}/iscsi-target.log

create_iscsi_target_vm ${wwn} ${initiator} ${tmpdir} ${logfile} || return 1

# eth0 is the mcast NIC (PCI addr=0x10, iSCSI network)
sed -i \
-e "s#@KSTEST_ISCSI_IP@#10.10.10.1#g" \
-e "s#@KSTEST_ISCSI_PORT@#3260#g" \
-e "s#@KSTEST_ISCSI_TARGET@#${wwn}#g" \
-e "s#@KSTEST_ISCSINAME@#${initiator}#g" \
-e "s#@KSTEST_NETDEV1@#eth0#g" \
${ks}

echo ${ks}
}
Comment thread
bruno-fs marked this conversation as resolved.
49 changes: 49 additions & 0 deletions iscsi-ordering.ks.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@

%ksappend repos/default.ks

# INSTALLER-4044 reproducer: ignoredisk BEFORE iscsi
# On unfixed builds, this fails with "Disk sda does not exist"
# On fixed builds (deferred device resolution), this works
ignoredisk --only-use=@KSTEST_ISCSI_DISK@

iscsiname @KSTEST_ISCSINAME@
iscsi --ipaddr @KSTEST_ISCSI_IP@ --port @KSTEST_ISCSI_PORT@ --target @KSTEST_ISCSI_TARGET@

bootloader --location=none
zerombr
clearpart --all
autopart --nohome

keyboard us
lang en
timezone America/New_York
rootpw qweqwe
poweroff

%packages
%end

%post --nochroot

SYSROOT=/mnt/sysroot

function check_iscsi_session_nochroot() {
local transport="$1"
local target="$2"

iscsiadm -m session | grep -Eq '^'${transport}':.*'${target}
if [[ $? -ne 0 ]]; then
echo "*** Failed check: ${target} session using ${transport} exists" >> $SYSROOT/root/RESULT
fi
}

check_iscsi_session_nochroot tcp @KSTEST_ISCSI_TARGET@

%end

%post
# No error was written to /root/RESULT file, everything is OK
if [[ ! -e /root/RESULT ]]; then
echo SUCCESS > /root/RESULT
fi
%end
49 changes: 49 additions & 0 deletions iscsi-ordering.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#
# Copyright (C) 2025 Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# the GNU General Public License v.2, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY expressed or implied, including the implied warranties of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details. You should have received a copy of the
# GNU General Public License along with this program; if not, write to the
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
# source code or documentation are not subject to the GNU General Public
# License and may only be used or replicated with the express permission of
# Red Hat, Inc.

# INSTALLER-4044: ignoredisk before iscsi ordering test
# Requires the anaconda fix that defers device resolution to process_kickstart()

# Ignore unused variable parsed out by tooling scripts as test tags metadata
# shellcheck disable=SC2034
TESTTYPE=${TESTTYPE:-"iscsi"}

. ${KSTESTDIR}/iscsi.sh

prepare() {
local ks=$1
local tmpdir=$2

local test_id=$(basename ${tmpdir})

Check warning

Code scanning / shellcheck

SC2155 Warning

Declare and assign separately to avoid masking return values.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
local lc_test_id=$(echo "${test_id,,}" | tr -c 'a-z0-9\n' '-')

Check warning

Code scanning / shellcheck

SC2155 Warning

Declare and assign separately to avoid masking return values.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
local wwn=iqn.2003-01.kickstart.test:${lc_test_id}
local initiator=iqn.2009-02.com.example:${lc_test_id}
local logfile=${tmpdir}/iscsi-target.log

create_iscsi_target_vm ${wwn} ${initiator} ${tmpdir} ${logfile} || return 1

# sda is the expected device name for the first SCSI disk from iSCSI on x86_64
sed -i \
-e "s#@KSTEST_ISCSI_IP@#10.10.10.1#g" \
-e "s#@KSTEST_ISCSI_PORT@#3260#g" \
-e "s#@KSTEST_ISCSI_TARGET@#${wwn}#g" \
-e "s#@KSTEST_ISCSINAME@#${initiator}#g" \
-e "s#@KSTEST_ISCSI_DISK@#sda#g" \
${ks}

echo ${ks}
}
8 changes: 4 additions & 4 deletions iscsi.ks.in
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
iscsiname @KSTEST_ISCSINAME@
iscsi --ipaddr @KSTEST_ISCSI_IP@ --port @KSTEST_ISCSI_PORT@ --target @KSTEST_ISCSI_TARGET@

bootloader --timeout=1
bootloader --location=none
zerombr
clearpart --all
autopart
autopart --nohome

# for non-offload iSCSI /boot can be on iSCSI only when using iBFT,
# so put it to local disk
Expand All @@ -20,7 +20,7 @@ keyboard us
lang en
timezone America/New_York
rootpw qweqwe
shutdown
poweroff

%packages
%end
Expand All @@ -33,7 +33,7 @@ function check_iscsi_session_nochroot() {
local transport="$1"
local target="$2"

iscsiadm -m session | egrep -q '^'${transport}':.*'${target}
iscsiadm -m session | grep -Eq '^'${transport}':.*'${target}
if [[ $? -ne 0 ]]; then
echo "*** Failed check: ${target} session using ${transport} exists" >> $SYSROOT/root/RESULT
fi
Expand Down
Loading