Skip to content

Commit 2577806

Browse files
authored
Merge pull request #2895 from OSInside/retain_spare_part
Add rd.kiwi.install.retain_last deployment option
2 parents 076b70c + 1c7639d commit 2577806

File tree

9 files changed

+299
-78
lines changed

9 files changed

+299
-78
lines changed

build-tests/x86/tumbleweed/test-image-disk/appliance.kiwi

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
2+
<!-- OBS-Profiles: @BUILD_FLAVOR@ -->
33
<image schemaversion="7.5" name="kiwi-test-image-disk">
44
<description type="system">
55
<author>Marcus Schäfer</author>
66
<contact>[email protected]</contact>
77
<specification>Disk test build</specification>
88
</description>
9+
<profiles>
10+
<profile name="Standard" description="Standard Disk"/>
11+
<profile name="Retain" description="Retain Last Partition"/>
12+
</profiles>
913
<preferences>
1014
<version>1.42.1</version>
1115
<packagemanager>zypper</packagemanager>
@@ -16,10 +20,13 @@
1620
<rpm-check-signatures>false</rpm-check-signatures>
1721
<bootsplash-theme>breeze</bootsplash-theme>
1822
<bootloader-theme>openSUSE</bootloader-theme>
23+
</preferences>
24+
<preferences profiles="Standard">
1925
<type image="oem" filesystem="btrfs" kernelcmdline="console=ttyS0" firmware="efi" installiso="true" bootpartition="false" btrfs_root_is_snapshot="true" installboot="install">
2026
<bootloader name="grub2" console="serial" timeout="10"/>
2127
<oemconfig>
2228
<oem-unattended>true</oem-unattended>
29+
<oem-swap>true</oem-swap>
2330
<oem-swapsize>1024</oem-swapsize>
2431
<oem-multipath-scan>false</oem-multipath-scan>
2532
</oemconfig>
@@ -28,8 +35,28 @@
2835
</systemdisk>
2936
</type>
3037
</preferences>
38+
<preferences profiles="Retain">
39+
<type image="oem" filesystem="btrfs" kernelcmdline="console=ttyS0 rd.kiwi.install.systemsize=all rd.kiwi.install.retain_last" firmware="efi" installiso="true" bootpartition="false" btrfs_root_is_snapshot="true" installboot="install" spare_part="0" spare_part_fs="ext4" spare_part_mountpoint="/home" spare_part_is_last="true">
40+
<bootloader name="grub2" console="serial" timeout="10"/>
41+
<oemconfig>
42+
<oem-unattended>true</oem-unattended>
43+
<oem-swap>true</oem-swap>
44+
<oem-swapsize>512</oem-swapsize>
45+
<!-- set root partition to a fixed value to keep address consistent -->
46+
<oem-systemsize>2048</oem-systemsize>
47+
<oem-multipath-scan>false</oem-multipath-scan>
48+
<oem-resize>true</oem-resize>
49+
</oemconfig>
50+
<systemdisk>
51+
<volume name="root"/>
52+
</systemdisk>
53+
<!-- whole disk must be big enough for fixed root + other -->
54+
<size unit="G">3</size>
55+
</type>
56+
</preferences>
3157
<users>
3258
<user password="$1$wYJUgpM5$RXMMeASDc035eX.NbYWFl0" home="/root" name="root" groups="root"/>
59+
<user password="$1$wYJUgpM5$RXMMeASDc035eX.NbYWFl0" home="/home/test-user" name="test-user" groups="users"/>
3360
</users>
3461
<repository type="rpm-md">
3562
<source path="obsrepositories:/"/>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
#!/bin/bash
22
set -ex
33

