diff --git a/README.rst b/README.rst index 0f47b41..264518a 100644 --- a/README.rst +++ b/README.rst @@ -158,10 +158,10 @@ Supported Features __ https://pypi.org/project/libyang/ .. _async: https://docs.python.org/3/library/asyncio-task.html#coroutine -Not Yet Supported Features --------------------------- +Partially Supported Features +---------------------------- -All other features are not yet supported by sysrepo-python. The most notable +All other features are not yet or only partially supported by sysrepo-python. The most notable are: - Module management (``sr_*_module_*``) diff --git a/cffi/cdefs.h b/cffi/cdefs.h index e38e64b..fb5db03 100644 --- a/cffi/cdefs.h +++ b/cffi/cdefs.h @@ -292,3 +292,6 @@ int sr_notif_subscribe_tree(sr_session_ctx_t *, const char *module_name, const c void *priv, sr_subscr_options_t, sr_subscription_ctx_t **); int sr_notif_send_tree(sr_session_ctx_t *, struct lyd_node *notif, uint32_t timeout_ms, int wait); + +typedef int... mode_t; +int sr_get_module_ds_access(sr_conn_ctx_t *conn, const char *module_name, int mod_ds, char **owner, char **group, mode_t *perm); diff --git a/sysrepo/connection.py b/sysrepo/connection.py index f1b3b48..a4845e6 100644 --- a/sysrepo/connection.py +++ b/sysrepo/connection.py @@ -4,14 +4,14 @@ from contextlib import contextmanager import logging import signal -from typing import Dict, Optional, Sequence +from typing import Dict, Optional, Sequence, Tuple import libyang from _sysrepo import ffi, lib from .errors import SysrepoInternalError, check_call from .session import SysrepoSession, datastore_value -from .util import str2c +from .util import c2str, str2c LOG = logging.getLogger(__name__) @@ -279,3 +279,31 @@ def enable_module_feature(self, name: str, feature_name: str) -> None: check_call( lib.sr_enable_module_feature, self.cdata, str2c(name), str2c(feature_name) ) + + def get_module_ds_access( + self, module_name: str, datastore: str = "running" + ) -> Tuple[str, str, int]: + """ + Learn about module permissions. + + :arg str module_name: + Name of the module. + :arg str datastore: + Name of the datastore that will be operated on. + :returns: + The owner, group and permissions of the given module name. + Owner and group are names, not numeric ids. + """ + owner = ffi.new("char **owner") + group = ffi.new("char **group") + perm = ffi.new("mode_t *perm") + check_call( + lib.sr_get_module_ds_access, + self.cdata, + str2c(module_name), + datastore_value(datastore), + owner, + group, + perm, + ) + return (c2str(owner[0]), c2str(group[0]), perm[0]) diff --git a/tests/test_connection.py b/tests/test_connection.py index d250d15..eeb2b84 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -1,8 +1,10 @@ # Copyright (c) 2020 6WIND S.A. # SPDX-License-Identifier: BSD-3-Clause +import grp import logging import os +import pwd import unittest import libyang @@ -77,3 +79,11 @@ def test_conn_enable_module_feature(self): data = [x for x in data if x["name"] == "sysrepo-example"][0] self.assertIn("feature", data) conn.remove_module("sysrepo-example") + + def test_conn_get_module_infos(self): + with sysrepo.SysrepoConnection() as conn: + conn.install_module(YANG_FILE) + owner, group, perm = conn.get_module_ds_access("sysrepo-example") + self.assertEqual(pwd.getpwnam(owner).pw_uid, os.geteuid()) + self.assertEqual(grp.getgrnam(group).gr_gid, os.getegid()) + self.assertEqual(perm, 0o600)