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