Skip to content

Commit

Permalink
rework how configuration is scanned
Browse files Browse the repository at this point in the history
  • Loading branch information
Michal Hecko committed Aug 9, 2024
1 parent a7cb184 commit becc30f
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 114 deletions.
8 changes: 8 additions & 0 deletions etc/leapp/files/devel-livemode.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Configuration for the *experimental* livemode feature
# For the full list of configuration options, see models/livemode.py
[livemode]
squashfs_fullpath=/var/lib/leapp/live-upgrade.img
setup_network_manager=no
autostart_upgrade_after_reboot=yes
setup_opensshd_with_auth_keys=no
setup_passwordless_root=no
13 changes: 0 additions & 13 deletions etc/leapp/files/livemode.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,74 +1,22 @@
import json
import os
import os.path

from leapp.actors import Actor
from leapp.exceptions import StopActorExecutionError
from leapp.libraries.common.rpms import has_package
from leapp.libraries.stdlib import api
from leapp.models import InstalledRPM, LiveModeConfigFacts, ModelViolationError
from leapp.libraries.actor import scan_livemode_config as scan_livemode_config_lib
from leapp.models import InstalledRPM, LiveModeConfigFacts
from leapp.tags import ExperimentalTag, FactsPhaseTag, IPUWorkflowTag

LEAPP_LIVEMODE_JSON = '/etc/leapp/files/livemode.json'


class LiveModeConfig(Actor):
"""
Read /etc/leapp/files/livemode.json
Read livemode configuration located at /etc/leapp/files/devel-livemode.ini
"""

name = 'live_mode_config'
name = 'live_mode_config_scanner'
consumes = (InstalledRPM)
produces = (LiveModeConfigFacts)
tags = (ExperimentalTag, FactsPhaseTag, IPUWorkflowTag,)

def process(self):
unsupported = os.getenv('LEAPP_UNSUPPORTED', 0)
if unsupported != '1' or not os.path.exists(LEAPP_LIVEMODE_JSON):
return

api.current_logger().info(
'Loading livemode config from {}'.format(LEAPP_LIVEMODE_JSON)
)

try:
with open(LEAPP_LIVEMODE_JSON) as f:
config = json.load(f)
except ValueError as error:
raise StopActorExecutionError(
'Cannot parse live mode config',
details={'Problem': str(error)})
except OSError as error:
api.current_logger().error('Failed to read livemode configuration. Error: %s', error)
raise StopActorExecutionError(
'Cannot read live mode config',
details={'Problem': 'reading {} failed.'.format(LEAPP_LIVEMODE_JSON)})

if api.current_actor().configuration.architecture != 'x86_64':
raise StopActorExecutionError(
'Cannot operate on this architecture.',
details={'Problem': 'Live mode has been attempted on x86_64 only.'})

if not has_package(InstalledRPM, 'squashfs-tools'):
raise StopActorExecutionError(
'Cannot use mksquashfs.',
details={'Problem': 'The squashfs-tools package is mandatory for the live mode.'})

try:
api.produce(LiveModeConfigFacts(
enabled=int(config['enabled']),
url=config['url'],
squashfs=config['squashfs'],
with_cache=config['with_cache'],
temp_dir=config['temp_dir'],
dracut_network=config['dracut_network'],
nm=config['nm'],
packages=config['packages'],
autostart=int(config['autostart']),
authorized_keys=config['authorized_keys'],
strace=config['strace'])
)
except ModelViolationError as error:
raise StopActorExecutionError(
'Cannot correctly parse {}'.format(LEAPP_LIVEMODE_JSON),
details={'Problem': str(error)})
def process(self):
scan_livemode_config_lib.scan_config_and_emit_message()
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import configparser

from leapp.libraries.common.config import architecture, get_env
from leapp.libraries.common.rpms import has_package
from leapp.exceptions import StopActorExecutionError
from leapp.models import InstalledRPM, LiveModeConfigFacts, ModelViolationError
from leapp.libraries.stdlib import api


LIVEMODE_CONFIG_LOCATION = '/etc/leapp/files/devel-livemode.ini'
DEFAULT_SQUASHFS_PATH = '/var/lib/leapp/live-upgrade.img'


def scan_config_and_emit_message():
is_unsupported = get_env('LEAPP_UNSUPPORTED', '0') == '1'
is_livemode_enabled = get_env('LEAPP_DEVEL_ENABLE_LIVE_MODE', '0') == '1'

if not is_unsupported:
api.current_logger().debug('Will not scan livemode config - the upgrade is not unsuppoted.')
return

if not is_livemode_enabled:
api.current_logger().debug('Will not scan livemode config - the live mode is not enabled.')
return

if not architecture.matches_architecture(architecture.ARCH_X86_64):
api.current_logger().debug('Will not scan livemode config - livemode is currently limited to x86_64.')
return

if not has_package(InstalledRPM, 'squashfs-tools'):
# This feature is not to be used by standard users, so stopping the upgrade and providing
# the developer a speedy feedback is OK.
raise StopActorExecutionError(
'The \'squashfs-tools\' is not installed',
details={'Problem': 'The \'squashfs-tools\' is required for the live mode.'}
)

api.current_logger().info('Loading livemode config from %s', LIVEMODE_CONFIG_LOCATION)
parser = configparser.ConfigParser()

