Skip to content

Commit

Permalink
Added new oem-resize-once element
Browse files Browse the repository at this point in the history
The new element controls the behavior of the repart/resize code
in the oem-repart dracut module. By default the repart/resize
happens on every reboot and therefore also allows for disk
geometry changes during the livetime of the machine. If the
element is set to false the repart/resize operation happens
only once and then never again. To check for this condition
a new profile environment variable kiwi_rootpartuuid which
holds the PARTUUID of the root partition has been added to
the disk builder.
  • Loading branch information
schaefi committed Mar 27, 2020
1 parent 3be0bc5 commit 94c7a7c
Show file tree
Hide file tree
Showing 22 changed files with 247 additions and 101 deletions.
4 changes: 2 additions & 2 deletions dracut/modules.d/90kiwi-repart/kiwi-repart-disk.sh
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,8 @@ mask_fsck_root_service
# initialize for disk repartition
initialize

if ! disk_has_unallocated_space "${disk}";then
# already resized or disk has not received any geometry change
# check if repart/resize is wanted
if ! resize_wanted "${root_device}" "${disk}"; then
return
fi

Expand Down
68 changes: 61 additions & 7 deletions dracut/modules.d/99kiwi-lib/kiwi-partitions-lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -311,15 +311,19 @@ function disk_has_unallocated_space {
local disk_device=$1
local pt_table_type
pt_table_type=$(get_partition_table_type "${disk_device}")
if [ "${pt_table_type}" = "dos" ];then
# we can't distinguish from 'intentional free space left'
# and the 'already resized' condition. Thus assume it's
# not fully allocated to allow for resize
true
elif [ "${pt_table_type}" = "gpt" ];then
if [ "${pt_table_type}" = "gpt" ];then
# GPT disks store a backup table at the end of the disk
# if the disk geometry changes the backup table is no
# longer at the end and this condition can be easily
# checked and used to detect that there is space
# unallocated due to a geometry change of the underlying
# block device layer
sgdisk --verify "${disk_device}" 2>&1 | grep -q "end of the disk"
else
# assume it's not fully allocated and allow for resize
# There is currently no method we could come up with
# to detect a geometry change for non GPT based disks.
# Thus we assume it's not fully allocated and allow
# for resize
true
fi
}
Expand Down Expand Up @@ -497,3 +501,53 @@ function _parted_write {
fi
_parted_init "${disk_device}"
}

function resize_wanted {
# """
# check if oem-resize-once was requested in the image
# description. If not we always try to repart/resize
# the image according to the configured constraints.
#
# If oem-resize-once is set to true we check if the
# system has been already resized compared to the
# original image PARTUUID and repart/resize the system
# only if the PARTUUID is still the original value.
# After resize a new PARTUUID will be written by the
# partitioner and that will result in the repart/resize
# operation to happen only once in the livetime of
# the image
#
# If the resize is wanted the method also checks for
# a real change in geometry on the block device layer
# and returns accordingly. Please note geometry change
# can currently only be detected on GPT disks. In any
# other case it is assumed the geometry has changed
# such that a resize can at least be tried
# """
declare kiwi_oemresizeonce=${kiwi_oemresizeonce}
declare kiwi_rootpartuuid=${kiwi_rootpartuuid}
local current_rootpart_uuid
local root_device=$1
local disk_device=$2
kiwi_oemresizeonce=$(bool "${kiwi_oemresizeonce}")
if [ "${kiwi_oemresizeonce}" = "true" ];then
current_rootpart_uuid=$(get_partition_uuid "${root_device}")
if [ "${current_rootpart_uuid}" == "${kiwi_rootpartuuid}" ];then
info "System was not yet resized"
else
info "System was already resized and oem-resize-once is requested"
info "Skipping resize operation"
return 1
fi
else
info "System resize is active on every reboot"
fi
if disk_has_unallocated_space "${disk_device}";then
info "Activating resize operation"
return 0
else
info "Disk geometry did not change"
info "Skipping resize operation"
return 1
fi
}
4 changes: 3 additions & 1 deletion kiwi/boot/image/builtin_kiwi.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ def prepare(self):
self.setup = SystemSetup(
self.boot_xml_state, self.boot_root_directory
)
self.setup.import_shell_environment(profile)
profile.create(
Defaults.get_profile_file(self.boot_root_directory)
)
self.setup.import_description()
self.setup.import_overlay_files(
follow_links=True
Expand Down
15 changes: 10 additions & 5 deletions kiwi/boot/image/dracut.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,22 +128,18 @@ def prepare(self):
"""
Prepare dracut caller environment
* Create kiwi .profile environment to be included in dracut initrd
* Setup machine_id(s) to be generic and rebuild by dracut on boot
"""
profile = Profile(self.xml_state)
defaults = Defaults()
defaults.to_profile(profile)
setup = SystemSetup(
self.xml_state, self.boot_root_directory
)
setup.import_shell_environment(profile)
setup.setup_machine_id()
self.dracut_options.append('--install')
self.dracut_options.append('/.profile')

def create_initrd(self, mbrid=None, basename=None, install_initrd=False):
"""
Create kiwi .profile environment to be included in dracut initrd.
Call dracut as chroot operation to create the initrd and move
the result into the image build target directory
Expand All @@ -153,6 +149,7 @@ def create_initrd(self, mbrid=None, basename=None, install_initrd=False):
"""
if self.is_prepared():
log.info('Creating generic dracut initrd archive')
self._create_profile_environment()
kernel_info = Kernel(self.boot_root_directory)
kernel_details = kernel_info.get_kernel(raise_on_not_found=True)
if basename:
Expand Down Expand Up @@ -222,3 +219,11 @@ def _module_available(self, module):
return True
log.warning(warn_msg.format(module))
return False

def _create_profile_environment(self):
profile = Profile(self.xml_state)
defaults = Defaults()
defaults.to_profile(profile)
profile.create(
Defaults.get_profile_file(self.boot_root_directory)
)
13 changes: 13 additions & 0 deletions kiwi/builder/disk.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,9 @@ def create_disk(self): # noqa: C901
label='SWAP'
)

