def _TestDiskBundleHelper(self, partition_start, partition_end, fs_uuid):
        disk_path = self._SetupMbrDisk(partition_start, partition_end, fs_uuid)

        with utils.LoadDiskImage(disk_path) as devices:
            # Get the path to do the disk.
            # devices will have something which is like /dev/mapper/loop0p1
            # We need to get loop0 out of it.
            disk_loop_back_path = '/dev/' + devices[0].split('/')[3][:-2]

            # Create a symlinks to the disk and loopback paths
            # This is required because of the code where we assume first
            # partition is device path appended by 1. Will remove it once we
            # update that part of the code.
            symlink_disk = os.path.join(self.tmp_root, 'disk')
            symlink_partition = self.tmp_root + '/disk1'
            utils.RunCommand(['ln', '-s', disk_loop_back_path, symlink_disk])
            utils.RunCommand(['ln', '-s', devices[0], symlink_partition])

            # Bundle up
            self._bundle.AddDisk(symlink_disk)
            self._bundle.AddSource(self.tmp_path)
            self._bundle.Verify()
            (_, _) = self._bundle.Bundleup()
        self._VerifyImageHas(self._tar_path, [
            'lost+found', 'test1', 'test2', 'dir1/', '/dir1/dir11/',
            '/dir1/sl1', '/dir1/hl2', 'dir2/', '/dir2/dir1', '/dir2/sl2',
            '/dir2/hl1'
        ])
        self._VerifyNumberOfHardLinksInRawDisk(self._tar_path, 'test1', 2)
        self._VerifyNumberOfHardLinksInRawDisk(self._tar_path, 'test2', 2)
        self._VerifyDiskSize(self._tar_path, self._fs_size)
        self._VerifyNonPartitionContents(self._tar_path, disk_path,
                                         partition_start)
        self._VerifyFilesystemUUID(self._tar_path, fs_uuid)
    def _VerifyFilesystemUUID(self, tar, expected_uuid):
        """Verifies UUID of the first partition on disk matches the value."""
        tmp_dir = tempfile.mkdtemp(dir=self.tmp_root)
        tar_cmd = ['tar', '-xzf', tar, '-C', tmp_dir]
        self.assertEqual(subprocess.call(tar_cmd), 0)

        created_disk_path = os.path.join(tmp_dir, 'disk.raw')
        with utils.LoadDiskImage(created_disk_path) as devices:
            self.assertEqual(1, len(devices))
            self.assertEqual(expected_uuid, utils.GetUUID(devices[0]))
 def _VerifyNumberOfHardLinksInRawDisk(self, tar, filename, count):
     """Tests if a file on raw disk has a specified number of hard links."""
     tmp_dir = tempfile.mkdtemp(dir=self.tmp_root)
     tar_cmd = ['tar', '-xzf', tar, '-C', tmp_dir]
     self.assertEqual(subprocess.call(tar_cmd), 0)
     disk_path = os.path.join(tmp_dir, 'disk.raw')
     with utils.LoadDiskImage(disk_path) as devices:
         self.assertEqual(len(devices), 1)
         mnt_dir = tempfile.mkdtemp(dir=self.tmp_root)
         with utils.MountFileSystem(devices[0], mnt_dir):
             self.assertEqual(
                 os.stat(os.path.join(mnt_dir, filename)).st_nlink, count)
