Skip to content

Commit

Permalink
Migrate the %pre-install and %post script
Browse files Browse the repository at this point in the history
  • Loading branch information
adamkankovsky committed Jul 23, 2024
1 parent 32e24a4 commit 2956709
Show file tree
Hide file tree
Showing 13 changed files with 302 additions and 70 deletions.
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ AC_CONFIG_FILES([Makefile
pyanaconda/modules/payloads/source/url/Makefile
pyanaconda/modules/runtime/Makefile
pyanaconda/modules/runtime/dracut_commands/Makefile
pyanaconda/modules/runtime/scripts/Makefile
pyanaconda/modules/runtime/user_interface/Makefile
pyanaconda/modules/storage/Makefile
pyanaconda/modules/storage/bootloader/Makefile
Expand Down
79 changes: 79 additions & 0 deletions pyanaconda/core/kickstart/scripts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#
# Commond utilities for working with scripts
#
# Copyright (C) 2024 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.
#
import os
import tempfile
from pyanaconda.core import util
from pyanaconda.core.path import open_with_perm

from pyanaconda.anaconda_loggers import get_module_logger
log = get_module_logger(__name__)

script_log = log.getChild("script")


__all__ = ["run_script"]


def run_script(script, chroot):
""" Run the kickstart script
This will write the script to a file named /tmp/ks-script- before
execution.
Output is logged by the program logger, the path specified by --log
or to /tmp/ks-script-\\*.log
# TODORV return
@param chroot directory path to chroot into before execution
"""
if script.inChroot:
scriptRoot = chroot
else:
scriptRoot = "/"

(fd, path) = tempfile.mkstemp("", "ks-script-", scriptRoot + "/tmp")

os.write(fd, script.script.encode("utf-8"))
os.close(fd)
os.chmod(path, 0o700)

# Always log stdout/stderr from scripts. Using --log just lets you
# pick where it goes. The script will also be logged to program.log
# because of execWithRedirect.
if script.logfile:
if script.inChroot:
messages = "%s/%s" % (scriptRoot, script.logfile)
else:
messages = script.logfile

d = os.path.dirname(messages)
if not os.path.exists(d):
os.makedirs(d)
else:
# Always log outside the chroot, we copy those logs into the
# chroot later.
messages = "/tmp/%s.log" % os.path.basename(path)

with open_with_perm(messages, "w", 0o600) as fp:
rc = util.execWithRedirect(script.interp, ["/tmp/%s" % os.path.basename(path)],
stdout=fp,
root=scriptRoot)

if rc != 0:
script_log.error("Error code %s running the kickstart script at line %s", rc, script.lineno)

return rc, messages
2 changes: 2 additions & 0 deletions pyanaconda/core/kickstart/specification.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ def __init__(self, specification):
for name, data in specification.addons.items():
self.registerAddonData(name, data)

self.scripts = []

def registerSectionData(self, name, data):
"""Register data used by a section."""
obj = data()
Expand Down
24 changes: 12 additions & 12 deletions pyanaconda/installation.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
CATEGORY_BOOTLOADER, CATEGORY_ENVIRONMENT, CATEGORY_STORAGE, CATEGORY_SOFTWARE
from pyanaconda.modules.boss.install_manager.installation_category_interface \
import CategoryReportTaskInterface
from pyanaconda.modules.common.constants.objects import BOOTLOADER, SNAPSHOT, FIREWALL
from pyanaconda.modules.common.constants.objects import BOOTLOADER, SNAPSHOT, FIREWALL, SCRIPTS
from pyanaconda.modules.common.constants.services import STORAGE, USERS, SERVICES, NETWORK, \
SECURITY, LOCALIZATION, TIMEZONE, BOSS, SUBSCRIPTION
SECURITY, LOCALIZATION, TIMEZONE, BOSS, SUBSCRIPTION, RUNTIME
from pyanaconda.modules.common.task import sync_run_task, Task as InstallationTask
from pyanaconda.modules.common.util import is_module_available
from pyanaconda import flags
Expand All @@ -38,7 +38,8 @@
from pyanaconda.kickstart import runPostScripts, runPreInstallScripts
from pyanaconda.kexec import setup_kexec
from pyanaconda.installation_tasks import Task, TaskQueue, DBusTask
from pykickstart.constants import SNAPSHOT_WHEN_POST_INSTALL
from pykickstart.constants import (SNAPSHOT_WHEN_POST_INSTALL, KS_SCRIPT_PREINSTALL,
KS_SCRIPT_POST)

from pyanaconda.anaconda_loggers import get_module_logger
log = get_module_logger(__name__)
Expand Down Expand Up @@ -286,11 +287,10 @@ def run_generate_initramfs():
_("Running post-installation scripts"),
CATEGORY_SYSTEM
)
post_scripts.append(Task(
"Run post installation scripts",
runPostScripts,
(ksdata.scripts,)
))
scripts_proxy = RUNTIME.get_proxy(SCRIPTS)
post_scripts.append_dbus_tasks(RUNTIME, [
scripts_proxy.RunScriptsWithTask(KS_SCRIPT_POST)
])
configuration_queue.append(post_scripts)

boss_proxy = BOSS.get_proxy()
Expand Down Expand Up @@ -376,10 +376,10 @@ def _prepare_installation(self, payload, ksdata):
_("Running pre-installation scripts"),
CATEGORY_ENVIRONMENT
)
pre_install_scripts.append(Task(
"Run %pre-install scripts",
runPreInstallScripts, (ksdata.scripts,)
))
scripts_proxy = RUNTIME.get_proxy(SCRIPTS)
pre_install_scripts.append_dbus_tasks(RUNTIME, [
scripts_proxy.RunScriptsWithTask(KS_SCRIPT_PREINSTALL)
])
installation_queue.append(pre_install_scripts)

