2013-01-23 17:28:19 +00:00
|
|
|
# install.py
|
|
|
|
# Do the hard work of performing an installation.
|
|
|
|
#
|
|
|
|
# Copyright (C) 2012 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.
|
|
|
|
#
|
|
|
|
# Red Hat Author(s): Chris Lumens <clumens@redhat.com>
|
|
|
|
#
|
|
|
|
|
2015-05-30 11:20:59 +00:00
|
|
|
from blivet import callbacks
|
|
|
|
from blivet.osinstall import turnOnFilesystems
|
|
|
|
from blivet.devices import BTRFSDevice
|
2013-01-23 17:28:19 +00:00
|
|
|
from pyanaconda.bootloader import writeBootLoader
|
2015-03-23 11:36:12 +00:00
|
|
|
from pyanaconda.progress import progress_report, progress_message, progress_step, progress_complete, progress_init
|
2013-01-23 17:28:19 +00:00
|
|
|
from pyanaconda.users import createLuserConf, getPassAlgo, Users
|
|
|
|
from pyanaconda import flags
|
2015-03-23 11:36:12 +00:00
|
|
|
from pyanaconda import iutil
|
2013-01-23 17:28:19 +00:00
|
|
|
from pyanaconda import timezone
|
2015-05-30 11:20:59 +00:00
|
|
|
from pyanaconda import network
|
2014-04-07 12:38:09 +00:00
|
|
|
from pyanaconda.i18n import _
|
|
|
|
from pyanaconda.threads import threadMgr
|
2015-03-23 11:36:12 +00:00
|
|
|
from pyanaconda.ui.lib.entropy import wait_for_entropy
|
2014-04-07 12:38:09 +00:00
|
|
|
import logging
|
2015-03-23 11:36:12 +00:00
|
|
|
import blivet
|
2014-04-07 12:38:09 +00:00
|
|
|
log = logging.getLogger("anaconda")
|
2013-01-23 17:28:19 +00:00
|
|
|
|
|
|
|
def _writeKS(ksdata):
|
|
|
|
import os
|
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
path = iutil.getSysroot() + "/root/anaconda-ks.cfg"
|
2013-01-23 17:28:19 +00:00
|
|
|
|
|
|
|
# Clear out certain sensitive information that kickstart doesn't have a
|
|
|
|
# way of representing encrypted.
|
|
|
|
for obj in [ksdata.autopart] + ksdata.logvol.dataList() + \
|
|
|
|
ksdata.partition.dataList() + ksdata.raid.dataList():
|
|
|
|
obj.passphrase = ""
|
|
|
|
|
|
|
|
with open(path, "w") as f:
|
|
|
|
f.write(str(ksdata))
|
|
|
|
|
|
|
|
# Make it so only root can read - could have passwords
|
2015-03-23 11:36:12 +00:00
|
|
|
iutil.eintr_retry_call(os.chmod, path, 0o600)
|
2013-01-23 17:28:19 +00:00
|
|
|
|
|
|
|
def doConfiguration(storage, payload, ksdata, instClass):
|
|
|
|
from pyanaconda.kickstart import runPostScripts
|
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
willWriteNetwork = not flags.flags.imageInstall and not flags.flags.dirInstall
|
|
|
|
willRunRealmd = ksdata.realm.discovered
|
|
|
|
|
|
|
|
# configure base, create users, configure addons, initramfs, post-install
|
|
|
|
step_count = 5
|
|
|
|
|
|
|
|
# network, maybe
|
|
|
|
if willWriteNetwork:
|
|
|
|
step_count += 1
|
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
# if a realm was discovered,
|
|
|
|
# increment the counter as the
|
|
|
|
# real joining step will be executed
|
2015-03-23 11:36:12 +00:00
|
|
|
if willRunRealmd:
|
2014-04-07 12:38:09 +00:00
|
|
|
step_count += 1
|
2015-03-23 11:36:12 +00:00
|
|
|
|
|
|
|
progress_init(step_count)
|
2013-01-23 17:28:19 +00:00
|
|
|
|
|
|
|
# Now run the execute methods of ksdata that require an installed system
|
|
|
|
# to be present first.
|
|
|
|
with progress_report(_("Configuring installed system")):
|
|
|
|
ksdata.authconfig.execute(storage, ksdata, instClass)
|
|
|
|
ksdata.selinux.execute(storage, ksdata, instClass)
|
|
|
|
ksdata.firstboot.execute(storage, ksdata, instClass)
|
|
|
|
ksdata.services.execute(storage, ksdata, instClass)
|
|
|
|
ksdata.keyboard.execute(storage, ksdata, instClass)
|
|
|
|
ksdata.timezone.execute(storage, ksdata, instClass)
|
|
|
|
ksdata.lang.execute(storage, ksdata, instClass)
|
|
|
|
ksdata.firewall.execute(storage, ksdata, instClass)
|
|
|
|
ksdata.xconfig.execute(storage, ksdata, instClass)
|
2015-03-23 11:36:12 +00:00
|
|
|
ksdata.skipx.execute(storage, ksdata, instClass)
|
2013-01-23 17:28:19 +00:00
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
if willWriteNetwork:
|
2013-02-07 23:59:56 +00:00
|
|
|
with progress_report(_("Writing network configuration")):
|
|
|
|
ksdata.network.execute(storage, ksdata, instClass)
|
2013-01-23 17:28:19 +00:00
|
|
|
|
|
|
|
# Creating users and groups requires some pre-configuration.
|
|
|
|
with progress_report(_("Creating users")):
|
2015-03-23 11:36:12 +00:00
|
|
|
createLuserConf(iutil.getSysroot(), algoname=getPassAlgo(ksdata.authconfig.authconfig))
|
2013-01-23 17:28:19 +00:00
|
|
|
u = Users()
|
|
|
|
ksdata.rootpw.execute(storage, ksdata, instClass, u)
|
|
|
|
ksdata.group.execute(storage, ksdata, instClass, u)
|
|
|
|
ksdata.user.execute(storage, ksdata, instClass, u)
|
2015-05-30 11:20:59 +00:00
|
|
|
ksdata.sshkey.execute(storage, ksdata, instClass, u)
|
2013-01-23 17:28:19 +00:00
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
with progress_report(_("Configuring addons")):
|
|
|
|
ksdata.addons.execute(storage, ksdata, instClass, u)
|
|
|
|
|
|
|
|
with progress_report(_("Generating initramfs")):
|
2015-05-30 11:20:59 +00:00
|
|
|
payload.recreateInitrds()
|
|
|
|
|
|
|
|
# Work around rhbz#1200539, grubby doesn't handle grub2 missing initrd with /boot on btrfs
|
|
|
|
# So rerun writing the bootloader if this is live and /boot is on btrfs
|
|
|
|
boot_on_btrfs = isinstance(storage.mountpoints.get("/boot", storage.mountpoints.get("/")), BTRFSDevice)
|
|
|
|
if flags.flags.livecdInstall and boot_on_btrfs \
|
|
|
|
and (not ksdata.bootloader.disabled and ksdata.bootloader != "none"):
|
|
|
|
writeBootLoader(storage, payload, instClass, ksdata)
|
2014-04-07 12:38:09 +00:00
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
if willRunRealmd:
|
2014-04-07 12:38:09 +00:00
|
|
|
with progress_report(_("Joining realm: %s") % ksdata.realm.discovered):
|
|
|
|
ksdata.realm.execute(storage, ksdata, instClass)
|
|
|
|
|
|
|
|
with progress_report(_("Running post-installation scripts")):
|
2013-01-23 17:28:19 +00:00
|
|
|
runPostScripts(ksdata.scripts)
|
|
|
|
|
|
|
|
# Write the kickstart file to the installed system (or, copy the input
|
|
|
|
# kickstart file over if one exists).
|
|
|
|
_writeKS(ksdata)
|
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
progress_complete()
|
|
|
|
|
2013-01-23 17:28:19 +00:00
|
|
|
def doInstall(storage, payload, ksdata, instClass):
|
|
|
|
"""Perform an installation. This method takes the ksdata as prepared by
|
|
|
|
the UI (the first hub, in graphical mode) and applies it to the disk.
|
|
|
|
The two main tasks for this are putting filesystems onto disks and
|
|
|
|
installing packages onto those filesystems.
|
|
|
|
"""
|
2015-03-23 11:36:12 +00:00
|
|
|
willRunRealmd = ksdata.realm.join_realm
|
|
|
|
willInstallBootloader = not flags.flags.dirInstall and (not ksdata.bootloader.disabled
|
|
|
|
and ksdata.bootloader != "none")
|
|
|
|
|
2013-01-23 17:28:19 +00:00
|
|
|
# First save system time to HW clock.
|
|
|
|
if flags.can_touch_runtime_system("save system time to HW clock"):
|
|
|
|
timezone.save_hw_clock(ksdata.timezone)
|
|
|
|
|
|
|
|
# We really only care about actions that affect filesystems, since
|
|
|
|
# those are the ones that take the most time.
|
2015-03-23 11:36:12 +00:00
|
|
|
steps = len(storage.devicetree.findActions(action_type="create", object_type="format")) + \
|
|
|
|
len(storage.devicetree.findActions(action_type="resize", object_type="format"))
|
|
|
|
|
2015-05-30 11:20:59 +00:00
|
|
|
# Update every 10% of packages installed. We don't know how many packages
|
|
|
|
# we are installing until it's too late (see realmd later on) so this is
|
|
|
|
# the best we can do.
|
|
|
|
steps += 10
|
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
# pre setup phase, post install
|
|
|
|
steps += 2
|
|
|
|
|
|
|
|
# realmd, maybe
|
|
|
|
if willRunRealmd:
|
|
|
|
steps += 1
|
|
|
|
|
|
|
|
# bootloader, maybe
|
|
|
|
if willInstallBootloader:
|
|
|
|
steps += 1
|
2014-04-07 12:38:09 +00:00
|
|
|
|
|
|
|
# This should be the only thread running, wait for the others to finish if not.
|
|
|
|
if threadMgr.running > 1:
|
2015-03-23 11:36:12 +00:00
|
|
|
progress_init(steps+1)
|
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
with progress_report(_("Waiting for %s threads to finish") % (threadMgr.running-1)):
|
|
|
|
map(log.debug, ("Thread %s is running" % n for n in threadMgr.names))
|
|
|
|
threadMgr.wait_all()
|
2015-03-23 11:36:12 +00:00
|
|
|
else:
|
|
|
|
progress_init(steps)
|
2014-04-07 12:38:09 +00:00
|
|
|
|
|
|
|
with progress_report(_("Setting up the installation environment")):
|
|
|
|
ksdata.firstboot.setup(storage, ksdata, instClass)
|
|
|
|
ksdata.addons.setup(storage, ksdata, instClass)
|
|
|
|
|
|
|
|
storage.updateKSData() # this puts custom storage info into ksdata
|
2013-01-23 17:28:19 +00:00
|
|
|
|
|
|
|
# Do partitioning.
|
|
|
|
payload.preStorage()
|
2014-04-07 12:38:09 +00:00
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
# callbacks for blivet
|
|
|
|
message_clbk = lambda clbk_data: progress_message(clbk_data.msg)
|
|
|
|
step_clbk = lambda clbk_data: progress_step(clbk_data.msg)
|
|
|
|
entropy_wait_clbk = lambda clbk_data: wait_for_entropy(clbk_data.msg,
|
|
|
|
clbk_data.min_entropy, ksdata)
|
|
|
|
callbacks_reg = callbacks.create_new_callbacks_register(create_format_pre=message_clbk,
|
|
|
|
create_format_post=step_clbk,
|
|
|
|
resize_format_pre=message_clbk,
|
|
|
|
resize_format_post=step_clbk,
|
|
|
|
wait_for_entropy=entropy_wait_clbk)
|
|
|
|
|
|
|
|
turnOnFilesystems(storage, mountOnly=flags.flags.dirInstall, callbacks=callbacks_reg)
|
|
|
|
write_storage_late = (flags.flags.livecdInstall or ksdata.ostreesetup.seen
|
2015-05-30 11:20:59 +00:00
|
|
|
or ksdata.method.method == "liveimg")
|
|
|
|
if not write_storage_late and not flags.flags.dirInstall:
|
2013-01-23 17:28:19 +00:00
|
|
|
storage.write()
|
|
|
|
|
|
|
|
# Do packaging.
|
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
# Discover information about realms to join,
|
|
|
|
# to determine additional packages
|
2015-03-23 11:36:12 +00:00
|
|
|
if willRunRealmd:
|
2014-04-07 12:38:09 +00:00
|
|
|
with progress_report(_("Discovering realm to join")):
|
|
|
|
ksdata.realm.setup()
|
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
# Check for additional packages
|
|
|
|
ksdata.authconfig.setup()
|
|
|
|
ksdata.firewall.setup()
|
|
|
|
|
2015-05-30 11:20:59 +00:00
|
|
|
# make name resolution work for rpm scripts in chroot
|
|
|
|
if flags.can_touch_runtime_system("copy /etc/resolv.conf to sysroot"):
|
|
|
|
network.copyFileToPath("/etc/resolv.conf", iutil.getSysroot())
|
|
|
|
|
2013-01-23 17:28:19 +00:00
|
|
|
# anaconda requires storage packages in order to make sure the target
|
|
|
|
# system is bootable and configurable, and some other packages in order
|
|
|
|
# to finish setting up the system.
|
2015-03-23 11:36:12 +00:00
|
|
|
packages = storage.packages + ksdata.realm.packages
|
|
|
|
packages += ksdata.authconfig.packages + ksdata.firewall.packages
|
|
|
|
|
|
|
|
if willInstallBootloader:
|
|
|
|
packages += storage.bootloader.packages
|
2014-04-07 12:38:09 +00:00
|
|
|
|
2015-05-30 11:20:59 +00:00
|
|
|
if network.is_using_team_device():
|
|
|
|
packages.append("teamd")
|
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
# don't try to install packages from the install class' ignored list and the
|
|
|
|
# explicitly excluded ones (user takes the responsibility)
|
|
|
|
packages = [p for p in packages
|
|
|
|
if p not in instClass.ignoredPackages and p not in ksdata.packages.excludedList]
|
2014-04-07 12:38:09 +00:00
|
|
|
payload.preInstall(packages=packages, groups=payload.languageGroups())
|
2013-01-23 17:28:19 +00:00
|
|
|
payload.install()
|
|
|
|
|
2015-05-30 11:20:59 +00:00
|
|
|
if write_storage_late and not flags.flags.dirInstall:
|
2015-03-23 11:36:12 +00:00
|
|
|
if iutil.getSysroot() != iutil.getTargetPhysicalRoot():
|
|
|
|
blivet.setSysroot(iutil.getTargetPhysicalRoot(),
|
|
|
|
iutil.getSysroot())
|
|
|
|
storage.write()
|
2013-01-23 17:28:19 +00:00
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
# Now that we have the FS layout in the target, umount
|
|
|
|
# things that were in the legacy sysroot, and put them in
|
|
|
|
# the target root, except for the physical /. First,
|
|
|
|
# unmount all target filesystems.
|
|
|
|
storage.umountFilesystems()
|
|
|
|
|
|
|
|
# Explicitly mount the root on the physical sysroot
|
|
|
|
rootmnt = storage.mountpoints.get('/')
|
|
|
|
rootmnt.setup()
|
|
|
|
rootmnt.format.setup(options=rootmnt.format.options, chroot=iutil.getTargetPhysicalRoot())
|
|
|
|
|
|
|
|
payload.prepareMountTargets(storage)
|
|
|
|
|
|
|
|
# Everything else goes in the target root, including /boot
|
|
|
|
# since the bootloader code will expect to find /boot
|
|
|
|
# inside the chroot.
|
|
|
|
storage.mountFilesystems(skipRoot=True)
|
|
|
|
else:
|
|
|
|
storage.write()
|
2013-01-23 17:28:19 +00:00
|
|
|
|
|
|
|
# Do bootloader.
|
2015-03-23 11:36:12 +00:00
|
|
|
if willInstallBootloader:
|
2015-05-30 11:20:59 +00:00
|
|
|
with progress_report(_("Installing boot loader")):
|
2014-04-07 12:38:09 +00:00
|
|
|
writeBootLoader(storage, payload, instClass, ksdata)
|
2013-01-23 17:28:19 +00:00
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
with progress_report(_("Performing post-installation setup tasks")):
|
|
|
|
payload.postInstall()
|
|
|
|
|
|
|
|
progress_complete()
|