FAQ Search Today's Posts Mark Forums Read
» Video Reviews

» Linux Archive

Linux-archive is a website aiming to archive linux email lists and to make them easily accessible for linux users/developers.


» Sponsor

» Partners

» Sponsor

Go Back   Linux Archive > Redhat > Fedora Development

 
 
LinkBack Thread Tools
 
Old 11-30-2010, 07:09 PM
David Lehman
 
Default Add support for installing onto block device image files.

Multiple image files can be specified via "--image=/path/to/image[:name]"
on the anaconda command line. The name cannot contain colons.

Whenever disk images are specified, they automatically become the
only disks visible to anaconda, as if "ignoredisks --only-use" had
been used.

Fow now, only normal disk images are supported. Do not try to build
a fwraid or mpath in image files and expect anaconda to handle it
correctly.

Don't log to system log for disk image installs. For one thing, it adds
a huge amount of text to /var/log/messages. It also has some problem
that prevents subsequent attempts to connect to the syslog socket (from
anaconda_log.py, anyway) to fail.

Don't allow configuration of network devices during disk image installs.
Also, don't write anything in /etc/sysconfig on the host system
when doing image installs.

Don't start auditd when doing an image install.

Don't run setupTimezone if installing to disk image file(s). We don't
want to change settings on the host system.

Don't start or stop iscsi, fcoe, dasd, or zfcp during image installs.
---
anaconda | 29 +++++++-
anaconda.spec.in | 1 +
data/liveinst/liveinst | 113 +++++++++++++++++++++-----------
pyanaconda/anaconda_log.py | 5 ++
pyanaconda/flags.py | 1 +
pyanaconda/iw/congrats_gui.py | 3 +-
pyanaconda/iw/network_gui.py | 3 +-
pyanaconda/network.py | 62 ++++++++++++-------
pyanaconda/packages.py | 2 +-
pyanaconda/rescue.py | 51 +++++++++++----
pyanaconda/storage/__init__.py | 19 +++---
pyanaconda/storage/devicelibs/loop.py | 6 +-
pyanaconda/storage/devices.py | 5 +-
pyanaconda/storage/devicetree.py | 111 +++++++++++++++++++++++++++++++--
pyanaconda/storage/udev.py | 2 +-
scripts/Makefile.am | 2 +
scripts/anaconda-image-cleanup | 57 +++++++++++++++++
17 files changed, 373 insertions(+), 99 deletions(-)
create mode 100755 scripts/anaconda-image-cleanup

diff --git a/anaconda b/anaconda
index 6c37f12..2116571 100755
--- a/anaconda
+++ b/anaconda
@@ -231,6 +231,7 @@ def parseOptions(argv = None):
op.add_option("--updates", dest="updateSrc", action="store", type="string")
op.add_option("--dogtail", dest="dogtail", action="store", type="string")
op.add_option("--dlabel", action="store_true", default=False)
+ op.add_option("--image", action="append", dest="images", default=[])