try:
parser.read(LIVEMODE_CONFIG_LOCATION)
except configparser.ParsingError as error:
api.current_logger().error('Failed to parse live mode configuration due to the following error: %s', error)

details = 'Failed to read livemode configuration due to the following error: {0}.'
raise StopActorExecutionError(
'Failed to read livemode configuration',
details={'Problem': details.format(error)}
)

livemode_section = 'livemode'
if livemode_section not in parser:
details = 'The configuration is missing the \'[{0}]\' section'.format(livemode_section)
raise StopActorExecutionError(
'Live mode configuration does not have the required structure',
details={'Problem': details}
)

config_kwargs = {
'enabled': True,
'url_to_load_squashfs_from': None,
'squashfs_fullpath': DEFAULT_SQUASHFS_PATH,
'dracut_network': None,
'setup_network_manager': False,
'additional_packages': None,
'autostart_upgrade_after_reboot': True,
'setup_opensshd_with_auth_keys': None,
'setup_passwordless_root': False,
'capture_upgrade_strace_into': None
}

config_str_options = (
'url_to_load_squashfs_from',
'squashfs_fullpath',
'dracut_network',
'additional_packages',
'setup_opensshd_with_auth_keys',
'capture_upgrade_strace_into'
)

config_bool_options = (
'setup_network_manager',
'setup_passwordless_root',
'autostart_upgrade_after_reboot',
)

livemode_config = parser[livemode_section]

for config_option in config_str_options:
if config_option in livemode_config:
config_kwargs[config_option] = livemode_config[config_option]

for config_option in config_bool_options:
if config_option in livemode_config:
config_kwargs[config_option] = livemode_config.getboolean(config_option)

try:
config = LiveModeConfigFacts(**config_kwargs)
except ModelViolationError as error:
raise StopActorExecutionError('Failed to parse livemode configuration.',
details={'Problem': str(error)})

api.produce(config)
73 changes: 30 additions & 43 deletions repos/system_upgrade/common/models/livemode.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,84 +2,71 @@
from leapp.topics import BootPrepTopic, SystemInfoTopic, TransactionTopic


class LiveModeConfigFacts(Model):
class LiveModeConfig(Model):
topic = SystemInfoTopic

"""
the LiveOS artifact is built if enabled = 1
default is 0
"""
enabled = fields.Integer()
enabled = fields.Boolean()
""" True if the live mode is enabled """

setup_passwordless_root = fields.Boolean(default=False)
""" Setup passwordless root for the live image used during the upgrade. """

url_to_load_squashfs_from = fields.Nullable(fields.String())
"""
url pointing to the squashfs image.
default is "" (booting locally)
example: "http://192.168.122.1/live-upgrade.img"
"""
url = fields.Nullable(fields.String())
Url pointing to the squashfs image.
if not set, the upgrade will boot locally
example: "http://192.168.122.1/live-upgrade.img"
"""
squashfs image storage filename (full path)
"""
squashfs = fields.Nullable(fields.String())

"""
include dnf cache into the image, default is 0
"""
with_cache = fields.Integer()
squashfs_fullpath = fields.String()
""" Path to where the squashfs image should be stored. """

dracut_network = fields.Nullable(fields.String())
"""
temporary LiveOS directory
"""
temp_dir = fields.Nullable(fields.String())
Dracut network arguments.
Required if the url_to_lead_squashfs_from is set
"""
dracut network arguments, mandatory if url is not ""
example1: "ip=dhcp"
example2: "ip=192.168.122.146::192.168.122.1:255.255.255.0:foo::none"
"""
dracut_network = fields.Nullable(fields.String())

"""
enable the NetworkManager, default is 0
"""
nm = fields.Integer()
setup_network_manager = fields.Boolean()
""" Enable the NetworkManager """

"""
list of extra packages to include in the target userspace
example: ["tcpdump", "trace-cmd"]
"""
packages = fields.List(fields.String())
additional_packages = fields.List(fields.String())
""" List of extra packages to include in the target userspace """

"""
autostart the upgrade upon reboot (or use upgrade.autostart=0 to disable)
default is 1
"""
autostart = fields.Integer()
autostart_upgrade_after_reboot = fields.Boolean()
""" Autostart the upgrade upon reboot """

setup_opensshd_with_auth_keys = fields.Nullable(fields.String())
"""
openssh-server will be installed if not null
Setup SSHD using the authorized keys file.
If empty, SSHD will not be enabled.
example: "/root/.ssh/authorized_keys"
"""
authorized_keys = fields.Nullable(fields.String())

capture_upgrade_strace_into = fields.Nullable(fields.String())
"""
strace the leapp upgrade service to this file ("" to disable)
File into which leapp upgrade service's strace output will be written.
If empty, leapp will not be run under strace.
example: "/var/lib/leapp/upgrade.strace"
"""
strace = fields.Nullable(fields.String())


class LiveModeRequirementsTasks(Model):
topic = TransactionTopic

packages = fields.List(fields.String())
"""
packages to be installed in the target userspace
"""
packages = fields.List(fields.String())


class LiveImagePreparationInfo(Model):
Expand Down

0 comments on commit becc30f

Please sign in to comment.