# Do various pre-installation tasks
Expand Down
69 changes: 13 additions & 56 deletions pyanaconda/kickstart.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

from pyanaconda.anaconda_loggers import get_module_logger, get_stdout_logger
from pyanaconda.core import util
from pyanaconda.core.kickstart.scripts import run_script
from pyanaconda.core.path import open_with_perm
from pyanaconda.core.configuration.anaconda import conf
from pyanaconda.core.kickstart import VERSION, commands as COMMANDS
Expand Down Expand Up @@ -72,63 +73,19 @@ def check_kickstart_error():


class AnacondaKSScript(KSScript):
""" Execute a kickstart script
This will write the script to a file named /tmp/ks-script- before
execution.
Output is logged by the program logger, the path specified by --log
or to /tmp/ks-script-\\*.log
"""
def run(self, chroot):
""" Run the kickstart script
@param chroot directory path to chroot into before execution
"""
if self.inChroot:
scriptRoot = chroot
else:
scriptRoot = "/"

(fd, path) = tempfile.mkstemp("", "ks-script-", scriptRoot + "/tmp")

os.write(fd, self.script.encode("utf-8"))
os.close(fd)
os.chmod(path, 0o700)

# Always log stdout/stderr from scripts. Using --log just lets you
# pick where it goes. The script will also be logged to program.log
# because of execWithRedirect.
if self.logfile:
if self.inChroot:
messages = "%s/%s" % (scriptRoot, self.logfile)
else:
messages = self.logfile

d = os.path.dirname(messages)
if not os.path.exists(d):
os.makedirs(d)
else:
# Always log outside the chroot, we copy those logs into the
# chroot later.
messages = "/tmp/%s.log" % os.path.basename(path)

with open_with_perm(messages, "w", 0o600) as fp:
rc = util.execWithRedirect(self.interp, ["/tmp/%s" % os.path.basename(path)],
stdout=fp,
root=scriptRoot)

if rc != 0:
script_log.error("Error code %s running the kickstart script at line %s", rc, self.lineno)
if self.errorOnFail:
err = ""
with open(messages, "r") as fp:
err = "".join(fp.readlines())

# Show error dialog even for non-interactive
flags.ksprompt = True

