util/ostree: new class to store subordinate ids

Add a new class `SubIdsDB` as a database of subordinate Ids, like the
ones in `/etc/subuid` and `/etc/subgid`. Methods to read and write
data from these two files are provided.
Add corresponding unit tests.
This commit is contained in:
Christian Kellner 2022-04-27 21:32:18 +02:00 committed by Tom Gundersen
parent b57376d160
commit 1e4507c3d6
2 changed files with 101 additions and 0 deletions

View file

@ -1,7 +1,9 @@
import collections
import contextlib
import json
import os
import subprocess
import sys
import tempfile
import typing
@ -186,3 +188,51 @@ class PasswdLike:
def _passwd_lines_to_dict(lines):
"""Take a list of passwd lines and produce a "name": "line" dictionary"""
return {line.split(':')[0]: line for line in lines}
class SubIdsDB:
"""Represention of subordinate Ids database
Class to represent a mapping of a user name to subordinate ids,
like `/etc/subgid` and `/etc/subuid`.
"""
def __init__(self) -> None:
self.db = collections.OrderedDict()
def read(self, fp) -> int:
idx = 0
for idx, line in enumerate(fp.readlines()):
line = line.strip()
if not line or line.startswith("#"):
continue
comps = line.split(":")
if len(comps) != 3:
print(f"WARNING: invalid line `{line}`", file=sys.stderr)
continue
name, uid, count = comps
self.db[name] = (uid, count)
return idx
def dumps(self) -> str:
"""Dump the database to a string"""
data = "\n".join([
f"{name}:{uid}:{count}\n"
for name, (uid, count) in self.db.items()
])
return data
def read_from(self, path: PathLike) -> int:
"""Read a file and add the entries to the database"""
with open(path, "r", encoding="utf-8") as f:
return self.read(f)
def write_to(self, path: PathLike) -> None:
"""Write the database to a file"""
data = self.dumps()
with open(path, "w", encoding="utf-8") as f:
f.write(data)
def __bool__(self) -> bool:
return bool(self.db)

View file

@ -2,6 +2,7 @@
# Tests for the 'osbuild.util.ostree' module.
#
import io
import json
import os
import subprocess
@ -147,3 +148,53 @@ class TestPasswdLike(unittest.TestCase):
with open(os.path.join(tmpdir, "result"), "r") as f:
self.assertEqual(sorted(f.readlines()), sorted(result_file_lines))
#pylint: disable=no-self-use
def test_subids_cfg(self):
with tempfile.TemporaryDirectory() as tmpdir:
first = [
"gicmo:100000:65536",
"achilles:100000:65536",
"ondrej:100000:65536"
]
txt = io.StringIO("\n".join(first))
subids = ostree.SubIdsDB()
subids.read(txt)
assert len(subids.db) == 3
for name in ("gicmo", "achilles", "ondrej"):
assert name in subids.db
uid, count = subids.db[name]
assert uid == "100000"
assert count == "65536"
second = [
"gicmo:200000:1000",
"tom:200000:1000",
"lars:200000:1000"
]
txt = io.StringIO("\n".join(second))
subids.read(txt)
assert len(subids.db) == 5
for name in ("gicmo", "achilles", "tom", "lars"):
assert name in subids.db
for name in ("gicmo", "tom", "lars"):
uid, count = subids.db[name]
assert uid == "200000"
assert count == "1000"
file = os.path.join(tmpdir, "subuid")
subids.write_to(file)
check = ostree.SubIdsDB()
check.read_from(file)
assert subids.db == check.db