xref: /titanic_50/usr/src/lib/pyzfs/common/dataset.py (revision 8cfa78e6de0de88f6a15cd29ee5f6a8a1bfe7c20)
124bb1048SAlexander 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*8cfa78e6SAndy 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*8cfa78e6SAndy 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*8cfa78e6SAndy 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*8cfa78e6SAndy 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*8cfa78e6SAndy 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*8cfa78e6SAndy Fiddaman				except zfs.util.ZFSError as e:
234842727c2SChris Kirby					if e.errno != errno.ENOENT:
235842727c2SChris Kirby						raise
236