9f9230833b50b8271840dc2c12bd1e94d9df7d12Alexander Pyhalov#!@PYTHON@
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens#
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# CDDL HEADER START
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens#
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# The contents of this file are subject to the terms of the
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# Common Development and Distribution License (the "License").
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# You may not use this file except in compliance with the License.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens#
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# or http://www.opensolaris.org/os/licensing.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# See the License for the specific language governing permissions
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# and limitations under the License.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens#
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# When distributing Covered Code, include this CDDL HEADER in each
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# If applicable, add the following below this CDDL HEADER, with the
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# fields enclosed by brackets "[]" replaced with your own identifying
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# information: Portions Copyright [yyyy] [name of copyright owner]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens#
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# CDDL HEADER END
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens#
6d52f363e3b2c0c5da672c5b8c8adec99d345f38Lori Alt# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens#
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens"""Implements the Dataset class, providing methods for manipulating ZFS
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensdatasets. Also implements the Property class, which describes ZFS
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensproperties."""
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensimport zfs.ioctl
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensimport zfs.util
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensimport errno
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens_ = zfs.util._
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensclass Property(object):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """This class represents a ZFS property. It contains
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens information about the property -- if it's readonly, a number vs
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens string vs index, etc. Only native properties are represented by
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens this class -- not user properties (eg "user:prop") or userspace
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens properties (eg "userquota@joe")."""
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens __slots__ = "name", "number", "type", "default", "attr", "validtypes", \
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens "values", "colname", "rightalign", "visible", "indextable"
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens __repr__ = zfs.util.default_repr
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens def __init__(self, t):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """t is the tuple of information about this property
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens from zfs.ioctl.get_proptable, which should match the
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens members of zprop_desc_t (see zfs_prop.h)."""
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens self.name = t[0]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens self.number = t[1]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens self.type = t[2]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if self.type == "string":
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens self.default = t[3]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens else:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens self.default = t[4]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens self.attr = t[5]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens self.validtypes = t[6]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens self.values = t[7]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens self.colname = t[8]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens self.rightalign = t[9]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens self.visible = t[10]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens self.indextable = t[11]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens def delegatable(self):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """Return True if this property can be delegated with
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens "zfs allow"."""
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return self.attr != "readonly"
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensproptable = dict()
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensfor name, t in zfs.ioctl.get_proptable().iteritems():
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens proptable[name] = Property(t)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensdel name, t
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensdef getpropobj(name):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """Return the Property object that is identified by the given
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens name string. It can be the full name, or the column name."""
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens try:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return proptable[name]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens except KeyError:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens for p in proptable.itervalues():
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if p.colname and p.colname.lower() == name:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return p
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens raise
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensclass Dataset(object):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """Represents a ZFS dataset (filesystem, snapshot, zvol, clone, etc).
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens Generally, this class provides interfaces to the C functions in
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens zfs.ioctl which actually interface with the kernel to manipulate
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens datasets.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens Unless otherwise noted, any method can raise a ZFSError to
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens indicate failure."""
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens __slots__ = "name", "__props"
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens __repr__ = zfs.util.default_repr
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens def __init__(self, name, props=None,
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens types=("filesystem", "volume"), snaps=True):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """Open the named dataset, checking that it exists and
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens is of the specified type.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens name is the string name of this dataset.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens props is the property settings dict from zfs.ioctl.next_dataset.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens types is an iterable of strings specifying which types
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens of datasets are permitted. Accepted strings are
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby "filesystem" and "volume". Defaults to accepting all
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens types.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens snaps is a boolean specifying if snapshots are acceptable.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens Raises a ZFSError if the dataset can't be accessed (eg
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens doesn't exist) or is not of the specified type.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens self.name = name
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens e = zfs.util.ZFSError(errno.EINVAL,
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens _("cannot open %s") % name,
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens _("operation not applicable to datasets of this type"))
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if "@" in name and not snaps:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens raise e
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if not props:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens props = zfs.ioctl.dataset_props(name)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens self.__props = props
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if "volume" not in types and self.getprop("type") == 3:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens raise e
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if "filesystem" not in types and self.getprop("type") == 2:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens raise e
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens def getprop(self, propname):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """Return the value of the given property for this dataset.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens Currently only works for native properties (those with a
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens Property object.)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens Raises KeyError if propname does not specify a native property.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens Does not raise ZFSError.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens p = getpropobj(propname)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens try:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return self.__props[p.name]["value"]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens except KeyError:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return p.default
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens def parent(self):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """Return a Dataset representing the parent of this one."""
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return Dataset(self.name[:self.name.rindex("/")])
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens def descendents(self):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """A generator function which iterates over all
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens descendent Datasets (not including snapshots."""
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens cookie = 0
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens while True:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # next_dataset raises StopIteration when done
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens (name, cookie, props) = \
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens zfs.ioctl.next_dataset(self.name, False, cookie)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens ds = Dataset(name, props)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens yield ds
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens for child in ds.descendents():
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens yield child
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens def userspace(self, prop):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """A generator function which iterates over a
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens userspace-type property.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens prop specifies which property ("userused@",
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens "userquota@", "groupused@", or "groupquota@").
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens returns 3-tuple of domain (string), rid (int), and space (int).
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens d = zfs.ioctl.userspace_many(self.name, prop)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens for ((domain, rid), space) in d.iteritems():
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens yield (domain, rid, space)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens def userspace_upgrade(self):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """Initialize the accounting information for
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens userused@... and groupused@... properties."""
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return zfs.ioctl.userspace_upgrade(self.name)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens def set_fsacl(self, un, d):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """Add to the "zfs allow"-ed permissions on this Dataset.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens un is True if the specified permissions should be removed.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens d is a dict specifying which permissions to add/remove:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens { "whostr" -> None # remove all perms for this entity
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens "whostr" -> { "perm" -> None} # add/remove these perms
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens } """
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return zfs.ioctl.set_fsacl(self.name, un, d)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens def get_fsacl(self):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """Get the "zfs allow"-ed permissions on the Dataset.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens Return a dict("whostr": { "perm" -> None })."""
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return zfs.ioctl.get_fsacl(self.name)
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby def get_holds(self):
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby """Get the user holds on this Dataset.
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby Return a dict("tag": timestamp)."""
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby return zfs.ioctl.get_holds(self.name)
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby
842727c2f41f01b380de4f5e787d905702870f23Chris Kirbydef snapshots_fromcmdline(dsnames, recursive):
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby for dsname in dsnames:
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby if not "@" in dsname:
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby raise zfs.util.ZFSError(errno.EINVAL,
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby _("cannot open %s") % dsname,
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby _("operation only applies to snapshots"))
d7747cbcf0e2da91e8d0e3dfd6d3ac45da469773Chris Kirby try:
d7747cbcf0e2da91e8d0e3dfd6d3ac45da469773Chris Kirby ds = Dataset(dsname)
d7747cbcf0e2da91e8d0e3dfd6d3ac45da469773Chris Kirby yield ds
d7747cbcf0e2da91e8d0e3dfd6d3ac45da469773Chris Kirby except zfs.util.ZFSError, e:
d7747cbcf0e2da91e8d0e3dfd6d3ac45da469773Chris Kirby if not recursive or e.errno != errno.ENOENT:
d7747cbcf0e2da91e8d0e3dfd6d3ac45da469773Chris Kirby raise
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby if recursive:
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby (base, snapname) = dsname.split('@')
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby parent = Dataset(base)
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby for child in parent.descendents():
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby try:
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby yield Dataset(child.name + "@" +
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby snapname)
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby except zfs.util.ZFSError, e:
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby if e.errno != errno.ENOENT:
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby raise