]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - cddl/contrib/opensolaris/lib/pyzfs/common/dataset.py
MFC r209962, r211970-r211972, r212050, r212605, r212611
[FreeBSD/stable/8.git] / cddl / contrib / opensolaris / lib / pyzfs / common / dataset.py
1 #! /usr/bin/python2.4
2 #
3 # CDDL HEADER START
4 #
5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
8 #
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
13 #
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
19 #
20 # CDDL HEADER END
21 #
22 # Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 # Use is subject to license terms.
24 #
25
26 """Implements the Dataset class, providing methods for manipulating ZFS
27 datasets.  Also implements the Property class, which describes ZFS
28 properties."""
29
30 import zfs.ioctl
31 import zfs.util
32 import errno
33
34 _ = zfs.util._
35
36 class Property(object):
37         """This class represents a ZFS property.  It contains
38         information about the property -- if it's readonly, a number vs
39         string vs index, etc.  Only native properties are represented by
40         this class -- not user properties (eg "user:prop") or userspace
41         properties (eg "userquota@joe")."""
42
43         __slots__ = "name", "number", "type", "default", "attr", "validtypes", \
44             "values", "colname", "rightalign", "visible", "indextable"
45         __repr__ = zfs.util.default_repr
46
47         def __init__(self, t):
48                 """t is the tuple of information about this property
49                 from zfs.ioctl.get_proptable, which should match the
50                 members of zprop_desc_t (see zfs_prop.h)."""
51
52                 self.name = t[0]
53                 self.number = t[1]
54                 self.type = t[2]
55                 if self.type == "string":
56                         self.default = t[3]
57                 else:
58                         self.default = t[4]
59                 self.attr = t[5]
60                 self.validtypes = t[6]
61                 self.values = t[7]
62                 self.colname = t[8]
63                 self.rightalign = t[9]
64                 self.visible = t[10]
65                 self.indextable = t[11]
66
67         def delegatable(self):
68                 """Return True if this property can be delegated with
69                 "zfs allow"."""
70                 return self.attr != "readonly"
71
72 proptable = dict()
73 for name, t in zfs.ioctl.get_proptable().iteritems():
74         proptable[name] = Property(t)
75 del name, t
76
77 def getpropobj(name):
78         """Return the Property object that is identified by the given
79         name string.  It can be the full name, or the column name."""
80         try:
81                 return proptable[name]
82         except KeyError:
83                 for p in proptable.itervalues():
84                         if p.colname and p.colname.lower() == name:
85                                 return p
86                 raise
87
88 class Dataset(object):
89         """Represents a ZFS dataset (filesystem, snapshot, zvol, clone, etc).
90
91         Generally, this class provides interfaces to the C functions in
92         zfs.ioctl which actually interface with the kernel to manipulate
93         datasets.
94         
95         Unless otherwise noted, any method can raise a ZFSError to
96         indicate failure."""
97
98         __slots__ = "name", "__props"
99         __repr__ = zfs.util.default_repr
100
101         def __init__(self, name, props=None,
102             types=("filesystem", "volume"), snaps=True):
103                 """Open the named dataset, checking that it exists and
104                 is of the specified type.
105                 
106                 name is the string name of this dataset.
107
108                 props is the property settings dict from zfs.ioctl.next_dataset.
109
110                 types is an iterable of strings specifying which types
111                 of datasets are permitted.  Accepted strings are
112                 "filesystem" and "volume".  Defaults to acceptying all
113                 types.
114
115                 snaps is a boolean specifying if snapshots are acceptable.
116
117                 Raises a ZFSError if the dataset can't be accessed (eg
118                 doesn't exist) or is not of the specified type.
119                 """
120
121                 self.name = name
122
123                 e = zfs.util.ZFSError(errno.EINVAL,
124                     _("cannot open %s") % name,
125                     _("operation not applicable to datasets of this type"))
126                 if "@" in name and not snaps:
127                         raise e
128                 if not props:
129                         props = zfs.ioctl.dataset_props(name)
130                 self.__props = props
131                 if "volume" not in types and self.getprop("type") == 3:
132                         raise e
133                 if "filesystem" not in types and self.getprop("type") == 2:
134                         raise e
135
136         def getprop(self, propname):
137                 """Return the value of the given property for this dataset.
138
139                 Currently only works for native properties (those with a
140                 Property object.)
141                 
142                 Raises KeyError if propname does not specify a native property.
143                 Does not raise ZFSError.
144                 """
145
146                 p = getpropobj(propname)
147                 try:
148                         return self.__props[p.name]["value"]
149                 except KeyError:
150                         return p.default
151
152         def parent(self):
153                 """Return a Dataset representing the parent of this one."""
154                 return Dataset(self.name[:self.name.rindex("/")])
155
156         def descendents(self):
157                 """A generator function which iterates over all
158                 descendent Datasets (not including snapshots."""
159
160                 cookie = 0
161                 while True:
162                         # next_dataset raises StopIteration when done
163                         (name, cookie, props) = \
164                             zfs.ioctl.next_dataset(self.name, False, cookie)
165                         ds = Dataset(name, props)
166                         yield ds
167                         for child in ds.descendents():
168                                 yield child
169         
170         def userspace(self, prop):
171                 """A generator function which iterates over a
172                 userspace-type property.
173
174                 prop specifies which property ("userused@",
175                 "userquota@", "groupused@", or "groupquota@").
176
177                 returns 3-tuple of domain (string), rid (int), and space (int).
178                 """
179
180                 d = zfs.ioctl.userspace_many(self.name, prop)
181                 for ((domain, rid), space) in d.iteritems():
182                         yield (domain, rid, space)
183
184         def userspace_upgrade(self):
185                 """Initialize the accounting information for
186                 userused@... and groupused@... properties."""
187                 return zfs.ioctl.userspace_upgrade(self.name)
188         
189         def set_fsacl(self, un, d):
190                 """Add to the "zfs allow"-ed permissions on this Dataset.
191
192                 un is True if the specified permissions should be removed.
193
194                 d is a dict specifying which permissions to add/remove:
195                 { "whostr" -> None # remove all perms for this entity
196                   "whostr" -> { "perm" -> None} # add/remove these perms
197                 } """
198                 return zfs.ioctl.set_fsacl(self.name, un, d)
199
200         def get_fsacl(self):
201                 """Get the "zfs allow"-ed permissions on the Dataset.
202
203                 Return a dict("whostr": { "perm" -> None })."""
204
205                 return zfs.ioctl.get_fsacl(self.name)