[Lorax] move image-minimizer to lorax (#1082642)
Brian C. Lane
bcl at redhat.com
Tue Apr 1 00:08:03 UTC 2014
This is used as a kickstart %post interpreter to streamline
modifications to images.
Also adds an example kickstart.
This obsoletes the old appliance-tools-minimizer and includes a Provide
so that the transition will be seamless.
---
docs/fedora-minimized.ks | 104 +++++++++++++++++++++++++
lorax.spec | 4 +
setup.py | 1 +
src/bin/image-minimizer | 198 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 307 insertions(+)
create mode 100644 docs/fedora-minimized.ks
create mode 100755 src/bin/image-minimizer
diff --git a/docs/fedora-minimized.ks b/docs/fedora-minimized.ks
new file mode 100644
index 0000000..ac97017
--- /dev/null
+++ b/docs/fedora-minimized.ks
@@ -0,0 +1,104 @@
+# Minimal Disk Image -- Example of image-minimizer usage in %post
+#
+sshpw --username=root --plaintext randOmStrinGhERE
+# Firewall configuration
+firewall --enabled
+# Use network installation
+url --url="http://dl.fedoraproject.org/pub/fedora/linux/development/20/x86_64/os/"
+
+# Root password
+rootpw --plaintext removethispw
+# Network information
+network --bootproto=dhcp --onboot=on --activate
+# System authorization information
+auth --useshadow --enablemd5
+# System keyboard
+keyboard --xlayouts=us --vckeymap=us
+# System language
+lang en_US.UTF-8
+# SELinux configuration
+selinux --enforcing
+# Installation logging level
+logging --level=info
+# Shutdown after installation
+shutdown
+# System timezone
+timezone US/Eastern
+# System bootloader configuration
+bootloader --location=mbr
+# Clear the Master Boot Record
+zerombr
+# Partition clearing information
+clearpart --all
+# Disk partitioning information
+part / --fstype="ext4" --size=4000
+part swap --size=1000
+
+%post
+# Remove root password
+passwd -d root > /dev/null
+%end
+
+%packages
+ at core
+kernel
+memtest86+
+grub2-efi
+grub2
+shim
+syslinux
+-dracut-config-rescue
+%end
+
+#
+# Use the image-minimizer to remove some packages and dirs
+#
+%post --interpreter=image-minimizer --nochroot
+
+
+# Kernel modules minimization
+# Drop many filesystems
+drop /lib/modules/*/kernel/fs
+keep /lib/modules/*/kernel/fs/ext*
+keep /lib/modules/*/kernel/fs/mbcache*
+keep /lib/modules/*/kernel/fs/squashfs
+keep /lib/modules/*/kernel/fs/jbd*
+keep /lib/modules/*/kernel/fs/btrfs
+keep /lib/modules/*/kernel/fs/cifs*
+keep /lib/modules/*/kernel/fs/fat
+keep /lib/modules/*/kernel/fs/nfs
+keep /lib/modules/*/kernel/fs/nfs_common
+keep /lib/modules/*/kernel/fs/fscache
+keep /lib/modules/*/kernel/fs/lockd
+keep /lib/modules/*/kernel/fs/nls/nls_utf8.ko
+keep /lib/modules/*/kernel/fs/configfs/configfs.ko
+keep /lib/modules/*/kernel/fs/fuse
+keep /lib/modules/*/kernel/fs/isofs
+# No sound
+drop /lib/modules/*/kernel/sound
+
+
+# Drop some unused rpms, without dropping dependencies
+droprpm checkpolicy
+droprpm dmraid-events
+droprpm gamin
+droprpm gnupg2
+droprpm linux-atm-libs
+droprpm make
+droprpm mtools
+droprpm mysql-libs
+droprpm perl
+droprpm perl-Module-Pluggable
+droprpm perl-Net-Telnet
+droprpm perl-PathTools
+droprpm perl-Pod-Escapes
+droprpm perl-Pod-Simple
+droprpm perl-Scalar-List-Utils
+droprpm perl-hivex
+droprpm perl-macros
+droprpm sgpio
+droprpm syslinux
+droprpm system-config-firewall-base
+droprpm usermode
+
+%end
diff --git a/lorax.spec b/lorax.spec
index 1adfd63..7b7e665 100644
--- a/lorax.spec
+++ b/lorax.spec
@@ -60,6 +60,9 @@ Requires: grub2-tools
Requires: openssh
%endif
+# Moved image-minimizer tool to lorax
+Provides: appliance-tools-minimizer
+
%description
Lorax is a tool for creating the anaconda install images.
@@ -85,6 +88,7 @@ make DESTDIR=$RPM_BUILD_ROOT mandir=%{_mandir} install
%{_sbindir}/lorax
%{_sbindir}/mkefiboot
%{_sbindir}/livemedia-creator
+%{_bindir}/image-minimizer
%dir %{_sysconfdir}/lorax
%config(noreplace) %{_sysconfdir}/lorax/lorax.conf
%dir %{_datadir}/lorax
diff --git a/setup.py b/setup.py
index 4d5b543..5d38b5b 100644
--- a/setup.py
+++ b/setup.py
@@ -18,6 +18,7 @@ for root, dnames, fnames in os.walk("share"):
# executable
data_files.append(("/usr/sbin", ["src/sbin/lorax", "src/sbin/mkefiboot",
"src/sbin/livemedia-creator"]))
+data_files.append(("/usr/bin", ["src/bin/image-minimizer"]))
# get the version
sys.path.insert(0, "src")
diff --git a/src/bin/image-minimizer b/src/bin/image-minimizer
new file mode 100755
index 0000000..e613556
--- /dev/null
+++ b/src/bin/image-minimizer
@@ -0,0 +1,198 @@
+#!/usr/bin/python
+#
+# image-minimizer: removes files and packages on the filesystem
+#
+# Copyright 2007-2010 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
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+import glob
+import optparse
+import os
+import shutil
+import sys
+import rpm
+
+class ImageMinimizer:
+ filename = ''
+ dryrun = False
+ verbose = False
+ prefix = None
+ drops = set()
+ visited = set()
+ drops_rpm = set()
+ ts = None
+
+ def __init__(self, filename, root, dryrun, verbose):
+ self.filename = filename
+ self.prefix = root
+ self.dryrun = dryrun
+ self.verbose = verbose
+ self.ts = None
+
+ # Recursively adds all files and directories.
+ # This is done becuase globbing does not allow
+ # ** for arbitrary nesting.
+ def add_directory(self, files, dirname):
+ self.visited.add(dirname)
+ for root, dirs, items in os.walk(dirname):
+ for dir in dirs:
+ self.visited.add(os.path.join(root, dir))
+ for name in items:
+ files.add(os.path.join(root, name))
+
+ def add_pattern(self, files, pattern):
+ globs = glob.glob(pattern)
+ if self.verbose and len(globs) == 0:
+ print "%s file not found" % pattern
+ for g in globs:
+ if os.path.isdir(g):
+ self.add_directory(files, g)
+ else:
+ files.add(g)
+
+ def add_pattern_rpm(self, rpms, pattern):
+ if self.ts is None:
+ if self.prefix is None:
+ raise Exception ('Must specify installation root for droprpm/keeprpm')
+ self.ts = rpm.TransactionSet(self.prefix)
+ mi = self.ts.dbMatch()
+ mi.pattern('name', rpm.RPMMIRE_GLOB, pattern)
+ not_found = True
+ for hdr in mi:
+ not_found = False
+ rpms.add(hdr['name'])
+ if self.verbose and not_found:
+ print "%s package not found" % pattern
+
+ # Parses each line in the ifle
+ def parse_line(self, line):
+ command = ""
+ pattern = ""
+ tok = line.split(None,1)
+ if len(tok) > 0:
+ command = tok[0].lower()
+ if len(tok) > 1:
+ pattern = tok[1].strip()
+
+ # Strip out all the comments and blank lines
+ if not (command.startswith('#') or command==''):
+ if command == 'keep':
+ if self.prefix is not None :
+ pattern = pattern.lstrip('/')
+ pattern = os.path.join(self.prefix, pattern)
+ keeps = set()
+ self.add_pattern(keeps, pattern)
+ self.drops.difference_update(keeps)
+ keeps = None
+ elif command == 'drop':
+ if self.prefix is not None :
+ pattern = pattern.lstrip('/')
+ pattern = os.path.join(self.prefix, pattern)
+ self.add_pattern(self.drops, pattern)
+ elif command == 'keeprpm':
+ keeps_rpm = set()
+ self.add_pattern_rpm(keeps_rpm, pattern)
+ self.drops_rpm.difference_update(keeps_rpm)
+ keeps_rpm = None
+ elif command == 'droprpm':
+ self.add_pattern_rpm(self.drops_rpm, pattern)
+ else:
+ raise Exception ('Unknown Command: ' + command)
+
+ def remove(self):
+ for tag in sorted(self.drops, reverse=True):
+ self.visited.add(os.path.split(tag)[0])
+ if os.path.isdir(tag):
+ self.visited.add(tag)
+ else:
+ if self.dryrun:
+ print 'rm ' + tag
+ else:
+ if self.verbose:
+ print 'rm ' + tag
+ os.remove(tag)
+
+ #remove all empty directory. Every 8k counts!
+ for dir in sorted(self.visited, reverse=True):
+ if len(os.listdir(dir)) == 0:
+ if self.dryrun:
+ print 'rm -rf ' + dir
+ else:
+ if self.verbose:
+ print 'rm -rf ' + dir
+ os.rmdir(dir)
+
+ def remove_rpm(self):
+
+ def runCallback(reason, amount, total, key, client_data):
+ if self.verbose and reason == rpm.RPMCALLBACK_UNINST_STOP:
+ print key, "erased"
+
+ if len(self.drops_rpm) == 0:
+ return
+
+ for pkg in self.drops_rpm:
+ if self.dryrun:
+ print "erasing ", pkg
+ else:
+ self.ts.addErase(pkg)
+ if not self.dryrun:
+ # skip ts.check(), equivalent to --nodeps
+ self.ts.run(runCallback, "erase")
+
+ def filter(self):
+ for line in (open(self.filename).readlines()):
+ self.parse_line(line.strip())
+ self.remove()
+ self.remove_rpm()
+
+
+def parse_options():
+ usage = "usage: %prog [options] filename"
+ parser = optparse.OptionParser(usage=usage)
+
+ parser.set_defaults(root=os.environ.get('INSTALL_ROOT', '/mnt/sysimage/'), dry_run=False)
+
+ parser.add_option("-i", "--installroot", type="string", dest="root",
+ help="Root path to prepend to all file patterns and installation root for RPM "
+ "operations. Defaults to INSTALL_ROOT or /mnt/sysimage/")
+
+ parser.add_option("--dryrun", action="store_true", dest="dryrun",
+ help="If set, no filesystem changes are made.")
+
+ parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
+ help="Display every action as it is performed.")
+
+ (options, args) = parser.parse_args()
+ if len(args) == 0:
+ parser.print_help()
+ sys.exit(1)
+
+ return (options, args)
+
+
+if __name__ == "__main__":
+ try:
+ (options, args) = parse_options()
+ filename = args[0]
+ minimizer = ImageMinimizer(filename, options.root, options.dryrun,
+ options.verbose)
+ minimizer.filter()
+ except SystemExit, e:
+ sys.exit(e.code)
+ except KeyboardInterrupt, e:
+ print >> sys.stderr, _("Aborted at user request")
+ except Exception, e:
+ print e
+ sys.exit(1)
--
1.9.0
More information about the anaconda-patches
mailing list