[PATCH] add syslinux and ssm
by Brian C. Lane
From: "Brian C. Lane" <bcl(a)redhat.com>
The x86 template needs syslinux to be installed.
system-storage-manager is useful in rescue mode.
---
share/runtime-install.tmpl | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/share/runtime-install.tmpl b/share/runtime-install.tmpl
index 7347fd2..e4cfebd 100644
--- a/share/runtime-install.tmpl
+++ b/share/runtime-install.tmpl
@@ -29,7 +29,7 @@ installpkg kernel
installpkg kernel-PAE gpart
%endif
%if basearch in ("i386", "x86_64"):
- installpkg grub2 grub2-tools shim grub2-efi efibootmgr biosdevname memtest86+
+ installpkg grub2 grub2-tools shim grub2-efi efibootmgr biosdevname memtest86+ syslinux
%endif
%if basearch in ("ppc", "ppc64"):
installpkg grub2 grub2-tools yaboot fbset hfsutils kernel-bootwrapper ppc64-utils
@@ -80,6 +80,7 @@ installpkg python-imaging
## filesystem tools
installpkg btrfs-progs jfsutils xfsprogs reiserfs-utils gfs2-utils ntfs-3g ntfsprogs
installpkg python-volume_key volume_key
+installpkg system-storage-manager
## SELinux support
installpkg selinux-policy-targeted audit libsemanage-python
--
1.8.1
11 years, 2 months
[PATCH] Add pigz to initrd.img
by Will Woods
Drastically speeds up compression of the initramfs for modern multicore
systems, doesn't slow anything down if you're on a single core machine
(like a virt guest), and only adds ~20kb to the image size. Good deal!
---
dracut/module-setup.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dracut/module-setup.sh b/dracut/module-setup.sh
index b9997f8..d196963 100755
--- a/dracut/module-setup.sh
+++ b/dracut/module-setup.sh
@@ -16,7 +16,7 @@ depends() {
install() {
# binaries we want in initramfs
- dracut_install eject
+ dracut_install eject -o pigz
# anaconda
inst "$moddir/anaconda-lib.sh" "/lib/anaconda-lib.sh"
inst_hook cmdline 25 "$moddir/parse-anaconda-options.sh"
--
1.8.1
11 years, 2 months
[livemedia-creator] Add filesystem image install support
by Brian C. Lane
From: "Brian C. Lane" <bcl(a)redhat.com>
This adds support for installing to a filesystem image instead of a
partitioned disk image. It requires Anaconda's --dirinstall support.
Also re-organized the code to break it up into smaller methods.
This speeds up iso creation in no-virt mode by removing the need to copy
the filesystem from the partitioned disk image to the filesystem image
that is used to make the squashfs image.
---
README.livemedia-creator | 44 ++--
src/sbin/livemedia-creator | 559 ++++++++++++++++++++++++++-------------------
2 files changed, 355 insertions(+), 248 deletions(-)
diff --git a/README.livemedia-creator b/README.livemedia-creator
index dee51b2..424bd24 100644
--- a/README.livemedia-creator
+++ b/README.livemedia-creator
@@ -2,7 +2,9 @@
INTRO
-----
livemedia-creator uses Anaconda, kickstart and Lorax to create bootable media
-such as live iso's that use the same install path as a normal system install.
+that use the same install path as a normal system install. It can be used to
+make live isos, bootable (partitioned) disk images and filesystem images for
+use with virtualization.
The general idea is to use virt-install to install into a disk image and then
use the disk image to create the bootable media.
@@ -18,12 +20,12 @@ minimum you need:
QUICKSTART
----------
sudo livemedia-creator --make-iso \
---iso=/extra/iso/Fedora-16-x86_64-netinst.iso --ks=./fedora-livemedia.ks
+--iso=/extra/iso/Fedora-18-x86_64-netinst.iso --ks=./docs/fedora-livemedia.ks
If you are using the lorax git repo you can run it like so:
sudo PATH=./src/sbin/:$PATH PYTHONPATH=./src/ ./src/sbin/livemedia-creator \
---make-iso --iso=/extra/iso/Fedora-16-x86_64-netinst.iso \
+--make-iso --iso=/extra/iso/Fedora-18-x86_64-netinst.iso \
--ks=./docs/fedora-livemedia.ks --lorax-templates=./share/
If you want to watch the install you can pass '--vnc vnc' and use a vnc
@@ -35,16 +37,17 @@ to monitor the logs for fatal errors, but may not catch everything.
HOW IT WORKS
------------
-The --make-* switches define the final output.
-
-You then need to either pass --iso and --ks in order to create a disk image
-using virt-install, or --disk-image to use a disk image from a previous run
-to create the .iso
-
-virt-install boots using the passed Anaconda installer iso and installs the
-system based on the kickstart. The %post section of the kickstart is used to
-customize the installed system in the same way that current spin-kickstarts
-do.
+There are 2 stages, the install stage which produces a disk or filesystem
+image as its output, and the boot media creation which uses the image as
+its input. Normally you would have it run both stages, but it is possible
+to have it stop after the install stage, using --image-only, or to have it
+skip the install stage and use a previously created disk image by passing
+--disk-image or --fs-image
+
+When creating an iso virt-install boots using the passed Anaconda installer iso
+and installs the system based on the kickstart. The %post section of the
+kickstart is used to customize the installed system in the same way that
+current spin-kickstarts do.
livemedia-creator monitors the install process for problems by watching the
install logs. They are written to the current directory or to the base
@@ -129,7 +132,7 @@ it as well.
ANACONDA IMAGE INSTALL
----------------------
You can create images without using virt-install by passing --no-virt on the
-cmdline. This will use Anaconda's image install feature to handle the install.
+cmdline. This will use Anaconda's directory install feature to handle the install.
There are a couple of things to keep in mind when doing this:
1. It will be most reliable when building images for the same release that the
@@ -168,10 +171,11 @@ This will produce an ami-root.img file in the working directory.
At this time I have not tested the image with EC2. Feedback would we welcome.
-APPLIANCE CREATION ------------------ livemedia-creator can now replace
-appliance-tools by using the --make-appliance switch. This will create the
-partitioned disk image and an XML file that can be used with virt-image to
-setup a virtual system.
+APPLIANCE CREATION
+------------------
+livemedia-creator can now replace appliance-tools by using the --make-appliance
+switch. This will create the partitioned disk image and an XML file that can be
+used with virt-image to setup a virtual system.
The XML is generated using the Mako template from
/usr/share/lorax/appliance/virt-image.xml You can use a different template by
@@ -218,7 +222,9 @@ disk image. Or you can pass --keep-image to keep it around after lorax is
run.
Cleaning up aborted --no-virt installs can sometimes be accomplished by running
-the anaconda-cleanup script.
+the anaconda-cleanup script. As of f18 anaconda is multi-threaded and it can
+sometimes become stuck and refuse to exit. When this happens you can usually
+clean up by first killing the anaconda process then running anaconda-cleanup.
HACKING
diff --git a/src/sbin/livemedia-creator b/src/sbin/livemedia-creator
index f80ad00..202e963 100755
--- a/src/sbin/livemedia-creator
+++ b/src/sbin/livemedia-creator
@@ -2,7 +2,7 @@
#
# Live Media Creator
#
-# Copyright (C) 2011-2012 Red Hat, Inc.
+# Copyright (C) 2011-2013 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -34,7 +34,6 @@ import threading
import SocketServer
from time import sleep
import shutil
-import traceback
import argparse
import hashlib
@@ -49,9 +48,10 @@ from mako.exceptions import text_error_template
# Use the Lorax treebuilder branch for iso creation
from pylorax.base import DataHolder
from pylorax.treebuilder import TreeBuilder, RuntimeBuilder, udev_escape
-from pylorax.sysutils import joinpaths, remove, linktree
+from pylorax.sysutils import joinpaths, remove
from pylorax.imgutils import PartitionMount, mksparse, mkext4img, loop_detach
-from pylorax.imgutils import get_loop_name, dm_detach
+from pylorax.imgutils import get_loop_name, dm_detach, mount, umount, Mount
+from pylorax.imgutils import mksquashfs
from pylorax.executils import execWithRedirect, execWithCapture
# no-virt mode doesn't need libvirt, so make it optional
@@ -64,6 +64,12 @@ except ImportError:
DRACUT_DEFAULT = ["--xz", "--add", "livenet dmsquash-live convertfs pollcdrom",
"--omit", "plymouth"]
+ROOT_PATH = "/mnt/sysimage/"
+RUNTIME = "images/install.img"
+
+class InstallError(Exception):
+ pass
+
class LogRequestHandler(SocketServer.BaseRequestHandler):
"""
@@ -184,11 +190,7 @@ class IsoMountpoint(object):
self.initrd_path = initrd_path
if not self.initrd_path:
- self.mount_dir = tempfile.mkdtemp()
- if not self.mount_dir:
- raise Exception("Error creating temporary directory")
-
- execWithRedirect("mount", ["-o", "loop", self.iso_path, self.mount_dir])
+ self.mount_dir = mount(self.iso_path, opts="loop")
else:
self.mount_dir = self.initrd_path
@@ -213,8 +215,7 @@ class IsoMountpoint(object):
def umount( self ):
if not self.initrd_path:
- execWithRedirect("umount", [self.mount_dir])
- os.rmdir( self.mount_dir )
+ umount(self.mount_dir)
def get_iso_label( self ):
"""
@@ -328,8 +329,8 @@ class VirtualInstall( object ):
Could use libvirt for this instead.
"""
log.info( "Shutting down {0}".format(self.virt_name) )
- subprocess.call(["virsh","destroy",self.virt_name])
- subprocess.call(["virsh","undefine",self.virt_name])
+ subprocess.call(["virsh", "destroy", self.virt_name])
+ subprocess.call(["virsh", "undefine", self.virt_name])
def is_image_mounted(disk_img):
"""
@@ -343,42 +344,37 @@ def is_image_mounted(disk_img):
return False
-def anaconda_install( disk_img, disk_size, kickstart, repo, args ):
+class KernelInfo(object):
"""
- disk_img Full path of the disk image
- disk_size Disk size in GB
- kickstart Full path to kickstart file
- repo URL of repository
- args Extra args to pass to anaconda --image install
+ Info about the kernels in boot_dir
"""
- import selinux
-
- # Set selinux to Permissive if it is Enforcing
- selinux_enforcing = False
- if selinux.is_selinux_enabled() and selinux.security_getenforce():
- selinux_enforcing = True
- selinux.security_setenforce(0)
-
- # Create the sparse image
- mksparse( disk_img, disk_size * 1024**3 )
-
- cmd = [ "anaconda", "--image", disk_img, "--kickstart", kickstart,
- "--cmdline", "--repo", repo_url ]
- cmd += args
-
- rc = execWithRedirect( cmd[0], cmd[1:] )
+ def __init__(self, boot_dir):
+ self.boot_dir = boot_dir
+ self.list = self.get_kernels()
+ self.arch = self.get_kernel_arch()
+ log.debug("kernel_list for {0.boot_dir} = {0.list}".format(self))
+ log.debug("kernel_arch is {0.arch}".format(self))
+
+ def get_kernels(self):
+ """
+ Get a list of the kernels in the boot_dir
- if selinux_enforcing:
- selinux.security_setenforce(1)
- return rc
+ Examine the vmlinuz-* versions and return a list of them
+ """
+ files = os.listdir(self.boot_dir)
+ return [f[8:] for f in files if f.startswith("vmlinuz-")]
+ def get_kernel_arch(self):
+ """
+ Get the arch of the first kernel in boot_dir
-def get_kernels( boot_dir ):
- """
- Examine the vmlinuz-* versions and return a list of them
- """
- files = os.listdir(boot_dir)
- return [f[8:] for f in files if f.startswith("vmlinuz-")]
+ Defaults to i386
+ """
+ if self.list:
+ kernel_arch = self.list[0].split(".")[-1]
+ else:
+ kernel_arch = "i386"
+ return kernel_arch
def make_appliance(disk_img, name, template, outfile, networks=None, ram=1024,
@@ -450,8 +446,32 @@ def make_ami( disk_img, ami_img="ami-root.img", ami_label="AMI" ):
return work_dir
-def make_livecd( disk_img, squashfs_args="", templatedir=None,
- title="Linux", project="Linux", releasever=16, isolabel=None ):
+def make_runtime(opts, mount_dir, work_dir):
+ """
+ Make the squashfs image from a directory
+
+ Result is in work_dir+RUNTIME
+ """
+ kernels = KernelInfo(joinpaths(mount_dir, "boot" ))
+
+ # Fake yum object
+ fake_yum = DataHolder(conf=DataHolder(installroot=mount_dir))
+ # Fake arch with only basearch set
+ arch = DataHolder(basearch=kernels.arch, libdir=None, buildarch=None)
+ # TODO: Need to get release info from someplace...
+ product = DataHolder(name=opts.project, version=opts.releasever, release="",
+ variant="", bugurl="", isfinal=False)
+
+ # This is a mounted image partition, cannot hardlink to it, so just use it
+ # symlink mount_dir/images to work_dir/images so we don't run out of space
+ os.makedirs(joinpaths(work_dir, "images"))
+
+ rb = RuntimeBuilder(product, arch, fake_yum)
+ log.info("Creating runtime")
+ rb.create_runtime(joinpaths(work_dir, RUNTIME), size=None)
+
+
+def make_livecd(opts, mount_dir, work_dir):
"""
Take the content from the disk image and make a livecd out of it
@@ -466,76 +486,195 @@ def make_livecd( disk_img, squashfs_args="", templatedir=None,
mounts that and then mounts LiveOS/rootfs.img as /
"""
- with PartitionMount( disk_img ) as img_mount:
- if not img_mount or not img_mount.mount_dir:
- return None
+ kernels = KernelInfo(joinpaths(mount_dir, "boot" ))
+
+ arch = DataHolder(basearch=kernels.arch, libdir=None, buildarch=None)
+ # TODO: Need to get release info from someplace...
+ product = DataHolder(name=opts.project, version=opts.releasever, release="",
+ variant="", bugurl="", isfinal=False)
+
+ # Link /images to work_dir/images to make the templates happy
+ if os.path.islink(joinpaths(mount_dir, "images")):
+ os.unlink(joinpaths(mount_dir, "images"))
+ execWithRedirect("/bin/ln", ["-s", joinpaths(work_dir, "images"),
+ joinpaths(mount_dir, "images")])
+
+ # The templates expect the config files to be in /tmp/config_files
+ # I think these should be release specific, not from lorax, but for now
+ configdir = joinpaths(opts.lorax_templates,"live/config_files/")
+ configdir_path = "tmp/config_files"
+ fullpath = joinpaths(mount_dir, configdir_path)
+ if os.path.exists(fullpath):
+ remove(fullpath)
+ shutil.copytree(configdir, fullpath)
+
+ isolabel = opts.volid or "{0.name} {0.version} {1.basearch}".format(product, arch)
+ if len(isolabel) > 32:
+ isolabel = isolabel[:32]
+ log.warn("Truncating isolabel to 32 chars: %s" % (isolabel,))
+
+ tb = TreeBuilder(product=product, arch=arch,
+ inroot=mount_dir, outroot=work_dir,
+ runtime=RUNTIME, isolabel=isolabel,
+ templatedir=joinpaths(opts.lorax_templates,"live/"))
+ log.info( "Rebuilding initrds" )
+ if not opts.dracut_args:
+ dracut_args = DRACUT_DEFAULT
+ else:
+ dracut_args = []
+ for arg in opts.dracut_args:
+ dracut_args += arg.split(" ", 1)
+ log.info("dracut args = {0}".format(dracut_args))
+ tb.rebuild_initrds(add_args=dracut_args)
+ log.info("Building boot.iso")
+ tb.build()
- kernel_list = get_kernels( joinpaths( img_mount.mount_dir, "boot" ) )
- log.debug( "kernel_list = {0}".format(kernel_list) )
- if kernel_list:
- kernel_arch = kernel_list[0].split(".")[-1]
- else:
- kernel_arch = "i386"
- log.debug( "kernel_arch = {0}".format(kernel_arch) )
+ return work_dir
- work_dir = tempfile.mkdtemp()
- log.info( "working dir is {0}".format(work_dir) )
-
- runtime = "images/install.img"
- # This is a mounted image partition, cannot hardlink to it, so just use it
- installroot = img_mount.mount_dir
- # symlink installroot/images to work_dir/images so we don't run out of space
- os.makedirs( joinpaths( work_dir, "images" ) )
-
- # TreeBuilder expects the config files to be in /tmp/config_files
- # I think these should be release specific, not from lorax, but for now
- configdir = joinpaths(templatedir,"live/config_files/")
- configdir_path = "tmp/config_files"
- fullpath = joinpaths(installroot, configdir_path)
- if os.path.exists(fullpath):
- remove(fullpath)
- shutil.copytree(configdir, fullpath)
-
- # Fake yum object
- fake_yum = DataHolder( conf=DataHolder( installroot=installroot ) )
- # Fake arch with only basearch set
- arch = DataHolder( basearch=kernel_arch, libdir=None, buildarch=None )
- # TODO: Need to get release info from someplace...
- product = DataHolder( name=project, version=releasever, release="",
- variant="", bugurl="", isfinal=False )
-
- rb = RuntimeBuilder( product, arch, fake_yum )
- log.info( "Creating runtime" )
- rb.create_runtime( joinpaths( work_dir, runtime ), size=None )
-
- # Link /images to work_dir/images to make the templates happy
- if os.path.islink( joinpaths( installroot, "images" ) ):
- os.unlink( joinpaths( installroot, "images" ) )
- execWithRedirect("/bin/ln", ["-s", joinpaths(work_dir, "images"),
- joinpaths(installroot, "images")])
-
- isolabel = isolabel or "{0.name} {0.version} {1.basearch}".format(product, arch)
- if len(isolabel) > 32:
- isolabel = isolabel[:32]
- log.error("Truncating isolabel to 32 chars: %s" % (isolabel,))
-
- tb = TreeBuilder( product=product, arch=arch,
- inroot=installroot, outroot=work_dir,
- runtime=runtime, isolabel=isolabel,
- templatedir=joinpaths(templatedir,"live/"))
- log.info( "Rebuilding initrds" )
- if not opts.dracut_args:
- dracut_args = DRACUT_DEFAULT
+
+def novirt_install(opts, disk_img, disk_size, repo_url):
+ """
+ Use Anaconda to install to a disk image
+ """
+ import selinux
+
+ # Set selinux to Permissive if it is Enforcing
+ selinux_enforcing = False
+ if selinux.is_selinux_enabled() and selinux.security_getenforce():
+ selinux_enforcing = True
+ selinux.security_setenforce(0)
+
+ cmd = ["anaconda", "--kickstart", opts.ks[0], "--cmdline", "--repo", repo_url]
+ if opts.anaconda_args:
+ for arg in opts.anaconda_args:
+ cmd += arg.split(" ", 1)
+ if opts.proxy:
+ cmd += ["--proxy", opts.proxy]
+ if opts.armplatform:
+ cmd += ["--armplatform", opts.armplatform]
+
+ if opts.make_iso or opts.make_fsimage:
+ # Make a blank fs image
+ cmd += ["--dirinstall"]
+
+ mkext4img(None, disk_img, label="Anaconda", size=disk_size * 1024**3)
+ if not os.path.isdir(ROOT_PATH):
+ os.mkdir(ROOT_PATH)
+ mount(disk_img, opts="loop", mnt=ROOT_PATH)
+ else:
+ cmd += ["--image", disk_img]
+
+ # Create the sparse image
+ mksparse( disk_img, disk_size * 1024**3 )
+
+ rc = execWithRedirect(cmd[0], cmd[1:])
+
+ # Move the anaconda logs over to a log directory
+ log_dir = os.path.abspath(os.path.dirname(opts.logfile))
+ log_anaconda = joinpaths(log_dir, "anaconda")
+ if not os.path.isdir(log_anaconda):
+ os.mkdir(log_anaconda)
+ for l in ["anaconda.log", "ifcfg.log", "program.log", "storage.log",
+ "packaging.log", "yum.log"]:
+ if os.path.exists("/tmp/"+l):
+ shutil.copy2("/tmp/"+l, log_anaconda)
+ os.unlink("/tmp/"+l)
+
+ if opts.make_iso or opts.make_fsimage:
+ umount(ROOT_PATH)
+ else:
+ # If anaconda failed the disk image may still be in use by dm
+ execWithRedirect("anaconda-cleanup", [])
+ dm_name = os.path.splitext(os.path.basename(disk_img))[0]
+ dm_path = "/dev/mapper/"+dm_name
+ if os.path.exists(dm_path):
+ dm_detach(dm_path)
+ loop_detach(get_loop_name(disk_img))
+
+ if selinux_enforcing:
+ selinux.security_setenforce(1)
+
+ if rc:
+ raise InstallError("novirt_install failed")
+
+
+def virt_install(opts, install_log, disk_img, disk_size):
+ """
+ Use virt-install to install to a disk image
+ """
+ iso_mount = IsoMountpoint(opts.iso, opts.location)
+ log_monitor = LogMonitor(install_log)
+
+ kernel_args = ""
+ if opts.kernel_args:
+ kernel_args += opts.kernel_args
+ if opts.proxy:
+ kernel_args += " proxy="+opts.proxy
+
+ virt = VirtualInstall(iso_mount, opts.ks, disk_img, disk_size,
+ kernel_args, opts.ram, opts.vnc, opts.arch,
+ log_check = log_monitor.server.log_check,
+ virtio_host = log_monitor.host,
+ virtio_port = log_monitor.port)
+ virt.destroy()
+ log_monitor.shutdown()
+ iso_mount.umount()
+
+ if log_monitor.server.log_check():
+ raise InstallError("virt_install failed")
+
+
+def make_squashfs(disk_img, work_dir, compression="xz"):
+ """
+ Take disk_img and put it into LiveOS/rootfs.img and squashfs this
+ tree into work_dir+RUNTIME
+ """
+ liveos_dir = joinpaths(work_dir, "runtime/LiveOS")
+ os.makedirs(liveos_dir)
+ os.makedirs(os.path.dirname(joinpaths(work_dir, RUNTIME)))
+ execWithRedirect("/bin/ln", [disk_img,
+ joinpaths(liveos_dir, "rootfs.img")])
+ mksquashfs(joinpaths(work_dir, "runtime"),
+ joinpaths(work_dir, RUNTIME), compression)
+ remove(joinpaths(work_dir, "runtime"))
+
+
+def make_image(opts, ks):
+ """
+ Install to an image
+
+ Use virt or anaconda to install to an image.
+
+ Returns the name of the image created.
+ """
+ disk_size = 1 + (sum([p.size for p in ks.handler.partition.partitions]) / 1024)
+ log.info("disk_size = {0}GB".format(disk_size))
+
+ repo_url = ks.handler.method.url
+
+ if opts.image_name:
+ disk_img = joinpaths(opts.tmp, opts.image_name)
+ else:
+ disk_img = tempfile.mktemp(prefix="disk", suffix=".img", dir=opts.tmp)
+ install_log = os.path.abspath(os.path.dirname(opts.logfile))+"/virt-install.log"
+
+ log.info("disk_img = {0}".format(disk_img))
+ log.info("install_log = {0}".format(install_log))
+
+ try:
+ if opts.no_virt:
+ novirt_install(opts, disk_img, disk_size, repo_url)
else:
- dracut_args = []
- for arg in opts.dracut_args:
- dracut_args += arg.split(" ", 1)
- log.info( "dracut args = {0}".format( dracut_args ) )
- tb.rebuild_initrds( add_args=dracut_args )
- log.info( "Building boot.iso" )
- tb.build()
+ virt_install(opts, install_log, disk_img, disk_size)
+ except InstallError as e:
+ log.error("Install failed: {0}".format(e))
+ if not opts.keep_image:
+ log.info("Removing bad disk image")
+ os.unlink(disk_img)
+ raise
- return work_dir
+ log.info("Disk Image install successful")
+ return disk_img
def setup_logging(opts):
@@ -574,7 +713,9 @@ if __name__ == '__main__':
action.add_argument( "--make-iso", action="store_true",
help="Build a live iso" )
action.add_argument( "--make-disk", action="store_true",
- help="Build a disk image" )
+ help="Build a partitioned disk image" )
+ action.add_argument( "--make-fsimage", action="store_true",
+ help="Build a filesystem image" )
action.add_argument( "--make-appliance", action="store_true",
help="Build an appliance image and XML description" )
action.add_argument( "--make-ami", action="store_true",
@@ -584,13 +725,15 @@ if __name__ == '__main__':
help="Anaconda installation .iso path to use for virt-install" )
parser.add_argument( "--disk-image", type=os.path.abspath,
help="Path to disk image to use for creating final image" )
+ parser.add_argument( "--fs-image", type=os.path.abspath,
+ help="Path to filesystem image to use for creating final image" )
parser.add_argument( "--ks", action="append", type=os.path.abspath,
help="Kickstart file defining the install." )
parser.add_argument( "--image-name", default=None,
- help="Name of disk image to create. Default is a random name." )
+ help="Name of fs/disk image to create. Default is a random name." )
parser.add_argument( "--image-only", action="store_true",
- help="Exit after creating disk image." )
+ help="Exit after creating fs/disk image." )
parser.add_argument( "--keep-image", action="store_true",
help="Keep raw disk image after .iso creation" )
parser.add_argument( "--no-virt", action="store_true",
@@ -692,23 +835,30 @@ if __name__ == '__main__':
log.error( "The disk image {0} is missing.".format( opts.disk_image ) )
sys.exit( 1 )
- if not opts.no_virt and not opts.iso and not opts.disk_image:
+ if opts.fs_image and not os.path.exists( opts.fs_image ):
+ log.error( "The filesystem image {0} is missing.".format( opts.fs_image ) )
+ sys.exit( 1 )
+
+ is_install = not (opts.disk_image or opts.fs_image)
+ if is_install and not opts.no_virt and not opts.iso:
log.error( "virt-install needs an install iso." )
sys.exit( 1 )
if opts.volid and len(opts.volid) > 32:
- logger.fatal("the volume id cannot be longer than 32 characters")
+ log.fatal("the volume id cannot be longer than 32 characters")
sys.exit(1)
- if not opts.no_virt and not libvirt:
+ if is_install and not opts.no_virt and not libvirt:
log.error("virt-install requires libvirt-python to be installed.")
sys.exit(1)
- if not opts.no_virt and not os.path.exists("/usr/bin/virt-install"):
+ if is_install and not opts.no_virt \
+ and not os.path.exists("/usr/bin/virt-install"):
log.error("virt-install requires python-virtinst to be installed.")
sys.exit(1)
- if opts.no_virt and not os.path.exists("/usr/sbin/anaconda"):
+ if not is_install and opts.no_virt \
+ and not os.path.exists("/usr/sbin/anaconda"):
log.error("no-virt requires anaconda to be installed.")
sys.exit(1)
@@ -721,7 +871,7 @@ if __name__ == '__main__':
"exist".format(opts.app_template))
sys.exit(1)
- if opts.image_name and os.path.exists(joinpaths(opts.tmp,opts.image_name)):
+ if opts.image_name and os.path.exists(joinpaths(opts.tmp, opts.image_name)):
log.error("The disk image to be created should not exist.")
sys.exit(1)
@@ -737,123 +887,74 @@ if __name__ == '__main__':
ks = KickstartParser( ks_version, errorsAreFatal=False, missingIncludeIsFatal=False )
ks.readKickstart( opts.ks[0] )
- # Make the disk image
- if not opts.disk_image:
+ # Make the disk or filesystem image
+ if not opts.disk_image and not opts.fs_image:
if not opts.ks:
log.error("Image creation requires a kickstart file")
sys.exit(1)
- disk_size = 1 + (sum( [p.size for p in ks.handler.partition.partitions] ) / 1024)
- log.info( "disk_size = {0}GB".format(disk_size) )
-
+ errors = []
if ks.handler.method.method != "url":
- log.error( "Only url install method is currently supported. Please "
- "fix your kickstart file." )
- sys.exit( 1 )
- repo_url = ks.handler.method.url
- if ks.handler.displaymode.displayMode is not None:
- log.error("The kickstart must not set a display mode (text, cmdline, "
- "graphical), this will interfere with livemedia-creator.")
- sys.exit(1)
+ errors.append("Only url install method is currently supported. Please "
+ "fix your kickstart file." )
- if opts.image_name:
- disk_img = joinpaths(opts.tmp, opts.image_name)
- else:
- disk_img = tempfile.mktemp( prefix="disk", suffix=".img", dir=opts.tmp )
- install_log = os.path.abspath(os.path.dirname(opts.logfile))+"/virt-install.log"
+ if ks.handler.displaymode.displayMode is not None:
+ errors.append("The kickstart must not set a display mode (text, cmdline, "
+ "graphical), this will interfere with livemedia-creator.")
- log.info( "disk_img = {0}".format(disk_img) )
- log.info( "install_log = {0}".format(install_log) )
+ if errors:
+ for e in errors:
+ log.error(e)
+ sys.exit(1)
- if opts.no_virt:
- anaconda_args = []
- if opts.anaconda_args:
- for arg in opts.anaconda_args:
- anaconda_args += arg.split(" ", 1)
- if opts.proxy:
- anaconda_args += [ "--proxy", opts.proxy ]
- if opts.armplatform:
- anaconda_args += [ "--armplatform", opts.armplatform ]
-
- # Use anaconda's image install
- install_error = anaconda_install( disk_img, disk_size, opts.ks[0],
- repo_url, anaconda_args )
-
- # Move the anaconda logs over to a log directory
- log_dir = os.path.abspath(os.path.dirname(opts.logfile))
- log_anaconda = joinpaths( log_dir, "anaconda" )
- if not os.path.isdir( log_anaconda ):
- os.mkdir( log_anaconda )
- for l in ["anaconda.log", "ifcfg.log", "program.log", "storage.log",
- "packaging.log", "yum.log"]:
- if os.path.exists( "/tmp/"+l ):
- shutil.copy2( "/tmp/"+l, log_anaconda )
- os.unlink( "/tmp/"+l )
-
- # If anaconda failed the disk image may still be in use by dm
- execWithRedirect("anaconda-cleanup", [])
- dm_name = os.path.splitext(os.path.basename(disk_img))[0]
- dm_path = "/dev/mapper/"+dm_name
- if os.path.exists(dm_path):
- dm_detach(dm_path)
- loop_detach(get_loop_name(disk_img))
+ # Make the image. Output of this is either a partitioned disk image or a fsimage
+ try:
+ disk_img = make_image(opts, ks)
+ except InstallError as e:
+ log.error("ERROR: Image creation failed: %s" % (e))
+ sys.exit(1)
- else:
- iso_mount = IsoMountpoint( opts.iso, opts.location )
- log_monitor = LogMonitor( install_log )
-
- kernel_args = ""
- if opts.kernel_args:
- kernel_args += opts.kernel_args
- if opts.proxy:
- kernel_args += " proxy="+opts.proxy
-
- virt = VirtualInstall( iso_mount, opts.ks, disk_img, disk_size,
- kernel_args, opts.ram, opts.vnc, opts.arch,
- log_check = log_monitor.server.log_check,
- virtio_host = log_monitor.host,
- virtio_port = log_monitor.port )
- virt.destroy()
- log_monitor.shutdown()
- iso_mount.umount()
-
- install_error = log_monitor.server.log_check()
-
- if install_error:
- log.error( "Install failed" )
- if not opts.keep_image:
- log.info( "Removing bad disk image" )
- os.unlink( disk_img )
- sys.exit( 1 )
- else:
- log.info( "Disk Image install successful" )
-
-
- result_dir = None
- if opts.make_iso and not opts.image_only:
- result_dir = make_livecd( opts.disk_image or disk_img, opts.squashfs_args,
- opts.lorax_templates,
- opts.title, opts.project, opts.releasever,
- opts.volid )
- # cleanup the mess
- if disk_img and not opts.keep_image and not opts.disk_image:
- os.unlink( disk_img )
- log.info("Disk image erased")
- disk_img = None
- elif opts.make_ami and not opts.image_only:
- result_dir = make_ami(opts.disk_image or disk_img)
- elif opts.make_appliance and not opts.image_only:
- if not opts.ks:
- networks = []
- else:
- networks = ks.handler.network.network
- make_appliance(opts.disk_image or disk_img, opts.app_name,
- opts.app_template, opts.app_file, networks, opts.ram,
- opts.vcpus, opts.arch, opts.title, opts.project, opts.releasever)
-
- if opts.result_dir and result_dir:
- shutil.copytree( result_dir, opts.result_dir )
- shutil.rmtree( result_dir )
+ if not opts.image_only:
+ result_dir = None
+ if opts.make_iso:
+ work_dir = tempfile.mkdtemp()
+ log.info("working dir is {0}".format(work_dir))
+
+ if (opts.fs_image or opts.no_virt) and not opts.disk_image:
+ # Create iso from a filesystem image
+ disk_img = opts.fs_image or disk_img
+
+ make_squashfs(disk_img, work_dir)
+ with Mount(disk_img, opts="loop") as mount_dir:
+ result_dir = make_livecd(opts, mount_dir, work_dir)
+ else:
+ # Create iso from a partitioned disk image
+ disk_img = opts.disk_image or disk_img
+ with PartitionMount(disk_img) as img_mount:
+ if img_mount and img_mount.mount_dir:
+ make_runtime(opts, img_mount.mount_dir, work_dir)
+ result_dir = make_livecd(opts, img_mount.mount_dir, work_dir)
+
+ # cleanup the mess
+ # cleanup work_dir?
+ if disk_img and not (opts.keep_image or opts.disk_image or opts.fs_image):
+ os.unlink(disk_img)
+ log.info("Disk image erased")
+ disk_img = None
+ elif opts.make_ami:
+ result_dir = make_ami(opts.disk_image or disk_img)
+ elif opts.make_appliance:
+ if not opts.ks:
+ networks = []
+ else:
+ networks = ks.handler.network.network
+ make_appliance(opts.disk_image or disk_img, opts.app_name,
+ opts.app_template, opts.app_file, networks, opts.ram,
+ opts.vcpus, opts.arch, opts.title, opts.project, opts.releasever)
+
+ if opts.result_dir and result_dir:
+ shutil.copytree( result_dir, opts.result_dir )
+ shutil.rmtree( result_dir )
log.info("SUMMARY")
log.info("-------")
--
1.8.1
11 years, 2 months
[PATCH] add *.relic to .gitignore
by Will Woods
...this is kind of helpful if you (like me) move stuff like 'loader' to
'loader.relic' so you can look at it later without having to switch
branches or something.
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index 754631c..6b50474 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,7 @@
.depend
.deps
.libs
+*.relic
ChangeLog
Makefile
Makefile.in
--
1.8.1
11 years, 2 months
[PATCH] networking: new nm.py using GDBus, isys.py cleanup, network.py cleanup
by Radek Vykydal
Fear not, [06/17] - [17/17] could be squashed.
This patchset:
- Removes unused code from spokes/network.py. [01]
- Removes unused code from network.py. [03]
- Moves networking code from isys to network.py. [02,04]
- Adds new module nm.py for calling NetworkManager [05]
- Replaces code for communication with NM (dbus) from network.py
with new module nm.py [06-17]
nm.py is using GDBus instead of dbus-python->libdbus which can have issues with
threads. Only _update_settings function is still using dbus-python, I need to
figure out how to construct updated GVariant settings object. The nm.py
__main__ code is a starter for tests which I haven't written (yet) because of
lack of time.
Some other selling points:
- overall +/- ratio is + only because of better documentation of nm.py
- cleaner interface with return values and exceptions documented
- better modularity - no need to import network.py just to learn whether
NM is connected
11 years, 2 months
[PATCH 1/4] Add dracut/save-initramfs.sh
by Will Woods
Since dracut dropped its slightly-too-clever trick to save a copy of
itself at /run/initramfs, we need to locate or save a copy of initramfs
so we can switch back into it and shut down properly.
So: first, check to see if we're running off media; if so, we can just
use the initramfs from the media. Easy!
Otherwise we need to save a copy. The anaconda initramfs (for current
F18-ish images on x86_64) uses about 96M RAM when unpacked, which is a
bit wasteful.
To save RAM we can filter out some stuff we don't need for shutdown:
* kernel modules: ~39M
* firmware: ~9M
* python: ~8M
* ssl certs: ~1M
* fsck binaries: ~1M
which leaves us with 38M of data. We can reduce this to 18M by gzipping
it, but that delays startup for 3s on my test system.
(Using xz would save 4.5M, but it takes 15s (!) and uses 100M RAM (!!).)
Using gzip -1 drops this to just over 1 second; RAM use goes up by 1M,
but that seems like a reasonable tradeoff.
If `pigz` is available, that gets used instead, which makes the delay
basically negligible on any modern multicore system.
---
dracut/Makefile.am | 3 ++-
dracut/module-setup.sh | 5 +++--
dracut/save-initramfs.sh | 27 +++++++++++++++++++++++++++
3 files changed, 32 insertions(+), 3 deletions(-)
create mode 100755 dracut/save-initramfs.sh
diff --git a/dracut/Makefile.am b/dracut/Makefile.am
index cb38e75..7646e23 100644
--- a/dracut/Makefile.am
+++ b/dracut/Makefile.am
@@ -38,7 +38,8 @@ dist_dracut_SCRIPTS = module-setup.sh \
fetch-kickstart-disk \
fetch-updates-disk \
parse-kickstart \
- anaconda-modprobe.sh
+ anaconda-modprobe.sh \
+ save-initramfs.sh
MAINTAINERCLEANFILES = Makefile.in
diff --git a/dracut/module-setup.sh b/dracut/module-setup.sh
index be2bd71..cdf3e4f 100755
--- a/dracut/module-setup.sh
+++ b/dracut/module-setup.sh
@@ -29,8 +29,9 @@ install() {
inst_hook initqueue/settled 00 "$moddir/anaconda-ks-sendheaders.sh"
inst_hook initqueue/online 80 "$moddir/anaconda-netroot.sh"
inst "$moddir/anaconda-diskroot" "/sbin/anaconda-diskroot"
- inst_hook pre-pivot 99 "$moddir/anaconda-copy-ks.sh"
- inst_hook pre-pivot 99 "$moddir/anaconda-copy-cmdline.sh"
+ inst_hook pre-pivot 50 "$moddir/anaconda-copy-ks.sh"
+ inst_hook pre-pivot 50 "$moddir/anaconda-copy-cmdline.sh"
+ inst_hook pre-pivot 99 "$moddir/save-initramfs.sh"
# kickstart parsing, WOOOO
inst_hook initqueue/online 10 "$moddir/fetch-kickstart-net.sh"
inst "$moddir/fetch-kickstart-disk" "/sbin/fetch-kickstart-disk"
diff --git a/dracut/save-initramfs.sh b/dracut/save-initramfs.sh
new file mode 100755
index 0000000..4ebbdfe
--- /dev/null
+++ b/dracut/save-initramfs.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# save-initramfs - save a copy of initramfs for shutdown/eject, if needed
+
+command -v config_get >/dev/null || . /lib/anaconda-lib.sh
+initramfs=""
+
+# First, check to see if we can find a copy of initramfs laying around
+for i in images/pxeboot/initrd.img ppc/ppc64/initrd.img images/initrd.img; do
+ [ -f $repodir/$i ] && initramfs=$repodir/$i && break
+done
+
+
+# If we didn't find an initramfs image, save a copy of it
+if [ -z "$initramfs" ]; then
+ initramfs=/run/initramfs/initramfs-saved.cpio.gz
+ gzip=$(type -P pigz || type -P gzip)
+ # Prune out things we don't need - modules & firmware, python, overlay file
+ find / -xdev | \
+ grep -Ev 'lib/modules|lib/firmware|python|overlay|etc/ssl|fsck' | \
+ cpio -co 2>/dev/null | $gzip -c1 > $initramfs
+fi
+
+
+# Make sure dracut-shutdown.service can find the initramfs later.
+mkdir -p $NEWROOT/boot
+ln -s $initramfs $NEWROOT/boot/initramfs-$(uname -r).img
+# NOTE: $repodir must also be somewhere under /run for this to work correctly
--
1.8.1
11 years, 2 months
[PATCH] Bring back the askmethod parameter (#889887).
by Chris Lumens
We've got this shiny new method selection UI but if you want to use it, you've
first got to sit through the delay of fetching metadata for the closest mirror
which might be completely wrong for you. Thus, this parameter will skip the
default action. Entering and leaving the source spoke will unset this
parameter.
---
anaconda | 4 ++++
dracut/parse-anaconda-options.sh | 1 -
pyanaconda/flags.py | 1 +
pyanaconda/packaging/yumpayload.py | 12 +++++++++++-
pyanaconda/ui/gui/spokes/source.py | 5 +++++
5 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/anaconda b/anaconda
index 10d1abb..fc81b91 100755
--- a/anaconda
+++ b/anaconda
@@ -234,6 +234,7 @@ def parseOptions(argv=None, cmdline=None):
op.add_option("--multilib", dest="multiLib", action="store_true", default=False)
op.add_option("-m", "--method", dest="method", default=None)
+ op.add_option("--askmethod", dest="askmethod", action="store_true", default=False)
op.add_option("--repo", dest="method", default=None)
op.add_option("--stage2", dest="stage2", default=None)
op.add_option("--noverifyssl", action="store_true", default=False)
@@ -655,6 +656,9 @@ if __name__ == "__main__":
if opts.images:
flags.imageInstall = True
+ if opts.askmethod:
+ flags.askmethod = True
+
# Set up logging as early as possible.
import logging
from pyanaconda import anaconda_log
diff --git a/dracut/parse-anaconda-options.sh b/dracut/parse-anaconda-options.sh
index 0bc7605..aa9c6b9 100755
--- a/dracut/parse-anaconda-options.sh
+++ b/dracut/parse-anaconda-options.sh
@@ -86,7 +86,6 @@ check_removed_arg ethtool
# interactive junk in initramfs
# (maybe we'll bring it back someday?)
-check_removed_arg askmethod "Use an appropriate 'inst.repo=' argument instead."
check_removed_arg asknetwork "Use an appropriate 'ip=' argument instead."
# lang & keymap
diff --git a/pyanaconda/flags.py b/pyanaconda/flags.py
index fdbd504..673822c 100644
--- a/pyanaconda/flags.py
+++ b/pyanaconda/flags.py
@@ -67,6 +67,7 @@ class Flags(object):
self.noverifyssl = False
self.imageInstall = False
self.automatedInstall = False
+ self.askmethod = False
# for non-physical consoles like some ppc and sgi altix,
# we need to preserve the console device and not try to
# do things like bogl on them. this preserves what that
diff --git a/pyanaconda/packaging/yumpayload.py b/pyanaconda/packaging/yumpayload.py
index 9fe60ad..c72b69f 100644
--- a/pyanaconda/packaging/yumpayload.py
+++ b/pyanaconda/packaging/yumpayload.py
@@ -25,7 +25,6 @@
TODO
- document all methods
- YumPayload
- - preupgrade
- write test cases
- more logging in key methods
- handling of proxy needs cleanup
@@ -416,6 +415,17 @@ reposdir=%s
# start with a fresh YumBase instance
self.reset(root=root)
+ # If askmethod was given on the command line, we don't want to do
+ # anything. Just disable all repos and return. This should avoid
+ # metadata fetching.
+ if flags.askmethod:
+ with _yum_lock:
+ for repo in self._yum.repos.repos.values():
+ self.disableRepo(repo.id)
+
+ self._yumCacheDirHack()
+ return
+
# see if we can get a usable base repo from self.data.method
try:
self._configureBaseRepo(self.storage, checkmount=checkmount)
diff --git a/pyanaconda/ui/gui/spokes/source.py b/pyanaconda/ui/gui/spokes/source.py
index 87ebb89..5751ca0 100644
--- a/pyanaconda/ui/gui/spokes/source.py
+++ b/pyanaconda/ui/gui/spokes/source.py
@@ -439,6 +439,11 @@ class SourceSpoke(NormalSpoke):
def apply(self):
import copy
+ # If askmethod was provided on the command line, entering the source
+ # spoke wipes that out.
+ if flags.askmethod:
+ flags.askmethod = False
+
old_source = copy.copy(self.data.method)
if self._autodetectButton.get_active():
--
1.7.11.2
11 years, 2 months
[PATCH] Add a new selectorFromDevice method to the accordion.
by Chris Lumens
This allows creating a new MountpointSelector using a Device as a template,
or modifying an existing MountpointSelector. It also consolidates a lot of
the specifics of doing that creation.
---
pyanaconda/ui/gui/spokes/custom.py | 69 ++++++----------------------
pyanaconda/ui/gui/spokes/lib/accordion.py | 75 ++++++++++++++++++++++++-------
2 files changed, 74 insertions(+), 70 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py
index 503ff11..70de470 100644
--- a/pyanaconda/ui/gui/spokes/custom.py
+++ b/pyanaconda/ui/gui/spokes/custom.py
@@ -22,8 +22,6 @@
# TODO:
# - Add a way for users to specify the names of subvols.
-# - We should either remove boot disk selection from the cart we show from here
-# or re-partition when it gets changed to make a best-effort at keeping up.
# - Deleting an LV is not reflected in available space in the bottom left.
# - this is only true for preexisting LVs
# - Device descriptions, suggested sizes, etc. should be moved out into a support file.
@@ -532,24 +530,6 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
fsCombo.append_text(obj.name)
self._fs_types.append(obj.name)
- def _mountpointName(self, mountpoint):
- # If there's a mount point, apply a kind of lame scheme to it to figure
- # out what the name should be. Basically, just look for the last directory
- # in the mount point's path and capitalize the first letter. So "/boot"
- # becomes "Boot", and "/usr/local" becomes "Local".
- if mountpoint == "/":
- return "Root"
- elif mountpoint != None:
- try:
- lastSlash = mountpoint.rindex("/")
- except ValueError:
- # No slash in the mount point? I suppose that's possible.
- return None
-
- return mountpoint[lastSlash+1:].capitalize()
- else:
- return None
-
@property
def _clearpartDevices(self):
return [d for d in self._devices if d.name in self.data.clearpart.drives and d.partitioned]
@@ -742,8 +722,8 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
(root.name != self.translated_new_install_name and not device.format.exists):
continue
- selector = page.addDevice(self._mountpointName(mountpoint) or device.format.name, Size(spec="%f MB" % device.size), mountpoint, self.on_selector_clicked)
- selector._device = device
+ selector = page.addSelector(device, self.on_selector_clicked,
+ mountpoint=mountpoint)
selector._root = root
for device in root.swaps:
@@ -751,10 +731,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
(root.name != self.translated_new_install_name and not device.format.exists):
continue
- selector = page.addDevice("Swap",
- Size(spec="%f MB" % device.size),
- None, self.on_selector_clicked)
- selector._device = device
+ selector = page.addSelector(device, self.on_selector_clicked)
selector._root = root
page.show_all()
@@ -769,8 +746,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
page.pageTitle = _("Unknown")
for u in sorted(self.unusedDevices, key=lambda d: d.name):
- selector = page.addDevice(u.name, Size(spec="%f MB" % u.size), u.format.name, self.on_selector_clicked)
- selector._device = u
+ page.addSelector(u, self.on_selector_clicked)
page.show_all()
self._accordion.addPage(page, cb=self.on_page_clicked)
@@ -836,16 +812,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
devices.extend(self.bootLoaderDevices)
for _device in devices:
- mountpoint = getattr(_device.format, "mountpoint", "") or ""
-
- if _device.format.type == "swap":
- name = "Swap"
- else:
- name = self._mountpointName(mountpoint) or _device.format.name
-
- selector = page.addDevice(name, Size(spec="%f MB" % _device.size),
- mountpoint, self.on_selector_clicked)
- selector._device = _device
+ page.addSelector(_device, self.on_selector_clicked)
page.show_all()
@@ -858,7 +825,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
for selector in page._members:
if selector._device.type.startswith("btrfs"):
- selector.props.size = str(Size(spec="%f MB" % selector._device.size)).upper()
+ selectorFromDevice(selector._device, selector=selector)
def _replace_device(self, *args, **kwargs):
""" Create a replacement device and update the device selector. """
@@ -872,8 +839,8 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
max_id = max([d.id for d in self._devices])
# update the selector with the new device and its size
- selector._device = self.__storage.devicetree.getDeviceByID(max_id)
- selector.props.size = str(Size(spec="%f MB" % selector._device.size)).upper()
+ selectorFromDevice(self.__storage.devicetree.getDeviceByID(max_id),
+ selector=selector)
def _save_right_side(self, selector):
""" Save settings from RHS and apply changes to the device.
@@ -1120,10 +1087,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
# you can't change the type of an existing device, so we
# don't need to concern ourselves with adding a new
# selector to the new page
- selector.props.mountpoint = (mountpoint or
- selector._device.format.name)
- selector.props.name = (self._mountpointName(mountpoint) or
- selector._device.format.name)
+ selectorFromDevice(device, selector=selector)
self._devices = self.__storage.devices
# update size props of all btrfs devices' selectors
@@ -1188,7 +1152,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
log.debug("updating selector size to '%s'"
% str(Size(spec="%f MB" % device.size)).upper())
# update the selector's size property
- selector.props.size = str(Size(spec="%f MB" % device.size)).upper()
+ selectorFromDevice(device, selector=selector)
# update size props of all btrfs devices' selectors
self._update_btrfs_selectors()
@@ -1292,10 +1256,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
# either update the existing selector or add a new one
if new_selector:
- new_selector.props.mountpoint = mountpoint or ""
- new_selector.props.name = (self._mountpointName(mountpoint)
- or device.format.name)
- new_selector._device = device
+ selectorFromDevice(device, selector=new_selector)
else:
self.add_new_selector(device)
@@ -1315,9 +1276,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
log.debug("updating mountpoint to %s" % mountpoint)
device.format.mountpoint = mountpoint
if old_mountpoint:
- selector.props.mountpoint = mountpoint
- selector.props.name = (self._mountpointName(mountpoint)
- or selector._device.format.name)
+ selectorFromDevice(device, selector=selector)
else:
# add an entry to the new page but do not remove any entries
# from other pages since we haven't altered the filesystem
@@ -1433,7 +1392,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
# We want to preserve the state of the customize expander so that it's
# open should you open it and then look at some other device instead.
- expander.set_expanded(selector.customizeIsOpen)
+ expander.set_expanded(selector._customizeIsOpen)
device = selector._device
if device.type == "luks/dm-crypt":
@@ -1673,7 +1632,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
if not self._current_selector:
return
- self._current_selector.customizeIsOpen = not self._current_selector.customizeIsOpen
+ self._current_selector._customizeIsOpen = not self._current_selector._customizeIsOpen
def on_add_clicked(self, button):
self._save_right_side(self._current_selector)
diff --git a/pyanaconda/ui/gui/spokes/lib/accordion.py b/pyanaconda/ui/gui/spokes/lib/accordion.py
index adb6e4a..aab6712 100644
--- a/pyanaconda/ui/gui/spokes/lib/accordion.py
+++ b/pyanaconda/ui/gui/spokes/lib/accordion.py
@@ -23,18 +23,73 @@
import gettext
_ = lambda x: gettext.ldgettext("anaconda", x)
+from blivet.size import Size
+
from pyanaconda.product import productName, productVersion
from gi.repository.AnacondaWidgets import MountpointSelector
from gi.repository import Gtk
__all__ = ["DATA_DEVICE", "SYSTEM_DEVICE",
+ "selectorFromDevice",
"Accordion",
"Page", "UnknownPage", "CreateNewPage"]
DATA_DEVICE = 0
SYSTEM_DEVICE = 1
+def mountpointName(mountpoint):
+ # If there's a mount point, apply a kind of lame scheme to it to figure
+ # out what the name should be. Basically, just look for the last directory
+ # in the mount point's path and capitalize the first letter. So "/boot"
+ # becomes "Boot", and "/usr/local" becomes "Local".
+ if mountpoint == "/":
+ return "Root"
+ elif mountpoint != None:
+ try:
+ lastSlash = mountpoint.rindex("/")
+ except ValueError:
+ # No slash in the mount point? I suppose that's possible.
+ return None
+
+ return mountpoint[lastSlash+1:].capitalize()
+ else:
+ return None
+
+def selectorFromDevice(device, selector=None, mountpoint=""):
+ """Create a MountpointSelector from a Device object template. This
+ method should be used whenever constructing a new selector, or when
+ setting a bunch of attributes on an existing selector. For just
+ changing the name or size, it's probably fine to do it by hand.
+
+ This method returns the selector created.
+
+ If given a selector parameter, attributes will be set on that object
+ instead of creating a new one. The optional mountpoint parameter
+ allows for specifying the mountpoint if it cannot be determined from
+ the device (like for a Root specifying an existing installation).
+ """
+ mp = mountpoint or getattr(device.format, "mountpoint", "")
+
+ if device.format.type == "swap":
+ name = "Swap"
+ else:
+ name = mountpointName(mp) or device.format.name
+
+ size = Size(spec="%f MB" % device.size)
+
+ if not selector:
+ selector = MountpointSelector(name, str(size).upper(), mp)
+ selector._root = None
+ selector._customizeIsOpen = False
+ else:
+ selector.props.name = name
+ selector.props.size = str(size).upper()
+ selector.props.mountpoint = mp
+
+ selector._device = device
+ return selector
+
# An Accordion is a box that goes on the left side of the custom partitioning spoke. It
# stores multiple expanders which are here called Pages. These Pages correspond to
# individual installed OSes on the system plus some special ones. When one Page is
@@ -146,18 +201,13 @@ class Page(Gtk.Box):
label.set_margin_left(24)
return label
- def addDevice(self, name, size, mountpoint, cb):
- selector = MountpointSelector(name, str(size).upper(), mountpoint or "")
+ def addSelector(self, device, cb, mountpoint=""):
+ selector = selectorFromDevice(device, mountpoint=mountpoint)
selector.connect("button-press-event", self._onSelectorClicked, cb)
selector.connect("key-release-event", self._onSelectorClicked, cb)
- #selector.connect("focus-in-event", self._onSelectorClicked, cb)
self._members.append(selector)
- selector._device = None
- selector._root = None
- selector.customizeIsOpen = False
-
- if self._mountpointType(mountpoint) == DATA_DEVICE:
+ if self._mountpointType(selector.props.mountpoint) == DATA_DEVICE:
self._dataBox.add(selector)
else:
self._systemBox.add(selector)
@@ -203,15 +253,10 @@ class UnknownPage(Page):
self._members = []
self.pageTitle = ""
- def addDevice(self, name, size, mountpoint, cb):
- selector = MountpointSelector(name, str(size).upper(), mountpoint or "")
+ def addSelector(self, device, cb, mountpoint=""):
+ selector = selectorFromDevice(device, mountpoint=mountpoint)
selector.connect("button-press-event", self._onSelectorClicked, cb)
selector.connect("key-release-event", self._onSelectorClicked, cb)
- #selector.connect("focus-in-event", self._onSelectorClicked, cb)
-
- selector._device = None
- selector._root = None
- selector.customizeIsOpen = False
self._members.append(selector)
self.add(selector)
--
1.7.11.2
11 years, 2 months
[blivet] housekeeping patches
by David Lehman
Move the code for top-down-specified device creation/management into its
own module, clean up and add comments to the trickier pieces of the
factory code, and update some strings from "storage" to "blivet".
11 years, 2 months