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:
parent
b57376d160
commit
1e4507c3d6
2 changed files with 101 additions and 0 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue