i'dWc@sdZddkZddkZddkZddkZddkZddkZddkZddkZddk l Z ddk l Z l Z lZddklZddklZddklZlZlZlZddklZlZdd klZlZdd klZl Z l!Z!l"Z"l#Z#dd k$l%Z%dd k&l'Z'dd k(l)Z*ddk+l,Z-ddk.l/Z/l0Z0ddk1l2Z2ddk3l4Z4l5Z5l6Z6l7Z7l8Z8ddk9l:Z:l;Z;l<Z<l=Z=l>Z>l?Z?l@Z@lAZAddkBlCZCdZDdZEdZFdZGdZHdZIdZJdZKdZLdZMdZNdZOd ZPd!ZQd"ZRd#ZSd$ZTd%ZUd&ZVd'ZWd(ZXd)ZYd*ZZd+Z[d,Z\d-Z]d.e*fd/YZ^e_d0joLd1Z`d2Zad3Zbd4Zcd5Zdd6Zed7Zfe`\ZgZhegio$efegii oeijnne'd8eYe^d9Zkekild:emeginoeaekionegipoebekionegiqoecekionegiroedekionegisoeeekionegitoekioiuGHnndS(;s discovery.py - target discovery checkpoint. Attempts to find all target devices on the given system. The Data Object Cache is populated with the information. iN(tSystemFirmware(t getmntanyt mnttab_opent mnttab_close(tBootPool(tget_curr_bootdisk(tALIAStBUSt CONTROLLERtDRIVE(tdescriptors_by_typetdescriptor_from_key(tefi_freetefi_read(tApplicationDatatCalledProcessErrortPopentis_install_envtrun(tDataObjectDict(t InstallEngine(tAbstractCheckpoint(tINSTALL_LOGGER_NAME(t CRO_LABELtTarget(tbe_list(tBEt FilesystemtLogicaltZpooltZvol(tDisktDiskPropt DiskGeometryt DiskKeywordtIscsit GPTPartitiont PartitiontSlice(tSizes/usr/sbin/biosdevs /boot/solaris/bin/create_diskmaps/usr/sbin/croinfos/usr/sbin/devfsadms/sbin/dhcpinfos/usr/sbin/dladms/usr/sbin/eeproms/usr/sbin/fstyps/usr/sbin/iscsiadms/usr/sbin/mounts/usr/lib/fs/pcfs/mounts/usr/sbin/prtvtocs /usr/bin/svcss/usr/sbin/svcadms/usr/sbin/umounts /usr/sbin/zfss/usr/sbin/zpools /dev/zvol/dsks/dev/zvol/rdsktdisktzpools/system/volatile/discovery.logs%/system/volatile/solaris_grubdisk.mapsc\d+(?:t\w+)?d\d+cCsyHtit|tiott|}|i}ntt|}Wn1tt fj o}t d||fnX|S(s@ function to return a drive object based on a specific name sUnable to look up %s - %s( tretmatchtDISK_REtIR RtdriveR tKeyErrortOSErrort RuntimeError(tnametaliasR.terr((s../discovery.pytretrieve_driveas c Cs:tit}yttgdtWntj odSXtii t ptt gdtnt t di i}z|~}|i}WdQXx|iD]}y|i\}}}Wntj o qnXt|}|io4|idiidjo|id||qq|SqWdS(sa function to collect all of the device paths returned by biosdev as possible boot disks. tloggertrNitusbs1skipping USB drive as an invalid boot disk: %s %s(tloggingt getLoggertILNRtBIOSDEVRtNonetostpathtexiststDISKMAPtCREATE_DISKMAPtopent__exit__t __enter__treadt splitlinestsplitt ValueErrorR5t controllerst attributesttypetdebug( R6t_[1]tfhtdatatlinet_indextctdtdevpathR.((s../discovery.pytget_bios_boot_diskrs,&  $  tTargetDiscoverycBseZdZddeedZdZdZdZdZ dZ dZ dZ d Z d d Zd Zddd ZedZdZdZedZdZRS(s> Discover all logical and physical devices on the system. c Cstt|i|t|_ti|_|ii|_ t t i |_ ||_ ||_||_||_t|_t|_t|_ti|_t|_d|_g|_t|_|i iidt }|o|i|_n|ip|idjo&t!i"i#djot$|_n<yt%|_Wn(t&j o}|i'i(|i)nX|idjoi|idjoYt*dg}t+|} | i,i-ddi.i/djo|i'i0d qnt1i2|_|i'i(d |it+t3d g} xZ| i,i4D]E} | i5d o/| i6dd jo|ii7| q}q8q8WndS(Nt class_typeti386tbiostsparcs diag-switch?t=ittrues eeprom diag-switch? is set to 'true'. This setting prevents the reading of the OBP boot-device setting. The use of the AI manifest disk keyword 'boot_device' can not be supported with this setting. To correct this issue set eeprom diag-switch? to false and reboot.s(Firmware dedicated boot pool devices: %ss-ps/devs/.cdrom(8tsuperRVt__init__tFalsetdry_runRt get_instancetengtdata_object_cachetdocRt DISCOVEREDtroott search_namet search_typet do_croinfotdo_iscsitlistt swap_listt dump_listtdedicated_bootpool_diskstplatformt processortarchtdicttcro_dictR=tbootdiskt mount_devst live_installt persistenttget_first_childRRtgettfw_nameRURR0R6RMtstrerrortEEPROMRtstdoutt partitiontstriptlowertwarnRtplatform_devicestMOUNTRGt startswithRHtappend( tselfR2RgRhRiRjtapp_dataR4tcmdtpRQ((s../discovery.pyR^sT              &   )   cCsdS(Ni ((R((s../discovery.pytget_progress_estimatescCsQtddt}|i}|i}|djo|iid|idS|idjo|iid|idSt |i didd}|dj oMt |i didd}|dj od ||f|_ q||_ n|i djo|i di|_ nxW|i D]L}|i |i|iio|ii|iq |ii|iq W|io'|i o|iid |idS|id|_ |i|_|i|_|i|_tii|io|iid otiti|i}nti|i}d |jo:d |jo-|id did d}||_qzn|idj ou|i |ijo^t|_ t!oG|i"o=|i"dii#djo#|i|i$jod|i _%qqnd|i |i&jo t'|_(nt)|_*|i"oi|i"dii#|i*_+xM|i,i-dt.D]2} |i | i/jod|i*_+| |_0qhqhWn|i1|i*_2|i oH|i |i3jo5|i3|i d|i*_4|i3|i d|_5n|i} |i6| |}g} |i7djoG|i8o=|i9 o2|iid  o|i:djod|_;|S|i:djo x|i9D]} |i<| | i} |i=| xT| ii8D]F}|i>|| i}| i?o| i=|n| i|iqWqWx1|i8D]m}|iid ot@iAd|i oq#n|i| jo&|i>|| i}|i=|q#q#Wn|i:djotiB|itiCtiDB}zqtE|}zSxL|i8D]A}|iFiG|iiH}|iI|| i|}|i=|qWWdtJ|XWdtiK|Xn|S(s discover_disk - method to discover a physical disk's attributes, partitions and slices drive - which physical drive to parse R(tvalidate_childrensdisk '%s' has no mediatDOWNsdisk '%s' is offlineitwwntluns%s,%ds"disk '%s' only has passive aliasess/dev/dids/devicest:iR8tcurrent_boot_devices /dev/dsk/RWtiSCSIiRXtGPTtVTOCs/dev/did/dsk/d\d+(?=s)N(LRR_RKtmediaR=R6RMR2tstatustgetattrtaliasesRRStverify_disk_readt blocksizet active_ctdsRt passive_ctdstdevidtcdromtiscdromtopathR>R?tislinkRtreadlinkR~t rpartitionRTRtR"t disk_keywordRRJRLRutkeyRntTruet isdedicatedR t disk_proptdev_typeRdtget_descendantsR#tctd_listtiscsit vendor_idt dev_vendorRst dev_chassist receptaclet set_geometryRqtslicest partitionstlabelt_labeltdiscover_partitiontinsert_childrentdiscover_slicet is_solarisR*R+RCtO_RDONLYtO_NDELAYR tcontentst efi_partstindextdiscover_gptpartitionR tclose(RR.tnew_disktdrive_attributest drive_mediaRRR3tlinkRtdrive_media_attributestvisited_slicesR~t new_partitiontslct new_sliceROtgptptefi_partt new_gpart((s../discovery.pyt discover_disks                                       c Csd|}|d}x||gD]}d}zpySti|titiB}yti||}Wntj o w!nXtSWntj o w!nXWd|dj oti|nXq!Wt S(sg verify_disk_read() - method to verify a low-level read from the raw ctd path. s /dev/rdsk/%sts2N( R=R>RCRRRFR0RRR_(RRSRtrawtraw2traw_disktfdt_none((s../discovery.pyRs$     cCs d}|idjo^tt|iti|i|i_t |id}|i od|_ t |_ qnd|_ |i |_ |i}|i}|i}tt|iti|i|i_t |i||}||_||_||_||_|S(s set_geometry() - method to set the geometry of the Disk DOC object from the libdiskmgt drive object. dma - the drive's media attributes as returned by libdiskmgt new_disk - Disk DOC object RRN(R=t ncylindersR'tstrtsizet sector_unitsRRtdev_sizeR!tefiRRtvolidtnheadstnsectorst naccessibletncyltgeometry(RtdmaRt new_geometryRtnheadtnsect((s../discovery.pyRs.           cCsx|iD]}x|iiD]}|i}d|jo|dddjo2|iito|ii|idqn|dddjo2|iito|i i|idqqqqWq WdS(sp discover_psuedo - method to discover pseudo controller information, usually zvol swap and dump tused_byt used_nameitdumpitswapN( tdrivesRRt use_statsR2Rt ZVOL_PATHRmRRl(Rt controllerR.Rtstats((s../discovery.pytdiscover_pseudos    c Cs|i}|iid\}}}t|dt}d|_|i|_|itidjoPy-|d}t |g} t | dt i Wqt j ot|_qXntt|itid||_t|i|_|i|_|io|i|i|_n|S(s discover_partition - method to discover a physical disk's partition layout partition - partition object as discovered by ldm blocksize - blocksize of the disk RRtpreservesSolaris/Linux swapRR}R(RKR2R~R%R_tactiontidt part_typet name_to_numtPRTVTOCRRtDEVNULLRRt is_linux_swapR'RRRRtlongtrelsectt start_sectortsize_in_sectorst is_efi_systemtis_pcfs_formattedt_is_pcfs_formatted( RR~Rtpartition_attributest root_pathRRRtslice2R((s../discovery.pyR&s(       cCs|i}tt|i}d|_tt|itid||_t|i |_ |i|_ |i }d|jo ||_ ndt|i|_ti|i|_ti|i|_|i|_|io|i|i|_n|S(s discover_gptpartition - method to discover a physical disk's GPT partition layout. # Note that libdiskmgmt terminology treats GPT partitions as slices # as does the Solaris cXtYdZsN notation # We shall refer to them as GPT partitions though, like the rest of # the world does. partition - object as discovered by ldm blocksize - blocksize of the disk efipart - DK_PART EFI cstruct RRRs{%s}(RKR$RRRR'RRRtstartRRRtin_usetp_guidRtcopytguidtp_uguidtuguidtp_flagtflagRRR2R(RR~Rtefiparttgpart_attributesRR((s../discovery.pyR[s"         cCs|i}tt|i}d|_|i|_|i|_tt|iti d||_t |i |_ |i|_ |i}d|jo ||_n|S(s discover_slices - method to discover a physical disk's slice layout. slc - slice object as discovered by ldm blocksize - blocksize of the disk RRR(RKR&RRRttagRR'RRRRRRRR(RRRtslc_attributesRR((s../discovery.pyRs         tc Cstd}t|_t|_tddddg}t|}|ii}x|D]}|o||joqUn|ii d|t |}d|_ |i |tdddd|g}t|}|ii d jo t|_ntd ddd d |g}t|}|ii|_|i|tdd ddddd|g }t|dhdd6}xt|ii iddD]V}y"|idd\} } } } WnBtj o6} |ii d||ii t| qnX| i|dd} | djot| }| |_n| djot| }t| |_tii|| |ijod|_ t!|_ntii|| |i"jod|_ t!|_qnd|_ |i |qWqUW|S(s discover_zpools - method to walk zpool list output to create Zpool objects. Returns a logical DOC object with all zpools populated. tlogicalRks-Hs-oR2sPopulating DOC for zpool: %sRtbootfst-Rytvaluet mountpoints-rs-tsfilesystem,volumesname,type,used,mountpointtenvtCtLC_ALLs iisUnable to process dataset: %rt/it filesystemtvolumeRRN(#RRtnoswaptnodumptZPOOLRR}RGR6RMRRRtrstriptis_roottZFSRRt set_vdev_mapRHR=RIRR~RRR'RR>R?tjoinRltuseR_Rm(RRgR RRt zpool_listt zpool_nameR)tdatasetR2tds_typetds_sizeRR4tobj((s../discovery.pytdiscover_zpoolssd            "          c Cs|iidt}|i}x|iD]\}}d|i|f}|djo|idd}n|}|i||x,|D]$\}} |idoY|i i d||i d\} } } } }|i d \}}}|p|}t } nd |}d d d dg}t|}|ip|i id|qnx|iii dD]}|ii \} }| |jo_|i d\} } }}|}|o2|d||f}|i i d||fnPqnqnWn|i dd}| oXx|D]I}|i|id ddjo#|i|_||_t |_Pq!q!Wq|i d \}}}|p*|i d\}}}|pqqnx|D]}t|do|i|jo|d joP|idjo|idt}qh|idjo|idt}qhn$|djo|idt}nx7|D]/}|i|jo|i|_||_qoqoWPqqqWqWq+WdS(s set_vdev_map() - walk the vdev_map to set the zpool's vdev entries and update existing physical DOC entries with the proper in_zpool and in_vdev attributes. zpool - zpool DOC object RWs%s-%stnoneRis/dev/dids#Converting disk '%s' to ctd format Rtss/dev/did/rdsk/%ss/usr/sbin/didadms-ls-os fullname,paths&Command '%s' failed to find DID devices s%s%ssDisk '%s' converted to '%s's /dev/dsk/iiRRSRRN(Rft get_childrenRtvdevst iteritemsR2R~tadd_vdevRR6tinfoRHRRRR}twarningRRRStrsplittin_zpooltin_vdevt _whole_diskthasattrRRR&R$R%( RR)tdisklisttvdev_mapt vdev_typet vdev_entriest in_vdev_labelt redundancyt full_entryt whole_disktblanktdevtdidtdsktdev_idtdev_dskt dev_lettert dev_indext did_rdsk_devRRtrowRStrdsktdid_ctdtentryR(tvdev_ctdt vdev_lettert vdev_indext child_listtchild((s../discovery.pyRs                           c Cst||}x|iidtD]n}|o||ijoq%nxG|D]?\}}}}} } ||ijo|it|qPqPWq%WdS(s^ discover_BEs - method to discover all Boot Environments (BEs) on the system. RWN(RRfRRR2RR( RR"R2tbe_lstR)tbe_nametbe_pooltroot_dst is_activetds_lsttss_lst((s../discovery.pyt discover_BEsvscCsxttD]}|ioq n|idjo|o|i|q xY|iD]N}|i|}|djp |ioqVn|o|i i |qVqVWq Wg}|i i dt D]}||i q~}|iidxttD]}|ioqn|iiitoqn|i|}|djp|ip|idjoqn|i |joqn|o|i i |qqWdS(s discover_entire_system - populates the root node of the DOC tree with the entire physical layout of the system. add_physical - boolean value to signal if physical targets should be added to the DOC. s/pseudoRWs,Adding drives without controllers to the DOCRN(R Rtfloppy_controllerR2RRRR=RRfRRRRTR6RMR RJRKRRt ZVOL_RPATHRS(Rt add_physicalRR.RRNR(t devpath_list((s../discovery.pytdiscover_entire_systems:   ,  'cCs|iidt}|pdSx}|D]u}|ip;y|iWqsttfj o|iqsXnt|i t o|id|i _ q(q(WdS(s set up the iSCSI initiator appropriately (if specified) such that any physical/logical iSCSI devices can be discovered. RWNi( RdRR#Rt setup_iscsiRR1tteardownt isinstancetparentRRS(Rt iscsi_listR((s../discovery.pyR\s   cCstdddg}t|}|ipdSd}xd|iiD]S}|id\}}}|pqCn||pd|f|i|<|d7}qCW|io)|iii t t |idt ndS(sX set up a DataObjectDict representing the output from /usr/sbin/croinfo s-hs-OtcARNiRt generate_xml( tCROINFORR}RGRHR=RsRdRwRRRR(RRRtiRQRSR3R((s../discovery.pyt setup_croinfos     cCs||_|iiidti}|io|in|io|i n|i t jot |i toTx|i D]B}t|}|i|}|dj o|ii|qqWqt|i }|i|}|dj o|ii|qn{|i tjo@|idt|ii|i|i |i|i n+|i|ii|i|i|p|iii|in/|d}x!|iiD]}|i|qWdS(s; primary execution checkpoint for Target Discovery R2RYiN(R`RdRwRRReRiReRjR\RhtDISK_SEARCH_NAMER^RgRkR5RR=RfRtZPOOL_SEARCH_NAMER[R_R'RVtchildren(RR`t discoveredR2R.RRN((s../discovery.pytexecutes@            c CsM|iddd}|idod|}n d|}tii|tjotd|nd }ztt d|}Wd t X|d j o#|i d d jot StSnt id d dd|}zRy7t||g}t|t|g}t|t SWntj otSXWd ti|XtSd S(s is_pcfs_formatted() Return a Boolean value of True if the GPT partition guid is already formatted with a pcfs filesystem. This test is useful in conjuction with the is_efi_system property to determine if an existing EFI system partition can be reused to store the Solaris UEFI boot program. If False, a format using mkfs on the partition would be required. Riis/dev/dids/dev/did/dsk/%ss /dev/dsk/%ssNo such block device exists: %st mnt_specialNt mnt_fstypetpcfstdirs/system/volatiletprefixsesp_%s_(R0RR>R?R@R_R1R=RRRRyRttempfiletmkdtempt PCFSMOUNTRtUMOUNTRtrmdir(Rtdev_pathtctdnRBtmntmatcht mount_pointt mount_cmdt umount_cmd((s../discovery.pyR8s8        N(t__name__t __module__t__doc__R=RR^RRRRRRRRR'RRVR[R\ReR_RjR(((s../discovery.pyRVs&S   0  5 +  ] y <   15} | {1:>5} | {2:>40} |s {0:>15} |it t|i*is| {0:>5} | {1:>40} |RiCs disk nameRsin use?RRs used by: %sRs (%s)Ns s ( RwR*RRtformatRSRR$RR=R2( RdRRRt disk_formatRt disk_linet entry_lineR(t gpart_listtgpartR((s../discovery.pytprint_gptpartitions2    !c Cs;dGH|iidtd}|idt}d}dddd}dd }d d }|GH|id ddddgGH|GHx|D]}|i|iGH|idt}xx|D]p} | itijo d} nd} | i o d} nd} |i| i i dd| | i | gGHqW|GHqWdS(s0 prints the output from the -p argument sPartition discoveryRWis.{0:>15} | {1:>5} | {2:>7} | {3:>5} | {4:>11} |s {0:>15} |i'RRis&| {0:>5} | {1:>7} | {2:>5} | {3:>11} |Ri9t disk_nameRsactive?tIDs Linux Swap?RRRiNs ( RwR*RRRRSR%tbootidtACTIVERR2RHR( RdRRRRt line_formatRR(tpartition_listR~tactivet linux_swap((s../discovery.pytprint_partitions6       c CsddGH|iidtd}|idt}d}dddd dd}dd }d d }|d}|GH|idddgGH|GHx|D]}|i|iGH|idt} x| D]} | idjo d} nWd| ijoFd| idd} d| ijo| d| idd7} q<n|i| i | gGHqW|GHqWdS(s0 prints the output from the -s argument sSlice discoveryRWis{0:>15} | {1:>5} | {2:>40} |s {0:>15} |iRRi*is| {0:>5} | {1:>40} |RiCs disk nameRsin use?RRs used by: %sRs (%s)Ns s ( RwR*RRRRSRR&RR=R2( RdRRRRRRRR(t slice_listRR((s../discovery.pyt print_slices2    !c Cs7dGH|iidtd}|idtd}|idt}d}dd}|GH|iddd d d gGH|GHx|D]}d d d|ig}ti|dti dti }g} |i i ddd!D]} | | i dq~ \} } } }|i|i| | | |gGHqW|GHdS(s0 prints the output from the -z argument sZpool discoveryRWis/{0:>10} | {1:>20} | {2:>20} | {3:>7} | {4:>8} |RiOR2RRRtcapacitys/usr/sbin/zpoolRysbootfs,guid,size,capacityR}tstderrs iiiN( RwR*RRRRR2Rt check_calltSTORER}RH(RdRR R!t print_formatt zpool_lineR)RRRNRQRRRR((s../discovery.pyt print_zpool s&    !Jc Csd}d}xttD]}||t|GH|d7}x|iD]}||t|GH|d7}x%|iD]}||t|GHqxWx<|iD]1}||t|GH|d7}x%|iD]}||t|GHqWx%|iD]}||t|GHqW|i}|dj o||t|GH|i }|d7}|i p |i o,x)|i D]} ||t| GHqoWnx%|i D]} ||t| GHqW|d8}n|d8}qW|d8}qJW|d8}qWdS(sA prints drive information from the --libdiskmgt argument cSs6dig}|iD]}|d||q~S(s2 function to print an indented string s s (RRG(tleveltstringRNRQ((s../discovery.pyt indent_str-siiN(R RRRJtpathsRRRR=RKRtfdiskRR( RtindenttbusRR?R.R3RRtpartR((s../discovery.pytprint_libdiskmgt)sN                t default_logsTest TDR`(vR}RR9RR>RoR*tsysRptbootmgmt.bootinfoRtbootmgmt.pysolRRRtbootmgmt.versabootRt libdevinfoRtlibdiskmgt.constRRRR RR R tlibefiR R tsolaris_installRRRRRt%solaris_install.data_object.data_dictRtsolaris_install.engineRt!solaris_install.engine.checkpointRt Checkpointtsolaris_install.loggerRR;tsolaris_install.targetRRtsolaris_install.target.libbeRtsolaris_install.target.logicalRRRRRtsolaris_install.target.physicalRR R!R"R#R$R%R&tsolaris_install.target.sizeR'R<RBRctDEVFSADMtDHCPINFOtDLADMR|tFSTYPtISCSIADMRRrRtSVCStSVCADMRsRRRRXRfRgtCLI_DEFAULT_LOGRAR,R5RURVR{RRRRRRRRRRtexittTDRjRR(RdRR~RR)Rtget_xml_tree_str(((s../discovery.pyts        "((:  )  "  #  -