Example #4
0
  def _InitializeDiskFileFromDevice(self, file_path):
    """Initializes disk file from the device specified in self._disk.

    It preserves whatever may be there on the device prior to the start of the
    first partition.

    At the moment this method supports devices with a single partition only.

    Args:
      file_path: The path where the disk file should be created.

    Returns:
      A tuple with partition_start, uuid. partition_start is the location
      where the first partition on the disk starts and uuid is the filesystem
      UUID to use for the first partition.

    Raises:
      RawDiskError: If there are more than one partition on the disk device.
    """
    # Find the disk size
    disk_size = utils.GetDiskSize(self._disk)
    logging.debug('Size of disk is %s', disk_size)
    # Make the disk file big enough to hold the disk
    self._ResizeFile(file_path, disk_size)
    # Find the location where the first partition starts
    partition_start = utils.GetPartitionStart(self._disk, 1)
    logging.debug('First partition starts at %s', partition_start)
    # Copy all the bytes as is from the start of the disk to the start of
    # first partition
    utils.CopyBytes(self._disk, file_path, partition_start)
    # Verify there is only 1 partition on the disk
    with utils.LoadDiskImage(file_path) as devices:
      # For now we only support disks with a single partition.
      if len(devices) == 0:
        raise RawDiskError(
            'Device %s should be a disk not a partition.' % self._disk)
      elif len(devices) != 1:
        raise RawDiskError(
            'Device %s has more than 1 partition. Only devices '
            'with a single partition are supported.' % self._disk)
    # Remove the first partition from the file we are creating. We will
    # recreate a partition that will fit inside _fs_size later.
    utils.RemovePartition(file_path, 1)
    # Resize the disk.raw file down to self._fs_size
    # We do this after removing the first partition to ensure that an
    # existing partition doesn't fall outside the boundary of the disk device.
    self._ResizeFile(file_path, self._fs_size)
    # Get UUID of the first partition on the disk
    # TODO(user): This is very hacky and relies on the disk path being
    # similar to /dev/sda etc which is bad. Need to fix it.
    uuid = utils.GetUUID(self._disk + '1')
    return partition_start, uuid
 def _VerifyFileInRawDiskEndsWith(self, tar, filename, text):
     """Tests if a file on raw disk contains ends with a specified text."""
     tmp_dir = tempfile.mkdtemp(dir=self.tmp_root)
     tar_cmd = ['tar', '-xzf', tar, '-C', tmp_dir]
     self.assertEqual(subprocess.call(tar_cmd), 0)
     disk_path = os.path.join(tmp_dir, 'disk.raw')
     with utils.LoadDiskImage(disk_path) as devices:
         self.assertEqual(len(devices), 1)
         mnt_dir = tempfile.mkdtemp(dir=self.tmp_root)
         with utils.MountFileSystem(devices[0], mnt_dir):
             f = open(os.path.join(mnt_dir, filename), 'r')
             file_content = f.read()
             f.close()
             self.assertTrue(file_content.endswith(text))
 def _VerifyImageHas(self, tar, expected):
     """Tests if raw disk contains an expected list of files/directories."""
     tmp_dir = tempfile.mkdtemp(dir=self.tmp_root)
     tar_cmd = ['tar', '-xzf', tar, '-C', tmp_dir]
     self.assertEqual(subprocess.call(tar_cmd), 0)
     disk_path = os.path.join(tmp_dir, 'disk.raw')
     with utils.LoadDiskImage(disk_path) as devices:
         self.assertEqual(len(devices), 1)
         mnt_dir = tempfile.mkdtemp(dir=self.tmp_root)
         with utils.MountFileSystem(devices[0], mnt_dir):
             found = []
             for root, dirs, files in os.walk(mnt_dir):
                 root = root.replace(mnt_dir, '')
                 for f in files:
                     found.append(os.path.join(root, f))
                 for d in dirs:
                     found.append(os.path.join(root, d))
     self._AssertListEqual(expected, found)
    def _SetupMbrDisk(self, partition_start, partition_end, fs_uuid):
        """Creates a disk with a fake MBR.

    Args:
      partition_start: The byte offset where the partition starts.
      partition_end: The byte offset where the partition ends.
      fs_uuid: The UUID of the filesystem to create on the partition.

    Returns:
      The path where the disk is located.
    """
        # Create the disk file with the size specified.
        disk_path = os.path.join(self.tmp_root, 'mbrdisk.raw')
        disk_size = partition_end + FsRawDiskTest._MEGABYTE
        with open(disk_path, 'wb') as disk_file:
            disk_file.truncate(disk_size)

        # Create a partition table
        utils.MakePartitionTable(disk_path)

        # Create the partition
        utils.MakePartition(disk_path, 'primary', 'ext2', partition_start,
                            partition_end)

        # Create the file system
        with utils.LoadDiskImage(disk_path) as devices:
            utils.MakeFileSystem(devices[0], 'ext4', fs_uuid)

        # Write some data after the MBR but before the first partition
        with open(disk_path, 'r+b') as disk_file:
            # Seek to last two bytes of first sector
            disk_file.seek(510)
            # Write MBR signature
            disk_file.write(chr(0x55))
            disk_file.write(chr(0xAA))
            # Write random data on the disk till the point first partition starts
            for _ in range(partition_start - 512):
                # Write a byte
                disk_file.write(chr(random.randint(0, 127)))

        return disk_path
Example #8
0
  def Bundleup(self):
    """Creates a raw disk copy of OS image and bundles it into gzipped tar.

    Returns:
      A size of a generated raw disk and the SHA1 digest of the the tar archive.

    Raises:
      RawDiskError: If number of partitions in a created image doesn't match
                    expected count.
    """

    # Create sparse file with specified size
    disk_file_path = os.path.join(self._scratch_dir, self._disk_file_name)
   # with open(disk_file_path, 'wb') as _:
   #   pass
    self._excludes.append(exclude_spec.ExcludeSpec(disk_file_path))

    logging.info('Initializing disk file')
    partition_start = None
    uuid = None
    if self._disk:
      # If a disk device has been provided then preserve whatever is there on
      # the disk before the first partition in case there is an MBR present.
      partition_start, uuid = self._InitializeDiskFileFromDevice(disk_file_path)
    else:
      #feoff: our code goes this way

      # User didn't specify a disk device. Initialize a device with a simple
      # partition table.
      logging.info("Setting partiton size: " + str(self._fs_size) )
      self._ResizeFile(disk_file_path, self._fs_size)

      # User didn't specify a disk to copy. Create a new partition table
      utils.MakePartitionTable(disk_file_path)
      # Pass 1MB as start to avoid 'Warning: The resulting partition is not
      # properly aligned for best performance.' from parted.
      partition_start = 1024 * 1024

    # Create a new partition starting at partition_start of size
    # self._fs_size - partition_start. 

    #feoff: it's not just a log ensure the size changed. we ensure the size is changed and OS updated info on it. needed in FUSE scenario
    utils.MakePartition(disk_file_path, 'primary', 'ext2', partition_start,
                        self._fs_size-512) # feoff: THE LAST PARM IS THE LAST SECTOR! , not size!

    logging.info("Preparing file disk size " + str(os.path.getsize(disk_file_path)) + " bytes")

    with utils.LoadDiskImage(disk_file_path) as devices:
      # For now we only support disks with a single partition.
      if len(devices) != 1:
        raise RawDiskError(devices)
      # List contents of /dev/mapper to help with debugging. Contents will
      # be listed in debug log only
      utils.RunCommand(['ls', '/dev/mapper'])
      logging.info('Making filesystem')
      uuid = utils.MakeFileSystem(devices[0], self._fs_type, uuid)
    with utils.LoadDiskImage(disk_file_path) as devices:
      if uuid is None:
        raise Exception('Could not get uuid from MakeFileSystem')
      mount_point = tempfile.mkdtemp(dir=self._scratch_dir)
      with utils.MountFileSystem(devices[0], mount_point, self._fs_type):
        logging.info('Copying contents')
        #feoff: temporary disable selinux to ensure rsync works fine, see https://github.com/GoogleCloudPlatform/compute-image-packages/issues/132
        selinux_state = self._setSELinux("0")
        self._CopySourceFiles(mount_point)
        self._CopyPlatformSpecialFiles(mount_point)
        self._ProcessOverwriteList(mount_point)
        self._CleanupNetwork(mount_point)
        self._UpdateFstab(mount_point, uuid)
        # feoff: set dhcp to eth0
        self._SetDhcp(mount_point)
        # feoff: grub
        # should move add_grub to the parm
        add_grub = True
        if add_grub:
            from gcimagebundlelib import grub
            grub.InstallGrub(mount_point, devices[0])
        self._setSELinux(selinux_state)
   

    tar_entries = []

    manifest_file_path = os.path.join(self._scratch_dir, 'manifest.json')
    manifest_created = self._manifest.CreateIfNeeded(manifest_file_path)
    if manifest_created:
      tar_entries.append(manifest_file_path)

    tar_entries.append(disk_file_path)
    
    #TODO(feoff): make it parametrizable - if to start tar or not
   # logging.info('Creating tar.gz archive')
    utils.TarAndGzipFile(tar_entries,
                         self._output_tarfile)
    # Removed the deletion of file
    for tar_entry in tar_entries:
        if not self._output_tarfile == tar_entry:
            os.remove(tar_entry)

    # TODO(user): It would be better to compute tar.gz file hash during
    # archiving.
    h = hashlib.sha1()
    with open(self._output_tarfile, 'rb') as tar_file:
      for chunk in iter(lambda: tar_file.read(8192), ''):
        h.update(chunk)
    return (self._fs_size, h.hexdigest())
