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