@@ -24,7 +24,9 @@ from .volume import command_volume_create, \ | |||
command_volume_untag, \ | |||
command_volume_remove, \ | |||
command_volume_set, \ | |||
command_volume_get | |||
command_volume_get, \ | |||
command_volume_protect, \ | |||
command_volume_unprotect | |||
import sys | |||
from .zfs import zfs_init | |||
from .jail import command_jail_create, \ | |||
@@ -209,6 +211,14 @@ def create_parser(): | |||
parser.add_argument('reference', type=str) | |||
parser.add_argument('properties', type=str, nargs=argparse.REMAINDER) | |||
parser = ListForwarder([subparsers.add_parser(cmd) for cmd in ['protect']]) | |||
parser.set_defaults(func=command_volume_protect) | |||
parser.add_argument('references', type=str, nargs='+') | |||
parser = ListForwarder([subparsers.add_parser(cmd) for cmd in ['unprotect']]) | |||
parser.set_defaults(func=command_volume_unprotect) | |||
parser.add_argument('references', type=str, nargs='+') | |||
# compose | |||
subparsers = ListForwarder([ subparsers_top.add_parser(cmd).add_subparsers(dest='L2_command') \ | |||
for cmd in ['compose', 'comp', 'c'] ]) | |||
@@ -51,7 +51,7 @@ def command_volume_remove(args): | |||
try: | |||
name, _ = zfs_find(ref, focker_type='volume') | |||
print('Removing:', name) | |||
zfs_run(['zfs', 'destroy', '-r', '-f', name]) | |||
zfs_destroy(name) | |||
except: | |||
if not args.force: | |||
raise | |||
@@ -71,3 +71,17 @@ def command_volume_get(args): | |||
res = zfs_parse_output(['zfs', 'get', '-H', ','.join(args.properties), name]) | |||
res = [ [ args.properties[i], a[2] ] for i, a in enumerate(res) ] | |||
print(tabulate(res, headers=['Property', 'Value'])) | |||
def command_volume_protect(args): | |||
for ref in args.references: | |||
name, _ = zfs_find(ref, focker_type='volume') | |||
print('Protecting:', name) | |||
zfs_protect(name) | |||
def command_volume_unprotect(args): | |||
for ref in args.references: | |||
name, _ = zfs_find(ref, focker_type='volume') | |||
print('Unprotecting:', name) | |||
zfs_unprotect(name) |
@@ -83,7 +83,7 @@ def zfs_prune(focker_type='image'): | |||
again = True | |||
while again: | |||
again = False | |||
lst = zfs_parse_output(['zfs', 'list', '-o', 'focker:sha256,focker:tags,origin,name', '-H', '-r', poolname + '/focker/' + focker_type + 's']) | |||
lst = zfs_parse_output(['zfs', 'list', '-o', 'focker:sha256,focker:tags,origin,name,focker:protect', '-H', '-r', poolname + '/focker/' + focker_type + 's']) | |||
used = set() | |||
for r in lst: | |||
if r[2] == '-': | |||
@@ -92,10 +92,29 @@ def zfs_prune(focker_type='image'): | |||
for r in lst: | |||
if r[0] == '-' or r[1] != '-': | |||
continue | |||
if r[3] not in used: | |||
print('Removing:', r[3]) | |||
zfs_run(['zfs', 'destroy', '-r', '-f', r[3]]) | |||
again = True | |||
if r[3] in used: | |||
continue | |||
if r[4] != '-': | |||
print('%s is protected against removal' % r[3]) | |||
continue | |||
print('Removing:', r[3]) | |||
zfs_run(['zfs', 'destroy', '-r', '-f', r[3]]) | |||
again = True | |||
def zfs_destroy(name): | |||
lst = zfs_parse_output(['zfs', 'get', '-H', 'focker:protect', name]) | |||
if lst[0][2] != '-': | |||
raise RuntimeError('%s is protected against removal' % name) | |||
zfs_run(['zfs', 'destroy', '-r', '-f', name]) | |||
def zfs_protect(name): | |||
zfs_run(['zfs', 'set', 'focker:protect=on', name]) | |||
def zfs_unprotect(name): | |||
zfs_run(['zfs', 'inherit', '-r', 'focker:protect', name]) | |||
def zfs_clone(name, target_name): | |||
@@ -7,13 +7,19 @@ from focker.volume import command_volume_create, \ | |||
command_volume_untag, \ | |||
command_volume_remove, \ | |||
command_volume_set, \ | |||
command_volume_get | |||
command_volume_get, \ | |||
command_volume_protect, \ | |||
command_volume_unprotect | |||
from focker.zfs import zfs_find, \ | |||
zfs_mountpoint, \ | |||
zfs_exists, \ | |||
zfs_parse_output | |||
zfs_parse_output, \ | |||
zfs_destroy, \ | |||
zfs_prune, \ | |||
zfs_run | |||
import os | |||
import focker.volume | |||
import focker.zfs | |||
def test_command_volume_create(): | |||
@@ -162,3 +168,52 @@ def test_command_volume_get(monkeypatch): | |||
assert headers == [ 'Property', 'Value' ] | |||
# assert lst == ['on', '1G'] | |||
subprocess.check_output(['focker', 'volume', 'remove', 'test-command-volume-get']) | |||
def test_command_volume_protect(monkeypatch): | |||
subprocess.check_output(['focker', 'volume', 'remove', '--force', 'test-command-volume-protect']) | |||
subprocess.check_output(['focker', 'volume', 'create', '-t', 'test-command-volume-protect']) | |||
args = lambda: 0 | |||
args.references = ['test-command-volume-protect'] | |||
command_volume_protect(args) | |||
name, sha256 = zfs_find('test-command-volume-protect', focker_type='volume') | |||
mountpoint = zfs_mountpoint(name) | |||
lst = zfs_parse_output(['zfs', 'get', '-H', 'focker:protect', name]) | |||
assert len(lst) == 1 | |||
assert lst[0][2] == 'on' | |||
with pytest.raises(RuntimeError): | |||
zfs_destroy(name) | |||
subprocess.check_output(['focker', 'volume', 'untag', 'test-command-volume-protect']) | |||
lst = zfs_parse_output(['zfs', 'get', '-H', 'focker:tags', name]) | |||
assert len(lst) == 1 | |||
assert lst[0][2] == '-' | |||
n_called = 0 | |||
def fake_run(*args, **kwargs): | |||
nonlocal n_called | |||
n_called += 1 | |||
return zfs_run(*args, **kwargs) | |||
monkeypatch.setattr(focker.zfs, 'zfs_run', fake_run) | |||
zfs_prune(focker_type='volume') | |||
assert not n_called == 1 | |||
with pytest.raises(subprocess.CalledProcessError): | |||
subprocess.check_output(['focker', 'volume', 'remove', sha256]) | |||
subprocess.check_output(['zfs', 'destroy', '-r', '-f', name]) | |||
assert not zfs_exists(name) | |||
assert not os.path.exists(mountpoint) | |||
def test_command_volume_unprotect(): | |||
subprocess.check_output(['focker', 'volume', 'remove', '--force', 'test-command-volume-unprotect']) | |||
subprocess.check_output(['focker', 'volume', 'create', '-t', 'test-command-volume-unprotect']) | |||
subprocess.check_output(['focker', 'volume', 'protect', 'test-command-volume-unprotect']) | |||
name, _ = zfs_find('test-command-volume-unprotect', focker_type='volume') | |||
lst = zfs_parse_output(['zfs', 'get', '-H', 'focker:protect', name]) | |||
assert len(lst) == 1 | |||
assert lst[0][2] == 'on' | |||
args = lambda: 0 | |||
args.references = ['test-command-volume-unprotect'] | |||
command_volume_unprotect(args) | |||
lst = zfs_parse_output(['zfs', 'get', '-H', 'focker:protect', name]) | |||
assert len(lst) == 1 | |||
assert lst[0][2] == '-' | |||
subprocess.check_output(['focker', 'volume', 'remove', 'test-command-volume-unprotect']) |