Generate manifest file
authorHuanhuan Li <huanhuanx.li@intel.com>
Fri, 21 Mar 2014 09:51:49 +0000 (17:51 +0800)
committerHuanhuan Li <huanhuanx.li@intel.com>
Tue, 25 Mar 2014 06:59:34 +0000 (14:59 +0800)
The manifest file stores important infomation such as image file name,
package format, compress format, partitions or disks. So when another program
want to parse image files, it can get the infomation more easily by reading
manifest file. There are two important kinds of format, see bellow:
loop:
   {
       "format": "loop",
       "version": "0.24",
       "loop": {
           "image_files": [
               "whole_rd_210-201403211800.tar.gz"
           ],
           "pack": ".tar.gz",
           "partitions": {
              "/opt": "data",
              "/opt/usr": "ums",
              "/": "platform"
          }
      },
      "created": "2014-03-21 18:02:07"
  }
raw:
   {
       "raw": {
          "image_files": [
               "ivi-201403211803-sda.raw.bz2",
               "ivi-201403211803-sdb.raw.bz2"
           ],
           "disks": [
               "sda",
               "sdb"
          ],
          "compress": "bz2",
          "sda": {
              "image": "ivi-201403211803-sda.raw.bz2",
              "bmap": "ivi-201403211803-sda.bmap"
          },
          "sdb": {
              "image": "ivi-201403211803-sdb.raw.bz2",
              "bmap": "ivi-201403211803-sdb.bmap"
          }
      },
      "format": "raw",
      "version": "0.24",
      "created": "2014-03-21 18:06:10"
  }
Change-Id: Ie9682bad79337319d1c1e6534b3cd4db25271124
Fixes: #1583

mic/imager/baseimager.py
mic/imager/fs.py
mic/imager/livecd.py
mic/imager/liveusb.py
mic/imager/loop.py
mic/imager/raw.py
plugins/imager/fs_plugin.py
plugins/imager/livecd_plugin.py
plugins/imager/liveusb_plugin.py
plugins/imager/loop_plugin.py
plugins/imager/raw_plugin.py

index 2e00384..045da22 100644 (file)
@@ -26,11 +26,13 @@ import subprocess
 import re
 import tarfile
 import glob
+import json
+from datetime import datetime
 
 import rpm
 
 from mic import kickstart
-from mic import msger
+from mic import msger, __version__ as VERSION
 from mic.utils.errors import CreatorError, Abort
 from mic.utils import misc, grabber, runner, fs_related as fs
 from mic.chroot import kill_proc_inchroot
@@ -48,6 +50,8 @@ class BaseImageCreator(object):
       imgcreate.ImageCreator(ks, "foo").create()
 
     """
+    # Output image format
+    img_format = ''
 
     def __del__(self):
         self.cleanup()
@@ -121,7 +125,8 @@ class BaseImageCreator(object):
 
         # Output image file names
         self.outimage = []
-
+        # Output info related with manifest
+        self.image_files = {}
         # A flag to generate checksum
         self._genchecksum = False
 
@@ -1353,3 +1358,30 @@ class BaseImageCreator(object):
         return self.pkgmgr(target_arch = self.target_arch,
                            instroot = self._instroot,
                            cachedir = self.cachedir)
+
+    def create_manifest(self):
+        def get_pack_suffix():
+            return '.' + self.pack_to.split('.', 1)[1]
+
+        if not os.path.exists(self.destdir):
+            os.makedirs(self.destdir)
+
+        now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+        manifest_dict = {'version': VERSION,
+                         'created': now}
+        if self.img_format:
+            manifest_dict.update({'format': self.img_format})
+
+        if hasattr(self, 'logfile') and self.logfile:
+            manifest_dict.update({'log_file': self.logfile})
+
+        if self.image_files:
+            if self.pack_to:
+                self.image_files.update({'pack': get_pack_suffix()})
+            manifest_dict.update({self.img_format: self.image_files})
+
+        msger.info('Creating manifest file...')
+        manifest_file_path = os.path.join(self.destdir, 'manifest.json')
+        with open(manifest_file_path, 'w') as fest_file:
+            json.dump(manifest_dict, fest_file, indent=4)
+        self.outimage.append(manifest_file_path)
index d53b29c..1cb0910 100644 (file)
@@ -24,6 +24,8 @@ from mic.utils.fs_related import find_binary_path
 from mic.imager.baseimager import BaseImageCreator
 
 class FsImageCreator(BaseImageCreator):
+    img_format = 'fs'
+
     def __init__(self, cfgmgr = None, pkgmgr = None):
         self.zips = {
             "tar.bz2" : ""
@@ -48,6 +50,7 @@ class FsImageCreator(BaseImageCreator):
             self._save_recording_pkgs(destdir)
 
         if not self.pack_to:
+            self.image_files = {'image_files': [self.name]}
             fsdir = os.path.join(destdir, self.name)
 
             misc.check_space_pre_cp(self._instroot, destdir)
@@ -61,6 +64,7 @@ class FsImageCreator(BaseImageCreator):
             self.outimage.append(fsdir)
 
         else:
+            self.image_files = {'image_files': [self.pack_to]}
             (tar, comp) = os.path.splitext(self.pack_to)
             try:
                 tarcreat = {'.tar': '-cf',
@@ -96,4 +100,3 @@ class FsImageCreator(BaseImageCreator):
                                    "Cmdline: %s" % (" ".join(tar_cmdline)))
 
             self.outimage.append(dst)
-
index 49137e2..df613a4 100644 (file)
@@ -23,6 +23,7 @@ from mic import kickstart, msger
 from mic.utils import fs_related, rpmmisc, runner, misc
 from mic.utils.errors import CreatorError
 from mic.imager.loop import LoopImageCreator
+from mic.imager.baseimager import BaseImageCreator
 
 
 class LiveImageCreatorBase(LoopImageCreator):
@@ -35,6 +36,8 @@ class LiveImageCreatorBase(LoopImageCreator):
         bootloader, bootloader configuration, kernel and initramfs.
     """
 
