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

s390x: add support for zFCP SCSI and ECKD DASD devices on zVM and LPAR #61

Merged
merged 9 commits into from
Nov 21, 2019
236 changes: 190 additions & 46 deletions coreos-installer
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,12 @@ ZskQ/mDUv6F4w6N8Vk9R/nJTfpI36vWTcH7xxLNoNRlL2b/7ra6dB8YPsOdLy158
-----END PGP PUBLIC KEY BLOCK-----
"

arch=$(uname -m)
boot_partition="/mnt/boot_partition"
tmpfs_mountpoint="/mnt/dl"
imagefile="$tmpfs_mountpoint/imagefile"
imagefile_compressed="$tmpfs_mountpoint/imagefile.compressed"
imagefile_compressed_sig="$tmpfs_mountpoint/imagefile.compressed.sig"

############################################################
# Helper to mount the boot partition from the device
Expand All @@ -313,16 +319,14 @@ mount_boot_partition() {
# The first command will find the partition with the boot label
# and the eval command will set the $UUID variable that we use later.
set -o pipefail
output=$(lsblk "${DEST_DEV}" --output NAME,LABEL,UUID --pairs | grep 'LABEL="boot"')
eval $(echo $output | tr ' ' '\n' | tail -n 1)
set +o pipefail

let retry=0
while true
do
mount "/dev/disk/by-uuid/${UUID}" /mnt/boot_partition
output=$(lsblk "${DEST_DEV}" --output NAME,LABEL,UUID --pairs | grep 'LABEL="boot"')
eval $(echo $output | tr ' ' '\n' | tail -n 1)
mount "/dev/disk/by-uuid/${UUID}" "$boot_partition"
RETCODE=$?
if [[ $RETCODE -ne 0 ]]; then
if [[ -z "$output" ]] || [[ $RETCODE -ne 0 ]]; then
if [[ $retry -lt 30 ]]; then
# retry and sleep to allow udevd to populate /dev/disk/by-uuid
sleep 1
Expand All @@ -334,6 +338,7 @@ mount_boot_partition() {
fi
break;
done
set +o pipefail
}

############################################################
Expand All @@ -347,12 +352,12 @@ write_ignition_file() {

log "Embedding provided Ignition config"
# mount the boot partition
mkdir -p /mnt/boot_partition
mount_boot_partition /mnt/boot_partition
trap 'umount /mnt/boot_partition; trap - RETURN' RETURN
mkdir -p "$boot_partition"
mount_boot_partition "$boot_partition"
trap 'umount $boot_partition; trap - RETURN' RETURN

mkdir -p /mnt/boot_partition/ignition
cp /tmp/ignition.ign /mnt/boot_partition/ignition/config.ign
mkdir -p "${boot_partition}/ignition"
cp /tmp/ignition.ign "${boot_partition}/ignition/config.ign"
RETCODE=$?
if [[ $RETCODE -ne 0 ]]; then
log "failed writing ignition config"
Expand All @@ -371,11 +376,11 @@ write_networking_opts() {

log "Embedding provided networking options"
# check for the boot partition
mkdir -p /mnt/boot_partition
mount_boot_partition /mnt/boot_partition
trap 'umount /mnt/boot_partition; trap - RETURN' RETURN
mkdir -p "$boot_partition"
mount_boot_partition "$boot_partition"
trap 'umount $boot_partition; trap - RETURN' RETURN

echo "set ignition_network_kcmdline=\"$(cat /tmp/networking_opts)\"" >> /mnt/boot_partition/ignition.firstboot
echo "set ignition_network_kcmdline=\"$(cat /tmp/networking_opts)\"" >> "${boot_partition}/ignition.firstboot"
}

#########################################################
Expand All @@ -394,10 +399,10 @@ write_platform_id() {

log "Overwriting ignition platform id"
# check for the boot partition
mkdir -p /mnt/boot_partition
mount_boot_partition /mnt/boot_partition
trap 'umount /mnt/boot_partition; trap - RETURN' RETURN
local conf_files=$(ls /mnt/boot_partition/loader/entries/*conf)
mkdir -p "$boot_partition"
mount_boot_partition "$boot_partition"
trap 'umount $boot_partition; trap - RETURN' RETURN
local conf_files=$(ls ${boot_partition}/loader/entries/*conf)

for f in $conf_files
do
Expand Down Expand Up @@ -425,11 +430,11 @@ write_additional_opts() {

log "Embedding provided additional options"
# check for the boot partition
mkdir -p /mnt/boot_partition
mount_boot_partition /mnt/boot_partition
trap 'umount /mnt/boot_partition; trap - RETURN' RETURN
mkdir -p "$boot_partition"
mount_boot_partition "$boot_partition"
trap 'umount $boot_partition; trap - RETURN' RETURN

echo "set ignition_extra_kcmdline=\"$(cat /tmp/additional_opts)\"" >> /mnt/boot_partition/ignition.firstboot
echo "set ignition_extra_kcmdline=\"$(cat /tmp/additional_opts)\"" >> "${boot_partition}/ignition.firstboot"
}

############################################################
Expand Down Expand Up @@ -572,24 +577,29 @@ get_ignition_url() {
#########################################################
mount_tmpfs() {
log "Mounting tmpfs"
mkdir -p /mnt/dl
mount -t tmpfs -o size=${TMPFS_MBSIZE}m tmpfs /mnt/dl
if [ -n "$1" ]; then
options="remount,size=${1}m"
tuan-hoang1 marked this conversation as resolved.
Show resolved Hide resolved
else
options="size=${TMPFS_MBSIZE}m"
fi
mkdir -p "$tmpfs_mountpoint"
mount -t tmpfs -o "$options" tmpfs "$tmpfs_mountpoint"
}

#########################################################
#And Get the Image
#########################################################
download_image() {
log "Downloading install image"
(curl -L -s -o /mnt/dl/imagefile.compressed $IMAGE_URL; echo $? > /tmp/curl-rc) &
(curl -L -s -o ${imagefile_compressed} $IMAGE_URL; echo $? > /tmp/curl-rc) &

while [ ! -f /tmp/curl-rc ]; do
# If the image hasn't show up yet then wait a sec and loop
if [ ! -f /mnt/dl/imagefile.compressed ]; then
if [ ! -f ${imagefile_compressed} ]; then
sleep 1
continue
fi
PART_FILE_SIZE=$(ls -l /mnt/dl/imagefile.compressed | awk '{print $5}') 2>/dev/null
PART_FILE_SIZE=$(ls -l ${imagefile_compressed} | awk '{print $5}') 2>/dev/null
PCT=$(dc -e"2 k $PART_FILE_SIZE $IMAGE_SIZE / 100 * p" | sed -e"s/\..*$//" 2>/dev/null)
echo "${PCT}%" >&2
sleep 1
Expand All @@ -601,14 +611,26 @@ download_image() {
log "Image download failed"
exit 1
fi

# Check for gzip and xz correspondingly
if [ "$(dd count=2 bs=1 if=${imagefile_compressed} status=none)" = "$(printf '\x1f\x8b')" ]
then
DECOMPRESSION_TOOL='zcat'
elif [ "$(dd count=5 bs=1 if=${imagefile_compressed} status=none)" = "$(printf '\xfd\x37\x7a\x58\x5a')" ]
then
DECOMPRESSION_TOOL='xzcat'
else
log "Compressed file format is not supported. Supported formats: '.xz', '.gz'"
exit 1
fi
}

#########################################################
#Get the corresponding signaure file
#########################################################
download_sig() {
log "Getting signature"
curl -L -s -o /mnt/dl/imagefile.compressed.sig $SIG_URL
curl -L -s -o ${imagefile_compressed_sig} $SIG_URL
if [ $? -ne 0 ]
then
log "Unable to download sig file."
Expand All @@ -625,16 +647,17 @@ validate_image() {
then
if [ "$SIG_TYPE" == "gpg" ]
then
gpg2 --trusted-key "${GPG_LONG_ID}" --verify /mnt/dl/imagefile.compressed.sig >/dev/null 2>&1
gpg2 --trusted-key "${GPG_LONG_ID}" --verify ${imagefile_compressed_sig} >/dev/null 2>&1
if [ $? -ne 0 ]
then
log "Install Image is corrupted."
exit 1
fi
elif [ "$SIG_TYPE" == "sha" ]
then
sed -i -e"s/$/\ \/mnt\/dl\/imagefile\.gz/" /mnt/dl/imagefile.compressed.sig
sha256sum -c /mnt/dl/imagefile.compressed.sig
# sed original file path with current path in signature file
sed -i -e "s@/.*/@$tmpfs_mountpoint/@g" ${imagefile_compressed_sig}
sha256sum -c ${imagefile_compressed_sig}
if [ $? -ne 0 ]
then
log "Install Image is corrupted."
Expand Down Expand Up @@ -662,30 +685,148 @@ log() {
echo "$1" >&2
}

#########################################################
#Update bootloader if needed
#########################################################
write_zipl_bootloader() {
if [[ "$arch" == "s390x" ]]; then
log "Updating zipl"
mkdir -p "$boot_partition"
mount_boot_partition "$boot_partition"
trap 'umount $boot_partition; trap - RETURN' RETURN


blsfile=$(ls ${boot_partition}/loader/entries/*.conf)
# We need to propagate s390x parameter to later boots via BLS files
# More details : https://github.com/coreos/fedora-coreos-tracker/issues/305
options="$(grep options $blsfile | cut -d' ' -f2-) $(cat /tmp/s390x_opts)"
sed -i -e "s@^options.*@options $options@g" $blsfile
# And also keep networking parameters for first boot
echo "$options $(cat /tmp/networking_opts) ignition.firstboot" > /tmp/zipl_prm
zipl --verbose -p /tmp/zipl_prm -i $(ls ${boot_partition}/ostree/*/*vmlinuz*) -r $(ls ${boot_partition}/ostree/*/*initramfs*) --target "$boot_partition"
if [[ $? -ne 0 ]]; then
log "failed updating bootloder"
exit 1
fi
# this allows a reboot into new installed disk
chreipl "${DEST_DEV}"
fi
}

#########################################################
tuan-hoang1 marked this conversation as resolved.
Show resolved Hide resolved
#Handle s390x ECKD DASD devices
#########################################################
write_image_to_dasd() {
log "Extracting disk image"
mount_tmpfs $(( $($DECOMPRESSION_TOOL ${imagefile_compressed} | wc --bytes) / 1024 / 1024 + ${TMPFS_MBSIZE} + 100 ))
$DECOMPRESSION_TOOL ${imagefile_compressed} > ${imagefile}

# low-level format the ECKD DASD using dasdfmt, if needed
DEST_DEV_BUS=$(lszdev --by-node ${DEST_DEV} | tail -n 1 | awk '{print $2}')
if [ "$(< /sys/bus/ccw/devices/${DEST_DEV_BUS}/status)" = "unformatted" ]; then
dasdfmt --blocksize 4096 --disk_layout cdl --mode full -ypv "${DEST_DEV}"
fi
block_per_tracks=$(fdasd -p ${DEST_DEV} | grep blocks\ per\ track | awk '{print $5}')

# the first 2 tracks of the ECKD DASD are reserved
first_track=2
# in RHCOS4.2 using anaconda, we have root partition at index 2 while in FCOS it's 4
Copy link
Author

Choose a reason for hiding this comment

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

I don't think this is a good thing to do when RHCOS 4.3 goes out - which matches FCOS. But for the time being, I don't have time/other way to do it.

BOOTPN=1
ROOTPN=2
if [[ -n $(grep -i fedora /usr/lib/initrd-release) ]]; then
ROOTPN=4
fi
boot_partition=($(fdisk -b 4096 -o DEVICE,START,SECTORS -l ${imagefile} | grep "${imagefile}${BOOTPN}" | awk '{print $2,$3}'))
root_partition=($(fdisk -b 4096 -o DEVICE,START,SECTORS -l ${imagefile} | grep "${imagefile}${ROOTPN}" | awk '{print $2,$3}'))
boot_partition+=( $first_track $(dc -e "${boot_partition[1]} $block_per_tracks 1 - + $block_per_tracks / p") )
root_partition+=($(( ${boot_partition[2]} + ${boot_partition[3]} )) "last")
cat > "/tmp/fdasd_conf" <<- EOF
[$first_track,$(( ${root_partition[2]} - 1 )),native]
[${root_partition[2]},${root_partition[3]},native]
EOF

# format the ECKD DASD using fdasd program
fdasd --silent --config /tmp/fdasd_conf "${DEST_DEV}"

# copy the content of each partition
set -- ${boot_partition[@]} ${root_partition[@]}
while [ $# -gt 0 ]; do
dd bs=4096 if="${imagefile}" iflag=fullblock of="${DEST_DEV}" \
status=none \
skip="$1" \
count="$2" \
seek="$(( $3 * $block_per_tracks ))"
if [[ $? -ne 0 ]]; then
log "failed to write image to ECKD DASD device"
exit 1
fi
shift 4
done
}

#########################################################
tuan-hoang1 marked this conversation as resolved.
Show resolved Hide resolved
#Handle s390x zFCP SCSI devices
#########################################################
write_image_to_zfcp_disk() {
log "Extracting disk image"
mount_tmpfs $(( $($DECOMPRESSION_TOOL ${imagefile_compressed} | wc --bytes) / 1024 / 1024 + ${TMPFS_MBSIZE} + 100 ))
$DECOMPRESSION_TOOL ${imagefile_compressed} > ${imagefile}

# we have to store the strings to a file because any change in this
# while-do block would not take effect outside
(while IFS='' read -r line || [ -n "$line" ]
do
if [[ $line =~ "start=" ]]
then
# we save the start= and size= here, then dd the partitions later
printf "%s:%s\n" \
tuan-hoang1 marked this conversation as resolved.
Show resolved Hide resolved
"$(echo $line | cut -d: -f 2 | cut -d, -f 1 | tr -d ' ')" \
"$(echo $line | cut -d: -f 2 | cut -d, -f 2 | tr -d ' ')" \
>> /tmp/sfdisk_info
ashcrow marked this conversation as resolved.
Show resolved Hide resolved
elif ! [[ $line =~ "label:" || $line =~ "label-id:" || $line =~ "unit:" ]]
then
continue
fi
echo $line
done <<< $(sfdisk -d ${imagefile})
) | sfdisk "${DEST_DEV}"

while IFS='' read -r line || [ -n "$line" ]
do
eval ${line%%:*} ${line##*:}
dd if=${imagefile} bs=512 iflag=fullblock \
of="${DEST_DEV}" status=none skip=$start seek=$start count=$size
if [[ $? -ne 0 ]]; then
log "failed to write image to zFCP SCSI disk"
exit 1
fi
done < /tmp/sfdisk_info
}
tuan-hoang1 marked this conversation as resolved.
Show resolved Hide resolved
#########################################################
#And Write the image to disk
#########################################################
write_image_to_disk() {
log "Writing disk image"

set -o pipefail
# Check for gzip and xz correspondingly
if [ "$(dd count=2 bs=1 if=/mnt/dl/imagefile.compressed status=none)" = "$(printf '\x1f\x8b')" ]
if [[ "${arch}" =~ (aarch64|ppc64le|x86_64) ]]
then
DECOMPRESSION_TOOL='zcat'
elif [ "$(dd count=5 bs=1 if=/mnt/dl/imagefile.compressed status=none)" = "$(printf '\xfd\x37\x7a\x58\x5a')" ]
$DECOMPRESSION_TOOL ${imagefile_compressed} |\
dd bs=1M iflag=fullblock oflag=direct of="${DEST_DEV}" status=none
RETCODE=$?
if [[ $RETCODE -ne 0 ]]; then
log "failed to write image to disk"
exit 1
fi
elif [[ "$arch" == "s390x" ]]
then
DECOMPRESSION_TOOL='xzcat'
if [[ "${DEST_DEV}" =~ "dasd" ]]; then
write_image_to_dasd
else
write_image_to_zfcp_disk
fi
else
log "Compressed file format is not supported. Supported formats: '.xz', '.gz'"
exit 1
fi

$DECOMPRESSION_TOOL /mnt/dl/imagefile.compressed |\
dd bs=1M iflag=fullblock oflag=direct of="${DEST_DEV}" status=none
RETCODE=$?
if [[ $RETCODE -ne 0 ]]; then
log "failed to write image to disk"
log "Unsupported architecture"
exit 1
fi
set +o pipefail
Expand Down Expand Up @@ -788,6 +929,9 @@ main() {
# If ignition platform id is provided, overwrite ignition.platform.id in BLS
write_platform_id

# If platform is s390x, update bootloader records
write_zipl_bootloader

log "Install complete"
}

Expand Down
5 changes: 5 additions & 0 deletions dracut/30coreos-installer/coreos-installer-generator
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ cmdline_arg() {
echo "${value}"
}

# allow adding boot parameters at boot time
if [[ $(uname -m) == "s390x" ]]; then
echo -e '\nRequires=dracut-cmdline-ask.service\nAfter=dracut-cmdline-ask.service' >> /usr/lib/systemd/system/coreos-installer.target
fi

if [[ $(cmdline_arg coreos.inst) == "yes" ]]; then
ln -sf "/usr/lib/systemd/system/coreos-installer.target" \
"${UNIT_DIR}/default.target"
Expand Down
13 changes: 13 additions & 0 deletions dracut/30coreos-installer/module-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ install() {
inst_multiple /usr/sbin/blockdev
inst_multiple /usr/sbin/wipefs

if [ "$arch" = "s390x" ]; then
tuan-hoang1 marked this conversation as resolved.
Show resolved Hide resolved
inst_multiple -o /usr/bin/wc
tuan-hoang1 marked this conversation as resolved.
Show resolved Hide resolved
inst_multiple -o /usr/sbin/zipl
inst_multiple -o /usr/sbin/chreipl
inst_multiple -o /usr/sbin/chzdev
inst_multiple -o /usr/sbin/lszdev
inst_multiple -o /usr/sbin/dasdfmt
inst_multiple -o /usr/sbin/fdasd
inst_multiple -o /usr/sbin/fdisk
inst_multiple -o /usr/sbin/sfdisk
inst_multiple -o /lib/s390-tools/stage3.bin
fi

inst_simple /usr/libexec/coreos-installer

inst_simple "$moddir/coreos-installer-generator" \
Expand Down
Loading