4+
declare kiwi_profiles=${kiwi_profiles}
5+
46
#======================================
57
# Activate services
68
#--------------------------------------
79
systemctl enable sshd
810
systemctl enable grub_config
911
systemctl enable dracut_hostonly
12+
13+
# Just in case the kiwi resizer is disabled in the system and
14+
# gets dropped from the initrd by the customer for some reason
15+
for profile in ${kiwi_profiles//,/ }; do
16+
if [ "${profile}" = "Retain" ]; then
17+
cat > /etc/fstab.script <<-EOF
18+
sed -ie "s@/home ext4 defaults@/home ext4 x-systemd.growfs,defaults@" /etc/fstab
19+
rm /etc/fstabe
20+
EOF
21+
fi
22+
done

doc/source/concept_and_workflow/customize_the_boot_process.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,17 @@ the available kernel boot parameters for these modules:
222222
Note that options starting with `rd.kiwi` are not passed to avoid
223223
side effects.
224224

225+
``rd.kiwi.install.retain_last``
226+
Instructs an OEM installation to retain the contents of the
227+
last partition on the target disk. This setting is only useful
228+
if the last partition does not belong to the main OS e.g. an
229+
extra data partition added via the `spare_part` attribute in
230+
the type setup of the image description. The implementation
231+
also checks if the start address of the last partition on the
232+
target disk matches with the start adress of the image to be
233+
deployed. Only if they match the data on the last partition
234+
can be retained.
235+
225236
``rd.kiwi.oem.luks.reencrypt``
226237
For OEM LUKS2 encrypted disk images. If set, reencrypts the disk
227238
prior an eventual resize and therefore creates a new key pool and

dracut/modules.d/55kiwi-dump/kiwi-dump-image.sh

Lines changed: 160 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -330,15 +330,50 @@ function dump_image {
330330
local load_text="Loading ${image_basename}..."
331331
local title_text="Installation..."
332332
local dump
333+
local parttable
334+
local count_32k
335+
local image_size
336+
local count=0
337+
local block_size=32k
338+
339+
# can we dump this
340+
check_image_fits_target "${image_target}"
333341

342+
# select dump method
334343
if [ -n "${image_from_remote}" ];then
335344
dump=dump_remote_image
336345
else
337346
dump=dump_local_image
338347
fi
339348

340-
check_image_fits_target "${image_target}"
349+
# setup blocks and blocksize to retain last
350+
if getargbool 0 rd.kiwi.install.retain_last; then
351+
if [ -n "${image_from_remote}" ];then
352+
image_size=$((blocks * blocksize))
353+
parttable=$(
354+
fetch_remote_partition_table "${image_source}" "${image_size}"
355+
)
356+
else
357+
parttable=$(
358+
fetch_local_partition_table "${image_source}"
359+
)
360+
fi
361+
if compatible_to_retain "${parttable}" "${image_target}"; then
362+
count=$(get_disk_offset_retain_last_partition "${parttable}")
363+
fi
364+
if [ "${count}" -gt 0 ];then
365+
block_size=$(get_sector_size_from_table_dump "${parttable}")
366+
count_32k=$(
367+
optimize_count_for_32k_blocksize "${block_size}" "${count}"
368+
)
369+
if [ ! "${count}" = "${count_32k}" ];then
370+
count="${count_32k}"
371+
block_size=32k
372+
fi
373+
fi
374+
fi
341375

376+
# last chance to stop us
342377
if [ "${kiwi_oemunattended}" = "false" ];then
343378
local ack_dump_text="Destroying ALL data on ${image_target}, continue ?"
344379
if ! run_dialog --yesno "\"${ack_dump_text}\"" 7 80; then
@@ -347,48 +382,157 @@ function dump_image {
347382
fi
348383
fi
349384

385+
# deploy
350386
echo "${load_text} [${image_target}]..."
351387
if command -v pv &>/dev/null && [ "${kiwi_oemsilentinstall}" = "false" ]
352388
then
353389
# dump with dialog based progress information
354390
setup_progress_fifo ${progress}
355-
eval "${dump}" "${image_source}" "${image_target}" "${progress}" &
391+
eval \
392+
"${dump}" \
393+
"${image_source}" \
394+
"${image_target}" \
395+
"${count}" \
396+
"${block_size}" \
397+
"${progress}" \
398+
&
356399
run_progress_dialog "${load_text}" "${title_text}"
357400
else
358401
# dump with silently blocked console
359-
if ! eval "${dump}" "${image_source}" "${image_target}"; then
402+
if ! eval \
403+
"${dump}" \
404+
"${image_source}" \
405+
"${image_target}" \
406+
"${count}" \
407+
"${block_size}"
408+
then
360409
report_and_quit "Failed to install image"
361410
fi
362411
fi
363412
}
364413

414+
function fetch_local_partition_table {
415+
local image_source=$1
416+
local parttable=/tmp/parttable
417+
sfdisk -d "${image_source}" > "${parttable}" 2>/dev/null
418+
echo "${parttable}"
419+
}
420+
421+
function fetch_remote_partition_table {
422+
local image_source=$1
423+
local image_size=$2
424+
local parttable=/tmp/parttable
425+
dd if=/dev/zero of=/tmp/table bs=1 count=0 seek="${image_size}" &>/dev/null
426+
fetch_file "${image_source}" 2>/dev/null | dd of=/tmp/table bs=512 count=1 conv=notrunc &>/dev/null
427+
sfdisk -d /tmp/table > "${parttable}" 2>/dev/null
428+
echo "${parttable}"
429+
}
430+
431+
function get_sector_size_from_table_dump {
432+
local parttable=$1
433+
sector_size=$(grep sector-size: "${parttable}" | cut -f2 -d:)
434+
echo "${sector_size}"
435+
}
436+
437+
function compatible_to_retain {
438+
local parttable=$1
439+
local image_target=$2
440+
local source_start
441+
local target_start
442+
source_start=$(
443+
tail -n 1 "${parttable}" | cut -f2 -d= | cut -f1 -d,
444+
)
445+
target_start=$(
446+
sfdisk -d "${image_target}" 2>/dev/null |\
447+
tail -n 1 | cut -f2 -d= | cut -f1 -d,
448+
)
449+
if [ -z "${source_start}" ] || [ -z "${target_start}" ];then
450+
# no partition information for either source or target
451+
# broken or net new deployment on empty disk
452+
touch /tmp/retain_not_applicable
453+
return 1
454+
fi
455+
if [ ! "${source_start}" = "${target_start}" ];then
456+
report_and_quit "Cannot retain partition, start address mismatch"
457+
fi
458+
return 0
459+
}
460+
461+
function get_disk_offset_retain_last_partition {
462+
local parttable=$1
463+
local next_to_last
464+
local start
465+
local size
466+
local offset
467+
next_to_last=$(tail -n 2 "${parttable}" | head -n 1)
468+
if [ -n "${next_to_last}" ];then
469+
start=$(echo "${next_to_last}" | cut -f2 -d= | cut -f1 -d,)
470+
size=$(echo "${next_to_last}" | cut -f3 -d= | cut -f1 -d,)
471+
offset=$((start + size))
472+
echo "${offset}"
473+
else
474+
echo 0
475+
fi
476+
}
477+
478+
function optimize_count_for_32k_blocksize {
479+
local block_size=$1
480+
local count=$2
481+
local dump_bytes
482+
dump_bytes=$((block_size * count))
483+
if [ $((dump_bytes % 32768)) -eq 0 ];then
484+
# dump_bytes is a multiple of 32k, use it for better I/O performance
485+
count=$((dump_bytes / 32768))
486+
fi
487+
echo "${count}"
488+
}
489+
365490
function dump_local_image {
366491
local image_source=$1
367492
local image_target=$2
368-
local progress=$3
493+
local count=$3
494+
local block_size=$4
495+
local progress=$5
496+
if [ "${count}" -gt 0 ];then
497+
count="count=${count}"
498+
else
499+
unset count
500+
fi
501+
# shellcheck disable=SC2086
369502
if [ -e "${progress}" ];then
370503
(
371-
pv -n "${image_source}" | dd bs=32k of="${image_target}" &>/dev/null
504+
pv -n "${image_source}" |\
505+
dd bs="${block_size}" ${count} of="${image_target}" &>/dev/null
372506
) 2>"${progress}"
373507
else
374-
dd if="${image_source}" bs=32k of="${image_target}" &>/dev/null
508+
dd \
509+
if="${image_source}" bs="${block_size}" ${count} \
510+
of="${image_target}" &>/dev/null
375511
fi
376512
}
377513

378514
function dump_remote_image {
379515
local image_source=$1
380516
local image_target=$2
381-
local progress=$3
517+
local count=$3
518+
local block_size=$4
519+
local progress=$5
382520
local image_size
383521
image_size=$((blocks * blocksize))
522+
if [ "${count}" -gt 0 ];then
523+
count="count=${count}"
524+
else
525+
unset count
526+
fi
527+
# shellcheck disable=SC2086
384528
if [ -e "${progress}" ];then
385529
(
386530
fetch_file "${image_source}" "${image_size}" |\
387-
dd bs=32k of="${image_target}" &>/dev/null
531+
dd bs="${block_size}" ${count} of="${image_target}" &>/dev/null
388532
) 2>"${progress}"
389533
else
390534
fetch_file "${image_source}" |\
391-
dd bs=32k of="${image_target}" &>/dev/null
535+
dd bs="${block_size}" ${count} of="${image_target}" &>/dev/null
392536
fi
393537
}
394538

@@ -406,6 +550,13 @@ function check_image_integrity {
406550
# no verification wanted
407551
return
408552
fi
553+
if getargbool 0 rd.kiwi.install.retain_last; then
554+
if [ ! -e /tmp/retain_not_applicable ];then
555+
# no verification possible as only a portion of
556+
# the image got deployed intentionally
557+
return
558+
fi
559+
fi
409560
if command -v pv &>/dev/null && [ "${kiwi_oemsilentverify}" = "false" ]
410561
then
411562
# verify with dialog based progress information

0 commit comments

Comments
 (0)