+    img_format = 'livecd'
+
     def __init__(self, creatoropts = None, pkgmgr = None):
         """Initialise a LiveImageCreator instance.
 
@@ -305,11 +308,15 @@ class LiveImageCreatorBase(LoopImageCreator):
                 packimg = os.path.join(self._outdir, self.pack_to)
                 misc.packing(packimg, isoimg)
                 os.unlink(isoimg)
+                self.image_files.update({'image_files': [self.pack_to]})
+            else:
+                self.image_files.update({'image_files': [self.name + ".iso"]})
 
         finally:
             shutil.rmtree(self.__isodir, ignore_errors = True)
             self.__isodir = None
 
+
 class x86LiveImageCreator(LiveImageCreatorBase):
     """ImageCreator for x86 machines"""
     def _get_mkisofs_options(self, isodir):
index 4cde4a2..3c01f39 100644 (file)
@@ -27,6 +27,8 @@ from mic.imager.livecd import LiveCDImageCreator
 
 
 class LiveUSBImageCreator(LiveCDImageCreator):
+    img_format = 'liveusb'
+
     def __init__(self, *args):
         LiveCDImageCreator.__init__(self, *args)
 
@@ -297,10 +299,13 @@ class LiveUSBImageCreator(LiveCDImageCreator):
                 self._create_usbimg(isodir)
 
                 if self.pack_to:
+                    self.image_files.update({'image_files': self.pack_to})
                     usbimg = os.path.join(self._outdir, self.name + ".usbimg")
                     packimg = os.path.join(self._outdir, self.pack_to)
                     misc.packing(packimg, usbimg)
                     os.unlink(usbimg)
+                else:
+                    self.image_files.update({'image_files': self.name + ".usbimg"})
 
         finally:
             shutil.rmtree(isodir, ignore_errors = True)
index 09f3a9e..049406c 100644 (file)
@@ -98,6 +98,7 @@ class LoopImageCreator(BaseImageCreator):
     When specifying multiple partitions in kickstart file, each partition
     will be created as a separated loop image.
     """
