Path: blob/main/cddl/contrib/opensolaris/lib/pyzfs/common/dataset.py
39563 views
#! /usr/bin/python2.61#2# CDDL HEADER START3#4# The contents of this file are subject to the terms of the5# Common Development and Distribution License (the "License").6# You may not use this file except in compliance with the License.7#8# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9# or http://www.opensolaris.org/os/licensing.10# See the License for the specific language governing permissions11# and limitations under the License.12#13# When distributing Covered Code, include this CDDL HEADER in each14# file and include the License file at usr/src/OPENSOLARIS.LICENSE.15# If applicable, add the following below this CDDL HEADER, with the16# fields enclosed by brackets "[]" replaced with your own identifying17# information: Portions Copyright [yyyy] [name of copyright owner]18#19# CDDL HEADER END20#21# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.22#2324"""Implements the Dataset class, providing methods for manipulating ZFS25datasets. Also implements the Property class, which describes ZFS26properties."""2728import zfs.ioctl29import zfs.util30import errno3132_ = zfs.util._3334class Property(object):35"""This class represents a ZFS property. It contains36information about the property -- if it's readonly, a number vs37string vs index, etc. Only native properties are represented by38this class -- not user properties (eg "user:prop") or userspace39properties (eg "userquota@joe")."""4041__slots__ = "name", "number", "type", "default", "attr", "validtypes", \42"values", "colname", "rightalign", "visible", "indextable"43__repr__ = zfs.util.default_repr4445def __init__(self, t):46"""t is the tuple of information about this property47from zfs.ioctl.get_proptable, which should match the48members of zprop_desc_t (see zfs_prop.h)."""4950self.name = t[0]51self.number = t[1]52self.type = t[2]53if self.type == "string":54self.default = t[3]55else:56self.default = t[4]57self.attr = t[5]58self.validtypes = t[6]59self.values = t[7]60self.colname = t[8]61self.rightalign = t[9]62self.visible = t[10]63self.indextable = t[11]6465def delegatable(self):66"""Return True if this property can be delegated with67"zfs allow"."""68return self.attr != "readonly"6970proptable = dict()71for name, t in zfs.ioctl.get_proptable().iteritems():72proptable[name] = Property(t)73del name, t7475def getpropobj(name):76"""Return the Property object that is identified by the given77name string. It can be the full name, or the column name."""78try:79return proptable[name]80except KeyError:81for p in proptable.itervalues():82if p.colname and p.colname.lower() == name:83return p84raise8586class Dataset(object):87"""Represents a ZFS dataset (filesystem, snapshot, zvol, clone, etc).8889Generally, this class provides interfaces to the C functions in90zfs.ioctl which actually interface with the kernel to manipulate91datasets.9293Unless otherwise noted, any method can raise a ZFSError to94indicate failure."""9596__slots__ = "name", "__props"97__repr__ = zfs.util.default_repr9899def __init__(self, name, props=None,100types=("filesystem", "volume"), snaps=True):101"""Open the named dataset, checking that it exists and102is of the specified type.103104name is the string name of this dataset.105106props is the property settings dict from zfs.ioctl.next_dataset.107108types is an iterable of strings specifying which types109of datasets are permitted. Accepted strings are110"filesystem" and "volume". Defaults to accepting all111types.112113snaps is a boolean specifying if snapshots are acceptable.114115Raises a ZFSError if the dataset can't be accessed (eg116doesn't exist) or is not of the specified type.117"""118119self.name = name120121e = zfs.util.ZFSError(errno.EINVAL,122_("cannot open %s") % name,123_("operation not applicable to datasets of this type"))124if "@" in name and not snaps:125raise e126if not props:127props = zfs.ioctl.dataset_props(name)128self.__props = props129if "volume" not in types and self.getprop("type") == 3:130raise e131if "filesystem" not in types and self.getprop("type") == 2:132raise e133134def getprop(self, propname):135"""Return the value of the given property for this dataset.136137Currently only works for native properties (those with a138Property object.)139140Raises KeyError if propname does not specify a native property.141Does not raise ZFSError.142"""143144p = getpropobj(propname)145try:146return self.__props[p.name]["value"]147except KeyError:148return p.default149150def parent(self):151"""Return a Dataset representing the parent of this one."""152return Dataset(self.name[:self.name.rindex("/")])153154def descendents(self):155"""A generator function which iterates over all156descendent Datasets (not including snapshots."""157158cookie = 0159while True:160# next_dataset raises StopIteration when done161(name, cookie, props) = \162zfs.ioctl.next_dataset(self.name, False, cookie)163ds = Dataset(name, props)164yield ds165for child in ds.descendents():166yield child167168def userspace(self, prop):169"""A generator function which iterates over a170userspace-type property.171172prop specifies which property ("userused@",173"userquota@", "groupused@", or "groupquota@").174175returns 3-tuple of domain (string), rid (int), and space (int).176"""177178d = zfs.ioctl.userspace_many(self.name, prop)179for ((domain, rid), space) in d.iteritems():180yield (domain, rid, space)181182def userspace_upgrade(self):183"""Initialize the accounting information for184userused@... and groupused@... properties."""185return zfs.ioctl.userspace_upgrade(self.name)186187def set_fsacl(self, un, d):188"""Add to the "zfs allow"-ed permissions on this Dataset.189190un is True if the specified permissions should be removed.191192d is a dict specifying which permissions to add/remove:193{ "whostr" -> None # remove all perms for this entity194"whostr" -> { "perm" -> None} # add/remove these perms195} """196return zfs.ioctl.set_fsacl(self.name, un, d)197198def get_fsacl(self):199"""Get the "zfs allow"-ed permissions on the Dataset.200201Return a dict("whostr": { "perm" -> None })."""202203return zfs.ioctl.get_fsacl(self.name)204205def get_holds(self):206"""Get the user holds on this Dataset.207208Return a dict("tag": timestamp)."""209210return zfs.ioctl.get_holds(self.name)211212def snapshots_fromcmdline(dsnames, recursive):213for dsname in dsnames:214if not "@" in dsname:215raise zfs.util.ZFSError(errno.EINVAL,216_("cannot open %s") % dsname,217_("operation only applies to snapshots"))218try:219ds = Dataset(dsname)220yield ds221except zfs.util.ZFSError, e:222if not recursive or e.errno != errno.ENOENT:223raise224if recursive:225(base, snapname) = dsname.split('@')226parent = Dataset(base)227for child in parent.descendents():228try:229yield Dataset(child.name + "@" +230snapname)231except zfs.util.ZFSError, e:232if e.errno != errno.ENOENT:233raise234235236