Example #9
0
    def Bundleup(self):
        """Creates a raw disk copy of OS image and bundles it into gzipped tar.

    Returns:
      A size of a generated raw disk and the SHA1 digest of the the tar archive.

    Raises:
      RawDiskError: If number of partitions in a created image doesn't match
                    expected count.
    """

        # Create sparse file with specified size
        disk_file_path = os.path.join(self._scratch_dir, 'disk.raw')
        with open(disk_file_path, 'wb') as _:
            pass
        self._excludes.append(exclude_spec.ExcludeSpec(disk_file_path))

        logging.info('Initializing disk file')
        partition_start = None
        uuid = None
        if self._disk:
            # If a disk device has been provided then preserve whatever is there on
            # the disk before the first partition in case there is an MBR present.
            partition_start, uuid = self._InitializeDiskFileFromDevice(
                disk_file_path)
        else:
            # User didn't specify a disk device. Initialize a device with a simple
            # partition table.
            self._ResizeFile(disk_file_path, self._fs_size)
            # User didn't specify a disk to copy. Create a new partition table
            utils.MakePartitionTable(disk_file_path)
            # Pass 1MB as start to avoid 'Warning: The resulting partition is not
            # properly aligned for best performance.' from parted.
            partition_start = 1024 * 1024

        # Create a new partition starting at partition_start of size
        # self._fs_size - partition_start
        utils.MakePartition(disk_file_path, 'primary', 'ext2', partition_start,
                            self._fs_size - partition_start)
        with utils.LoadDiskImage(disk_file_path) as devices:
            # For now we only support disks with a single partition.
            if len(devices) != 1:
                raise RawDiskError(devices)
            # List contents of /dev/mapper to help with debugging. Contents will
            # be listed in debug log only
            utils.RunCommand(['ls', '/dev/mapper'])
            logging.info('Making filesystem')
            uuid = utils.MakeFileSystem(devices[0], self._fs_type, uuid)
        with utils.LoadDiskImage(disk_file_path) as devices:
            if uuid is None:
                raise Exception('Could not get uuid from MakeFileSystem')
            mount_point = tempfile.mkdtemp(dir=self._scratch_dir)
            with utils.MountFileSystem(devices[0], mount_point):
                logging.info('Copying contents')
                self._CopySourceFiles(mount_point)
                self._CopyPlatformSpecialFiles(mount_point)
                self._ProcessOverwriteList(mount_point)
                self._CleanupNetwork(mount_point)
                self._UpdateFstab(mount_point, uuid)

        tar_entries = []

        manifest_file_path = os.path.join(self._scratch_dir, 'manifest.json')
        manifest_created = self._manifest.CreateIfNeeded(manifest_file_path)
        if manifest_created:
            tar_entries.append(manifest_file_path)

        tar_entries.append(disk_file_path)
        logging.info('Creating tar.gz archive')
        utils.TarAndGzipFile(tar_entries, self._output_tarfile)
        for tar_entry in tar_entries:
            os.remove(tar_entry)

        # TODO(user): It would be better to compute tar.gz file hash during
        # archiving.
        h = hashlib.sha1()
        with open(self._output_tarfile, 'rb') as tar_file:
            for chunk in iter(lambda: tar_file.read(8192), ''):
                h.update(chunk)
        return (self._fs_size, h.hexdigest())