xref: /freebsd-src/cddl/contrib/opensolaris/lib/pyzfs/common/dataset.py (revision 10b9d77bf1ccf2f3affafa6261692cb92cf7e992)
1*10b9d77bSPawel Jakub Dawidek#! /usr/bin/python2.6
28fc25799SMartin Matuska#
38fc25799SMartin Matuska# CDDL HEADER START
48fc25799SMartin Matuska#
58fc25799SMartin Matuska# The contents of this file are subject to the terms of the
68fc25799SMartin Matuska# Common Development and Distribution License (the "License").
78fc25799SMartin Matuska# You may not use this file except in compliance with the License.
88fc25799SMartin Matuska#
98fc25799SMartin Matuska# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
108fc25799SMartin Matuska# or http://www.opensolaris.org/os/licensing.
118fc25799SMartin Matuska# See the License for the specific language governing permissions
128fc25799SMartin Matuska# and limitations under the License.
138fc25799SMartin Matuska#
148fc25799SMartin Matuska# When distributing Covered Code, include this CDDL HEADER in each
158fc25799SMartin Matuska# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
168fc25799SMartin Matuska# If applicable, add the following below this CDDL HEADER, with the
178fc25799SMartin Matuska# fields enclosed by brackets "[]" replaced with your own identifying
188fc25799SMartin Matuska# information: Portions Copyright [yyyy] [name of copyright owner]
198fc25799SMartin Matuska#
208fc25799SMartin Matuska# CDDL HEADER END
218fc25799SMartin Matuska#
22*10b9d77bSPawel Jakub Dawidek# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
238fc25799SMartin Matuska#
248fc25799SMartin Matuska
258fc25799SMartin Matuska"""Implements the Dataset class, providing methods for manipulating ZFS
268fc25799SMartin Matuskadatasets.  Also implements the Property class, which describes ZFS
278fc25799SMartin Matuskaproperties."""
288fc25799SMartin Matuska
298fc25799SMartin Matuskaimport zfs.ioctl
308fc25799SMartin Matuskaimport zfs.util
318fc25799SMartin Matuskaimport errno
328fc25799SMartin Matuska
338fc25799SMartin Matuska_ = zfs.util._
348fc25799SMartin Matuska
358fc25799SMartin Matuskaclass Property(object):
368fc25799SMartin Matuska	"""This class represents a ZFS property.  It contains
378fc25799SMartin Matuska	information about the property -- if it's readonly, a number vs
388fc25799SMartin Matuska	string vs index, etc.  Only native properties are represented by
398fc25799SMartin Matuska	this class -- not user properties (eg "user:prop") or userspace
408fc25799SMartin Matuska	properties (eg "userquota@joe")."""
418fc25799SMartin Matuska
428fc25799SMartin Matuska	__slots__ = "name", "number", "type", "default", "attr", "validtypes", \
438fc25799SMartin Matuska	    "values", "colname", "rightalign", "visible", "indextable"
448fc25799SMartin Matuska	__repr__ = zfs.util.default_repr
458fc25799SMartin Matuska
468fc25799SMartin Matuska	def __init__(self, t):
478fc25799SMartin Matuska		"""t is the tuple of information about this property
488fc25799SMartin Matuska		from zfs.ioctl.get_proptable, which should match the
498fc25799SMartin Matuska		members of zprop_desc_t (see zfs_prop.h)."""
508fc25799SMartin Matuska
518fc25799SMartin Matuska		self.name = t[0]
528fc25799SMartin Matuska		self.number = t[1]
538fc25799SMartin Matuska		self.type = t[2]
548fc25799SMartin Matuska		if self.type == "string":
558fc25799SMartin Matuska			self.default = t[3]
568fc25799SMartin Matuska		else:
578fc25799SMartin Matuska			self.default = t[4]
588fc25799SMartin Matuska		self.attr = t[5]
598fc25799SMartin Matuska		self.validtypes = t[6]
608fc25799SMartin Matuska		self.values = t[7]
618fc25799SMartin Matuska		self.colname = t[8]
628fc25799SMartin Matuska		self.rightalign = t[9]
638fc25799SMartin Matuska		self.visible = t[10]
648fc25799SMartin Matuska		self.indextable = t[11]
658fc25799SMartin Matuska
668fc25799SMartin Matuska	def delegatable(self):
678fc25799SMartin Matuska		"""Return True if this property can be delegated with
688fc25799SMartin Matuska		"zfs allow"."""
698fc25799SMartin Matuska		return self.attr != "readonly"
708fc25799SMartin Matuska
718fc25799SMartin Matuskaproptable = dict()
728fc25799SMartin Matuskafor name, t in zfs.ioctl.get_proptable().iteritems():
738fc25799SMartin Matuska	proptable[name] = Property(t)
748fc25799SMartin Matuskadel name, t
758fc25799SMartin Matuska
768fc25799SMartin Matuskadef getpropobj(name):
778fc25799SMartin Matuska	"""Return the Property object that is identified by the given
788fc25799SMartin Matuska	name string.  It can be the full name, or the column name."""
798fc25799SMartin Matuska	try:
808fc25799SMartin Matuska		return proptable[name]
818fc25799SMartin Matuska	except KeyError:
828fc25799SMartin Matuska		for p in proptable.itervalues():
838fc25799SMartin Matuska			if p.colname and p.colname.lower() == name:
848fc25799SMartin Matuska				return p
858fc25799SMartin Matuska		raise
868fc25799SMartin Matuska
878fc25799SMartin Matuskaclass Dataset(object):
888fc25799SMartin Matuska	"""Represents a ZFS dataset (filesystem, snapshot, zvol, clone, etc).
898fc25799SMartin Matuska
908fc25799SMartin Matuska	Generally, this class provides interfaces to the C functions in
918fc25799SMartin Matuska	zfs.ioctl which actually interface with the kernel to manipulate
928fc25799SMartin Matuska	datasets.
938fc25799SMartin Matuska
948fc25799SMartin Matuska	Unless otherwise noted, any method can raise a ZFSError to
958fc25799SMartin Matuska	indicate failure."""
968fc25799SMartin Matuska
978fc25799SMartin Matuska	__slots__ = "name", "__props"
988fc25799SMartin Matuska	__repr__ = zfs.util.default_repr
998fc25799SMartin Matuska
1008fc25799SMartin Matuska	def __init__(self, name, props=None,
1018fc25799SMartin Matuska	    types=("filesystem", "volume"), snaps=True):
1028fc25799SMartin Matuska		"""Open the named dataset, checking that it exists and
1038fc25799SMartin Matuska		is of the specified type.
1048fc25799SMartin Matuska
1058fc25799SMartin Matuska		name is the string name of this dataset.
1068fc25799SMartin Matuska
1078fc25799SMartin Matuska		props is the property settings dict from zfs.ioctl.next_dataset.
1088fc25799SMartin Matuska
1098fc25799SMartin Matuska		types is an iterable of strings specifying which types
1108fc25799SMartin Matuska		of datasets are permitted.  Accepted strings are
111*10b9d77bSPawel Jakub Dawidek		"filesystem" and "volume".  Defaults to accepting all
1128fc25799SMartin Matuska		types.
1138fc25799SMartin Matuska
1148fc25799SMartin Matuska		snaps is a boolean specifying if snapshots are acceptable.
1158fc25799SMartin Matuska
1168fc25799SMartin Matuska		Raises a ZFSError if the dataset can't be accessed (eg
1178fc25799SMartin Matuska		doesn't exist) or is not of the specified type.
1188fc25799SMartin Matuska		"""
1198fc25799SMartin Matuska
1208fc25799SMartin Matuska		self.name = name
1218fc25799SMartin Matuska
1228fc25799SMartin Matuska		e = zfs.util.ZFSError(errno.EINVAL,
1238fc25799SMartin Matuska		    _("cannot open %s") % name,
1248fc25799SMartin Matuska		    _("operation not applicable to datasets of this type"))
1258fc25799SMartin Matuska		if "@" in name and not snaps:
1268fc25799SMartin Matuska			raise e
1278fc25799SMartin Matuska		if not props:
1288fc25799SMartin Matuska			props = zfs.ioctl.dataset_props(name)
1298fc25799SMartin Matuska		self.__props = props
1308fc25799SMartin Matuska		if "volume" not in types and self.getprop("type") == 3:
1318fc25799SMartin Matuska			raise e
1328fc25799SMartin Matuska		if "filesystem" not in types and self.getprop("type") == 2:
1338fc25799SMartin Matuska			raise e
1348fc25799SMartin Matuska
1358fc25799SMartin Matuska	def getprop(self, propname):
1368fc25799SMartin Matuska		"""Return the value of the given property for this dataset.
1378fc25799SMartin Matuska
1388fc25799SMartin Matuska		Currently only works for native properties (those with a
1398fc25799SMartin Matuska		Property object.)
1408fc25799SMartin Matuska
1418fc25799SMartin Matuska		Raises KeyError if propname does not specify a native property.
1428fc25799SMartin Matuska		Does not raise ZFSError.
1438fc25799SMartin Matuska		"""
1448fc25799SMartin Matuska
1458fc25799SMartin Matuska		p = getpropobj(propname)
1468fc25799SMartin Matuska		try:
1478fc25799SMartin Matuska			return self.__props[p.name]["value"]
1488fc25799SMartin Matuska		except KeyError:
1498fc25799SMartin Matuska			return p.default
1508fc25799SMartin Matuska
1518fc25799SMartin Matuska	def parent(self):
1528fc25799SMartin Matuska		"""Return a Dataset representing the parent of this one."""
1538fc25799SMartin Matuska		return Dataset(self.name[:self.name.rindex("/")])
1548fc25799SMartin Matuska
1558fc25799SMartin Matuska	def descendents(self):
1568fc25799SMartin Matuska		"""A generator function which iterates over all
1578fc25799SMartin Matuska		descendent Datasets (not including snapshots."""
1588fc25799SMartin Matuska
1598fc25799SMartin Matuska		cookie = 0
1608fc25799SMartin Matuska		while True:
1618fc25799SMartin Matuska			# next_dataset raises StopIteration when done
1628fc25799SMartin Matuska			(name, cookie, props) = \
1638fc25799SMartin Matuska			    zfs.ioctl.next_dataset(self.name, False, cookie)
1648fc25799SMartin Matuska			ds = Dataset(name, props)
1658fc25799SMartin Matuska			yield ds
1668fc25799SMartin Matuska			for child in ds.descendents():
1678fc25799SMartin Matuska				yield child
1688fc25799SMartin Matuska
1698fc25799SMartin Matuska	def userspace(self, prop):
1708fc25799SMartin Matuska		"""A generator function which iterates over a
1718fc25799SMartin Matuska		userspace-type property.
1728fc25799SMartin Matuska
1738fc25799SMartin Matuska		prop specifies which property ("userused@",
1748fc25799SMartin Matuska		"userquota@", "groupused@", or "groupquota@").
1758fc25799SMartin Matuska
1768fc25799SMartin Matuska		returns 3-tuple of domain (string), rid (int), and space (int).
1778fc25799SMartin Matuska		"""
1788fc25799SMartin Matuska
1798fc25799SMartin Matuska		d = zfs.ioctl.userspace_many(self.name, prop)
1808fc25799SMartin Matuska		for ((domain, rid), space) in d.iteritems():
1818fc25799SMartin Matuska			yield (domain, rid, space)
1828fc25799SMartin Matuska
1838fc25799SMartin Matuska	def userspace_upgrade(self):
1848fc25799SMartin Matuska		"""Initialize the accounting information for
1858fc25799SMartin Matuska		userused@... and groupused@... properties."""
1868fc25799SMartin Matuska		return zfs.ioctl.userspace_upgrade(self.name)
1878fc25799SMartin Matuska
1888fc25799SMartin Matuska	def set_fsacl(self, un, d):
1898fc25799SMartin Matuska		"""Add to the "zfs allow"-ed permissions on this Dataset.
1908fc25799SMartin Matuska
1918fc25799SMartin Matuska		un is True if the specified permissions should be removed.
1928fc25799SMartin Matuska
1938fc25799SMartin Matuska		d is a dict specifying which permissions to add/remove:
1948fc25799SMartin Matuska		{ "whostr" -> None # remove all perms for this entity
1958fc25799SMartin Matuska		  "whostr" -> { "perm" -> None} # add/remove these perms
1968fc25799SMartin Matuska		} """
1978fc25799SMartin Matuska		return zfs.ioctl.set_fsacl(self.name, un, d)
1988fc25799SMartin Matuska
1998fc25799SMartin Matuska	def get_fsacl(self):
2008fc25799SMartin Matuska		"""Get the "zfs allow"-ed permissions on the Dataset.
2018fc25799SMartin Matuska
2028fc25799SMartin Matuska		Return a dict("whostr": { "perm" -> None })."""
2038fc25799SMartin Matuska
2048fc25799SMartin Matuska		return zfs.ioctl.get_fsacl(self.name)
205*10b9d77bSPawel Jakub Dawidek
206*10b9d77bSPawel Jakub Dawidek	def get_holds(self):
207*10b9d77bSPawel Jakub Dawidek		"""Get the user holds on this Dataset.
208*10b9d77bSPawel Jakub Dawidek
209*10b9d77bSPawel Jakub Dawidek		Return a dict("tag": timestamp)."""
210*10b9d77bSPawel Jakub Dawidek
211*10b9d77bSPawel Jakub Dawidek		return zfs.ioctl.get_holds(self.name)
212*10b9d77bSPawel Jakub Dawidek
213*10b9d77bSPawel Jakub Dawidekdef snapshots_fromcmdline(dsnames, recursive):
214*10b9d77bSPawel Jakub Dawidek	for dsname in dsnames:
215*10b9d77bSPawel Jakub Dawidek		if not "@" in dsname:
216*10b9d77bSPawel Jakub Dawidek			raise zfs.util.ZFSError(errno.EINVAL,
217*10b9d77bSPawel Jakub Dawidek			    _("cannot open %s") % dsname,
218*10b9d77bSPawel Jakub Dawidek			    _("operation only applies to snapshots"))
219*10b9d77bSPawel Jakub Dawidek		try:
220*10b9d77bSPawel Jakub Dawidek			ds = Dataset(dsname)
221*10b9d77bSPawel Jakub Dawidek			yield ds
222*10b9d77bSPawel Jakub Dawidek		except zfs.util.ZFSError, e:
223*10b9d77bSPawel Jakub Dawidek			if not recursive or e.errno != errno.ENOENT:
224*10b9d77bSPawel Jakub Dawidek				raise
225*10b9d77bSPawel Jakub Dawidek		if recursive:
226*10b9d77bSPawel Jakub Dawidek			(base, snapname) = dsname.split('@')
227*10b9d77bSPawel Jakub Dawidek			parent = Dataset(base)
228*10b9d77bSPawel Jakub Dawidek			for child in parent.descendents():
229*10b9d77bSPawel Jakub Dawidek				try:
230*10b9d77bSPawel Jakub Dawidek					yield Dataset(child.name + "@" +
231*10b9d77bSPawel Jakub Dawidek					    snapname)
232*10b9d77bSPawel Jakub Dawidek				except zfs.util.ZFSError, e:
233*10b9d77bSPawel Jakub Dawidek					if e.errno != errno.ENOENT:
234*10b9d77bSPawel Jakub Dawidek						raise
235