+    img_format = 'loop'
 
     def __init__(self, creatoropts=None, pkgmgr=None,
                  compress_image=None,
@@ -390,8 +391,14 @@ class LoopImageCreator(BaseImageCreator):
             if item['fstype'] == "ext4":
                 runner.show('/sbin/tune2fs -O ^huge_file,extents,uninit_bg %s '
                             % imgfile)
+            self.image_files.setdefault('partitions', {}).update(
+                    {item['mountpoint']: item['label']})
             if self.compress_image:
                 misc.compressing(imgfile, self.compress_image)
+                self.image_files.setdefault('image_files', []).append(
+                                '.'.join([item['name'], self.compress_image]))
+            else:
+                self.image_files.setdefault('image_files', []).append(item['name'])
 
         if not self.pack_to:
             for item in os.listdir(self.__imgdir):
@@ -401,6 +408,8 @@ class LoopImageCreator(BaseImageCreator):
             msger.info("Pack all loop images together to %s" % self.pack_to)
             dstfile = os.path.join(self._outdir, self.pack_to)
             misc.packing(dstfile, self.__imgdir)
+            self.image_files['image_files'] = [self.pack_to]
+
 
         if self.pack_to:
             mountfp_xml = os.path.splitext(self.pack_to)[0]
@@ -426,3 +435,7 @@ class LoopImageCreator(BaseImageCreator):
             msger.verbose("Copy attachment %s to %s" % (item, dpath))
             shutil.copy(item, dpath)
 
+    def create_manifest(self):
+        if self.compress_image:
+            self.image_files.update({'compress': self.compress_image})
+        super(LoopImageCreator, self).create_manifest()
index a849a56..6b53ac6 100644 (file)
@@ -34,6 +34,7 @@ class RawImageCreator(BaseImageCreator):
     and the system installed into an virtual disk. The disk image can
     subsequently be booted in a virtual machine or accessed with kpartx
     """
+    img_format = 'raw'
 
     def __init__(self, creatoropts=None, pkgmgr=None, compress_image=None, generate_bmap=None, fstab_entry="uuid"):
         """Initialize a ApplianceImageCreator instance.
@@ -440,6 +441,17 @@ class RawImageCreator(BaseImageCreator):
            write meta data
         """
         self._resparse()
+        self.image_files.update({'disks': self.__disks.keys()})
+
+        if not (self.compress_image or self.pack_to):
+            for imgfile in os.listdir(self.__imgdir):
+                if imgfile.endswith('.raw'):
+                    for disk in self.__disks.keys():
+                        if imgfile.find(disk) != -1:
+                            self.image_files.setdefault(disk, {}).update(
+                                   {'image': imgfile})
+                            self.image_files.setdefault('image_files',
+                                   []).append(imgfile)
 
         if self.compress_image:
             for imgfile in os.listdir(self.__imgdir):
@@ -447,11 +459,20 @@ class RawImageCreator(BaseImageCreator):
                     imgpath = os.path.join(self.__imgdir, imgfile)
                     msger.info("Compressing image %s" % imgfile)
                     misc.compressing(imgpath, self.compress_image)
+                if imgfile.endswith('.raw') and not self.pack_to:
+                    for disk in self.__disks.keys():
+                        if imgfile.find(disk) != -1:
+                            imgname = '%s.%s' % (imgfile, self.compress_image)
+                            self.image_files.setdefault(disk, {}).update(
+                                   {'image': imgname})
+                            self.image_files.setdefault('image_files',
+                                    []).append(imgname)
 
         if self.pack_to:
             dst = os.path.join(self._outdir, self.pack_to)
             msger.info("Pack all raw images to %s" % dst)
             misc.packing(dst, self.__imgdir)
+            self.image_files.update({'image_files': self.pack_to})
         else:
             msger.debug("moving disks to stage location")
             for imgfile in os.listdir(self.__imgdir):
@@ -459,6 +480,7 @@ class RawImageCreator(BaseImageCreator):
                 dst = os.path.join(self._outdir, imgfile)
                 msger.debug("moving %s to %s" % (src,dst))
                 shutil.move(src,dst)
+
         self._write_image_xml()
 
     def _write_image_xml(self):
@@ -556,6 +578,8 @@ class RawImageCreator(BaseImageCreator):
         for name in self.__disks.keys():
             image = self._full_path(self.__imgdir, name, self.__disk_format)
             bmap_file = self._full_path(self._outdir, name, "bmap")
+            self.image_files.setdefault(name, {}).update({'bmap': \
+                                            os.path.basename(bmap_file)})
 
             msger.debug("Generating block map file '%s'" % bmap_file)
 
@@ -565,3 +589,8 @@ class RawImageCreator(BaseImageCreator):
                 del creator
             except BmapCreate.Error as err:
                 raise CreatorError("Failed to create bmap file: %s" % str(err))
+
+    def create_manifest(self):
+        if self.compress_image:
+            self.image_files.update({'compress': self.compress_image})
+        super(RawImageCreator, self).create_manifest()
index 3333157..9d4d79f 100644 (file)
@@ -126,6 +126,7 @@ class FsPlugin(ImagerPlugin):
             creator.copy_kernel()
             creator.unmount()
             creator.package(creatoropts["outdir"])
+            creator.create_manifest()
             if creatoropts['release'] is not None:
                 creator.release_output(ksconf, creatoropts['outdir'], creatoropts['release'])
             creator.print_outimage_info()
index 0ccba72..35ff512 100644 (file)
@@ -117,6 +117,7 @@ class LiveCDPlugin(ImagerPlugin):
             creator.copy_kernel()
             creator.unmount()
             creator.package(creatoropts["outdir"])
+            creator.create_manifest()
             if creatoropts['release'] is not None:
                 creator.release_output(ksconf, creatoropts['outdir'], creatoropts['release'])
             creator.print_outimage_info()
index 297a9b0..bc2b9aa 100644 (file)
@@ -118,6 +118,7 @@ class LiveUSBPlugin(ImagerPlugin):
             creator.copy_kernel()
             creator.unmount()
             creator.package(creatoropts["outdir"])
+            creator.create_manifest()
             if creatoropts['release'] is not None:
                 creator.release_output(ksconf, creatoropts['outdir'], creatoropts['release'])
             creator.print_outimage_info()
index 30dc3d9..3641ec9 100644 (file)
@@ -129,6 +129,7 @@ class LoopPlugin(ImagerPlugin):
             creator.copy_kernel()
             creator.unmount()
             creator.package(creatoropts["outdir"])
+            creator.create_manifest()
 
             if creatoropts['release'] is not None:
                 creator.release_output(ksconf,
index 25409a9..bb8c7f0 100644 (file)
@@ -132,6 +132,7 @@ class RawPlugin(ImagerPlugin):
             creator.unmount()
             creator.generate_bmap()
             creator.package(creatoropts["outdir"])
+            creator.create_manifest()
             if creatoropts['release'] is not None:
                 creator.release_output(ksconf, creatoropts['outdir'], creatoropts['release'])
             creator.print_outimage_info()