[virt-tools-list] [virt-bootstrap] [PATCH v3 05/12] bootstrap: Implement UID/GID mapping
Radostin Stoyanov
rstoyanov1 at gmail.com
Thu Jul 20 11:29:40 UTC 2017
When Libvirt creates LXC container with enabled user namespace the
ownership of files in the container should be mapped to the specified
target UID/GID.
Files and directories in the root file system are mapped as foll:
New file's UID/GID = Target UID/GID + File's UID/GID - User's UID/GID
Example:
- User which creates container: uid/gid = 0
- File extracted from container image: uid/gid = 0
- Target: uid/gid = 1000
New file's uid/gid: 1000 = 1000 + 0 - 0
The new file's uid/gid will be 1000 on the host and 0 inside container
with:
```xml
<idmap>
<uid start='0' target='1000' count='10'/>
<gid start='0' target='1000' count='10'/>
</idmap>
```
---
src/virtBootstrap/virt_bootstrap.py | 53 +++++++++++++++++++++++++++++++++----
1 file changed, 48 insertions(+), 5 deletions(-)
diff --git a/src/virtBootstrap/virt_bootstrap.py b/src/virtBootstrap/virt_bootstrap.py
index 98c629a..588d1f7 100755
--- a/src/virtBootstrap/virt_bootstrap.py
+++ b/src/virtBootstrap/virt_bootstrap.py
@@ -69,12 +69,36 @@ def get_source(source_type):
raise Exception("Invalid image URL scheme: '%s'" % source_type)
+def map_id(path, map_uid, map_gid):
+ """
+ Map the ownership of files in the root file system
+
+ New file's UID/GID = Mapped UID/GID + File's UID/GID - User's UID/GID
+ """
+ user_uid = os.geteuid()
+ user_gid = os.getegid()
+ path = os.path.realpath(path)
+
+ for root, _ignore, files in os.walk(path):
+ for name in [root] + files:
+
+ filepath = os.path.join(root, name)
+ stat_info = os.lstat(filepath)
+ file_uid = stat_info.st_uid
+ file_gid = stat_info.st_gid
+
+ new_uid = map_uid + (file_uid - user_uid)
+ new_gid = map_gid + (file_gid - user_gid)
+ os.lchown(filepath, new_uid, new_gid)
+
+
# pylint: disable=too-many-arguments
def bootstrap(uri, dest,
fmt='dir',
username=None,
password=None,
root_password=None,
+ idmap=None,
not_secure=False,
no_cache=False,
progress_cb=None):
@@ -104,9 +128,14 @@ def bootstrap(uri, dest,
no_cache=no_cache,
progress=prog).unpack(dest)
- if fmt == "dir" and root_password is not None:
- logger.info("Setting password of the root account")
- utils.set_root_password(dest, root_password)
+ if fmt == "dir":
+ if root_password is not None:
+ logger.info("Setting password of the root account")
+ utils.set_root_password(dest, root_password)
+
+ if idmap is not None:
+ logger.info("Mapping UID/GID")
+ map_id(dest, *idmap)
def set_logging_conf(loglevel=None):
@@ -157,6 +186,8 @@ def main():
help=_("Password for accessing the source registry"))
parser.add_argument("--root-password", default=None,
help=_("Root password to set in the created rootfs"))
+ parser.add_argument("-i", "--idmap", default=None,
+ help=_("UID / GID mapping of the created rootfs"))
parser.add_argument("--no-cache", action="store_true",
help=_("Do not store downloaded Docker images"))
parser.add_argument("-f", "--format", default='dir',
@@ -173,8 +204,6 @@ def main():
help=_("Show only the current status and progress"
"of virt-bootstrap"))
- # TODO add UID / GID mapping parameters
-
try:
args = parser.parse_args()
@@ -182,6 +211,19 @@ def main():
# Configure logging lovel/format
set_logging_conf(args.loglevel)
+ idmap = None
+ if args.idmap:
+ try:
+ uid, gid = args.idmap.split(':')
+ idmap = (int(uid), int(gid))
+ except Exception:
+ msg = ("Invalid UID / GID mapping value.\n"
+ "Supported format:\n\t"
+ "<uid>:<gid>\n"
+ "Example:\n\t"
+ "virt-bootstrap docker://fedora /tmp/foo -i 1000:1000")
+ raise ValueError(msg)
+
# do the job here!
bootstrap(uri=args.uri,
dest=args.dest,
@@ -189,6 +231,7 @@ def main():
username=args.username,
password=args.password,
root_password=args.root_password,
+ idmap=idmap,
not_secure=args.not_secure,
no_cache=args.no_cache,
progress_cb=args.status_only)
--
2.9.4
More information about the virt-tools-list
mailing list