xref: /titanic_51/usr/src/lib/pyzfs/common/dataset.py (revision 6d52f363e3b2c0c5da672c5b8c8adec99d345f38)
1*6d52f363SLori Alt#! /usr/bin/python2.6
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#
22*6d52f363SLori Alt# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2314843421SMatthew Ahrens#
2414843421SMatthew Ahrens
2514843421SMatthew Ahrens"""Implements the Dataset class, providing methods for manipulating ZFS
2614843421SMatthew Ahrensdatasets.  Also implements the Property class, which describes ZFS
2714843421SMatthew Ahrensproperties."""
2814843421SMatthew Ahrens
2914843421SMatthew Ahrensimport zfs.ioctl
3014843421SMatthew Ahrensimport zfs.util
3114843421SMatthew Ahrensimport errno
3214843421SMatthew Ahrens
3314843421SMatthew Ahrens_ = zfs.util._
3414843421SMatthew Ahrens
3514843421SMatthew Ahrensclass Property(object):
3614843421SMatthew Ahrens	"""This class represents a ZFS property.  It contains
3714843421SMatthew Ahrens	information about the property -- if it's readonly, a number vs
3814843421SMatthew Ahrens	string vs index, etc.  Only native properties are represented by
3914843421SMatthew Ahrens	this class -- not user properties (eg "user:prop") or userspace
4014843421SMatthew Ahrens	properties (eg "userquota@joe")."""
4114843421SMatthew Ahrens
4214843421SMatthew Ahrens	__slots__ = "name", "number", "type", "default", "attr", "validtypes", \
4314843421SMatthew Ahrens	    "values", "colname", "rightalign", "visible", "indextable"
4414843421SMatthew Ahrens	__repr__ = zfs.util.default_repr
4514843421SMatthew Ahrens
4614843421SMatthew Ahrens	def __init__(self, t):
4714843421SMatthew Ahrens		"""t is the tuple of information about this property
4814843421SMatthew Ahrens		from zfs.ioctl.get_proptable, which should match the
4914843421SMatthew Ahrens		members of zprop_desc_t (see zfs_prop.h)."""
5014843421SMatthew Ahrens
5114843421SMatthew Ahrens		self.name = t[0]
5214843421SMatthew Ahrens		self.number = t[1]
5314843421SMatthew Ahrens		self.type = t[2]
5414843421SMatthew Ahrens		if self.type == "string":
5514843421SMatthew Ahrens			self.default = t[3]
5614843421SMatthew Ahrens		else:
5714843421SMatthew Ahrens			self.default = t[4]
5814843421SMatthew Ahrens		self.attr = t[5]
5914843421SMatthew Ahrens		self.validtypes = t[6]
6014843421SMatthew Ahrens		self.values = t[7]
6114843421SMatthew Ahrens		self.colname = t[8]
6214843421SMatthew Ahrens		self.rightalign = t[9]
6314843421SMatthew Ahrens		self.visible = t[10]
6414843421SMatthew Ahrens		self.indextable = t[11]
6514843421SMatthew Ahrens
6614843421SMatthew Ahrens	def delegatable(self):
6714843421SMatthew Ahrens		"""Return True if this property can be delegated with
6814843421SMatthew Ahrens		"zfs allow"."""
6914843421SMatthew Ahrens		return self.attr != "readonly"
7014843421SMatthew Ahrens
7114843421SMatthew Ahrensproptable = dict()
7214843421SMatthew Ahrensfor name, t in zfs.ioctl.get_proptable().iteritems():
7314843421SMatthew Ahrens	proptable[name] = Property(t)
7414843421SMatthew Ahrensdel name, t
7514843421SMatthew Ahrens
7614843421SMatthew Ahrensdef getpropobj(name):
7714843421SMatthew Ahrens	"""Return the Property object that is identified by the given
7814843421SMatthew Ahrens	name string.  It can be the full name, or the column name."""
7914843421SMatthew Ahrens	try:
8014843421SMatthew Ahrens		return proptable[name]
8114843421SMatthew Ahrens	except KeyError:
8214843421SMatthew Ahrens		for p in proptable.itervalues():
8314843421SMatthew Ahrens			if p.colname and p.colname.lower() == name:
8414843421SMatthew Ahrens				return p
8514843421SMatthew Ahrens		raise
8614843421SMatthew Ahrens
8714843421SMatthew Ahrensclass Dataset(object):
8814843421SMatthew Ahrens	"""Represents a ZFS dataset (filesystem, snapshot, zvol, clone, etc).
8914843421SMatthew Ahrens
9014843421SMatthew Ahrens	Generally, this class provides interfaces to the C functions in
9114843421SMatthew Ahrens	zfs.ioctl which actually interface with the kernel to manipulate
9214843421SMatthew Ahrens	datasets.
9314843421SMatthew Ahrens
9414843421SMatthew Ahrens	Unless otherwise noted, any method can raise a ZFSError to
9514843421SMatthew Ahrens	indicate failure."""
9614843421SMatthew Ahrens
9714843421SMatthew Ahrens	__slots__ = "name", "__props"
9814843421SMatthew Ahrens	__repr__ = zfs.util.default_repr
9914843421SMatthew Ahrens
10014843421SMatthew Ahrens	def __init__(self, name, props=None,
10114843421SMatthew Ahrens	    types=("filesystem", "volume"), snaps=True):
10214843421SMatthew Ahrens		"""Open the named dataset, checking that it exists and
10314843421SMatthew Ahrens		is of the specified type.
10414843421SMatthew Ahrens
10514843421SMatthew Ahrens		name is the string name of this dataset.
10614843421SMatthew Ahrens
10714843421SMatthew Ahrens		props is the property settings dict from zfs.ioctl.next_dataset.
10814843421SMatthew Ahrens
10914843421SMatthew Ahrens		types is an iterable of strings specifying which types
11014843421SMatthew Ahrens		of datasets are permitted.  Accepted strings are
111842727c2SChris Kirby		"filesystem" and "volume".  Defaults to accepting all
11214843421SMatthew Ahrens		types.
11314843421SMatthew Ahrens
11414843421SMatthew Ahrens		snaps is a boolean specifying if snapshots are acceptable.
11514843421SMatthew Ahrens
11614843421SMatthew Ahrens		Raises a ZFSError if the dataset can't be accessed (eg
11714843421SMatthew Ahrens		doesn't exist) or is not of the specified type.
11814843421SMatthew Ahrens		"""
11914843421SMatthew Ahrens
12014843421SMatthew Ahrens		self.name = name
12114843421SMatthew Ahrens
12214843421SMatthew Ahrens		e = zfs.util.ZFSError(errno.EINVAL,
12314843421SMatthew Ahrens		    _("cannot open %s") % name,
12414843421SMatthew Ahrens		    _("operation not applicable to datasets of this type"))
12514843421SMatthew Ahrens		if "@" in name and not snaps:
12614843421SMatthew Ahrens			raise e
12714843421SMatthew Ahrens		if not props:
12814843421SMatthew Ahrens			props = zfs.ioctl.dataset_props(name)
12914843421SMatthew Ahrens		self.__props = props
13014843421SMatthew Ahrens		if "volume" not in types and self.getprop("type") == 3:
13114843421SMatthew Ahrens			raise e
13214843421SMatthew Ahrens		if "filesystem" not in types and self.getprop("type") == 2:
13314843421SMatthew Ahrens			raise e
13414843421SMatthew Ahrens
13514843421SMatthew Ahrens	def getprop(self, propname):
13614843421SMatthew Ahrens		"""Return the value of the given property for this dataset.
13714843421SMatthew Ahrens
13814843421SMatthew Ahrens		Currently only works for native properties (those with a
13914843421SMatthew Ahrens		Property object.)
14014843421SMatthew Ahrens
14114843421SMatthew Ahrens		Raises KeyError if propname does not specify a native property.
14214843421SMatthew Ahrens		Does not raise ZFSError.
14314843421SMatthew Ahrens		"""
14414843421SMatthew Ahrens
14514843421SMatthew Ahrens		p = getpropobj(propname)
14614843421SMatthew Ahrens		try:
14714843421SMatthew Ahrens			return self.__props[p.name]["value"]
14814843421SMatthew Ahrens		except KeyError:
14914843421SMatthew Ahrens			return p.default
15014843421SMatthew Ahrens
15114843421SMatthew Ahrens	def parent(self):
15214843421SMatthew Ahrens		"""Return a Dataset representing the parent of this one."""
15314843421SMatthew Ahrens		return Dataset(self.name[:self.name.rindex("/")])
15414843421SMatthew Ahrens
15514843421SMatthew Ahrens	def descendents(self):
15614843421SMatthew Ahrens		"""A generator function which iterates over all
15714843421SMatthew Ahrens		descendent Datasets (not including snapshots."""
15814843421SMatthew Ahrens
15914843421SMatthew Ahrens		cookie = 0
16014843421SMatthew Ahrens		while True:
16114843421SMatthew Ahrens			# next_dataset raises StopIteration when done
16214843421SMatthew Ahrens			(name, cookie, props) = \
16314843421SMatthew Ahrens			    zfs.ioctl.next_dataset(self.name, False, cookie)
16414843421SMatthew Ahrens			ds = Dataset(name, props)
16514843421SMatthew Ahrens			yield ds
16614843421SMatthew Ahrens			for child in ds.descendents():
16714843421SMatthew Ahrens				yield child
16814843421SMatthew Ahrens
16914843421SMatthew Ahrens	def userspace(self, prop):
17014843421SMatthew Ahrens		"""A generator function which iterates over a
17114843421SMatthew Ahrens		userspace-type property.
17214843421SMatthew Ahrens
17314843421SMatthew Ahrens		prop specifies which property ("userused@",
17414843421SMatthew Ahrens		"userquota@", "groupused@", or "groupquota@").
17514843421SMatthew Ahrens
17614843421SMatthew Ahrens		returns 3-tuple of domain (string), rid (int), and space (int).
17714843421SMatthew Ahrens		"""
17814843421SMatthew Ahrens
17914843421SMatthew Ahrens		d = zfs.ioctl.userspace_many(self.name, prop)
18014843421SMatthew Ahrens		for ((domain, rid), space) in d.iteritems():
18114843421SMatthew Ahrens			yield (domain, rid, space)
18214843421SMatthew Ahrens
18314843421SMatthew Ahrens	def userspace_upgrade(self):
18414843421SMatthew Ahrens		"""Initialize the accounting information for
18514843421SMatthew Ahrens		userused@... and groupused@... properties."""
18614843421SMatthew Ahrens		return zfs.ioctl.userspace_upgrade(self.name)
18714843421SMatthew Ahrens
18814843421SMatthew Ahrens	def set_fsacl(self, un, d):
18914843421SMatthew Ahrens		"""Add to the "zfs allow"-ed permissions on this Dataset.
19014843421SMatthew Ahrens
19114843421SMatthew Ahrens		un is True if the specified permissions should be removed.
19214843421SMatthew Ahrens
19314843421SMatthew Ahrens		d is a dict specifying which permissions to add/remove:
19414843421SMatthew Ahrens		{ "whostr" -> None # remove all perms for this entity
19514843421SMatthew Ahrens		  "whostr" -> { "perm" -> None} # add/remove these perms
19614843421SMatthew Ahrens		} """
19714843421SMatthew Ahrens		return zfs.ioctl.set_fsacl(self.name, un, d)
19814843421SMatthew Ahrens
19914843421SMatthew Ahrens	def get_fsacl(self):
20014843421SMatthew Ahrens		"""Get the "zfs allow"-ed permissions on the Dataset.
20114843421SMatthew Ahrens
20214843421SMatthew Ahrens		Return a dict("whostr": { "perm" -> None })."""
20314843421SMatthew Ahrens
20414843421SMatthew Ahrens		return zfs.ioctl.get_fsacl(self.name)
205842727c2SChris Kirby
206842727c2SChris Kirby	def get_holds(self):
207842727c2SChris Kirby		"""Get the user holds on this Dataset.
208842727c2SChris Kirby
209842727c2SChris Kirby		Return a dict("tag": timestamp)."""
210842727c2SChris Kirby
211842727c2SChris Kirby		return zfs.ioctl.get_holds(self.name)
212842727c2SChris Kirby
213842727c2SChris Kirbydef snapshots_fromcmdline(dsnames, recursive):
214842727c2SChris Kirby	for dsname in dsnames:
215842727c2SChris Kirby		if not "@" in dsname:
216842727c2SChris Kirby			raise zfs.util.ZFSError(errno.EINVAL,
217842727c2SChris Kirby			    _("cannot open %s") % dsname,
218842727c2SChris Kirby			    _("operation only applies to snapshots"))
219d7747cbcSChris Kirby		try:
220d7747cbcSChris Kirby			ds = Dataset(dsname)
221842727c2SChris Kirby			yield ds
222d7747cbcSChris Kirby		except zfs.util.ZFSError, e:
223d7747cbcSChris Kirby			if not recursive or e.errno != errno.ENOENT:
224d7747cbcSChris Kirby				raise
225842727c2SChris Kirby		if recursive:
226842727c2SChris Kirby			(base, snapname) = dsname.split('@')
227842727c2SChris Kirby			parent = Dataset(base)
228842727c2SChris Kirby			for child in parent.descendents():
229842727c2SChris Kirby				try:
230842727c2SChris Kirby					yield Dataset(child.name + "@" +
231842727c2SChris Kirby					    snapname)
232842727c2SChris Kirby				except zfs.util.ZFSError, e:
233842727c2SChris Kirby					if e.errno != errno.ENOENT:
234842727c2SChris Kirby						raise
235