i'dWc@sdZddlZddlZddlZddlZddlZddlZddlZddlm Z ddl m Z ddl m Z ddlmZddlmZmZmZmZmZddlmZdd lmZdd lmZmZdd lmZm Z m!Z!m"Z"dd l#m$Z$m%Z%m&Z&m'Z'dd l(m)Z)dZ*dZ+dZ,dZ-dZ.dZ/dZ0dZ1dZ2dZ3dZ4dZ5dZ6dZ7dZ8dZ9de:fdYZ;d e<fd!YZ=d"e<fd#YZ>d$e<fd%YZ?d&Z@d'ZAd(ZBd)ZCd*ZDd+ZEd,ZFd-ZGd.ZHd/ZIdd0ZKd1ZLd2ZMd3ZNd4ZOd5ZPd6ZQdd7ZRd8ZSd9ZTd:ZUd;ZVdd<ZWdd=ZXdd>ZYdd?ZZdd@Z[ddAZ\ddBZ]dCZ^dDZ_dEZ`ddFZae dGdHdIdJdKgZbdLZcdMZddNZedOZfdddddPZgdddddQZhdddddRZidSZjdTZkdUZldS(Vs+ Utility functions for the archive library iN(tDiskBootConfig(t namedtuple(tetree(t attrgetter(tPopentruntCalledProcessErrort SetUIDasEUIDt_(t InstallEngine(tINSTALL_LOGGER_NAME(tlibbetvdevs(tZpooltZvolt FilesystemtBE(tDiskt GPTPartitiont PartitiontSlice(tSizes/usr/sbin/beadms /usr/bin/curls#/usr/lib/brand/shared/get_active_bes/usr/sbin/labeladms /usr/bin/pkgs/usr/sbin/prtconfs/usr/sbin/prtdiags/usr/sbin/virtinfos/usr/sbin/zlogins/usr/sbin/zonecfgs/usr/bin/zonenames /usr/sbin/zfss/usr/sbin/zpools/usr/sbin/zoneadms/usr/sbin/zonep2vchkcCstjjd|dS(s~Utility to write to stdout while spinner is in play. Drops a ' ' on the front of output and writes it out to stdout. s N(tsyststdouttwrite(toutput((sutil.pyt spinwriteEst ArchiveErrorcBseZdZRS(s,General exception class for archive library.(t__name__t __module__t__doc__(((sutil.pyRMst SystemInfocBseZdZddZedZejdZedZejdZedZ e jdZ edZ e jd Z e d d Z ed Z e jd Z edZejdZRS(sbUtility class which organizes and encodes system-related information such as hardware resources and software components. Optional 'zone' constructor argument will derive information from a zone, otherwise it is the executing environment. Attributes: hostname hostname of the system (nodename) system_type system model or virtual system type os_name e.g. 'Solaris 11.2' os_version branch of osnet-incorporation arch ISA ('sparc' or 'i386') trusted boolean, True if labeling is enabled (global only) cCs|dk rBt|ts*tdn||_t|_nd|_d|_d|_d|_d|_ d|_ d|_ d|_ dS(s9Construct a new SystemInfo object. If the optional 'zone' argument is passed, the system information is based upon that particular zone. Otherwise, it's based upon the executing environment. Arguments: zone An optional zone to base the instance upon. s!'zone' argument is zonename (str)N( tNonet isinstancetstrt ValueErrort_zonet get_zonenamet _exec_zonet _hostnamet _system_typet_os_namet _os_versiont_archt_trusted(tselftzone((sutil.pyt__init__`s         cCs(|jdkr!tj|_n|jS(N(R+R tplatformt processor(R-((sutil.pytarchzscCs ||_dS(N(R+(R-tvalue((sutil.pyR2scCs|jdkr|j|jkr3tj|_qt|jdkrttt |jdg}WdQX|j j |_qd|_n|jS(Ntrunningthostnames ( R'R R$R&tsockett gethostnametget_zone_stateRRtZLOGINRtstrip(R-tp((sutil.pyR5s  cCs ||_dS(N(R'(R-R3((sutil.pyR5scCs|jdkr|jdkrybtjd}ttdtj}t t t |j |j jdjdj|_Wqttdddd d g}|j j|_qXqt|jd krd |_qd |_n|jS(Ntglobals!^System\s+Configuration\:\s+(.*)$t check_resultiis-ctcurrenttlists-Hotnames solaris-kzs kernel-zonesnon-global-zone(R(R R$tretcompileRtPRTDIAGRtANYtfiltertbooltmaptmatchRt splitlinestgroupR:tVIRTINFOtget_zone_brand(R-trxR;((sutil.pyt system_types 5  cCs ||_dS(N(R((R-R3((sutil.pyRNsc Cs|jdkr|j|jks6t|jdkrptdd&}|jjdj|_WdQXqt |jdkrt t t |jddg}WdQX|j jdj|_qttdn|jS(Ns solaris-kzs /etc/releasetriR4tcats solaris-kz zones must be running(R)R R$R&RLtopentreadRIR:R8RRR9Rt RuntimeErrorR(R-tfR;((sutil.pytos_names( !cCs ||_dS(N(R)(R-R3((sutil.pyRUst _OSVersionsversion, branchc Cs|jdkrt|jdkr3d}d}nod}|j|jks`t|jdkrttd|gdidd 6}net|jd krt0tt |jtd|gdidd 6}WdQXnt t d t j d }ttt|jg|jjD]}tj|^qd jd}t j d}ttt|jg|jjD]}tj|^qtd jd}tj|||_n|jS(Nt solaris10s5.10sN/As'consolidation/osnet/osnet-incorporations solaris-kztinfotenvtCtLC_ALLR4s solaris-kz zones must be runnings^Version: (\S+)$iis^Branch: (\S+)$(R*R RLR$R&RtPKGR8RR9RSRRARBRERFRGRHRRIR"R:RJRRV(R-tversiontbranchtonR;t version_retlt branch_re((sutil.pyt os_versions. %  > >cCs.t|tsttjj||_dS(N(R!ttupletAssertionErrorRRVt_makeR*(R-R3((sutil.pyRcscCs4|jdkr-|jdkr-t|_n|jS(NR<(R&R,R ttrusted_enabled(R-((sutil.pyttrustedscCs ||_dS(N(R,(R-R3((sutil.pyRhsN(RRRR R/tpropertyR2tsetterR5RNRURRVRcRh(((sutil.pyRRs  %tBootEnvcBs_eZdZddZedZejdZdZdZ dZ dZ RS( s+Utility class for Solaris Boot Environment creation and management during archive preparation and creation. Attributes: name BE name mountpoint BE mountpoint mounted True if mounted datasets list of datasets by name which comprise the BE Methods: create() Create a new BE 'name', cloned from the active BE mount() Mount the BE on 'mountpoint' unmount() Unmount the BE destroy() Destroy the BE cCsf||_tjjd||_t|_g|_|jgtj D]}|d^qFk|_ dS(scConstruct an instance of BootEnv. Arguments: name BE name s/system/volatileiN( R@tostpathtjoint mountpointtFalsetmountedt _datasetsR tbe_listt_exists(R-R@tbe((sutil.pyR/s    cCsm|jrf|j rfttddd|jg}g|jjD]}|jdd^qA|_n|jS(NR?s-ds-Ht;i(RtRrRtBEADMR@RRItsplit(R-R;tds((sutil.pytdatasetss5cCs ||_dS(N(Rr(R-R3((sutil.pyRz&scCsR|jrtd|jntttd|jgWdQXt|_dS(s Create the BEsBE '%s' existstcreateN(RtR#R@RRRwtTrue(R-((sutil.pyR{*s   c Cs9t!ttd|j|jgWdQXt|_dS(s Mount the BEtmountN(RRRwR@RoR|Rq(R-((sutil.pyR}2s "c Cs?t'ttdd|jgdtjWdQXt|_dS(sUnmount the BEtunmounts-ftstderrN(RRRwR@RtDEVNULLRpRq(R-((sutil.pyR~8s (c CsHt'ttdd|jgdtjWdQXt|_g|_dS(sDestroy the BEtdestroys-fFRN( RRRwR@RRRpRtRr(R-((sutil.pyR>s ( N( RRRR R/RiRzRjR{R}R~R(((sutil.pyRks    tZoneInfocBseZdZddZedZejdZedZedZ edZ edZ edZ ed Z ed Zejd Zed Zed ZedZejdZedZejdZdZRS(s Utility class which organizes and encodes zone-related information such as brand and configuration data. Attributes: name zonename brand zone brand (e.g. 'solaris', 'solaris-kz', etc) state state of zone (e.g. 'installed', etc) zonepath zonepath zonepath_dataset zonepath dataset rpool_dataset zone's rpool dataset varshare_dataset zone's varshare dataset delegated_datasets list of a non-global zone's delegated datasets zonetype type of zone ('global' or 'non-global') is_global boolean, True if global ip_type IP type of zone ('shared' or 'exclusive') zonecfg zone configuration (in XML) devices list of device resources (solaris-kz) Methods: update_zonecfg(exclude) Update the zonecfg by removing any dataset elements which are in the 'exclude' list. cCs|dk rBt|ts*tdn||_t|_n d|_d|_d|_d|_ d|_ d|_ d|_ d|_ d|_d|_d|_d|_dS(sConstruct an instance of ZoneInfo. Arguments: zone The zone which is described by this instance. s!'zone' argument is zonename (str)N(R R!R"R#R@R%R&t_brandt_statet _zonepatht_zonepath_datasett_rpool_datasett_varshare_datasett_delegated_datasetst _zonetypet_ip_typet_zonecfgt_devices(R-R.((sutil.pyR/_s"             cCs+|jdkr$t|j|_n|jS(N(RR RLR@(R-((sutil.pytbrandzscCs ||_dS(N(R(R-R3((sutil.pyRscCs+|jdkr$t|j|_n|jS(N(RR R8R@(R-((sutil.pytstatescCs5|jdkr.|j r.t|j|_n|jS(N(RR t is_globalt get_zonepathR@(R-((sutil.pytzonepathscCs5|jdk r.|j r.t|j|_n|jS(N(RR Rtget_zonepath_datasetR@R(R-((sutil.pytzonepath_datasetscCs:|jdkr3|jdkr3t|j|_n|jS(NR<(RR R@tget_zone_rpool_dataset(R-((sutil.pyt rpool_datasetscCs+|jdkr$t|j|_n|jS(N(RR tget_varshare_datasetR@(R-((sutil.pytvarshare_datasetscCs|jdkr|jS|jdkr|jdkrg|_tj|j}x{|jdD]g}tt |j |j }d|dkr|dj d|j|ds( RR tinsertR9RRRRxRER"tmaxRGtint(RtkzRtversions((sutil.pytget_max_zfs_versions  cCsttdddgjjS(s!Return list of ZFS pools by name.R?s-HoR@(RtZPOOLRRx(((sutil.pytget_all_zpoolsscCsDtjj}g|jdtD]}|jr"|j^q"jS(s!Return the name of the root pool.R(R RRRR tis_rootR@tpop(RR;((sutil.pyt get_root_poolscCsNt}tgd|dd|}|jrJ|jjrJ|jjjSndS(s!Return the name of the boot pool.trpnamettldpathRN(RRt versaboott boot_poolt pool_nameR (t root_pooltbootcfg((sutil.pyt get_boot_pools    cCsH|tkr"td|nttddd|gjjdS(s>Return the health (as documented in ZFS literature) of 'pool'.sZFS pool not found: %sR?s-Hothealthi(RR#RRRRx(R((sutil.pytget_zpool_healthscCstdd|g}|dk rx|jdt|jd|t,t|jjddjd}WdQXn't|jjddjd}t |S(sURetrieve the version of ZFS pool 'pool', alternatively in kernel zone 'kz'. RR]iiiN( RR RR9RRRRIRxR(RRRR]((sutil.pytget_zpool_versions  0'c Cstd||g}|dk rj|jdt|jd|tt|jjd}WdQXnt|jjd}|j\}}}}|S(s'Get value of prop passed and return it.RiiN( RR RR9RRRRIRx( tpoolnametpropRRtoutt_poolt_proptvalt_source((sutil.pytzpool_get_props  "cCs\|dk rKt|ddg}|jd|tjt|jjStj |SdS(sCReturn the vdev mapping for poolname, from remote 'kz' if provided.s/usr/bin/pythons-csR'from solaris_install.target.vdevs import _get_vdev_mapping as gv; print gv("%s")'N( R R9Rtastt literal_evalRRR:R t_get_vdev_mapping(RRR((sutil.pytzpool_get_vdev_mappings   c Csg}tdd|g}|dk rp|jdt|jd|tt|jjd}WdQXnt|jjd}xB|D]:}|j\}}}}|dkr|j |qqW|S(s8Return a list of all local properties set on 'poolname'.RtalliiNtlocal( RR RR9RRRRIRxR( RRt local_propsRt prop_linesRt_nonetpropnametsource((sutil.pytzpool_get_local_propss  "  cCstdddddg}|dk rj|jdt|jd|tt|jjSWdQXnt|jjSdS( s=Return a list of all snapshots on the system, by datasetname.R?s-HoR@s-ttsnapiiN(RR RR9RRRRI(RR((sutil.pytzfs_get_all_snapshotss  cCso|jd\}}|g}xJt|D]<}|j|dr+|jd|r+|j|q+q+W|S(s?Return a list of snapshots heirarchically rooted at 'snapshot'.t@R(RxRRtendswithR(tsnapshotRttop_dstsnapnametsnaplistR((sutil.pytzfs_snapshot_and_descendants's  &c Csd}xt||D]}tdddd|g}|d k r|jdt|jd|t+t|didd 6jjd}Wd QXn&t|didd 6jjd}|t |j 7}qW|S( sUsing 'snapshot' as a top level, get the 'referred' value on all snapshots in the heirarchy downward. return the total sum, in bytes. this serves as an estimate for the amount of space the stream will take up in a pool when deployed. iRs-HoR3treferiRYRZR[N( RRR RR9RRRRxRt byte_value(RRttotal_size_in_bytestsRR((sutil.pytzfs_get_all_snapshot_referred1s  /&c Cs4tddddddd|g }t|jjS(sReturn a list of all filesystems and volumes in this pool, by name. Note snapshots, while datasets, are not returned. R?s-Hs-tsfilesystem,volumes-oR@s-r(RRRRx(RR((sutil.pytget_pool_datasetsFs c CsMtjj}g}t|jttttd|jdt|S(s~Return a list of all Filesystem and Volume datasets on the system. Note snapshots, while datasets, are not returned. R@R( R RRRGRRRRR (Rtds_list((sutil.pytget_all_datasetsPs c Cstjt}ttddgdidd6}g|jjD]}|jd^qA}tddd d d d d dddg }t|didd6jj}g}x:|D]2}||kr|jd||j |qqW|S(sCheck the host global zone's platform portability by determining if any key support software packages are missing. Return a list of packages by name which are found to be missing. R?s-asRYRZR[itcontentss-rs-Hs-otfmris-ttdepends-as type=groups'pkg:/group/system/solaris-core-platforms^UnifiedArchive: portability notice, '%s' is notinstalled. This may affect archive portability.( tloggingt getLoggertILNRR\RRIRxtdebugR(tloggerR;RaRt get_contenttcontenttmissingtpkg((sutil.pytlist_missing_platform_support]s","   cCs|dkrtddg}ntd|ddg}t}xAt|didd6jjD]}|j|jdq_W|S( s/Return set of publishers that are currently sett publishers-Hs-RRYRZR[iN(R R\tsetRRRItaddRx(t be_mountpointRt publishersR((sutil.pytpkg_get_publishersws  )t OriginInfoturitproxytkeytcertcCsg}d\}}}}ttd|gdidd6}x"|jjdD] }|j}|jdr|r|jt||||n|j d}d\}}}qN|jdr|j d}|d kr[d }q[qN|jd r$|j d}|d kr[d }q[qN|jd rN|j d}|d kr[d }q[qNqNW|r|jt||||n|st t d |n|S(sReturn a list of this publisher's origins. Each origin item is a namedtuple that consists of its URI, Proxy, SSL Key and Cert.R-RYRZR[is Origin URI:isProxy:R sSSL Key:s SSL Cert:s5unable to determine repository URI for publisher '%s'N(NNNN(NNN( R RR\RRIR:RRR3RxRSR(R-toriginsR4R5R6R7R;R((sutil.pytpkg_get_originss8"        cCs(|ddkr|S|d|dSdS(sBReturn the next-largest header-aligned (i.e. 512b-aligned) offset.iiN((toffset((sutil.pyttar_header_alignscCsFy7ttdgjjdjd}|dkSWntSXdS(s_Return True if current environment has labeling enabled. Valid in a global zone only. RXiitenabledN(RtLABELADMRRIRxRp(R((sutil.pyRgs )cCs2t}tgd|dd|}|jdk S(s9Return True if current environment has VersaBoot enabled.RRRN(RRRR (RR((sutil.pytversaboot_enableds cCsYt||||}td|g}x(|D] }|jt|d|q+Wt|S(Ns--headi(tcurl_build_credential_optstCURLRtlenR(turlR6R7tcacertthttp_auth_tokentcredential_optsttest_cmdtarg((sutil.pyt_curl_get_heads    c CsF|s |r(|o| r(tdnyt|||||}Wntk rctdnXx|jjD]0}|jdrt|jdjdk SqtWt ||||}t dddd |g}x(|D] } |j t |d| qWy7t |}|jjd } d | kr2tStSWntSXd S( sReturn True if server passed in 'url' accepts ranges. Optionally pass crendentials in key, cert, cacert and http_auth_token. skey and cert must be pairedsunable to reach hosts Accept-Rangesitnones-sSs--heads-rs0-32is206 Partial ContentN(R#RHRRSRRIRRxtlowerR?R@RRARR|Rp( RBR6R7RCRDR;RRERFRGtresponse((sutil.pytserver_accepts_rangess,      cCs>yt|||||Wntk r9tdnXdS(sVerify the credentials passed in. Valid combinations are key and cert, cacert, or all three. Raises RuntimeError if credentials are invalid. scredentials invalidN(RHRRS(RBR6R7RCRD((sutil.pytverify_credentialss cCsg}|dk r(|jd|gn|dk rJ|jd|gn|dk rl|jd|gn|dk rd|}|jddd|gn|S( sUtility routine to set up an array of credentials options for curl. Returns an empty list of no credentials are passed in. s--keys--certs--cacertsX-Auth-Token: %ss-XtGETs--headerN(R R(R6R7RCRDt cred_optstx_http_auth_token((sutil.pyR? s     c Cst|j|j|j|j}dd }ytdd||jg}x(|D] }|jt|d|qPWt |j j dd}yt |d }Wn#t td |jnXWn+tk r}t t|jjnX|S( Ns%s-%si|is-sSs-ritiis!%s is not a valid Unified Archive(i|i(R?R6R7RCRDR@tgeturlRRARRRxRRSRRtpopenR( R4t credentialsREt range_strtget_sizeRGtdatatdescriptor_sizeR((sutil.pytget_descriptor_sizes$     c Cst}xs|jdtD]_}|j|krA|jqnx'tttgD]}|jd|qQW|j |jqWdddg}t t t tg}xU|D]M}xD|jd|D]0}t |dr|j|krd|_qqWqWt t t g}x|jdtD]} t| _t} | j|krDqnxN|D]F}| r[Pnx3| jd|D]}|j|krnt} PqnqnWqKW| s| jqqW|jS(sPrune an existing Target object to contain only the ZFS pools and their respective physical components for use during AI deployment. Rtpreservet use_existingtuse_existing_solaris2tactionR{(R?RR R@tdeleteRRRtdelete_childrenRRRRthasattrR]RR|tall_names_to_xmlRptin_zpoolt get_childrentget_xml_tree_str( troott zpool_listtzpoolstzptchildtactionstobjstobjt child_listtdisktdisk_participates((sutil.pytcreate_origin_target=s<      (mRRR#RlR0RAR6Rtbootmgmt.bootconfigRt collectionsRtlxmlRtoperatorRtsolaris_installRRRRRtsolaris_install.engineR tsolaris_install.loggerR R%tsolaris_install.targetR R tsolaris_install.target.logicalR RRRtsolaris_install.target.physicalRRRRtsolaris_install.target.sizeRRwR@RR=R\tPRTCONFRCRKR9RRRRRRRt ExceptionRtobjectRRkRRRRRRRRR8R%RLR RRRRRRRRRRRRRRRRRRRRRR,R2R3R9R;RgR>RHRLRMR?RYRp(((sutil.pyts       ("" I                        )     %