i'dWc@sLdZddlZddlZddlmZddlmZddlmZddl m Z ddl m Z m Z ddlmZdd lmZdd lmZdd lmZmZmZmZmZmZdd lmZdd lmZddl m!Z!ddl"m#Z#dZ$dZ%dZ&dZ'dZ(dZ)dZ*dZ+dZ,dZ-dZ.dZ/dZ0dZ1dZ2de fd YZ3d!e fd"YZ4d#e fd$YZ5d%e fd&YZ6d'e fd(YZ7d)efd*YZ8d+e8fd,YZ9d-e8fd.YZ:d/e fd0YZ;d1e<fd2YZ=dS(3ss logical.py -- library containing class definitions for logical DOC objects, including Zpool, Filesystem, and Zvol iN(tetree(tNVList(tNV_UNIQUE_NAME(tPopen(t DataObjectt ParsingError(tDataObjectDict(tINSTALL_LOGGER_NAME(tvdevs(tbe_listtbe_initt be_destroyt be_activatetbe_mountt be_unmount(t ShadowLogical(t ShadowZpool(tSize(tset_vdevs/usr/sbin/beadms /usr/sbin/dfs/usr/sbin/dumpadms/usr/sbin/lofiadms/usr/sbin/mkfiles/usr/sbin/mounts/usr/sbin/newfss/usr/sbin/swaps/usr/sbin/umounts /usr/sbin/zfss/usr/sbin/zpooltsolarissboot-environmentsbe-names be-mountpointtLogicalcBskeZdZdZdZedZedZeed dZ dZ dZ dZ RS( s! logical DOC node definition cCs;tt|j|t|_t|_t||_dS(N(tsuperRt__init__tFalsetnoswaptnodumpRt _children(tselftname((s logical.pyRFs  cCsQtjd}|jdt|jj|jdt|jj|S(NtlogicalRR(RtElementtsettstrRtlowerR(Rtelement((s logical.pytto_xmlOscCs|jdkrtStS(s; Returns True if the element has the tag 'logical' R(ttagtTrueR(tclsR"((s logical.pyt can_handleUscCs|jd}|jd}td}|dk ry%itd6td6|j|_Wqtk r~tddqXn|dk ry%itd6td6|j|_ Wqtk rtddqXn|S( NRRRttruetfalses$Logical element's noswap attribute s must be either 'true' or 'false's$Logical element's nodump attribute ( tgetRtNoneR%RR!RtKeyErrorRR(R&R"RRR((s logical.pytfrom_xml]s   %  % cCsS|r|rtdnt|}||_||_||_|j||S(sk add_zpool() - method to create a Zpool object and add it as a child of the Logical object s:Zpool cannot be marked as the boot pool and the root pool.(t ExceptiontZpooltis_roottis_boott mountpointtinsert_children(Rt zpool_nameR0R1R2t new_zpool((s logical.pyt add_zpoolss      cCs|jd|jdtdS(sC delete_zpool() - method to delete a specific Zpool object Rt class_typeN(tdelete_childrenRR/(Rtzpool((s logical.pyt delete_zpoolscCs(tt|j}t||_|S(s method to override the parent's version of __copy__. We want the _children list to be a shadow list instead of a flat list (RRt__copy__RR(Rtnew_copy((s logical.pyR;scCsd|j|jfS(NsLogical: noswap=%s; nodump=%s(RR(R((s logical.pyt__repr__sN(t__name__t __module__t__doc__RR#t classmethodR'R-RR+R6R:R;R=(((s logical.pyRBs    R/cBsOeZdZdddZdZedZedZe dZ e dZ dZ e dZ e d Ze d Ze d Zd Zd ZddZgddZedZedZdZdZdZddZdZdejdedZ dZ!dZ"dZ#RS(s zpool DOC node definition cCsttt|j|d|_t|_t|_||_t|t sX|g|_ n ||_ t ||_ dS(Ntcreate( RR/RtactionRR0R1R2t isinstancetlistt vdev_listRR(RRRFR2((s logical.pyRs     cCstjd}|jd|j|jd|j|jdt|jj|jdt|jj|j dk r|jd|j n|S(NR9RRCR0R1R2( RRRRRCR R0R!R1R2R+(RR"((s logical.pyR#scCs0|jdkrtS|jddkr,tStS(s{ Returns True if element has: - the tag 'zpool' - a name attribute otherwise return False R9RN(R$RR*R+R%(R&R"((s logical.pyR's cCs;|jd}|jd}|jd}|jd}|jd}t|}|dk ro||_n|dk ry%itd6td6|j|_Wqtk rt dd qXn|dk ry%itd6td6|j|_ Wqtk rt d d qXn|dk r7||_ n|S( NRRCR0R1R2R(R)s'Zpool element's is_root attribute must sbe either 'true' or 'false's'Zpool element's is_boot attribute must ( R*R/R+RCR%RR!R0R,RR1R2(R&R"RRCR0R1R2R9((s logical.pyR-s.    %  %   cCsM|jdt}|rFx+|D] }d|jkr|jdSqWn|jS(s property to return the pool's realname (the name it will be the next time it's exported) as set in the pool object's PoolOptions R7trealname(t get_childrent PoolOptionst data_dictR(Rtpool_options_listt pool_options((s logical.pyRGs  cCsItd|jg}tj|dtjdtjdtj}|jdkS(s: property to check for the existance of the zpool REtstdouttstderrt check_resulti(tZPOOLRRt check_calltSTOREtANYt returncode(Rtcmdtp((s logical.pytexistss c Cs|dkrtd|n|js,dStddd|dd d |jg }tj|d tjd tjd t}|j j S(sD private method to return all datasets of a particular type t filesystemtvolumetsnapshotsdataset_type not supported: %sREs-Hs-ts-oRs-rRMRNtlogger(s filesystemRYssnapshotN( t ValueErrorRWR+tZFSRRRQRRtILNRMt splitlines(Rt dataset_typeRURV((s logical.pyt_get_dataset_namess    cCs7g}x*|jdD]}|jt|qW|S(sC method to return all filesystems which belong to the pool RX(Ratappendt Filesystem(Rtfs_listtfs((s logical.pyt filesystems scCs7g}x*|jdD]}|jt|qW|S(s? method to return all volumes which belong to the pool RY(RaRbtZvol(Rtvol_listtvol((s logical.pytvolumesscCs |jdS(sA method to return all snapshots which belong to the pool RZ(Ra(R((s logical.pyt snapshotsscCs|jrtj|jSdS(s method to return a dictionary representing this pool's vdev(s) and each vdev's devices. dictionary is keyed by vdev name ('none' if it's not named) and each value is a list of disk aliases. N(RWRt_get_vdev_mappingR(R((s logical.pyR"s cCs|jdt}|s:tdt}|j|n:d}x1|D]}d|jkrG|}PqGqGW|d}|j|jd<||_dS(sW method to set name of Zpool object with 'temp_name' and set Zpool object's 'realname' property with current name. Upon creation, pool will be named 'temp_name', but because it will be set up with the 'realname' pool property, upon export of the pool, zfs will rename it to 'realname'. R7RGiN(RHRIR+tdictR3RJRt_name(Rt temp_nameRKRLtentry((s logical.pyt set_temp_name+s  cCsQtdd||f|jg}|sMtj|dtjdtjdtndS(s/ method to set a property for the pool Rs%s=%sRMRNR[N(RPRRRQRRR^(Rtpropnamet propvaluetdry_runRU((s logical.pyRKstallc Cstd||jg}tj|dtjdtjdt}t}xC|jjdD].}|j j \}}}}|||R?R@R+RR#RAR'R-tpropertyRGRWRaRfRjRkRRqRR*RBRRR^RRRRRRRtgb_unitsRRR;R=(((s logical.pyR/s8       2  *     RcBsGeZdZdZdZedZedZdZRS(s vdev DOC node definition cCs#tt|j|d|_dS(Ntmirror(RRRR(RR((s logical.pyR5scCs9tjd}|jd|j|jd|j|S(NRRR(RRRRR(RR"((s logical.pyR#:scCs|jdkrtStS(NR(R$R%R(R&R"((s logical.pyR'@scCsF|jd}|jd}t|}|dk rB||_n|S(NRR(R*RR+R(R&R"RRR((s logical.pyR-Fs    cCsd|j|jfS(NsVdev: name=%s; redundancy=%s(RR(R((s logical.pyR=Os( R>R?R@RR#RAR'R-R=(((s logical.pyR1s    RccBs eZdZdZedZedZdZedZ edZ dZ e dZ d Zd ZeeZe d Ze d Ze d ZdZe dZde dZe dZe dZe dZedZRS(s$ Filesystem DOC node definition cCs5tt|j|d|_d|_t|_dS(NRB(RRcRRCR+R2Rtin_be(RR((s logical.pyRWs  cCs|jdk r|jr[|jjdt}tjj|jjd|j|jj dStjj|jj|jj dSn|jSdS(s Keep a full_name attribute with the entire ZFS path for the filesystem. This is done because Filesystem objects can be created via Zpool.add_filesystem, simple instantiation, or with the in_be attribute set. R7tROOTRN( tparentR+Rtget_first_childtBEtostpathtjoinRtlstrip(Rtbe((s logical.pyt full_name_s (cCs|jdk r|jr[|jjdt}tjj|jjd|j |j j dStjj|jj|j j dSn|j SdS(s The full_realname attribute returns the full name as it will be the next time the zpool in which this filesystem belongs will be imported. R7RRN( RR+RRRRRRRGRR(RR((s logical.pyt full_realnamers cCs}tjd}|jd|j|jd|j|jdk rZ|jd|jn|jdt|jj |S(NRXRRCR2R( RRRRRCR2R+R RR!(RR"((s logical.pyR#scCs0|jdkrtS|jddkr,tStS(s Returns True if element has: - the tag 'filesystem' - a name attribute - an action attribute otherwise return False RXRN(R$RR*R+R%(R&R"((s logical.pyR's cCs|jd}|jd}|jd}|jd}t|}|dk r`||_n|dk rx||_n|dk ry%itd6td6|j|_Wqt k rt ddqXn|S( NRRCR2RR(R)s%Filesystem element's in_be attribute s must be either 'true' or 'false'( R*RcR+RCR2R%RR!RR,R(R&R"RRCR2RRX((s logical.pyR-s"        cCs=d|j|jf}|jdk r9|d|j7}n|S(NsFilesystem: name=%s; action=%ss; mountpoint=%s(RRCR2R+(RR((s logical.pyR=scCsu|j|}|r=||jkr=|jdtd|ntd|g}tj|dtjdtjdtdS(s snapshot - method to create a ZFS shapshot of the filesystem snapshot_name - name of the snapshot to create overwrite - boolean argument to determine if ZFS should delete an existing snapshot with the same name (if it exists) RtRZRMRNR[N( tsnapnamet snapshot_listRRR]RRQRRR^(Rt snapshot_namet overwritetsnapRU((s logical.pyRZs cCs|jd|S(sNReturns the full (dataset@snapshot) name based on the given short namet@(R(Rt short_name((s logical.pyRsc Cs^tddddddddd |jg }tj|d tjd tjd t}|jjS( so Get list of snapshots. Snapshots returned will be in creation time order with the earliest first REs-Hs-oRs-tRZs-stcreations-rRMRNR[(R]RRRQRRR^RMR_(RRURV((s logical.pyt _snapshotss  cCsatdg}|r"|jdn|j|j|tj|dtjdtjdtdS(sV rollback - method to rollback a ZFS filesystem to a given checkpoint trollbacks-rRMRNR[N(R]RbRRRQRRR^(Rt to_snapshott recursiveRU((s logical.pyRs  cCsjtdd||f|jg}|r8|jddn|sftj|dtjdtjdtndS( s8 method to set a property on the ZFS filesystem Rs%s=%sis-rRMRNR[N(R]RtinsertRRQRRR^(RR{R|RtRRU((s logical.pyRs cCs`td||jg}|r.|jddn|s\tj|dtjdtjdtndS(s< method to inherit a property on the ZFS filesystem R}is-rRMRNR[N(R]RRRRQRRR^(RR{RtRRU((s logical.pyR}s c Cs[tdddd||jg}tj|dtjdtjdtjdt}|jj S( sI method to return the value for a ZFS property of the filesystem R*s-Hs-oR|RMRNtstderr_loglevelR[( R]RRRQRRRtDEBUGR^RMRv(RR{RURV((s logical.pyR*sc Cs|jstddg}|jdt}|d k rL|j|jn|jd k rx|jdd|jgn|j|j |st j |dt j dt j dt d id d 6qnd S( s create the filesystem RBs-pR7s-os mountpoint=%sRMRNR[tenvtCtLC_ALLN(RWR]RtOptionsR+R~t get_arg_listR2RbRRRQRRR^(RRtRUt zfs_options((s logical.pyRBs  cCs|jr|stdg}|r1|jdn|dk rV|j|j|n|j|jtj|dtjdtjdt qndS(s destroy the filesystem Rs-rRMRNR[N( RWR]RbR+RRRRQRRR^(RRtRZRRU((s logical.pyRs   c Cs]|jrYtd|jg}|sYtj|dtjdtjdtdidd6qYndS( s mount the filesystem tmountRMRNR[RRRN(RWR]RRRQRRR^(RRtRU((s logical.pyR"s  c Cs]|jrYtd|jg}|sYtj|dtjdtjdtdidd6qYndS( s umount the filesystem tumountRMRNR[RRRN(RWR]RRRQRRR^(RRtRU((s logical.pyR+s  c Csg|jrctddd||jg}|sctj|dtjdtjdtdidd 6qcnd S( s* Temporarily mount the filesystem Rs-os mountpoint=%sRMRNR[RRRN(RWR]RRRQRRR^(Rt temp_mountRtRU((s logical.pyttemporary_mount4s   cCsItd|jg}tj|dtjdtjdtj}|jdkS(s? property to check for the existance of the filesystem RERMRNROi(R]RRRQRRRSRT(RRURV((s logical.pyRW>s N(R>R?R@RRRRR#RAR'R-R=RRZRRRRRR}R*RBR+RRRRRW(((s logical.pyRcSs,         RgcBseZdZdZedZedZdZedZ edZ edZ dZ d Z d Zd Zd Zejd ZRS(s Zvol DOC node definition cCs>tt|j|d|_d|_d|_t|_dS(NRBtnoneR(RRgRRCRRRR(RR((s logical.pyRLs    cCs6|jdk r+tjj|jj|jS|jSdS(s keep a full_name attribute with the entire ZFS path for the zvol. This is done because Zvol objects can either be created via Zpool.add_zvol or by simple instantiation (Zvol("tank/zv")) N(RR+RRRR(R((s logical.pyRUscCs6|jdk r+tjj|jj|jS|jSdS(s The full_realname attribute returns the full name as it will be the next time the zpool in which this zvol belongs will be imported. N(RR+RRRRGR(R((s logical.pyRascCswtjd}|jd|j|jd|j|jd|jtj|d}|jdt|j|S(NRRRCRRtval( RRRRRCRt SubElementR R(RR"R((s logical.pyR#lscCs0|jdkrtS|jddkr,tStS(s Returns True if element has: - the tag 'zvol' - a name attribute - an action attribute otherwise return False RRN(R$RR*R+R%(R&R"((s logical.pyR'ws cCs|jd}|jd}|jd}t|}|jd}|dk r|jddkr|tddn|jddkr|dks|d krtd qn|jd|_n td ||_|dk r||_n|S( NRRCRRRs"Size element must contain a 'val' t attributeRtswapsA'max' value for 'val' attribute is applicable only for swap zvol.s+Zvol element must contain a size subelement(R*RgtfindR+RRRCR(R&R"RRCRRR((s logical.pyR-s$       cCsItd|jg}tj|dtjdtjdtj}|jdkS(s9 property to check for the existance of the zvol RERMRNROi(R]RRRQRRRSRT(RRURV((s logical.pyRWs c Cs[tdddd||jg}tj|dtjdtjdtjdt}|jj S( sE method to return the value for a ZFS property of the volume R*s-Hs-oR|RMRNRR[( R]RRRQRRRRR^RMRv(RR{RURV((s logical.pyR*sc CsP|jdkrjtdtjjd|jg}|sLtj|dtjdtjdt dt j qLn|jdkr)t d tjjd|jg}|j rd}nd}|sLtj|dtjdtjdt dt j d |}|jd kr&t jt }|jd |jq&qLn#t jt }|jd|jdS(sE method to add zvol (for use as swap or dump) to live system Rs-as /dev/zvol/dskRMRNR[Rtdumps-diiROs(Unable to create dump Zvol with size %s.sEZvol %s does not have use of 'swap' or 'dump'. Not adding to system.N(ii(i(RtSWAPRRRRRRQRRR^RRtDUMPADMRRTRtwarningR(RRtRUtresultsRVR[((s logical.pyt add_to_systems0!      c Csg|jsct|jtrCtt|jjtjd}n|jdkr|jdk rt |jj }t|jd}tt|jtjdd}t||_qn |j}t ddd|g}|j dt}|dk r|j|jn|j|j|sctj|d tjd tjd td id d6qcndS(s" method to create a zvol. tMRt availableg?RBs-ps-VR7RMRNR[RRRN(RWRDRRR RR*tmb_unitsRR+RcRR]RRR~RRbRRRQRRR^(RRtt zvol_sizeRetfs_sizeRUR((s logical.pyRBs& (  c Cs|jr|stjjd|j}tdg}tj|dtjdtjdt dtj dt j }|j jd}x]|D]U}|j|rtd |g}tj|dtjdtjdt dt j qqWtjtgdtjdtjdt }x|j jD]Q}|jjd r||krjt jt }|jd |jPqjqqWtd |jg}tj|dtjdtjdt qnd S(s# method to destroy a zvol. s /dev/zvol/dsks-lRMRNR[RORis-ds Dump device:s:Unable to destroy Zvol '%s' as it is under dumpadm controlRN(RWRRRRRRRQRRR^RSRRRMR_t startswithRRRRR]( RRtt full_pathRURVt swap_listRpRyR[((s logical.pyRs6         cCs d|j|j|j|jfS(Ns)Zvol: name=%s; action=%s; use=%s; size=%s(RRCRR(R((s logical.pyR="scCs@|j|jj|j||t|t||_dS(s4 resize() - method to resize a Zvol object. N(tdeleteRRRR R(Rtnew_sizeR((s logical.pytresize&s (R>R?R@RRRRR#RAR'R-RWR*RRBRR=RRR(((s logical.pyRgHs     ! . RcBsJeZdZdZdZdZedZedZdZ dZ RS(s)Base class for all ZFS options variationsRtoptions-ocCs)tt|jd|dtdtdS(sInitialize ZfsOptionsDict. t generate_xmlt value_as_attrN(RRRR+R%(RRRJR((s logical.pyR:scCsvt}xf|jD][}|j|j|rP|jd||j|fq|jd||j|fqW|S(s9Returns a list of arguments suitable for passing to Popens%s="%s"s%s=%s(RERJRbtOPTIONS_PARAM_STR(Rtquotetarg_listtkey((s logical.pyRDs !"cCsftdt}|jdks3t|jdkr7|Sx(|jD]}|j|||dfRRR%(R((s logical.pyR=]s ( R>R?R@tTAG_NAMEt SUB_TAG_NAMERRRRRR=(((s logical.pyR3s RIcBseZdZdZRS(s pool_options DOC node definition Its a DataObjectDict using the tags like: RL(R>R?R@R(((s logical.pyRIbs tDatasetOptionscBseZdZdZdZRS(s' dataset_options DOC node definition Its a DataObjectDict using the tags like: tdataset_optionss-O(R>R?R@RR(((s logical.pyRqs RcBseZdZddZedZdZedZ edZ edZ edZ edZ d Zd edddded Zd Zd ZddZddZRS(s be DOC node definition cCsS|dkrt}ntt|j|d|_||_d|_d|_dS(N( R+tDEFAULT_BE_NAMERRRt created_namet initial_nameR2tpoolname(RR((s logical.pyRs     cCs|jp|jS(N(RR(R((s logical.pyRscCs&tjd}|jd|j|S(NRR(RRRR(RR"((s logical.pyR#scCs|jdkrtStS(s] Returns True if element has: - the tag 'BE' otherwise return False R(R$RR%(R&R"((s logical.pyR'scCs1|jd}|r$t|}n t}|S(NR(R*R(R&R"RR((s logical.pyR-s  cCst|j|j}|S(s7 property to check for the existance of the BE (R RR(RRW((s logical.pyRWscCs!t|j|jdd}|S(s- returns True if BE is the active BE ii(R RR(Rtactive((s logical.pyt is_activescCs9t|j|j}t|dks-t|ddS(s9 returns a list of datasets that make up this BE iii(R RRRtAssertionError(Rtbelist((s logical.pytdatasetsscCs4d|j}|jdk r0|d|j7}n|S(Ns BE: name=%ss; mountpoint=%s(RR2R+(RR((s logical.pyR=s trpoolc Cs|s|jdt} t|j|d|d| d|d|d|d|d|} |r| d k rtjt} | jd | | |_ n|j d k r|j |j ||n||_ nd S( sZ method to initialize a BE by creating the empty datasets for the BE. R7t nested_betzfs_propertiesRdtfs_zfs_propertiestshared_fs_listtshared_fs_zfs_propertiestallow_auto_namings!Initialized BE with auto name: %sN( RRR RR+RRR^RRR2RR( RRtt pool_nameR RdRRRRt be_optionstnew_nameR[((s logical.pytinits    cCs|st|jndS(s! method to destroy a BE. N(R R(RRt((s logical.pyRscCs|st|jndS(s" method to activate a BE. N(R R(RRt((s logical.pytactivatescCsj|sftjj|s(tj|n|rDt|j||nt|j||j||_ndS(s method to mount a BE. N(RRRWtmakedirsR RRR2(RR2Rttaltpool((s logical.pyRscCsB|s>|rt|j|nt|j|jd|_ndS(s! method to unmount a BE. N(RRRR+R2(RRtR((s logical.pytunmounts N(R>R?R@R+RRRR#RAR'R-RWRR R=RR%RRRRR(((s logical.pyRs$        tLoficBseZdZdddeedZedZedZej dZdZ dZ dZ d Z d Zd Zd Zd ZdZRS(ss class representing a loopback file interface. The backing-store does not have to exist; it can be created icCsU||_||_||_||_||_d|_d|_t|_ ||_ dS(s= constructor for the class ramdisk - path to the file to use as a backing store mountpoint - Path to mount the file as a loopback device. If not provided, lofi device is not mounted. size - size of the file to create nbpi - number of bytes per inode - used when backend file is formatted with ufs(7fs). If not provided, newfs(1m) uses default value. run_newfs - If set to True, backend file is formatted with ufs(7fs). labeled - If set to True, lofi device is created as labeled. N( tramdiskR2Rt run_newfstlabeledR+tlofi_blktlofi_rawRt_mountedtnbpi(RRR2RR"RR((s logical.pyRs        cCstjj|jS(s< property to check for the existance of the ramdisk (RRRWR(R((s logical.pyRW/scCs|jS(sj property to return a boolean value representing if the lofi device is currently mounted. (R!(R((s logical.pytmounted5scCs ||_dS(N(R!(RR((s logical.pyR#<scCsW|jsStd|j|jg}|sStj|dtjdtjdtqSndS(sB create_ramdisk - method to create the ramdisk, if needed s%dkRMRNR[N(RWtMKFILERRRRQRRR^(RRtRU((s logical.pytcreate_ramdisk@s  cCs|jS(s$ Returns block lofi device. (R(R((s logical.pytget_blkKscCs|jS(s" Returns raw lofi device. (R (R((s logical.pytget_rawPscCs |jdk S(so Returns True if image file is currently exported as lofi device. Otherwise returns False. N(RR+(R((s logical.pyRUscCs(|j||jr.tdd|jg}ntd|jg}|stj|dtjdtjdt}|jj |_ |jr|j j dd|_ q|j j dd |_ n|j rtd d d d g}|jdk r|jd|jt|jn|j|j |stjt}|jddj|t|dtjdtjdtj}|jdqn|jdk r$tjj|j r| rtj|jntddd d|j |jg}|stj|dtjdtjdtnt |_!ndS(sB create - method to create, newfs and mount a lofi device s-ls-aRMRNR[tdsktrdsktlofitrlofis-mt0s-otspaces-is Executing: %sRtstdinsy s-FtufstrwN("R%RtLOFIADMRRRQRRR^RMRvRtreplaceR RtNEWFSR"R+RbR RRRRtPIPEtDEVNULLt communicateR2RRRWRtMOUNTR%R#(RRtRURVR[((s logical.pyRB\s@         cCsY|jrUtd|jg}|sItj|dtjdtjdtnt|_ndS(s( method to unmount the ramdisk. s-fRMRNR[N(R#tUMOUNTR2RRQRRR^R(RRtRU((s logical.pyRs   cCss|js dS|j|tdd|jg}|s]tj|dtjdtjdtnd|_d|_ dS(s7 method to unmount and destroy the lofi device Ns-fs-dRMRNR[( RWRR1RRRQRRR^R+R (RRtRU((s logical.pyRs    c Cs|jrtd|jg}tj|dtjdtj}g|jjD]}|j^qL}|dj \}}}}} } d|||| f} nd} | S(s method to get usage. s-hRMRNis+size %s, used %s, available %s, capacity %ssunavailable (not mounted)( R#tDFR2RRQRRRMR_RRw( RRURVtlt size_infoRRtusedtavailtcapR2tusage((s logical.pyt get_usages !("cCs,d|j|j|j|j|j|jfS(NsMLofi: ramdisk=%s; mountpoint=%s; size=%s; lofi_device=%s; mounted=%s; nbpi=%s(RR2RRR!R"(R((s logical.pyR=sN(R>R?R@R+RRRRWR#tsetterR%R&R'RRBRRR@R=(((s logical.pyRs     5  (>R@RRtlxmlRt libnvpairRtlibnvpair.constRtsolaris_installRtsolaris_install.data_objectRRt%solaris_install.data_object.data_dictRtsolaris_install.loggerRR^tsolaris_install.targetRtsolaris_install.target.libbeR R R R R Rt%solaris_install.target.shadow.logicalRt#solaris_install.target.shadow.zpoolRtsolaris_install.target.sizeRt zfs.ioctlRtBEADMR9RR1R$R7R3RR8R]RPRtBOOT_ENVIRONMENTtBE_NAMEt BE_MOUNTPOINTRR/RRcRgRRIRRtobjectR(((s logical.pytsR  .X"/