-
Notifications
You must be signed in to change notification settings - Fork 497
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
NAS-132120 / 25.10 / Add API to enable ZFS snapdir access over NFS (b…
…y anodos325) (#15712) This commit adds support for the new exports "zfs_snapdir" line for enterprise customers.
- Loading branch information
Showing
6 changed files
with
185 additions
and
1 deletion.
There are no files selected for viewing
21 changes: 21 additions & 0 deletions
21
src/middlewared/middlewared/alembic/versions/25.04/2025-02-14_15-13_nfs_add_snapdir.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
"""Add zfs_snapdir to NFS exports | ||
Revision ID: d908d564231d | ||
Revises: 673dd6925aba | ||
Create Date: 2025-02-14 15:13:59.521506+00:00 | ||
""" | ||
from alembic import op | ||
import sqlalchemy as sa | ||
|
||
|
||
# revision identifiers, used by Alembic. | ||
revision = 'd908d564231d' | ||
down_revision = '673dd6925aba' | ||
branch_labels = None | ||
depends_on = None | ||
|
||
|
||
def upgrade(): | ||
with op.batch_alter_table('sharing_nfs_share', schema=None) as batch_op: | ||
batch_op.add_column(sa.Column('nfs_expose_snapshots', sa.Boolean(), nullable=False, server_default='0')) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import pytest | ||
|
||
from middlewared.test.integration.assets.filesystem import directory | ||
from middlewared.test.integration.assets.pool import dataset | ||
from middlewared.test.integration.assets.product import product_type | ||
from middlewared.test.integration.utils import call, ssh, password | ||
from middlewared.test.integration.utils.client import truenas_server | ||
from middlewared.service_exception import ValidationErrors | ||
from protocols import SSH_NFS | ||
|
||
SNAPDIR_EXPORTS_ENTRY = 'zfs_snapdir' | ||
|
||
|
||
@pytest.fixture(scope='module') | ||
def start_nfs(): | ||
call('service.start', 'nfs') | ||
yield | ||
call('service.stop', 'nfs') | ||
|
||
|
||
@pytest.fixture(scope='function') | ||
def enterprise(): | ||
with product_type(): | ||
yield | ||
|
||
|
||
@pytest.fixture(scope='module') | ||
def nfs_dataset(): | ||
with dataset('nfs_snapdir') as ds: | ||
ssh(f'echo -n Cats > /mnt/{ds}/canary') | ||
call('zfs.snapshot.create', {'dataset': ds, 'name': 'now'}) | ||
yield ds | ||
|
||
|
||
@pytest.fixture(scope='function') | ||
def community(): | ||
with product_type('COMMUNITY_EDITION'): | ||
yield | ||
|
||
|
||
@pytest.fixture(scope='function') | ||
def nfs_export(nfs_dataset): | ||
share = call('sharing.nfs.create', {'path': f'/mnt/{nfs_dataset}'}) | ||
try: | ||
yield share['id'] | ||
finally: | ||
call('sharing.nfs.delete', share['id']) | ||
|
||
|
||
def test__snapdir_community_fail_create(community, nfs_dataset): | ||
with pytest.raises(ValidationErrors, match='This is an enterprise feature'): | ||
share = call('sharing.nfs.create', { | ||
'path': f'/mnt/{nfs_dataset}', | ||
'expose_snapshots': True | ||
}) | ||
# cleanup just in case test failed | ||
call('sharing.nfs.delete', share['id']) | ||
|
||
|
||
def test__snapdir_community_fail_update(community, nfs_export): | ||
with pytest.raises(ValidationErrors, match='This is an enterprise feature'): | ||
call('sharing.nfs.update', nfs_export, {'expose_snapshots': True}) | ||
|
||
|
||
def test__snapdir_enterprise_fail_subdir(enterprise, nfs_dataset): | ||
with directory(f'/mnt/{nfs_dataset}/subdir') as d: | ||
with pytest.raises(ValidationErrors, match='not the root directory of a dataset'): | ||
share = call('sharing.nfs.create', { | ||
'path': d, | ||
'expose_snapshots': True | ||
}) | ||
# cleanup just in case test failed | ||
call('sharing.nfs.delete', share['id']) | ||
|
||
|
||
def test__snapdir_enable_enterprise_create(start_nfs, enterprise, nfs_dataset): | ||
""" check that create sets correct exports line """ | ||
share = call('sharing.nfs.create', { | ||
'path': f'/mnt/{nfs_dataset}', | ||
'expose_snapshots': True | ||
}) | ||
|
||
try: | ||
assert share['expose_snapshots'] is True | ||
exports = ssh('cat /etc/exports') | ||
assert SNAPDIR_EXPORTS_ENTRY in exports | ||
finally: | ||
call('sharing.nfs.delete', share['id']) | ||
|
||
|
||
def test__snapdir_enable_enterprise_update(start_nfs, enterprise, nfs_export): | ||
""" check that update sets correct exports line """ | ||
exports = ssh('cat /etc/exports') | ||
assert SNAPDIR_EXPORTS_ENTRY not in exports | ||
|
||
share = call('sharing.nfs.update', nfs_export, {'expose_snapshots': True}) | ||
assert share['expose_snapshots'] is True | ||
|
||
exports = ssh('cat /etc/exports') | ||
assert SNAPDIR_EXPORTS_ENTRY in exports | ||
|
||
share = call('sharing.nfs.update', nfs_export, {'expose_snapshots': False}) | ||
assert share['expose_snapshots'] is False | ||
|
||
exports = ssh('cat /etc/exports') | ||
assert SNAPDIR_EXPORTS_ENTRY not in exports | ||
|
||
|
||
@pytest.mark.parametrize('vers', [3, 4]) | ||
def test__snapdir_functional(start_nfs, enterprise, nfs_dataset, nfs_export, vers): | ||
share = call('sharing.nfs.update', nfs_export, {'expose_snapshots': True}) | ||
assert share['expose_snapshots'] is True | ||
call('service.stop', 'nfs') | ||
call('service.start', 'nfs', {'silent': False}) | ||
with SSH_NFS( | ||
hostname=truenas_server.ip, | ||
path=f'/mnt/{nfs_dataset}', | ||
vers=vers, | ||
user='root', | ||
password=password(), | ||
ip=truenas_server.ip | ||
) as n: | ||
|
||
contents = n.ls('.') | ||
assert 'canary' in contents | ||
|
||
snapdir_contents = n.ls('.zfs/snapshot/now') | ||
assert 'canary' in snapdir_contents |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters