Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions COMPATIBILITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Sysrepo Compatibility Notes

## Sysrepo 3.x/4.x (SO Version 7-8) Compatibility

This Python wrapper has been updated to work with the upcoming sysrepo 3.x/4.x series
(currently in the devel branch). The changes from sysrepo 2.x to 3.x/4.x include
several function renames and API improvements.

### API Changes Between SO Version 7 and 8

Starting with SO version 8, several connection flags have been changed:

#### Connection Flag Changes (SO 8+)

- **`SR_CONN_CACHE_RUNNING` removed** - This flag has been replaced with a dedicated function:
- Old: Pass `SR_CONN_CACHE_RUNNING` flag to `sr_connect()`
- New: Call `sr_cache_running(1)` to enable or `sr_cache_running(0)` to disable

- **`SR_CONN_CTX_SET_PRIV_PARSED` renamed and moved** - This flag is now in a separate enum:
- Old: Pass `SR_CONN_CTX_SET_PRIV_PARSED` as connection flag
- New: Use `SR_CTX_SET_PRIV_PARSED` from `sr_context_flag_t` enum
- Set via: `sr_context_options(SR_CTX_SET_PRIV_PARSED, apply, &prev_opts)`

The wrapper now uses these new APIs when compiled against SO version 8.

### API Changes Implemented

Based on the compatibility notes in sysrepo's `compatibility/6.0.0_to_7.0.0/CHANGES`,
the following function renames have been incorporated:

#### Renamed Functions (Already Updated)

- `sr_event_notif_send()` → `sr_notif_send()` ✓
- `sr_event_notif_send_tree()` → `sr_notif_send_tree()` ✓
- `sr_event_notif_subscribe()` → `sr_notif_subscribe()` ✓
- `sr_event_notif_subscribe_tree()` → `sr_notif_subscribe_tree()` ✓
- `sr_oper_get_items_subscribe()` → `sr_oper_get_subscribe()` ✓
- `sr_process_events()` → `sr_subscription_process_events()` ✓
- `sr_get_context()` → `sr_acquire_context()` and `sr_release_context()` ✓
- `sr_get_module_access()` → `sr_get_module_ds_access()` ✓

#### Removed Functions (Not Used)

The following functions were removed in sysrepo 3.x but were not used by this wrapper:

- `sr_cancel_update_module()`
- `sr_connection_count()`
- `sr_get_module_info()` (now replaced with different mechanism)

#### Removed Flags (Not Used)

- `SR_SUBSCR_CTX_REUSE` - This flag was removed. The new API requires that subscription
pointers be initialized to NULL on first call. This wrapper already does this correctly
using `ffi.new("sr_subscription_ctx_t **")`.

### New Functions Not Yet Exposed

The following new functions are available in sysrepo 3.x/4.x but not yet exposed by this wrapper:

- `sr_acquire_data()` / `sr_session_acquire_data()` - Helper functions for context-safe data access
- `sr_install_module2()` - Extended module installation with more options
- `sr_install_modules2()` - Batch module installation with more options
- `sr_get_module_replay_support()` - Query notification replay support
- `sr_check_module_ds_access()` - Check datastore access permissions
- `sr_get_su_uid()` - Get sysrepo superuser UID
- `sr_subscription_thread_suspend()` / `sr_subscription_thread_resume()` - Thread control

These functions can be added in future versions if needed.

### Changed Function Signatures

#### `sr_get_module_ds_access()`

Changed from:
```c
int sr_get_module_ds_access(sr_conn_ctx_t *conn, const char *module_name,
sr_datastore_t datastore, char **owner, char **group, mode_t *perm);
```

To:
```c
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);
```

The `sr_datastore_t` enum was replaced with a plain `int` to allow for more flexible
datastore specification. This change is already reflected in `cffi/cdefs.h`.

### Context Management Changes

The biggest change is how the libyang context is accessed:

- **Old API**: `sr_get_context()` returned a const context pointer directly
- **New API**: `sr_acquire_context()` acquires a READ LOCK on the context and must be
paired with `sr_release_context()` to release the lock

This is important because the context can be changed at any point (e.g., when modules
are installed/removed), so locking ensures safe concurrent access.

The wrapper properly implements this pattern using context managers:
```python
with conn.get_ly_ctx() as ctx:
# use ctx safely
# context is automatically released
```

### Testing Compatibility

To test with the sysrepo devel branch:

```bash
SYSREPO_BRANCH=devel LIBYANG_BRANCH=devel python3 -m tox -e py312
```

The `tox-install.sh` script will clone and build the specified branches of libyang
and sysrepo before running tests.

### Migration from Older Versions

If you're using an older version of sysrepo-python with sysrepo 2.x, no code changes
should be required. The wrapper maintains backward compatibility with sysrepo 2.2.0+.

### Version Support Matrix

| sysrepo-python | Sysrepo C Library | SO Version | Notes |
|----------------|-------------------|------------|-------|
| 2.x.x (current) | 2.2.0 - 4.x.x | 6 - 8 | Compatible with both stable and devel |
| 1.x.x | 1.x.x | < 6 | EOL, use sysrepo-python 0.7.0 |
| 0.7.0 | 1.x.x | < 6 | Last version for sysrepo 1.x |

