[virt-tools-list] [virt-bootstrap] [PATCH v2 07/14] Enable UID/GID mapping for qcow2

Cedric Bosdonnat cbosdonnat at suse.com
Tue Aug 1 15:22:55 UTC 2017


On Tue, 2017-08-01 at 12:28 +0100, Radostin Stoyanov wrote:
> Implement UID/GID file ownership mapping for qcow2 images.
> 
> The implementation consist of:
>     For each layer:
>         1. Create qcow2 image with backing chain
>         2. Tar-in the content form tarball
>         2. Get a list of all members (stored files) of this tarball
>         3. For each member get the UID/GID
>         4. Apply the new ownership for this member in the qcow2 image
> ---
>  src/virtBootstrap/sources/docker_source.py |  5 ++++-
>  src/virtBootstrap/sources/file_source.py   |  6 +++--
>  src/virtBootstrap/utils.py                 | 35 +++++++++++++++++++++++++++++-
>  src/virtBootstrap/virt_bootstrap.py        |  2 ++
>  4 files changed, 44 insertions(+), 4 deletions(-)
> 
> diff --git a/src/virtBootstrap/sources/docker_source.py b/src/virtBootstrap/sources/docker_source.py
> index 9220e13..0ca3b20 100644
> --- a/src/virtBootstrap/sources/docker_source.py
> +++ b/src/virtBootstrap/sources/docker_source.py
> @@ -58,6 +58,8 @@ class DockerSource(object):
>          self.url = self.gen_valid_uri(kwargs['uri'])
>          self.username = kwargs['username']
>          self.password = kwargs['password']
> +        self.uid_map = kwargs['uid_map']
> +        self.gid_map = kwargs['gid_map']
>          self.output_format = kwargs['fmt']
>          self.insecure = kwargs['not_secure']
>          self.no_cache = kwargs['no_cache']
> @@ -262,7 +264,8 @@ class DockerSource(object):
>              elif self.output_format == 'qcow2':
>                  self.progress("Extracting container layers into qcow2 images",
>                                value=50, logger=logger)
> -                utils.Build_QCOW2_Image(self.tar_files, dest, self.progress)
> +                utils.Build_QCOW2_Image(self.tar_files, dest, self.progress,
> +                                        self.uid_map, self.gid_map)
>              else:
>                  raise Exception("Unknown format:" + self.output_format)
>  
> diff --git a/src/virtBootstrap/sources/file_source.py b/src/virtBootstrap/sources/file_source.py
> index 87589f6..748181f 100644
> --- a/src/virtBootstrap/sources/file_source.py
> +++ b/src/virtBootstrap/sources/file_source.py
> @@ -44,6 +44,8 @@ class FileSource(object):
>          """
>          self.path = kwargs['uri'].path
>          self.output_format = kwargs['fmt']
> +        self.uid_map = kwargs['uid_map']
> +        self.gid_map = kwargs['gid_map']
>          self.progress = kwargs['progress'].update_progress
>  
>      def unpack(self, dest):
> @@ -60,11 +62,11 @@ class FileSource(object):
>              self.progress("Extracting files into destination directory",
>                            value=0, logger=logger)
>              utils.safe_untar(self.path, dest)
> -
>          elif self.output_format == 'qcow2':
>              self.progress("Extracting files into qcow2 image", value=0,
>                            logger=logger)
> -            utils.Build_QCOW2_Image([self.path], dest, self.progress)
> +            utils.Build_QCOW2_Image([self.path], dest, self.progress,
> +                                    self.uid_map, self.gid_map)
>          else:
>              raise Exception("Unknown format:" + self.output_format)
>  
> diff --git a/src/virtBootstrap/utils.py b/src/virtBootstrap/utils.py
> index cf5becc..c69b5da 100644
> --- a/src/virtBootstrap/utils.py
> +++ b/src/virtBootstrap/utils.py
> @@ -28,6 +28,7 @@ import hashlib
>  import json
>  import os
>  import sys
> +import tarfile
>  import tempfile
>  import logging
>  import re
> @@ -56,7 +57,7 @@ class Build_QCOW2_Image(object):
>      """
>      Create qcow2 image with backing chains from list of tar files.
>      """
> -    def __init__(self, tar_files, dest, progress):
> +    def __init__(self, tar_files, dest, progress, uid_map=None, gid_map=None):
>          """
>          Initialize guestfs
>          """
> @@ -65,6 +66,8 @@ class Build_QCOW2_Image(object):
>          self.tar_files = tar_files
>          self.nlayers = len(tar_files)
>          self.progress = progress
> +        self.uid_map = uid_map
> +        self.gid_map = gid_map
>          self.fmt = 'qcow2'
>          self.qcow2_files = [os.path.join(dest, 'layer-%s.qcow2' % i)
>                              for i in range(self.nlayers)]
> @@ -100,6 +103,14 @@ class Build_QCOW2_Image(object):
>          # from tar file.
>          self.g.tar_in(tar_file, '/', get_compression_type(tar_file),
>                        xattrs=True, selinux=True, acls=True)
> +
> +        # UID/GID Mapping
> +        if self.uid_map or self.gid_map:
> +            tar_members = tarfile.open(tar_file).getmembers()
> +            balance_uid_gid_maps(self.uid_map, self.gid_map)
> +            for uid, gid in zip(self.uid_map, self.gid_map):
> +                self.map_id(tar_members, uid, gid)
> +
>          # Shutdown guestfs instance to avoid hot-plugging of devices.
>          self.g.umount('/')
>  
> @@ -139,6 +150,28 @@ class Build_QCOW2_Image(object):
>              self.tar_in(tar_file, devices[i])
>  
>  
> +    def map_id(self, tar_members, map_uid, map_gid):
> +        """
> +        Remapping ownership of all files inside image.
> +
> +        map_gid and map_uid: Contain integers in a list with format:
> +            [<start>, <target>, <count>]
> +        """
> +        if map_uid:
> +            uid_opts = get_mapping_opts(map_uid)
> +        if map_gid:
> +            gid_opts = get_mapping_opts(map_gid)
> +
> +        for member in tar_members:
> +            old_uid = member.uid
> +            old_gid = member.gid
> +
> +            new_uid = get_map_id(old_uid, uid_opts) if map_uid else -1
> +            new_gid = get_map_id(old_gid, gid_opts) if map_gid else -1
> +            if new_uid != -1 or new_gid != -1:
> +                self.g.lchown(new_uid, new_gid, os.path.join('/', member.name))
> +
> +
>  def get_compression_type(tar_file):
>      """
>      Get compression type of tar file.
> diff --git a/src/virtBootstrap/virt_bootstrap.py b/src/virtBootstrap/virt_bootstrap.py
> index 4459ba0..54025d2 100755
> --- a/src/virtBootstrap/virt_bootstrap.py
> +++ b/src/virtBootstrap/virt_bootstrap.py
> @@ -124,6 +124,8 @@ def bootstrap(uri, dest,
>             fmt=fmt,
>             username=username,
>             password=password,
> +           uid_map=uid_map,
> +           gid_map=gid_map,
>             not_secure=not_secure,
>             no_cache=no_cache,
>             progress=prog).unpack(dest)

ACK

--
Cedric




More information about the virt-tools-list mailing list