# Deprecated, unloved, unused
op.add_option("-r", "--rootPath", dest="unsupportedMode",
@@ -471,6 +472,12 @@ if __name__ == "__main__":
# this handles setting up updates for pypackages to minimize the set needed
setupPythonUpdates()

+ # do this early so we can set flags before initializing logging
+ (opts, args) = parseOptions()
+ from pyanaconda.flags import flags
+ if opts.images:
+ flags.imageInstall = True
+
# Set up logging as early as possible.
import logging
from pyanaconda import anaconda_log
@@ -498,8 +505,6 @@ if __name__ == "__main__":
from pyanaconda import kickstart
import pyanaconda.storage.storage_log

- from pyanaconda.flags import flags
-
# the following makes me very sad. -- katzj
# we have a slightly different set of udev rules in the second
# stage than the first stage. why this doesn't get picked up
@@ -538,7 +543,6 @@ if __name__ == "__main__":
vncS = vnc.VncServer() # The vnc Server object.
vncS.anaconda = anaconda

- (opts, args) = parseOptions()
anaconda.opts = opts

# check memory, just the text mode for now:
@@ -606,6 +610,23 @@ if __name__ == "__main__":
(path, name) = string.split(mod, ":")
anaconda.extraModules.append((path, name))

+ image_count = 0
+ for image in opts.images:
+ image_spec = image.rsplit(":", 1)
+ path = image_spec[0]
+ if len(image_spec) == 2 and image_spec[1].strip():
+ name = image_spec[1].strip()
+ else:
+ name = os.path.splitext(os.path.basename(path))[0]
+
+ if "/" in name or name in anaconda.storage.config.diskImages.keys():
+ name = "diskimg%d" % image_count
+
+ log.info("naming disk image '%s' '%s'" % (path, name))
+ anaconda.storage.config.diskImages[name] = path
+ image_count += 1
+ flags.imageInstall = True
+
if opts.vnc:
flags.usevnc = 1
anaconda.displayMode = 'g'
@@ -642,7 +663,7 @@ if __name__ == "__main__":
anaconda.xdriver = opts.xdriver
anaconda.writeXdriver(root="/")

- if not flags.livecdInstall:
+ if not flags.livecdInstall and not flags.imageInstall:
startAuditDaemon()

# setup links required for all install types
diff --git a/anaconda.spec.in b/anaconda.spec.in
index e1a7efa..2b19f9a 100644
--- a/anaconda.spec.in
+++ b/anaconda.spec.in
@@ -216,6 +216,7 @@ update-desktop-database &> /dev/null || :
%{_libdir}/python*/site-packages/pyanaconda/*
%{_libdir}/python*/site-packages/log_picker/*
%{_libdir}/anaconda*
+%{_bindir}/anaconda-image-cleanup
%ifarch %livearches
%{_bindir}/liveinst
%{_sbindir}/liveinst
diff --git a/data/liveinst/liveinst b/data/liveinst/liveinst
index e424a62..46213a8 100755
--- a/data/liveinst/liveinst
+++ b/data/liveinst/liveinst
@@ -18,6 +18,30 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

+if [ -n "$DISPLAY" -a -n "$LANG" ]; then
+ INSTLANG="--lang $LANG"
+fi
+
+LIVE_INSTALL=0
+IMAGE_INSTALL=0
+RESCUE=0
+if [[ "$LIVECMD $*" =~ "--rescue" ]]; then
+ RESCUE=1
+fi
+
+if [ -z "$LIVECMD" ]; then
+ LIVE_INSTALL=1
+fi
+
+if [[ "$LIVECMD $*" =~ "--image" ]]; then
+ IMAGE_INSTALL=1
+fi
+
+if [[ "$LIVECMD $*" =~ "--liveinst" ]]; then
+ LIVE_INSTALL=1
+fi
+
+
if [ -z "$LIVE_BLOCK" ]; then
if [ -b "/dev/mapper/live-osimg-min" ]; then
LIVE_BLOCK="/dev/mapper/live-osimg-min"
@@ -26,16 +50,25 @@ if [ -z "$LIVE_BLOCK" ]; then
fi
fi

-if [ ! -b $LIVE_BLOCK ]; then
+if [ $LIVE_INSTALL = 1 -a ! -b $LIVE_BLOCK ]; then
zenity --error --title="Not a Live image" --text "Can't do live image installation unless running from a live image"
exit 1
fi

+# Allow running another command in the place of anaconda, but in this same
+# environment. This allows storage testing to make use of all the module
+# loading and lvm control in this file, too.
+ANACONDA=${LIVECMD:=/usr/sbin/anaconda --liveinst --method=livecd://$LIVE_BLOCK $INSTLANG}
+
# load modules that would get loaded by the loader... (#230945)
for i in raid0 raid1 raid5 raid6 raid456 raid10 dm-mod dm-zero dm-mirror dm-snapshot dm-multipath dm-round-robin vfat dm-crypt cbc sha256 lrw xts iscsi_tcp iscsi_ibft; do /sbin/modprobe $i 2>/dev/null ; done

export ANACONDA_PRODUCTNAME=$( cat /etc/system-release | sed -r -e 's/ *release.*//' )
-export ANACONDA_PRODUCTVERSION=$( cat /etc/system-release | sed -r -e 's/^.* ([0-9.]+).*$/1/' )
+if [ $LIVE_INSTALL = 1 ]; then
+ export ANACONDA_PRODUCTVERSION=$( cat /etc/system-release | sed -r -e 's/^.* ([0-9.]+).*$/1/' )
+elif [ $IMAGE_INSTALL = 1 ]; then
+ export ANACONDA_PRODUCTVERSION=$(rpmquery -q --qf '%{VERSION}' anaconda | cut -d. -f1)
+fi
export ANACONDA_BUGURL=${ANACONDA_BUGURL:="https://bugzilla.redhat.com/bugzilla/"}

RELEASE=$(rpm -q --qf '%{Release}' fedora-release)
@@ -47,15 +80,6 @@ fi

export PATH=/sbin:/usr/sbin:$PATH

-if [ -n "$DISPLAY" -a -n "$LANG" ]; then
- INSTLANG="--lang $LANG"
-fi
-
-# Allow running another command in the place of anaconda, but in this same
-# environment. This allows storage testing to make use of all the module
-# loading and lvm control in this file, too.
-ANACONDA=${LIVECMD:=/usr/sbin/anaconda --liveinst --method=livecd://$LIVE_BLOCK $INSTLANG}
-
if [ -x /usr/sbin/setenforce -a -e /selinux/enforce ]; then
current=$(cat /selinux/enforce)
/usr/sbin/setenforce 0
@@ -74,34 +98,38 @@ for opt in `cat /proc/cmdline`; do
esac
done

-# devkit-disks is now mounting lots of stuff. for now, let's just try to unmount it all
-umount /media/* 2>/dev/null
-tac /proc/mounts | grep ^/dev | grep -v live | while read dev mntpoint rest; do
- # hack - don't unmount devices the storage test code requires
- if [ "$mntpoint" = "/mnt/anactest" ]; then
- continue
- fi
-
- if [ -b $dev ]; then
- umount $mntpoint 2>/dev/null
- fi
-done
-
-/sbin/swapoff -a
-/sbin/lvm vgchange -an --ignorelockingfailure
-for i in /dev/md*; do
- if [ ! -b $i ]; then
- continue
- fi
-
- case "$i" in
- /dev/md*p*)
- ;;
- *)
- mdadm --stop $i >/dev/null 2>&1
- ;;
- esac
-done
+if [ $IMAGE_INSTALL = 0 ]; then
+ # devkit-disks is now mounting lots of stuff. for now, let's just try to
+ # unmount it all
+ umount /media/* 2>/dev/null
+ tac /proc/mounts | grep ^/dev | grep -v live |
+ while read dev mntpoint rest; do
+ # hack - don't unmount devices the storage test code requires
+ if [ "$mntpoint" = "/mnt/anactest" ]; then
+ continue
+ fi
+
+ if [ -b $dev ]; then
+ umount $mntpoint 2>/dev/null
+ fi
+ done
+
+ /sbin/swapoff -a
+ /sbin/lvm vgchange -an --ignorelockingfailure
+ for i in /dev/md*; do
+ if [ ! -b $i ]; then
+ continue
+ fi
+
+ case "$i" in
+ /dev/md*p*)
+ ;;
+ *)
+ mdadm --stop $i >/dev/null 2>&1
+ ;;
+ esac
+ done
+fi

/sbin/udevadm control --env=ANACONDA=1

@@ -113,6 +141,13 @@ else
$ANACONDA $*
fi

+# try to teardown the filesystems if this was an image install
+if [ $IMAGE_INSTALL = 1 -a $RESCUE = 0 ]; then
+ anaconda-image-cleanup
+fi
+
+rm -f /dev/.in_sysinit 2>/dev/null
+
if [ -n "$current" ]; then
/usr/sbin/setenforce $current
fi
diff --git a/pyanaconda/anaconda_log.py b/pyanaconda/anaconda_log.py
index 2f48630..c298b4e 100644
--- a/pyanaconda/anaconda_log.py
+++ b/pyanaconda/anaconda_log.py
@@ -30,6 +30,7 @@ from logging.handlers import SysLogHandler, SYSLOG_UDP_PORT
import types

import iutil
+from flags import flags

DEFAULT_TTY_LEVEL = logging.INFO
ENTRY_FORMAT = "%(asctime)s,%(msecs)03d %(levelname)s %(name)s: %(message)s"
@@ -129,6 +130,10 @@ class AnacondaLog:
def forwardToSyslog(self, logger):
"""Forward everything that goes in the logger to the syslog daemon.
"""
+ if flags.imageInstall:
+ # don't clutter up the system logs when doing an image install
+ return
+
syslogHandler = AnacondaSyslogHandler(
'/dev/log',
ANACONDA_SYSLOG_FACILITY,
diff --git a/pyanaconda/flags.py b/pyanaconda/flags.py
index 79a5e66..68a53b1 100644
--- a/pyanaconda/flags.py
+++ b/pyanaconda/flags.py
@@ -93,6 +93,7 @@ class Flags:
self.__dict__['flags']['sshd'] = 0
self.__dict__['flags']['preexisting_x11'] = False
self.__dict__['flags']['noverifyssl'] = False
+ self.__dict__['flags']['imageInstall'] = 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/iw/congrats_gui.py b/pyanaconda/iw/congrats_gui.py
index c80f2f8..e5a3af3 100644
--- a/pyanaconda/iw/congrats_gui.py
+++ b/pyanaconda/iw/congrats_gui.py
@@ -22,6 +22,7 @@ import gtk
from pyanaconda import gui
from iw_gui import *
from pyanaconda.constants import *
+from pyanaconda.flags import flags
import os
from pyanaconda import platform

@@ -45,7 +46,7 @@ class CongratulationWindow (InstallWindow):
# this mucks around a bit, but it's the weird case and it's
# better than adding a lot of complication to the normal
ics.cw.mainxml.get_widget("nextButton").hide()
- if os.path.exists(os.environ.get("LIVE_BLOCK", "/dev/mapper/live-osimg-min")):
+ if flags.livecdInstall or flags.imageInstall:
ics.cw.mainxml.get_widget("closeButton").show()
ics.cw.mainxml.get_widget("closeButton").grab_focu s()
else:
diff --git a/pyanaconda/iw/network_gui.py b/pyanaconda/iw/network_gui.py
index 9f7c40d..4f1ec17 100644
--- a/pyanaconda/iw/network_gui.py
+++ b/pyanaconda/iw/network_gui.py
@@ -26,6 +26,7 @@ from iw_gui import *
from pyanaconda import gui
from pyanaconda import network
from pyanaconda import iutil
+from pyanaconda.flags import flags
import gobject
import subprocess
import gtk
@@ -50,7 +51,7 @@ class NetworkWindow(InstallWindow):

self.netconfButton = self.xml.get_widget("netconfButton")
self.netconfButton.connect("clicked", self._setupNetwork)
- if len(self.anaconda.network.netdevices) == 0:
+ if len(self.anaconda.network.netdevices) == 0 or flags.imageInstall:
self.netconfButton.set_sensitive(False)

# pressing Enter in confirm == clicking Next
diff --git a/pyanaconda/network.py b/pyanaconda/network.py
index 8b567d5..9cad759 100644
--- a/pyanaconda/network.py
+++ b/pyanaconda/network.py
@@ -356,12 +356,14 @@ class Network:
self.setNMControlledDevices(self.netdevices.keys() )

def update(self):
-
ifcfglog.debug("Network.update() called")

self.netdevices = {}
self.ksdevice = None

+ if flags.imageInstall:
+ return
+
# populate self.netdevices
devhash = isys.getDeviceProperties(dev=None)
for iface in devhash.keys():
@@ -643,6 +645,14 @@ class Network:
return True

def copyConfigToPath(self, instPath='):
+ if flags.imageInstall and instPath:
+ # for image installs we only want to write out
+ # /etc/sysconfig/network
+ destfile = os.path.normpath(instPath + networkConfFile)
+ if not os.path.isdir(os.path.dirname(destfile)):
+ iutil.mkdirChain(os.path.dirname(destfile))
+ shutil.move("/tmp/sysconfig-network", destfile)
+ return

# /etc/sysconfig/network-scripts/ifcfg-DEVICE
# /etc/sysconfig/network-scripts/keys-DEVICE
@@ -682,29 +692,14 @@ class Network:
device.path)

def write(self):
-
ifcfglog.debug("Network.write() called")

- devices = self.netdevices.values()
-
- # /etc/sysconfig/network-scripts/ifcfg-*
- # /etc/sysconfig/network-scripts/keys-*
- for dev in devices:
-
- bootproto = dev.get('BOOTPROTO').lower()
- # write out the hostname as DHCP_HOSTNAME if given (#81613)
- if (bootproto == 'dhcp' and self.hostname and
- self.overrideDHCPhostname):
- dev.set(('DHCP_HOSTNAME', self.hostname))
-
- dev.writeIfcfgFile()
-
- if dev.wepkey:
- dev.writeWepkeyFile(dir=netscriptsDir, overwrite=False)
-
-
# /etc/sysconfig/network
- newnetwork = "%s.new" % (networkConfFile)
+ if flags.imageInstall:
+ # don't write files into host's /etc/sysconfig on image installs
+ newnetwork = "/tmp/sysconfig-network"
+ else:
+ newnetwork = "%s.new" % (networkConfFile)

f = open(newnetwork, "w")
f.write("NETWORKING=yes
")
@@ -723,7 +718,30 @@ class Network:
f.write("IPV6_DEFAULTGW=%s
" % self.ipv6_defaultgw)

f.close()
- shutil.move(newnetwork, networkConfFile)
+ if flags.imageInstall:
+ # for image installs, all we want to write out is the contents of
+ # /etc/sysconfig/network
+ ifcfglog.debug("not writing per-device configs for image install")
+ return
+ else:
+ shutil.move(newnetwork, networkConfFile)
+
+ devices = self.netdevices.values()
+
+ # /etc/sysconfig/network-scripts/ifcfg-*
+ # /etc/sysconfig/network-scripts/keys-*
+ for dev in devices:
+
+ bootproto = dev.get('BOOTPROTO').lower()
+ # write out the hostname as DHCP_HOSTNAME if given (#81613)
+ if (bootproto == 'dhcp' and self.hostname and
+ self.overrideDHCPhostname):
+ dev.set(('DHCP_HOSTNAME', self.hostname))
+
+ dev.writeIfcfgFile()
+
+ if dev.wepkey:
+ dev.writeWepkeyFile(dir=netscriptsDir, overwrite=False)

# /etc/resolv.conf is managed by NM

diff --git a/pyanaconda/packages.py b/pyanaconda/packages.py
index eb01f23..064ba17 100644
--- a/pyanaconda/packages.py
+++ b/pyanaconda/packages.py
@@ -157,7 +157,7 @@ def turnOnFilesystems(anaconda):

def setupTimezone(anaconda):
# we don't need this on an upgrade or going backwards
- if anaconda.upgrade or anaconda.dir == DISPATCH_BACK:
+ if anaconda.upgrade or flags.imageInstall or anaconda.dir == DISPATCH_BACK:
return

os.environ["TZ"] = anaconda.timezone.tz
diff --git a/pyanaconda/rescue.py b/pyanaconda/rescue.py
index 9a6b9f8..aea3c94 100644
--- a/pyanaconda/rescue.py
+++ b/pyanaconda/rescue.py
@@ -169,6 +169,9 @@ def makeFStab(instPath = ""):

# make sure they have a resolv.conf in the chroot
def makeResolvConf(instPath):
+ if flags.imageInstall:
+ return
+
if not os.access("/etc/resolv.conf", os.R_OK):
return

@@ -218,8 +221,13 @@ def runShell(screen = None, msg=""):
print
if msg:
print (msg)
- print(_("When finished please exit from the shell and your "
- "system will reboot."))
+
+ if flags.imageInstall:
+ print(_("Run anaconda-image-cleanup to unmount the system "
+ "when you are finished."))
+ else:
+ print(_("When finished please exit from the shell and your "
+ "system will reboot."))
print

proc = None
@@ -367,6 +375,13 @@ def runRescue(anaconda):
allowDirty = 1, warnDirty = 1,
readOnly = readOnly)

+ if not flags.imageInstall:
+ msg = _("The system will reboot automatically when you exit "
+ "from the shell.")
+ else:
+ msg = _("Run anaconda-image-cleanup to unmount the system "
+ "when you are finished.")
+
if rc == -1:
if anaconda.ksdata:
log.error("System had dirty file systems which you chose not to mount")
@@ -374,9 +389,8 @@ def runRescue(anaconda):
ButtonChoiceWindow(screen, _("Rescue"),
_("Your system had dirty file systems which you chose not "
"to mount. Press return to get a shell from which "
- "you can fsck and mount your partitions. The system "
- "will reboot automatically when you exit from the "
- "shell."), [_("OK")], width = 50)
+ "you can fsck and mount your partitions. %s") % msg,
+ [_("OK")], width = 50)
rootmounted = 0
else:
if anaconda.ksdata:
@@ -386,9 +400,9 @@ def runRescue(anaconda):
_("Your system has been mounted under %(rootPath)s.

"
"Press <return> to get a shell. If you would like to "
"make your system the root environment, run the command:

"
- " chroot %(rootPath)s

The system will reboot "
- "automatically when you exit from the shell.") %
- {'rootPath': anaconda.rootPath},
+ " chroot %(rootPath)s

%(msg)s") %
+ {'rootPath': anaconda.rootPath,
+ 'msg': msg},
[_("OK")] )
rootmounted = 1

@@ -416,7 +430,7 @@ def runRescue(anaconda):
log.warning("cannot touch /.autorelabel")

# set a library path to use mounted fs
- libdirs = os.environ["LD_LIBRARY_PATH"].split(":")
+ libdirs = os.environ.get("LD_LIBRARY_PATH", "").split(":")
mounted = map(lambda dir: "/mnt/sysimage%s" % dir, libdirs)
os.environ["LD_LIBRARY_PATH"] = ":".join(libdirs + mounted)

@@ -467,11 +481,18 @@ def runRescue(anaconda):
if anaconda.ksdata:
log.error("An error occurred trying to mount some or all of your system")
else:
+ if not flags.imageInstall:
+ msg = _("The system will reboot automatically when you "
+ "exit from the shell.")
+ else:
+ msg = _("Run anaconda-image-cleanup to unmount the system "
+ "when you are finished.")
+
ButtonChoiceWindow(screen, _("Rescue"),
_("An error occurred trying to mount some or all of your "
"system. Some of it may be mounted under %s.

"
- "Press <return> to get a shell. The system will reboot "
- "automatically when you exit from the shell.") % (anaconda.rootPath,),
+ "Press <return> to get a shell. %s")
+ % (anaconda.rootPath, msg),
[_("OK")] )
else:
if anaconda.ksdata and
@@ -481,10 +502,14 @@ def runRescue(anaconda):
print(_("You don't have any Linux partitions. Rebooting.
"))
sys.exit(0)
else:
+ if not flags.imageInstall:
+ msg = _(" The system will reboot automatically when you exit "
+ "from the shell.")
+ else:
+ msg = ""
ButtonChoiceWindow(screen, _("Rescue Mode"),
_("You don't have any Linux partitions. Press "
- "return to get a shell. The system will reboot "
- "automatically when you exit from the shell."),
+ "return to get a shell.%s") % msg,
[ _("OK") ], width = 50)

msgStr = ""
diff --git a/pyanaconda/storage/__init__.py b/pyanaconda/storage/__init__.py
index 29f6cc6..ae700c8 100644
--- a/pyanaconda/storage/__init__.py
+++ b/pyanaconda/storage/__init__.py
@@ -268,6 +268,7 @@ class StorageDiscoveryConfig(object):
self.reinitializeDisks = False
self.zeroMbr = None
self.protectedDevSpecs = []
+ self.diskImages = {}

def writeKS(self, f):
# clearpart
@@ -382,9 +383,10 @@ class Storage(object):
except Exception as e:
log.error("failure tearing down device tree: %s" % e)

- self.zfcp.shutdown()
+ if not flags.imageInstall:
+ self.zfcp.shutdown()

- # TODO: iscsi.shutdown()
+ # TODO: iscsi.shutdown()

def reset(self):
""" Reset storage configuration to reflect actual system state.
@@ -401,12 +403,13 @@ class Storage(object):

w = self.anaconda.intf.waitWindow(_("Examining Devices"),
_("Examining storage devices"))
- self.iscsi.startup(self.anaconda.intf)
- self.fcoe.startup(self.anaconda.intf)
- self.zfcp.startup(self.anaconda.intf)
- self.dasd.startup(self.anaconda.intf,
- self.config.exclusiveDisks,
- self.config.zeroMbr)
+ if not flags.imageInstall:
+ self.iscsi.startup(self.anaconda.intf)
+ self.fcoe.startup(self.anaconda.intf)
+ self.zfcp.startup(self.anaconda.intf)
+ self.dasd.startup(self.anaconda.intf,
+ self.config.exclusiveDisks,
+ self.config.zeroMbr)
clearPartType = self.config.clearPartType # save this before overriding it
if self.anaconda.upgrade:
self.config.clearPartType = CLEARPART_TYPE_NONE
diff --git a/pyanaconda/storage/devicelibs/loop.py b/pyanaconda/storage/devicelibs/loop.py
index 298e613..e0dc4f7 100644
--- a/pyanaconda/storage/devicelibs/loop.py
+++ b/pyanaconda/storage/devicelibs/loop.py
@@ -46,7 +46,7 @@ def losetup(args, capture=False):
stderr="/dev/tty5",
**exec_kwargs)
except RuntimeError as e:
- raise LoopError(e.message)
+ raise LoopError(str(e))

return ret

@@ -80,7 +80,7 @@ def loop_setup(path):
try:
msg = losetup(args)
except LoopError as e:
- msg = e.message
+ msg = str(e)

if msg:
raise LoopError("failed to set up loop for %s: %s" % (path, msg))
@@ -91,7 +91,7 @@ def loop_teardown(path):
try:
msg = losetup(args)
except LoopError as e:
- msg = e.message
+ msg = str(e)

if msg:
raise DeviceError("failed to tear down loop %s: %s" % (path, msg))
diff --git a/pyanaconda/storage/devices.py b/pyanaconda/storage/devices.py
index dc4d930..85bfa1e 100644
--- a/pyanaconda/storage/devices.py
+++ b/pyanaconda/storage/devices.py
@@ -1686,7 +1686,7 @@ class DMLinearDevice(DMDevice):
# information about it
self._size = self.currentSize

- def deactivate(self):
+ def deactivate(self, recursive=False):
if not self.exists:
raise DeviceError("device has not been created", self.name)

@@ -1702,6 +1702,9 @@ class DMLinearDevice(DMDevice):
dm.dm_remove(self.name)
udev_settle()

+ if recursive:
+ self.teardownParents(recursive=recursive)
+
def teardown(self, recursive=None):
""" Close, or tear down, a device. """
log_method_call(self, self.name, status=self.status)
diff --git a/pyanaconda/storage/devicetree.py b/pyanaconda/storage/devicetree.py
index 81cbc96..2981d35 100644
--- a/pyanaconda/storage/devicetree.py
+++ b/pyanaconda/storage/devicetree.py
@@ -24,6 +24,7 @@ import os
import stat
import block
import re
+import shutil

from errors import *
from devices import *
@@ -35,6 +36,7 @@ import devicelibs.mdraid
import devicelibs.dm
import devicelibs.lvm
import devicelibs.mpath
+import devicelibs.loop
from udev import *
from .storage_log import log_method_call
from pyanaconda import iutil
@@ -170,6 +172,11 @@ class DeviceTree(object):
self.iscsi = iscsi
self.dasd = dasd

+ # disk image files are automatically exclusive
+ self.diskImages = getattr(conf, "diskImages", {})
+ if self.diskImages:
+ self.exclusiveDisks = self.diskImages.keys()
+
# protected device specs as provided by the user
self.protectedDevSpecs = getattr(conf, "protectedDevSpecs", [])

@@ -527,6 +534,11 @@ class DeviceTree(object):
self.exclusiveDisks[i] = name
return False

+ # never ignore mapped disk images. if you don't want to use them,
+ # don't specify them in the first place
+ if udev_device_is_dm_anaconda(info):
+ return False
+
# We want exclusiveDisks to operate on anything that could be
# considered a directly usable disk, ie: fwraid array, mpath, or disk.
#
@@ -548,9 +560,14 @@ class DeviceTree(object):
# udev.py: enumerate_block_devices(), but we can still end up trying
# to add them to the tree when they are slaves of other devices, this
# happens for example with the livecd
- if name.startswith("loop") or name.startswith("ram"):
+ if name.startswith("ram"):
return True

+ if name.startswith("loop"):
+ # ignore loop devices unless they're backed by a disk image file
+ backing_device = devicelibs.loop.get_device_path(name)
+ return (backing_device not in self.diskImages.values())
+
# FIXME: check for virtual devices whose slaves are on the ignore list

def addUdevDMDevice(self, info):
@@ -1521,11 +1538,99 @@ class DeviceTree(object):

return ret

+ def setupDiskImages(self):
+ for (name, path) in self.diskImages.items():
+ log.info("setting up disk image file '%s' as '%s'" % (path, name))
+ try:
+ filedev = FileDevice(path, exists=True)
+ filedev.setup()
+ log.debug("%s" % filedev)
+
+ loop_name = devicelibs.loop.get_loop_name(filedev.path)
+ loop_sysfs = None
+ if loop_name:
+ loop_sysfs = "/class/block/%s" % loop_name
+ loopdev = LoopDevice(name=loop_name,
+ parents=[filedev],
+ sysfsPath=loop_sysfs,
+ exists=True)
+ loopdev.setup()
+ log.debug("%s" % loopdev)
+ dmdev = DMLinearDevice(name,
+ parents=[loopdev],
+ exists=True)
+ dmdev.setup()
+ dmdev.updateSysfsPath()
+ log.debug("%s" % dmdev)
+ except (ValueError, DeviceError) as e:
+ log.error("failed to set up disk image: %s" % e)
+ else:
+ self._addDevice(filedev)
+ self._addDevice(loopdev)
+ self._addDevice(dmdev)
+ info = udev_get_block_device(dmdev.sysfsPath)
+ self.addUdevDevice(info)
+
+ def backupConfigs(self, restore=False):
+ """ Create a backup copies of some storage config files. """
+ configs = ["/etc/mdadm.conf", "/etc/multipath.conf"]
+ for cfg in configs:
+ if restore:
+ src = cfg + ".anacbak"
+ dst = cfg
+ func = os.rename
+ op = "restore from backup"
+ else:
+ src = cfg
+ dst = cfg + ".anacbak"
+ func = shutil.copy2
+ op = "create backup copy"
+
+ if os.access(dst, os.W_OK):
+ try:
+ os.unlink(dst)
+ except OSError as e:
+ msg = str(e)
+ log.info("failed to remove %s: %s" % (dst, msg))
+
+ if os.access(src, os.W_OK):
+ # copy the config to a backup with extension ".anacbak"
+ try:
+ func(src, dst)
+ except (IOError, OSError) as e:
+ msg = str(e)
+ log.error("failed to %s of %s: %s" % (op, cfg, msg))
+ elif restore:
+ # remove the config since we created it
+ log.info("removing anaconda-created %s" % cfg)
+ try:
+ os.unlink(cfg)
+ except OSError as e:
+ msg = str(e)
+ log.error("failed to remove %s: %s" % (cfg, msg))
+ else:
+ # don't try to backup non-existent configs
+ log.info("not going to %s of non-existent %s" % (op, cfg))
+
+ def restoreConfigs(self):
+ self.backupConfigs(restore=True)
+
def populate(self):
""" Locate all storage devices. """
+ self.backupConfigs()
+ try:
+ self._populate()
+ except Exception:
+ raise
+ finally:
+ self.restoreConfigs()
+
+ def _populate(self):
log.debug("DeviceTree.populate: ignoredDisks is %s ; exclusiveDisks is %s"
% (self._ignoredDisks, self.exclusiveDisks))

+ self.setupDiskImages()
+
# mark the tree as unpopulated so exception handlers can tell the
# exception originated while finding storage devices
self.populated = False
@@ -1622,10 +1727,6 @@ class DeviceTree(object):
self._handleInconsistencies()

self.teardownAll()
- try:
- os.unlink("/etc/mdadm.conf")
- except OSError:
- log.info("failed to unlink /etc/mdadm.conf")

def teardownAll(self):
""" Run teardown methods on all devices. """
diff --git a/pyanaconda/storage/udev.py b/pyanaconda/storage/udev.py
index 1f4c3d5..9dfe37c 100644
--- a/pyanaconda/storage/udev.py
+++ b/pyanaconda/storage/udev.py
@@ -107,7 +107,7 @@ def udev_get_block_devices():

def __is_blacklisted_blockdev(dev_name):
"""Is this a blockdev we never want for an install?"""
- if dev_name.startswith("loop") or dev_name.startswith("ram") or dev_name.startswith("fd"):
+ if dev_name.startswith("ram") or dev_name.startswith("fd"):
return True

if os.path.exists("/sys/class/block/%s/device/model" %(dev_name,)):
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index 187d4c6..839567d 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -28,6 +28,8 @@ dist_noinst_SCRIPTS = getlangnames.py upd-bootimage upd-initrd upd-kernel
analogdir = $(libexecdir)/$(PACKAGE_NAME)
dist_analog_SCRIPTS = analog

+dist_bin_SCRIPTS = anaconda-image-cleanup
+
stage2scriptsdir = $(datadir)/$(PACKAGE_NAME)
dist_stage2scripts_SCRIPTS = restart-anaconda

diff --git a/scripts/anaconda-image-cleanup b/scripts/anaconda-image-cleanup
new file mode 100755
index 0000000..00f2c82
--- /dev/null
+++ b/scripts/anaconda-image-cleanup
@@ -0,0 +1,57 @@
+#!/usr/bin/python
+import os
+import sys
+
+# set the imageInstall flag so the logger won't log to the syslog
+from pyanaconda.flags import flags
+flags.imageInstall = True
+
+import pyanaconda.anaconda_log
+pyanaconda.anaconda_log.init()
+
+from pyanaconda import iutil
+
+from pyanaconda.cmdline import InstallInterface
+from pyanaconda.storage import StorageDiscoveryConfig
+from pyanaconda.storage.devicetree import DeviceTree
+from pyanaconda.storage import devicelibs
+
+intf = InstallInterface()
+storage_config = StorageDiscoveryConfig()
+
+# unmount filesystems
+for mounted in reversed(open("/proc/mounts").readlines()):
+ (device, mountpoint, rest) = mounted.split(" ", 2)
+ if not mountpoint.startswith("/mnt/sysimage"):
+ continue
+ os.system("umount %s" % mountpoint)
+
+# tear down the devices representing the disk images
+sys_class_block = "/sys/class/block"
+for dev in os.listdir(sys_class_block):
+ if not dev.startswith("dm-"):
+ continue
+
+ name = open("%s/%s/dm/name" % (sys_class_block, dev)).read().strip()
+ uuid = open("%s/%s/dm/uuid" % (sys_class_block, dev)).read().strip()
+ if not name or not uuid.startswith("ANACONDA-"):
+ continue
+
+ loop = os.listdir("%s/%s/slaves" % (sys_class_block, dev))[0].strip()
+ path = devicelibs.loop.get_device_path(loop)
+ storage_config.diskImages[name] = path
+
+if not storage_config.diskImages:
+ sys.exit(1)
+
+os.system("udevadm control --env=ANACONDA=1")
+os.system("udevadm trigger --subsystem-match block")
+os.system("udevadm settle")
+devicetree = DeviceTree(intf=intf, conf=storage_config)
+devicetree.populate()
+devicetree.teardownAll()
+for name in devicetree.diskImages.keys():
+ device = devicetree.getDeviceByName(name)
+ device.deactivate(recursive=True)
+os.system("udevadm control --env=ANACONDA=0")
+
--
1.7.3.2

_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@redhat.com
https://www.redhat.com/mailman/listinfo/anaconda-devel-list
 
Old 12-01-2010, 05:09 PM
Chris Lumens
 
Default Add support for installing onto block device image files.

> Multiple image files can be specified via "--image=/path/to/image[:name]"
> on the anaconda command line. The name cannot contain colons.

Make sure this gets documented on
https://fedoraproject.org/wiki/Anaconda/Options, at the least.

> anaconda | 29 +++++++-
> anaconda.spec.in | 1 +
> data/liveinst/liveinst | 113 +++++++++++++++++++++-----------
> pyanaconda/anaconda_log.py | 5 ++
> pyanaconda/flags.py | 1 +
> pyanaconda/iw/congrats_gui.py | 3 +-
> pyanaconda/iw/network_gui.py | 3 +-
> pyanaconda/network.py | 62 ++++++++++++-------
> pyanaconda/packages.py | 2 +-
> pyanaconda/rescue.py | 51 +++++++++++----
> pyanaconda/storage/__init__.py | 19 +++---
> pyanaconda/storage/devicelibs/loop.py | 6 +-
> pyanaconda/storage/devices.py | 5 +-
> pyanaconda/storage/devicetree.py | 111 +++++++++++++++++++++++++++++++--
> pyanaconda/storage/udev.py | 2 +-
> scripts/Makefile.am | 2 +
> scripts/anaconda-image-cleanup | 57 +++++++++++++++++
> 17 files changed, 373 insertions(+), 99 deletions(-)
> create mode 100755 scripts/anaconda-image-cleanup

I suppose if I were picky enough, I could find something to change. But
for now, I'm happy with this one going in and we can deal with any minor
bugs as they come up.

- Chris

_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@redhat.com
https://www.redhat.com/mailman/listinfo/anaconda-devel-list
 

Thread Tools




All times are GMT. The time now is 08:31 PM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.
Copyright 2007 - 2008, www.linux-archive.org