### Additional Resources

- [Sysrepo Repository](https://github.com/sysrepo/sysrepo)
- [Sysrepo Devel Branch](https://github.com/sysrepo/sysrepo/tree/devel)
- [Sysrepo Compatibility Documentation](https://github.com/sysrepo/sysrepo/tree/devel/compatibility)
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ On a Debian/Ubuntu system:
Compatibility
-------------

The current version requires at least C `sysrepo 2.2.0`__.
The current version works with C `sysrepo 2.2.0`__ and later, including the upcoming sysrepo 3.x/4.x series from the devel branch.

The last version of the bindings that works with C `sysrepo 1.x`__ is v0.7.0__.

__ https://github.com/sysrepo/sysrepo/commit/8c48a7a50eb2
__ https://github.com/sysrepo/sysrepo/tree/devel
__ https://github.com/sysrepo/sysrepo/tree/libyang1
__ https://pypi.org/project/sysrepo/0.7.0/

Expand Down
11 changes: 9 additions & 2 deletions cffi/cdefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,15 @@ sr_log_level_t sr_log_get_syslog(void);
typedef struct sr_conn_ctx_s sr_conn_ctx_t;
typedef struct sr_session_ctx_s sr_session_ctx_t;
typedef enum sr_conn_flag_e {
SR_CONN_CACHE_RUNNING,
SR_CONN_CTX_SET_PRIV_PARSED,
SR_CONN_DEFAULT,
...
} sr_conn_flag_t;
typedef enum sr_context_flag_e {
SR_CTX_DEFAULT,
SR_CTX_NO_PRINTED,
SR_CTX_SET_PRIV_PARSED,
...
} sr_context_flag_t;
typedef uint32_t sr_conn_options_t;
typedef enum sr_datastore_e {
SR_DS_STARTUP,
Expand Down Expand Up @@ -78,6 +83,8 @@ struct timespec {

int sr_connect(const sr_conn_options_t, sr_conn_ctx_t **);
int sr_disconnect(sr_conn_ctx_t *);
void sr_cache_running(int);
int sr_context_options(uint32_t, int, uint32_t *);
const struct ly_ctx *sr_acquire_context(sr_conn_ctx_t *);
void sr_release_context(sr_conn_ctx_t *);
int sr_install_module(sr_conn_ctx_t *, const char *, const char *, const char **);
Expand Down
6 changes: 3 additions & 3 deletions cffi/source.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
#include <sysrepo/version.h>
#include <sysrepo/netconf_acm.h>

#if (SR_VERSION_MAJOR != 7)
#error "This version of sysrepo bindings only works with libsysrepo.so.7"
#if (SR_VERSION_MAJOR < 7 || SR_VERSION_MAJOR > 8)
#error "This version of sysrepo bindings only works with libsysrepo.so.7 or libsysrepo.so.8"
#endif
#if (SR_VERSION_MINOR < 10)
#if (SR_VERSION_MAJOR == 7 && SR_VERSION_MINOR < 10)
#error "Need at least libsysrepo.so.7.10"
#endif
15 changes: 8 additions & 7 deletions sysrepo/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,20 @@ def __init__(self, cache_running: bool = False):
Always cache running datastore data which makes mainly repeated retrieval of
data much faster. Affects all sessions created on this connection.
"""
flags = 0
# Set context options to work with libyang-python
# This must be done before creating the connection
check_call(lib.sr_context_options, lib.SR_CTX_SET_PRIV_PARSED, 0, ffi.NULL)

# Enable running cache if requested
if cache_running:
flags |= lib.SR_CONN_CACHE_RUNNING

# mandatory flag to work with libyang-python
flags |= lib.SR_CONN_CTX_SET_PRIV_PARSED
lib.sr_cache_running(1)

conn_p = ffi.new("sr_conn_ctx_t **")
# valid_signals() is only available since python 3.8
valid_signals = getattr(signal, "valid_signals", lambda: range(1, signal.NSIG))
sigmask = signal.pthread_sigmask(signal.SIG_BLOCK, valid_signals())
try:
check_call(lib.sr_connect, flags, conn_p)
check_call(lib.sr_connect, 0, conn_p)
self.cdata = ffi.gc(conn_p[0], lib.sr_disconnect)
finally:
signal.pthread_sigmask(signal.SIG_SETMASK, sigmask)
Expand Down Expand Up @@ -110,7 +111,7 @@ def acquire_context(self) -> libyang.Context:
"""
ctx = lib.sr_acquire_context(self.cdata)
if not ctx:
raise SysrepoInternalError("sr_get_context failed")
raise SysrepoInternalError("sr_acquire_context failed")
return libyang.Context(cdata=ctx)

def release_context(self):
Expand Down
2 changes: 1 addition & 1 deletion sysrepo/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def acquire_context(self) -> libyang.Context:
raise SysrepoInternalError("sr_session_get_connection failed")
ctx = lib.sr_acquire_context(conn)
if not ctx:
raise SysrepoInternalError("sr_get_context failed")
raise SysrepoInternalError("sr_acquire_context failed")

return libyang.Context(cdata=ctx)

Expand Down