[virt-tools-list] [virt-bootstrap] [PATCH v2 07/14] Enable UID/GID mapping for qcow2
Radostin Stoyanov
rstoyanov1 at gmail.com
Tue Aug 1 11:28:48 UTC 2017
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)
--
2.13.3
More information about the virt-tools-list
mailing list