errorHandler.cb(ScriptError(self.lineno, err))
util.ipmi_report(IPMI_ABORTED)
sys.exit(0)
rc, log_file = run_script(self, chroot)
if self.errorOnFail and rc != 0:
err = ""
with open(log_file, "r") as fp:
err = "".join(fp.readlines())

# Show error dialog even for non-interactive
flags.ksprompt = True

errorHandler.cb(ScriptError(self.lineno, err))
util.ipmi_report(IPMI_ABORTED)
sys.exit(0)


class AnacondaInternalScript(AnacondaKSScript):
Expand Down
7 changes: 6 additions & 1 deletion pyanaconda/modules/common/constants/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@
PARTITIONING_NAMESPACE, DEVICE_TREE_NAMESPACE, \
RHSM_NAMESPACE, RUNTIME_NAMESPACE

# Boss objects.
# Runtime objects

SCRIPTS = DBusObjectIdentifier(
namespace=RUNTIME_NAMESPACE,
basename="Scripts"
)

USER_INTERFACE = DBusObjectIdentifier(
namespace=RUNTIME_NAMESPACE,
Expand Down
2 changes: 1 addition & 1 deletion pyanaconda/modules/runtime/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

SUBDIRS = dracut_commands user_interface
SUBDIRS = dracut_commands scripts user_interface

pkgpyexecdir = $(pyexecdir)/py$(PACKAGE_NAME)
runtimedir = $(pkgpyexecdir)/modules/runtime
Expand Down
9 changes: 9 additions & 0 deletions pyanaconda/modules/runtime/kickstart.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
# License and may only be used or replicated with the express permission of
# Red Hat, Inc.
#
from pykickstart.parser import Script
from pykickstart.sections import PreInstallScriptSection, PostScriptSection

from pyanaconda.core.kickstart import KickstartSpecification, commands as COMMANDS
from pyanaconda.kickstart import AnacondaKSScript


class RuntimeKickstartSpecification(KickstartSpecification):
Expand All @@ -41,3 +45,8 @@ class RuntimeKickstartSpecification(KickstartSpecification):
"DriverDiskData": COMMANDS.DriverDiskData,
"SshPwData": COMMANDS.SshPwData,
}

sections = {
"pre-install": lambda handler: PreInstallScriptSection(handler, dataObj=AnacondaKSScript),
"post": lambda handler: PostScriptSection(handler, dataObj=AnacondaKSScript),
}
4 changes: 4 additions & 0 deletions pyanaconda/modules/runtime/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from pyanaconda.modules.runtime.runtime_interface import RuntimeInterface
from pyanaconda.modules.runtime.kickstart import RuntimeKickstartSpecification
from pyanaconda.modules.runtime.dracut_commands import DracutCommandsModule
from pyanaconda.modules.runtime.scripts import ScriptsModule
from pyanaconda.modules.runtime.user_interface import UIModule
from pyanaconda.modules.common.base import KickstartService
from pyanaconda.modules.common.constants.services import RUNTIME
Expand All @@ -51,6 +52,9 @@ def __init__(self):
self._dracut_module = DracutCommandsModule()
self._modules.add_module(self._dracut_module)

self._scripts_module = ScriptsModule()
self._modules.add_module(self._scripts_module)

self._ui_module = UIModule()
self._modules.add_module(self._ui_module)

Expand Down
21 changes: 21 additions & 0 deletions pyanaconda/modules/runtime/scripts/Makefile.am
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#
# Copyright (C) 2024 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

pkgpyexecdir = $(pyexecdir)/py$(PACKAGE_NAME)
scriptsdir = $(pkgpyexecdir)/modules/runtime/scripts
dist_scripts_DATA = $(wildcard $(srcdir)/*.py)

MAINTAINERCLEANFILES = Makefile.in
20 changes: 20 additions & 0 deletions pyanaconda/modules/runtime/scripts/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#
# Copyright (C) 2024 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.
#
from pyanaconda.modules.runtime.scripts.scripts import ScriptsModule

__all__ = ["ScriptsModule"]
Loading

0 comments on commit 2956709

Please sign in to comment.