Generate manifest file
authorHuanhuan Li <huanhuanx.li@intel.com>
Fri, 21 Mar 2014 09:51:49 +0000 (17:51 +0800)
committerLihong Sun <lihongx.sun@intel.com>
Wed, 21 Jan 2015 09:34:36 +0000 (04:34 -0500)
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

Conflicts:
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

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 c6a479d..09499c2 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()
@@ -117,7 +121,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 4a9e5d7..f2ccb78 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',
@@ -95,4 +99,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 282097a..15a7644 100644 (file)
@@ -122,6 +122,7 @@ class FsPlugin(ImagerPlugin):
             creator.copy_kernel()
             creator.unmount()
             creator.package(creatoropts["destdir"])
+            creator.create_manifest()
             if creatoropts['release'] is not None:
                 creator.release_output(ksconf, creatoropts['destdir'],
                         creatoropts['release'])
index 44b57ef..3b45b5a 100644 (file)
@@ -113,6 +113,7 @@ class LiveCDPlugin(ImagerPlugin):
             creator.copy_kernel()
             creator.unmount()
             creator.package(creatoropts["destdir"])
+            creator.create_manifest()
             if creatoropts['release'] is not None:
                 creator.release_output(ksconf, creatoropts['destdir'], creatoropts['release'])
             creator.print_outimage_info()
index b00b2eb..a2f300f 100644 (file)
@@ -114,6 +114,7 @@ class LiveUSBPlugin(ImagerPlugin):
             creator.copy_kernel()
             creator.unmount()
             creator.package(creatoropts["destdir"])
+            creator.create_manifest()
             if creatoropts['release'] is not None:
                 creator.release_output(ksconf, creatoropts['destdir'], creatoropts['release'])
             creator.print_outimage_info()
index 50e1c01..e306ad1 100644 (file)
@@ -123,6 +123,7 @@ class LoopPlugin(ImagerPlugin):
             creator.copy_kernel()
             creator.unmount()
             creator.package(creatoropts["destdir"])
+            creator.create_manifest()
 
             if creatoropts['release'] is not None:
                 creator.release_output(ksconf,
index a24b549..e994036 100644 (file)
@@ -128,6 +128,7 @@ class RawPlugin(ImagerPlugin):
             creator.unmount()
             creator.generate_bmap()
             creator.package(creatoropts["destdir"])
+            creator.create_manifest()
             if creatoropts['release'] is not None:
                 creator.release_output(ksconf, creatoropts['destdir'], creatoropts['release'])
             creator.print_outimage_info()