[PATCH pylorax] livemedia-creator: add file system manifest creation option for --make-iso builds

Joey Boggs jboggs at redhat.com
Fri Sep 13 16:23:23 UTC 2013


This add a fine level of details about the created image including:
- installed packages
- source rpms used
- licensing
- dependencies
- where disk space is used

Signed-off-by: Joey Boggs <jboggs at redhat.com>
---
 src/pylorax/treebuilder.py | 84 ++++++++++++++++++++++++++++++++++++++++++++++
 src/sbin/livemedia-creator |  6 ++++
 2 files changed, 90 insertions(+)

diff --git a/src/pylorax/treebuilder.py b/src/pylorax/treebuilder.py
index 2e7c43e..0311118 100644
--- a/src/pylorax/treebuilder.py
+++ b/src/pylorax/treebuilder.py
@@ -29,6 +29,7 @@ from base import DataHolder
 from ltmpl import LoraxTemplateRunner
 import imgutils
 from pylorax.executils import runcmd, runcmd_output
+from subprocess import Popen, PIPE, STDOUT
 
 templatemap = {
     'i386':    'x86.tmpl',
@@ -184,6 +185,88 @@ class TreeBuilder(object):
     def kernels(self):
         return findkernels(root=self.vars.inroot)
 
+    def collect_manifest(self, cmd, output_file, sort=False):
+        output = runcmd_output(cmd, root=self.vars.inroot)
+        with open(os.path.join(self.manifest_path, output_file), "w") as f:
+            if sort:
+                output = output.split("\n")
+                for line in sorted(set(output),key=str.lower):
+                    if line:
+                        f.write("%s\n" % line)
+            else:
+                f.write(output)
+
+    def create_manifests(self):
+        self.manifest_path = os.path.join(self.vars.outroot, "isolinux")
+        env = os.environ.copy()
+        env['LC_ALL'] = 'C'
+        os.makedirs(self.manifest_path)
+        # collect installed packages information
+        cmd = ["rpm", "-qa", "--qf",
+               "%{name}-%{version}-%{release}.%{arch} (%{SIGPGP:pgpsig})\n"]
+        self.collect_manifest(cmd, "manifest-rpm.txt", True)
+
+        # collect source rpms
+        cmd = ["rpm", "-qa", "--qf", "%{sourcerpm}\n"]
+        self.collect_manifest(cmd, "manifest-srpm.txt", True)
+
+        # collect all included licenses rhbz#601927
+        cmd = ["rpm", "-qa", "--qf", "%{license}\n"]
+        self.collect_manifest(cmd, "manifest-license.txt", True)
+
+        # get individial file sizes
+        cmd = ["du", "-akx", "--exclude=/var/cache/yum", "/"]
+        self.collect_manifest(cmd, "manifest-file.txt", True)
+
+        # get directory sizes
+        cmd = ["du", "-x", "--exclude=/var/cache/yum", "/"]
+        self.collect_manifest(cmd, "manifest-dir.txt", True)
+
+        # find orphaned files
+        file_list = []
+        cmd = ["rpm", "-qa"]
+        installed_rpms = runcmd_output(cmd).strip()
+
+        for pkg in installed_rpms.split("\n"):
+            cmd = ["rpm", "-ql", pkg]
+            pkg_files = runcmd_output(cmd).strip()
+            for f in pkg_files.split("\n"):
+                file_list.append("%s##%s" % (f, pkg))
+
+        cmd = ["find", "/", "-xdev"]
+        fs_list = runcmd_output(cmd).strip()
+
+        for f in fs_list.split("\n"):
+            file_list.append("%s##Not owned by any package." % f)
+
+        final_list = {}
+
+        for item in file_list:
+            f, owner = item.split("##")
+            if not f in final_list:
+                final_list[f] = owner
+
+        output_file = os.path.join(self.manifest_path, "manifest-owns.txt")
+        with open(output_file, "w") as t:
+            for x in final_list.keys():
+                t.write("%s\n%s\n" % (x, final_list[x]))
+
+        # get dependency list
+        cmd = ["rpm", "-qa"]
+        output = runcmd_output(cmd, root=self.vars.inroot)
+        piped_cmd = ["xargs", "-n1", "rpm", "-e", "--test"]
+        run_cmd = Popen(piped_cmd, stdout=PIPE, stdin=PIPE, stderr=PIPE)
+        stdout_data = run_cmd.communicate(input=output)[1]
+        deps_file = os.path.join(self.manifest_path, "manifest-deps.txt")
+        with open(deps_file, "w") as f:
+            f.write("%s\n" % stdout_data)
+
+        # bzip large manufest files
+        for f in ["deps", "owns", "file", "dir" ]:
+            path = os.path.join(self.manifest_path, "manifest-%s.txt" % f)
+            cmd = ["bzip2", path]
+            runcmd(cmd)
+
     def rebuild_initrds(self, add_args=[], backup="", prefix=""):
         '''Rebuild all the initrds in the tree. If backup is specified, each
         initrd will be renamed with backup as a suffix before rebuilding.
@@ -269,6 +352,7 @@ def findkernels(root="/", kdir="boot"):
                      r"(\.(?P<flavor>{0}))?)$".format("|".join(flavors)))
     kernels = []
     bootfiles = os.listdir(joinpaths(root, kdir))
+
     for f in bootfiles:
         match = kre.match(f)
         if match:
diff --git a/src/sbin/livemedia-creator b/src/sbin/livemedia-creator
index 9239445..61c4a5e 100755
--- a/src/sbin/livemedia-creator
+++ b/src/sbin/livemedia-creator
@@ -535,6 +535,9 @@ def make_livecd(opts, mount_dir, work_dir):
     log.info("dracut args = {0}".format(dracut_args))
     tb.rebuild_initrds(add_args=dracut_args)
     log.info("Building boot.iso")
+    log.info("Generating Manifests")
+    if opts.create_manifests and opts.make_iso:
+        tb.create_manifests()
     tb.build()
 
     return work_dir
@@ -814,6 +817,9 @@ if __name__ == '__main__':
     parser.add_argument( "--volid", default=None, help="volume id")
     parser.add_argument( "--squashfs_args",
                          help="additional squashfs args" )
+    parser.add_argument( "--create-manifests", action="store_true",
+                         help="Create file system manifests of image",
+                         default=False )
 
     opts = parser.parse_args()
 
-- 
1.8.3.1



More information about the anaconda-patches mailing list