12fb4439dSAlexander Pyhalov#!@PYTHON@ 214843421SMatthew Ahrens# 314843421SMatthew Ahrens# CDDL HEADER START 414843421SMatthew Ahrens# 514843421SMatthew Ahrens# The contents of this file are subject to the terms of the 614843421SMatthew Ahrens# Common Development and Distribution License (the "License"). 714843421SMatthew Ahrens# You may not use this file except in compliance with the License. 814843421SMatthew Ahrens# 914843421SMatthew Ahrens# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 1014843421SMatthew Ahrens# or http://www.opensolaris.org/os/licensing. 1114843421SMatthew Ahrens# See the License for the specific language governing permissions 1214843421SMatthew Ahrens# and limitations under the License. 1314843421SMatthew Ahrens# 1414843421SMatthew Ahrens# When distributing Covered Code, include this CDDL HEADER in each 1514843421SMatthew Ahrens# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1614843421SMatthew Ahrens# If applicable, add the following below this CDDL HEADER, with the 1714843421SMatthew Ahrens# fields enclosed by brackets "[]" replaced with your own identifying 1814843421SMatthew Ahrens# information: Portions Copyright [yyyy] [name of copyright owner] 1914843421SMatthew Ahrens# 2014843421SMatthew Ahrens# CDDL HEADER END 2114843421SMatthew Ahrens# 226d52f363SLori Alt# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 23*d561bb99SAndy Fiddaman# Copyright 2018 OmniOS Community Edition (OmniOSce) Association. 2414843421SMatthew Ahrens# 2514843421SMatthew Ahrens 2614843421SMatthew Ahrens"""Implements the Dataset class, providing methods for manipulating ZFS 2714843421SMatthew Ahrensdatasets. Also implements the Property class, which describes ZFS 2814843421SMatthew Ahrensproperties.""" 2914843421SMatthew Ahrens 3014843421SMatthew Ahrensimport zfs.ioctl 3114843421SMatthew Ahrensimport zfs.util 3214843421SMatthew Ahrensimport errno 3314843421SMatthew Ahrens 3414843421SMatthew Ahrens_ = zfs.util._ 3514843421SMatthew Ahrens 3614843421SMatthew Ahrensclass Property(object): 3714843421SMatthew Ahrens """This class represents a ZFS property. It contains 3814843421SMatthew Ahrens information about the property -- if it's readonly, a number vs 3914843421SMatthew Ahrens string vs index, etc. Only native properties are represented by 4014843421SMatthew Ahrens this class -- not user properties (eg "user:prop") or userspace 4114843421SMatthew Ahrens properties (eg "userquota@joe").""" 4214843421SMatthew Ahrens 4314843421SMatthew Ahrens __slots__ = "name", "number", "type", "default", "attr", "validtypes", \ 4414843421SMatthew Ahrens "values", "colname", "rightalign", "visible", "indextable" 4514843421SMatthew Ahrens __repr__ = zfs.util.default_repr 4614843421SMatthew Ahrens 4714843421SMatthew Ahrens def __init__(self, t): 4814843421SMatthew Ahrens """t is the tuple of information about this property 4914843421SMatthew Ahrens from zfs.ioctl.get_proptable, which should match the 5014843421SMatthew Ahrens members of zprop_desc_t (see zfs_prop.h).""" 5114843421SMatthew Ahrens 5214843421SMatthew Ahrens self.name = t[0] 5314843421SMatthew Ahrens self.number = t[1] 5414843421SMatthew Ahrens self.type = t[2] 5514843421SMatthew Ahrens if self.type == "string": 5614843421SMatthew Ahrens self.default = t[3] 5714843421SMatthew Ahrens else: 5814843421SMatthew Ahrens self.default = t[4] 5914843421SMatthew Ahrens self.attr = t[5] 6014843421SMatthew Ahrens self.validtypes = t[6] 6114843421SMatthew Ahrens self.values = t[7] 6214843421SMatthew Ahrens self.colname = t[8] 6314843421SMatthew Ahrens self.rightalign = t[9] 6414843421SMatthew Ahrens self.visible = t[10] 6514843421SMatthew Ahrens self.indextable = t[11] 6614843421SMatthew Ahrens 6714843421SMatthew Ahrens def delegatable(self): 6814843421SMatthew Ahrens """Return True if this property can be delegated with 6914843421SMatthew Ahrens "zfs allow".""" 7014843421SMatthew Ahrens return self.attr != "readonly" 7114843421SMatthew Ahrens 7214843421SMatthew Ahrensproptable = dict() 73*d561bb99SAndy Fiddamanfor name, t in zfs.ioctl.get_proptable().items(): 7414843421SMatthew Ahrens proptable[name] = Property(t) 7514843421SMatthew Ahrensdel name, t 7614843421SMatthew Ahrens 7714843421SMatthew Ahrensdef getpropobj(name): 7814843421SMatthew Ahrens """Return the Property object that is identified by the given 7914843421SMatthew Ahrens name string. It can be the full name, or the column name.""" 8014843421SMatthew Ahrens try: 8114843421SMatthew Ahrens return proptable[name] 8214843421SMatthew Ahrens except KeyError: 83*d561bb99SAndy Fiddaman for p in proptable.values(): 8414843421SMatthew Ahrens if p.colname and p.colname.lower() == name: 8514843421SMatthew Ahrens return p 8614843421SMatthew Ahrens raise 8714843421SMatthew Ahrens 8814843421SMatthew Ahrensclass Dataset(object): 8914843421SMatthew Ahrens """Represents a ZFS dataset (filesystem, snapshot, zvol, clone, etc). 9014843421SMatthew Ahrens 9114843421SMatthew Ahrens Generally, this class provides interfaces to the C functions in 9214843421SMatthew Ahrens zfs.ioctl which actually interface with the kernel to manipulate 9314843421SMatthew Ahrens datasets. 9414843421SMatthew Ahrens 9514843421SMatthew Ahrens Unless otherwise noted, any method can raise a ZFSError to 9614843421SMatthew Ahrens indicate failure.""" 9714843421SMatthew Ahrens 9814843421SMatthew Ahrens __slots__ = "name", "__props" 9914843421SMatthew Ahrens __repr__ = zfs.util.default_repr 10014843421SMatthew Ahrens 10114843421SMatthew Ahrens def __init__(self, name, props=None, 10214843421SMatthew Ahrens types=("filesystem", "volume"), snaps=True): 10314843421SMatthew Ahrens """Open the named dataset, checking that it exists and 10414843421SMatthew Ahrens is of the specified type. 10514843421SMatthew Ahrens 10614843421SMatthew Ahrens name is the string name of this dataset. 10714843421SMatthew Ahrens 10814843421SMatthew Ahrens props is the property settings dict from zfs.ioctl.next_dataset. 10914843421SMatthew Ahrens 11014843421SMatthew Ahrens types is an iterable of strings specifying which types 11114843421SMatthew Ahrens of datasets are permitted. Accepted strings are 112842727c2SChris Kirby "filesystem" and "volume". Defaults to accepting all 11314843421SMatthew Ahrens types. 11414843421SMatthew Ahrens 11514843421SMatthew Ahrens snaps is a boolean specifying if snapshots are acceptable. 11614843421SMatthew Ahrens 11714843421SMatthew Ahrens Raises a ZFSError if the dataset can't be accessed (eg 11814843421SMatthew Ahrens doesn't exist) or is not of the specified type. 11914843421SMatthew Ahrens """ 12014843421SMatthew Ahrens 12114843421SMatthew Ahrens self.name = name 12214843421SMatthew Ahrens 12314843421SMatthew Ahrens e = zfs.util.ZFSError(errno.EINVAL, 12414843421SMatthew Ahrens _("cannot open %s") % name, 12514843421SMatthew Ahrens _("operation not applicable to datasets of this type")) 12614843421SMatthew Ahrens if "@" in name and not snaps: 12714843421SMatthew Ahrens raise e 12814843421SMatthew Ahrens if not props: 12914843421SMatthew Ahrens props = zfs.ioctl.dataset_props(name) 13014843421SMatthew Ahrens self.__props = props 13114843421SMatthew Ahrens if "volume" not in types and self.getprop("type") == 3: 13214843421SMatthew Ahrens raise e 13314843421SMatthew Ahrens if "filesystem" not in types and self.getprop("type") == 2: 13414843421SMatthew Ahrens raise e 13514843421SMatthew Ahrens 13614843421SMatthew Ahrens def getprop(self, propname): 13714843421SMatthew Ahrens """Return the value of the given property for this dataset. 13814843421SMatthew Ahrens 13914843421SMatthew Ahrens Currently only works for native properties (those with a 14014843421SMatthew Ahrens Property object.) 14114843421SMatthew Ahrens 14214843421SMatthew Ahrens Raises KeyError if propname does not specify a native property. 14314843421SMatthew Ahrens Does not raise ZFSError. 14414843421SMatthew Ahrens """ 14514843421SMatthew Ahrens 14614843421SMatthew Ahrens p = getpropobj(propname) 14714843421SMatthew Ahrens try: 14814843421SMatthew Ahrens return self.__props[p.name]["value"] 14914843421SMatthew Ahrens except KeyError: 15014843421SMatthew Ahrens return p.default 15114843421SMatthew Ahrens 15214843421SMatthew Ahrens def parent(self): 15314843421SMatthew Ahrens """Return a Dataset representing the parent of this one.""" 15414843421SMatthew Ahrens return Dataset(self.name[:self.name.rindex("/")]) 15514843421SMatthew Ahrens 15614843421SMatthew Ahrens def descendents(self): 15714843421SMatthew Ahrens """A generator function which iterates over all 15814843421SMatthew Ahrens descendent Datasets (not including snapshots.""" 15914843421SMatthew Ahrens 16014843421SMatthew Ahrens cookie = 0 16114843421SMatthew Ahrens while True: 16214843421SMatthew Ahrens # next_dataset raises StopIteration when done 16314843421SMatthew Ahrens (name, cookie, props) = \ 16414843421SMatthew Ahrens zfs.ioctl.next_dataset(self.name, False, cookie) 16514843421SMatthew Ahrens ds = Dataset(name, props) 16614843421SMatthew Ahrens yield ds 16714843421SMatthew Ahrens for child in ds.descendents(): 16814843421SMatthew Ahrens yield child 16914843421SMatthew Ahrens 17014843421SMatthew Ahrens def userspace(self, prop): 17114843421SMatthew Ahrens """A generator function which iterates over a 17214843421SMatthew Ahrens userspace-type property. 17314843421SMatthew Ahrens 17414843421SMatthew Ahrens prop specifies which property ("userused@", 17514843421SMatthew Ahrens "userquota@", "groupused@", or "groupquota@"). 17614843421SMatthew Ahrens 17714843421SMatthew Ahrens returns 3-tuple of domain (string), rid (int), and space (int). 17814843421SMatthew Ahrens """ 17914843421SMatthew Ahrens 18014843421SMatthew Ahrens d = zfs.ioctl.userspace_many(self.name, prop) 181*d561bb99SAndy Fiddaman for ((domain, rid), space) in d.items(): 18214843421SMatthew Ahrens yield (domain, rid, space) 18314843421SMatthew Ahrens 18414843421SMatthew Ahrens def userspace_upgrade(self): 18514843421SMatthew Ahrens """Initialize the accounting information for 18614843421SMatthew Ahrens userused@... and groupused@... properties.""" 18714843421SMatthew Ahrens return zfs.ioctl.userspace_upgrade(self.name) 18814843421SMatthew Ahrens 18914843421SMatthew Ahrens def set_fsacl(self, un, d): 19014843421SMatthew Ahrens """Add to the "zfs allow"-ed permissions on this Dataset. 19114843421SMatthew Ahrens 19214843421SMatthew Ahrens un is True if the specified permissions should be removed. 19314843421SMatthew Ahrens 19414843421SMatthew Ahrens d is a dict specifying which permissions to add/remove: 19514843421SMatthew Ahrens { "whostr" -> None # remove all perms for this entity 19614843421SMatthew Ahrens "whostr" -> { "perm" -> None} # add/remove these perms 19714843421SMatthew Ahrens } """ 19814843421SMatthew Ahrens return zfs.ioctl.set_fsacl(self.name, un, d) 19914843421SMatthew Ahrens 20014843421SMatthew Ahrens def get_fsacl(self): 20114843421SMatthew Ahrens """Get the "zfs allow"-ed permissions on the Dataset. 20214843421SMatthew Ahrens 20314843421SMatthew Ahrens Return a dict("whostr": { "perm" -> None }).""" 20414843421SMatthew Ahrens 20514843421SMatthew Ahrens return zfs.ioctl.get_fsacl(self.name) 206842727c2SChris Kirby 207842727c2SChris Kirby def get_holds(self): 208842727c2SChris Kirby """Get the user holds on this Dataset. 209842727c2SChris Kirby 210842727c2SChris Kirby Return a dict("tag": timestamp).""" 211842727c2SChris Kirby 212842727c2SChris Kirby return zfs.ioctl.get_holds(self.name) 213842727c2SChris Kirby 214842727c2SChris Kirbydef snapshots_fromcmdline(dsnames, recursive): 215842727c2SChris Kirby for dsname in dsnames: 216842727c2SChris Kirby if not "@" in dsname: 217842727c2SChris Kirby raise zfs.util.ZFSError(errno.EINVAL, 218842727c2SChris Kirby _("cannot open %s") % dsname, 219842727c2SChris Kirby _("operation only applies to snapshots")) 220d7747cbcSChris Kirby try: 221d7747cbcSChris Kirby ds = Dataset(dsname) 222842727c2SChris Kirby yield ds 223*d561bb99SAndy Fiddaman except zfs.util.ZFSError as e: 224d7747cbcSChris Kirby if not recursive or e.errno != errno.ENOENT: 225d7747cbcSChris Kirby raise 226842727c2SChris Kirby if recursive: 227842727c2SChris Kirby (base, snapname) = dsname.split('@') 228842727c2SChris Kirby parent = Dataset(base) 229842727c2SChris Kirby for child in parent.descendents(): 230842727c2SChris Kirby try: 231842727c2SChris Kirby yield Dataset(child.name + "@" + 232842727c2SChris Kirby snapname) 233*d561bb99SAndy Fiddaman except zfs.util.ZFSError as e: 234842727c2SChris Kirby if e.errno != errno.ENOENT: 235842727c2SChris Kirby raise 236