# store root partition uuid for profile
self._preserve_root_partition_uuid(device_map)

# create a random image identifier
self.mbrid = SystemIdentifier()
self.mbrid.calculate_id()
Expand Down Expand Up @@ -941,6 +944,16 @@ def _add_generic_fstab_entry(
)
self.fstab.add_entry(fstab_entry)

def _preserve_root_partition_uuid(self, device_map):
block_operation = BlockID(
device_map['root'].get_device()
)
partition_uuid = block_operation.get_blkid('PARTUUID')
if partition_uuid:
self.xml_state.set_root_partition_uuid(
partition_uuid
)

def _write_image_identifier_to_system_image(self):
log.info('Creating image identifier: %s', self.mbrid.get_id())
self.mbrid.write(
Expand Down
6 changes: 6 additions & 0 deletions kiwi/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -1495,6 +1495,12 @@ def get(self, key):
if key in self.defaults:
return self.defaults[key]

def get_profile_file(root_dir):
"""
Return name of profile file for given root directory
"""
return root_dir + '/.profile'

def to_profile(self, profile):
"""
Implements method to add list of profile keys and their values
Expand Down
19 changes: 19 additions & 0 deletions kiwi/schema/kiwi.rnc
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,24 @@ div {
}
}

#==========================================
# common element <oem-resize-once>
#
div {
k.oem-resize-once.content = xsd:boolean
k.oem-resize-once.attlist = empty
k.oem-resize-once =
## For oem images: repart/resize only on first boot: true/false
## By default the repart/resize happens on every reboot and
## therefore also allows for disk geometry changes during the
## livetime of the machine. If set to false the repart/resize
## operation happens only once and then never again
element oem-resize-once {
k.oem-resize-once.attlist,
k.oem-resize-once.content
}
}

#==========================================
# common element <oem-device-filter>
#
Expand Down Expand Up @@ -2435,6 +2453,7 @@ div {
k.oemconfig.attlist &
k.oem-boot-title? &
k.oem-bootwait? &
k.oem-resize-once? &
k.oem-device-filter? &
k.oem-nic-filter? &
k.oem-inplace-recovery? &
Expand Down
27 changes: 27 additions & 0 deletions kiwi/schema/kiwi.rng
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,30 @@ of the OEM image</a:documentation>
</element>
</define>
</div>
<!--
==========================================
common element <oem-resize-once>
-->
<div>
<define name="k.oem-resize-once.content">
<data type="boolean"/>
</define>
<define name="k.oem-resize-once.attlist">
<empty/>
</define>
<define name="k.oem-resize-once">
<element name="oem-resize-once">
<a:documentation>For oem images: repart/resize only on first boot: true/false
By default the repart/resize happens on every reboot and
therefore also allows for disk geometry changes during the
livetime of the machine. If set to false the repart/resize
operation happens only once and then never again</a:documentation>
<ref name="k.oem-resize-once.attlist"/>
<ref name="k.oem-resize-once.content"/>
</element>
</define>
</div>
<!--
==========================================
common element <oem-device-filter>
Expand Down Expand Up @@ -3760,6 +3784,9 @@ and setup the system disk.</a:documentation>
<optional>
<ref name="k.oem-bootwait"/>
</optional>
<optional>
<ref name="k.oem-resize-once"/>
</optional>
<optional>
<ref name="k.oem-device-filter"/>
</optional>
Expand Down
25 changes: 20 additions & 5 deletions kiwi/system/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@
# You should have received a copy of the GNU General Public License
# along with kiwi. If not, see <http://www.gnu.org/licenses/>
#
import os
import logging
import collections
from tempfile import NamedTemporaryFile

# project
from kiwi.system.shell import Shell
from kiwi.defaults import Defaults

log = logging.getLogger('kiwi')


class Profile:
"""
Expand All @@ -47,6 +51,7 @@ def __init__(self, xml_state):
self._strip_to_profile()
self._oemconfig_to_profile()
self._drivers_to_profile()
self._root_partition_uuid_to_profile()

def add(self, key, value):
"""
Expand All @@ -61,13 +66,11 @@ def delete(self, key):
if key in self.dot_profile:
del self.dot_profile[key]

def create(self):
def create(self, filename):
"""
Create bash quoted profile
:return: profile dump for bash
:rtype: str
:param str filename: file path name
"""
sorted_profile = collections.OrderedDict(
sorted(self.dot_profile.items())
Expand All @@ -79,14 +82,19 @@ def create(self):
profile.write(
format(key) + '=' + self._format(value) + '\n'
)
return Shell.quote_key_value_file(temp_profile.name)
profile_environment = Shell.quote_key_value_file(temp_profile.name)
with open(filename, 'w') as profile:
for line in profile_environment:
profile.write(line + os.linesep)
log.debug('--> {0}'.format(line))

def _oemconfig_to_profile(self):
# kiwi_oemvmcp_parmfile
# kiwi_oemmultipath_scan
# kiwi_oemswapMB
# kiwi_oemrootMB
# kiwi_oemswap
# kiwi_oemresizeonce
# kiwi_oempartition_install
# kiwi_oemdevicefilter
# kiwi_oemtitle
Expand Down Expand Up @@ -127,6 +135,8 @@ def _oemconfig_to_profile(self):
self.dot_profile['kiwi_oemswap'] = \
self._text(False)

self.dot_profile['kiwi_oemresizeonce'] = \
self._text(oemconfig.get_oem_resize_once())
self.dot_profile['kiwi_oempartition_install'] = \
self._text(oemconfig.get_oem_partition_install())
self.dot_profile['kiwi_oemdevicefilter'] = \
Expand Down Expand Up @@ -355,6 +365,11 @@ def _image_names_to_profile(self):
if self.xml_state.get_build_type_name() == 'cpio':
self.dot_profile['kiwi_cpio_name'] = self.dot_profile['kiwi_iname']

def _root_partition_uuid_to_profile(self):
# kiwi_rootpartuuid
self.dot_profile['kiwi_rootpartuuid'] = \
self.xml_state.get_root_partition_uuid()

def _text(self, section_content):
"""
Helper method to return the text for XML elements of the
Expand Down
15 changes: 0 additions & 15 deletions kiwi/system/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,21 +151,6 @@ def import_repositories_marked_as_imageinclude(self):
repo_sourcetype
)

def import_shell_environment(self, profile):
"""
Create profile environment to let scripts consume
information from the XML description.
:param object profile: instance of :class:`Profile`
"""
profile_file = self.root_dir + '/.profile'
log.info('Creating .profile environment')
profile_environment = profile.create()
with open(profile_file, 'w') as profile:
for line in profile_environment:
profile.write(line + '\n')
log.debug('--> %s', line)

def import_cdroot_files(self, target_dir):
"""
Copy cdroot files from the image description to the
Expand Down
4 changes: 3 additions & 1 deletion kiwi/tasks/system_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,11 +218,13 @@ def process(self): # noqa: C901

defaults = Defaults()
defaults.to_profile(profile)
profile.create(
Defaults.get_profile_file(image_root)
)

setup = SystemSetup(
self.xml_state, image_root
)
setup.import_shell_environment(profile)

setup.import_description()
setup.import_overlay_files()
Expand Down
5 changes: 4 additions & 1 deletion kiwi/tasks/system_prepare.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,10 @@ def process(self): # noqa: C901
setup = SystemSetup(
self.xml_state, abs_root_path
)
setup.import_shell_environment(profile)

profile.create(
Defaults.get_profile_file(abs_root_path)
)

setup.import_description()
setup.import_overlay_files()
Expand Down
Loading

0 comments on commit 94c7a7c

Please sign in to comment.